block.py 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import numpy as np
  2. from ..util import view_as_blocks
  3. def block_reduce(image, block_size=2, func=np.sum, cval=0, func_kwargs=None):
  4. """Downsample image by applying function `func` to local blocks.
  5. This function is useful for max and mean pooling, for example.
  6. Parameters
  7. ----------
  8. image : (M[, ...]) ndarray
  9. N-dimensional input image.
  10. block_size : array_like or int
  11. Array containing down-sampling integer factor along each axis.
  12. Default block_size is 2.
  13. func : callable
  14. Function object which is used to calculate the return value for each
  15. local block. This function must implement an ``axis`` parameter.
  16. Primary functions are ``numpy.sum``, ``numpy.min``, ``numpy.max``,
  17. ``numpy.mean`` and ``numpy.median``. See also `func_kwargs`.
  18. cval : float
  19. Constant padding value if image is not perfectly divisible by the
  20. block size.
  21. func_kwargs : dict
  22. Keyword arguments passed to `func`. Notably useful for passing dtype
  23. argument to ``np.mean``. Takes dictionary of inputs, e.g.:
  24. ``func_kwargs={'dtype': np.float16})``.
  25. Returns
  26. -------
  27. image : ndarray
  28. Down-sampled image with same number of dimensions as input image.
  29. Examples
  30. --------
  31. >>> from skimage.measure import block_reduce
  32. >>> image = np.arange(3*3*4).reshape(3, 3, 4)
  33. >>> image # doctest: +NORMALIZE_WHITESPACE
  34. array([[[ 0, 1, 2, 3],
  35. [ 4, 5, 6, 7],
  36. [ 8, 9, 10, 11]],
  37. [[12, 13, 14, 15],
  38. [16, 17, 18, 19],
  39. [20, 21, 22, 23]],
  40. [[24, 25, 26, 27],
  41. [28, 29, 30, 31],
  42. [32, 33, 34, 35]]])
  43. >>> block_reduce(image, block_size=(3, 3, 1), func=np.mean)
  44. array([[[16., 17., 18., 19.]]])
  45. >>> image_max1 = block_reduce(image, block_size=(1, 3, 4), func=np.max)
  46. >>> image_max1 # doctest: +NORMALIZE_WHITESPACE
  47. array([[[11]],
  48. [[23]],
  49. [[35]]])
  50. >>> image_max2 = block_reduce(image, block_size=(3, 1, 4), func=np.max)
  51. >>> image_max2 # doctest: +NORMALIZE_WHITESPACE
  52. array([[[27],
  53. [31],
  54. [35]]])
  55. """
  56. if np.isscalar(block_size):
  57. block_size = (block_size,) * image.ndim
  58. elif len(block_size) != image.ndim:
  59. raise ValueError(
  60. "`block_size` must be a scalar or have " "the same length as `image.shape`"
  61. )
  62. if func_kwargs is None:
  63. func_kwargs = {}
  64. pad_width = []
  65. for i in range(len(block_size)):
  66. if block_size[i] < 1:
  67. raise ValueError(
  68. "Down-sampling factors must be >= 1. Use "
  69. "`skimage.transform.resize` to up-sample an "
  70. "image."
  71. )
  72. if image.shape[i] % block_size[i] != 0:
  73. after_width = block_size[i] - (image.shape[i] % block_size[i])
  74. else:
  75. after_width = 0
  76. pad_width.append((0, after_width))
  77. if np.any(np.asarray(pad_width)):
  78. image = np.pad(
  79. image, pad_width=pad_width, mode='constant', constant_values=cval
  80. )
  81. blocked = view_as_blocks(image, block_size)
  82. return func(blocked, axis=tuple(range(image.ndim, blocked.ndim)), **func_kwargs)