measurements.py 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467
  1. # Copyright (C) 2003-2005 Peter J. Verveer
  2. #
  3. # Redistribution and use in source and binary forms, with or without
  4. # modification, are permitted provided that the following conditions
  5. # are met:
  6. #
  7. # 1. Redistributions of source code must retain the above copyright
  8. # notice, this list of conditions and the following disclaimer.
  9. #
  10. # 2. Redistributions in binary form must reproduce the above
  11. # copyright notice, this list of conditions and the following
  12. # disclaimer in the documentation and/or other materials provided
  13. # with the distribution.
  14. #
  15. # 3. The name of the author may not be used to endorse or promote
  16. # products derived from this software without specific prior
  17. # written permission.
  18. #
  19. # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
  20. # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  21. # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22. # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  23. # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24. # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  25. # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  26. # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  27. # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  28. # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  29. # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. from __future__ import division, print_function, absolute_import
  31. import numpy
  32. import numpy as np
  33. from . import _ni_support
  34. from . import _ni_label
  35. from . import _nd_image
  36. from . import morphology
  37. __all__ = ['label', 'find_objects', 'labeled_comprehension', 'sum', 'mean',
  38. 'variance', 'standard_deviation', 'minimum', 'maximum', 'median',
  39. 'minimum_position', 'maximum_position', 'extrema', 'center_of_mass',
  40. 'histogram', 'watershed_ift']
  41. def label(input, structure=None, output=None):
  42. """
  43. Label features in an array.
  44. Parameters
  45. ----------
  46. input : array_like
  47. An array-like object to be labeled. Any non-zero values in `input` are
  48. counted as features and zero values are considered the background.
  49. structure : array_like, optional
  50. A structuring element that defines feature connections.
  51. `structure` must be symmetric. If no structuring element is provided,
  52. one is automatically generated with a squared connectivity equal to
  53. one. That is, for a 2-D `input` array, the default structuring element
  54. is::
  55. [[0,1,0],
  56. [1,1,1],
  57. [0,1,0]]
  58. output : (None, data-type, array_like), optional
  59. If `output` is a data type, it specifies the type of the resulting
  60. labeled feature array
  61. If `output` is an array-like object, then `output` will be updated
  62. with the labeled features from this function. This function can
  63. operate in-place, by passing output=input.
  64. Note that the output must be able to store the largest label, or this
  65. function will raise an Exception.
  66. Returns
  67. -------
  68. label : ndarray or int
  69. An integer ndarray where each unique feature in `input` has a unique
  70. label in the returned array.
  71. num_features : int
  72. How many objects were found.
  73. If `output` is None, this function returns a tuple of
  74. (`labeled_array`, `num_features`).
  75. If `output` is a ndarray, then it will be updated with values in
  76. `labeled_array` and only `num_features` will be returned by this
  77. function.
  78. See Also
  79. --------
  80. find_objects : generate a list of slices for the labeled features (or
  81. objects); useful for finding features' position or
  82. dimensions
  83. Examples
  84. --------
  85. Create an image with some features, then label it using the default
  86. (cross-shaped) structuring element:
  87. >>> from scipy.ndimage import label, generate_binary_structure
  88. >>> a = np.array([[0,0,1,1,0,0],
  89. ... [0,0,0,1,0,0],
  90. ... [1,1,0,0,1,0],
  91. ... [0,0,0,1,0,0]])
  92. >>> labeled_array, num_features = label(a)
  93. Each of the 4 features are labeled with a different integer:
  94. >>> num_features
  95. 4
  96. >>> labeled_array
  97. array([[0, 0, 1, 1, 0, 0],
  98. [0, 0, 0, 1, 0, 0],
  99. [2, 2, 0, 0, 3, 0],
  100. [0, 0, 0, 4, 0, 0]])
  101. Generate a structuring element that will consider features connected even
  102. if they touch diagonally:
  103. >>> s = generate_binary_structure(2,2)
  104. or,
  105. >>> s = [[1,1,1],
  106. ... [1,1,1],
  107. ... [1,1,1]]
  108. Label the image using the new structuring element:
  109. >>> labeled_array, num_features = label(a, structure=s)
  110. Show the 2 labeled features (note that features 1, 3, and 4 from above are
  111. now considered a single feature):
  112. >>> num_features
  113. 2
  114. >>> labeled_array
  115. array([[0, 0, 1, 1, 0, 0],
  116. [0, 0, 0, 1, 0, 0],
  117. [2, 2, 0, 0, 1, 0],
  118. [0, 0, 0, 1, 0, 0]])
  119. """
  120. input = numpy.asarray(input)
  121. if numpy.iscomplexobj(input):
  122. raise TypeError('Complex type not supported')
  123. if structure is None:
  124. structure = morphology.generate_binary_structure(input.ndim, 1)
  125. structure = numpy.asarray(structure, dtype=bool)
  126. if structure.ndim != input.ndim:
  127. raise RuntimeError('structure and input must have equal rank')
  128. for ii in structure.shape:
  129. if ii != 3:
  130. raise ValueError('structure dimensions must be equal to 3')
  131. # Use 32 bits if it's large enough for this image.
  132. # _ni_label.label() needs two entries for background and
  133. # foreground tracking
  134. need_64bits = input.size >= (2**31 - 2)
  135. if isinstance(output, numpy.ndarray):
  136. if output.shape != input.shape:
  137. raise ValueError("output shape not correct")
  138. caller_provided_output = True
  139. else:
  140. caller_provided_output = False
  141. if output is None:
  142. output = np.empty(input.shape, np.intp if need_64bits else np.int32)
  143. else:
  144. output = np.empty(input.shape, output)
  145. # handle scalars, 0-dim arrays
  146. if input.ndim == 0 or input.size == 0:
  147. if input.ndim == 0:
  148. # scalar
  149. maxlabel = 1 if (input != 0) else 0
  150. output[...] = maxlabel
  151. else:
  152. # 0-dim
  153. maxlabel = 0
  154. if caller_provided_output:
  155. return maxlabel
  156. else:
  157. return output, maxlabel
  158. try:
  159. max_label = _ni_label._label(input, structure, output)
  160. except _ni_label.NeedMoreBits:
  161. # Make another attempt with enough bits, then try to cast to the
  162. # new type.
  163. tmp_output = np.empty(input.shape, np.intp if need_64bits else np.int32)
  164. max_label = _ni_label._label(input, structure, tmp_output)
  165. output[...] = tmp_output[...]
  166. if not np.all(output == tmp_output):
  167. # refuse to return bad results
  168. raise RuntimeError("insufficient bit-depth in requested output type")
  169. if caller_provided_output:
  170. # result was written in-place
  171. return max_label
  172. else:
  173. return output, max_label
  174. def find_objects(input, max_label=0):
  175. """
  176. Find objects in a labeled array.
  177. Parameters
  178. ----------
  179. input : ndarray of ints
  180. Array containing objects defined by different labels. Labels with
  181. value 0 are ignored.
  182. max_label : int, optional
  183. Maximum label to be searched for in `input`. If max_label is not
  184. given, the positions of all objects are returned.
  185. Returns
  186. -------
  187. object_slices : list of tuples
  188. A list of tuples, with each tuple containing N slices (with N the
  189. dimension of the input array). Slices correspond to the minimal
  190. parallelepiped that contains the object. If a number is missing,
  191. None is returned instead of a slice.
  192. See Also
  193. --------
  194. label, center_of_mass
  195. Notes
  196. -----
  197. This function is very useful for isolating a volume of interest inside
  198. a 3-D array, that cannot be "seen through".
  199. Examples
  200. --------
  201. >>> from scipy import ndimage
  202. >>> a = np.zeros((6,6), dtype=int)
  203. >>> a[2:4, 2:4] = 1
  204. >>> a[4, 4] = 1
  205. >>> a[:2, :3] = 2
  206. >>> a[0, 5] = 3
  207. >>> a
  208. array([[2, 2, 2, 0, 0, 3],
  209. [2, 2, 2, 0, 0, 0],
  210. [0, 0, 1, 1, 0, 0],
  211. [0, 0, 1, 1, 0, 0],
  212. [0, 0, 0, 0, 1, 0],
  213. [0, 0, 0, 0, 0, 0]])
  214. >>> ndimage.find_objects(a)
  215. [(slice(2, 5, None), slice(2, 5, None)), (slice(0, 2, None), slice(0, 3, None)), (slice(0, 1, None), slice(5, 6, None))]
  216. >>> ndimage.find_objects(a, max_label=2)
  217. [(slice(2, 5, None), slice(2, 5, None)), (slice(0, 2, None), slice(0, 3, None))]
  218. >>> ndimage.find_objects(a == 1, max_label=2)
  219. [(slice(2, 5, None), slice(2, 5, None)), None]
  220. >>> loc = ndimage.find_objects(a)[0]
  221. >>> a[loc]
  222. array([[1, 1, 0],
  223. [1, 1, 0],
  224. [0, 0, 1]])
  225. """
  226. input = numpy.asarray(input)
  227. if numpy.iscomplexobj(input):
  228. raise TypeError('Complex type not supported')
  229. if max_label < 1:
  230. max_label = input.max()
  231. return _nd_image.find_objects(input, max_label)
  232. def labeled_comprehension(input, labels, index, func, out_dtype, default, pass_positions=False):
  233. """
  234. Roughly equivalent to [func(input[labels == i]) for i in index].
  235. Sequentially applies an arbitrary function (that works on array_like input)
  236. to subsets of an n-D image array specified by `labels` and `index`.
  237. The option exists to provide the function with positional parameters as the
  238. second argument.
  239. Parameters
  240. ----------
  241. input : array_like
  242. Data from which to select `labels` to process.
  243. labels : array_like or None
  244. Labels to objects in `input`.
  245. If not None, array must be same shape as `input`.
  246. If None, `func` is applied to raveled `input`.
  247. index : int, sequence of ints or None
  248. Subset of `labels` to which to apply `func`.
  249. If a scalar, a single value is returned.
  250. If None, `func` is applied to all non-zero values of `labels`.
  251. func : callable
  252. Python function to apply to `labels` from `input`.
  253. out_dtype : dtype
  254. Dtype to use for `result`.
  255. default : int, float or None
  256. Default return value when a element of `index` does not exist
  257. in `labels`.
  258. pass_positions : bool, optional
  259. If True, pass linear indices to `func` as a second argument.
  260. Default is False.
  261. Returns
  262. -------
  263. result : ndarray
  264. Result of applying `func` to each of `labels` to `input` in `index`.
  265. Examples
  266. --------
  267. >>> a = np.array([[1, 2, 0, 0],
  268. ... [5, 3, 0, 4],
  269. ... [0, 0, 0, 7],
  270. ... [9, 3, 0, 0]])
  271. >>> from scipy import ndimage
  272. >>> lbl, nlbl = ndimage.label(a)
  273. >>> lbls = np.arange(1, nlbl+1)
  274. >>> ndimage.labeled_comprehension(a, lbl, lbls, np.mean, float, 0)
  275. array([ 2.75, 5.5 , 6. ])
  276. Falling back to `default`:
  277. >>> lbls = np.arange(1, nlbl+2)
  278. >>> ndimage.labeled_comprehension(a, lbl, lbls, np.mean, float, -1)
  279. array([ 2.75, 5.5 , 6. , -1. ])
  280. Passing positions:
  281. >>> def fn(val, pos):
  282. ... print("fn says: %s : %s" % (val, pos))
  283. ... return (val.sum()) if (pos.sum() % 2 == 0) else (-val.sum())
  284. ...
  285. >>> ndimage.labeled_comprehension(a, lbl, lbls, fn, float, 0, True)
  286. fn says: [1 2 5 3] : [0 1 4 5]
  287. fn says: [4 7] : [ 7 11]
  288. fn says: [9 3] : [12 13]
  289. array([ 11., 11., -12., 0.])
  290. """
  291. as_scalar = numpy.isscalar(index)
  292. input = numpy.asarray(input)
  293. if pass_positions:
  294. positions = numpy.arange(input.size).reshape(input.shape)
  295. if labels is None:
  296. if index is not None:
  297. raise ValueError("index without defined labels")
  298. if not pass_positions:
  299. return func(input.ravel())
  300. else:
  301. return func(input.ravel(), positions.ravel())
  302. try:
  303. input, labels = numpy.broadcast_arrays(input, labels)
  304. except ValueError:
  305. raise ValueError("input and labels must have the same shape "
  306. "(excepting dimensions with width 1)")
  307. if index is None:
  308. if not pass_positions:
  309. return func(input[labels > 0])
  310. else:
  311. return func(input[labels > 0], positions[labels > 0])
  312. index = numpy.atleast_1d(index)
  313. if np.any(index.astype(labels.dtype).astype(index.dtype) != index):
  314. raise ValueError("Cannot convert index values from <%s> to <%s> "
  315. "(labels' type) without loss of precision" %
  316. (index.dtype, labels.dtype))
  317. index = index.astype(labels.dtype)
  318. # optimization: find min/max in index, and select those parts of labels, input, and positions
  319. lo = index.min()
  320. hi = index.max()
  321. mask = (labels >= lo) & (labels <= hi)
  322. # this also ravels the arrays
  323. labels = labels[mask]
  324. input = input[mask]
  325. if pass_positions:
  326. positions = positions[mask]
  327. # sort everything by labels
  328. label_order = labels.argsort()
  329. labels = labels[label_order]
  330. input = input[label_order]
  331. if pass_positions:
  332. positions = positions[label_order]
  333. index_order = index.argsort()
  334. sorted_index = index[index_order]
  335. def do_map(inputs, output):
  336. """labels must be sorted"""
  337. nidx = sorted_index.size
  338. # Find boundaries for each stretch of constant labels
  339. # This could be faster, but we already paid N log N to sort labels.
  340. lo = numpy.searchsorted(labels, sorted_index, side='left')
  341. hi = numpy.searchsorted(labels, sorted_index, side='right')
  342. for i, l, h in zip(range(nidx), lo, hi):
  343. if l == h:
  344. continue
  345. output[i] = func(*[inp[l:h] for inp in inputs])
  346. temp = numpy.empty(index.shape, out_dtype)
  347. temp[:] = default
  348. if not pass_positions:
  349. do_map([input], temp)
  350. else:
  351. do_map([input, positions], temp)
  352. output = numpy.zeros(index.shape, out_dtype)
  353. output[index_order] = temp
  354. if as_scalar:
  355. output = output[0]
  356. return output
  357. def _safely_castable_to_int(dt):
  358. """Test whether the numpy data type `dt` can be safely cast to an int."""
  359. int_size = np.dtype(int).itemsize
  360. safe = ((np.issubdtype(dt, np.signedinteger) and dt.itemsize <= int_size) or
  361. (np.issubdtype(dt, np.unsignedinteger) and dt.itemsize < int_size))
  362. return safe
  363. def _stats(input, labels=None, index=None, centered=False):
  364. """Count, sum, and optionally compute (sum - centre)^2 of input by label
  365. Parameters
  366. ----------
  367. input : array_like, n-dimensional
  368. The input data to be analyzed.
  369. labels : array_like (n-dimensional), optional
  370. The labels of the data in `input`. This array must be broadcast
  371. compatible with `input`; typically it is the same shape as `input`.
  372. If `labels` is None, all nonzero values in `input` are treated as
  373. the single labeled group.
  374. index : label or sequence of labels, optional
  375. These are the labels of the groups for which the stats are computed.
  376. If `index` is None, the stats are computed for the single group where
  377. `labels` is greater than 0.
  378. centered : bool, optional
  379. If True, the centered sum of squares for each labeled group is
  380. also returned. Default is False.
  381. Returns
  382. -------
  383. counts : int or ndarray of ints
  384. The number of elements in each labeled group.
  385. sums : scalar or ndarray of scalars
  386. The sums of the values in each labeled group.
  387. sums_c : scalar or ndarray of scalars, optional
  388. The sums of mean-centered squares of the values in each labeled group.
  389. This is only returned if `centered` is True.
  390. """
  391. def single_group(vals):
  392. if centered:
  393. vals_c = vals - vals.mean()
  394. return vals.size, vals.sum(), (vals_c * vals_c.conjugate()).sum()
  395. else:
  396. return vals.size, vals.sum()
  397. if labels is None:
  398. return single_group(input)
  399. # ensure input and labels match sizes
  400. input, labels = numpy.broadcast_arrays(input, labels)
  401. if index is None:
  402. return single_group(input[labels > 0])
  403. if numpy.isscalar(index):
  404. return single_group(input[labels == index])
  405. def _sum_centered(labels):
  406. # `labels` is expected to be an ndarray with the same shape as `input`.
  407. # It must contain the label indices (which are not necessarily the labels
  408. # themselves).
  409. means = sums / counts
  410. centered_input = input - means[labels]
  411. # bincount expects 1d inputs, so we ravel the arguments.
  412. bc = numpy.bincount(labels.ravel(),
  413. weights=(centered_input *
  414. centered_input.conjugate()).ravel())
  415. return bc
  416. # Remap labels to unique integers if necessary, or if the largest
  417. # label is larger than the number of values.
  418. if (not _safely_castable_to_int(labels.dtype) or
  419. labels.min() < 0 or labels.max() > labels.size):
  420. # Use numpy.unique to generate the label indices. `new_labels` will
  421. # be 1-d, but it should be interpreted as the flattened n-d array of
  422. # label indices.
  423. unique_labels, new_labels = numpy.unique(labels, return_inverse=True)
  424. counts = numpy.bincount(new_labels)
  425. sums = numpy.bincount(new_labels, weights=input.ravel())
  426. if centered:
  427. # Compute the sum of the mean-centered squares.
  428. # We must reshape new_labels to the n-d shape of `input` before
  429. # passing it _sum_centered.
  430. sums_c = _sum_centered(new_labels.reshape(labels.shape))
  431. idxs = numpy.searchsorted(unique_labels, index)
  432. # make all of idxs valid
  433. idxs[idxs >= unique_labels.size] = 0
  434. found = (unique_labels[idxs] == index)
  435. else:
  436. # labels are an integer type allowed by bincount, and there aren't too
  437. # many, so call bincount directly.
  438. counts = numpy.bincount(labels.ravel())
  439. sums = numpy.bincount(labels.ravel(), weights=input.ravel())
  440. if centered:
  441. sums_c = _sum_centered(labels)
  442. # make sure all index values are valid
  443. idxs = numpy.asanyarray(index, numpy.int).copy()
  444. found = (idxs >= 0) & (idxs < counts.size)
  445. idxs[~found] = 0
  446. counts = counts[idxs]
  447. counts[~found] = 0
  448. sums = sums[idxs]
  449. sums[~found] = 0
  450. if not centered:
  451. return (counts, sums)
  452. else:
  453. sums_c = sums_c[idxs]
  454. sums_c[~found] = 0
  455. return (counts, sums, sums_c)
  456. def sum(input, labels=None, index=None):
  457. """
  458. Calculate the sum of the values of the array.
  459. Parameters
  460. ----------
  461. input : array_like
  462. Values of `input` inside the regions defined by `labels`
  463. are summed together.
  464. labels : array_like of ints, optional
  465. Assign labels to the values of the array. Has to have the same shape as
  466. `input`.
  467. index : array_like, optional
  468. A single label number or a sequence of label numbers of
  469. the objects to be measured.
  470. Returns
  471. -------
  472. sum : ndarray or scalar
  473. An array of the sums of values of `input` inside the regions defined
  474. by `labels` with the same shape as `index`. If 'index' is None or scalar,
  475. a scalar is returned.
  476. See also
  477. --------
  478. mean, median
  479. Examples
  480. --------
  481. >>> from scipy import ndimage
  482. >>> input = [0,1,2,3]
  483. >>> labels = [1,1,2,2]
  484. >>> ndimage.sum(input, labels, index=[1,2])
  485. [1.0, 5.0]
  486. >>> ndimage.sum(input, labels, index=1)
  487. 1
  488. >>> ndimage.sum(input, labels)
  489. 6
  490. """
  491. count, sum = _stats(input, labels, index)
  492. return sum
  493. def mean(input, labels=None, index=None):
  494. """
  495. Calculate the mean of the values of an array at labels.
  496. Parameters
  497. ----------
  498. input : array_like
  499. Array on which to compute the mean of elements over distinct
  500. regions.
  501. labels : array_like, optional
  502. Array of labels of same shape, or broadcastable to the same shape as
  503. `input`. All elements sharing the same label form one region over
  504. which the mean of the elements is computed.
  505. index : int or sequence of ints, optional
  506. Labels of the objects over which the mean is to be computed.
  507. Default is None, in which case the mean for all values where label is
  508. greater than 0 is calculated.
  509. Returns
  510. -------
  511. out : list
  512. Sequence of same length as `index`, with the mean of the different
  513. regions labeled by the labels in `index`.
  514. See also
  515. --------
  516. ndimage.variance, ndimage.standard_deviation, ndimage.minimum,
  517. ndimage.maximum, ndimage.sum
  518. ndimage.label
  519. Examples
  520. --------
  521. >>> from scipy import ndimage
  522. >>> a = np.arange(25).reshape((5,5))
  523. >>> labels = np.zeros_like(a)
  524. >>> labels[3:5,3:5] = 1
  525. >>> index = np.unique(labels)
  526. >>> labels
  527. array([[0, 0, 0, 0, 0],
  528. [0, 0, 0, 0, 0],
  529. [0, 0, 0, 0, 0],
  530. [0, 0, 0, 1, 1],
  531. [0, 0, 0, 1, 1]])
  532. >>> index
  533. array([0, 1])
  534. >>> ndimage.mean(a, labels=labels, index=index)
  535. [10.285714285714286, 21.0]
  536. """
  537. count, sum = _stats(input, labels, index)
  538. return sum / numpy.asanyarray(count).astype(numpy.float)
  539. def variance(input, labels=None, index=None):
  540. """
  541. Calculate the variance of the values of an n-D image array, optionally at
  542. specified sub-regions.
  543. Parameters
  544. ----------
  545. input : array_like
  546. Nd-image data to process.
  547. labels : array_like, optional
  548. Labels defining sub-regions in `input`.
  549. If not None, must be same shape as `input`.
  550. index : int or sequence of ints, optional
  551. `labels` to include in output. If None (default), all values where
  552. `labels` is non-zero are used.
  553. Returns
  554. -------
  555. variance : float or ndarray
  556. Values of variance, for each sub-region if `labels` and `index` are
  557. specified.
  558. See Also
  559. --------
  560. label, standard_deviation, maximum, minimum, extrema
  561. Examples
  562. --------
  563. >>> a = np.array([[1, 2, 0, 0],
  564. ... [5, 3, 0, 4],
  565. ... [0, 0, 0, 7],
  566. ... [9, 3, 0, 0]])
  567. >>> from scipy import ndimage
  568. >>> ndimage.variance(a)
  569. 7.609375
  570. Features to process can be specified using `labels` and `index`:
  571. >>> lbl, nlbl = ndimage.label(a)
  572. >>> ndimage.variance(a, lbl, index=np.arange(1, nlbl+1))
  573. array([ 2.1875, 2.25 , 9. ])
  574. If no index is given, all non-zero `labels` are processed:
  575. >>> ndimage.variance(a, lbl)
  576. 6.1875
  577. """
  578. count, sum, sum_c_sq = _stats(input, labels, index, centered=True)
  579. return sum_c_sq / np.asanyarray(count).astype(float)
  580. def standard_deviation(input, labels=None, index=None):
  581. """
  582. Calculate the standard deviation of the values of an n-D image array,
  583. optionally at specified sub-regions.
  584. Parameters
  585. ----------
  586. input : array_like
  587. Nd-image data to process.
  588. labels : array_like, optional
  589. Labels to identify sub-regions in `input`.
  590. If not None, must be same shape as `input`.
  591. index : int or sequence of ints, optional
  592. `labels` to include in output. If None (default), all values where
  593. `labels` is non-zero are used.
  594. Returns
  595. -------
  596. standard_deviation : float or ndarray
  597. Values of standard deviation, for each sub-region if `labels` and
  598. `index` are specified.
  599. See Also
  600. --------
  601. label, variance, maximum, minimum, extrema
  602. Examples
  603. --------
  604. >>> a = np.array([[1, 2, 0, 0],
  605. ... [5, 3, 0, 4],
  606. ... [0, 0, 0, 7],
  607. ... [9, 3, 0, 0]])
  608. >>> from scipy import ndimage
  609. >>> ndimage.standard_deviation(a)
  610. 2.7585095613392387
  611. Features to process can be specified using `labels` and `index`:
  612. >>> lbl, nlbl = ndimage.label(a)
  613. >>> ndimage.standard_deviation(a, lbl, index=np.arange(1, nlbl+1))
  614. array([ 1.479, 1.5 , 3. ])
  615. If no index is given, non-zero `labels` are processed:
  616. >>> ndimage.standard_deviation(a, lbl)
  617. 2.4874685927665499
  618. """
  619. return numpy.sqrt(variance(input, labels, index))
  620. def _select(input, labels=None, index=None, find_min=False, find_max=False,
  621. find_min_positions=False, find_max_positions=False,
  622. find_median=False):
  623. """Returns min, max, or both, plus their positions (if requested), and
  624. median."""
  625. input = numpy.asanyarray(input)
  626. find_positions = find_min_positions or find_max_positions
  627. positions = None
  628. if find_positions:
  629. positions = numpy.arange(input.size).reshape(input.shape)
  630. def single_group(vals, positions):
  631. result = []
  632. if find_min:
  633. result += [vals.min()]
  634. if find_min_positions:
  635. result += [positions[vals == vals.min()][0]]
  636. if find_max:
  637. result += [vals.max()]
  638. if find_max_positions:
  639. result += [positions[vals == vals.max()][0]]
  640. if find_median:
  641. result += [numpy.median(vals)]
  642. return result
  643. if labels is None:
  644. return single_group(input, positions)
  645. # ensure input and labels match sizes
  646. input, labels = numpy.broadcast_arrays(input, labels)
  647. if index is None:
  648. mask = (labels > 0)
  649. masked_positions = None
  650. if find_positions:
  651. masked_positions = positions[mask]
  652. return single_group(input[mask], masked_positions)
  653. if numpy.isscalar(index):
  654. mask = (labels == index)
  655. masked_positions = None
  656. if find_positions:
  657. masked_positions = positions[mask]
  658. return single_group(input[mask], masked_positions)
  659. # remap labels to unique integers if necessary, or if the largest
  660. # label is larger than the number of values.
  661. if (not _safely_castable_to_int(labels.dtype) or
  662. labels.min() < 0 or labels.max() > labels.size):
  663. # remap labels, and indexes
  664. unique_labels, labels = numpy.unique(labels, return_inverse=True)
  665. idxs = numpy.searchsorted(unique_labels, index)
  666. # make all of idxs valid
  667. idxs[idxs >= unique_labels.size] = 0
  668. found = (unique_labels[idxs] == index)
  669. else:
  670. # labels are an integer type, and there aren't too many.
  671. idxs = numpy.asanyarray(index, numpy.int).copy()
  672. found = (idxs >= 0) & (idxs <= labels.max())
  673. idxs[~ found] = labels.max() + 1
  674. if find_median:
  675. order = numpy.lexsort((input.ravel(), labels.ravel()))
  676. else:
  677. order = input.ravel().argsort()
  678. input = input.ravel()[order]
  679. labels = labels.ravel()[order]
  680. if find_positions:
  681. positions = positions.ravel()[order]
  682. result = []
  683. if find_min:
  684. mins = numpy.zeros(labels.max() + 2, input.dtype)
  685. mins[labels[::-1]] = input[::-1]
  686. result += [mins[idxs]]
  687. if find_min_positions:
  688. minpos = numpy.zeros(labels.max() + 2, int)
  689. minpos[labels[::-1]] = positions[::-1]
  690. result += [minpos[idxs]]
  691. if find_max:
  692. maxs = numpy.zeros(labels.max() + 2, input.dtype)
  693. maxs[labels] = input
  694. result += [maxs[idxs]]
  695. if find_max_positions:
  696. maxpos = numpy.zeros(labels.max() + 2, int)
  697. maxpos[labels] = positions
  698. result += [maxpos[idxs]]
  699. if find_median:
  700. locs = numpy.arange(len(labels))
  701. lo = numpy.zeros(labels.max() + 2, numpy.int)
  702. lo[labels[::-1]] = locs[::-1]
  703. hi = numpy.zeros(labels.max() + 2, numpy.int)
  704. hi[labels] = locs
  705. lo = lo[idxs]
  706. hi = hi[idxs]
  707. # lo is an index to the lowest value in input for each label,
  708. # hi is an index to the largest value.
  709. # move them to be either the same ((hi - lo) % 2 == 0) or next
  710. # to each other ((hi - lo) % 2 == 1), then average.
  711. step = (hi - lo) // 2
  712. lo += step
  713. hi -= step
  714. result += [(input[lo] + input[hi]) / 2.0]
  715. return result
  716. def minimum(input, labels=None, index=None):
  717. """
  718. Calculate the minimum of the values of an array over labeled regions.
  719. Parameters
  720. ----------
  721. input : array_like
  722. Array_like of values. For each region specified by `labels`, the
  723. minimal values of `input` over the region is computed.
  724. labels : array_like, optional
  725. An array_like of integers marking different regions over which the
  726. minimum value of `input` is to be computed. `labels` must have the
  727. same shape as `input`. If `labels` is not specified, the minimum
  728. over the whole array is returned.
  729. index : array_like, optional
  730. A list of region labels that are taken into account for computing the
  731. minima. If index is None, the minimum over all elements where `labels`
  732. is non-zero is returned.
  733. Returns
  734. -------
  735. minimum : float or list of floats
  736. List of minima of `input` over the regions determined by `labels` and
  737. whose index is in `index`. If `index` or `labels` are not specified, a
  738. float is returned: the minimal value of `input` if `labels` is None,
  739. and the minimal value of elements where `labels` is greater than zero
  740. if `index` is None.
  741. See also
  742. --------
  743. label, maximum, median, minimum_position, extrema, sum, mean, variance,
  744. standard_deviation
  745. Notes
  746. -----
  747. The function returns a Python list and not a Numpy array, use
  748. `np.array` to convert the list to an array.
  749. Examples
  750. --------
  751. >>> from scipy import ndimage
  752. >>> a = np.array([[1, 2, 0, 0],
  753. ... [5, 3, 0, 4],
  754. ... [0, 0, 0, 7],
  755. ... [9, 3, 0, 0]])
  756. >>> labels, labels_nb = ndimage.label(a)
  757. >>> labels
  758. array([[1, 1, 0, 0],
  759. [1, 1, 0, 2],
  760. [0, 0, 0, 2],
  761. [3, 3, 0, 0]])
  762. >>> ndimage.minimum(a, labels=labels, index=np.arange(1, labels_nb + 1))
  763. [1.0, 4.0, 3.0]
  764. >>> ndimage.minimum(a)
  765. 0.0
  766. >>> ndimage.minimum(a, labels=labels)
  767. 1.0
  768. """
  769. return _select(input, labels, index, find_min=True)[0]
  770. def maximum(input, labels=None, index=None):
  771. """
  772. Calculate the maximum of the values of an array over labeled regions.
  773. Parameters
  774. ----------
  775. input : array_like
  776. Array_like of values. For each region specified by `labels`, the
  777. maximal values of `input` over the region is computed.
  778. labels : array_like, optional
  779. An array of integers marking different regions over which the
  780. maximum value of `input` is to be computed. `labels` must have the
  781. same shape as `input`. If `labels` is not specified, the maximum
  782. over the whole array is returned.
  783. index : array_like, optional
  784. A list of region labels that are taken into account for computing the
  785. maxima. If index is None, the maximum over all elements where `labels`
  786. is non-zero is returned.
  787. Returns
  788. -------
  789. output : float or list of floats
  790. List of maxima of `input` over the regions determined by `labels` and
  791. whose index is in `index`. If `index` or `labels` are not specified, a
  792. float is returned: the maximal value of `input` if `labels` is None,
  793. and the maximal value of elements where `labels` is greater than zero
  794. if `index` is None.
  795. See also
  796. --------
  797. label, minimum, median, maximum_position, extrema, sum, mean, variance,
  798. standard_deviation
  799. Notes
  800. -----
  801. The function returns a Python list and not a Numpy array, use
  802. `np.array` to convert the list to an array.
  803. Examples
  804. --------
  805. >>> a = np.arange(16).reshape((4,4))
  806. >>> a
  807. array([[ 0, 1, 2, 3],
  808. [ 4, 5, 6, 7],
  809. [ 8, 9, 10, 11],
  810. [12, 13, 14, 15]])
  811. >>> labels = np.zeros_like(a)
  812. >>> labels[:2,:2] = 1
  813. >>> labels[2:, 1:3] = 2
  814. >>> labels
  815. array([[1, 1, 0, 0],
  816. [1, 1, 0, 0],
  817. [0, 2, 2, 0],
  818. [0, 2, 2, 0]])
  819. >>> from scipy import ndimage
  820. >>> ndimage.maximum(a)
  821. 15.0
  822. >>> ndimage.maximum(a, labels=labels, index=[1,2])
  823. [5.0, 14.0]
  824. >>> ndimage.maximum(a, labels=labels)
  825. 14.0
  826. >>> b = np.array([[1, 2, 0, 0],
  827. ... [5, 3, 0, 4],
  828. ... [0, 0, 0, 7],
  829. ... [9, 3, 0, 0]])
  830. >>> labels, labels_nb = ndimage.label(b)
  831. >>> labels
  832. array([[1, 1, 0, 0],
  833. [1, 1, 0, 2],
  834. [0, 0, 0, 2],
  835. [3, 3, 0, 0]])
  836. >>> ndimage.maximum(b, labels=labels, index=np.arange(1, labels_nb + 1))
  837. [5.0, 7.0, 9.0]
  838. """
  839. return _select(input, labels, index, find_max=True)[0]
  840. def median(input, labels=None, index=None):
  841. """
  842. Calculate the median of the values of an array over labeled regions.
  843. Parameters
  844. ----------
  845. input : array_like
  846. Array_like of values. For each region specified by `labels`, the
  847. median value of `input` over the region is computed.
  848. labels : array_like, optional
  849. An array_like of integers marking different regions over which the
  850. median value of `input` is to be computed. `labels` must have the
  851. same shape as `input`. If `labels` is not specified, the median
  852. over the whole array is returned.
  853. index : array_like, optional
  854. A list of region labels that are taken into account for computing the
  855. medians. If index is None, the median over all elements where `labels`
  856. is non-zero is returned.
  857. Returns
  858. -------
  859. median : float or list of floats
  860. List of medians of `input` over the regions determined by `labels` and
  861. whose index is in `index`. If `index` or `labels` are not specified, a
  862. float is returned: the median value of `input` if `labels` is None,
  863. and the median value of elements where `labels` is greater than zero
  864. if `index` is None.
  865. See also
  866. --------
  867. label, minimum, maximum, extrema, sum, mean, variance, standard_deviation
  868. Notes
  869. -----
  870. The function returns a Python list and not a Numpy array, use
  871. `np.array` to convert the list to an array.
  872. Examples
  873. --------
  874. >>> from scipy import ndimage
  875. >>> a = np.array([[1, 2, 0, 1],
  876. ... [5, 3, 0, 4],
  877. ... [0, 0, 0, 7],
  878. ... [9, 3, 0, 0]])
  879. >>> labels, labels_nb = ndimage.label(a)
  880. >>> labels
  881. array([[1, 1, 0, 2],
  882. [1, 1, 0, 2],
  883. [0, 0, 0, 2],
  884. [3, 3, 0, 0]])
  885. >>> ndimage.median(a, labels=labels, index=np.arange(1, labels_nb + 1))
  886. [2.5, 4.0, 6.0]
  887. >>> ndimage.median(a)
  888. 1.0
  889. >>> ndimage.median(a, labels=labels)
  890. 3.0
  891. """
  892. return _select(input, labels, index, find_median=True)[0]
  893. def minimum_position(input, labels=None, index=None):
  894. """
  895. Find the positions of the minimums of the values of an array at labels.
  896. Parameters
  897. ----------
  898. input : array_like
  899. Array_like of values.
  900. labels : array_like, optional
  901. An array of integers marking different regions over which the
  902. position of the minimum value of `input` is to be computed.
  903. `labels` must have the same shape as `input`. If `labels` is not
  904. specified, the location of the first minimum over the whole
  905. array is returned.
  906. The `labels` argument only works when `index` is specified.
  907. index : array_like, optional
  908. A list of region labels that are taken into account for finding the
  909. location of the minima. If `index` is None, the ``first`` minimum
  910. over all elements where `labels` is non-zero is returned.
  911. The `index` argument only works when `labels` is specified.
  912. Returns
  913. -------
  914. output : list of tuples of ints
  915. Tuple of ints or list of tuples of ints that specify the location
  916. of minima of `input` over the regions determined by `labels` and
  917. whose index is in `index`.
  918. If `index` or `labels` are not specified, a tuple of ints is
  919. returned specifying the location of the first minimal value of `input`.
  920. See also
  921. --------
  922. label, minimum, median, maximum_position, extrema, sum, mean, variance,
  923. standard_deviation
  924. Examples
  925. --------
  926. >>> a = np.array([[10, 20, 30],
  927. ... [40, 80, 100],
  928. ... [1, 100, 200]])
  929. >>> b = np.array([[1, 2, 0, 1],
  930. ... [5, 3, 0, 4],
  931. ... [0, 0, 0, 7],
  932. ... [9, 3, 0, 0]])
  933. >>> from scipy import ndimage
  934. >>> ndimage.minimum_position(a)
  935. (2, 0)
  936. >>> ndimage.minimum_position(b)
  937. (0, 2)
  938. Features to process can be specified using `labels` and `index`:
  939. >>> label, pos = ndimage.label(a)
  940. >>> ndimage.minimum_position(a, label, index=np.arange(1, pos+1))
  941. [(2, 0)]
  942. >>> label, pos = ndimage.label(b)
  943. >>> ndimage.minimum_position(b, label, index=np.arange(1, pos+1))
  944. [(0, 0), (0, 3), (3, 1)]
  945. """
  946. dims = numpy.array(numpy.asarray(input).shape)
  947. # see numpy.unravel_index to understand this line.
  948. dim_prod = numpy.cumprod([1] + list(dims[:0:-1]))[::-1]
  949. result = _select(input, labels, index, find_min_positions=True)[0]
  950. if numpy.isscalar(result):
  951. return tuple((result // dim_prod) % dims)
  952. return [tuple(v) for v in (result.reshape(-1, 1) // dim_prod) % dims]
  953. def maximum_position(input, labels=None, index=None):
  954. """
  955. Find the positions of the maximums of the values of an array at labels.
  956. For each region specified by `labels`, the position of the maximum
  957. value of `input` within the region is returned.
  958. Parameters
  959. ----------
  960. input : array_like
  961. Array_like of values.
  962. labels : array_like, optional
  963. An array of integers marking different regions over which the
  964. position of the maximum value of `input` is to be computed.
  965. `labels` must have the same shape as `input`. If `labels` is not
  966. specified, the location of the first maximum over the whole
  967. array is returned.
  968. The `labels` argument only works when `index` is specified.
  969. index : array_like, optional
  970. A list of region labels that are taken into account for finding the
  971. location of the maxima. If `index` is None, the first maximum
  972. over all elements where `labels` is non-zero is returned.
  973. The `index` argument only works when `labels` is specified.
  974. Returns
  975. -------
  976. output : list of tuples of ints
  977. List of tuples of ints that specify the location of maxima of
  978. `input` over the regions determined by `labels` and whose index
  979. is in `index`.
  980. If `index` or `labels` are not specified, a tuple of ints is
  981. returned specifying the location of the ``first`` maximal value
  982. of `input`.
  983. See also
  984. --------
  985. label, minimum, median, maximum_position, extrema, sum, mean, variance,
  986. standard_deviation
  987. """
  988. dims = numpy.array(numpy.asarray(input).shape)
  989. # see numpy.unravel_index to understand this line.
  990. dim_prod = numpy.cumprod([1] + list(dims[:0:-1]))[::-1]
  991. result = _select(input, labels, index, find_max_positions=True)[0]
  992. if numpy.isscalar(result):
  993. return tuple((result // dim_prod) % dims)
  994. return [tuple(v) for v in (result.reshape(-1, 1) // dim_prod) % dims]
  995. def extrema(input, labels=None, index=None):
  996. """
  997. Calculate the minimums and maximums of the values of an array
  998. at labels, along with their positions.
  999. Parameters
  1000. ----------
  1001. input : ndarray
  1002. Nd-image data to process.
  1003. labels : ndarray, optional
  1004. Labels of features in input.
  1005. If not None, must be same shape as `input`.
  1006. index : int or sequence of ints, optional
  1007. Labels to include in output. If None (default), all values where
  1008. non-zero `labels` are used.
  1009. Returns
  1010. -------
  1011. minimums, maximums : int or ndarray
  1012. Values of minimums and maximums in each feature.
  1013. min_positions, max_positions : tuple or list of tuples
  1014. Each tuple gives the n-D coordinates of the corresponding minimum
  1015. or maximum.
  1016. See Also
  1017. --------
  1018. maximum, minimum, maximum_position, minimum_position, center_of_mass
  1019. Examples
  1020. --------
  1021. >>> a = np.array([[1, 2, 0, 0],
  1022. ... [5, 3, 0, 4],
  1023. ... [0, 0, 0, 7],
  1024. ... [9, 3, 0, 0]])
  1025. >>> from scipy import ndimage
  1026. >>> ndimage.extrema(a)
  1027. (0, 9, (0, 2), (3, 0))
  1028. Features to process can be specified using `labels` and `index`:
  1029. >>> lbl, nlbl = ndimage.label(a)
  1030. >>> ndimage.extrema(a, lbl, index=np.arange(1, nlbl+1))
  1031. (array([1, 4, 3]),
  1032. array([5, 7, 9]),
  1033. [(0, 0), (1, 3), (3, 1)],
  1034. [(1, 0), (2, 3), (3, 0)])
  1035. If no index is given, non-zero `labels` are processed:
  1036. >>> ndimage.extrema(a, lbl)
  1037. (1, 9, (0, 0), (3, 0))
  1038. """
  1039. dims = numpy.array(numpy.asarray(input).shape)
  1040. # see numpy.unravel_index to understand this line.
  1041. dim_prod = numpy.cumprod([1] + list(dims[:0:-1]))[::-1]
  1042. minimums, min_positions, maximums, max_positions = _select(input, labels,
  1043. index,
  1044. find_min=True,
  1045. find_max=True,
  1046. find_min_positions=True,
  1047. find_max_positions=True)
  1048. if numpy.isscalar(minimums):
  1049. return (minimums, maximums, tuple((min_positions // dim_prod) % dims),
  1050. tuple((max_positions // dim_prod) % dims))
  1051. min_positions = [tuple(v) for v in (min_positions.reshape(-1, 1) // dim_prod) % dims]
  1052. max_positions = [tuple(v) for v in (max_positions.reshape(-1, 1) // dim_prod) % dims]
  1053. return minimums, maximums, min_positions, max_positions
  1054. def center_of_mass(input, labels=None, index=None):
  1055. """
  1056. Calculate the center of mass of the values of an array at labels.
  1057. Parameters
  1058. ----------
  1059. input : ndarray
  1060. Data from which to calculate center-of-mass. The masses can either
  1061. be positive or negative.
  1062. labels : ndarray, optional
  1063. Labels for objects in `input`, as generated by `ndimage.label`.
  1064. Only used with `index`. Dimensions must be the same as `input`.
  1065. index : int or sequence of ints, optional
  1066. Labels for which to calculate centers-of-mass. If not specified,
  1067. all labels greater than zero are used. Only used with `labels`.
  1068. Returns
  1069. -------
  1070. center_of_mass : tuple, or list of tuples
  1071. Coordinates of centers-of-mass.
  1072. Examples
  1073. --------
  1074. >>> a = np.array(([0,0,0,0],
  1075. ... [0,1,1,0],
  1076. ... [0,1,1,0],
  1077. ... [0,1,1,0]))
  1078. >>> from scipy import ndimage
  1079. >>> ndimage.measurements.center_of_mass(a)
  1080. (2.0, 1.5)
  1081. Calculation of multiple objects in an image
  1082. >>> b = np.array(([0,1,1,0],
  1083. ... [0,1,0,0],
  1084. ... [0,0,0,0],
  1085. ... [0,0,1,1],
  1086. ... [0,0,1,1]))
  1087. >>> lbl = ndimage.label(b)[0]
  1088. >>> ndimage.measurements.center_of_mass(b, lbl, [1,2])
  1089. [(0.33333333333333331, 1.3333333333333333), (3.5, 2.5)]
  1090. Negative masses are also accepted, which can occur for example when
  1091. bias is removed from measured data due to random noise.
  1092. >>> c = np.array(([-1,0,0,0],
  1093. ... [0,-1,-1,0],
  1094. ... [0,1,-1,0],
  1095. ... [0,1,1,0]))
  1096. >>> ndimage.measurements.center_of_mass(c)
  1097. (-4.0, 1.0)
  1098. If there are division by zero issues, the function does not raise an
  1099. error but rather issues a RuntimeWarning before returning inf and/or NaN.
  1100. >>> d = np.array([-1, 1])
  1101. >>> ndimage.measurements.center_of_mass(d)
  1102. (inf,)
  1103. """
  1104. normalizer = sum(input, labels, index)
  1105. grids = numpy.ogrid[[slice(0, i) for i in input.shape]]
  1106. results = [sum(input * grids[dir].astype(float), labels, index) / normalizer
  1107. for dir in range(input.ndim)]
  1108. if numpy.isscalar(results[0]):
  1109. return tuple(results)
  1110. return [tuple(v) for v in numpy.array(results).T]
  1111. def histogram(input, min, max, bins, labels=None, index=None):
  1112. """
  1113. Calculate the histogram of the values of an array, optionally at labels.
  1114. Histogram calculates the frequency of values in an array within bins
  1115. determined by `min`, `max`, and `bins`. The `labels` and `index`
  1116. keywords can limit the scope of the histogram to specified sub-regions
  1117. within the array.
  1118. Parameters
  1119. ----------
  1120. input : array_like
  1121. Data for which to calculate histogram.
  1122. min, max : int
  1123. Minimum and maximum values of range of histogram bins.
  1124. bins : int
  1125. Number of bins.
  1126. labels : array_like, optional
  1127. Labels for objects in `input`.
  1128. If not None, must be same shape as `input`.
  1129. index : int or sequence of ints, optional
  1130. Label or labels for which to calculate histogram. If None, all values
  1131. where label is greater than zero are used
  1132. Returns
  1133. -------
  1134. hist : ndarray
  1135. Histogram counts.
  1136. Examples
  1137. --------
  1138. >>> a = np.array([[ 0. , 0.2146, 0.5962, 0. ],
  1139. ... [ 0. , 0.7778, 0. , 0. ],
  1140. ... [ 0. , 0. , 0. , 0. ],
  1141. ... [ 0. , 0. , 0.7181, 0.2787],
  1142. ... [ 0. , 0. , 0.6573, 0.3094]])
  1143. >>> from scipy import ndimage
  1144. >>> ndimage.measurements.histogram(a, 0, 1, 10)
  1145. array([13, 0, 2, 1, 0, 1, 1, 2, 0, 0])
  1146. With labels and no indices, non-zero elements are counted:
  1147. >>> lbl, nlbl = ndimage.label(a)
  1148. >>> ndimage.measurements.histogram(a, 0, 1, 10, lbl)
  1149. array([0, 0, 2, 1, 0, 1, 1, 2, 0, 0])
  1150. Indices can be used to count only certain objects:
  1151. >>> ndimage.measurements.histogram(a, 0, 1, 10, lbl, 2)
  1152. array([0, 0, 1, 1, 0, 0, 1, 1, 0, 0])
  1153. """
  1154. _bins = numpy.linspace(min, max, bins + 1)
  1155. def _hist(vals):
  1156. return numpy.histogram(vals, _bins)[0]
  1157. return labeled_comprehension(input, labels, index, _hist, object, None,
  1158. pass_positions=False)
  1159. def watershed_ift(input, markers, structure=None, output=None):
  1160. """
  1161. Apply watershed from markers using image foresting transform algorithm.
  1162. Parameters
  1163. ----------
  1164. input : array_like
  1165. Input.
  1166. markers : array_like
  1167. Markers are points within each watershed that form the beginning
  1168. of the process. Negative markers are considered background markers
  1169. which are processed after the other markers.
  1170. structure : structure element, optional
  1171. A structuring element defining the connectivity of the object can be
  1172. provided. If None, an element is generated with a squared
  1173. connectivity equal to one.
  1174. output : ndarray, optional
  1175. An output array can optionally be provided. The same shape as input.
  1176. Returns
  1177. -------
  1178. watershed_ift : ndarray
  1179. Output. Same shape as `input`.
  1180. References
  1181. ----------
  1182. .. [1] A.X. Falcao, J. Stolfi and R. de Alencar Lotufo, "The image
  1183. foresting transform: theory, algorithms, and applications",
  1184. Pattern Analysis and Machine Intelligence, vol. 26, pp. 19-29, 2004.
  1185. """
  1186. input = numpy.asarray(input)
  1187. if input.dtype.type not in [numpy.uint8, numpy.uint16]:
  1188. raise TypeError('only 8 and 16 unsigned inputs are supported')
  1189. if structure is None:
  1190. structure = morphology.generate_binary_structure(input.ndim, 1)
  1191. structure = numpy.asarray(structure, dtype=bool)
  1192. if structure.ndim != input.ndim:
  1193. raise RuntimeError('structure and input must have equal rank')
  1194. for ii in structure.shape:
  1195. if ii != 3:
  1196. raise RuntimeError('structure dimensions must be equal to 3')
  1197. if not structure.flags.contiguous:
  1198. structure = structure.copy()
  1199. markers = numpy.asarray(markers)
  1200. if input.shape != markers.shape:
  1201. raise RuntimeError('input and markers must have equal shape')
  1202. integral_types = [numpy.int0,
  1203. numpy.int8,
  1204. numpy.int16,
  1205. numpy.int32,
  1206. numpy.int_,
  1207. numpy.int64,
  1208. numpy.intc,
  1209. numpy.intp]
  1210. if markers.dtype.type not in integral_types:
  1211. raise RuntimeError('marker should be of integer type')
  1212. if isinstance(output, numpy.ndarray):
  1213. if output.dtype.type not in integral_types:
  1214. raise RuntimeError('output should be of integer type')
  1215. else:
  1216. output = markers.dtype
  1217. output = _ni_support._get_output(output, input)
  1218. _nd_image.watershed_ift(input, markers, structure, output)
  1219. return output