import numpy as np from skimage.util import view_as_blocks, pad def block_reduce(image, block_size, func=np.sum, cval=0): """Down-sample image by applying function to local blocks. Parameters ---------- image : ndarray N-dimensional input image. block_size : array_like Array containing down-sampling integer factor along each axis. func : callable Function object which is used to calculate the return value for each local block. This function must implement an ``axis`` parameter such as ``numpy.sum`` or ``numpy.min``. cval : float Constant padding value if image is not perfectly divisible by the block size. Returns ------- image : ndarray Down-sampled image with same number of dimensions as input image. Examples -------- >>> from skimage.measure import block_reduce >>> image = np.arange(3*3*4).reshape(3, 3, 4) >>> image # doctest: +NORMALIZE_WHITESPACE array([[[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]], [[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]], [[24, 25, 26, 27], [28, 29, 30, 31], [32, 33, 34, 35]]]) >>> block_reduce(image, block_size=(3, 3, 1), func=np.mean) array([[[ 16., 17., 18., 19.]]]) >>> image_max1 = block_reduce(image, block_size=(1, 3, 4), func=np.max) >>> image_max1 # doctest: +NORMALIZE_WHITESPACE array([[[11]], [[23]], [[35]]]) >>> image_max2 = block_reduce(image, block_size=(3, 1, 4), func=np.max) >>> image_max2 # doctest: +NORMALIZE_WHITESPACE array([[[27], [31], [35]]]) """ if len(block_size) != image.ndim: raise ValueError("`block_size` must have the same length " "as `image.shape`.") pad_width = [] for i in range(len(block_size)): if image.shape[i] % block_size[i] != 0: after_width = block_size[i] - (image.shape[i] % block_size[i]) else: after_width = 0 pad_width.append((0, after_width)) image = pad(image, pad_width=pad_width, mode='constant', constant_values=cval) out = view_as_blocks(image, block_size) for i in range(len(out.shape) // 2): out = func(out, axis=-1) return out