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

1# Copyright (C) 2003-2005 Peter J. Verveer 

2# 

3# Redistribution and use in source and binary forms, with or without 

4# modification, are permitted provided that the following conditions 

5# are met: 

6# 

7# 1. Redistributions of source code must retain the above copyright 

8# notice, this list of conditions and the following disclaimer. 

9# 

10# 2. Redistributions in binary form must reproduce the above 

11# copyright notice, this list of conditions and the following 

12# disclaimer in the documentation and/or other materials provided 

13# with the distribution. 

14# 

15# 3. The name of the author may not be used to endorse or promote 

16# products derived from this software without specific prior 

17# written permission. 

18# 

19# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 

20# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 

21# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 

22# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 

23# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 

24# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 

25# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 

26# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 

27# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 

28# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 

29# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 

30 

31import numpy 

32import numpy as np 

33from . import _ni_support 

34from . import _ni_label 

35from . import _nd_image 

36from . import _morphology 

37 

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'] 

42 

43 

44def label(input, structure=None, output=None): 

45 """ 

46 Label features in an array. 

47 

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:: 

61 

62 [[0,1,0], 

63 [1,1,1], 

64 [0,1,0]] 

65 

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. 

74 

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. 

82 

83 If `output` is None, this function returns a tuple of 

84 (`labeled_array`, `num_features`). 

85 

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. 

89 

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 

95 

96 Notes 

97 ----- 

98 A centrosymmetric matrix is a matrix that is symmetric about the center. 

99 See [1]_ for more information. 

100 

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:: 

105 

106 [[0,1,0], 

107 [1,1,0], 

108 [0,0,0]] 

109 

110 and the `input` is:: 

111 

112 [[1,2], 

113 [0,3]] 

114 

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. 

118 

119 Examples 

120 -------- 

121 Create an image with some features, then label it using the default 

122 (cross-shaped) structuring element: 

123 

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) 

131 

132 Each of the 4 features are labeled with a different integer: 

133 

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]]) 

141 

142 Generate a structuring element that will consider features connected even 

143 if they touch diagonally: 

144 

145 >>> s = generate_binary_structure(2,2) 

146 

147 or, 

148 

149 >>> s = [[1,1,1], 

150 ... [1,1,1], 

151 ... [1,1,1]] 

152 

153 Label the image using the new structuring element: 

154 

155 >>> labeled_array, num_features = label(a, structure=s) 

156 

157 Show the 2 labeled features (note that features 1, 3, and 4 from above are 

158 now considered a single feature): 

159 

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]]) 

167 

168 References 

169 ---------- 

170 

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. 

175 

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') 

188 

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) 

193 

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) 

204 

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 

218 

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 

232 

233 if caller_provided_output: 

234 # result was written in-place 

235 return max_label 

236 else: 

237 return output, max_label 

238 

239 

240def find_objects(input, max_label=0): 

241 """ 

242 Find objects in a labeled array. 

243 

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. 

252 

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. 

261 

262 See Also 

263 -------- 

264 label, center_of_mass 

265 

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". 

270 

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] 

293 

294 >>> loc = ndimage.find_objects(a)[0] 

295 >>> a[loc] 

296 array([[1, 1, 0], 

297 [1, 1, 0], 

298 [0, 0, 1]]) 

299 

300 """ 

301 input = numpy.asarray(input) 

302 if numpy.iscomplexobj(input): 

303 raise TypeError('Complex type not supported') 

304 

305 if max_label < 1: 

306 max_label = input.max() 

307 

308 return _nd_image.find_objects(input, max_label) 

309 

310 

311def value_indices(arr, *, ignore_value=None): 

312 """ 

313 Find indices of each distinct value in given array. 

314 

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. 

323 

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. 

331 

332 This dictionary can occupy significant memory, usually several times 

333 the size of the input array. 

334 

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. 

344 

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()``. 

350 

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()``. 

355 

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). 

360 

361 .. versionadded:: 1.10.0 

362 

363 See Also 

364 -------- 

365 label, maximum, median, minimum_position, extrema, sum, mean, variance, 

366 standard_deviation, numpy.where, numpy.unique 

367 

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) 

385 

386 The dictionary `val_indices` will have an entry for each distinct 

387 value in the input array. 

388 

389 >>> val_indices.keys() 

390 dict_keys([0, 1, 2, 3]) 

391 

392 The entry for each value is an index tuple, locating the elements 

393 with that value. 

394 

395 >>> ndx1 = val_indices[1] 

396 >>> ndx1 

397 (array([2, 2, 3, 3, 4]), array([2, 3, 2, 3, 4])) 

398 

399 This can be used to index into the original array, or any other 

400 array with the same shape. 

401 

402 >>> a[ndx1] 

403 array([1, 1, 1, 1, 1]) 

404 

405 If the zeros were to be ignored, then the resulting dictionary 

406 would no longer have an entry for zero. 

407 

408 >>> val_indices = ndimage.value_indices(a, ignore_value=0) 

409 >>> val_indices.keys() 

410 dict_keys([1, 2, 3]) 

411 

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) 

420 

421 val_indices = _nd_image.value_indices(arr, ignoreIsNone, ignore_value_arr) 

422 return val_indices 

423 

424 

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]. 

428 

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. 

433 

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. 

456 

457 Returns 

458 ------- 

459 result : ndarray 

460 Result of applying `func` to each of `labels` to `input` in `index`. 

461 

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. ]) 

474 

475 Falling back to `default`: 

476 

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. ]) 

480 

481 Passing positions: 

482 

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.]) 

492 

493 """ 

494 

495 as_scalar = numpy.isscalar(index) 

496 input = numpy.asarray(input) 

497 

498 if pass_positions: 

499 positions = numpy.arange(input.size).reshape(input.shape) 

500 

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()) 

508 

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 

514 

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]) 

520 

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)) 

526 

527 index = index.astype(labels.dtype) 

528 

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) 

533 

534 # this also ravels the arrays 

535 labels = labels[mask] 

536 input = input[mask] 

537 if pass_positions: 

538 positions = positions[mask] 

539 

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] 

546 

547 index_order = index.argsort() 

548 sorted_index = index[index_order] 

549 

550 def do_map(inputs, output): 

551 """labels must be sorted""" 

552 nidx = sorted_index.size 

553 

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') 

558 

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]) 

563 

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) 

570 

571 output = numpy.zeros(index.shape, out_dtype) 

572 output[index_order] = temp 

573 if as_scalar: 

574 output = output[0] 

575 

576 return output 

577 

578 

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 

585 

586 

587def _stats(input, labels=None, index=None, centered=False): 

588 """Count, sum, and optionally compute (sum - centre)^2 of input by label 

589 

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. 

606 

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. 

616 

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() 

624 

625 if labels is None: 

626 return single_group(input) 

627 

628 # ensure input and labels match sizes 

629 input, labels = numpy.broadcast_arrays(input, labels) 

630 

631 if index is None: 

632 return single_group(input[labels > 0]) 

633 

634 if numpy.isscalar(index): 

635 return single_group(input[labels == index]) 

636 

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 

648 

649 # Remap labels to unique integers if necessary, or if the largest 

650 # label is larger than the number of values. 

651 

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 

680 

681 counts = counts[idxs] 

682 counts[~found] = 0 

683 sums = sums[idxs] 

684 sums[~found] = 0 

685 

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) 

692 

693 

694def sum(input, labels=None, index=None): 

695 """ 

696 Calculate the sum of the values of the array. 

697 

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. 

703 

704 """ 

705 return sum_labels(input, labels, index) 

706 

707 

708def sum_labels(input, labels=None, index=None): 

709 """ 

710 Calculate the sum of the values of the array. 

711 

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. 

723 

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. 

730 

731 See Also 

732 -------- 

733 mean, median 

734 

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 

746 

747 

748 """ 

749 count, sum = _stats(input, labels, index) 

750 return sum 

751 

752 

753def mean(input, labels=None, index=None): 

754 """ 

755 Calculate the mean of the values of an array at labels. 

756 

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. 

770 

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`. 

776 

777 See Also 

778 -------- 

779 variance, standard_deviation, minimum, maximum, sum, label 

780 

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] 

799 

800 """ 

801 

802 count, sum = _stats(input, labels, index) 

803 return sum / numpy.asanyarray(count).astype(numpy.float64) 

804 

805 

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. 

810 

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. 

821 

822 Returns 

823 ------- 

824 variance : float or ndarray 

825 Values of variance, for each sub-region if `labels` and `index` are 

826 specified. 

827 

828 See Also 

829 -------- 

830 label, standard_deviation, maximum, minimum, extrema 

831 

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 

842 

843 Features to process can be specified using `labels` and `index`: 

844 

845 >>> lbl, nlbl = ndimage.label(a) 

846 >>> ndimage.variance(a, lbl, index=np.arange(1, nlbl+1)) 

847 array([ 2.1875, 2.25 , 9. ]) 

848 

849 If no index is given, all non-zero `labels` are processed: 

850 

851 >>> ndimage.variance(a, lbl) 

852 6.1875 

853 

854 """ 

855 count, sum, sum_c_sq = _stats(input, labels, index, centered=True) 

856 return sum_c_sq / np.asanyarray(count).astype(float) 

857 

858 

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. 

863 

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. 

874 

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. 

880 

881 See Also 

882 -------- 

883 label, variance, maximum, minimum, extrema 

884 

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 

895 

896 Features to process can be specified using `labels` and `index`: 

897 

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. ]) 

901 

902 If no index is given, non-zero `labels` are processed: 

903 

904 >>> ndimage.standard_deviation(a, lbl) 

905 2.4874685927665499 

906 

907 """ 

908 return numpy.sqrt(variance(input, labels, index)) 

909 

910 

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.""" 

916 

917 input = numpy.asanyarray(input) 

918 

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) 

923 

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 

937 

938 if labels is None: 

939 return single_group(input, positions) 

940 

941 # ensure input and labels match sizes 

942 input, labels = numpy.broadcast_arrays(input, labels) 

943 

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) 

950 

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) 

957 

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) 

965 

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()) 

973 

974 idxs[~ found] = labels.max() + 1 

975 

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] 

984 

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] 

1023 

1024 return result 

1025 

1026 

1027def minimum(input, labels=None, index=None): 

1028 """ 

1029 Calculate the minimum of the values of an array over labeled regions. 

1030 

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. 

1045 

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. 

1054 

1055 See Also 

1056 -------- 

1057 label, maximum, median, minimum_position, extrema, sum, mean, variance, 

1058 standard_deviation 

1059 

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. 

1064 

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 

1085 

1086 """ 

1087 return _select(input, labels, index, find_min=True)[0] 

1088 

1089 

1090def maximum(input, labels=None, index=None): 

1091 """ 

1092 Calculate the maximum of the values of an array over labeled regions. 

1093 

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. 

1108 

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. 

1117 

1118 See Also 

1119 -------- 

1120 label, minimum, median, maximum_position, extrema, sum, mean, variance, 

1121 standard_deviation 

1122 

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. 

1127 

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 

1152 

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] 

1165 

1166 """ 

1167 return _select(input, labels, index, find_max=True)[0] 

1168 

1169 

1170def median(input, labels=None, index=None): 

1171 """ 

1172 Calculate the median of the values of an array over labeled regions. 

1173 

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. 

1188 

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. 

1197 

1198 See Also 

1199 -------- 

1200 label, minimum, maximum, extrema, sum, mean, variance, standard_deviation 

1201 

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. 

1206 

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 

1227 

1228 """ 

1229 return _select(input, labels, index, find_median=True)[0] 

1230 

1231 

1232def minimum_position(input, labels=None, index=None): 

1233 """ 

1234 Find the positions of the minimums of the values of an array at labels. 

1235 

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. 

1246 

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. 

1252 

1253 The `index` argument only works when `labels` is specified. 

1254 

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`. 

1261 

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`. 

1264 

1265 See Also 

1266 -------- 

1267 label, minimum, median, maximum_position, extrema, sum, mean, variance, 

1268 standard_deviation 

1269 

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]]) 

1280 

1281 >>> from scipy import ndimage 

1282 

1283 >>> ndimage.minimum_position(a) 

1284 (2, 0) 

1285 >>> ndimage.minimum_position(b) 

1286 (0, 2) 

1287 

1288 Features to process can be specified using `labels` and `index`: 

1289 

1290 >>> label, pos = ndimage.label(a) 

1291 >>> ndimage.minimum_position(a, label, index=np.arange(1, pos+1)) 

1292 [(2, 0)] 

1293 

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)] 

1297 

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] 

1302 

1303 result = _select(input, labels, index, find_min_positions=True)[0] 

1304 

1305 if numpy.isscalar(result): 

1306 return tuple((result // dim_prod) % dims) 

1307 

1308 return [tuple(v) for v in (result.reshape(-1, 1) // dim_prod) % dims] 

1309 

1310 

1311def maximum_position(input, labels=None, index=None): 

1312 """ 

1313 Find the positions of the maximums of the values of an array at labels. 

1314 

1315 For each region specified by `labels`, the position of the maximum 

1316 value of `input` within the region is returned. 

1317 

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. 

1328 

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. 

1334 

1335 The `index` argument only works when `labels` is specified. 

1336 

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`. 

1343 

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`. 

1347 

1348 See also 

1349 -------- 

1350 label, minimum, median, maximum_position, extrema, sum, mean, variance, 

1351 standard_deviation 

1352 

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) 

1363 

1364 Features to process can be specified using `labels` and `index`: 

1365 

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) 

1372 

1373 If no index is given, non-zero `labels` are processed: 

1374 

1375 >>> ndimage.maximum_position(a, lbl) 

1376 (2, 3) 

1377 

1378 If there are no maxima, the position of the first element is returned: 

1379 

1380 >>> ndimage.maximum_position(a, lbl, 2) 

1381 (0, 2) 

1382 

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] 

1387 

1388 result = _select(input, labels, index, find_max_positions=True)[0] 

1389 

1390 if numpy.isscalar(result): 

1391 return tuple((result // dim_prod) % dims) 

1392 

1393 return [tuple(v) for v in (result.reshape(-1, 1) // dim_prod) % dims] 

1394 

1395 

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. 

1400 

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. 

1411 

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. 

1419 

1420 See Also 

1421 -------- 

1422 maximum, minimum, maximum_position, minimum_position, center_of_mass 

1423 

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)) 

1434 

1435 Features to process can be specified using `labels` and `index`: 

1436 

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)]) 

1443 

1444 If no index is given, non-zero `labels` are processed: 

1445 

1446 >>> ndimage.extrema(a, lbl) 

1447 (1, 9, (0, 0), (3, 0)) 

1448 

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] 

1453 

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) 

1460 

1461 if numpy.isscalar(minimums): 

1462 return (minimums, maximums, tuple((min_positions // dim_prod) % dims), 

1463 tuple((max_positions // dim_prod) % dims)) 

1464 

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] 

1467 

1468 return minimums, maximums, min_positions, max_positions 

1469 

1470 

1471def center_of_mass(input, labels=None, index=None): 

1472 """ 

1473 Calculate the center of mass of the values of an array at labels. 

1474 

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`. 

1487 

1488 Returns 

1489 ------- 

1490 center_of_mass : tuple, or list of tuples 

1491 Coordinates of centers-of-mass. 

1492 

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) 

1503 

1504 Calculation of multiple objects in an image 

1505 

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)] 

1514 

1515 Negative masses are also accepted, which can occur for example when 

1516 bias is removed from measured data due to random noise. 

1517 

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) 

1524 

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. 

1527 

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]] 

1534 

1535 results = [sum(input * grids[dir].astype(float), labels, index) / normalizer 

1536 for dir in range(input.ndim)] 

1537 

1538 if numpy.isscalar(results[0]): 

1539 return tuple(results) 

1540 

1541 return [tuple(v) for v in numpy.array(results).T] 

1542 

1543 

1544def histogram(input, min, max, bins, labels=None, index=None): 

1545 """ 

1546 Calculate the histogram of the values of an array, optionally at labels. 

1547 

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. 

1552 

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 

1567 

1568 Returns 

1569 ------- 

1570 hist : ndarray 

1571 Histogram counts. 

1572 

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]) 

1584 

1585 With labels and no indices, non-zero elements are counted: 

1586 

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]) 

1590 

1591 Indices can be used to count only certain objects: 

1592 

1593 >>> ndimage.histogram(a, 0, 1, 10, lbl, 2) 

1594 array([0, 0, 1, 1, 0, 0, 1, 1, 0, 0]) 

1595 

1596 """ 

1597 _bins = numpy.linspace(min, max, bins + 1) 

1598 

1599 def _hist(vals): 

1600 return numpy.histogram(vals, _bins)[0] 

1601 

1602 return labeled_comprehension(input, labels, index, _hist, object, None, 

1603 pass_positions=False) 

1604 

1605 

1606def watershed_ift(input, markers, structure=None, output=None): 

1607 """ 

1608 Apply watershed from markers using image foresting transform algorithm. 

1609 

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. 

1624 

1625 Returns 

1626 ------- 

1627 watershed_ift : ndarray 

1628 Output. Same shape as `input`. 

1629 

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. 

1635 

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') 

1640 

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') 

1649 

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') 

1655 

1656 integral_types = [numpy.int8, 

1657 numpy.int16, 

1658 numpy.int32, 

1659 numpy.int_, 

1660 numpy.int64, 

1661 numpy.intc, 

1662 numpy.intp] 

1663 

1664 if markers.dtype.type not in integral_types: 

1665 raise RuntimeError('marker should be of integer type') 

1666 

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 

1672 

1673 output = _ni_support._get_output(output, input) 

1674 _nd_image.watershed_ift(input, markers, structure, output) 

1675 return output