/scipy/ndimage/filters.py

http://github.com/scipy/scipy · Python · 1529 lines · 1374 code · 24 blank · 131 comment · 13 complexity · 0ffa1b4d2ba1909be3db503d176afa98 MD5 · raw file

  1. # Copyright (C) 2003-2005 Peter J. Verveer
  2. #
  3. # Redistribution and use in source and binary forms, with or without
  4. # modification, are permitted provided that the following conditions
  5. # are met:
  6. #
  7. # 1. Redistributions of source code must retain the above copyright
  8. # notice, this list of conditions and the following disclaimer.
  9. #
  10. # 2. Redistributions in binary form must reproduce the above
  11. # copyright notice, this list of conditions and the following
  12. # disclaimer in the documentation and/or other materials provided
  13. # with the distribution.
  14. #
  15. # 3. The name of the author may not be used to endorse or promote
  16. # products derived from this software without specific prior
  17. # written permission.
  18. #
  19. # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
  20. # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  21. # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22. # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  23. # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24. # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  25. # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  26. # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  27. # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  28. # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  29. # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. from collections.abc import Iterable
  31. import warnings
  32. import numpy
  33. import operator
  34. from numpy.core.multiarray import normalize_axis_index
  35. from . import _ni_support
  36. from . import _nd_image
  37. from . import _ni_docstrings
  38. __all__ = ['correlate1d', 'convolve1d', 'gaussian_filter1d', 'gaussian_filter',
  39. 'prewitt', 'sobel', 'generic_laplace', 'laplace',
  40. 'gaussian_laplace', 'generic_gradient_magnitude',
  41. 'gaussian_gradient_magnitude', 'correlate', 'convolve',
  42. 'uniform_filter1d', 'uniform_filter', 'minimum_filter1d',
  43. 'maximum_filter1d', 'minimum_filter', 'maximum_filter',
  44. 'rank_filter', 'median_filter', 'percentile_filter',
  45. 'generic_filter1d', 'generic_filter']
  46. def _invalid_origin(origin, lenw):
  47. return (origin < -(lenw // 2)) or (origin > (lenw - 1) // 2)
  48. @_ni_docstrings.docfiller
  49. def correlate1d(input, weights, axis=-1, output=None, mode="reflect",
  50. cval=0.0, origin=0):
  51. """Calculate a 1-D correlation along the given axis.
  52. The lines of the array along the given axis are correlated with the
  53. given weights.
  54. Parameters
  55. ----------
  56. %(input)s
  57. weights : array
  58. 1-D sequence of numbers.
  59. %(axis)s
  60. %(output)s
  61. %(mode)s
  62. %(cval)s
  63. %(origin)s
  64. Examples
  65. --------
  66. >>> from scipy.ndimage import correlate1d
  67. >>> correlate1d([2, 8, 0, 4, 1, 9, 9, 0], weights=[1, 3])
  68. array([ 8, 26, 8, 12, 7, 28, 36, 9])
  69. """
  70. input = numpy.asarray(input)
  71. if numpy.iscomplexobj(input):
  72. raise TypeError('Complex type not supported')
  73. output = _ni_support._get_output(output, input)
  74. weights = numpy.asarray(weights, dtype=numpy.float64)
  75. if weights.ndim != 1 or weights.shape[0] < 1:
  76. raise RuntimeError('no filter weights given')
  77. if not weights.flags.contiguous:
  78. weights = weights.copy()
  79. axis = normalize_axis_index(axis, input.ndim)
  80. if _invalid_origin(origin, len(weights)):
  81. raise ValueError('Invalid origin; origin must satisfy '
  82. '-(len(weights) // 2) <= origin <= '
  83. '(len(weights)-1) // 2')
  84. mode = _ni_support._extend_mode_to_code(mode)
  85. _nd_image.correlate1d(input, weights, axis, output, mode, cval,
  86. origin)
  87. return output
  88. @_ni_docstrings.docfiller
  89. def convolve1d(input, weights, axis=-1, output=None, mode="reflect",
  90. cval=0.0, origin=0):
  91. """Calculate a 1-D convolution along the given axis.
  92. The lines of the array along the given axis are convolved with the
  93. given weights.
  94. Parameters
  95. ----------
  96. %(input)s
  97. weights : ndarray
  98. 1-D sequence of numbers.
  99. %(axis)s
  100. %(output)s
  101. %(mode)s
  102. %(cval)s
  103. %(origin)s
  104. Returns
  105. -------
  106. convolve1d : ndarray
  107. Convolved array with same shape as input
  108. Examples
  109. --------
  110. >>> from scipy.ndimage import convolve1d
  111. >>> convolve1d([2, 8, 0, 4, 1, 9, 9, 0], weights=[1, 3])
  112. array([14, 24, 4, 13, 12, 36, 27, 0])
  113. """
  114. weights = weights[::-1]
  115. origin = -origin
  116. if not len(weights) & 1:
  117. origin -= 1
  118. return correlate1d(input, weights, axis, output, mode, cval, origin)
  119. def _gaussian_kernel1d(sigma, order, radius):
  120. """
  121. Computes a 1-D Gaussian convolution kernel.
  122. """
  123. if order < 0:
  124. raise ValueError('order must be non-negative')
  125. exponent_range = numpy.arange(order + 1)
  126. sigma2 = sigma * sigma
  127. x = numpy.arange(-radius, radius+1)
  128. phi_x = numpy.exp(-0.5 / sigma2 * x ** 2)
  129. phi_x = phi_x / phi_x.sum()
  130. if order == 0:
  131. return phi_x
  132. else:
  133. # f(x) = q(x) * phi(x) = q(x) * exp(p(x))
  134. # f'(x) = (q'(x) + q(x) * p'(x)) * phi(x)
  135. # p'(x) = -1 / sigma ** 2
  136. # Implement q'(x) + q(x) * p'(x) as a matrix operator and apply to the
  137. # coefficients of q(x)
  138. q = numpy.zeros(order + 1)
  139. q[0] = 1
  140. D = numpy.diag(exponent_range[1:], 1) # D @ q(x) = q'(x)
  141. P = numpy.diag(numpy.ones(order)/-sigma2, -1) # P @ q(x) = q(x) * p'(x)
  142. Q_deriv = D + P
  143. for _ in range(order):
  144. q = Q_deriv.dot(q)
  145. q = (x[:, None] ** exponent_range).dot(q)
  146. return q * phi_x
  147. @_ni_docstrings.docfiller
  148. def gaussian_filter1d(input, sigma, axis=-1, order=0, output=None,
  149. mode="reflect", cval=0.0, truncate=4.0):
  150. """1-D Gaussian filter.
  151. Parameters
  152. ----------
  153. %(input)s
  154. sigma : scalar
  155. standard deviation for Gaussian kernel
  156. %(axis)s
  157. order : int, optional
  158. An order of 0 corresponds to convolution with a Gaussian
  159. kernel. A positive order corresponds to convolution with
  160. that derivative of a Gaussian.
  161. %(output)s
  162. %(mode)s
  163. %(cval)s
  164. truncate : float, optional
  165. Truncate the filter at this many standard deviations.
  166. Default is 4.0.
  167. Returns
  168. -------
  169. gaussian_filter1d : ndarray
  170. Examples
  171. --------
  172. >>> from scipy.ndimage import gaussian_filter1d
  173. >>> gaussian_filter1d([1.0, 2.0, 3.0, 4.0, 5.0], 1)
  174. array([ 1.42704095, 2.06782203, 3. , 3.93217797, 4.57295905])
  175. >>> gaussian_filter1d([1.0, 2.0, 3.0, 4.0, 5.0], 4)
  176. array([ 2.91948343, 2.95023502, 3. , 3.04976498, 3.08051657])
  177. >>> import matplotlib.pyplot as plt
  178. >>> np.random.seed(280490)
  179. >>> x = np.random.randn(101).cumsum()
  180. >>> y3 = gaussian_filter1d(x, 3)
  181. >>> y6 = gaussian_filter1d(x, 6)
  182. >>> plt.plot(x, 'k', label='original data')
  183. >>> plt.plot(y3, '--', label='filtered, sigma=3')
  184. >>> plt.plot(y6, ':', label='filtered, sigma=6')
  185. >>> plt.legend()
  186. >>> plt.grid()
  187. >>> plt.show()
  188. """
  189. sd = float(sigma)
  190. # make the radius of the filter equal to truncate standard deviations
  191. lw = int(truncate * sd + 0.5)
  192. # Since we are calling correlate, not convolve, revert the kernel
  193. weights = _gaussian_kernel1d(sigma, order, lw)[::-1]
  194. return correlate1d(input, weights, axis, output, mode, cval, 0)
  195. @_ni_docstrings.docfiller
  196. def gaussian_filter(input, sigma, order=0, output=None,
  197. mode="reflect", cval=0.0, truncate=4.0):
  198. """Multidimensional Gaussian filter.
  199. Parameters
  200. ----------
  201. %(input)s
  202. sigma : scalar or sequence of scalars
  203. Standard deviation for Gaussian kernel. The standard
  204. deviations of the Gaussian filter are given for each axis as a
  205. sequence, or as a single number, in which case it is equal for
  206. all axes.
  207. order : int or sequence of ints, optional
  208. The order of the filter along each axis is given as a sequence
  209. of integers, or as a single number. An order of 0 corresponds
  210. to convolution with a Gaussian kernel. A positive order
  211. corresponds to convolution with that derivative of a Gaussian.
  212. %(output)s
  213. %(mode_multiple)s
  214. %(cval)s
  215. truncate : float
  216. Truncate the filter at this many standard deviations.
  217. Default is 4.0.
  218. Returns
  219. -------
  220. gaussian_filter : ndarray
  221. Returned array of same shape as `input`.
  222. Notes
  223. -----
  224. The multidimensional filter is implemented as a sequence of
  225. 1-D convolution filters. The intermediate arrays are
  226. stored in the same data type as the output. Therefore, for output
  227. types with a limited precision, the results may be imprecise
  228. because intermediate results may be stored with insufficient
  229. precision.
  230. Examples
  231. --------
  232. >>> from scipy.ndimage import gaussian_filter
  233. >>> a = np.arange(50, step=2).reshape((5,5))
  234. >>> a
  235. array([[ 0, 2, 4, 6, 8],
  236. [10, 12, 14, 16, 18],
  237. [20, 22, 24, 26, 28],
  238. [30, 32, 34, 36, 38],
  239. [40, 42, 44, 46, 48]])
  240. >>> gaussian_filter(a, sigma=1)
  241. array([[ 4, 6, 8, 9, 11],
  242. [10, 12, 14, 15, 17],
  243. [20, 22, 24, 25, 27],
  244. [29, 31, 33, 34, 36],
  245. [35, 37, 39, 40, 42]])
  246. >>> from scipy import misc
  247. >>> import matplotlib.pyplot as plt
  248. >>> fig = plt.figure()
  249. >>> plt.gray() # show the filtered result in grayscale
  250. >>> ax1 = fig.add_subplot(121) # left side
  251. >>> ax2 = fig.add_subplot(122) # right side
  252. >>> ascent = misc.ascent()
  253. >>> result = gaussian_filter(ascent, sigma=5)
  254. >>> ax1.imshow(ascent)
  255. >>> ax2.imshow(result)
  256. >>> plt.show()
  257. """
  258. input = numpy.asarray(input)
  259. output = _ni_support._get_output(output, input)
  260. orders = _ni_support._normalize_sequence(order, input.ndim)
  261. sigmas = _ni_support._normalize_sequence(sigma, input.ndim)
  262. modes = _ni_support._normalize_sequence(mode, input.ndim)
  263. axes = list(range(input.ndim))
  264. axes = [(axes[ii], sigmas[ii], orders[ii], modes[ii])
  265. for ii in range(len(axes)) if sigmas[ii] > 1e-15]
  266. if len(axes) > 0:
  267. for axis, sigma, order, mode in axes:
  268. gaussian_filter1d(input, sigma, axis, order, output,
  269. mode, cval, truncate)
  270. input = output
  271. else:
  272. output[...] = input[...]
  273. return output
  274. @_ni_docstrings.docfiller
  275. def prewitt(input, axis=-1, output=None, mode="reflect", cval=0.0):
  276. """Calculate a Prewitt filter.
  277. Parameters
  278. ----------
  279. %(input)s
  280. %(axis)s
  281. %(output)s
  282. %(mode_multiple)s
  283. %(cval)s
  284. Examples
  285. --------
  286. >>> from scipy import ndimage, misc
  287. >>> import matplotlib.pyplot as plt
  288. >>> fig = plt.figure()
  289. >>> plt.gray() # show the filtered result in grayscale
  290. >>> ax1 = fig.add_subplot(121) # left side
  291. >>> ax2 = fig.add_subplot(122) # right side
  292. >>> ascent = misc.ascent()
  293. >>> result = ndimage.prewitt(ascent)
  294. >>> ax1.imshow(ascent)
  295. >>> ax2.imshow(result)
  296. >>> plt.show()
  297. """
  298. input = numpy.asarray(input)
  299. axis = normalize_axis_index(axis, input.ndim)
  300. output = _ni_support._get_output(output, input)
  301. modes = _ni_support._normalize_sequence(mode, input.ndim)
  302. correlate1d(input, [-1, 0, 1], axis, output, modes[axis], cval, 0)
  303. axes = [ii for ii in range(input.ndim) if ii != axis]
  304. for ii in axes:
  305. correlate1d(output, [1, 1, 1], ii, output, modes[ii], cval, 0,)
  306. return output
  307. @_ni_docstrings.docfiller
  308. def sobel(input, axis=-1, output=None, mode="reflect", cval=0.0):
  309. """Calculate a Sobel filter.
  310. Parameters
  311. ----------
  312. %(input)s
  313. %(axis)s
  314. %(output)s
  315. %(mode_multiple)s
  316. %(cval)s
  317. Examples
  318. --------
  319. >>> from scipy import ndimage, misc
  320. >>> import matplotlib.pyplot as plt
  321. >>> fig = plt.figure()
  322. >>> plt.gray() # show the filtered result in grayscale
  323. >>> ax1 = fig.add_subplot(121) # left side
  324. >>> ax2 = fig.add_subplot(122) # right side
  325. >>> ascent = misc.ascent()
  326. >>> result = ndimage.sobel(ascent)
  327. >>> ax1.imshow(ascent)
  328. >>> ax2.imshow(result)
  329. >>> plt.show()
  330. """
  331. input = numpy.asarray(input)
  332. axis = normalize_axis_index(axis, input.ndim)
  333. output = _ni_support._get_output(output, input)
  334. modes = _ni_support._normalize_sequence(mode, input.ndim)
  335. correlate1d(input, [-1, 0, 1], axis, output, modes[axis], cval, 0)
  336. axes = [ii for ii in range(input.ndim) if ii != axis]
  337. for ii in axes:
  338. correlate1d(output, [1, 2, 1], ii, output, modes[ii], cval, 0)
  339. return output
  340. @_ni_docstrings.docfiller
  341. def generic_laplace(input, derivative2, output=None, mode="reflect",
  342. cval=0.0,
  343. extra_arguments=(),
  344. extra_keywords=None):
  345. """
  346. N-D Laplace filter using a provided second derivative function.
  347. Parameters
  348. ----------
  349. %(input)s
  350. derivative2 : callable
  351. Callable with the following signature::
  352. derivative2(input, axis, output, mode, cval,
  353. *extra_arguments, **extra_keywords)
  354. See `extra_arguments`, `extra_keywords` below.
  355. %(output)s
  356. %(mode_multiple)s
  357. %(cval)s
  358. %(extra_keywords)s
  359. %(extra_arguments)s
  360. """
  361. if extra_keywords is None:
  362. extra_keywords = {}
  363. input = numpy.asarray(input)
  364. output = _ni_support._get_output(output, input)
  365. axes = list(range(input.ndim))
  366. if len(axes) > 0:
  367. modes = _ni_support._normalize_sequence(mode, len(axes))
  368. derivative2(input, axes[0], output, modes[0], cval,
  369. *extra_arguments, **extra_keywords)
  370. for ii in range(1, len(axes)):
  371. tmp = derivative2(input, axes[ii], output.dtype, modes[ii], cval,
  372. *extra_arguments, **extra_keywords)
  373. output += tmp
  374. else:
  375. output[...] = input[...]
  376. return output
  377. @_ni_docstrings.docfiller
  378. def laplace(input, output=None, mode="reflect", cval=0.0):
  379. """N-D Laplace filter based on approximate second derivatives.
  380. Parameters
  381. ----------
  382. %(input)s
  383. %(output)s
  384. %(mode_multiple)s
  385. %(cval)s
  386. Examples
  387. --------
  388. >>> from scipy import ndimage, misc
  389. >>> import matplotlib.pyplot as plt
  390. >>> fig = plt.figure()
  391. >>> plt.gray() # show the filtered result in grayscale
  392. >>> ax1 = fig.add_subplot(121) # left side
  393. >>> ax2 = fig.add_subplot(122) # right side
  394. >>> ascent = misc.ascent()
  395. >>> result = ndimage.laplace(ascent)
  396. >>> ax1.imshow(ascent)
  397. >>> ax2.imshow(result)
  398. >>> plt.show()
  399. """
  400. def derivative2(input, axis, output, mode, cval):
  401. return correlate1d(input, [1, -2, 1], axis, output, mode, cval, 0)
  402. return generic_laplace(input, derivative2, output, mode, cval)
  403. @_ni_docstrings.docfiller
  404. def gaussian_laplace(input, sigma, output=None, mode="reflect",
  405. cval=0.0, **kwargs):
  406. """Multidimensional Laplace filter using Gaussian second derivatives.
  407. Parameters
  408. ----------
  409. %(input)s
  410. sigma : scalar or sequence of scalars
  411. The standard deviations of the Gaussian filter are given for
  412. each axis as a sequence, or as a single number, in which case
  413. it is equal for all axes.
  414. %(output)s
  415. %(mode_multiple)s
  416. %(cval)s
  417. Extra keyword arguments will be passed to gaussian_filter().
  418. Examples
  419. --------
  420. >>> from scipy import ndimage, misc
  421. >>> import matplotlib.pyplot as plt
  422. >>> ascent = misc.ascent()
  423. >>> fig = plt.figure()
  424. >>> plt.gray() # show the filtered result in grayscale
  425. >>> ax1 = fig.add_subplot(121) # left side
  426. >>> ax2 = fig.add_subplot(122) # right side
  427. >>> result = ndimage.gaussian_laplace(ascent, sigma=1)
  428. >>> ax1.imshow(result)
  429. >>> result = ndimage.gaussian_laplace(ascent, sigma=3)
  430. >>> ax2.imshow(result)
  431. >>> plt.show()
  432. """
  433. input = numpy.asarray(input)
  434. def derivative2(input, axis, output, mode, cval, sigma, **kwargs):
  435. order = [0] * input.ndim
  436. order[axis] = 2
  437. return gaussian_filter(input, sigma, order, output, mode, cval,
  438. **kwargs)
  439. return generic_laplace(input, derivative2, output, mode, cval,
  440. extra_arguments=(sigma,),
  441. extra_keywords=kwargs)
  442. @_ni_docstrings.docfiller
  443. def generic_gradient_magnitude(input, derivative, output=None,
  444. mode="reflect", cval=0.0,
  445. extra_arguments=(), extra_keywords=None):
  446. """Gradient magnitude using a provided gradient function.
  447. Parameters
  448. ----------
  449. %(input)s
  450. derivative : callable
  451. Callable with the following signature::
  452. derivative(input, axis, output, mode, cval,
  453. *extra_arguments, **extra_keywords)
  454. See `extra_arguments`, `extra_keywords` below.
  455. `derivative` can assume that `input` and `output` are ndarrays.
  456. Note that the output from `derivative` is modified inplace;
  457. be careful to copy important inputs before returning them.
  458. %(output)s
  459. %(mode_multiple)s
  460. %(cval)s
  461. %(extra_keywords)s
  462. %(extra_arguments)s
  463. """
  464. if extra_keywords is None:
  465. extra_keywords = {}
  466. input = numpy.asarray(input)
  467. output = _ni_support._get_output(output, input)
  468. axes = list(range(input.ndim))
  469. if len(axes) > 0:
  470. modes = _ni_support._normalize_sequence(mode, len(axes))
  471. derivative(input, axes[0], output, modes[0], cval,
  472. *extra_arguments, **extra_keywords)
  473. numpy.multiply(output, output, output)
  474. for ii in range(1, len(axes)):
  475. tmp = derivative(input, axes[ii], output.dtype, modes[ii], cval,
  476. *extra_arguments, **extra_keywords)
  477. numpy.multiply(tmp, tmp, tmp)
  478. output += tmp
  479. # This allows the sqrt to work with a different default casting
  480. numpy.sqrt(output, output, casting='unsafe')
  481. else:
  482. output[...] = input[...]
  483. return output
  484. @_ni_docstrings.docfiller
  485. def gaussian_gradient_magnitude(input, sigma, output=None,
  486. mode="reflect", cval=0.0, **kwargs):
  487. """Multidimensional gradient magnitude using Gaussian derivatives.
  488. Parameters
  489. ----------
  490. %(input)s
  491. sigma : scalar or sequence of scalars
  492. The standard deviations of the Gaussian filter are given for
  493. each axis as a sequence, or as a single number, in which case
  494. it is equal for all axes.
  495. %(output)s
  496. %(mode_multiple)s
  497. %(cval)s
  498. Extra keyword arguments will be passed to gaussian_filter().
  499. Returns
  500. -------
  501. gaussian_gradient_magnitude : ndarray
  502. Filtered array. Has the same shape as `input`.
  503. Examples
  504. --------
  505. >>> from scipy import ndimage, misc
  506. >>> import matplotlib.pyplot as plt
  507. >>> fig = plt.figure()
  508. >>> plt.gray() # show the filtered result in grayscale
  509. >>> ax1 = fig.add_subplot(121) # left side
  510. >>> ax2 = fig.add_subplot(122) # right side
  511. >>> ascent = misc.ascent()
  512. >>> result = ndimage.gaussian_gradient_magnitude(ascent, sigma=5)
  513. >>> ax1.imshow(ascent)
  514. >>> ax2.imshow(result)
  515. >>> plt.show()
  516. """
  517. input = numpy.asarray(input)
  518. def derivative(input, axis, output, mode, cval, sigma, **kwargs):
  519. order = [0] * input.ndim
  520. order[axis] = 1
  521. return gaussian_filter(input, sigma, order, output, mode,
  522. cval, **kwargs)
  523. return generic_gradient_magnitude(input, derivative, output, mode,
  524. cval, extra_arguments=(sigma,),
  525. extra_keywords=kwargs)
  526. def _correlate_or_convolve(input, weights, output, mode, cval, origin,
  527. convolution):
  528. input = numpy.asarray(input)
  529. if numpy.iscomplexobj(input):
  530. raise TypeError('Complex type not supported')
  531. origins = _ni_support._normalize_sequence(origin, input.ndim)
  532. weights = numpy.asarray(weights, dtype=numpy.float64)
  533. wshape = [ii for ii in weights.shape if ii > 0]
  534. if len(wshape) != input.ndim:
  535. raise RuntimeError('filter weights array has incorrect shape.')
  536. if convolution:
  537. weights = weights[tuple([slice(None, None, -1)] * weights.ndim)]
  538. for ii in range(len(origins)):
  539. origins[ii] = -origins[ii]
  540. if not weights.shape[ii] & 1:
  541. origins[ii] -= 1
  542. for origin, lenw in zip(origins, wshape):
  543. if _invalid_origin(origin, lenw):
  544. raise ValueError('Invalid origin; origin must satisfy '
  545. '-(weights.shape[k] // 2) <= origin[k] <= '
  546. '(weights.shape[k]-1) // 2')
  547. if not weights.flags.contiguous:
  548. weights = weights.copy()
  549. output = _ni_support._get_output(output, input)
  550. temp_needed = numpy.shares_memory(input, output)
  551. if temp_needed:
  552. # input and output arrays cannot share memory
  553. temp = output
  554. output = _ni_support._get_output(output.dtype, input)
  555. if not isinstance(mode, str) and isinstance(mode, Iterable):
  556. raise RuntimeError("A sequence of modes is not supported")
  557. mode = _ni_support._extend_mode_to_code(mode)
  558. _nd_image.correlate(input, weights, output, mode, cval, origins)
  559. if temp_needed:
  560. temp[...] = output
  561. output = temp
  562. return output
  563. @_ni_docstrings.docfiller
  564. def correlate(input, weights, output=None, mode='reflect', cval=0.0,
  565. origin=0):
  566. """
  567. Multidimensional correlation.
  568. The array is correlated with the given kernel.
  569. Parameters
  570. ----------
  571. %(input)s
  572. weights : ndarray
  573. array of weights, same number of dimensions as input
  574. %(output)s
  575. %(mode)s
  576. %(cval)s
  577. %(origin_multiple)s
  578. Returns
  579. -------
  580. result : ndarray
  581. The result of correlation of `input` with `weights`.
  582. See Also
  583. --------
  584. convolve : Convolve an image with a kernel.
  585. Examples
  586. --------
  587. Correlation is the process of moving a filter mask often referred to
  588. as kernel over the image and computing the sum of products at each location.
  589. >>> from scipy.ndimage import correlate
  590. >>> input_img = np.arange(25).reshape(5,5)
  591. >>> print(input_img)
  592. [[ 0 1 2 3 4]
  593. [ 5 6 7 8 9]
  594. [10 11 12 13 14]
  595. [15 16 17 18 19]
  596. [20 21 22 23 24]]
  597. Define a kernel (weights) for correlation. In this example, it is for sum of
  598. center and up, down, left and right next elements.
  599. >>> weights = [[0, 1, 0],
  600. ... [1, 1, 1],
  601. ... [0, 1, 0]]
  602. We can calculate a correlation result:
  603. For example, element ``[2,2]`` is ``7 + 11 + 12 + 13 + 17 = 60``.
  604. >>> correlate(input_img, weights)
  605. array([[ 6, 10, 15, 20, 24],
  606. [ 26, 30, 35, 40, 44],
  607. [ 51, 55, 60, 65, 69],
  608. [ 76, 80, 85, 90, 94],
  609. [ 96, 100, 105, 110, 114]])
  610. """
  611. return _correlate_or_convolve(input, weights, output, mode, cval,
  612. origin, False)
  613. @_ni_docstrings.docfiller
  614. def convolve(input, weights, output=None, mode='reflect', cval=0.0,
  615. origin=0):
  616. """
  617. Multidimensional convolution.
  618. The array is convolved with the given kernel.
  619. Parameters
  620. ----------
  621. %(input)s
  622. weights : array_like
  623. Array of weights, same number of dimensions as input
  624. %(output)s
  625. %(mode)s
  626. cval : scalar, optional
  627. Value to fill past edges of input if `mode` is 'constant'. Default
  628. is 0.0
  629. %(origin_multiple)s
  630. Returns
  631. -------
  632. result : ndarray
  633. The result of convolution of `input` with `weights`.
  634. See Also
  635. --------
  636. correlate : Correlate an image with a kernel.
  637. Notes
  638. -----
  639. Each value in result is :math:`C_i = \\sum_j{I_{i+k-j} W_j}`, where
  640. W is the `weights` kernel,
  641. j is the N-D spatial index over :math:`W`,
  642. I is the `input` and k is the coordinate of the center of
  643. W, specified by `origin` in the input parameters.
  644. Examples
  645. --------
  646. Perhaps the simplest case to understand is ``mode='constant', cval=0.0``,
  647. because in this case borders (i.e., where the `weights` kernel, centered
  648. on any one value, extends beyond an edge of `input`) are treated as zeros.
  649. >>> a = np.array([[1, 2, 0, 0],
  650. ... [5, 3, 0, 4],
  651. ... [0, 0, 0, 7],
  652. ... [9, 3, 0, 0]])
  653. >>> k = np.array([[1,1,1],[1,1,0],[1,0,0]])
  654. >>> from scipy import ndimage
  655. >>> ndimage.convolve(a, k, mode='constant', cval=0.0)
  656. array([[11, 10, 7, 4],
  657. [10, 3, 11, 11],
  658. [15, 12, 14, 7],
  659. [12, 3, 7, 0]])
  660. Setting ``cval=1.0`` is equivalent to padding the outer edge of `input`
  661. with 1.0's (and then extracting only the original region of the result).
  662. >>> ndimage.convolve(a, k, mode='constant', cval=1.0)
  663. array([[13, 11, 8, 7],
  664. [11, 3, 11, 14],
  665. [16, 12, 14, 10],
  666. [15, 6, 10, 5]])
  667. With ``mode='reflect'`` (the default), outer values are reflected at the
  668. edge of `input` to fill in missing values.
  669. >>> b = np.array([[2, 0, 0],
  670. ... [1, 0, 0],
  671. ... [0, 0, 0]])
  672. >>> k = np.array([[0,1,0], [0,1,0], [0,1,0]])
  673. >>> ndimage.convolve(b, k, mode='reflect')
  674. array([[5, 0, 0],
  675. [3, 0, 0],
  676. [1, 0, 0]])
  677. This includes diagonally at the corners.
  678. >>> k = np.array([[1,0,0],[0,1,0],[0,0,1]])
  679. >>> ndimage.convolve(b, k)
  680. array([[4, 2, 0],
  681. [3, 2, 0],
  682. [1, 1, 0]])
  683. With ``mode='nearest'``, the single nearest value in to an edge in
  684. `input` is repeated as many times as needed to match the overlapping
  685. `weights`.
  686. >>> c = np.array([[2, 0, 1],
  687. ... [1, 0, 0],
  688. ... [0, 0, 0]])
  689. >>> k = np.array([[0, 1, 0],
  690. ... [0, 1, 0],
  691. ... [0, 1, 0],
  692. ... [0, 1, 0],
  693. ... [0, 1, 0]])
  694. >>> ndimage.convolve(c, k, mode='nearest')
  695. array([[7, 0, 3],
  696. [5, 0, 2],
  697. [3, 0, 1]])
  698. """
  699. return _correlate_or_convolve(input, weights, output, mode, cval,
  700. origin, True)
  701. @_ni_docstrings.docfiller
  702. def uniform_filter1d(input, size, axis=-1, output=None,
  703. mode="reflect", cval=0.0, origin=0):
  704. """Calculate a 1-D uniform filter along the given axis.
  705. The lines of the array along the given axis are filtered with a
  706. uniform filter of given size.
  707. Parameters
  708. ----------
  709. %(input)s
  710. size : int
  711. length of uniform filter
  712. %(axis)s
  713. %(output)s
  714. %(mode)s
  715. %(cval)s
  716. %(origin)s
  717. Examples
  718. --------
  719. >>> from scipy.ndimage import uniform_filter1d
  720. >>> uniform_filter1d([2, 8, 0, 4, 1, 9, 9, 0], size=3)
  721. array([4, 3, 4, 1, 4, 6, 6, 3])
  722. """
  723. input = numpy.asarray(input)
  724. if numpy.iscomplexobj(input):
  725. raise TypeError('Complex type not supported')
  726. axis = normalize_axis_index(axis, input.ndim)
  727. if size < 1:
  728. raise RuntimeError('incorrect filter size')
  729. output = _ni_support._get_output(output, input)
  730. if (size // 2 + origin < 0) or (size // 2 + origin >= size):
  731. raise ValueError('invalid origin')
  732. mode = _ni_support._extend_mode_to_code(mode)
  733. _nd_image.uniform_filter1d(input, size, axis, output, mode, cval,
  734. origin)
  735. return output
  736. @_ni_docstrings.docfiller
  737. def uniform_filter(input, size=3, output=None, mode="reflect",
  738. cval=0.0, origin=0):
  739. """Multidimensional uniform filter.
  740. Parameters
  741. ----------
  742. %(input)s
  743. size : int or sequence of ints, optional
  744. The sizes of the uniform filter are given for each axis as a
  745. sequence, or as a single number, in which case the size is
  746. equal for all axes.
  747. %(output)s
  748. %(mode_multiple)s
  749. %(cval)s
  750. %(origin_multiple)s
  751. Returns
  752. -------
  753. uniform_filter : ndarray
  754. Filtered array. Has the same shape as `input`.
  755. Notes
  756. -----
  757. The multidimensional filter is implemented as a sequence of
  758. 1-D uniform filters. The intermediate arrays are stored
  759. in the same data type as the output. Therefore, for output types
  760. with a limited precision, the results may be imprecise because
  761. intermediate results may be stored with insufficient precision.
  762. Examples
  763. --------
  764. >>> from scipy import ndimage, misc
  765. >>> import matplotlib.pyplot as plt
  766. >>> fig = plt.figure()
  767. >>> plt.gray() # show the filtered result in grayscale
  768. >>> ax1 = fig.add_subplot(121) # left side
  769. >>> ax2 = fig.add_subplot(122) # right side
  770. >>> ascent = misc.ascent()
  771. >>> result = ndimage.uniform_filter(ascent, size=20)
  772. >>> ax1.imshow(ascent)
  773. >>> ax2.imshow(result)
  774. >>> plt.show()
  775. """
  776. input = numpy.asarray(input)
  777. output = _ni_support._get_output(output, input)
  778. sizes = _ni_support._normalize_sequence(size, input.ndim)
  779. origins = _ni_support._normalize_sequence(origin, input.ndim)
  780. modes = _ni_support._normalize_sequence(mode, input.ndim)
  781. axes = list(range(input.ndim))
  782. axes = [(axes[ii], sizes[ii], origins[ii], modes[ii])
  783. for ii in range(len(axes)) if sizes[ii] > 1]
  784. if len(axes) > 0:
  785. for axis, size, origin, mode in axes:
  786. uniform_filter1d(input, int(size), axis, output, mode,
  787. cval, origin)
  788. input = output
  789. else:
  790. output[...] = input[...]
  791. return output
  792. @_ni_docstrings.docfiller
  793. def minimum_filter1d(input, size, axis=-1, output=None,
  794. mode="reflect", cval=0.0, origin=0):
  795. """Calculate a 1-D minimum filter along the given axis.
  796. The lines of the array along the given axis are filtered with a
  797. minimum filter of given size.
  798. Parameters
  799. ----------
  800. %(input)s
  801. size : int
  802. length along which to calculate 1D minimum
  803. %(axis)s
  804. %(output)s
  805. %(mode)s
  806. %(cval)s
  807. %(origin)s
  808. Notes
  809. -----
  810. This function implements the MINLIST algorithm [1]_, as described by
  811. Richard Harter [2]_, and has a guaranteed O(n) performance, `n` being
  812. the `input` length, regardless of filter size.
  813. References
  814. ----------
  815. .. [1] http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.42.2777
  816. .. [2] http://www.richardhartersworld.com/cri/2001/slidingmin.html
  817. Examples
  818. --------
  819. >>> from scipy.ndimage import minimum_filter1d
  820. >>> minimum_filter1d([2, 8, 0, 4, 1, 9, 9, 0], size=3)
  821. array([2, 0, 0, 0, 1, 1, 0, 0])
  822. """
  823. input = numpy.asarray(input)
  824. if numpy.iscomplexobj(input):
  825. raise TypeError('Complex type not supported')
  826. axis = normalize_axis_index(axis, input.ndim)
  827. if size < 1:
  828. raise RuntimeError('incorrect filter size')
  829. output = _ni_support._get_output(output, input)
  830. if (size // 2 + origin < 0) or (size // 2 + origin >= size):
  831. raise ValueError('invalid origin')
  832. mode = _ni_support._extend_mode_to_code(mode)
  833. _nd_image.min_or_max_filter1d(input, size, axis, output, mode, cval,
  834. origin, 1)
  835. return output
  836. @_ni_docstrings.docfiller
  837. def maximum_filter1d(input, size, axis=-1, output=None,
  838. mode="reflect", cval=0.0, origin=0):
  839. """Calculate a 1-D maximum filter along the given axis.
  840. The lines of the array along the given axis are filtered with a
  841. maximum filter of given size.
  842. Parameters
  843. ----------
  844. %(input)s
  845. size : int
  846. Length along which to calculate the 1-D maximum.
  847. %(axis)s
  848. %(output)s
  849. %(mode)s
  850. %(cval)s
  851. %(origin)s
  852. Returns
  853. -------
  854. maximum1d : ndarray, None
  855. Maximum-filtered array with same shape as input.
  856. None if `output` is not None
  857. Notes
  858. -----
  859. This function implements the MAXLIST algorithm [1]_, as described by
  860. Richard Harter [2]_, and has a guaranteed O(n) performance, `n` being
  861. the `input` length, regardless of filter size.
  862. References
  863. ----------
  864. .. [1] http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.42.2777
  865. .. [2] http://www.richardhartersworld.com/cri/2001/slidingmin.html
  866. Examples
  867. --------
  868. >>> from scipy.ndimage import maximum_filter1d
  869. >>> maximum_filter1d([2, 8, 0, 4, 1, 9, 9, 0], size=3)
  870. array([8, 8, 8, 4, 9, 9, 9, 9])
  871. """
  872. input = numpy.asarray(input)
  873. if numpy.iscomplexobj(input):
  874. raise TypeError('Complex type not supported')
  875. axis = normalize_axis_index(axis, input.ndim)
  876. if size < 1:
  877. raise RuntimeError('incorrect filter size')
  878. output = _ni_support._get_output(output, input)
  879. if (size // 2 + origin < 0) or (size // 2 + origin >= size):
  880. raise ValueError('invalid origin')
  881. mode = _ni_support._extend_mode_to_code(mode)
  882. _nd_image.min_or_max_filter1d(input, size, axis, output, mode, cval,
  883. origin, 0)
  884. return output
  885. def _min_or_max_filter(input, size, footprint, structure, output, mode,
  886. cval, origin, minimum):
  887. if (size is not None) and (footprint is not None):
  888. warnings.warn("ignoring size because footprint is set", UserWarning, stacklevel=3)
  889. if structure is None:
  890. if footprint is None:
  891. if size is None:
  892. raise RuntimeError("no footprint provided")
  893. separable = True
  894. else:
  895. footprint = numpy.asarray(footprint, dtype=bool)
  896. if not footprint.any():
  897. raise ValueError("All-zero footprint is not supported.")
  898. if footprint.all():
  899. size = footprint.shape
  900. footprint = None
  901. separable = True
  902. else:
  903. separable = False
  904. else:
  905. structure = numpy.asarray(structure, dtype=numpy.float64)
  906. separable = False
  907. if footprint is None:
  908. footprint = numpy.ones(structure.shape, bool)
  909. else:
  910. footprint = numpy.asarray(footprint, dtype=bool)
  911. input = numpy.asarray(input)
  912. if numpy.iscomplexobj(input):
  913. raise TypeError('Complex type not supported')
  914. output = _ni_support._get_output(output, input)
  915. temp_needed = numpy.shares_memory(input, output)
  916. if temp_needed:
  917. # input and output arrays cannot share memory
  918. temp = output
  919. output = _ni_support._get_output(output.dtype, input)
  920. origins = _ni_support._normalize_sequence(origin, input.ndim)
  921. if separable:
  922. sizes = _ni_support._normalize_sequence(size, input.ndim)
  923. modes = _ni_support._normalize_sequence(mode, input.ndim)
  924. axes = list(range(input.ndim))
  925. axes = [(axes[ii], sizes[ii], origins[ii], modes[ii])
  926. for ii in range(len(axes)) if sizes[ii] > 1]
  927. if minimum:
  928. filter_ = minimum_filter1d
  929. else:
  930. filter_ = maximum_filter1d
  931. if len(axes) > 0:
  932. for axis, size, origin, mode in axes:
  933. filter_(input, int(size), axis, output, mode, cval, origin)
  934. input = output
  935. else:
  936. output[...] = input[...]
  937. else:
  938. fshape = [ii for ii in footprint.shape if ii > 0]
  939. if len(fshape) != input.ndim:
  940. raise RuntimeError('footprint array has incorrect shape.')
  941. for origin, lenf in zip(origins, fshape):
  942. if (lenf // 2 + origin < 0) or (lenf // 2 + origin >= lenf):
  943. raise ValueError('invalid origin')
  944. if not footprint.flags.contiguous:
  945. footprint = footprint.copy()
  946. if structure is not None:
  947. if len(structure.shape) != input.ndim:
  948. raise RuntimeError('structure array has incorrect shape')
  949. if not structure.flags.contiguous:
  950. structure = structure.copy()
  951. if not isinstance(mode, str) and isinstance(mode, Iterable):
  952. raise RuntimeError(
  953. "A sequence of modes is not supported for non-separable "
  954. "footprints")
  955. mode = _ni_support._extend_mode_to_code(mode)
  956. _nd_image.min_or_max_filter(input, footprint, structure, output,
  957. mode, cval, origins, minimum)
  958. if temp_needed:
  959. temp[...] = output
  960. output = temp
  961. return output
  962. @_ni_docstrings.docfiller
  963. def minimum_filter(input, size=None, footprint=None, output=None,
  964. mode="reflect", cval=0.0, origin=0):
  965. """Calculate a multidimensional minimum filter.
  966. Parameters
  967. ----------
  968. %(input)s
  969. %(size_foot)s
  970. %(output)s
  971. %(mode_multiple)s
  972. %(cval)s
  973. %(origin_multiple)s
  974. Returns
  975. -------
  976. minimum_filter : ndarray
  977. Filtered array. Has the same shape as `input`.
  978. Notes
  979. -----
  980. A sequence of modes (one per axis) is only supported when the footprint is
  981. separable. Otherwise, a single mode string must be provided.
  982. Examples
  983. --------
  984. >>> from scipy import ndimage, misc
  985. >>> import matplotlib.pyplot as plt
  986. >>> fig = plt.figure()
  987. >>> plt.gray() # show the filtered result in grayscale
  988. >>> ax1 = fig.add_subplot(121) # left side
  989. >>> ax2 = fig.add_subplot(122) # right side
  990. >>> ascent = misc.ascent()
  991. >>> result = ndimage.minimum_filter(ascent, size=20)
  992. >>> ax1.imshow(ascent)
  993. >>> ax2.imshow(result)
  994. >>> plt.show()
  995. """
  996. return _min_or_max_filter(input, size, footprint, None, output, mode,
  997. cval, origin, 1)
  998. @_ni_docstrings.docfiller
  999. def maximum_filter(input, size=None, footprint=None, output=None,
  1000. mode="reflect", cval=0.0, origin=0):
  1001. """Calculate a multidimensional maximum filter.
  1002. Parameters
  1003. ----------
  1004. %(input)s
  1005. %(size_foot)s
  1006. %(output)s
  1007. %(mode_multiple)s
  1008. %(cval)s
  1009. %(origin_multiple)s
  1010. Returns
  1011. -------
  1012. maximum_filter : ndarray
  1013. Filtered array. Has the same shape as `input`.
  1014. Notes
  1015. -----
  1016. A sequence of modes (one per axis) is only supported when the footprint is
  1017. separable. Otherwise, a single mode string must be provided.
  1018. Examples
  1019. --------
  1020. >>> from scipy import ndimage, misc
  1021. >>> import matplotlib.pyplot as plt
  1022. >>> fig = plt.figure()
  1023. >>> plt.gray() # show the filtered result in grayscale
  1024. >>> ax1 = fig.add_subplot(121) # left side
  1025. >>> ax2 = fig.add_subplot(122) # right side
  1026. >>> ascent = misc.ascent()
  1027. >>> result = ndimage.maximum_filter(ascent, size=20)
  1028. >>> ax1.imshow(ascent)
  1029. >>> ax2.imshow(result)
  1030. >>> plt.show()
  1031. """
  1032. return _min_or_max_filter(input, size, footprint, None, output, mode,
  1033. cval, origin, 0)
  1034. @_ni_docstrings.docfiller
  1035. def _rank_filter(input, rank, size=None, footprint=None, output=None,
  1036. mode="reflect", cval=0.0, origin=0, operation='rank'):
  1037. if (size is not None) and (footprint is not None):
  1038. warnings.warn("ignoring size because footprint is set", UserWarning, stacklevel=3)
  1039. input = numpy.asarray(input)
  1040. if numpy.iscomplexobj(input):
  1041. raise TypeError('Complex type not supported')
  1042. origins = _ni_support._normalize_sequence(origin, input.ndim)
  1043. if footprint is None:
  1044. if size is None:
  1045. raise RuntimeError("no footprint or filter size provided")
  1046. sizes = _ni_support._normalize_sequence(size, input.ndim)
  1047. footprint = numpy.ones(sizes, dtype=bool)
  1048. else:
  1049. footprint = numpy.asarray(footprint, dtype=bool)
  1050. fshape = [ii for ii in footprint.shape if ii > 0]
  1051. if len(fshape) != input.ndim:
  1052. raise RuntimeError('filter footprint array has incorrect shape.')
  1053. for origin, lenf in zip(origins, fshape):
  1054. if (lenf // 2 + origin < 0) or (lenf // 2 + origin >= lenf):
  1055. raise ValueError('invalid origin')
  1056. if not footprint.flags.contiguous:
  1057. footprint = footprint.copy()
  1058. filter_size = numpy.where(footprint, 1, 0).sum()
  1059. if operation == 'median':
  1060. rank = filter_size // 2
  1061. elif operation == 'percentile':
  1062. percentile = rank
  1063. if percentile < 0.0:
  1064. percentile += 100.0
  1065. if percentile < 0 or percentile > 100:
  1066. raise RuntimeError('invalid percentile')
  1067. if percentile == 100.0:
  1068. rank = filter_size - 1
  1069. else:
  1070. rank = int(float(filter_size) * percentile / 100.0)
  1071. if rank < 0:
  1072. rank += filter_size
  1073. if rank < 0 or rank >= filter_size:
  1074. raise RuntimeError('rank not within filter footprint size')
  1075. if rank == 0:
  1076. return minimum_filter(input, None, footprint, output, mode, cval,
  1077. origins)
  1078. elif rank == filter_size - 1:
  1079. return maximum_filter(input, None, footprint, output, mode, cval,
  1080. origins)
  1081. else:
  1082. output = _ni_support._get_output(output, input)
  1083. temp_needed = numpy.shares_memory(input, output)
  1084. if temp_needed:
  1085. # input and output arrays cannot share memory
  1086. temp = output
  1087. output = _ni_support._get_output(output.dtype, input)
  1088. if not isinstance(mode, str) and isinstance(mode, Iterable):
  1089. raise RuntimeError(
  1090. "A sequence of modes is not supported by non-separable rank "
  1091. "filters")
  1092. mode = _ni_support._extend_mode_to_code(mode)
  1093. _nd_image.rank_filter(input, rank, footprint, output, mode, cval,
  1094. origins)
  1095. if temp_needed:
  1096. temp[...] = output
  1097. output = temp
  1098. return output
  1099. @_ni_docstrings.docfiller
  1100. def rank_filter(input, rank, size=None, footprint=None, output=None,
  1101. mode="reflect", cval=0.0, origin=0):
  1102. """Calculate a multidimensional rank filter.
  1103. Parameters
  1104. ----------
  1105. %(input)s
  1106. rank : int
  1107. The rank parameter may be less then zero, i.e., rank = -1
  1108. indicates the largest element.
  1109. %(size_foot)s
  1110. %(output)s
  1111. %(mode)s
  1112. %(cval)s
  1113. %(origin_multiple)s
  1114. Returns
  1115. -------
  1116. rank_filter : ndarray
  1117. Filtered array. Has the same shape as `input`.
  1118. Examples
  1119. --------
  1120. >>> from scipy import ndimage, misc
  1121. >>> import matplotlib.pyplot as plt
  1122. >>> fig = plt.figure()
  1123. >>> plt.gray() # show the filtered result in grayscale
  1124. >>> ax1 = fig.add_subplot(121) # left side
  1125. >>> ax2 = fig.add_subplot(122) # right side
  1126. >>> ascent = misc.ascent()
  1127. >>> result = ndimage.rank_filter(ascent, rank=42, size=20)
  1128. >>> ax1.imshow(ascent)
  1129. >>> ax2.imshow(result)
  1130. >>> plt.show()
  1131. """
  1132. rank = operator.index(rank)
  1133. return _rank_filter(input, rank, size, footprint, output, mode, cval,
  1134. origin, 'rank')
  1135. @_ni_docstrings.docfiller
  1136. def median_filter(input, size=None, footprint=None, output=None,
  1137. mode="reflect", cval=0.0, origin=0):
  1138. """
  1139. Calculate a multidimensional median filter.
  1140. Parameters
  1141. ----------
  1142. %(input)s
  1143. %(size_foot)s
  1144. %(output)s
  1145. %(mode)s
  1146. %(cval)s
  1147. %(origin_multiple)s
  1148. Returns
  1149. -------
  1150. median_filter : ndarray
  1151. Filtered array. Has the same shape as `input`.
  1152. Examples
  1153. --------
  1154. >>> from scipy import ndimage, misc
  1155. >>> import matplotlib.pyplot as plt
  1156. >>> fig = plt.figure()
  1157. >>> plt.gray() # show the filtered result in grayscale
  1158. >>> ax1 = fig.add_subplot(121) # left side
  1159. >>> ax2 = fig.add_subplot(122) # right side
  1160. >>> ascent = misc.ascent()
  1161. >>> result = ndimage.median_filter(ascent, size=20)
  1162. >>> ax1.imshow(ascent)
  1163. >>> ax2.imshow(result)
  1164. >>> plt.show()
  1165. """
  1166. return _rank_filter(input, 0, size, footprint, output, mode, cval,
  1167. origin, 'median')
  1168. @_ni_docstrings.docfiller
  1169. def percentile_filter(input, percentile, size=None, footprint=None,
  1170. output=None, mode="reflect", cval=0.0, origin=0):
  1171. """Calculate a multidimensional percentile filter.
  1172. Parameters
  1173. ----------
  1174. %(input)s
  1175. percentile : scalar
  1176. The percentile parameter may be less then zero, i.e.,
  1177. percentile = -20 equals percentile = 80
  1178. %(size_foot)s
  1179. %(output)s
  1180. %(mode)s
  1181. %(cval)s
  1182. %(origin_multiple)s
  1183. Returns
  1184. -------
  1185. percentile_filter : ndarray
  1186. Filtered array. Has the same shape as `input`.
  1187. Examples
  1188. --------
  1189. >>> from scipy import ndimage, misc
  1190. >>> import matplotlib.pyplot as plt
  1191. >>> fig = plt.figure()
  1192. >>> plt.gray() # show the filtered result in grayscale
  1193. >>> ax1 = fig.add_subplot(121) # left side
  1194. >>> ax2 = fig.add_subplot(122) # right side
  1195. >>> ascent = misc.ascent()
  1196. >>> result = ndimage.percentile_filter(ascent, percentile=20, size=20)
  1197. >>> ax1.imshow(ascent)
  1198. >>> ax2.imshow(result)
  1199. >>> plt.show()
  1200. """
  1201. return _rank_filter(input, percentile, size, footprint, output, mode,
  1202. cval, origin, 'percentile')
  1203. @_ni_docstrings.docfiller
  1204. def generic_filter1d(input, function, filter_size, axis=-1,
  1205. output=None, mode="reflect", cval=0.0, origin=0,
  1206. extra_arguments=(), extra_keywords=None):
  1207. """Calculate a 1-D filter along the given axis.
  1208. `generic_filter1d` iterates over the lines of the array, calling the
  1209. given function at each line. The arguments of the line are the
  1210. input line, and the output line. The input and output lines are 1-D
  1211. double arrays. The input line is extended appropriately according
  1212. to the filter size and origin. The output line must be modified
  1213. in-place with the result.
  1214. Parameters
  1215. ----------
  1216. %(input)s
  1217. function : {callable, scipy.LowLevelCallable}
  1218. Function to apply along given axis.
  1219. filter_size : scalar
  1220. Length of the filter.
  1221. %(axis)s
  1222. %(output)s
  1223. %(mode)s
  1224. %(cval)s
  1225. %(origin)s
  1226. %(extra_arguments)s
  1227. %(extra_keywords)s
  1228. Notes
  1229. -----
  1230. This function also accepts low-level callback functions with one of
  1231. the following signatures and wrapped in `scipy.LowLevelCallable`:
  1232. .. code:: c
  1233. int function(double *input_line, npy_intp input_length,
  1234. double *output_line, npy_intp output_length,
  1235. void *user_data)
  1236. int function(double *input_line, intptr_t input_length,
  1237. double *output_line, intptr_t output_length,
  1238. void *user_data)
  1239. The calling function iterates over the lines of the input and output
  1240. arrays, calling the callback function at each line. The current line
  1241. is extended according to the border conditions set by the calling
  1242. function, and the result is copied into the array that is passed
  1243. through ``input_line``. The length of the input line (after extension)
  1244. is passed through ``input_length``. The callback function should apply
  1245. the filter and store the result in the array passed through
  1246. ``output_line``. The length of the output line is passed through
  1247. ``output_length``. ``user_data`` is the data pointer provided
  1248. to `scipy.LowLevelCallable` as-is.
  1249. The callback function must return an integer error status that is zero
  1250. if something went wrong and one otherwise. If an error occurs, you should
  1251. normally set the python error status with an informative message
  1252. before returning, otherwise a default error message is set by the
  1253. calling function.
  1254. In addition, some other low-level function pointer specifications
  1255. are accepted, but these are for backward compatibility only and should
  1256. not be used in new code.
  1257. """
  1258. if extra_keywords is None:
  1259. extra_keywords = {}
  1260. input = numpy.asarray(input)
  1261. if numpy.iscomplexobj(input):
  1262. raise TypeError('Complex type not supported')
  1263. output = _ni_support._get_output(output, input)
  1264. if filter_size < 1:
  1265. raise RuntimeError('invalid filter size')
  1266. axis = normalize_axis_index(axis, input.ndim)
  1267. if (filter_size // 2 + origin < 0) or (filter_size // 2 + origin >=
  1268. filter_size):
  1269. raise ValueError('invalid origin')
  1270. mode = _ni_support._extend_mode_to_code(mode)
  1271. _nd_image.generic_filter1d(input, function, filter_size, axis, output,
  1272. mode, cval, origin, extra_arguments,
  1273. extra_keywords)
  1274. return output
  1275. @_ni_docstrings.docfiller
  1276. def generic_filter(input, function, size=None, footprint=None,
  1277. output=None, mode="reflect", cval=0.0, origin=0,
  1278. extra_arguments=(), extra_keywords=None):
  1279. """Calculate a multidimensional filter using the given function.
  1280. At each element the provided function is called. The input values
  1281. within the filter footprint at that element are passed to the function
  1282. as a 1-D array of double values.
  1283. Parameters
  1284. ----------
  1285. %(input)s
  1286. function : {callable, scipy.LowLevelCallable}
  1287. Function to apply at each element.
  1288. %(size_foot)s
  1289. %(output)s
  1290. %(mode)s
  1291. %(cval)s
  1292. %(origin_multiple)s
  1293. %(extra_arguments)s
  1294. %(extra_keywords)s
  1295. Notes
  1296. -----
  1297. This function also accepts low-level callback functions with one of
  1298. the following signatures and wrapped in `scipy.LowLevelCallable`:
  1299. .. code:: c
  1300. int callback(double *buffer, npy_intp filter_size,
  1301. double *return_value, void *user_data)
  1302. int callback(double *buffer, intptr_t filter_size,
  1303. double *return_value, void *user_data)
  1304. The calling function iterates over the elements of the input and
  1305. output arrays, calling the callback function at each element. The
  1306. elements within the footprint of the filter at the current element are
  1307. passed through the ``buffer`` parameter, and the number of elements
  1308. within the footprint through ``filter_size``. The calculated value is
  1309. returned in ``return_value``. ``user_data`` is the data pointer provided
  1310. to `scipy.LowLevelCallable` as-is.
  1311. The callback function must return an integer error status that is zero
  1312. if something went wrong and one otherwise. If an error occurs, you should
  1313. normally set the python error status with an informative message
  1314. before returning, otherwise a default error message is set by the
  1315. calling function.
  1316. In addition, some other low-level function pointer specifications
  1317. are accepted, but these are for backward compatibility only and should
  1318. not be used in new code.
  1319. """
  1320. if (size is not None) and (footprint is not None):
  1321. warnings.warn("ignoring size because footprint is set", UserWarning, stacklevel=2)
  1322. if extra_keywords is None:
  1323. extra_keywords = {}
  1324. input = numpy.asarray(input)
  1325. if numpy.iscomplexobj(input):
  1326. raise TypeError('Complex type not supported')
  1327. origins = _ni_support._normalize_sequence(origin, input.ndim)
  1328. if footprint is None:
  1329. if size is None:
  1330. raise RuntimeError("no footprint or filter size provided")
  1331. sizes = _ni_support._normalize_sequence(size, input.ndim)
  1332. footprint = numpy.ones(sizes, dtype=bool)
  1333. else:
  1334. footprint = numpy.asarray(footprint, dtype=bool)
  1335. fshape = [ii for ii in footprint.shape if ii > 0]
  1336. if len(fshape) != input.ndim:
  1337. raise RuntimeError('filter footprint array has incorrect shape.')
  1338. for origin, lenf in zip(origins, fshape):
  1339. if (lenf // 2 + origin < 0) or (lenf // 2 + origin >= lenf):
  1340. raise ValueError('invalid origin')
  1341. if not footprint.flags.contiguous:
  1342. footprint = footprint.copy()
  1343. output = _ni_support._get_output(output, input)
  1344. mode = _ni_support._extend_mode_to_code(mode)
  1345. _nd_image.generic_filter(input, function, footprint, output, mode,
  1346. cval, origins, extra_arguments, extra_keywords)
  1347. return output