Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/scipy/ndimage/_measurements.py: 9%
325 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-12 06:31 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-12 06:31 +0000
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.
261 See Also
262 --------
263 label, center_of_mass
265 Notes
266 -----
267 This function is very useful for isolating a volume of interest inside
268 a 3-D array, that cannot be "seen through".
270 Examples
271 --------
272 >>> from scipy import ndimage
273 >>> import numpy as np
274 >>> a = np.zeros((6,6), dtype=int)
275 >>> a[2:4, 2:4] = 1
276 >>> a[4, 4] = 1
277 >>> a[:2, :3] = 2
278 >>> a[0, 5] = 3
279 >>> a
280 array([[2, 2, 2, 0, 0, 3],
281 [2, 2, 2, 0, 0, 0],
282 [0, 0, 1, 1, 0, 0],
283 [0, 0, 1, 1, 0, 0],
284 [0, 0, 0, 0, 1, 0],
285 [0, 0, 0, 0, 0, 0]])
286 >>> ndimage.find_objects(a)
287 [(slice(2, 5, None), slice(2, 5, None)), (slice(0, 2, None), slice(0, 3, None)), (slice(0, 1, None), slice(5, 6, None))]
288 >>> ndimage.find_objects(a, max_label=2)
289 [(slice(2, 5, None), slice(2, 5, None)), (slice(0, 2, None), slice(0, 3, None))]
290 >>> ndimage.find_objects(a == 1, max_label=2)
291 [(slice(2, 5, None), slice(2, 5, None)), None]
293 >>> loc = ndimage.find_objects(a)[0]
294 >>> a[loc]
295 array([[1, 1, 0],
296 [1, 1, 0],
297 [0, 0, 1]])
299 """
300 input = numpy.asarray(input)
301 if numpy.iscomplexobj(input):
302 raise TypeError('Complex type not supported')
304 if max_label < 1:
305 max_label = input.max()
307 return _nd_image.find_objects(input, max_label)
310def value_indices(arr, *, ignore_value=None):
311 """
312 Find indices of each distinct value in given array.
314 Parameters
315 ----------
316 arr : ndarray of ints
317 Array containing integer values.
318 ignore_value : int, optional
319 This value will be ignored in searching the `arr` array. If not
320 given, all values found will be included in output. Default
321 is None.
323 Returns
324 -------
325 indices : dictionary
326 A Python dictionary of array indices for each distinct value. The
327 dictionary is keyed by the distinct values, the entries are array
328 index tuples covering all occurrences of the value within the
329 array.
331 This dictionary can occupy significant memory, usually several times
332 the size of the input array.
334 Notes
335 -----
336 For a small array with few distinct values, one might use
337 `numpy.unique()` to find all possible values, and ``(arr == val)`` to
338 locate each value within that array. However, for large arrays,
339 with many distinct values, this can become extremely inefficient,
340 as locating each value would require a new search through the entire
341 array. Using this function, there is essentially one search, with
342 the indices saved for all distinct values.
344 This is useful when matching a categorical image (e.g. a segmentation
345 or classification) to an associated image of other data, allowing
346 any per-class statistic(s) to then be calculated. Provides a
347 more flexible alternative to functions like ``scipy.ndimage.mean()``
348 and ``scipy.ndimage.variance()``.
350 Some other closely related functionality, with different strengths and
351 weaknesses, can also be found in ``scipy.stats.binned_statistic()`` and
352 the `scikit-image <https://scikit-image.org/>`_ function
353 ``skimage.measure.regionprops()``.
355 Note for IDL users: this provides functionality equivalent to IDL's
356 REVERSE_INDICES option (as per the IDL documentation for the
357 `HISTOGRAM <https://www.l3harrisgeospatial.com/docs/histogram.html>`_
358 function).
360 .. versionadded:: 1.10.0
362 See Also
363 --------
364 label, maximum, median, minimum_position, extrema, sum, mean, variance,
365 standard_deviation, numpy.where, numpy.unique
367 Examples
368 --------
369 >>> import numpy as np
370 >>> from scipy import ndimage
371 >>> a = np.zeros((6, 6), dtype=int)
372 >>> a[2:4, 2:4] = 1
373 >>> a[4, 4] = 1
374 >>> a[:2, :3] = 2
375 >>> a[0, 5] = 3
376 >>> a
377 array([[2, 2, 2, 0, 0, 3],
378 [2, 2, 2, 0, 0, 0],
379 [0, 0, 1, 1, 0, 0],
380 [0, 0, 1, 1, 0, 0],
381 [0, 0, 0, 0, 1, 0],
382 [0, 0, 0, 0, 0, 0]])
383 >>> val_indices = ndimage.value_indices(a)
385 The dictionary `val_indices` will have an entry for each distinct
386 value in the input array.
388 >>> val_indices.keys()
389 dict_keys([0, 1, 2, 3])
391 The entry for each value is an index tuple, locating the elements
392 with that value.
394 >>> ndx1 = val_indices[1]
395 >>> ndx1
396 (array([2, 2, 3, 3, 4]), array([2, 3, 2, 3, 4]))
398 This can be used to index into the original array, or any other
399 array with the same shape.
401 >>> a[ndx1]
402 array([1, 1, 1, 1, 1])
404 If the zeros were to be ignored, then the resulting dictionary
405 would no longer have an entry for zero.
407 >>> val_indices = ndimage.value_indices(a, ignore_value=0)
408 >>> val_indices.keys()
409 dict_keys([1, 2, 3])
411 """
412 # Cope with ignore_value being None, without too much extra complexity
413 # in the C code. If not None, the value is passed in as a numpy array
414 # with the same dtype as arr.
415 ignore_value_arr = numpy.zeros((1,), dtype=arr.dtype)
416 ignoreIsNone = (ignore_value is None)
417 if not ignoreIsNone:
418 ignore_value_arr[0] = ignore_value_arr.dtype.type(ignore_value)
420 val_indices = _nd_image.value_indices(arr, ignoreIsNone, ignore_value_arr)
421 return val_indices
424def labeled_comprehension(input, labels, index, func, out_dtype, default, pass_positions=False):
425 """
426 Roughly equivalent to [func(input[labels == i]) for i in index].
428 Sequentially applies an arbitrary function (that works on array_like input)
429 to subsets of an N-D image array specified by `labels` and `index`.
430 The option exists to provide the function with positional parameters as the
431 second argument.
433 Parameters
434 ----------
435 input : array_like
436 Data from which to select `labels` to process.
437 labels : array_like or None
438 Labels to objects in `input`.
439 If not None, array must be same shape as `input`.
440 If None, `func` is applied to raveled `input`.
441 index : int, sequence of ints or None
442 Subset of `labels` to which to apply `func`.
443 If a scalar, a single value is returned.
444 If None, `func` is applied to all non-zero values of `labels`.
445 func : callable
446 Python function to apply to `labels` from `input`.
447 out_dtype : dtype
448 Dtype to use for `result`.
449 default : int, float or None
450 Default return value when a element of `index` does not exist
451 in `labels`.
452 pass_positions : bool, optional
453 If True, pass linear indices to `func` as a second argument.
454 Default is False.
456 Returns
457 -------
458 result : ndarray
459 Result of applying `func` to each of `labels` to `input` in `index`.
461 Examples
462 --------
463 >>> import numpy as np
464 >>> a = np.array([[1, 2, 0, 0],
465 ... [5, 3, 0, 4],
466 ... [0, 0, 0, 7],
467 ... [9, 3, 0, 0]])
468 >>> from scipy import ndimage
469 >>> lbl, nlbl = ndimage.label(a)
470 >>> lbls = np.arange(1, nlbl+1)
471 >>> ndimage.labeled_comprehension(a, lbl, lbls, np.mean, float, 0)
472 array([ 2.75, 5.5 , 6. ])
474 Falling back to `default`:
476 >>> lbls = np.arange(1, nlbl+2)
477 >>> ndimage.labeled_comprehension(a, lbl, lbls, np.mean, float, -1)
478 array([ 2.75, 5.5 , 6. , -1. ])
480 Passing positions:
482 >>> def fn(val, pos):
483 ... print("fn says: %s : %s" % (val, pos))
484 ... return (val.sum()) if (pos.sum() % 2 == 0) else (-val.sum())
485 ...
486 >>> ndimage.labeled_comprehension(a, lbl, lbls, fn, float, 0, True)
487 fn says: [1 2 5 3] : [0 1 4 5]
488 fn says: [4 7] : [ 7 11]
489 fn says: [9 3] : [12 13]
490 array([ 11., 11., -12., 0.])
492 """
494 as_scalar = numpy.isscalar(index)
495 input = numpy.asarray(input)
497 if pass_positions:
498 positions = numpy.arange(input.size).reshape(input.shape)
500 if labels is None:
501 if index is not None:
502 raise ValueError("index without defined labels")
503 if not pass_positions:
504 return func(input.ravel())
505 else:
506 return func(input.ravel(), positions.ravel())
508 try:
509 input, labels = numpy.broadcast_arrays(input, labels)
510 except ValueError as e:
511 raise ValueError("input and labels must have the same shape "
512 "(excepting dimensions with width 1)") from e
514 if index is None:
515 if not pass_positions:
516 return func(input[labels > 0])
517 else:
518 return func(input[labels > 0], positions[labels > 0])
520 index = numpy.atleast_1d(index)
521 if np.any(index.astype(labels.dtype).astype(index.dtype) != index):
522 raise ValueError("Cannot convert index values from <%s> to <%s> "
523 "(labels' type) without loss of precision" %
524 (index.dtype, labels.dtype))
526 index = index.astype(labels.dtype)
528 # optimization: find min/max in index, and select those parts of labels, input, and positions
529 lo = index.min()
530 hi = index.max()
531 mask = (labels >= lo) & (labels <= hi)
533 # this also ravels the arrays
534 labels = labels[mask]
535 input = input[mask]
536 if pass_positions:
537 positions = positions[mask]
539 # sort everything by labels
540 label_order = labels.argsort()
541 labels = labels[label_order]
542 input = input[label_order]
543 if pass_positions:
544 positions = positions[label_order]
546 index_order = index.argsort()
547 sorted_index = index[index_order]
549 def do_map(inputs, output):
550 """labels must be sorted"""
551 nidx = sorted_index.size
553 # Find boundaries for each stretch of constant labels
554 # This could be faster, but we already paid N log N to sort labels.
555 lo = numpy.searchsorted(labels, sorted_index, side='left')
556 hi = numpy.searchsorted(labels, sorted_index, side='right')
558 for i, l, h in zip(range(nidx), lo, hi):
559 if l == h:
560 continue
561 output[i] = func(*[inp[l:h] for inp in inputs])
563 temp = numpy.empty(index.shape, out_dtype)
564 temp[:] = default
565 if not pass_positions:
566 do_map([input], temp)
567 else:
568 do_map([input, positions], temp)
570 output = numpy.zeros(index.shape, out_dtype)
571 output[index_order] = temp
572 if as_scalar:
573 output = output[0]
575 return output
578def _safely_castable_to_int(dt):
579 """Test whether the NumPy data type `dt` can be safely cast to an int."""
580 int_size = np.dtype(int).itemsize
581 safe = ((np.issubdtype(dt, np.signedinteger) and dt.itemsize <= int_size) or
582 (np.issubdtype(dt, np.unsignedinteger) and dt.itemsize < int_size))
583 return safe
586def _stats(input, labels=None, index=None, centered=False):
587 """Count, sum, and optionally compute (sum - centre)^2 of input by label
589 Parameters
590 ----------
591 input : array_like, N-D
592 The input data to be analyzed.
593 labels : array_like (N-D), optional
594 The labels of the data in `input`. This array must be broadcast
595 compatible with `input`; typically, it is the same shape as `input`.
596 If `labels` is None, all nonzero values in `input` are treated as
597 the single labeled group.
598 index : label or sequence of labels, optional
599 These are the labels of the groups for which the stats are computed.
600 If `index` is None, the stats are computed for the single group where
601 `labels` is greater than 0.
602 centered : bool, optional
603 If True, the centered sum of squares for each labeled group is
604 also returned. Default is False.
606 Returns
607 -------
608 counts : int or ndarray of ints
609 The number of elements in each labeled group.
610 sums : scalar or ndarray of scalars
611 The sums of the values in each labeled group.
612 sums_c : scalar or ndarray of scalars, optional
613 The sums of mean-centered squares of the values in each labeled group.
614 This is only returned if `centered` is True.
616 """
617 def single_group(vals):
618 if centered:
619 vals_c = vals - vals.mean()
620 return vals.size, vals.sum(), (vals_c * vals_c.conjugate()).sum()
621 else:
622 return vals.size, vals.sum()
624 if labels is None:
625 return single_group(input)
627 # ensure input and labels match sizes
628 input, labels = numpy.broadcast_arrays(input, labels)
630 if index is None:
631 return single_group(input[labels > 0])
633 if numpy.isscalar(index):
634 return single_group(input[labels == index])
636 def _sum_centered(labels):
637 # `labels` is expected to be an ndarray with the same shape as `input`.
638 # It must contain the label indices (which are not necessarily the labels
639 # themselves).
640 means = sums / counts
641 centered_input = input - means[labels]
642 # bincount expects 1-D inputs, so we ravel the arguments.
643 bc = numpy.bincount(labels.ravel(),
644 weights=(centered_input *
645 centered_input.conjugate()).ravel())
646 return bc
648 # Remap labels to unique integers if necessary, or if the largest
649 # label is larger than the number of values.
651 if (not _safely_castable_to_int(labels.dtype) or
652 labels.min() < 0 or labels.max() > labels.size):
653 # Use numpy.unique to generate the label indices. `new_labels` will
654 # be 1-D, but it should be interpreted as the flattened N-D array of
655 # label indices.
656 unique_labels, new_labels = numpy.unique(labels, return_inverse=True)
657 counts = numpy.bincount(new_labels)
658 sums = numpy.bincount(new_labels, weights=input.ravel())
659 if centered:
660 # Compute the sum of the mean-centered squares.
661 # We must reshape new_labels to the N-D shape of `input` before
662 # passing it _sum_centered.
663 sums_c = _sum_centered(new_labels.reshape(labels.shape))
664 idxs = numpy.searchsorted(unique_labels, index)
665 # make all of idxs valid
666 idxs[idxs >= unique_labels.size] = 0
667 found = (unique_labels[idxs] == index)
668 else:
669 # labels are an integer type allowed by bincount, and there aren't too
670 # many, so call bincount directly.
671 counts = numpy.bincount(labels.ravel())
672 sums = numpy.bincount(labels.ravel(), weights=input.ravel())
673 if centered:
674 sums_c = _sum_centered(labels)
675 # make sure all index values are valid
676 idxs = numpy.asanyarray(index, numpy.int_).copy()
677 found = (idxs >= 0) & (idxs < counts.size)
678 idxs[~found] = 0
680 counts = counts[idxs]
681 counts[~found] = 0
682 sums = sums[idxs]
683 sums[~found] = 0
685 if not centered:
686 return (counts, sums)
687 else:
688 sums_c = sums_c[idxs]
689 sums_c[~found] = 0
690 return (counts, sums, sums_c)
693def sum(input, labels=None, index=None):
694 """
695 Calculate the sum of the values of the array.
697 Notes
698 -----
699 This is an alias for `ndimage.sum_labels` kept for backwards compatibility
700 reasons, for new code please prefer `sum_labels`. See the `sum_labels`
701 docstring for more details.
703 """
704 return sum_labels(input, labels, index)
707def sum_labels(input, labels=None, index=None):
708 """
709 Calculate the sum of the values of the array.
711 Parameters
712 ----------
713 input : array_like
714 Values of `input` inside the regions defined by `labels`
715 are summed together.
716 labels : array_like of ints, optional
717 Assign labels to the values of the array. Has to have the same shape as
718 `input`.
719 index : array_like, optional
720 A single label number or a sequence of label numbers of
721 the objects to be measured.
723 Returns
724 -------
725 sum : ndarray or scalar
726 An array of the sums of values of `input` inside the regions defined
727 by `labels` with the same shape as `index`. If 'index' is None or scalar,
728 a scalar is returned.
730 See Also
731 --------
732 mean, median
734 Examples
735 --------
736 >>> from scipy import ndimage
737 >>> input = [0,1,2,3]
738 >>> labels = [1,1,2,2]
739 >>> ndimage.sum_labels(input, labels, index=[1,2])
740 [1.0, 5.0]
741 >>> ndimage.sum_labels(input, labels, index=1)
742 1
743 >>> ndimage.sum_labels(input, labels)
744 6
747 """
748 count, sum = _stats(input, labels, index)
749 return sum
752def mean(input, labels=None, index=None):
753 """
754 Calculate the mean of the values of an array at labels.
756 Parameters
757 ----------
758 input : array_like
759 Array on which to compute the mean of elements over distinct
760 regions.
761 labels : array_like, optional
762 Array of labels of same shape, or broadcastable to the same shape as
763 `input`. All elements sharing the same label form one region over
764 which the mean of the elements is computed.
765 index : int or sequence of ints, optional
766 Labels of the objects over which the mean is to be computed.
767 Default is None, in which case the mean for all values where label is
768 greater than 0 is calculated.
770 Returns
771 -------
772 out : list
773 Sequence of same length as `index`, with the mean of the different
774 regions labeled by the labels in `index`.
776 See Also
777 --------
778 variance, standard_deviation, minimum, maximum, sum, label
780 Examples
781 --------
782 >>> from scipy import ndimage
783 >>> import numpy as np
784 >>> a = np.arange(25).reshape((5,5))
785 >>> labels = np.zeros_like(a)
786 >>> labels[3:5,3:5] = 1
787 >>> index = np.unique(labels)
788 >>> labels
789 array([[0, 0, 0, 0, 0],
790 [0, 0, 0, 0, 0],
791 [0, 0, 0, 0, 0],
792 [0, 0, 0, 1, 1],
793 [0, 0, 0, 1, 1]])
794 >>> index
795 array([0, 1])
796 >>> ndimage.mean(a, labels=labels, index=index)
797 [10.285714285714286, 21.0]
799 """
801 count, sum = _stats(input, labels, index)
802 return sum / numpy.asanyarray(count).astype(numpy.float64)
805def variance(input, labels=None, index=None):
806 """
807 Calculate the variance of the values of an N-D image array, optionally at
808 specified sub-regions.
810 Parameters
811 ----------
812 input : array_like
813 Nd-image data to process.
814 labels : array_like, optional
815 Labels defining sub-regions in `input`.
816 If not None, must be same shape as `input`.
817 index : int or sequence of ints, optional
818 `labels` to include in output. If None (default), all values where
819 `labels` is non-zero are used.
821 Returns
822 -------
823 variance : float or ndarray
824 Values of variance, for each sub-region if `labels` and `index` are
825 specified.
827 See Also
828 --------
829 label, standard_deviation, maximum, minimum, extrema
831 Examples
832 --------
833 >>> import numpy as np
834 >>> a = np.array([[1, 2, 0, 0],
835 ... [5, 3, 0, 4],
836 ... [0, 0, 0, 7],
837 ... [9, 3, 0, 0]])
838 >>> from scipy import ndimage
839 >>> ndimage.variance(a)
840 7.609375
842 Features to process can be specified using `labels` and `index`:
844 >>> lbl, nlbl = ndimage.label(a)
845 >>> ndimage.variance(a, lbl, index=np.arange(1, nlbl+1))
846 array([ 2.1875, 2.25 , 9. ])
848 If no index is given, all non-zero `labels` are processed:
850 >>> ndimage.variance(a, lbl)
851 6.1875
853 """
854 count, sum, sum_c_sq = _stats(input, labels, index, centered=True)
855 return sum_c_sq / np.asanyarray(count).astype(float)
858def standard_deviation(input, labels=None, index=None):
859 """
860 Calculate the standard deviation of the values of an N-D image array,
861 optionally at specified sub-regions.
863 Parameters
864 ----------
865 input : array_like
866 N-D image data to process.
867 labels : array_like, optional
868 Labels to identify sub-regions in `input`.
869 If not None, must be same shape as `input`.
870 index : int or sequence of ints, optional
871 `labels` to include in output. If None (default), all values where
872 `labels` is non-zero are used.
874 Returns
875 -------
876 standard_deviation : float or ndarray
877 Values of standard deviation, for each sub-region if `labels` and
878 `index` are specified.
880 See Also
881 --------
882 label, variance, maximum, minimum, extrema
884 Examples
885 --------
886 >>> import numpy as np
887 >>> a = np.array([[1, 2, 0, 0],
888 ... [5, 3, 0, 4],
889 ... [0, 0, 0, 7],
890 ... [9, 3, 0, 0]])
891 >>> from scipy import ndimage
892 >>> ndimage.standard_deviation(a)
893 2.7585095613392387
895 Features to process can be specified using `labels` and `index`:
897 >>> lbl, nlbl = ndimage.label(a)
898 >>> ndimage.standard_deviation(a, lbl, index=np.arange(1, nlbl+1))
899 array([ 1.479, 1.5 , 3. ])
901 If no index is given, non-zero `labels` are processed:
903 >>> ndimage.standard_deviation(a, lbl)
904 2.4874685927665499
906 """
907 return numpy.sqrt(variance(input, labels, index))
910def _select(input, labels=None, index=None, find_min=False, find_max=False,
911 find_min_positions=False, find_max_positions=False,
912 find_median=False):
913 """Returns min, max, or both, plus their positions (if requested), and
914 median."""
916 input = numpy.asanyarray(input)
918 find_positions = find_min_positions or find_max_positions
919 positions = None
920 if find_positions:
921 positions = numpy.arange(input.size).reshape(input.shape)
923 def single_group(vals, positions):
924 result = []
925 if find_min:
926 result += [vals.min()]
927 if find_min_positions:
928 result += [positions[vals == vals.min()][0]]
929 if find_max:
930 result += [vals.max()]
931 if find_max_positions:
932 result += [positions[vals == vals.max()][0]]
933 if find_median:
934 result += [numpy.median(vals)]
935 return result
937 if labels is None:
938 return single_group(input, positions)
940 # ensure input and labels match sizes
941 input, labels = numpy.broadcast_arrays(input, labels)
943 if index is None:
944 mask = (labels > 0)
945 masked_positions = None
946 if find_positions:
947 masked_positions = positions[mask]
948 return single_group(input[mask], masked_positions)
950 if numpy.isscalar(index):
951 mask = (labels == index)
952 masked_positions = None
953 if find_positions:
954 masked_positions = positions[mask]
955 return single_group(input[mask], masked_positions)
957 # remap labels to unique integers if necessary, or if the largest
958 # label is larger than the number of values.
959 if (not _safely_castable_to_int(labels.dtype) or
960 labels.min() < 0 or labels.max() > labels.size):
961 # remap labels, and indexes
962 unique_labels, labels = numpy.unique(labels, return_inverse=True)
963 idxs = numpy.searchsorted(unique_labels, index)
965 # make all of idxs valid
966 idxs[idxs >= unique_labels.size] = 0
967 found = (unique_labels[idxs] == index)
968 else:
969 # labels are an integer type, and there aren't too many
970 idxs = numpy.asanyarray(index, numpy.int_).copy()
971 found = (idxs >= 0) & (idxs <= labels.max())
973 idxs[~ found] = labels.max() + 1
975 if find_median:
976 order = numpy.lexsort((input.ravel(), labels.ravel()))
977 else:
978 order = input.ravel().argsort()
979 input = input.ravel()[order]
980 labels = labels.ravel()[order]
981 if find_positions:
982 positions = positions.ravel()[order]
984 result = []
985 if find_min:
986 mins = numpy.zeros(labels.max() + 2, input.dtype)
987 mins[labels[::-1]] = input[::-1]
988 result += [mins[idxs]]
989 if find_min_positions:
990 minpos = numpy.zeros(labels.max() + 2, int)
991 minpos[labels[::-1]] = positions[::-1]
992 result += [minpos[idxs]]
993 if find_max:
994 maxs = numpy.zeros(labels.max() + 2, input.dtype)
995 maxs[labels] = input
996 result += [maxs[idxs]]
997 if find_max_positions:
998 maxpos = numpy.zeros(labels.max() + 2, int)
999 maxpos[labels] = positions
1000 result += [maxpos[idxs]]
1001 if find_median:
1002 locs = numpy.arange(len(labels))
1003 lo = numpy.zeros(labels.max() + 2, numpy.int_)
1004 lo[labels[::-1]] = locs[::-1]
1005 hi = numpy.zeros(labels.max() + 2, numpy.int_)
1006 hi[labels] = locs
1007 lo = lo[idxs]
1008 hi = hi[idxs]
1009 # lo is an index to the lowest value in input for each label,
1010 # hi is an index to the largest value.
1011 # move them to be either the same ((hi - lo) % 2 == 0) or next
1012 # to each other ((hi - lo) % 2 == 1), then average.
1013 step = (hi - lo) // 2
1014 lo += step
1015 hi -= step
1016 if (np.issubdtype(input.dtype, np.integer)
1017 or np.issubdtype(input.dtype, np.bool_)):
1018 # avoid integer overflow or boolean addition (gh-12836)
1019 result += [(input[lo].astype('d') + input[hi].astype('d')) / 2.0]
1020 else:
1021 result += [(input[lo] + input[hi]) / 2.0]
1023 return result
1026def minimum(input, labels=None, index=None):
1027 """
1028 Calculate the minimum of the values of an array over labeled regions.
1030 Parameters
1031 ----------
1032 input : array_like
1033 Array_like of values. For each region specified by `labels`, the
1034 minimal values of `input` over the region is computed.
1035 labels : array_like, optional
1036 An array_like of integers marking different regions over which the
1037 minimum value of `input` is to be computed. `labels` must have the
1038 same shape as `input`. If `labels` is not specified, the minimum
1039 over the whole array is returned.
1040 index : array_like, optional
1041 A list of region labels that are taken into account for computing the
1042 minima. If index is None, the minimum over all elements where `labels`
1043 is non-zero is returned.
1045 Returns
1046 -------
1047 minimum : float or list of floats
1048 List of minima of `input` over the regions determined by `labels` and
1049 whose index is in `index`. If `index` or `labels` are not specified, a
1050 float is returned: the minimal value of `input` if `labels` is None,
1051 and the minimal value of elements where `labels` is greater than zero
1052 if `index` is None.
1054 See Also
1055 --------
1056 label, maximum, median, minimum_position, extrema, sum, mean, variance,
1057 standard_deviation
1059 Notes
1060 -----
1061 The function returns a Python list and not a NumPy array, use
1062 `np.array` to convert the list to an array.
1064 Examples
1065 --------
1066 >>> from scipy import ndimage
1067 >>> import numpy as np
1068 >>> a = np.array([[1, 2, 0, 0],
1069 ... [5, 3, 0, 4],
1070 ... [0, 0, 0, 7],
1071 ... [9, 3, 0, 0]])
1072 >>> labels, labels_nb = ndimage.label(a)
1073 >>> labels
1074 array([[1, 1, 0, 0],
1075 [1, 1, 0, 2],
1076 [0, 0, 0, 2],
1077 [3, 3, 0, 0]])
1078 >>> ndimage.minimum(a, labels=labels, index=np.arange(1, labels_nb + 1))
1079 [1.0, 4.0, 3.0]
1080 >>> ndimage.minimum(a)
1081 0.0
1082 >>> ndimage.minimum(a, labels=labels)
1083 1.0
1085 """
1086 return _select(input, labels, index, find_min=True)[0]
1089def maximum(input, labels=None, index=None):
1090 """
1091 Calculate the maximum of the values of an array over labeled regions.
1093 Parameters
1094 ----------
1095 input : array_like
1096 Array_like of values. For each region specified by `labels`, the
1097 maximal values of `input` over the region is computed.
1098 labels : array_like, optional
1099 An array of integers marking different regions over which the
1100 maximum value of `input` is to be computed. `labels` must have the
1101 same shape as `input`. If `labels` is not specified, the maximum
1102 over the whole array is returned.
1103 index : array_like, optional
1104 A list of region labels that are taken into account for computing the
1105 maxima. If index is None, the maximum over all elements where `labels`
1106 is non-zero is returned.
1108 Returns
1109 -------
1110 output : float or list of floats
1111 List of maxima of `input` over the regions determined by `labels` and
1112 whose index is in `index`. If `index` or `labels` are not specified, a
1113 float is returned: the maximal value of `input` if `labels` is None,
1114 and the maximal value of elements where `labels` is greater than zero
1115 if `index` is None.
1117 See Also
1118 --------
1119 label, minimum, median, maximum_position, extrema, sum, mean, variance,
1120 standard_deviation
1122 Notes
1123 -----
1124 The function returns a Python list and not a NumPy array, use
1125 `np.array` to convert the list to an array.
1127 Examples
1128 --------
1129 >>> import numpy as np
1130 >>> a = np.arange(16).reshape((4,4))
1131 >>> a
1132 array([[ 0, 1, 2, 3],
1133 [ 4, 5, 6, 7],
1134 [ 8, 9, 10, 11],
1135 [12, 13, 14, 15]])
1136 >>> labels = np.zeros_like(a)
1137 >>> labels[:2,:2] = 1
1138 >>> labels[2:, 1:3] = 2
1139 >>> labels
1140 array([[1, 1, 0, 0],
1141 [1, 1, 0, 0],
1142 [0, 2, 2, 0],
1143 [0, 2, 2, 0]])
1144 >>> from scipy import ndimage
1145 >>> ndimage.maximum(a)
1146 15.0
1147 >>> ndimage.maximum(a, labels=labels, index=[1,2])
1148 [5.0, 14.0]
1149 >>> ndimage.maximum(a, labels=labels)
1150 14.0
1152 >>> b = np.array([[1, 2, 0, 0],
1153 ... [5, 3, 0, 4],
1154 ... [0, 0, 0, 7],
1155 ... [9, 3, 0, 0]])
1156 >>> labels, labels_nb = ndimage.label(b)
1157 >>> labels
1158 array([[1, 1, 0, 0],
1159 [1, 1, 0, 2],
1160 [0, 0, 0, 2],
1161 [3, 3, 0, 0]])
1162 >>> ndimage.maximum(b, labels=labels, index=np.arange(1, labels_nb + 1))
1163 [5.0, 7.0, 9.0]
1165 """
1166 return _select(input, labels, index, find_max=True)[0]
1169def median(input, labels=None, index=None):
1170 """
1171 Calculate the median of the values of an array over labeled regions.
1173 Parameters
1174 ----------
1175 input : array_like
1176 Array_like of values. For each region specified by `labels`, the
1177 median value of `input` over the region is computed.
1178 labels : array_like, optional
1179 An array_like of integers marking different regions over which the
1180 median value of `input` is to be computed. `labels` must have the
1181 same shape as `input`. If `labels` is not specified, the median
1182 over the whole array is returned.
1183 index : array_like, optional
1184 A list of region labels that are taken into account for computing the
1185 medians. If index is None, the median over all elements where `labels`
1186 is non-zero is returned.
1188 Returns
1189 -------
1190 median : float or list of floats
1191 List of medians of `input` over the regions determined by `labels` and
1192 whose index is in `index`. If `index` or `labels` are not specified, a
1193 float is returned: the median value of `input` if `labels` is None,
1194 and the median value of elements where `labels` is greater than zero
1195 if `index` is None.
1197 See Also
1198 --------
1199 label, minimum, maximum, extrema, sum, mean, variance, standard_deviation
1201 Notes
1202 -----
1203 The function returns a Python list and not a NumPy array, use
1204 `np.array` to convert the list to an array.
1206 Examples
1207 --------
1208 >>> from scipy import ndimage
1209 >>> import numpy as np
1210 >>> a = np.array([[1, 2, 0, 1],
1211 ... [5, 3, 0, 4],
1212 ... [0, 0, 0, 7],
1213 ... [9, 3, 0, 0]])
1214 >>> labels, labels_nb = ndimage.label(a)
1215 >>> labels
1216 array([[1, 1, 0, 2],
1217 [1, 1, 0, 2],
1218 [0, 0, 0, 2],
1219 [3, 3, 0, 0]])
1220 >>> ndimage.median(a, labels=labels, index=np.arange(1, labels_nb + 1))
1221 [2.5, 4.0, 6.0]
1222 >>> ndimage.median(a)
1223 1.0
1224 >>> ndimage.median(a, labels=labels)
1225 3.0
1227 """
1228 return _select(input, labels, index, find_median=True)[0]
1231def minimum_position(input, labels=None, index=None):
1232 """
1233 Find the positions of the minimums of the values of an array at labels.
1235 Parameters
1236 ----------
1237 input : array_like
1238 Array_like of values.
1239 labels : array_like, optional
1240 An array of integers marking different regions over which the
1241 position of the minimum value of `input` is to be computed.
1242 `labels` must have the same shape as `input`. If `labels` is not
1243 specified, the location of the first minimum over the whole
1244 array is returned.
1246 The `labels` argument only works when `index` is specified.
1247 index : array_like, optional
1248 A list of region labels that are taken into account for finding the
1249 location of the minima. If `index` is None, the ``first`` minimum
1250 over all elements where `labels` is non-zero is returned.
1252 The `index` argument only works when `labels` is specified.
1254 Returns
1255 -------
1256 output : list of tuples of ints
1257 Tuple of ints or list of tuples of ints that specify the location
1258 of minima of `input` over the regions determined by `labels` and
1259 whose index is in `index`.
1261 If `index` or `labels` are not specified, a tuple of ints is
1262 returned specifying the location of the first minimal value of `input`.
1264 See Also
1265 --------
1266 label, minimum, median, maximum_position, extrema, sum, mean, variance,
1267 standard_deviation
1269 Examples
1270 --------
1271 >>> import numpy as np
1272 >>> a = np.array([[10, 20, 30],
1273 ... [40, 80, 100],
1274 ... [1, 100, 200]])
1275 >>> b = np.array([[1, 2, 0, 1],
1276 ... [5, 3, 0, 4],
1277 ... [0, 0, 0, 7],
1278 ... [9, 3, 0, 0]])
1280 >>> from scipy import ndimage
1282 >>> ndimage.minimum_position(a)
1283 (2, 0)
1284 >>> ndimage.minimum_position(b)
1285 (0, 2)
1287 Features to process can be specified using `labels` and `index`:
1289 >>> label, pos = ndimage.label(a)
1290 >>> ndimage.minimum_position(a, label, index=np.arange(1, pos+1))
1291 [(2, 0)]
1293 >>> label, pos = ndimage.label(b)
1294 >>> ndimage.minimum_position(b, label, index=np.arange(1, pos+1))
1295 [(0, 0), (0, 3), (3, 1)]
1297 """
1298 dims = numpy.array(numpy.asarray(input).shape)
1299 # see numpy.unravel_index to understand this line.
1300 dim_prod = numpy.cumprod([1] + list(dims[:0:-1]))[::-1]
1302 result = _select(input, labels, index, find_min_positions=True)[0]
1304 if numpy.isscalar(result):
1305 return tuple((result // dim_prod) % dims)
1307 return [tuple(v) for v in (result.reshape(-1, 1) // dim_prod) % dims]
1310def maximum_position(input, labels=None, index=None):
1311 """
1312 Find the positions of the maximums of the values of an array at labels.
1314 For each region specified by `labels`, the position of the maximum
1315 value of `input` within the region is returned.
1317 Parameters
1318 ----------
1319 input : array_like
1320 Array_like of values.
1321 labels : array_like, optional
1322 An array of integers marking different regions over which the
1323 position of the maximum value of `input` is to be computed.
1324 `labels` must have the same shape as `input`. If `labels` is not
1325 specified, the location of the first maximum over the whole
1326 array is returned.
1328 The `labels` argument only works when `index` is specified.
1329 index : array_like, optional
1330 A list of region labels that are taken into account for finding the
1331 location of the maxima. If `index` is None, the first maximum
1332 over all elements where `labels` is non-zero is returned.
1334 The `index` argument only works when `labels` is specified.
1336 Returns
1337 -------
1338 output : list of tuples of ints
1339 List of tuples of ints that specify the location of maxima of
1340 `input` over the regions determined by `labels` and whose index
1341 is in `index`.
1343 If `index` or `labels` are not specified, a tuple of ints is
1344 returned specifying the location of the ``first`` maximal value
1345 of `input`.
1347 See also
1348 --------
1349 label, minimum, median, maximum_position, extrema, sum, mean, variance,
1350 standard_deviation
1352 Examples
1353 --------
1354 >>> from scipy import ndimage
1355 >>> import numpy as np
1356 >>> a = np.array([[1, 2, 0, 0],
1357 ... [5, 3, 0, 4],
1358 ... [0, 0, 0, 7],
1359 ... [9, 3, 0, 0]])
1360 >>> ndimage.maximum_position(a)
1361 (3, 0)
1363 Features to process can be specified using `labels` and `index`:
1365 >>> lbl = np.array([[0, 1, 2, 3],
1366 ... [0, 1, 2, 3],
1367 ... [0, 1, 2, 3],
1368 ... [0, 1, 2, 3]])
1369 >>> ndimage.maximum_position(a, lbl, 1)
1370 (1, 1)
1372 If no index is given, non-zero `labels` are processed:
1374 >>> ndimage.maximum_position(a, lbl)
1375 (2, 3)
1377 If there are no maxima, the position of the first element is returned:
1379 >>> ndimage.maximum_position(a, lbl, 2)
1380 (0, 2)
1382 """
1383 dims = numpy.array(numpy.asarray(input).shape)
1384 # see numpy.unravel_index to understand this line.
1385 dim_prod = numpy.cumprod([1] + list(dims[:0:-1]))[::-1]
1387 result = _select(input, labels, index, find_max_positions=True)[0]
1389 if numpy.isscalar(result):
1390 return tuple((result // dim_prod) % dims)
1392 return [tuple(v) for v in (result.reshape(-1, 1) // dim_prod) % dims]
1395def extrema(input, labels=None, index=None):
1396 """
1397 Calculate the minimums and maximums of the values of an array
1398 at labels, along with their positions.
1400 Parameters
1401 ----------
1402 input : ndarray
1403 N-D image data to process.
1404 labels : ndarray, optional
1405 Labels of features in input.
1406 If not None, must be same shape as `input`.
1407 index : int or sequence of ints, optional
1408 Labels to include in output. If None (default), all values where
1409 non-zero `labels` are used.
1411 Returns
1412 -------
1413 minimums, maximums : int or ndarray
1414 Values of minimums and maximums in each feature.
1415 min_positions, max_positions : tuple or list of tuples
1416 Each tuple gives the N-D coordinates of the corresponding minimum
1417 or maximum.
1419 See Also
1420 --------
1421 maximum, minimum, maximum_position, minimum_position, center_of_mass
1423 Examples
1424 --------
1425 >>> import numpy as np
1426 >>> a = np.array([[1, 2, 0, 0],
1427 ... [5, 3, 0, 4],
1428 ... [0, 0, 0, 7],
1429 ... [9, 3, 0, 0]])
1430 >>> from scipy import ndimage
1431 >>> ndimage.extrema(a)
1432 (0, 9, (0, 2), (3, 0))
1434 Features to process can be specified using `labels` and `index`:
1436 >>> lbl, nlbl = ndimage.label(a)
1437 >>> ndimage.extrema(a, lbl, index=np.arange(1, nlbl+1))
1438 (array([1, 4, 3]),
1439 array([5, 7, 9]),
1440 [(0, 0), (1, 3), (3, 1)],
1441 [(1, 0), (2, 3), (3, 0)])
1443 If no index is given, non-zero `labels` are processed:
1445 >>> ndimage.extrema(a, lbl)
1446 (1, 9, (0, 0), (3, 0))
1448 """
1449 dims = numpy.array(numpy.asarray(input).shape)
1450 # see numpy.unravel_index to understand this line.
1451 dim_prod = numpy.cumprod([1] + list(dims[:0:-1]))[::-1]
1453 minimums, min_positions, maximums, max_positions = _select(input, labels,
1454 index,
1455 find_min=True,
1456 find_max=True,
1457 find_min_positions=True,
1458 find_max_positions=True)
1460 if numpy.isscalar(minimums):
1461 return (minimums, maximums, tuple((min_positions // dim_prod) % dims),
1462 tuple((max_positions // dim_prod) % dims))
1464 min_positions = [tuple(v) for v in (min_positions.reshape(-1, 1) // dim_prod) % dims]
1465 max_positions = [tuple(v) for v in (max_positions.reshape(-1, 1) // dim_prod) % dims]
1467 return minimums, maximums, min_positions, max_positions
1470def center_of_mass(input, labels=None, index=None):
1471 """
1472 Calculate the center of mass of the values of an array at labels.
1474 Parameters
1475 ----------
1476 input : ndarray
1477 Data from which to calculate center-of-mass. The masses can either
1478 be positive or negative.
1479 labels : ndarray, optional
1480 Labels for objects in `input`, as generated by `ndimage.label`.
1481 Only used with `index`. Dimensions must be the same as `input`.
1482 index : int or sequence of ints, optional
1483 Labels for which to calculate centers-of-mass. If not specified,
1484 the combined center of mass of all labels greater than zero
1485 will be calculated. Only used with `labels`.
1487 Returns
1488 -------
1489 center_of_mass : tuple, or list of tuples
1490 Coordinates of centers-of-mass.
1492 Examples
1493 --------
1494 >>> import numpy as np
1495 >>> a = np.array(([0,0,0,0],
1496 ... [0,1,1,0],
1497 ... [0,1,1,0],
1498 ... [0,1,1,0]))
1499 >>> from scipy import ndimage
1500 >>> ndimage.center_of_mass(a)
1501 (2.0, 1.5)
1503 Calculation of multiple objects in an image
1505 >>> b = np.array(([0,1,1,0],
1506 ... [0,1,0,0],
1507 ... [0,0,0,0],
1508 ... [0,0,1,1],
1509 ... [0,0,1,1]))
1510 >>> lbl = ndimage.label(b)[0]
1511 >>> ndimage.center_of_mass(b, lbl, [1,2])
1512 [(0.33333333333333331, 1.3333333333333333), (3.5, 2.5)]
1514 Negative masses are also accepted, which can occur for example when
1515 bias is removed from measured data due to random noise.
1517 >>> c = np.array(([-1,0,0,0],
1518 ... [0,-1,-1,0],
1519 ... [0,1,-1,0],
1520 ... [0,1,1,0]))
1521 >>> ndimage.center_of_mass(c)
1522 (-4.0, 1.0)
1524 If there are division by zero issues, the function does not raise an
1525 error but rather issues a RuntimeWarning before returning inf and/or NaN.
1527 >>> d = np.array([-1, 1])
1528 >>> ndimage.center_of_mass(d)
1529 (inf,)
1530 """
1531 normalizer = sum(input, labels, index)
1532 grids = numpy.ogrid[[slice(0, i) for i in input.shape]]
1534 results = [sum(input * grids[dir].astype(float), labels, index) / normalizer
1535 for dir in range(input.ndim)]
1537 if numpy.isscalar(results[0]):
1538 return tuple(results)
1540 return [tuple(v) for v in numpy.array(results).T]
1543def histogram(input, min, max, bins, labels=None, index=None):
1544 """
1545 Calculate the histogram of the values of an array, optionally at labels.
1547 Histogram calculates the frequency of values in an array within bins
1548 determined by `min`, `max`, and `bins`. The `labels` and `index`
1549 keywords can limit the scope of the histogram to specified sub-regions
1550 within the array.
1552 Parameters
1553 ----------
1554 input : array_like
1555 Data for which to calculate histogram.
1556 min, max : int
1557 Minimum and maximum values of range of histogram bins.
1558 bins : int
1559 Number of bins.
1560 labels : array_like, optional
1561 Labels for objects in `input`.
1562 If not None, must be same shape as `input`.
1563 index : int or sequence of ints, optional
1564 Label or labels for which to calculate histogram. If None, all values
1565 where label is greater than zero are used
1567 Returns
1568 -------
1569 hist : ndarray
1570 Histogram counts.
1572 Examples
1573 --------
1574 >>> import numpy as np
1575 >>> a = np.array([[ 0. , 0.2146, 0.5962, 0. ],
1576 ... [ 0. , 0.7778, 0. , 0. ],
1577 ... [ 0. , 0. , 0. , 0. ],
1578 ... [ 0. , 0. , 0.7181, 0.2787],
1579 ... [ 0. , 0. , 0.6573, 0.3094]])
1580 >>> from scipy import ndimage
1581 >>> ndimage.histogram(a, 0, 1, 10)
1582 array([13, 0, 2, 1, 0, 1, 1, 2, 0, 0])
1584 With labels and no indices, non-zero elements are counted:
1586 >>> lbl, nlbl = ndimage.label(a)
1587 >>> ndimage.histogram(a, 0, 1, 10, lbl)
1588 array([0, 0, 2, 1, 0, 1, 1, 2, 0, 0])
1590 Indices can be used to count only certain objects:
1592 >>> ndimage.histogram(a, 0, 1, 10, lbl, 2)
1593 array([0, 0, 1, 1, 0, 0, 1, 1, 0, 0])
1595 """
1596 _bins = numpy.linspace(min, max, bins + 1)
1598 def _hist(vals):
1599 return numpy.histogram(vals, _bins)[0]
1601 return labeled_comprehension(input, labels, index, _hist, object, None,
1602 pass_positions=False)
1605def watershed_ift(input, markers, structure=None, output=None):
1606 """
1607 Apply watershed from markers using image foresting transform algorithm.
1609 Parameters
1610 ----------
1611 input : array_like
1612 Input.
1613 markers : array_like
1614 Markers are points within each watershed that form the beginning
1615 of the process. Negative markers are considered background markers
1616 which are processed after the other markers.
1617 structure : structure element, optional
1618 A structuring element defining the connectivity of the object can be
1619 provided. If None, an element is generated with a squared
1620 connectivity equal to one.
1621 output : ndarray, optional
1622 An output array can optionally be provided. The same shape as input.
1624 Returns
1625 -------
1626 watershed_ift : ndarray
1627 Output. Same shape as `input`.
1629 References
1630 ----------
1631 .. [1] A.X. Falcao, J. Stolfi and R. de Alencar Lotufo, "The image
1632 foresting transform: theory, algorithms, and applications",
1633 Pattern Analysis and Machine Intelligence, vol. 26, pp. 19-29, 2004.
1635 """
1636 input = numpy.asarray(input)
1637 if input.dtype.type not in [numpy.uint8, numpy.uint16]:
1638 raise TypeError('only 8 and 16 unsigned inputs are supported')
1640 if structure is None:
1641 structure = _morphology.generate_binary_structure(input.ndim, 1)
1642 structure = numpy.asarray(structure, dtype=bool)
1643 if structure.ndim != input.ndim:
1644 raise RuntimeError('structure and input must have equal rank')
1645 for ii in structure.shape:
1646 if ii != 3:
1647 raise RuntimeError('structure dimensions must be equal to 3')
1649 if not structure.flags.contiguous:
1650 structure = structure.copy()
1651 markers = numpy.asarray(markers)
1652 if input.shape != markers.shape:
1653 raise RuntimeError('input and markers must have equal shape')
1655 integral_types = [numpy.int8,
1656 numpy.int16,
1657 numpy.int32,
1658 numpy.int_,
1659 numpy.int64,
1660 numpy.intc,
1661 numpy.intp]
1663 if markers.dtype.type not in integral_types:
1664 raise RuntimeError('marker should be of integer type')
1666 if isinstance(output, numpy.ndarray):
1667 if output.dtype.type not in integral_types:
1668 raise RuntimeError('output should be of integer type')
1669 else:
1670 output = markers.dtype
1672 output = _ni_support._get_output(output, input)
1673 _nd_image.watershed_ift(input, markers, structure, output)
1674 return output