From 04b14b42c9c2bcf811ab0904ef7c0f34afb19d8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Fri, 5 Jul 2013 09:04:09 +0200 Subject: [PATCH 01/11] Refactor local block functions and add additional functionality. --- skimage/measure/__init__.py | 2 +- skimage/measure/_sum_blocks.py | 38 ---- skimage/measure/blocks.py | 210 ++++++++++++++++++ skimage/measure/tests/test_blocks.py | 21 ++ .../tests/test_structural_similarity.py | 1 + skimage/measure/tests/test_sum_blocks.py | 16 -- skimage/transform/__init__.py | 4 +- skimage/transform/_warps.py | 144 ++++-------- skimage/transform/tests/test_warps.py | 8 +- 9 files changed, 286 insertions(+), 158 deletions(-) delete mode 100644 skimage/measure/_sum_blocks.py create mode 100644 skimage/measure/blocks.py create mode 100644 skimage/measure/tests/test_blocks.py delete mode 100644 skimage/measure/tests/test_sum_blocks.py diff --git a/skimage/measure/__init__.py b/skimage/measure/__init__.py index a9fbae24..4c44dc2f 100755 --- a/skimage/measure/__init__.py +++ b/skimage/measure/__init__.py @@ -3,7 +3,7 @@ from ._regionprops import regionprops, perimeter from ._structural_similarity import structural_similarity from ._polygon import approximate_polygon, subdivide_polygon from .fit import LineModel, CircleModel, EllipseModel, ransac -from ._sum_blocks import sum_blocks +from .blocks import block_sum, block_median, block_mean, block_min, block_max __all__ = ['find_contours', diff --git a/skimage/measure/_sum_blocks.py b/skimage/measure/_sum_blocks.py deleted file mode 100644 index c65c121e..00000000 --- a/skimage/measure/_sum_blocks.py +++ /dev/null @@ -1,38 +0,0 @@ -def sum_blocks(array, factors): - """Sums the elements in blocks of integer factors and pads the original - array with zeroes if the dimensions are not perfectly divisible by factors. - - This function is different from resize and rescale in transform._warps in - the sense that they use interpolation to upsample or downsample on a 2D - array, while this function performs only dawnsampling but on any - n-dimensional array and returns the sum of elements in a block of size - factors in the original array. - - Parameters - ---------- - array : ndarray - Input n-dimensional array. - factors: tuple - Tuple containing integer values representing block length along each - axis. - - Returns - ------- - array : ndarray - Downsampled array with same number of dimensions as that of input - array. - - Example - ------- - >>> a = np.arange(15).reshape(3, 5) - >>> a - array([[ 0, 1, 2, 3, 4], - [ 5, 6, 7, 8, 9], - [10, 11, 12, 13, 14]]) - >>> sum_blocks(a, (2,3)) - array([[21, 24], - [33, 27]]) - - """ - from ..transform._warps import _downsample - return _downsample(array, factors) diff --git a/skimage/measure/blocks.py b/skimage/measure/blocks.py new file mode 100644 index 00000000..428ecf11 --- /dev/null +++ b/skimage/measure/blocks.py @@ -0,0 +1,210 @@ +import numpy as np +from ..util.shape import view_as_blocks, _pad_asymmetric_zeros + + +def _block_func(image, factors, func): + """Down-sample image by integer factors. + + Parameters + ---------- + image : ndarray + N-dimensional input image. + factors : array_like + Array containing down-sampling integer factor along each axis. + func : object + Function object which is used to calculate the return value for each + local block, e.g. `numpy.sum`. + + Returns + ------- + image : ndarray + Down-sampled image with same number of dimensions as input image. + + """ + + pad_size = [] + if len(factors) != image.ndim: + raise ValueError("`factors` must have the same length " + "as `image.shape`.") + + for i in range(len(factors)): + if image.shape[i] % factors[i] != 0: + pad_size.append(factors[i] - (image.shape[i] % factors[i])) + else: + pad_size.append(0) + + for i in range(len(pad_size)): + image = _pad_asymmetric_zeros(image, pad_size[i], i) + + out = view_as_blocks(image, factors) + block_shape = out.shape + + for i in range(len(block_shape) // 2): + out = func(out, axis=-1) + + return out + + +def block_sum(image, block_size): + """Sum elements in local blocks. + + The image is padded with zeros if it is not perfectly divisible by integer + factors. + + Parameters + ---------- + image : ndarray + N-dimensional input image. + block_size : array_like + Array containing down-sampling integer factor along each axis. + + Returns + ------- + image : ndarray + Down-sampled image with same number of dimensions as input image. + + Example + ------- + >>> a = np.arange(15).reshape(3, 5) + >>> a + image([[ 0, 1, 2, 3, 4], + [ 5, 6, 7, 8, 9], + [10, 11, 12, 13, 14]]) + >>> sum_blocks(a, (2, 3)) + image([[21, 24], + [33, 27]]) + + """ + return _block_func(image, block_size, np.sum) + + +def block_mean(image, block_size): + """Average elements in local blocks. + + The image is padded with zeros if it is not perfectly divisible by integer + factors. + + Parameters + ---------- + image : ndarray + N-dimensional input image. + block_size : array_like + Array containing down-sampling integer factor along each axis. + + Returns + ------- + image : ndarray + Down-sampled image with same number of dimensions as input image. + + Example + ------- + >>> a = np.arange(15).reshape(3, 5) + >>> a + image([[ 0, 1, 2, 3, 4], + [ 5, 6, 7, 8, 9], + [10, 11, 12, 13, 14]]) + >>> sum_blocks(a, (2, 3)) + image([[21, 24], + [33, 27]]) + + """ + return _block_func(image, block_size, np.mean) + + +def block_median(image, block_size): + """Median element in local blocks. + + The image is padded with zeros if it is not perfectly divisible by integer + factors. + + Parameters + ---------- + image : ndarray + N-dimensional input image. + block_size : array_like + Array containing down-sampling integer factor along each axis. + + Returns + ------- + image : ndarray + Down-sampled image with same number of dimensions as input image. + + Example + ------- + >>> a = np.arange(15).reshape(3, 5) + >>> a + image([[ 0, 1, 2, 3, 4], + [ 5, 6, 7, 8, 9], + [10, 11, 12, 13, 14]]) + >>> sum_blocks(a, (2, 3)) + image([[21, 24], + [33, 27]]) + + """ + return _block_func(image, block_size, np.median) + + +def block_min(image, block_size): + """Minimum element in local blocks. + + The image is padded with zeros if it is not perfectly divisible by integer + factors. + + Parameters + ---------- + image : ndarray + N-dimensional input image. + block_size : array_like + Array containing down-sampling integer factor along each axis. + + Returns + ------- + image : ndarray + Down-sampled image with same number of dimensions as input image. + + Example + ------- + >>> a = np.arange(15).reshape(3, 5) + >>> a + image([[ 0, 1, 2, 3, 4], + [ 5, 6, 7, 8, 9], + [10, 11, 12, 13, 14]]) + >>> sum_blocks(a, (2, 3)) + image([[21, 24], + [33, 27]]) + + """ + return _block_func(image, block_size, np.min) + + +def block_max(image, block_size): + """Maximum element in local blocks. + + The image is padded with zeros if it is not perfectly divisible by integer + factors. + + Parameters + ---------- + image : ndarray + N-dimensional input image. + block_size : array_like + Array containing down-sampling integer factor along each axis. + + Returns + ------- + image : ndarray + Down-sampled image with same number of dimensions as input image. + + Example + ------- + >>> a = np.arange(15).reshape(3, 5) + >>> a + image([[ 0, 1, 2, 3, 4], + [ 5, 6, 7, 8, 9], + [10, 11, 12, 13, 14]]) + >>> sum_blocks(a, (2, 3)) + image([[21, 24], + [33, 27]]) + + """ + return _block_func(image, block_size, np.max) diff --git a/skimage/measure/tests/test_blocks.py b/skimage/measure/tests/test_blocks.py new file mode 100644 index 00000000..77dc2b11 --- /dev/null +++ b/skimage/measure/tests/test_blocks.py @@ -0,0 +1,21 @@ +import numpy as np +from numpy.testing import assert_array_equal +from skimage.measure import block_sum + + +def test_block_sum(): + image1 = np.arange(4 * 6).reshape(4, 6) + out1 = block_sum(image1, (2, 3)) + expected1 = np.array([[ 24, 42], + [ 96, 114]]) + assert_array_equal(expected1, out1) + + image2 = np.arange(5 * 8).reshape(5, 8) + out2 = block_sum(image2, (3, 3)) + expected2 = np.array([[ 81, 108, 87], + [174, 192, 138]]) + assert_array_equal(expected2, out2) + + +if __name__ == "__main__": + np.testing.run_module_suite() diff --git a/skimage/measure/tests/test_structural_similarity.py b/skimage/measure/tests/test_structural_similarity.py index ec5ce7ef..e08f2c31 100644 --- a/skimage/measure/tests/test_structural_similarity.py +++ b/skimage/measure/tests/test_structural_similarity.py @@ -68,5 +68,6 @@ def test_invalid_input(): assert_raises(ValueError, ssim, X, X, win_size=8) + if __name__ == "__main__": np.testing.run_module_suite() diff --git a/skimage/measure/tests/test_sum_blocks.py b/skimage/measure/tests/test_sum_blocks.py deleted file mode 100644 index b4910495..00000000 --- a/skimage/measure/tests/test_sum_blocks.py +++ /dev/null @@ -1,16 +0,0 @@ -import numpy as np -from numpy.testing import assert_array_equal -from skimage.measure._sum_blocks import sum_blocks - -def test_downsample_sum_blocks(): - """Verifying downsampling of an array with expected result in sum mode""" - image1 = np.arange(4*6).reshape(4, 6) - out1 = sum_blocks(image1, (2, 3)) - expected1 = np.array([[ 24, 42], - [ 96, 114]]) - assert_array_equal(expected1, out1) - image2 = np.arange(5*8).reshape(5, 8) - out2 = sum_blocks(image2, (3, 3)) - expected2 = np.array([[ 81, 108, 87], - [174, 192, 138]]) - assert_array_equal(expected2, out2) diff --git a/skimage/transform/__init__.py b/skimage/transform/__init__.py index f079ada4..15513f94 100644 --- a/skimage/transform/__init__.py +++ b/skimage/transform/__init__.py @@ -9,7 +9,7 @@ from ._geometric import (warp, warp_coords, estimate_transform, SimilarityTransform, AffineTransform, ProjectiveTransform, PolynomialTransform, PiecewiseAffineTransform) -from ._warps import swirl, resize, rotate, rescale, downscale_local_means +from ._warps import swirl, resize, rotate, rescale, downscale_local_mean from .pyramids import (pyramid_reduce, pyramid_expand, pyramid_gaussian, pyramid_laplacian) @@ -40,7 +40,7 @@ __all__ = ['hough_circle', 'resize', 'rotate', 'rescale', - 'downscale_local_means', + 'downscale_local_mean', 'pyramid_reduce', 'pyramid_expand', 'pyramid_gaussian', diff --git a/skimage/transform/_warps.py b/skimage/transform/_warps.py index c2727c74..cefe61a3 100644 --- a/skimage/transform/_warps.py +++ b/skimage/transform/_warps.py @@ -2,17 +2,16 @@ import numpy as np from scipy import ndimage from ._geometric import warp, SimilarityTransform, AffineTransform -from skimage.util.shape import view_as_blocks, _pad_asymmetric_zeros +from ..measure.blocks import _block_func def resize(image, output_shape, order=1, mode='constant', cval=0.): """Resize image to match a certain size. - Resize performs interpolation to upsample or downsample 2D arrays. For - downsampling any n-dimensional array by performing arithmetic sum or - arithmetic mean, see measure._sum_blocks.sum_blocks and - transform._warps.downscale_local_means respectively. - + Performs interpolation to up-size or down-size images. For down-sampling + N-dimensional images by applying the arithmetic sum or mean, see + `skimage.measure.sum_blocks` and `skimage.transform.downscale_local_means`, + respectively. Parameters ---------- @@ -95,10 +94,10 @@ def resize(image, output_shape, order=1, mode='constant', cval=0.): def rescale(image, scale, order=1, mode='constant', cval=0.): """Scale image by a certain factor. - Rescale performs interpolation to upsample or downsample 2D arrays. For - downsampling any n-dimensional array by performing arithmetic sum or - arithmetic mean, see measure._sum_blocks.sum_blocks and - transform._warps.downscale_local_means respectively. + Performs interpolation to upscale or down-scale images. For down-sampling + N-dimensional images with integer factors by applying the arithmetic sum or + mean, see `skimage.measure.sum_blocks` and + `skimage.transform.downscale_local_means`, respectively. Parameters ---------- @@ -226,6 +225,44 @@ def rotate(image, angle, resize=False, order=1, mode='constant', cval=0.): mode=mode, cval=cval) +def downscale_local_mean(image, factors): + """Down-sample N-dimensional image by local averaging. + + The image is padded with zeros if it is not perfectly divisible by integer + factors. + + In contrast to the 2-D interpolation in `skimage.transform.resize` and + `skimage.transform.rescale` this function may be applied to N-dimensional + images and calculates the local mean of elements in each block of size + `factors` in the input image. + + Parameters + ---------- + image : ndarray + N-dimensional input image. + factors : array_like + Array containing down-sampling integer factor along each axis. + + Returns + ------- + image : ndarray + Down-sampled image with same number of dimensions as input image. + + Example + ------- + >>> a = np.arange(15).reshape(3, 5) + >>> a + array([[ 0, 1, 2, 3, 4], + [ 5, 6, 7, 8, 9], + [10, 11, 12, 13, 14]]) + >>> downscale_local_means(a, (2, 3)) + array([[3.5, 4.], + [5.5, 4.5]]) + + """ + return _block_func(image, factors, np.mean) + + def _swirl_mapping(xy, center, rotation, strength, radius): x, y = xy.T x0, y0 = center @@ -296,90 +333,3 @@ def swirl(image, center=None, strength=1, radius=100, rotation=0, return warp(image, _swirl_mapping, map_args=warp_args, output_shape=output_shape, order=order, mode=mode, cval=cval) - - -def _downsample(array, factors, sum=True): - """Performs downsampling with integer factors. - - Parameters - ---------- - array : ndarray - Input n-dimensional array. - factors: tuple - Tuple containing downsampling factor along each axis. - sum : bool - If True, downsampled element is the sum of its corresponding - constituent elements in the input array. Default is True. - - Returns - ------- - array : ndarray - Downsampled array with same number of dimensions as that of input - array. - - """ - - pad_size = [] - if len(factors) != array.ndim: - raise ValueError("'factors' must have the same length " - "as 'array.shape'") - else: - for i in range(len(factors)): - if array.shape[i] % factors[i] != 0: - pad_size.append(factors[i] - (array.shape[i] % factors[i])) - else: - pad_size.append(0) - - for i in range(len(pad_size)): - array = _pad_asymmetric_zeros(array, pad_size[i], i) - - out = view_as_blocks(array, factors) - block_shape = out.shape - - if sum: - for i in range(len(block_shape) // 2): - out = out.sum(-1) - else: - for i in range(len(block_shape) // 2): - out = out.mean(-1) - return out - - -def downscale_local_means(array, factors): - """Downsamples the array in blocks of input integer factors after padding - the original array with zeroes if the dimensions are not perfectly - divisible by factors and replaces it with mean i.e. average value. - - This function is different from resize and rescale in the sense that they - use interpolation to upsample or downsample on a 2D array, while this - function performs only dawnsampling but on any n-dimensional array and - returns the arithmetic mean of elements in a block of size factors in the - original array. - - Parameters - ---------- - array : ndarray - Input n-dimensional array. - factors: tuple - Tuple containing integer values representing block length along each - axis. - - Returns - ------- - array : ndarray - Downsampled array with same number of dimensions as that of input - array. - - Example - ------- - >>> a = np.arange(15).reshape(3, 5) - >>> a - array([[ 0, 1, 2, 3, 4], - [ 5, 6, 7, 8, 9], - [10, 11, 12, 13, 14]]) - >>> downscale_local_means(a, (2,3)) - array([[3.5, 4.], - [5.5, 4.5]]) - - """ - return _downsample(array, factors, False) diff --git a/skimage/transform/tests/test_warps.py b/skimage/transform/tests/test_warps.py index 88ede530..272be66e 100644 --- a/skimage/transform/tests/test_warps.py +++ b/skimage/transform/tests/test_warps.py @@ -6,7 +6,7 @@ from skimage.transform import (warp, warp_coords, rotate, resize, rescale, AffineTransform, ProjectiveTransform, SimilarityTransform, - downscale_local_means) + downscale_local_mean) from skimage import transform as tf, data, img_as_float from skimage.color import rgb2gray @@ -195,15 +195,15 @@ def test_warp_coords_example(): map_coordinates(image[:, :, 0], coords[:2]) -def test_downscale_local_means(): +def test_downscale_local_mean(): """Verifying downsampling of an array with expected result in mean mode""" image1 = np.arange(4*6).reshape(4, 6) - out1 = downscale_local_means(image1, (2, 3)) + out1 = downscale_local_mean(image1, (2, 3)) expected1 = np.array([[ 4., 7.], [ 16., 19.]]) assert_array_equal(expected1, out1) image2 = np.arange(5*8).reshape(5, 8) - out2 = downscale_local_means(image2, (4, 5)) + out2 = downscale_local_mean(image2, (4, 5)) expected2 = np.array([[ 14. , 10.8], [ 8.5, 5.7]]) assert_array_equal(expected2, out2) From f9546d0d1447c1eb3807cdcf72a66a222cb4472b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Fri, 5 Jul 2013 09:07:02 +0200 Subject: [PATCH 02/11] Fix import namespace --- skimage/measure/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/skimage/measure/__init__.py b/skimage/measure/__init__.py index 4c44dc2f..021a6edf 100755 --- a/skimage/measure/__init__.py +++ b/skimage/measure/__init__.py @@ -16,4 +16,8 @@ __all__ = ['find_contours', 'CircleModel', 'EllipseModel', 'ransac', - 'sum_blocks'] + 'block_sum', + 'block_mean', + 'block_median', + 'block_min', + 'block_max'] From 5579aa22985299ff7dd35de37eb6756993c9964f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Fri, 5 Jul 2013 09:13:50 +0200 Subject: [PATCH 03/11] Fix doc string examples --- skimage/measure/blocks.py | 32 +++++++++++++++----------------- skimage/transform/_warps.py | 2 +- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/skimage/measure/blocks.py b/skimage/measure/blocks.py index 428ecf11..0e45cde2 100644 --- a/skimage/measure/blocks.py +++ b/skimage/measure/blocks.py @@ -70,7 +70,7 @@ def block_sum(image, block_size): image([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14]]) - >>> sum_blocks(a, (2, 3)) + >>> block_sum(a, (2, 3)) image([[21, 24], [33, 27]]) @@ -103,9 +103,9 @@ def block_mean(image, block_size): image([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14]]) - >>> sum_blocks(a, (2, 3)) - image([[21, 24], - [33, 27]]) + >>> block_mean(a, (2, 3)) + array([[ 3.5, 4. ], + [ 5.5, 4.5]]) """ return _block_func(image, block_size, np.mean) @@ -131,14 +131,12 @@ def block_median(image, block_size): Example ------- - >>> a = np.arange(15).reshape(3, 5) + >>> a = np.array([[1, 5, 100], [0, 5, 1000]]) >>> a - image([[ 0, 1, 2, 3, 4], - [ 5, 6, 7, 8, 9], - [10, 11, 12, 13, 14]]) - >>> sum_blocks(a, (2, 3)) - image([[21, 24], - [33, 27]]) + array([[ 1, 5, 100], + [ 0, 5, 1000]]) + >>> block_median(a, (2, 3)) + array([[ 5.]]) """ return _block_func(image, block_size, np.median) @@ -169,9 +167,9 @@ def block_min(image, block_size): image([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14]]) - >>> sum_blocks(a, (2, 3)) - image([[21, 24], - [33, 27]]) + >>> block_min(a, (2, 2)) + array([[0, 2, 0], + [0, 0, 0]]) """ return _block_func(image, block_size, np.min) @@ -202,9 +200,9 @@ def block_max(image, block_size): image([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14]]) - >>> sum_blocks(a, (2, 3)) - image([[21, 24], - [33, 27]]) + >>> block_max(a, (2, 3)) + array([[ 7, 9], + [12, 14]]) """ return _block_func(image, block_size, np.max) diff --git a/skimage/transform/_warps.py b/skimage/transform/_warps.py index cefe61a3..c3d918ee 100644 --- a/skimage/transform/_warps.py +++ b/skimage/transform/_warps.py @@ -255,7 +255,7 @@ def downscale_local_mean(image, factors): array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14]]) - >>> downscale_local_means(a, (2, 3)) + >>> downscale_local_mean(a, (2, 3)) array([[3.5, 4.], [5.5, 4.5]]) From c0a019eb12fdcbe28ebd5668247d2f366b26a7de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Fri, 5 Jul 2013 09:28:28 +0200 Subject: [PATCH 04/11] Update test cases for block functions --- skimage/measure/tests/test_blocks.py | 63 ++++++++++++++++++++++++++- skimage/transform/tests/test_warps.py | 6 +-- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/skimage/measure/tests/test_blocks.py b/skimage/measure/tests/test_blocks.py index 77dc2b11..11894585 100644 --- a/skimage/measure/tests/test_blocks.py +++ b/skimage/measure/tests/test_blocks.py @@ -1,6 +1,7 @@ import numpy as np from numpy.testing import assert_array_equal -from skimage.measure import block_sum +from skimage.measure import (block_sum, block_mean, block_median, block_min, + block_max) def test_block_sum(): @@ -17,5 +18,65 @@ def test_block_sum(): assert_array_equal(expected2, out2) +def test_block_mean(): + image1 = np.arange(4 * 6).reshape(4, 6) + out1 = block_mean(image1, (2, 3)) + expected1 = np.array([[ 4., 7.], + [ 16., 19.]]) + assert_array_equal(expected1, out1) + + image2 = np.arange(5 * 8).reshape(5, 8) + out2 = block_mean(image2, (4, 5)) + expected2 = np.array([[14. , 10.8], + [ 8.5, 5.7]]) + assert_array_equal(expected2, out2) + + +def test_block_median(): + image1 = np.arange(4 * 6).reshape(4, 6) + out1 = block_median(image1, (2, 3)) + expected1 = np.array([[ 4., 7.], + [ 16., 19.]]) + assert_array_equal(expected1, out1) + + image2 = np.arange(5 * 8).reshape(5, 8) + out2 = block_median(image2, (4, 5)) + expected2 = np.array([[ 14., 17.], + [ 0., 0.]]) + assert_array_equal(expected2, out2) + + image3 = np.array([[1, 5, 5, 5], [5, 5, 5, 1000]]) + out3 = block_median(image3, (2, 4)) + assert_array_equal(5, out3) + + +def test_block_min(): + image1 = np.arange(4 * 6).reshape(4, 6) + out1 = block_min(image1, (2, 3)) + expected1 = np.array([[ 0, 3], + [12, 15]]) + assert_array_equal(expected1, out1) + + image2 = np.arange(5 * 8).reshape(5, 8) + out2 = block_min(image2, (4, 5)) + expected2 = np.array([[0, 0], + [0, 0]]) + assert_array_equal(expected2, out2) + + +def test_block_max(): + image1 = np.arange(4 * 6).reshape(4, 6) + out1 = block_max(image1, (2, 3)) + expected1 = np.array([[ 8, 11], + [20, 23]]) + assert_array_equal(expected1, out1) + + image2 = np.arange(5 * 8).reshape(5, 8) + out2 = block_max(image2, (4, 5)) + expected2 = np.array([[28, 31], + [36, 39]]) + assert_array_equal(expected2, out2) + + if __name__ == "__main__": np.testing.run_module_suite() diff --git a/skimage/transform/tests/test_warps.py b/skimage/transform/tests/test_warps.py index 272be66e..af2b95da 100644 --- a/skimage/transform/tests/test_warps.py +++ b/skimage/transform/tests/test_warps.py @@ -196,13 +196,13 @@ def test_warp_coords_example(): def test_downscale_local_mean(): - """Verifying downsampling of an array with expected result in mean mode""" - image1 = np.arange(4*6).reshape(4, 6) + image1 = np.arange(4 * 6).reshape(4, 6) out1 = downscale_local_mean(image1, (2, 3)) expected1 = np.array([[ 4., 7.], [ 16., 19.]]) assert_array_equal(expected1, out1) - image2 = np.arange(5*8).reshape(5, 8) + + image2 = np.arange(5 * 8).reshape(5, 8) out2 = downscale_local_mean(image2, (4, 5)) expected2 = np.array([[ 14. , 10.8], [ 8.5, 5.7]]) From 9d806eb413942bafa23e675ff912dd0a27764a9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Fri, 5 Jul 2013 09:32:06 +0200 Subject: [PATCH 05/11] Update doc string for new functionality --- skimage/measure/blocks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skimage/measure/blocks.py b/skimage/measure/blocks.py index 0e45cde2..abeef10f 100644 --- a/skimage/measure/blocks.py +++ b/skimage/measure/blocks.py @@ -3,7 +3,7 @@ from ..util.shape import view_as_blocks, _pad_asymmetric_zeros def _block_func(image, factors, func): - """Down-sample image by integer factors. + """Down-sample image by applying function to local blocks. Parameters ---------- From 4f6b39dcd3fe85ee2453f3ba35fa84ad9ee68550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Fri, 5 Jul 2013 14:19:10 +0200 Subject: [PATCH 06/11] Rename block_* functions to local_* --- skimage/measure/__init__.py | 12 +++---- skimage/measure/{blocks.py => local.py} | 22 ++++++------ .../tests/{test_blocks.py => test_local.py} | 36 +++++++++---------- skimage/transform/_warps.py | 4 +-- 4 files changed, 37 insertions(+), 37 deletions(-) rename skimage/measure/{blocks.py => local.py} (90%) rename skimage/measure/tests/{test_blocks.py => test_local.py} (73%) diff --git a/skimage/measure/__init__.py b/skimage/measure/__init__.py index 021a6edf..26eb179c 100755 --- a/skimage/measure/__init__.py +++ b/skimage/measure/__init__.py @@ -3,7 +3,7 @@ from ._regionprops import regionprops, perimeter from ._structural_similarity import structural_similarity from ._polygon import approximate_polygon, subdivide_polygon from .fit import LineModel, CircleModel, EllipseModel, ransac -from .blocks import block_sum, block_median, block_mean, block_min, block_max +from .local import local_sum, local_mean, local_median, local_min, local_max __all__ = ['find_contours', @@ -16,8 +16,8 @@ __all__ = ['find_contours', 'CircleModel', 'EllipseModel', 'ransac', - 'block_sum', - 'block_mean', - 'block_median', - 'block_min', - 'block_max'] + 'local_sum', + 'local_mean', + 'local_median', + 'local_min', + 'local_max'] diff --git a/skimage/measure/blocks.py b/skimage/measure/local.py similarity index 90% rename from skimage/measure/blocks.py rename to skimage/measure/local.py index abeef10f..3f628a53 100644 --- a/skimage/measure/blocks.py +++ b/skimage/measure/local.py @@ -2,7 +2,7 @@ import numpy as np from ..util.shape import view_as_blocks, _pad_asymmetric_zeros -def _block_func(image, factors, func): +def _local_func(image, factors, func): """Down-sample image by applying function to local blocks. Parameters @@ -45,7 +45,7 @@ def _block_func(image, factors, func): return out -def block_sum(image, block_size): +def local_sum(image, block_size): """Sum elements in local blocks. The image is padded with zeros if it is not perfectly divisible by integer @@ -75,10 +75,10 @@ def block_sum(image, block_size): [33, 27]]) """ - return _block_func(image, block_size, np.sum) + return _local_func(image, block_size, np.sum) -def block_mean(image, block_size): +def local_mean(image, block_size): """Average elements in local blocks. The image is padded with zeros if it is not perfectly divisible by integer @@ -108,10 +108,10 @@ def block_mean(image, block_size): [ 5.5, 4.5]]) """ - return _block_func(image, block_size, np.mean) + return _local_func(image, block_size, np.mean) -def block_median(image, block_size): +def local_median(image, block_size): """Median element in local blocks. The image is padded with zeros if it is not perfectly divisible by integer @@ -139,10 +139,10 @@ def block_median(image, block_size): array([[ 5.]]) """ - return _block_func(image, block_size, np.median) + return _local_func(image, block_size, np.median) -def block_min(image, block_size): +def local_min(image, block_size): """Minimum element in local blocks. The image is padded with zeros if it is not perfectly divisible by integer @@ -172,10 +172,10 @@ def block_min(image, block_size): [0, 0, 0]]) """ - return _block_func(image, block_size, np.min) + return _local_func(image, block_size, np.min) -def block_max(image, block_size): +def local_max(image, block_size): """Maximum element in local blocks. The image is padded with zeros if it is not perfectly divisible by integer @@ -205,4 +205,4 @@ def block_max(image, block_size): [12, 14]]) """ - return _block_func(image, block_size, np.max) + return _local_func(image, block_size, np.max) diff --git a/skimage/measure/tests/test_blocks.py b/skimage/measure/tests/test_local.py similarity index 73% rename from skimage/measure/tests/test_blocks.py rename to skimage/measure/tests/test_local.py index 11894585..fc01b7b9 100644 --- a/skimage/measure/tests/test_blocks.py +++ b/skimage/measure/tests/test_local.py @@ -1,78 +1,78 @@ import numpy as np from numpy.testing import assert_array_equal -from skimage.measure import (block_sum, block_mean, block_median, block_min, - block_max) +from skimage.measure import (local_sum, local_mean, local_median, local_min, + local_max) -def test_block_sum(): +def test_local_sum(): image1 = np.arange(4 * 6).reshape(4, 6) - out1 = block_sum(image1, (2, 3)) + out1 = local_sum(image1, (2, 3)) expected1 = np.array([[ 24, 42], [ 96, 114]]) assert_array_equal(expected1, out1) image2 = np.arange(5 * 8).reshape(5, 8) - out2 = block_sum(image2, (3, 3)) + out2 = local_sum(image2, (3, 3)) expected2 = np.array([[ 81, 108, 87], [174, 192, 138]]) assert_array_equal(expected2, out2) -def test_block_mean(): +def test_local_mean(): image1 = np.arange(4 * 6).reshape(4, 6) - out1 = block_mean(image1, (2, 3)) + out1 = local_mean(image1, (2, 3)) expected1 = np.array([[ 4., 7.], [ 16., 19.]]) assert_array_equal(expected1, out1) image2 = np.arange(5 * 8).reshape(5, 8) - out2 = block_mean(image2, (4, 5)) + out2 = local_mean(image2, (4, 5)) expected2 = np.array([[14. , 10.8], [ 8.5, 5.7]]) assert_array_equal(expected2, out2) -def test_block_median(): +def test_local_median(): image1 = np.arange(4 * 6).reshape(4, 6) - out1 = block_median(image1, (2, 3)) + out1 = local_median(image1, (2, 3)) expected1 = np.array([[ 4., 7.], [ 16., 19.]]) assert_array_equal(expected1, out1) image2 = np.arange(5 * 8).reshape(5, 8) - out2 = block_median(image2, (4, 5)) + out2 = local_median(image2, (4, 5)) expected2 = np.array([[ 14., 17.], [ 0., 0.]]) assert_array_equal(expected2, out2) image3 = np.array([[1, 5, 5, 5], [5, 5, 5, 1000]]) - out3 = block_median(image3, (2, 4)) + out3 = local_median(image3, (2, 4)) assert_array_equal(5, out3) -def test_block_min(): +def test_local_min(): image1 = np.arange(4 * 6).reshape(4, 6) - out1 = block_min(image1, (2, 3)) + out1 = local_min(image1, (2, 3)) expected1 = np.array([[ 0, 3], [12, 15]]) assert_array_equal(expected1, out1) image2 = np.arange(5 * 8).reshape(5, 8) - out2 = block_min(image2, (4, 5)) + out2 = local_min(image2, (4, 5)) expected2 = np.array([[0, 0], [0, 0]]) assert_array_equal(expected2, out2) -def test_block_max(): +def test_local_max(): image1 = np.arange(4 * 6).reshape(4, 6) - out1 = block_max(image1, (2, 3)) + out1 = local_max(image1, (2, 3)) expected1 = np.array([[ 8, 11], [20, 23]]) assert_array_equal(expected1, out1) image2 = np.arange(5 * 8).reshape(5, 8) - out2 = block_max(image2, (4, 5)) + out2 = local_max(image2, (4, 5)) expected2 = np.array([[28, 31], [36, 39]]) assert_array_equal(expected2, out2) diff --git a/skimage/transform/_warps.py b/skimage/transform/_warps.py index c3d918ee..6511182b 100644 --- a/skimage/transform/_warps.py +++ b/skimage/transform/_warps.py @@ -2,7 +2,7 @@ import numpy as np from scipy import ndimage from ._geometric import warp, SimilarityTransform, AffineTransform -from ..measure.blocks import _block_func +from ..measure.local import _local_func def resize(image, output_shape, order=1, mode='constant', cval=0.): @@ -260,7 +260,7 @@ def downscale_local_mean(image, factors): [5.5, 4.5]]) """ - return _block_func(image, factors, np.mean) + return _local_func(image, factors, np.mean) def _swirl_mapping(xy, center, rotation, strength, radius): From b7f72ff15fe20abb64a099ae99e7859a7acb1bbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Fri, 5 Jul 2013 14:36:25 +0200 Subject: [PATCH 07/11] Fix deprecated function name referneces in doc strings --- skimage/transform/_warps.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/skimage/transform/_warps.py b/skimage/transform/_warps.py index 6511182b..539e8b8d 100644 --- a/skimage/transform/_warps.py +++ b/skimage/transform/_warps.py @@ -10,7 +10,7 @@ def resize(image, output_shape, order=1, mode='constant', cval=0.): Performs interpolation to up-size or down-size images. For down-sampling N-dimensional images by applying the arithmetic sum or mean, see - `skimage.measure.sum_blocks` and `skimage.transform.downscale_local_means`, + `skimage.measure.local_sum` and `skimage.transform.downscale_local_mean`, respectively. Parameters @@ -96,8 +96,8 @@ def rescale(image, scale, order=1, mode='constant', cval=0.): Performs interpolation to upscale or down-scale images. For down-sampling N-dimensional images with integer factors by applying the arithmetic sum or - mean, see `skimage.measure.sum_blocks` and - `skimage.transform.downscale_local_means`, respectively. + mean, see `skimage.measure.local_sum` and + `skimage.transform.downscale_local_mean`, respectively. Parameters ---------- From 06aaf93e6389401e63d16f2742dff491def407d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Fri, 5 Jul 2013 17:34:19 +0200 Subject: [PATCH 08/11] Use pad function and add option to define cval --- skimage/measure/local.py | 88 ++++++++++++++++++++++--------------- skimage/transform/_warps.py | 16 ++++--- skimage/util/shape.py | 12 ----- 3 files changed, 63 insertions(+), 53 deletions(-) diff --git a/skimage/measure/local.py b/skimage/measure/local.py index 3f628a53..bcb587cf 100644 --- a/skimage/measure/local.py +++ b/skimage/measure/local.py @@ -1,19 +1,22 @@ import numpy as np -from ..util.shape import view_as_blocks, _pad_asymmetric_zeros +from skimage.util import view_as_blocks, pad -def _local_func(image, factors, func): +def _local_func(image, block_size, func, cval): """Down-sample image by applying function to local blocks. Parameters ---------- image : ndarray N-dimensional input image. - factors : array_like + block_size : array_like Array containing down-sampling integer factor along each axis. func : object Function object which is used to calculate the return value for each local block, e.g. `numpy.sum`. + cval : float, optional + Constant padding value if image is not perfectly divisible by the + block size. Returns ------- @@ -22,34 +25,34 @@ def _local_func(image, factors, func): """ - pad_size = [] - if len(factors) != image.ndim: - raise ValueError("`factors` must have the same length " + if len(block_size) != image.ndim: + raise ValueError("`block_size` must have the same length " "as `image.shape`.") - for i in range(len(factors)): - if image.shape[i] % factors[i] != 0: - pad_size.append(factors[i] - (image.shape[i] % factors[i])) + 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: - pad_size.append(0) + after_width = 0 + pad_width.append((0, after_width)) - for i in range(len(pad_size)): - image = _pad_asymmetric_zeros(image, pad_size[i], i) + image = pad(image, pad_width=pad_width, mode='constant', + constant_values=cval) - out = view_as_blocks(image, factors) - block_shape = out.shape + out = view_as_blocks(image, block_size) - for i in range(len(block_shape) // 2): + for i in range(len(out.shape) // 2): out = func(out, axis=-1) return out -def local_sum(image, block_size): +def local_sum(image, block_size, cval=0): """Sum elements in local blocks. - The image is padded with zeros if it is not perfectly divisible by integer - factors. + The image is padded with zeros if it is not perfectly divisible by the + block size. Parameters ---------- @@ -57,6 +60,9 @@ def local_sum(image, block_size): N-dimensional input image. block_size : array_like Array containing down-sampling integer factor along each axis. + cval : float, optional + Constant padding value if image is not perfectly divisible by the + block size. Returns ------- @@ -75,14 +81,14 @@ def local_sum(image, block_size): [33, 27]]) """ - return _local_func(image, block_size, np.sum) + return _local_func(image, block_size, np.sum, cval) -def local_mean(image, block_size): +def local_mean(image, block_size, cval=0): """Average elements in local blocks. - The image is padded with zeros if it is not perfectly divisible by integer - factors. + The image is padded with zeros if it is not perfectly divisible by the + block size. Parameters ---------- @@ -90,6 +96,9 @@ def local_mean(image, block_size): N-dimensional input image. block_size : array_like Array containing down-sampling integer factor along each axis. + cval : float, optional + Constant padding value if image is not perfectly divisible by the + block size. Returns ------- @@ -108,14 +117,14 @@ def local_mean(image, block_size): [ 5.5, 4.5]]) """ - return _local_func(image, block_size, np.mean) + return _local_func(image, block_size, np.mean, cval) -def local_median(image, block_size): +def local_median(image, block_size, cval=0): """Median element in local blocks. - The image is padded with zeros if it is not perfectly divisible by integer - factors. + The image is padded with zeros if it is not perfectly divisible by the + block size. Parameters ---------- @@ -123,6 +132,9 @@ def local_median(image, block_size): N-dimensional input image. block_size : array_like Array containing down-sampling integer factor along each axis. + cval : float, optional + Constant padding value if image is not perfectly divisible by the + block size. Returns ------- @@ -139,14 +151,14 @@ def local_median(image, block_size): array([[ 5.]]) """ - return _local_func(image, block_size, np.median) + return _local_func(image, block_size, np.median, cval) -def local_min(image, block_size): +def local_min(image, block_size, cval=0): """Minimum element in local blocks. - The image is padded with zeros if it is not perfectly divisible by integer - factors. + The image is padded with zeros if it is not perfectly divisible by the + block size. Parameters ---------- @@ -154,6 +166,9 @@ def local_min(image, block_size): N-dimensional input image. block_size : array_like Array containing down-sampling integer factor along each axis. + cval : float, optional + Constant padding value if image is not perfectly divisible by the + block size. Returns ------- @@ -172,14 +187,14 @@ def local_min(image, block_size): [0, 0, 0]]) """ - return _local_func(image, block_size, np.min) + return _local_func(image, block_size, np.min, cval) -def local_max(image, block_size): +def local_max(image, block_size, cval=0): """Maximum element in local blocks. - The image is padded with zeros if it is not perfectly divisible by integer - factors. + The image is padded with zeros if it is not perfectly divisible by the + block size. Parameters ---------- @@ -187,6 +202,9 @@ def local_max(image, block_size): N-dimensional input image. block_size : array_like Array containing down-sampling integer factor along each axis. + cval : float, optional + Constant padding value if image is not perfectly divisible by the + block size. Returns ------- @@ -205,4 +223,4 @@ def local_max(image, block_size): [12, 14]]) """ - return _local_func(image, block_size, np.max) + return _local_func(image, block_size, np.max, cval) diff --git a/skimage/transform/_warps.py b/skimage/transform/_warps.py index 539e8b8d..e4463721 100644 --- a/skimage/transform/_warps.py +++ b/skimage/transform/_warps.py @@ -1,8 +1,9 @@ import numpy as np from scipy import ndimage -from ._geometric import warp, SimilarityTransform, AffineTransform -from ..measure.local import _local_func +from skimage.transform._geometric import (warp, SimilarityTransform, + AffineTransform) +from skimage.measure.local import _local_func def resize(image, output_shape, order=1, mode='constant', cval=0.): @@ -225,11 +226,11 @@ def rotate(image, angle, resize=False, order=1, mode='constant', cval=0.): mode=mode, cval=cval) -def downscale_local_mean(image, factors): +def downscale_local_mean(image, factors, cval=0): """Down-sample N-dimensional image by local averaging. - The image is padded with zeros if it is not perfectly divisible by integer - factors. + The image is padded with `cval` if it is not perfectly divisible by the + integer factors. In contrast to the 2-D interpolation in `skimage.transform.resize` and `skimage.transform.rescale` this function may be applied to N-dimensional @@ -242,6 +243,9 @@ def downscale_local_mean(image, factors): N-dimensional input image. factors : array_like Array containing down-sampling integer factor along each axis. + cval : float, optional + Constant padding value if image is not perfectly divisible by the + integer factors. Returns ------- @@ -260,7 +264,7 @@ def downscale_local_mean(image, factors): [5.5, 4.5]]) """ - return _local_func(image, factors, np.mean) + return _local_func(image, factors, np.mean, cval) def _swirl_mapping(xy, center, rotation, strength, radius): diff --git a/skimage/util/shape.py b/skimage/util/shape.py index 2763d3d4..0126d2e3 100644 --- a/skimage/util/shape.py +++ b/skimage/util/shape.py @@ -230,15 +230,3 @@ def view_as_windows(arr_in, window_shape): arr_out = as_strided(arr_in, shape=new_shape, strides=new_strides) return arr_out - - -def _pad_asymmetric_zeros(arr, pad_amt, axis=-1): - """Pads `arr` with zeros by `pad_amt` along specified `axis`""" - if axis == -1: - axis = arr.ndim - 1 - - zeroshape = tuple([x if i != axis else pad_amt - for (i, x) in enumerate(arr.shape)]) - - return np.concatenate((arr, np.zeros(zeroshape, dtype=arr.dtype)), - axis=axis) From 486909c5f5cacf03c516c28ab9416660c395d0e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Mon, 15 Jul 2013 21:51:55 +0200 Subject: [PATCH 09/11] Rename and combine local_* functions to block_reduce --- skimage/measure/__init__.py | 8 +- skimage/measure/block.py | 49 ++++ skimage/measure/local.py | 226 ------------------ .../tests/{test_local.py => test_block.py} | 35 ++- 4 files changed, 68 insertions(+), 250 deletions(-) create mode 100644 skimage/measure/block.py delete mode 100644 skimage/measure/local.py rename skimage/measure/tests/{test_local.py => test_block.py} (70%) diff --git a/skimage/measure/__init__.py b/skimage/measure/__init__.py index 26eb179c..423aa9a7 100755 --- a/skimage/measure/__init__.py +++ b/skimage/measure/__init__.py @@ -3,7 +3,7 @@ from ._regionprops import regionprops, perimeter from ._structural_similarity import structural_similarity from ._polygon import approximate_polygon, subdivide_polygon from .fit import LineModel, CircleModel, EllipseModel, ransac -from .local import local_sum, local_mean, local_median, local_min, local_max +from .block import block_reduce __all__ = ['find_contours', @@ -16,8 +16,4 @@ __all__ = ['find_contours', 'CircleModel', 'EllipseModel', 'ransac', - 'local_sum', - 'local_mean', - 'local_median', - 'local_min', - 'local_max'] + 'block_reduce'] diff --git a/skimage/measure/block.py b/skimage/measure/block.py new file mode 100644 index 00000000..7bef1220 --- /dev/null +++ b/skimage/measure/block.py @@ -0,0 +1,49 @@ +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. + + """ + + 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 diff --git a/skimage/measure/local.py b/skimage/measure/local.py deleted file mode 100644 index bcb587cf..00000000 --- a/skimage/measure/local.py +++ /dev/null @@ -1,226 +0,0 @@ -import numpy as np -from skimage.util import view_as_blocks, pad - - -def _local_func(image, block_size, func, cval): - """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 : object - Function object which is used to calculate the return value for each - local block, e.g. `numpy.sum`. - cval : float, optional - 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. - - """ - - 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 - - -def local_sum(image, block_size, cval=0): - """Sum elements in local blocks. - - The image is padded with zeros if it is not perfectly divisible by the - block size. - - Parameters - ---------- - image : ndarray - N-dimensional input image. - block_size : array_like - Array containing down-sampling integer factor along each axis. - cval : float, optional - 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. - - Example - ------- - >>> a = np.arange(15).reshape(3, 5) - >>> a - image([[ 0, 1, 2, 3, 4], - [ 5, 6, 7, 8, 9], - [10, 11, 12, 13, 14]]) - >>> block_sum(a, (2, 3)) - image([[21, 24], - [33, 27]]) - - """ - return _local_func(image, block_size, np.sum, cval) - - -def local_mean(image, block_size, cval=0): - """Average elements in local blocks. - - The image is padded with zeros if it is not perfectly divisible by the - block size. - - Parameters - ---------- - image : ndarray - N-dimensional input image. - block_size : array_like - Array containing down-sampling integer factor along each axis. - cval : float, optional - 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. - - Example - ------- - >>> a = np.arange(15).reshape(3, 5) - >>> a - image([[ 0, 1, 2, 3, 4], - [ 5, 6, 7, 8, 9], - [10, 11, 12, 13, 14]]) - >>> block_mean(a, (2, 3)) - array([[ 3.5, 4. ], - [ 5.5, 4.5]]) - - """ - return _local_func(image, block_size, np.mean, cval) - - -def local_median(image, block_size, cval=0): - """Median element in local blocks. - - The image is padded with zeros if it is not perfectly divisible by the - block size. - - Parameters - ---------- - image : ndarray - N-dimensional input image. - block_size : array_like - Array containing down-sampling integer factor along each axis. - cval : float, optional - 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. - - Example - ------- - >>> a = np.array([[1, 5, 100], [0, 5, 1000]]) - >>> a - array([[ 1, 5, 100], - [ 0, 5, 1000]]) - >>> block_median(a, (2, 3)) - array([[ 5.]]) - - """ - return _local_func(image, block_size, np.median, cval) - - -def local_min(image, block_size, cval=0): - """Minimum element in local blocks. - - The image is padded with zeros if it is not perfectly divisible by the - block size. - - Parameters - ---------- - image : ndarray - N-dimensional input image. - block_size : array_like - Array containing down-sampling integer factor along each axis. - cval : float, optional - 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. - - Example - ------- - >>> a = np.arange(15).reshape(3, 5) - >>> a - image([[ 0, 1, 2, 3, 4], - [ 5, 6, 7, 8, 9], - [10, 11, 12, 13, 14]]) - >>> block_min(a, (2, 2)) - array([[0, 2, 0], - [0, 0, 0]]) - - """ - return _local_func(image, block_size, np.min, cval) - - -def local_max(image, block_size, cval=0): - """Maximum element in local blocks. - - The image is padded with zeros if it is not perfectly divisible by the - block size. - - Parameters - ---------- - image : ndarray - N-dimensional input image. - block_size : array_like - Array containing down-sampling integer factor along each axis. - cval : float, optional - 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. - - Example - ------- - >>> a = np.arange(15).reshape(3, 5) - >>> a - image([[ 0, 1, 2, 3, 4], - [ 5, 6, 7, 8, 9], - [10, 11, 12, 13, 14]]) - >>> block_max(a, (2, 3)) - array([[ 7, 9], - [12, 14]]) - - """ - return _local_func(image, block_size, np.max, cval) diff --git a/skimage/measure/tests/test_local.py b/skimage/measure/tests/test_block.py similarity index 70% rename from skimage/measure/tests/test_local.py rename to skimage/measure/tests/test_block.py index fc01b7b9..a8bc62a9 100644 --- a/skimage/measure/tests/test_local.py +++ b/skimage/measure/tests/test_block.py @@ -1,78 +1,77 @@ import numpy as np from numpy.testing import assert_array_equal -from skimage.measure import (local_sum, local_mean, local_median, local_min, - local_max) +from skimage.measure import block_reduce -def test_local_sum(): +def test_block_reduce_sum(): image1 = np.arange(4 * 6).reshape(4, 6) - out1 = local_sum(image1, (2, 3)) + out1 = block_reduce(image1, (2, 3)) expected1 = np.array([[ 24, 42], [ 96, 114]]) assert_array_equal(expected1, out1) image2 = np.arange(5 * 8).reshape(5, 8) - out2 = local_sum(image2, (3, 3)) + out2 = block_reduce(image2, (3, 3)) expected2 = np.array([[ 81, 108, 87], [174, 192, 138]]) assert_array_equal(expected2, out2) -def test_local_mean(): +def test_block_reduce_mean(): image1 = np.arange(4 * 6).reshape(4, 6) - out1 = local_mean(image1, (2, 3)) + out1 = block_reduce(image1, (2, 3), func=np.mean) expected1 = np.array([[ 4., 7.], [ 16., 19.]]) assert_array_equal(expected1, out1) image2 = np.arange(5 * 8).reshape(5, 8) - out2 = local_mean(image2, (4, 5)) + out2 = block_reduce(image2, (4, 5), func=np.mean) expected2 = np.array([[14. , 10.8], [ 8.5, 5.7]]) assert_array_equal(expected2, out2) -def test_local_median(): +def test_block_reduce_median(): image1 = np.arange(4 * 6).reshape(4, 6) - out1 = local_median(image1, (2, 3)) + out1 = block_reduce(image1, (2, 3), func=np.median) expected1 = np.array([[ 4., 7.], [ 16., 19.]]) assert_array_equal(expected1, out1) image2 = np.arange(5 * 8).reshape(5, 8) - out2 = local_median(image2, (4, 5)) + out2 = block_reduce(image2, (4, 5), func=np.median) expected2 = np.array([[ 14., 17.], [ 0., 0.]]) assert_array_equal(expected2, out2) image3 = np.array([[1, 5, 5, 5], [5, 5, 5, 1000]]) - out3 = local_median(image3, (2, 4)) + out3 = block_reduce(image3, (2, 4), func=np.median) assert_array_equal(5, out3) -def test_local_min(): +def test_block_reduce_min(): image1 = np.arange(4 * 6).reshape(4, 6) - out1 = local_min(image1, (2, 3)) + out1 = block_reduce(image1, (2, 3), func=np.min) expected1 = np.array([[ 0, 3], [12, 15]]) assert_array_equal(expected1, out1) image2 = np.arange(5 * 8).reshape(5, 8) - out2 = local_min(image2, (4, 5)) + out2 = block_reduce(image2, (4, 5), func=np.min) expected2 = np.array([[0, 0], [0, 0]]) assert_array_equal(expected2, out2) -def test_local_max(): +def test_block_reduce_max(): image1 = np.arange(4 * 6).reshape(4, 6) - out1 = local_max(image1, (2, 3)) + out1 = block_reduce(image1, (2, 3), func=np.max) expected1 = np.array([[ 8, 11], [20, 23]]) assert_array_equal(expected1, out1) image2 = np.arange(5 * 8).reshape(5, 8) - out2 = local_max(image2, (4, 5)) + out2 = block_reduce(image2, (4, 5), func=np.max) expected2 = np.array([[28, 31], [36, 39]]) assert_array_equal(expected2, out2) From 7efb010051dbf505d73eea6184348997ee0d1767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Mon, 15 Jul 2013 22:00:05 +0200 Subject: [PATCH 10/11] Add short doc string example --- skimage/measure/block.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/skimage/measure/block.py b/skimage/measure/block.py index 7bef1220..fad5668c 100644 --- a/skimage/measure/block.py +++ b/skimage/measure/block.py @@ -24,6 +24,34 @@ def block_reduce(image, block_size, func=np.sum, cval=0): 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 + 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.]]]) + >>> block_reduce(image, block_size=(1, 3, 4), func=np.max) + array([[[11]], + + [[23]], + + [[35]]]) + >>> block_reduce(image, block_size=(3, 1, 4), func=np.max) + array([[[27], + [31], + [35]]]) """ if len(block_size) != image.ndim: From 109f500d4bae033419095db69f63d21800b36c99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Thu, 25 Jul 2013 22:15:23 +0200 Subject: [PATCH 11/11] Replace deprecated import of _local_func with block_reduce --- skimage/transform/_warps.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/skimage/transform/_warps.py b/skimage/transform/_warps.py index e4463721..d8da73d5 100644 --- a/skimage/transform/_warps.py +++ b/skimage/transform/_warps.py @@ -3,7 +3,7 @@ from scipy import ndimage from skimage.transform._geometric import (warp, SimilarityTransform, AffineTransform) -from skimage.measure.local import _local_func +from skimage.measure import block_reduce def resize(image, output_shape, order=1, mode='constant', cval=0.): @@ -264,7 +264,7 @@ def downscale_local_mean(image, factors, cval=0): [5.5, 4.5]]) """ - return _local_func(image, factors, np.mean, cval) + return block_reduce(image, factors, np.mean, cval) def _swirl_mapping(xy, center, rotation, strength, radius):