Coverage for /usr/lib/python3/dist-packages/scipy/ndimage/_measurements.py: 9%
325 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
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.
31import numpy
32import numpy as np
33from . import _ni_support
34from . import _ni_label
35from . import _nd_image
36from . import _morphology
38__all__ = ['label', 'find_objects', 'labeled_comprehension', 'sum', 'mean',
39 'variance', 'standard_deviation', 'minimum', 'maximum', 'median',
40 'minimum_position', 'maximum_position', 'extrema', 'center_of_mass',
41 'histogram', 'watershed_ift', 'sum_labels', 'value_indices']
44def label(input, structure=None, output=None):
45 """
46 Label features in an array.
48 Parameters
49 ----------
50 input : array_like
51 An array-like object to be labeled. Any non-zero values in `input` are
52 counted as features and zero values are considered the background.
53 structure : array_like, optional
54 A structuring element that defines feature connections.
55 `structure` must be centrosymmetric
56 (see Notes).
57 If no structuring element is provided,
58 one is automatically generated with a squared connectivity equal to
59 one. That is, for a 2-D `input` array, the default structuring element
60 is::
62 [[0,1,0],
63 [1,1,1],
64 [0,1,0]]
66 output : (None, data-type, array_like), optional
67 If `output` is a data type, it specifies the type of the resulting
68 labeled feature array.
69 If `output` is an array-like object, then `output` will be updated
70 with the labeled features from this function. This function can
71 operate in-place, by passing output=input.
72 Note that the output must be able to store the largest label, or this
73 function will raise an Exception.
75 Returns
76 -------
77 label : ndarray or int
78 An integer ndarray where each unique feature in `input` has a unique
79 label in the returned array.
80 num_features : int
81 How many objects were found.
83 If `output` is None, this function returns a tuple of
84 (`labeled_array`, `num_features`).
86 If `output` is a ndarray, then it will be updated with values in
87 `labeled_array` and only `num_features` will be returned by this
88 function.
90 See Also
91 --------
92 find_objects : generate a list of slices for the labeled features (or
93 objects); useful for finding features' position or
94 dimensions
96 Notes
97 -----
98 A centrosymmetric matrix is a matrix that is symmetric about the center.
99 See [1]_ for more information.
101 The `structure` matrix must be centrosymmetric to ensure
102 two-way connections.
103 For instance, if the `structure` matrix is not centrosymmetric
104 and is defined as::
106 [[0,1,0],
107 [1,1,0],
108 [0,0,0]]
110 and the `input` is::
112 [[1,2],
113 [0,3]]
115 then the structure matrix would indicate the
116 entry 2 in the input is connected to 1,
117 but 1 is not connected to 2.
119 Examples
120 --------
121 Create an image with some features, then label it using the default
122 (cross-shaped) structuring element:
124 >>> from scipy.ndimage import label, generate_binary_structure
125 >>> import numpy as np
126 >>> a = np.array([[0,0,1,1,0,0],
127 ... [0,0,0,1,0,0],
128 ... [1,1,0,0,1,0],
129 ... [0,0,0,1,0,0]])
130 >>> labeled_array, num_features = label(a)
132 Each of the 4 features are labeled with a different integer:
134 >>> num_features
135 4
136 >>> labeled_array
137 array([[0, 0, 1, 1, 0, 0],
138 [0, 0, 0, 1, 0, 0],
139 [2, 2, 0, 0, 3, 0],
140 [0, 0, 0, 4, 0, 0]])
142 Generate a structuring element that will consider features connected even
143 if they touch diagonally:
145 >>> s = generate_binary_structure(2,2)
147 or,
149 >>> s = [[1,1,1],
150 ... [1,1,1],
151 ... [1,1,1]]
153 Label the image using the new structuring element:
155 >>> labeled_array, num_features = label(a, structure=s)
157 Show the 2 labeled features (note that features 1, 3, and 4 from above are
158 now considered a single feature):
160 >>> num_features
161 2
162 >>> labeled_array
163 array([[0, 0, 1, 1, 0, 0],
164 [0, 0, 0, 1, 0, 0],
165 [2, 2, 0, 0, 1, 0],
166 [0, 0, 0, 1, 0, 0]])
168 References
169 ----------
171 .. [1] James R. Weaver, "Centrosymmetric (cross-symmetric)
172 matrices, their basic properties, eigenvalues, and
173 eigenvectors." The American Mathematical Monthly 92.10
174 (1985): 711-717.
176 """
177 input = numpy.asarray(input)
178 if numpy.iscomplexobj(input):
179 raise TypeError('Complex type not supported')
180 if structure is None:
181 structure = _morphology.generate_binary_structure(input.ndim, 1)
182 structure = numpy.asarray(structure, dtype=bool)
183 if structure.ndim != input.ndim:
184 raise RuntimeError('structure and input must have equal rank')
185 for ii in structure.shape:
186 if ii != 3:
187 raise ValueError('structure dimensions must be equal to 3')
189 # Use 32 bits if it's large enough for this image.
190 # _ni_label.label() needs two entries for background and
191 # foreground tracking
192 need_64bits = input.size >= (2**31 - 2)
194 if isinstance(output, numpy.ndarray):
195 if output.shape != input.shape:
196 raise ValueError("output shape not correct")
197 caller_provided_output = True
198 else:
199 caller_provided_output = False
200 if output is None:
201 output = np.empty(input.shape, np.intp if need_64bits else np.int32)
202 else:
203 output = np.empty(input.shape, output)
205 # handle scalars, 0-D arrays
206 if input.ndim == 0 or input.size == 0:
207 if input.ndim == 0:
208 # scalar
209 maxlabel = 1 if (input != 0) else 0
210 output[...] = maxlabel
211 else:
212 # 0-D
213 maxlabel = 0
214 if caller_provided_output:
215 return maxlabel
216 else:
217 return output, maxlabel
219 try:
220 max_label = _ni_label._label(input, structure, output)
221 except _ni_label.NeedMoreBits as e:
222 # Make another attempt with enough bits, then try to cast to the
223 # new type.
224 tmp_output = np.empty(input.shape, np.intp if need_64bits else np.int32)
225 max_label = _ni_label._label(input, structure, tmp_output)
226 output[...] = tmp_output[...]
227 if not np.all(output == tmp_output):
228 # refuse to return bad results
229 raise RuntimeError(
230 "insufficient bit-depth in requested output type"
231 ) from e
233 if caller_provided_output:
234 # result was written in-place
235 return max_label
236 else:
237 return output, max_label
240def find_objects(input, max_label=0):
241 """
242 Find objects in a labeled array.
244 Parameters
245 ----------
246 input : ndarray of ints
247 Array containing objects defined by different labels. Labels with
248 value 0 are ignored.
249 max_label : int, optional
250 Maximum label to be searched for in `input`. If max_label is not
251 given, the positions of all objects are returned.
253 Returns
254 -------
255 object_slices : list of tuples
256 A list of tuples, with each tuple containing N slices (with N the
257 dimension of the input array). Slices correspond to the minimal
258 parallelepiped that contains the object. If a number is missing,
259 None is returned instead of a slice. The label ``l`` corresponds to
260 the index ``l-1`` in the returned list.
262 See Also
263 --------
264 label, center_of_mass
266 Notes
267 -----
268 This function is very useful for isolating a volume of interest inside
269 a 3-D array, that cannot be "seen through".
271 Examples
272 --------
273 >>> from scipy import ndimage
274 >>> import numpy as np
275 >>> a = np.zeros((6,6), dtype=int)
276 >>> a[2:4, 2:4] = 1
277 >>> a[4, 4] = 1
278 >>> a[:2, :3] = 2
279 >>> a[0, 5] = 3
280 >>> a
281 array([[2, 2, 2, 0, 0, 3],
282 [2, 2, 2, 0, 0, 0],
283 [0, 0, 1, 1, 0, 0],
284 [0, 0, 1, 1, 0, 0],
285 [0, 0, 0, 0, 1, 0],
286 [0, 0, 0, 0, 0, 0]])
287 >>> ndimage.find_objects(a)
288 [(slice(2, 5, None), slice(2, 5, None)), (slice(0, 2, None), slice(0, 3, None)), (slice(0, 1, None), slice(5, 6, None))]
289 >>> ndimage.find_objects(a, max_label=2)
290 [(slice(2, 5, None), slice(2, 5, None)), (slice(0, 2, None), slice(0, 3, None))]
291 >>> ndimage.find_objects(a == 1, max_label=2)
292 [(slice(2, 5, None), slice(2, 5, None)), None]
294 >>> loc = ndimage.find_objects(a)[0]
295 >>> a[loc]
296 array([[1, 1, 0],
297 [1, 1, 0],
298 [0, 0, 1]])
300 """
301 input = numpy.asarray(input)
302 if numpy.iscomplexobj(input):
303 raise TypeError('Complex type not supported')
305 if max_label < 1:
306 max_label = input.max()
308 return _nd_image.find_objects(input, max_label)
311def value_indices(arr, *, ignore_value=None):
312 """
313 Find indices of each distinct value in given array.
315 Parameters
316 ----------
317 arr : ndarray of ints
318 Array containing integer values.
319 ignore_value : int, optional
320 This value will be ignored in searching the `arr` array. If not
321 given, all values found will be included in output. Default
322 is None.
324 Returns
325 -------
326 indices : dictionary
327 A Python dictionary of array indices for each distinct value. The
328 dictionary is keyed by the distinct values, the entries are array
329 index tuples covering all occurrences of the value within the
330 array.
332 This dictionary can occupy significant memory, usually several times
333 the size of the input array.
335 Notes
336 -----
337 For a small array with few distinct values, one might use
338 `numpy.unique()` to find all possible values, and ``(arr == val)`` to
339 locate each value within that array. However, for large arrays,
340 with many distinct values, this can become extremely inefficient,
341 as locating each value would require a new search through the entire
342 array. Using this function, there is essentially one search, with
343 the indices saved for all distinct values.
345 This is useful when matching a categorical image (e.g. a segmentation
346 or classification) to an associated image of other data, allowing
347 any per-class statistic(s) to then be calculated. Provides a
348 more flexible alternative to functions like ``scipy.ndimage.mean()``
349 and ``scipy.ndimage.variance()``.
351 Some other closely related functionality, with different strengths and
352 weaknesses, can also be found in ``scipy.stats.binned_statistic()`` and
353 the `scikit-image <https://scikit-image.org/>`_ function
354 ``skimage.measure.regionprops()``.
356 Note for IDL users: this provides functionality equivalent to IDL's
357 REVERSE_INDICES option (as per the IDL documentation for the
358 `HISTOGRAM <https://www.l3harrisgeospatial.com/docs/histogram.html>`_
359 function).
361 .. versionadded:: 1.10.0
363 See Also
364 --------
365 label, maximum, median, minimum_position, extrema, sum, mean, variance,
366 standard_deviation, numpy.where, numpy.unique
368 Examples
369 --------
370 >>> import numpy as np
371 >>> from scipy import ndimage
372 >>> a = np.zeros((6, 6), dtype=int)
373 >>> a[2:4, 2:4] = 1
374 >>> a[4, 4] = 1
375 >>> a[:2, :3] = 2
376 >>> a[0, 5] = 3
377 >>> a
378 array([[2, 2, 2, 0, 0, 3],
379 [2, 2, 2, 0, 0, 0],
380 [0, 0, 1, 1, 0, 0],
381 [0, 0, 1, 1, 0, 0],
382 [0, 0, 0, 0, 1, 0],
383 [0, 0, 0, 0, 0, 0]])
384 >>> val_indices = ndimage.value_indices(a)
386 The dictionary `val_indices` will have an entry for each distinct
387 value in the input array.
389 >>> val_indices.keys()
390 dict_keys([0, 1, 2, 3])
392 The entry for each value is an index tuple, locating the elements
393 with that value.
395 >>> ndx1 = val_indices[1]
396 >>> ndx1
397 (array([2, 2, 3, 3, 4]), array([2, 3, 2, 3, 4]))
399 This can be used to index into the original array, or any other
400 array with the same shape.
402 >>> a[ndx1]
403 array([1, 1, 1, 1, 1])
405 If the zeros were to be ignored, then the resulting dictionary
406 would no longer have an entry for zero.
408 >>> val_indices = ndimage.value_indices(a, ignore_value=0)
409 >>> val_indices.keys()
410 dict_keys([1, 2, 3])
412 """
413 # Cope with ignore_value being None, without too much extra complexity
414 # in the C code. If not None, the value is passed in as a numpy array
415 # with the same dtype as arr.
416 ignore_value_arr = numpy.zeros((1,), dtype=arr.dtype)
417 ignoreIsNone = (ignore_value is None)
418 if not ignoreIsNone:
419 ignore_value_arr[0] = ignore_value_arr.dtype.type(ignore_value)
421 val_indices = _nd_image.value_indices(arr, ignoreIsNone, ignore_value_arr)
422 return val_indices
425def labeled_comprehension(input, labels, index, func, out_dtype, default, pass_positions=False):
426 """
427 Roughly equivalent to [func(input[labels == i]) for i in index].
429 Sequentially applies an arbitrary function (that works on array_like input)
430 to subsets of an N-D image array specified by `labels` and `index`.
431 The option exists to provide the function with positional parameters as the
432 second argument.
434 Parameters
435 ----------
436 input : array_like
437 Data from which to select `labels` to process.
438 labels : array_like or None
439 Labels to objects in `input`.
440 If not None, array must be same shape as `input`.
441 If None, `func` is applied to raveled `input`.
442 index : int, sequence of ints or None
443 Subset of `labels` to which to apply `func`.
444 If a scalar, a single value is returned.
445 If None, `func` is applied to all non-zero values of `labels`.
446 func : callable
447 Python function to apply to `labels` from `input`.
448 out_dtype : dtype
449 Dtype to use for `result`.
450 default : int, float or None
451 Default return value when a element of `index` does not exist
452 in `labels`.
453 pass_positions : bool, optional
454 If True, pass linear indices to `func` as a second argument.
455 Default is False.
457 Returns
458 -------
459 result : ndarray
460 Result of applying `func` to each of `labels` to `input` in `index`.
462 Examples
463 --------
464 >>> import numpy as np
465 >>> a = np.array([[1, 2, 0, 0],
466 ... [5, 3, 0, 4],
467 ... [0, 0, 0, 7],
468 ... [9, 3, 0, 0]])
469 >>> from scipy import ndimage
470 >>> lbl, nlbl = ndimage.label(a)
471 >>> lbls = np.arange(1, nlbl+1)
472 >>> ndimage.labeled_comprehension(a, lbl, lbls, np.mean, float, 0)
473 array([ 2.75, 5.5 , 6. ])
475 Falling back to `default`:
477 >>> lbls = np.arange(1, nlbl+2)
478 >>> ndimage.labeled_comprehension(a, lbl, lbls, np.mean, float, -1)
479 array([ 2.75, 5.5 , 6. , -1. ])
481 Passing positions:
483 >>> def fn(val, pos):
484 ... print("fn says: %s : %s" % (val, pos))
485 ... return (val.sum()) if (pos.sum() % 2 == 0) else (-val.sum())
486 ...
487 >>> ndimage.labeled_comprehension(a, lbl, lbls, fn, float, 0, True)
488 fn says: [1 2 5 3] : [0 1 4 5]
489 fn says: [4 7] : [ 7 11]
490 fn says: [9 3] : [12 13]
491 array([ 11., 11., -12., 0.])
493 """
495 as_scalar = numpy.isscalar(index)
496 input = numpy.asarray(input)
498 if pass_positions:
499 positions = numpy.arange(input.size).reshape(input.shape)
501 if labels is None:
502 if index is not None:
503 raise ValueError("index without defined labels")
504 if not pass_positions:
505 return func(input.ravel())
506 else:
507 return func(input.ravel(), positions.ravel())
509 try:
510 input, labels = numpy.broadcast_arrays(input, labels)
511 except ValueError as e:
512 raise ValueError("input and labels must have the same shape "
513 "(excepting dimensions with width 1)") from e
515 if index is None:
516 if not pass_positions:
517 return func(input[labels > 0])
518 else:
519 return func(input[labels > 0], positions[labels > 0])
521 index = numpy.atleast_1d(index)
522 if np.any(index.astype(labels.dtype).astype(index.dtype) != index):
523 raise ValueError("Cannot convert index values from <%s> to <%s> "
524 "(labels' type) without loss of precision" %
525 (index.dtype, labels.dtype))
527 index = index.astype(labels.dtype)
529 # optimization: find min/max in index, and select those parts of labels, input, and positions
530 lo = index.min()
531 hi = index.max()
532 mask = (labels >= lo) & (labels <= hi)
534 # this also ravels the arrays
535 labels = labels[mask]
536 input = input[mask]
537 if pass_positions:
538 positions = positions[mask]
540 # sort everything by labels
541 label_order = labels.argsort()
542 labels = labels[label_order]
543 input = input[label_order]
544 if pass_positions:
545 positions = positions[label_order]
547 index_order = index.argsort()
548 sorted_index = index[index_order]
550 def do_map(inputs, output):
551 """labels must be sorted"""
552 nidx = sorted_index.size
554 # Find boundaries for each stretch of constant labels
555 # This could be faster, but we already paid N log N to sort labels.
556 lo = numpy.searchsorted(labels, sorted_index, side='left')
557 hi = numpy.searchsorted(labels, sorted_index, side='right')
559 for i, l, h in zip(range(nidx), lo, hi):
560 if l == h:
561 continue
562 output[i] = func(*[inp[l:h] for inp in inputs])
564 temp = numpy.empty(index.shape, out_dtype)
565 temp[:] = default
566 if not pass_positions:
567 do_map([input], temp)
568 else:
569 do_map([input, positions], temp)
571 output = numpy.zeros(index.shape, out_dtype)
572 output[index_order] = temp
573 if as_scalar:
574 output = output[0]
576 return output
579def _safely_castable_to_int(dt):
580 """Test whether the NumPy data type `dt` can be safely cast to an int."""
581 int_size = np.dtype(int).itemsize
582 safe = ((np.issubdtype(dt, np.signedinteger) and dt.itemsize <= int_size) or
583 (np.issubdtype(dt, np.unsignedinteger) and dt.itemsize < int_size))
584 return safe
587def _stats(input, labels=None, index=None, centered=False):
588 """Count, sum, and optionally compute (sum - centre)^2 of input by label
590 Parameters
591 ----------
592 input : array_like, N-D
593 The input data to be analyzed.
594 labels : array_like (N-D), optional
595 The labels of the data in `input`. This array must be broadcast
596 compatible with `input`; typically, it is the same shape as `input`.
597 If `labels` is None, all nonzero values in `input` are treated as
598 the single labeled group.
599 index : label or sequence of labels, optional
600 These are the labels of the groups for which the stats are computed.
601 If `index` is None, the stats are computed for the single group where
602 `labels` is greater than 0.
603 centered : bool, optional
604 If True, the centered sum of squares for each labeled group is
605 also returned. Default is False.
607 Returns
608 -------
609 counts : int or ndarray of ints
610 The number of elements in each labeled group.
611 sums : scalar or ndarray of scalars
612 The sums of the values in each labeled group.
613 sums_c : scalar or ndarray of scalars, optional
614 The sums of mean-centered squares of the values in each labeled group.
615 This is only returned if `centered` is True.
617 """
618 def single_group(vals):
619 if centered:
620 vals_c = vals - vals.mean()
621 return vals.size, vals.sum(), (vals_c * vals_c.conjugate()).sum()
622 else:
623 return vals.size, vals.sum()
625 if labels is None:
626 return single_group(input)
628 # ensure input and labels match sizes
629 input, labels = numpy.broadcast_arrays(input, labels)
631 if index is None:
632 return single_group(input[labels > 0])
634 if numpy.isscalar(index):
635 return single_group(input[labels == index])
637 def _sum_centered(labels):
638 # `labels` is expected to be an ndarray with the same shape as `input`.
639 # It must contain the label indices (which are not necessarily the labels
640 # themselves).
641 means = sums / counts
642 centered_input = input - means[labels]
643 # bincount expects 1-D inputs, so we ravel the arguments.
644 bc = numpy.bincount(labels.ravel(),
645 weights=(centered_input *
646 centered_input.conjugate()).ravel())
647 return bc
649 # Remap labels to unique integers if necessary, or if the largest
650 # label is larger than the number of values.
652 if (not _safely_castable_to_int(labels.dtype) or
653 labels.min() < 0 or labels.max() > labels.size):
654 # Use numpy.unique to generate the label indices. `new_labels` will
655 # be 1-D, but it should be interpreted as the flattened N-D array of
656 # label indices.
657 unique_labels, new_labels = numpy.unique(labels, return_inverse=True)
658 counts = numpy.bincount(new_labels)
659 sums = numpy.bincount(new_labels, weights=input.ravel())
660 if centered:
661 # Compute the sum of the mean-centered squares.
662 # We must reshape new_labels to the N-D shape of `input` before
663 # passing it _sum_centered.
664 sums_c = _sum_centered(new_labels.reshape(labels.shape))
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 allowed by bincount, and there aren't too
671 # many, so call bincount directly.
672 counts = numpy.bincount(labels.ravel())
673 sums = numpy.bincount(labels.ravel(), weights=input.ravel())
674 if centered:
675 sums_c = _sum_centered(labels)
676 # make sure all index values are valid
677 idxs = numpy.asanyarray(index, numpy.int_).copy()
678 found = (idxs >= 0) & (idxs < counts.size)
679 idxs[~found] = 0
681 counts = counts[idxs]
682 counts[~found] = 0
683 sums = sums[idxs]
684 sums[~found] = 0
686 if not centered:
687 return (counts, sums)
688 else:
689 sums_c = sums_c[idxs]
690 sums_c[~found] = 0
691 return (counts, sums, sums_c)
694def sum(input, labels=None, index=None):
695 """
696 Calculate the sum of the values of the array.
698 Notes
699 -----
700 This is an alias for `ndimage.sum_labels` kept for backwards compatibility
701 reasons, for new code please prefer `sum_labels`. See the `sum_labels`
702 docstring for more details.
704 """
705 return sum_labels(input, labels, index)
708def sum_labels(input, labels=None, index=None):
709 """
710 Calculate the sum of the values of the array.
712 Parameters
713 ----------
714 input : array_like
715 Values of `input` inside the regions defined by `labels`
716 are summed together.
717 labels : array_like of ints, optional
718 Assign labels to the values of the array. Has to have the same shape as
719 `input`.
720 index : array_like, optional
721 A single label number or a sequence of label numbers of
722 the objects to be measured.
724 Returns
725 -------
726 sum : ndarray or scalar
727 An array of the sums of values of `input` inside the regions defined
728 by `labels` with the same shape as `index`. If 'index' is None or scalar,
729 a scalar is returned.
731 See Also
732 --------
733 mean, median
735 Examples
736 --------
737 >>> from scipy import ndimage
738 >>> input = [0,1,2,3]
739 >>> labels = [1,1,2,2]
740 >>> ndimage.sum_labels(input, labels, index=[1,2])
741 [1.0, 5.0]
742 >>> ndimage.sum_labels(input, labels, index=1)
743 1
744 >>> ndimage.sum_labels(input, labels)
745 6
748 """
749 count, sum = _stats(input, labels, index)
750 return sum
753def mean(input, labels=None, index=None):
754 """
755 Calculate the mean of the values of an array at labels.
757 Parameters
758 ----------
759 input : array_like
760 Array on which to compute the mean of elements over distinct
761 regions.
762 labels : array_like, optional
763 Array of labels of same shape, or broadcastable to the same shape as
764 `input`. All elements sharing the same label form one region over
765 which the mean of the elements is computed.
766 index : int or sequence of ints, optional
767 Labels of the objects over which the mean is to be computed.
768 Default is None, in which case the mean for all values where label is
769 greater than 0 is calculated.
771 Returns
772 -------
773 out : list
774 Sequence of same length as `index`, with the mean of the different
775 regions labeled by the labels in `index`.
777 See Also
778 --------
779 variance, standard_deviation, minimum, maximum, sum, label
781 Examples
782 --------
783 >>> from scipy import ndimage
784 >>> import numpy as np
785 >>> a = np.arange(25).reshape((5,5))
786 >>> labels = np.zeros_like(a)
787 >>> labels[3:5,3:5] = 1
788 >>> index = np.unique(labels)
789 >>> labels
790 array([[0, 0, 0, 0, 0],
791 [0, 0, 0, 0, 0],
792 [0, 0, 0, 0, 0],
793 [0, 0, 0, 1, 1],
794 [0, 0, 0, 1, 1]])
795 >>> index
796 array([0, 1])
797 >>> ndimage.mean(a, labels=labels, index=index)
798 [10.285714285714286, 21.0]
800 """
802 count, sum = _stats(input, labels, index)
803 return sum / numpy.asanyarray(count).astype(numpy.float64)
806def variance(input, labels=None, index=None):
807 """
808 Calculate the variance of the values of an N-D image array, optionally at
809 specified sub-regions.
811 Parameters
812 ----------
813 input : array_like
814 Nd-image data to process.
815 labels : array_like, optional
816 Labels defining sub-regions in `input`.
817 If not None, must be same shape as `input`.
818 index : int or sequence of ints, optional
819 `labels` to include in output. If None (default), all values where
820 `labels` is non-zero are used.
822 Returns
823 -------
824 variance : float or ndarray
825 Values of variance, for each sub-region if `labels` and `index` are
826 specified.
828 See Also
829 --------
830 label, standard_deviation, maximum, minimum, extrema
832 Examples
833 --------
834 >>> import numpy as np
835 >>> a = np.array([[1, 2, 0, 0],
836 ... [5, 3, 0, 4],
837 ... [0, 0, 0, 7],
838 ... [9, 3, 0, 0]])
839 >>> from scipy import ndimage
840 >>> ndimage.variance(a)
841 7.609375
843 Features to process can be specified using `labels` and `index`:
845 >>> lbl, nlbl = ndimage.label(a)
846 >>> ndimage.variance(a, lbl, index=np.arange(1, nlbl+1))
847 array([ 2.1875, 2.25 , 9. ])
849 If no index is given, all non-zero `labels` are processed:
851 >>> ndimage.variance(a, lbl)
852 6.1875
854 """
855 count, sum, sum_c_sq = _stats(input, labels, index, centered=True)
856 return sum_c_sq / np.asanyarray(count).astype(float)
859def standard_deviation(input, labels=None, index=None):
860 """
861 Calculate the standard deviation of the values of an N-D image array,
862 optionally at specified sub-regions.
864 Parameters
865 ----------
866 input : array_like
867 N-D image data to process.
868 labels : array_like, optional
869 Labels to identify sub-regions in `input`.
870 If not None, must be same shape as `input`.
871 index : int or sequence of ints, optional
872 `labels` to include in output. If None (default), all values where
873 `labels` is non-zero are used.
875 Returns
876 -------
877 standard_deviation : float or ndarray
878 Values of standard deviation, for each sub-region if `labels` and
879 `index` are specified.
881 See Also
882 --------
883 label, variance, maximum, minimum, extrema
885 Examples
886 --------
887 >>> import numpy as np
888 >>> a = np.array([[1, 2, 0, 0],
889 ... [5, 3, 0, 4],
890 ... [0, 0, 0, 7],
891 ... [9, 3, 0, 0]])
892 >>> from scipy import ndimage
893 >>> ndimage.standard_deviation(a)
894 2.7585095613392387
896 Features to process can be specified using `labels` and `index`:
898 >>> lbl, nlbl = ndimage.label(a)
899 >>> ndimage.standard_deviation(a, lbl, index=np.arange(1, nlbl+1))
900 array([ 1.479, 1.5 , 3. ])
902 If no index is given, non-zero `labels` are processed:
904 >>> ndimage.standard_deviation(a, lbl)
905 2.4874685927665499
907 """
908 return numpy.sqrt(variance(input, labels, index))
911def _select(input, labels=None, index=None, find_min=False, find_max=False,
912 find_min_positions=False, find_max_positions=False,
913 find_median=False):
914 """Returns min, max, or both, plus their positions (if requested), and
915 median."""
917 input = numpy.asanyarray(input)
919 find_positions = find_min_positions or find_max_positions
920 positions = None
921 if find_positions:
922 positions = numpy.arange(input.size).reshape(input.shape)
924 def single_group(vals, positions):
925 result = []
926 if find_min:
927 result += [vals.min()]
928 if find_min_positions:
929 result += [positions[vals == vals.min()][0]]
930 if find_max:
931 result += [vals.max()]
932 if find_max_positions:
933 result += [positions[vals == vals.max()][0]]
934 if find_median:
935 result += [numpy.median(vals)]
936 return result
938 if labels is None:
939 return single_group(input, positions)
941 # ensure input and labels match sizes
942 input, labels = numpy.broadcast_arrays(input, labels)
944 if index is None:
945 mask = (labels > 0)
946 masked_positions = None
947 if find_positions:
948 masked_positions = positions[mask]
949 return single_group(input[mask], masked_positions)
951 if numpy.isscalar(index):
952 mask = (labels == index)
953 masked_positions = None
954 if find_positions:
955 masked_positions = positions[mask]
956 return single_group(input[mask], masked_positions)
958 # remap labels to unique integers if necessary, or if the largest
959 # label is larger than the number of values.
960 if (not _safely_castable_to_int(labels.dtype) or
961 labels.min() < 0 or labels.max() > labels.size):
962 # remap labels, and indexes
963 unique_labels, labels = numpy.unique(labels, return_inverse=True)
964 idxs = numpy.searchsorted(unique_labels, index)
966 # make all of idxs valid
967 idxs[idxs >= unique_labels.size] = 0
968 found = (unique_labels[idxs] == index)
969 else:
970 # labels are an integer type, and there aren't too many
971 idxs = numpy.asanyarray(index, numpy.int_).copy()
972 found = (idxs >= 0) & (idxs <= labels.max())
974 idxs[~ found] = labels.max() + 1
976 if find_median:
977 order = numpy.lexsort((input.ravel(), labels.ravel()))
978 else:
979 order = input.ravel().argsort()
980 input = input.ravel()[order]
981 labels = labels.ravel()[order]
982 if find_positions:
983 positions = positions.ravel()[order]
985 result = []
986 if find_min:
987 mins = numpy.zeros(labels.max() + 2, input.dtype)
988 mins[labels[::-1]] = input[::-1]
989 result += [mins[idxs]]
990 if find_min_positions:
991 minpos = numpy.zeros(labels.max() + 2, int)
992 minpos[labels[::-1]] = positions[::-1]
993 result += [minpos[idxs]]
994 if find_max:
995 maxs = numpy.zeros(labels.max() + 2, input.dtype)
996 maxs[labels] = input
997 result += [maxs[idxs]]
998 if find_max_positions:
999 maxpos = numpy.zeros(labels.max() + 2, int)
1000 maxpos[labels] = positions
1001 result += [maxpos[idxs]]
1002 if find_median:
1003 locs = numpy.arange(len(labels))
1004 lo = numpy.zeros(labels.max() + 2, numpy.int_)
1005 lo[labels[::-1]] = locs[::-1]
1006 hi = numpy.zeros(labels.max() + 2, numpy.int_)
1007 hi[labels] = locs
1008 lo = lo[idxs]
1009 hi = hi[idxs]
1010 # lo is an index to the lowest value in input for each label,
1011 # hi is an index to the largest value.
1012 # move them to be either the same ((hi - lo) % 2 == 0) or next
1013 # to each other ((hi - lo) % 2 == 1), then average.
1014 step = (hi - lo) // 2
1015 lo += step
1016 hi -= step
1017 if (np.issubdtype(input.dtype, np.integer)
1018 or np.issubdtype(input.dtype, np.bool_)):
1019 # avoid integer overflow or boolean addition (gh-12836)
1020 result += [(input[lo].astype('d') + input[hi].astype('d')) / 2.0]
1021 else:
1022 result += [(input[lo] + input[hi]) / 2.0]
1024 return result
1027def minimum(input, labels=None, index=None):
1028 """
1029 Calculate the minimum of the values of an array over labeled regions.
1031 Parameters
1032 ----------
1033 input : array_like
1034 Array_like of values. For each region specified by `labels`, the
1035 minimal values of `input` over the region is computed.
1036 labels : array_like, optional
1037 An array_like of integers marking different regions over which the
1038 minimum value of `input` is to be computed. `labels` must have the
1039 same shape as `input`. If `labels` is not specified, the minimum
1040 over the whole array is returned.
1041 index : array_like, optional
1042 A list of region labels that are taken into account for computing the
1043 minima. If index is None, the minimum over all elements where `labels`
1044 is non-zero is returned.
1046 Returns
1047 -------
1048 minimum : float or list of floats
1049 List of minima of `input` over the regions determined by `labels` and
1050 whose index is in `index`. If `index` or `labels` are not specified, a
1051 float is returned: the minimal value of `input` if `labels` is None,
1052 and the minimal value of elements where `labels` is greater than zero
1053 if `index` is None.
1055 See Also
1056 --------
1057 label, maximum, median, minimum_position, extrema, sum, mean, variance,
1058 standard_deviation
1060 Notes
1061 -----
1062 The function returns a Python list and not a NumPy array, use
1063 `np.array` to convert the list to an array.
1065 Examples
1066 --------
1067 >>> from scipy import ndimage
1068 >>> import numpy as np
1069 >>> a = np.array([[1, 2, 0, 0],
1070 ... [5, 3, 0, 4],
1071 ... [0, 0, 0, 7],
1072 ... [9, 3, 0, 0]])
1073 >>> labels, labels_nb = ndimage.label(a)
1074 >>> labels
1075 array([[1, 1, 0, 0],
1076 [1, 1, 0, 2],
1077 [0, 0, 0, 2],
1078 [3, 3, 0, 0]])
1079 >>> ndimage.minimum(a, labels=labels, index=np.arange(1, labels_nb + 1))
1080 [1.0, 4.0, 3.0]
1081 >>> ndimage.minimum(a)
1082 0.0
1083 >>> ndimage.minimum(a, labels=labels)
1084 1.0
1086 """
1087 return _select(input, labels, index, find_min=True)[0]
1090def maximum(input, labels=None, index=None):
1091 """
1092 Calculate the maximum of the values of an array over labeled regions.
1094 Parameters
1095 ----------
1096 input : array_like
1097 Array_like of values. For each region specified by `labels`, the
1098 maximal values of `input` over the region is computed.
1099 labels : array_like, optional
1100 An array of integers marking different regions over which the
1101 maximum value of `input` is to be computed. `labels` must have the
1102 same shape as `input`. If `labels` is not specified, the maximum
1103 over the whole array is returned.
1104 index : array_like, optional
1105 A list of region labels that are taken into account for computing the
1106 maxima. If index is None, the maximum over all elements where `labels`
1107 is non-zero is returned.
1109 Returns
1110 -------
1111 output : float or list of floats
1112 List of maxima of `input` over the regions determined by `labels` and
1113 whose index is in `index`. If `index` or `labels` are not specified, a
1114 float is returned: the maximal value of `input` if `labels` is None,
1115 and the maximal value of elements where `labels` is greater than zero
1116 if `index` is None.
1118 See Also
1119 --------
1120 label, minimum, median, maximum_position, extrema, sum, mean, variance,
1121 standard_deviation
1123 Notes
1124 -----
1125 The function returns a Python list and not a NumPy array, use
1126 `np.array` to convert the list to an array.
1128 Examples
1129 --------
1130 >>> import numpy as np
1131 >>> a = np.arange(16).reshape((4,4))
1132 >>> a
1133 array([[ 0, 1, 2, 3],
1134 [ 4, 5, 6, 7],
1135 [ 8, 9, 10, 11],
1136 [12, 13, 14, 15]])
1137 >>> labels = np.zeros_like(a)
1138 >>> labels[:2,:2] = 1
1139 >>> labels[2:, 1:3] = 2
1140 >>> labels
1141 array([[1, 1, 0, 0],
1142 [1, 1, 0, 0],
1143 [0, 2, 2, 0],
1144 [0, 2, 2, 0]])
1145 >>> from scipy import ndimage
1146 >>> ndimage.maximum(a)
1147 15.0
1148 >>> ndimage.maximum(a, labels=labels, index=[1,2])
1149 [5.0, 14.0]
1150 >>> ndimage.maximum(a, labels=labels)
1151 14.0
1153 >>> b = np.array([[1, 2, 0, 0],
1154 ... [5, 3, 0, 4],
1155 ... [0, 0, 0, 7],
1156 ... [9, 3, 0, 0]])
1157 >>> labels, labels_nb = ndimage.label(b)
1158 >>> labels
1159 array([[1, 1, 0, 0],
1160 [1, 1, 0, 2],
1161 [0, 0, 0, 2],
1162 [3, 3, 0, 0]])
1163 >>> ndimage.maximum(b, labels=labels, index=np.arange(1, labels_nb + 1))
1164 [5.0, 7.0, 9.0]
1166 """
1167 return _select(input, labels, index, find_max=True)[0]
1170def median(input, labels=None, index=None):
1171 """
1172 Calculate the median of the values of an array over labeled regions.
1174 Parameters
1175 ----------
1176 input : array_like
1177 Array_like of values. For each region specified by `labels`, the
1178 median value of `input` over the region is computed.
1179 labels : array_like, optional
1180 An array_like of integers marking different regions over which the
1181 median value of `input` is to be computed. `labels` must have the
1182 same shape as `input`. If `labels` is not specified, the median
1183 over the whole array is returned.
1184 index : array_like, optional
1185 A list of region labels that are taken into account for computing the
1186 medians. If index is None, the median over all elements where `labels`
1187 is non-zero is returned.
1189 Returns
1190 -------
1191 median : float or list of floats
1192 List of medians of `input` over the regions determined by `labels` and
1193 whose index is in `index`. If `index` or `labels` are not specified, a
1194 float is returned: the median value of `input` if `labels` is None,
1195 and the median value of elements where `labels` is greater than zero
1196 if `index` is None.
1198 See Also
1199 --------
1200 label, minimum, maximum, extrema, sum, mean, variance, standard_deviation
1202 Notes
1203 -----
1204 The function returns a Python list and not a NumPy array, use
1205 `np.array` to convert the list to an array.
1207 Examples
1208 --------
1209 >>> from scipy import ndimage
1210 >>> import numpy as np
1211 >>> a = np.array([[1, 2, 0, 1],
1212 ... [5, 3, 0, 4],
1213 ... [0, 0, 0, 7],
1214 ... [9, 3, 0, 0]])
1215 >>> labels, labels_nb = ndimage.label(a)
1216 >>> labels
1217 array([[1, 1, 0, 2],
1218 [1, 1, 0, 2],
1219 [0, 0, 0, 2],
1220 [3, 3, 0, 0]])
1221 >>> ndimage.median(a, labels=labels, index=np.arange(1, labels_nb + 1))
1222 [2.5, 4.0, 6.0]
1223 >>> ndimage.median(a)
1224 1.0
1225 >>> ndimage.median(a, labels=labels)
1226 3.0
1228 """
1229 return _select(input, labels, index, find_median=True)[0]
1232def minimum_position(input, labels=None, index=None):
1233 """
1234 Find the positions of the minimums of the values of an array at labels.
1236 Parameters
1237 ----------
1238 input : array_like
1239 Array_like of values.
1240 labels : array_like, optional
1241 An array of integers marking different regions over which the
1242 position of the minimum value of `input` is to be computed.
1243 `labels` must have the same shape as `input`. If `labels` is not
1244 specified, the location of the first minimum over the whole
1245 array is returned.
1247 The `labels` argument only works when `index` is specified.
1248 index : array_like, optional
1249 A list of region labels that are taken into account for finding the
1250 location of the minima. If `index` is None, the ``first`` minimum
1251 over all elements where `labels` is non-zero is returned.
1253 The `index` argument only works when `labels` is specified.
1255 Returns
1256 -------
1257 output : list of tuples of ints
1258 Tuple of ints or list of tuples of ints that specify the location
1259 of minima of `input` over the regions determined by `labels` and
1260 whose index is in `index`.
1262 If `index` or `labels` are not specified, a tuple of ints is
1263 returned specifying the location of the first minimal value of `input`.
1265 See Also
1266 --------
1267 label, minimum, median, maximum_position, extrema, sum, mean, variance,
1268 standard_deviation
1270 Examples
1271 --------
1272 >>> import numpy as np
1273 >>> a = np.array([[10, 20, 30],
1274 ... [40, 80, 100],
1275 ... [1, 100, 200]])
1276 >>> b = np.array([[1, 2, 0, 1],
1277 ... [5, 3, 0, 4],
1278 ... [0, 0, 0, 7],
1279 ... [9, 3, 0, 0]])
1281 >>> from scipy import ndimage
1283 >>> ndimage.minimum_position(a)
1284 (2, 0)
1285 >>> ndimage.minimum_position(b)
1286 (0, 2)
1288 Features to process can be specified using `labels` and `index`:
1290 >>> label, pos = ndimage.label(a)
1291 >>> ndimage.minimum_position(a, label, index=np.arange(1, pos+1))
1292 [(2, 0)]
1294 >>> label, pos = ndimage.label(b)
1295 >>> ndimage.minimum_position(b, label, index=np.arange(1, pos+1))
1296 [(0, 0), (0, 3), (3, 1)]
1298 """
1299 dims = numpy.array(numpy.asarray(input).shape)
1300 # see numpy.unravel_index to understand this line.
1301 dim_prod = numpy.cumprod([1] + list(dims[:0:-1]))[::-1]
1303 result = _select(input, labels, index, find_min_positions=True)[0]
1305 if numpy.isscalar(result):
1306 return tuple((result // dim_prod) % dims)
1308 return [tuple(v) for v in (result.reshape(-1, 1) // dim_prod) % dims]
1311def maximum_position(input, labels=None, index=None):
1312 """
1313 Find the positions of the maximums of the values of an array at labels.
1315 For each region specified by `labels`, the position of the maximum
1316 value of `input` within the region is returned.
1318 Parameters
1319 ----------
1320 input : array_like
1321 Array_like of values.
1322 labels : array_like, optional
1323 An array of integers marking different regions over which the
1324 position of the maximum value of `input` is to be computed.
1325 `labels` must have the same shape as `input`. If `labels` is not
1326 specified, the location of the first maximum over the whole
1327 array is returned.
1329 The `labels` argument only works when `index` is specified.
1330 index : array_like, optional
1331 A list of region labels that are taken into account for finding the
1332 location of the maxima. If `index` is None, the first maximum
1333 over all elements where `labels` is non-zero is returned.
1335 The `index` argument only works when `labels` is specified.
1337 Returns
1338 -------
1339 output : list of tuples of ints
1340 List of tuples of ints that specify the location of maxima of
1341 `input` over the regions determined by `labels` and whose index
1342 is in `index`.
1344 If `index` or `labels` are not specified, a tuple of ints is
1345 returned specifying the location of the ``first`` maximal value
1346 of `input`.
1348 See also
1349 --------
1350 label, minimum, median, maximum_position, extrema, sum, mean, variance,
1351 standard_deviation
1353 Examples
1354 --------
1355 >>> from scipy import ndimage
1356 >>> import numpy as np
1357 >>> a = np.array([[1, 2, 0, 0],
1358 ... [5, 3, 0, 4],
1359 ... [0, 0, 0, 7],
1360 ... [9, 3, 0, 0]])
1361 >>> ndimage.maximum_position(a)
1362 (3, 0)
1364 Features to process can be specified using `labels` and `index`:
1366 >>> lbl = np.array([[0, 1, 2, 3],
1367 ... [0, 1, 2, 3],
1368 ... [0, 1, 2, 3],
1369 ... [0, 1, 2, 3]])
1370 >>> ndimage.maximum_position(a, lbl, 1)
1371 (1, 1)
1373 If no index is given, non-zero `labels` are processed:
1375 >>> ndimage.maximum_position(a, lbl)
1376 (2, 3)
1378 If there are no maxima, the position of the first element is returned:
1380 >>> ndimage.maximum_position(a, lbl, 2)
1381 (0, 2)
1383 """
1384 dims = numpy.array(numpy.asarray(input).shape)
1385 # see numpy.unravel_index to understand this line.
1386 dim_prod = numpy.cumprod([1] + list(dims[:0:-1]))[::-1]
1388 result = _select(input, labels, index, find_max_positions=True)[0]
1390 if numpy.isscalar(result):
1391 return tuple((result // dim_prod) % dims)
1393 return [tuple(v) for v in (result.reshape(-1, 1) // dim_prod) % dims]
1396def extrema(input, labels=None, index=None):
1397 """
1398 Calculate the minimums and maximums of the values of an array
1399 at labels, along with their positions.
1401 Parameters
1402 ----------
1403 input : ndarray
1404 N-D image data to process.
1405 labels : ndarray, optional
1406 Labels of features in input.
1407 If not None, must be same shape as `input`.
1408 index : int or sequence of ints, optional
1409 Labels to include in output. If None (default), all values where
1410 non-zero `labels` are used.
1412 Returns
1413 -------
1414 minimums, maximums : int or ndarray
1415 Values of minimums and maximums in each feature.
1416 min_positions, max_positions : tuple or list of tuples
1417 Each tuple gives the N-D coordinates of the corresponding minimum
1418 or maximum.
1420 See Also
1421 --------
1422 maximum, minimum, maximum_position, minimum_position, center_of_mass
1424 Examples
1425 --------
1426 >>> import numpy as np
1427 >>> a = np.array([[1, 2, 0, 0],
1428 ... [5, 3, 0, 4],
1429 ... [0, 0, 0, 7],
1430 ... [9, 3, 0, 0]])
1431 >>> from scipy import ndimage
1432 >>> ndimage.extrema(a)
1433 (0, 9, (0, 2), (3, 0))
1435 Features to process can be specified using `labels` and `index`:
1437 >>> lbl, nlbl = ndimage.label(a)
1438 >>> ndimage.extrema(a, lbl, index=np.arange(1, nlbl+1))
1439 (array([1, 4, 3]),
1440 array([5, 7, 9]),
1441 [(0, 0), (1, 3), (3, 1)],
1442 [(1, 0), (2, 3), (3, 0)])
1444 If no index is given, non-zero `labels` are processed:
1446 >>> ndimage.extrema(a, lbl)
1447 (1, 9, (0, 0), (3, 0))
1449 """
1450 dims = numpy.array(numpy.asarray(input).shape)
1451 # see numpy.unravel_index to understand this line.
1452 dim_prod = numpy.cumprod([1] + list(dims[:0:-1]))[::-1]
1454 minimums, min_positions, maximums, max_positions = _select(input, labels,
1455 index,
1456 find_min=True,
1457 find_max=True,
1458 find_min_positions=True,
1459 find_max_positions=True)
1461 if numpy.isscalar(minimums):
1462 return (minimums, maximums, tuple((min_positions // dim_prod) % dims),
1463 tuple((max_positions // dim_prod) % dims))
1465 min_positions = [tuple(v) for v in (min_positions.reshape(-1, 1) // dim_prod) % dims]
1466 max_positions = [tuple(v) for v in (max_positions.reshape(-1, 1) // dim_prod) % dims]
1468 return minimums, maximums, min_positions, max_positions
1471def center_of_mass(input, labels=None, index=None):
1472 """
1473 Calculate the center of mass of the values of an array at labels.
1475 Parameters
1476 ----------
1477 input : ndarray
1478 Data from which to calculate center-of-mass. The masses can either
1479 be positive or negative.
1480 labels : ndarray, optional
1481 Labels for objects in `input`, as generated by `ndimage.label`.
1482 Only used with `index`. Dimensions must be the same as `input`.
1483 index : int or sequence of ints, optional
1484 Labels for which to calculate centers-of-mass. If not specified,
1485 the combined center of mass of all labels greater than zero
1486 will be calculated. Only used with `labels`.
1488 Returns
1489 -------
1490 center_of_mass : tuple, or list of tuples
1491 Coordinates of centers-of-mass.
1493 Examples
1494 --------
1495 >>> import numpy as np
1496 >>> a = np.array(([0,0,0,0],
1497 ... [0,1,1,0],
1498 ... [0,1,1,0],
1499 ... [0,1,1,0]))
1500 >>> from scipy import ndimage
1501 >>> ndimage.center_of_mass(a)
1502 (2.0, 1.5)
1504 Calculation of multiple objects in an image
1506 >>> b = np.array(([0,1,1,0],
1507 ... [0,1,0,0],
1508 ... [0,0,0,0],
1509 ... [0,0,1,1],
1510 ... [0,0,1,1]))
1511 >>> lbl = ndimage.label(b)[0]
1512 >>> ndimage.center_of_mass(b, lbl, [1,2])
1513 [(0.33333333333333331, 1.3333333333333333), (3.5, 2.5)]
1515 Negative masses are also accepted, which can occur for example when
1516 bias is removed from measured data due to random noise.
1518 >>> c = np.array(([-1,0,0,0],
1519 ... [0,-1,-1,0],
1520 ... [0,1,-1,0],
1521 ... [0,1,1,0]))
1522 >>> ndimage.center_of_mass(c)
1523 (-4.0, 1.0)
1525 If there are division by zero issues, the function does not raise an
1526 error but rather issues a RuntimeWarning before returning inf and/or NaN.
1528 >>> d = np.array([-1, 1])
1529 >>> ndimage.center_of_mass(d)
1530 (inf,)
1531 """
1532 normalizer = sum(input, labels, index)
1533 grids = numpy.ogrid[[slice(0, i) for i in input.shape]]
1535 results = [sum(input * grids[dir].astype(float), labels, index) / normalizer
1536 for dir in range(input.ndim)]
1538 if numpy.isscalar(results[0]):
1539 return tuple(results)
1541 return [tuple(v) for v in numpy.array(results).T]
1544def histogram(input, min, max, bins, labels=None, index=None):
1545 """
1546 Calculate the histogram of the values of an array, optionally at labels.
1548 Histogram calculates the frequency of values in an array within bins
1549 determined by `min`, `max`, and `bins`. The `labels` and `index`
1550 keywords can limit the scope of the histogram to specified sub-regions
1551 within the array.
1553 Parameters
1554 ----------
1555 input : array_like
1556 Data for which to calculate histogram.
1557 min, max : int
1558 Minimum and maximum values of range of histogram bins.
1559 bins : int
1560 Number of bins.
1561 labels : array_like, optional
1562 Labels for objects in `input`.
1563 If not None, must be same shape as `input`.
1564 index : int or sequence of ints, optional
1565 Label or labels for which to calculate histogram. If None, all values
1566 where label is greater than zero are used
1568 Returns
1569 -------
1570 hist : ndarray
1571 Histogram counts.
1573 Examples
1574 --------
1575 >>> import numpy as np
1576 >>> a = np.array([[ 0. , 0.2146, 0.5962, 0. ],
1577 ... [ 0. , 0.7778, 0. , 0. ],
1578 ... [ 0. , 0. , 0. , 0. ],
1579 ... [ 0. , 0. , 0.7181, 0.2787],
1580 ... [ 0. , 0. , 0.6573, 0.3094]])
1581 >>> from scipy import ndimage
1582 >>> ndimage.histogram(a, 0, 1, 10)
1583 array([13, 0, 2, 1, 0, 1, 1, 2, 0, 0])
1585 With labels and no indices, non-zero elements are counted:
1587 >>> lbl, nlbl = ndimage.label(a)
1588 >>> ndimage.histogram(a, 0, 1, 10, lbl)
1589 array([0, 0, 2, 1, 0, 1, 1, 2, 0, 0])
1591 Indices can be used to count only certain objects:
1593 >>> ndimage.histogram(a, 0, 1, 10, lbl, 2)
1594 array([0, 0, 1, 1, 0, 0, 1, 1, 0, 0])
1596 """
1597 _bins = numpy.linspace(min, max, bins + 1)
1599 def _hist(vals):
1600 return numpy.histogram(vals, _bins)[0]
1602 return labeled_comprehension(input, labels, index, _hist, object, None,
1603 pass_positions=False)
1606def watershed_ift(input, markers, structure=None, output=None):
1607 """
1608 Apply watershed from markers using image foresting transform algorithm.
1610 Parameters
1611 ----------
1612 input : array_like
1613 Input.
1614 markers : array_like
1615 Markers are points within each watershed that form the beginning
1616 of the process. Negative markers are considered background markers
1617 which are processed after the other markers.
1618 structure : structure element, optional
1619 A structuring element defining the connectivity of the object can be
1620 provided. If None, an element is generated with a squared
1621 connectivity equal to one.
1622 output : ndarray, optional
1623 An output array can optionally be provided. The same shape as input.
1625 Returns
1626 -------
1627 watershed_ift : ndarray
1628 Output. Same shape as `input`.
1630 References
1631 ----------
1632 .. [1] A.X. Falcao, J. Stolfi and R. de Alencar Lotufo, "The image
1633 foresting transform: theory, algorithms, and applications",
1634 Pattern Analysis and Machine Intelligence, vol. 26, pp. 19-29, 2004.
1636 """
1637 input = numpy.asarray(input)
1638 if input.dtype.type not in [numpy.uint8, numpy.uint16]:
1639 raise TypeError('only 8 and 16 unsigned inputs are supported')
1641 if structure is None:
1642 structure = _morphology.generate_binary_structure(input.ndim, 1)
1643 structure = numpy.asarray(structure, dtype=bool)
1644 if structure.ndim != input.ndim:
1645 raise RuntimeError('structure and input must have equal rank')
1646 for ii in structure.shape:
1647 if ii != 3:
1648 raise RuntimeError('structure dimensions must be equal to 3')
1650 if not structure.flags.contiguous:
1651 structure = structure.copy()
1652 markers = numpy.asarray(markers)
1653 if input.shape != markers.shape:
1654 raise RuntimeError('input and markers must have equal shape')
1656 integral_types = [numpy.int8,
1657 numpy.int16,
1658 numpy.int32,
1659 numpy.int_,
1660 numpy.int64,
1661 numpy.intc,
1662 numpy.intp]
1664 if markers.dtype.type not in integral_types:
1665 raise RuntimeError('marker should be of integer type')
1667 if isinstance(output, numpy.ndarray):
1668 if output.dtype.type not in integral_types:
1669 raise RuntimeError('output should be of integer type')
1670 else:
1671 output = markers.dtype
1673 output = _ni_support._get_output(output, input)
1674 _nd_image.watershed_ift(input, markers, structure, output)
1675 return output