From 7cfbd7020471f651b74864b083aa1c9538ff1b8f Mon Sep 17 00:00:00 2001 From: "Gregory R. Lee" Date: Tue, 7 Jul 2015 15:20:49 -0400 Subject: [PATCH 01/19] BUG: fix bugs in coord_map for modes wrap and reflect --- skimage/_shared/interpolation.pxd | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/skimage/_shared/interpolation.pxd b/skimage/_shared/interpolation.pxd index 3b4ac538..b197bef4 100644 --- a/skimage/_shared/interpolation.pxd +++ b/skimage/_shared/interpolation.pxd @@ -317,28 +317,25 @@ cdef inline Py_ssize_t coord_map(Py_ssize_t dim, long coord, char mode) nogil: falls outside [0, dim). """ - dim = dim - 1 + cdef Py_ssize_t cmax + cmax = dim - 1 if mode == 'R': # reflect if coord < 0: - # How many times times does the coordinate wrap? - if (-coord / dim) % 2 != 0: - return dim - (-coord % dim) - else: - return (-coord % dim) - elif coord > dim: + coord = -coord - 1 + if coord > cmax: if (coord / dim) % 2 != 0: - return (dim - (coord % dim)) + return (cmax - (coord % dim)) else: return (coord % dim) elif mode == 'W': # wrap if coord < 0: - return (dim - (-coord % dim)) - elif coord > dim: + return (cmax - ((-coord - 1) % dim)) + elif coord > cmax: return (coord % dim) elif mode == 'N': # nearest if coord < 0: return 0 - elif coord > dim: - return dim + elif coord > cmax: + return cmax return coord From a36ab880fc9e8fc3949bf1a152fde52ddb1e0e0d Mon Sep 17 00:00:00 2001 From: "Gregory R. Lee" Date: Tue, 7 Jul 2015 16:04:01 -0400 Subject: [PATCH 02/19] TST: add tests for coord_map function --- skimage/_shared/_interpolation_test.pyx | 5 +++++ skimage/_shared/setup.py | 3 ++- skimage/_shared/tests/test_interpolation.py | 19 +++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 skimage/_shared/_interpolation_test.pyx create mode 100644 skimage/_shared/tests/test_interpolation.py diff --git a/skimage/_shared/_interpolation_test.pyx b/skimage/_shared/_interpolation_test.pyx new file mode 100644 index 00000000..1c243926 --- /dev/null +++ b/skimage/_shared/_interpolation_test.pyx @@ -0,0 +1,5 @@ +from interpolation cimport coord_map as _coord_map + +def coord_map(Py_ssize_t dim, long coord, mode): + cdef char mode_c = ord(mode[0].upper()) + return _coord_map(dim, coord, mode_c) \ No newline at end of file diff --git a/skimage/_shared/setup.py b/skimage/_shared/setup.py index 4c36b97e..6a6baeda 100644 --- a/skimage/_shared/setup.py +++ b/skimage/_shared/setup.py @@ -15,11 +15,12 @@ def configuration(parent_package='', top_path=None): cython(['geometry.pyx'], working_path=base_path) cython(['transform.pyx'], working_path=base_path) + cython(['_interpolation_test.pyx'], working_path=base_path) config.add_extension('geometry', sources=['geometry.c']) config.add_extension('transform', sources=['transform.c'], include_dirs=[get_numpy_include_dirs()]) - + config.add_extension('_interpolation_test', sources=['_interpolation_test.c']) return config diff --git a/skimage/_shared/tests/test_interpolation.py b/skimage/_shared/tests/test_interpolation.py new file mode 100644 index 00000000..98bafb5b --- /dev/null +++ b/skimage/_shared/tests/test_interpolation.py @@ -0,0 +1,19 @@ +from skimage._shared._interpolation_test import coord_map +from numpy.testing import assert_array_equal + +def test_coord_map(): + + reflect = [coord_map(4, n, 'R') for n in range(-6, 6)] + expected_reflect = [2, 3, 3, 2, 1, 0, 0, 1, 2, 3, 3, 2] + assert_array_equal(reflect, expected_reflect) + + wrap = [coord_map(4, n, 'W') for n in range(-6, 6)] + expected_wrap = [2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1] + assert_array_equal(wrap, expected_wrap) + + nearest = [coord_map(4, n, 'N') for n in range(-6, 6)] + expected_neareset = [0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3] + assert_array_equal(nearest, expected_neareset) + + other = [coord_map(4, n, 'undefined') for n in range(-6, 6)] + assert_array_equal(other, list(range(-6, 6))) \ No newline at end of file From c5a735420f099062063608ecdf9beda59d5b0dc6 Mon Sep 17 00:00:00 2001 From: "Gregory R. Lee" Date: Tue, 7 Jul 2015 17:45:47 -0400 Subject: [PATCH 03/19] DOC: add visual example of edge modes --- doc/examples/plot_edge_modes.py | 36 +++++++++++++++++++++ skimage/_shared/_interpolation_test.pyx | 28 +++++++++++++++- skimage/_shared/tests/test_interpolation.py | 3 +- 3 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 doc/examples/plot_edge_modes.py diff --git a/doc/examples/plot_edge_modes.py b/doc/examples/plot_edge_modes.py new file mode 100644 index 00000000..58666090 --- /dev/null +++ b/doc/examples/plot_edge_modes.py @@ -0,0 +1,36 @@ +""" +========================= +Interpolation: Edge Modes +========================= + +This example illustrates the different edge modes available during +interpolation in routines such as ``skimage.transform.rescale`` and +``skimage.transform.resize``. +""" +from skimage._shared._interpolation_test import extend_image +import skimage.data +import matplotlib.pyplot as plt +import numpy as np + +img = np.zeros((9, 9)) +img[:8, :8] += 1 +img[:4, :4] += 1 +img[:2, :2] += 1 +img[:1, :1] += 2 + +modes = ['constant', 'nearest', 'wrap', 'reflect'] +fig, axes = plt.subplots(1, 4, figsize=(15, 5)) +for n, mode in enumerate(modes): + img_extended = extend_image(img, pad=img.shape[0], mode=mode) + axes[n].imshow(img_extended, cmap=plt.cm.gray, interpolation='nearest') + axes[n].plot([8.5, 8.5], [8.5, 17.5], 'y--', linewidth=0.5) + axes[n].plot([17.5, 17.5], [8.5, 17.5], 'y--', linewidth=0.5) + axes[n].plot([8.5, 17.5], [8.5, 8.5], 'y--', linewidth=0.5) + axes[n].plot([8.5, 17.5], [17.5, 17.5], 'y--', linewidth=0.5) + axes[n].set_axis_off() + axes[n].set_aspect('equal') + axes[n].set_title(mode) + +plt.tight_layout() + +plt.show() \ No newline at end of file diff --git a/skimage/_shared/_interpolation_test.pyx b/skimage/_shared/_interpolation_test.pyx index 1c243926..fa11382f 100644 --- a/skimage/_shared/_interpolation_test.pyx +++ b/skimage/_shared/_interpolation_test.pyx @@ -1,5 +1,31 @@ from interpolation cimport coord_map as _coord_map +from interpolation cimport get_pixel2d +import numpy as np +cimport numpy as cnp + def coord_map(Py_ssize_t dim, long coord, mode): + """ interpolation.coord_map python wrapper """ cdef char mode_c = ord(mode[0].upper()) - return _coord_map(dim, coord, mode_c) \ No newline at end of file + return _coord_map(dim, coord, mode_c) + + +def extend_image(image, pad=10, mode='C', cval=0): + """ can be used to verify proper get_pixel2d behavior. """ + cdef: + Py_ssize_t rows = image.shape[0] + Py_ssize_t cols = image.shape[1] + long ro, co + char mode_c = ord(mode[0].upper()) + + image = np.ascontiguousarray(image.astype(np.float64)) + output_shape = np.asarray(image.shape) + 2*pad + image_out = np.zeros(output_shape, dtype=image.dtype) + for r in range(-pad, rows+pad): + for c in range(-pad, cols+pad): + ro = r + pad + co = c + pad + image_out[ro, co] = get_pixel2d( cnp.PyArray_DATA(image), + rows, cols, r, c, + mode_c, cval) + return image_out diff --git a/skimage/_shared/tests/test_interpolation.py b/skimage/_shared/tests/test_interpolation.py index 98bafb5b..261fbe99 100644 --- a/skimage/_shared/tests/test_interpolation.py +++ b/skimage/_shared/tests/test_interpolation.py @@ -1,6 +1,7 @@ from skimage._shared._interpolation_test import coord_map from numpy.testing import assert_array_equal + def test_coord_map(): reflect = [coord_map(4, n, 'R') for n in range(-6, 6)] @@ -16,4 +17,4 @@ def test_coord_map(): assert_array_equal(nearest, expected_neareset) other = [coord_map(4, n, 'undefined') for n in range(-6, 6)] - assert_array_equal(other, list(range(-6, 6))) \ No newline at end of file + assert_array_equal(other, list(range(-6, 6))) From 2f02ad385fc12123029794f576846b5b79c4d059 Mon Sep 17 00:00:00 2001 From: "Gregory R. Lee" Date: Tue, 7 Jul 2015 20:18:38 -0400 Subject: [PATCH 04/19] BUG: fix bento.info --- bento.info | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bento.info b/bento.info index 659247d1..93d56188 100644 --- a/bento.info +++ b/bento.info @@ -107,6 +107,9 @@ Library: Extension: skimage._shared.transform Sources: skimage/_shared/transform.pyx + Extension: skimage._shared._interpolation_test + Sources: + skimage/_shared/_interpolation_test.pyx Extension: skimage.segmentation._slic Sources: skimage/segmentation/_slic.pyx From 080c276791a92481a1130be72107ac7941b2fc0e Mon Sep 17 00:00:00 2001 From: "Gregory R. Lee" Date: Tue, 7 Jul 2015 17:45:47 -0400 Subject: [PATCH 05/19] DOC: add visual example of edge modes --- doc/examples/plot_edge_modes.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/examples/plot_edge_modes.py b/doc/examples/plot_edge_modes.py index 58666090..bb99ac68 100644 --- a/doc/examples/plot_edge_modes.py +++ b/doc/examples/plot_edge_modes.py @@ -12,21 +12,21 @@ import skimage.data import matplotlib.pyplot as plt import numpy as np -img = np.zeros((9, 9)) +img = np.zeros((16, 16)) img[:8, :8] += 1 img[:4, :4] += 1 img[:2, :2] += 1 img[:1, :1] += 2 modes = ['constant', 'nearest', 'wrap', 'reflect'] -fig, axes = plt.subplots(1, 4, figsize=(15, 5)) +fig, axes = plt.subplots(1, 4, figsize=(12, 3)) for n, mode in enumerate(modes): img_extended = extend_image(img, pad=img.shape[0], mode=mode) axes[n].imshow(img_extended, cmap=plt.cm.gray, interpolation='nearest') - axes[n].plot([8.5, 8.5], [8.5, 17.5], 'y--', linewidth=0.5) - axes[n].plot([17.5, 17.5], [8.5, 17.5], 'y--', linewidth=0.5) - axes[n].plot([8.5, 17.5], [8.5, 8.5], 'y--', linewidth=0.5) - axes[n].plot([8.5, 17.5], [17.5, 17.5], 'y--', linewidth=0.5) + axes[n].plot([15.5, 15.5], [15.5, 31.5], 'y--', linewidth=0.5) + axes[n].plot([31.5, 31.5], [15.5, 31.5], 'y--', linewidth=0.5) + axes[n].plot([15.5, 31.5], [15.5, 15.5], 'y--', linewidth=0.5) + axes[n].plot([15.5, 31.5], [31.5, 31.5], 'y--', linewidth=0.5) axes[n].set_axis_off() axes[n].set_aspect('equal') axes[n].set_title(mode) From 3ae1e3138adeef4cb6f6f1c87a9a87b46898bc1b Mon Sep 17 00:00:00 2001 From: "Gregory R. Lee" Date: Wed, 8 Jul 2015 14:41:34 -0400 Subject: [PATCH 06/19] BUG: bugfix for resize: upgrade image to 3d if necessary --- skimage/transform/_warps.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/skimage/transform/_warps.py b/skimage/transform/_warps.py index f069122a..54c1bc75 100644 --- a/skimage/transform/_warps.py +++ b/skimage/transform/_warps.py @@ -69,7 +69,9 @@ def resize(image, output_shape, order=1, mode='constant', cval=0, clip=True, if len(output_shape) == 3 and (image.ndim == 2 or output_shape[2] != image.shape[2]): dim = output_shape[2] - orig_dim = 1 if image.ndim == 2 else image.shape[2] + if image.ndim == 2: + image = image[:, :, np.newaxis] + orig_dim = image.shape[2] dim_scale = float(orig_dim) / dim map_rows, map_cols, map_dims = np.mgrid[:rows, :cols, :dim] From 9e9c65b97c258c9efb23d181677605a874645b9c Mon Sep 17 00:00:00 2001 From: "Gregory R. Lee" Date: Wed, 8 Jul 2015 15:39:44 -0400 Subject: [PATCH 07/19] ENH: add mode 'mirror' to interpolation.pxd and dependent functions --- skimage/_shared/interpolation.pxd | 41 +++++++++++++-------- skimage/_shared/tests/test_interpolation.py | 4 ++ skimage/filters/_gabor.py | 2 +- skimage/measure/profile.py | 2 +- skimage/transform/_geometric.py | 8 ++-- skimage/transform/_warps.py | 24 ++++++++---- skimage/transform/_warps_cy.pyx | 16 ++++++-- 7 files changed, 64 insertions(+), 33 deletions(-) diff --git a/skimage/_shared/interpolation.pxd b/skimage/_shared/interpolation.pxd index b197bef4..da2d6e6b 100644 --- a/skimage/_shared/interpolation.pxd +++ b/skimage/_shared/interpolation.pxd @@ -24,8 +24,8 @@ cdef inline double nearest_neighbour_interpolation(double* image, Shape of image. r, c : double Position at which to interpolate. - mode : {'C', 'W', 'R', 'N'} - Wrapping mode. Constant, Wrap, Reflect or Nearest. + mode : {'C', 'W', 'R', 'N', 'M'} + Wrapping mode. Constant, Wrap, Reflect, Nearest or Mirror. cval : double Constant value to use for constant mode. @@ -52,8 +52,8 @@ cdef inline double bilinear_interpolation(double* image, Py_ssize_t rows, Shape of image. r, c : double Position at which to interpolate. - mode : {'C', 'W', 'R', 'N'} - Wrapping mode. Constant, Wrap, Reflect or Nearest. + mode : {'C', 'W', 'R', 'N', 'M'} + Wrapping mode. Constant, Wrap, Reflect, Nearest or Mirror. cval : double Constant value to use for constant mode. @@ -119,8 +119,8 @@ cdef inline double biquadratic_interpolation(double* image, Py_ssize_t rows, Shape of image. r, c : double Position at which to interpolate. - mode : {'C', 'W', 'R', 'N'} - Wrapping mode. Constant, Wrap, Reflect or Nearest. + mode : {'C', 'W', 'R', 'N', 'M'} + Wrapping mode. Constant, Wrap, Reflect, Nearest or Mirror. cval : double Constant value to use for constant mode. @@ -192,8 +192,8 @@ cdef inline double bicubic_interpolation(double* image, Py_ssize_t rows, Shape of image. r, c : double Position at which to interpolate. - mode : {'C', 'W', 'R', 'N'} - Wrapping mode. Constant, Wrap, Reflect or Nearest. + mode : {'C', 'W', 'R', 'N', 'M'} + Wrapping mode. Constant, Wrap, Reflect, Nearest or Mirror. cval : double Constant value to use for constant mode. @@ -248,8 +248,8 @@ cdef inline double get_pixel2d(double* image, Py_ssize_t rows, Py_ssize_t cols, Shape of image. r, c : int Position at which to get the pixel. - mode : {'C', 'W', 'R', 'N'} - Wrapping mode. Constant, Wrap, Reflect or Nearest. + mode : {'C', 'W', 'R', 'N', 'M'} + Wrapping mode. Constant, Wrap, Reflect, Nearest or Mirror. cval : double Constant value to use for constant mode. @@ -281,8 +281,8 @@ cdef inline double get_pixel3d(double* image, Py_ssize_t rows, Py_ssize_t cols, Shape of image. r, c, d : int Position at which to get the pixel. - mode : {'C', 'W', 'R', 'N'} - Wrapping mode. Constant, Wrap, Reflect or Nearest. + mode : {'C', 'W', 'R', 'N', 'M'} + Wrapping mode. Constant, Wrap, Reflect, Nearest or Mirror. cval : double Constant value to use for constant mode. @@ -312,8 +312,8 @@ cdef inline Py_ssize_t coord_map(Py_ssize_t dim, long coord, char mode) nogil: Maximum coordinate. coord : int Coord provided by user. May be < 0 or > dim. - mode : {'W', 'R', 'N'} - Whether to wrap or reflect the coordinate if it + mode : {'W', 'R', 'N', 'M'} + Whether to wrap, reflect, mirror or use the nearest coordinate if it falls outside [0, dim). """ @@ -337,5 +337,16 @@ cdef inline Py_ssize_t coord_map(Py_ssize_t dim, long coord, char mode) nogil: return 0 elif coord > cmax: return cmax - + elif mode == 'M': # mirror + if coord < 0: + # How many times times does the coordinate wrap? + if (-coord / cmax) % 2 != 0: + return cmax - (-coord % cmax) + else: + return (-coord % cmax) + elif coord > cmax: + if (coord / cmax) % 2 != 0: + return (cmax - (coord % cmax)) + else: + return (coord % cmax) return coord diff --git a/skimage/_shared/tests/test_interpolation.py b/skimage/_shared/tests/test_interpolation.py index 261fbe99..8edfbcc6 100644 --- a/skimage/_shared/tests/test_interpolation.py +++ b/skimage/_shared/tests/test_interpolation.py @@ -16,5 +16,9 @@ def test_coord_map(): expected_neareset = [0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3] assert_array_equal(nearest, expected_neareset) + mirror = [coord_map(4, n, 'M') for n in range(-6, 6)] + expected_mirror = [0, 1, 2, 3, 2, 1, 0, 1, 2, 3, 2, 1] + assert_array_equal(mirror, expected_mirror) + other = [coord_map(4, n, 'undefined') for n in range(-6, 6)] assert_array_equal(other, list(range(-6, 6))) diff --git a/skimage/filters/_gabor.py b/skimage/filters/_gabor.py index 3eeccc0f..4d249d2c 100644 --- a/skimage/filters/_gabor.py +++ b/skimage/filters/_gabor.py @@ -129,7 +129,7 @@ def gabor_filter(image, frequency, theta=0, bandwidth=1, sigma_x=None, deviations. offset : float, optional Phase offset of harmonic function in radians. - mode : string, optional + mode : {'constant', 'nearest', 'reflect', 'mirror', 'wrap'}, optional Mode used to convolve image with a kernel, passed to `ndi.convolve` cval : scalar, optional Value to fill past edges of input if `mode` of convolution is diff --git a/skimage/measure/profile.py b/skimage/measure/profile.py index 819b8cff..9dbc2d7a 100644 --- a/skimage/measure/profile.py +++ b/skimage/measure/profile.py @@ -21,7 +21,7 @@ def profile_line(img, src, dst, linewidth=1, order : int in {0, 1, 2, 3, 4, 5}, optional The order of the spline interpolation to compute image values at non-integer coordinates. 0 means nearest-neighbor interpolation. - mode : string, one of {'constant', 'nearest', 'reflect', 'wrap'}, optional + mode : {'constant', 'nearest', 'reflect', 'mirror', 'wrap'}, optional How to compute any values falling outside of the image. cval : float, optional If `mode` is 'constant', what constant value to use outside the image. diff --git a/skimage/transform/_geometric.py b/skimage/transform/_geometric.py index 1245a127..3915a055 100644 --- a/skimage/transform/_geometric.py +++ b/skimage/transform/_geometric.py @@ -1128,9 +1128,9 @@ def _clip_warp_output(input_image, output_image, order, mode, cval, clip): order : int, optional The order of the spline interpolation, default is 1. The order has to be in the range 0-5. See `skimage.transform.warp` for detail. - mode : string, optional + mode : {'constant', 'nearest', 'reflect', 'mirror', 'wrap'}, optional Points outside the boundaries of the input are filled according - to the given mode ('constant', 'nearest', 'reflect' or 'wrap'). + to the given mode. cval : float, optional Used in conjunction with mode 'constant', the value outside the image boundaries. @@ -1211,9 +1211,9 @@ def warp(image, inverse_map=None, map_args={}, output_shape=None, order=1, - 3: Bi-cubic - 4: Bi-quartic - 5: Bi-quintic - mode : string, optional + mode : {'constant', 'nearest', 'reflect', 'mirror', 'wrap'}, optional Points outside the boundaries of the input are filled according - to the given mode ('constant', 'nearest', 'reflect' or 'wrap'). + to the given mode. cval : float, optional Used in conjunction with mode 'constant', the value outside the image boundaries. diff --git a/skimage/transform/_warps.py b/skimage/transform/_warps.py index 54c1bc75..c87c7adb 100644 --- a/skimage/transform/_warps.py +++ b/skimage/transform/_warps.py @@ -35,9 +35,9 @@ def resize(image, output_shape, order=1, mode='constant', cval=0, clip=True, order : int, optional The order of the spline interpolation, default is 1. The order has to be in the range 0-5. See `skimage.transform.warp` for detail. - mode : string, optional + mode : {'constant', 'nearest', 'reflect', 'mirror', 'wrap'}, optional Points outside the boundaries of the input are filled according - to the given mode ('constant', 'nearest', 'reflect' or 'wrap'). + to the given mode. cval : float, optional Used in conjunction with mode 'constant', the value outside the image boundaries. @@ -49,6 +49,14 @@ def resize(image, output_shape, order=1, mode='constant', cval=0, clip=True, Whether to keep the original range of values. Otherwise, the input image is converted according to the conventions of `img_as_float`. + Notes + ----- + Modes 'mirror' and 'reflect' are similar, but differ in whether the edge + voxels are duplicated during the reflection. As an example, if an array + has values [0, 1, 2] and was padded to the right by four values using + reflect, the result would be [0, 1, 2, 2, 1, 0, 0], while for mirror it + would be [0, 1, 2, 1, 0, 1, 2]. + Examples -------- >>> from skimage import data @@ -138,9 +146,9 @@ def rescale(image, scale, order=1, mode='constant', cval=0, clip=True, order : int, optional The order of the spline interpolation, default is 1. The order has to be in the range 0-5. See `skimage.transform.warp` for detail. - mode : string, optional + mode : {'constant', 'nearest', 'reflect', 'mirror', 'wrap'}, optional Points outside the boundaries of the input are filled according - to the given mode ('constant', 'nearest', 'reflect' or 'wrap'). + to the given mode. cval : float, optional Used in conjunction with mode 'constant', the value outside the image boundaries. @@ -206,9 +214,9 @@ def rotate(image, angle, resize=False, center=None, order=1, mode='constant', order : int, optional The order of the spline interpolation, default is 1. The order has to be in the range 0-5. See `skimage.transform.warp` for detail. - mode : string, optional + mode : {'constant', 'nearest', 'reflect', 'mirror', 'wrap'}, optional Points outside the boundaries of the input are filled according - to the given mode ('constant', 'nearest', 'reflect' or 'wrap'). + to the given mode. cval : float, optional Used in conjunction with mode 'constant', the value outside the image boundaries. @@ -360,9 +368,9 @@ def swirl(image, center=None, strength=1, radius=100, rotation=0, order : int, optional The order of the spline interpolation, default is 1. The order has to be in the range 0-5. See `skimage.transform.warp` for detail. - mode : string, optional + mode : {'constant', 'nearest', 'reflect', 'mirror', 'wrap'}, optional Points outside the boundaries of the input are filled according - to the given mode ('constant', 'nearest', 'reflect' or 'wrap'). + to the given mode. cval : float, optional Used in conjunction with mode 'constant', the value outside the image boundaries. diff --git a/skimage/transform/_warps_cy.pyx b/skimage/transform/_warps_cy.pyx index aa2f3b6e..fd802817 100644 --- a/skimage/transform/_warps_cy.pyx +++ b/skimage/transform/_warps_cy.pyx @@ -70,20 +70,28 @@ def _warp_fast(cnp.ndarray image, cnp.ndarray H, output_shape=None, * 1: Bi-linear (default) * 2: Bi-quadratic * 3: Bi-cubic - mode : {'constant', 'reflect', 'wrap', 'nearest'}, optional + mode : {'constant', 'reflect', 'mirror', 'wrap', 'nearest'}, optional How to handle values outside the image borders (default is constant). cval : string, optional (default 0) Used in conjunction with mode 'C' (constant), the value outside the image boundaries. + Notes + ----- + Modes 'mirror' and 'reflect' are similar, but differ in whether the edge + voxels are duplicated during the reflection. As an example, if an array + has values [0, 1, 2] and was padded to the right by four values using + reflect, the result would be [0, 1, 2, 2, 1, 0, 0], while for mirror it + would be [0, 1, 2, 1, 0, 1, 2]. + """ cdef double[:, ::1] img = np.ascontiguousarray(image, dtype=np.double) cdef double[:, ::1] M = np.ascontiguousarray(H) - if mode not in ('constant', 'wrap', 'reflect', 'nearest'): - raise ValueError("Invalid mode specified. Please use " - "`constant`, `nearest`, `wrap` or `reflect`.") + if mode not in ('constant', 'wrap', 'reflect', 'mirror', 'nearest'): + raise ValueError("Invalid mode specified. Please use `constant`, " + "`nearest`, `wrap`, `mirror` or `reflect`.") cdef char mode_c = ord(mode[0].upper()) cdef Py_ssize_t out_r, out_c From 48622ca179b5ced06b28a2a3da43c468d375c08b Mon Sep 17 00:00:00 2001 From: "Gregory R. Lee" Date: Wed, 8 Jul 2015 15:54:38 -0400 Subject: [PATCH 08/19] TST: add test for resizing 2D image with a 3D output shape --- skimage/transform/tests/test_warps.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/skimage/transform/tests/test_warps.py b/skimage/transform/tests/test_warps.py index 4de59359..12754d5a 100644 --- a/skimage/transform/tests/test_warps.py +++ b/skimage/transform/tests/test_warps.py @@ -181,6 +181,18 @@ def test_resize3d_resize(): assert_almost_equal(resized, ref) + +def test_resize3d_2din_3dout(): + # 3D output with 2D input + x = np.zeros((5, 5), dtype=np.double) + x[1, 1] = 1 + resized = resize(x, (10, 10, 1), order=0) + ref = np.zeros((10, 10, 1)) + ref[2:4, 2:4] = 1 + assert_almost_equal(resized, ref) + + + def test_resize3d_bilinear(): # bilinear 3rd dimension x = np.zeros((5, 5, 2), dtype=np.double) From fb0b258deb78c8da8332125a64a7121019b4ec6c Mon Sep 17 00:00:00 2001 From: "Gregory R. Lee" Date: Wed, 8 Jul 2015 16:07:17 -0400 Subject: [PATCH 09/19] DOC: update the edge mode example to include mirror --- doc/examples/plot_edge_modes.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/examples/plot_edge_modes.py b/doc/examples/plot_edge_modes.py index bb99ac68..3ef4f408 100644 --- a/doc/examples/plot_edge_modes.py +++ b/doc/examples/plot_edge_modes.py @@ -17,9 +17,10 @@ img[:8, :8] += 1 img[:4, :4] += 1 img[:2, :2] += 1 img[:1, :1] += 2 +img[8, 8] = 4 -modes = ['constant', 'nearest', 'wrap', 'reflect'] -fig, axes = plt.subplots(1, 4, figsize=(12, 3)) +modes = ['constant', 'nearest', 'wrap', 'reflect', 'mirror'] +fig, axes = plt.subplots(1, 5, figsize=(15, 5)) for n, mode in enumerate(modes): img_extended = extend_image(img, pad=img.shape[0], mode=mode) axes[n].imshow(img_extended, cmap=plt.cm.gray, interpolation='nearest') From cef22e4234e611e69337531c2dffebf5a78eb19e Mon Sep 17 00:00:00 2001 From: "Gregory R. Lee" Date: Thu, 9 Jul 2015 13:02:37 -0400 Subject: [PATCH 10/19] MAINT: PEP8 fixes and _interpolation_test.pyx -> interpolation.pyx rename --- doc/examples/plot_edge_modes.py | 2 +- skimage/_shared/_interpolation_test.pyx | 31 ------------ skimage/_shared/interpolation.pyx | 56 +++++++++++++++++++++ skimage/_shared/setup.py | 4 +- skimage/_shared/tests/test_interpolation.py | 13 +++-- skimage/transform/_warps.py | 4 +- skimage/transform/_warps_cy.pyx | 4 +- skimage/transform/tests/test_warps.py | 2 - 8 files changed, 69 insertions(+), 47 deletions(-) delete mode 100644 skimage/_shared/_interpolation_test.pyx create mode 100644 skimage/_shared/interpolation.pyx diff --git a/doc/examples/plot_edge_modes.py b/doc/examples/plot_edge_modes.py index 3ef4f408..4044f032 100644 --- a/doc/examples/plot_edge_modes.py +++ b/doc/examples/plot_edge_modes.py @@ -34,4 +34,4 @@ for n, mode in enumerate(modes): plt.tight_layout() -plt.show() \ No newline at end of file +plt.show() diff --git a/skimage/_shared/_interpolation_test.pyx b/skimage/_shared/_interpolation_test.pyx deleted file mode 100644 index fa11382f..00000000 --- a/skimage/_shared/_interpolation_test.pyx +++ /dev/null @@ -1,31 +0,0 @@ -from interpolation cimport coord_map as _coord_map -from interpolation cimport get_pixel2d -import numpy as np -cimport numpy as cnp - - -def coord_map(Py_ssize_t dim, long coord, mode): - """ interpolation.coord_map python wrapper """ - cdef char mode_c = ord(mode[0].upper()) - return _coord_map(dim, coord, mode_c) - - -def extend_image(image, pad=10, mode='C', cval=0): - """ can be used to verify proper get_pixel2d behavior. """ - cdef: - Py_ssize_t rows = image.shape[0] - Py_ssize_t cols = image.shape[1] - long ro, co - char mode_c = ord(mode[0].upper()) - - image = np.ascontiguousarray(image.astype(np.float64)) - output_shape = np.asarray(image.shape) + 2*pad - image_out = np.zeros(output_shape, dtype=image.dtype) - for r in range(-pad, rows+pad): - for c in range(-pad, cols+pad): - ro = r + pad - co = c + pad - image_out[ro, co] = get_pixel2d( cnp.PyArray_DATA(image), - rows, cols, r, c, - mode_c, cval) - return image_out diff --git a/skimage/_shared/interpolation.pyx b/skimage/_shared/interpolation.pyx new file mode 100644 index 00000000..b6470651 --- /dev/null +++ b/skimage/_shared/interpolation.pyx @@ -0,0 +1,56 @@ +from interpolation cimport coord_map, get_pixel2d +import numpy as np +cimport numpy as cnp + + +def coord_map_py(Py_ssize_t dim, long coord, mode): + """ interpolation.coord_map python wrapper """ + cdef char mode_c = ord(mode[0].upper()) + return coord_map(dim, coord, mode_c) + + +def extend_image(image, pad=10, mode='constant', cval=0): + """ Pad a 2D image by ``pad`` pixels on each side. + + Parameters + ---------- + image : ndarray + Input image. + pad : int, optional + The number of pixels to pad around the border + mode : {'constant', 'nearest', 'reflect', 'mirror', 'wrap'}, optional + Points outside the boundaries of the input are filled according + to the given mode. + cval : float, optional + Used in conjunction with mode 'constant', the value outside + the image boundaries. + + Returns + ------- + extended : ndarray + The extended version of the input image. + + Note + ---- + For image padding, ``skimage.util.pad`` should be used instead. This + function is intended only for testing get_pixel2d and demonstrating the + coordinate mapping modes implemented in ``coord_map``. + """ + + cdef: + Py_ssize_t rows = image.shape[0] + Py_ssize_t cols = image.shape[1] + long ro, co + char mode_c = ord(mode[0].upper()) + + image = np.ascontiguousarray(image.astype(np.float64)) + output_shape = np.asarray(image.shape) + 2 * pad + extended = np.zeros(output_shape, dtype=image.dtype) + for r in range(-pad, rows + pad): + for c in range(-pad, cols + pad): + ro = r + pad + co = c + pad + extended[ro, co] = get_pixel2d( cnp.PyArray_DATA(image), + rows, cols, r, c, + mode_c, cval) + return extended diff --git a/skimage/_shared/setup.py b/skimage/_shared/setup.py index 6a6baeda..066a856f 100644 --- a/skimage/_shared/setup.py +++ b/skimage/_shared/setup.py @@ -15,12 +15,12 @@ def configuration(parent_package='', top_path=None): cython(['geometry.pyx'], working_path=base_path) cython(['transform.pyx'], working_path=base_path) - cython(['_interpolation_test.pyx'], working_path=base_path) + cython(['interpolation.pyx'], working_path=base_path) config.add_extension('geometry', sources=['geometry.c']) config.add_extension('transform', sources=['transform.c'], include_dirs=[get_numpy_include_dirs()]) - config.add_extension('_interpolation_test', sources=['_interpolation_test.c']) + config.add_extension('interpolation', sources=['interpolation.c']) return config diff --git a/skimage/_shared/tests/test_interpolation.py b/skimage/_shared/tests/test_interpolation.py index 8edfbcc6..8022e0e1 100644 --- a/skimage/_shared/tests/test_interpolation.py +++ b/skimage/_shared/tests/test_interpolation.py @@ -1,24 +1,23 @@ -from skimage._shared._interpolation_test import coord_map +from skimage._shared.interpolation import coord_map_py from numpy.testing import assert_array_equal def test_coord_map(): - - reflect = [coord_map(4, n, 'R') for n in range(-6, 6)] + reflect = [coord_map_py(4, n, 'R') for n in range(-6, 6)] expected_reflect = [2, 3, 3, 2, 1, 0, 0, 1, 2, 3, 3, 2] assert_array_equal(reflect, expected_reflect) - wrap = [coord_map(4, n, 'W') for n in range(-6, 6)] + wrap = [coord_map_py(4, n, 'W') for n in range(-6, 6)] expected_wrap = [2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1] assert_array_equal(wrap, expected_wrap) - nearest = [coord_map(4, n, 'N') for n in range(-6, 6)] + nearest = [coord_map_py(4, n, 'N') for n in range(-6, 6)] expected_neareset = [0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3] assert_array_equal(nearest, expected_neareset) - mirror = [coord_map(4, n, 'M') for n in range(-6, 6)] + mirror = [coord_map_py(4, n, 'M') for n in range(-6, 6)] expected_mirror = [0, 1, 2, 3, 2, 1, 0, 1, 2, 3, 2, 1] assert_array_equal(mirror, expected_mirror) - other = [coord_map(4, n, 'undefined') for n in range(-6, 6)] + other = [coord_map_py(4, n, 'undefined') for n in range(-6, 6)] assert_array_equal(other, list(range(-6, 6))) diff --git a/skimage/transform/_warps.py b/skimage/transform/_warps.py index c87c7adb..8f968777 100644 --- a/skimage/transform/_warps.py +++ b/skimage/transform/_warps.py @@ -49,8 +49,8 @@ def resize(image, output_shape, order=1, mode='constant', cval=0, clip=True, Whether to keep the original range of values. Otherwise, the input image is converted according to the conventions of `img_as_float`. - Notes - ----- + Note + ---- Modes 'mirror' and 'reflect' are similar, but differ in whether the edge voxels are duplicated during the reflection. As an example, if an array has values [0, 1, 2] and was padded to the right by four values using diff --git a/skimage/transform/_warps_cy.pyx b/skimage/transform/_warps_cy.pyx index fd802817..caab79fd 100644 --- a/skimage/transform/_warps_cy.pyx +++ b/skimage/transform/_warps_cy.pyx @@ -76,8 +76,8 @@ def _warp_fast(cnp.ndarray image, cnp.ndarray H, output_shape=None, Used in conjunction with mode 'C' (constant), the value outside the image boundaries. - Notes - ----- + Note + ---- Modes 'mirror' and 'reflect' are similar, but differ in whether the edge voxels are duplicated during the reflection. As an example, if an array has values [0, 1, 2] and was padded to the right by four values using diff --git a/skimage/transform/tests/test_warps.py b/skimage/transform/tests/test_warps.py index 12754d5a..a8dfcb87 100644 --- a/skimage/transform/tests/test_warps.py +++ b/skimage/transform/tests/test_warps.py @@ -181,7 +181,6 @@ def test_resize3d_resize(): assert_almost_equal(resized, ref) - def test_resize3d_2din_3dout(): # 3D output with 2D input x = np.zeros((5, 5), dtype=np.double) @@ -192,7 +191,6 @@ def test_resize3d_2din_3dout(): assert_almost_equal(resized, ref) - def test_resize3d_bilinear(): # bilinear 3rd dimension x = np.zeros((5, 5, 2), dtype=np.double) From 75edad1448fce0721558704df35d094e2bad4668 Mon Sep 17 00:00:00 2001 From: "Gregory R. Lee" Date: Thu, 9 Jul 2015 13:56:22 -0400 Subject: [PATCH 11/19] BUG: fix bento.info again --- bento.info | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bento.info b/bento.info index 93d56188..1d7f3a28 100644 --- a/bento.info +++ b/bento.info @@ -107,9 +107,9 @@ Library: Extension: skimage._shared.transform Sources: skimage/_shared/transform.pyx - Extension: skimage._shared._interpolation_test + Extension: skimage._shared.interpolation Sources: - skimage/_shared/_interpolation_test.pyx + skimage/_shared/interpolation.pyx Extension: skimage.segmentation._slic Sources: skimage/segmentation/_slic.pyx From f45a72ee1f9ccdf48ad79622343817dc06a82194 Mon Sep 17 00:00:00 2001 From: "Gregory R. Lee" Date: Thu, 9 Jul 2015 19:25:49 -0400 Subject: [PATCH 12/19] BUG: fix import in plot_edge_modes.py --- doc/examples/plot_edge_modes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/examples/plot_edge_modes.py b/doc/examples/plot_edge_modes.py index 4044f032..f48d7aed 100644 --- a/doc/examples/plot_edge_modes.py +++ b/doc/examples/plot_edge_modes.py @@ -7,7 +7,7 @@ This example illustrates the different edge modes available during interpolation in routines such as ``skimage.transform.rescale`` and ``skimage.transform.resize``. """ -from skimage._shared._interpolation_test import extend_image +from skimage._shared.interpolation import extend_image import skimage.data import matplotlib.pyplot as plt import numpy as np From 8e3b6bc9da6408aa2f59cb88f4ff4db8029288f5 Mon Sep 17 00:00:00 2001 From: "Gregory R. Lee" Date: Thu, 13 Aug 2015 22:05:11 -0400 Subject: [PATCH 13/19] MAINT: convert additional numpy.pad mode names to their dask.array equivalents --- skimage/util/apply_parallel.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/skimage/util/apply_parallel.py b/skimage/util/apply_parallel.py index fd50ba56..c19b4bfd 100644 --- a/skimage/util/apply_parallel.py +++ b/skimage/util/apply_parallel.py @@ -68,13 +68,18 @@ def apply_parallel(function, array, chunks=None, depth=0, mode=None, depth : int, optional Integer equal to the depth of the added boundary cells. Defaults to zero. - mode : 'reflect', 'periodic', 'wrap', 'nearest', optional - type of external boundary padding + mode : {'reflect', 'symmetric', 'periodic', 'wrap', 'nearest', 'edge'}, optional + type of external boundary padding. extra_arguments : tuple, optional Tuple of arguments to be passed to the function. extra_keywords : dictionary, optional Dictionary of keyword arguments to be passed to the function. + Notes + ----- + Numpy edge modes `symmetric`, `wrap` and `edge` are converted to the + equivalent `dask` boundary modes `reflect`, `periodic` and `nearest`, + respectively. """ import dask.array as da @@ -88,6 +93,10 @@ def apply_parallel(function, array, chunks=None, depth=0, mode=None, if mode == 'wrap': mode = 'periodic' + elif mode == 'symmetric': + mode = 'reflect' + elif mode == 'edge': + mode = 'nearest' def wrapped_func(arr): return function(arr, *extra_arguments, **extra_keywords) From 81ea7a6e342d805cc02629369870641b4a3166fa Mon Sep 17 00:00:00 2001 From: "Gregory R. Lee" Date: Thu, 13 Aug 2015 22:11:04 -0400 Subject: [PATCH 14/19] MAINT: All modes in _shared.interpolation.pxd were changed to be consistent with numpy.pad naming conventions. Specifically 'nearest' was changed to 'edge' and 'mirror' was changed to 'reflect'. All functions with a mode argument that rely on these functions had their inputs changed accordingly. For now there is a deprecation warning if the user supplies mode 'nearest'. Mode 'mirror' never appeared in an official release of skimage and so has no corresponding deprecation warning. --- skimage/_shared/interpolation.pxd | 51 +++++++++++++-------- skimage/_shared/interpolation.pyx | 5 +- skimage/_shared/tests/test_interpolation.py | 22 +++++---- skimage/_shared/utils.py | 11 +++++ skimage/restoration/_denoise.py | 6 ++- skimage/restoration/_denoise_cy.pyx | 6 +-- skimage/transform/_geometric.py | 16 ++++--- skimage/transform/_warps.py | 33 +++++++++---- skimage/transform/_warps_cy.pyx | 13 +++--- skimage/transform/pyramids.py | 8 ++-- 10 files changed, 109 insertions(+), 62 deletions(-) diff --git a/skimage/_shared/interpolation.pxd b/skimage/_shared/interpolation.pxd index da2d6e6b..aa58684d 100644 --- a/skimage/_shared/interpolation.pxd +++ b/skimage/_shared/interpolation.pxd @@ -2,6 +2,20 @@ #cython: boundscheck=False #cython: nonecheck=False #cython: wraparound=False +""" +Note: All edge modes implemented here follow the corresponding numpy.pad +conventions. + +The table below illustrates the behavior for the array [1, 2, 3, 4], if padded +by 4 values on each side: + + pad original pad + constant (with c=0) : 0 0 0 0 | 1 2 3 4 | 0 0 0 0 + wrap : 1 2 3 4 | 1 2 3 4 | 1 2 3 4 + symmetric : 4 3 2 1 | 1 2 3 4 | 4 3 2 1 + edge : 1 1 1 1 | 1 2 3 4 | 4 4 4 4 + reflect : 3 4 3 2 | 1 2 3 4 | 3 2 1 2 +""" from libc.math cimport ceil, floor @@ -24,8 +38,8 @@ cdef inline double nearest_neighbour_interpolation(double* image, Shape of image. r, c : double Position at which to interpolate. - mode : {'C', 'W', 'R', 'N', 'M'} - Wrapping mode. Constant, Wrap, Reflect, Nearest or Mirror. + mode : {'C', 'W', 'S', 'E', 'R'} + Wrapping mode. Constant, Wrap, Symmetric, Edge or Reflect. cval : double Constant value to use for constant mode. @@ -52,8 +66,8 @@ cdef inline double bilinear_interpolation(double* image, Py_ssize_t rows, Shape of image. r, c : double Position at which to interpolate. - mode : {'C', 'W', 'R', 'N', 'M'} - Wrapping mode. Constant, Wrap, Reflect, Nearest or Mirror. + mode : {'C', 'W', 'S', 'E', 'R'} + Wrapping mode. Constant, Wrap, Symmetric, Edge or Reflect. cval : double Constant value to use for constant mode. @@ -119,8 +133,8 @@ cdef inline double biquadratic_interpolation(double* image, Py_ssize_t rows, Shape of image. r, c : double Position at which to interpolate. - mode : {'C', 'W', 'R', 'N', 'M'} - Wrapping mode. Constant, Wrap, Reflect, Nearest or Mirror. + mode : {'C', 'W', 'S', 'E', 'R'} + Wrapping mode. Constant, Wrap, Symmetric, Edge or Reflect. cval : double Constant value to use for constant mode. @@ -192,8 +206,8 @@ cdef inline double bicubic_interpolation(double* image, Py_ssize_t rows, Shape of image. r, c : double Position at which to interpolate. - mode : {'C', 'W', 'R', 'N', 'M'} - Wrapping mode. Constant, Wrap, Reflect, Nearest or Mirror. + mode : {'C', 'W', 'S', 'E', 'R'} + Wrapping mode. Constant, Wrap, Symmetric, Edge or Reflect. cval : double Constant value to use for constant mode. @@ -248,8 +262,8 @@ cdef inline double get_pixel2d(double* image, Py_ssize_t rows, Py_ssize_t cols, Shape of image. r, c : int Position at which to get the pixel. - mode : {'C', 'W', 'R', 'N', 'M'} - Wrapping mode. Constant, Wrap, Reflect, Nearest or Mirror. + mode : {'C', 'W', 'S', 'E', 'R'} + Wrapping mode. Constant, Wrap, Symmetric, Edge or Reflect. cval : double Constant value to use for constant mode. @@ -281,8 +295,8 @@ cdef inline double get_pixel3d(double* image, Py_ssize_t rows, Py_ssize_t cols, Shape of image. r, c, d : int Position at which to get the pixel. - mode : {'C', 'W', 'R', 'N', 'M'} - Wrapping mode. Constant, Wrap, Reflect, Nearest or Mirror. + mode : {'C', 'W', 'S', 'E', 'R'} + Wrapping mode. Constant, Wrap, Symmetric, Edge or Reflect. cval : double Constant value to use for constant mode. @@ -312,14 +326,13 @@ cdef inline Py_ssize_t coord_map(Py_ssize_t dim, long coord, char mode) nogil: Maximum coordinate. coord : int Coord provided by user. May be < 0 or > dim. - mode : {'W', 'R', 'N', 'M'} - Whether to wrap, reflect, mirror or use the nearest coordinate if it - falls outside [0, dim). - + mode : {'W', 'S', 'R', 'E'} + Whether to wrap, symmetric reflect, reflect or use the nearest + coordinate if `coord` falls outside [0, dim). """ cdef Py_ssize_t cmax cmax = dim - 1 - if mode == 'R': # reflect + if mode == 'S': # symmetric if coord < 0: coord = -coord - 1 if coord > cmax: @@ -332,12 +345,12 @@ cdef inline Py_ssize_t coord_map(Py_ssize_t dim, long coord, char mode) nogil: return (cmax - ((-coord - 1) % dim)) elif coord > cmax: return (coord % dim) - elif mode == 'N': # nearest + elif mode == 'E': # edge if coord < 0: return 0 elif coord > cmax: return cmax - elif mode == 'M': # mirror + elif mode == 'R': # reflect (mirror) if coord < 0: # How many times times does the coordinate wrap? if (-coord / cmax) % 2 != 0: diff --git a/skimage/_shared/interpolation.pyx b/skimage/_shared/interpolation.pyx index b6470651..f5110480 100644 --- a/skimage/_shared/interpolation.pyx +++ b/skimage/_shared/interpolation.pyx @@ -1,6 +1,7 @@ from interpolation cimport coord_map, get_pixel2d import numpy as np cimport numpy as cnp +from .utils import _mode_deprecations def coord_map_py(Py_ssize_t dim, long coord, mode): @@ -18,7 +19,7 @@ def extend_image(image, pad=10, mode='constant', cval=0): Input image. pad : int, optional The number of pixels to pad around the border - mode : {'constant', 'nearest', 'reflect', 'mirror', 'wrap'}, optional + mode : {'constant', 'edge', 'symmetric', 'reflect', 'wrap'}, optional Points outside the boundaries of the input are filled according to the given mode. cval : float, optional @@ -36,7 +37,7 @@ def extend_image(image, pad=10, mode='constant', cval=0): function is intended only for testing get_pixel2d and demonstrating the coordinate mapping modes implemented in ``coord_map``. """ - + mode = _mode_deprecations(mode) cdef: Py_ssize_t rows = image.shape[0] Py_ssize_t cols = image.shape[1] diff --git a/skimage/_shared/tests/test_interpolation.py b/skimage/_shared/tests/test_interpolation.py index 8022e0e1..61a24ea9 100644 --- a/skimage/_shared/tests/test_interpolation.py +++ b/skimage/_shared/tests/test_interpolation.py @@ -3,21 +3,25 @@ from numpy.testing import assert_array_equal def test_coord_map(): - reflect = [coord_map_py(4, n, 'R') for n in range(-6, 6)] - expected_reflect = [2, 3, 3, 2, 1, 0, 0, 1, 2, 3, 3, 2] - assert_array_equal(reflect, expected_reflect) + symmetric = [coord_map_py(4, n, 'S') for n in range(-6, 6)] + expected_symmetric = [2, 3, 3, 2, 1, 0, 0, 1, 2, 3, 3, 2] + assert_array_equal(symmetric, expected_symmetric) wrap = [coord_map_py(4, n, 'W') for n in range(-6, 6)] expected_wrap = [2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1] assert_array_equal(wrap, expected_wrap) - nearest = [coord_map_py(4, n, 'N') for n in range(-6, 6)] - expected_neareset = [0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3] - assert_array_equal(nearest, expected_neareset) + edge = [coord_map_py(4, n, 'E') for n in range(-6, 6)] + expected_edge = [0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3] + assert_array_equal(edge, expected_edge) - mirror = [coord_map_py(4, n, 'M') for n in range(-6, 6)] - expected_mirror = [0, 1, 2, 3, 2, 1, 0, 1, 2, 3, 2, 1] - assert_array_equal(mirror, expected_mirror) + reflect = [coord_map_py(4, n, 'R') for n in range(-6, 6)] + expected_reflect = [0, 1, 2, 3, 2, 1, 0, 1, 2, 3, 2, 1] + assert_array_equal(reflect, expected_reflect) + + constant = [coord_map_py(4, n, 'C') for n in range(-6, 6)] + expected_constant = [0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0] + assert_array_equal(constant, expected_constant) other = [coord_map_py(4, n, 'undefined') for n in range(-6, 6)] assert_array_equal(other, list(range(-6, 6))) diff --git a/skimage/_shared/utils.py b/skimage/_shared/utils.py index 43fda35d..eadc3015 100644 --- a/skimage/_shared/utils.py +++ b/skimage/_shared/utils.py @@ -163,3 +163,14 @@ def assert_nD(array, ndim, arg_name='image'): ndim = [ndim] if not array.ndim in ndim: raise ValueError(msg % (arg_name, '-or-'.join([str(n) for n in ndim]))) + + +def _mode_deprecations(mode): + """ to be used by functions to update deprecated mode names in + `skimage._shared.interpolation.pyx`.""" + if mode.lower() == 'nearest': + warnings.warn(skimage_deprecation( + "Mode 'nearest' has been renamed 'edge'. Mode 'nearest' will be " + "removed in a future release.")) + mode = 'edge' + return mode diff --git a/skimage/restoration/_denoise.py b/skimage/restoration/_denoise.py index 10de6c68..c44ab1f1 100644 --- a/skimage/restoration/_denoise.py +++ b/skimage/restoration/_denoise.py @@ -2,6 +2,7 @@ import numpy as np from .. import img_as_float from ..restoration._denoise_cy import _denoise_bilateral, _denoise_tv_bregman +from .._shared.utils import _mode_deprecations def denoise_bilateral(image, win_size=5, sigma_range=None, sigma_spatial=1, @@ -37,9 +38,9 @@ def denoise_bilateral(image, win_size=5, sigma_range=None, sigma_spatial=1, bins : int Number of discrete values for gaussian weights of color filtering. A larger value results in improved accuracy. - mode : string + mode : {'constant', 'edge', 'symmetric', 'reflect', 'wrap'} How to handle values outside the image borders. See - `scipy.ndimage.map_coordinates` for detail. + `numpy.pad` for detail. cval : string Used in conjunction with mode 'constant', the value outside the image boundaries. @@ -54,6 +55,7 @@ def denoise_bilateral(image, win_size=5, sigma_range=None, sigma_spatial=1, .. [1] http://users.soe.ucsc.edu/~manduchi/Papers/ICCV98.pdf """ + mode = _mode_deprecations(mode) return _denoise_bilateral(image, win_size, sigma_range, sigma_spatial, bins, mode, cval) diff --git a/skimage/restoration/_denoise_cy.pyx b/skimage/restoration/_denoise_cy.pyx index 7d3a82b9..b679b488 100644 --- a/skimage/restoration/_denoise_cy.pyx +++ b/skimage/restoration/_denoise_cy.pyx @@ -105,9 +105,9 @@ def _denoise_bilateral(image, Py_ssize_t win_size, sigma_range, centres = malloc(dims * sizeof(double)) total_values = malloc(dims * sizeof(double)) - if mode not in ('constant', 'wrap', 'reflect', 'nearest'): - raise ValueError("Invalid mode specified. Please use " - "`constant`, `nearest`, `wrap` or `reflect`.") + if mode not in ('constant', 'wrap', 'symmetric', 'reflect', 'edge'): + raise ValueError("Invalid mode specified. Please use `constant`, " + "`edge`, `wrap`, `symmetric` or `reflect`.") cdef char cmode = ord(mode[0].upper()) for r in range(rows): diff --git a/skimage/transform/_geometric.py b/skimage/transform/_geometric.py index 3915a055..db115c08 100644 --- a/skimage/transform/_geometric.py +++ b/skimage/transform/_geometric.py @@ -5,8 +5,10 @@ import numpy as np from scipy import spatial from scipy import ndimage as ndi -from .._shared.utils import get_bound_method_class, safe_as_int +from .._shared.utils import (get_bound_method_class, safe_as_int, + _mode_deprecations) from ..util import img_as_float + from ._warps_cy import _warp_fast @@ -1128,9 +1130,9 @@ def _clip_warp_output(input_image, output_image, order, mode, cval, clip): order : int, optional The order of the spline interpolation, default is 1. The order has to be in the range 0-5. See `skimage.transform.warp` for detail. - mode : {'constant', 'nearest', 'reflect', 'mirror', 'wrap'}, optional + mode : {'constant', 'edge', 'symmetric', 'reflect', 'wrap'}, optional Points outside the boundaries of the input are filled according - to the given mode. + to the given mode. Modes match the behaviour of `numpy.pad`. cval : float, optional Used in conjunction with mode 'constant', the value outside the image boundaries. @@ -1140,7 +1142,7 @@ def _clip_warp_output(input_image, output_image, order, mode, cval, clip): produce values outside the given input range. """ - + mode = _mode_deprecations(mode) if clip and order != 0: min_val = input_image.min() max_val = input_image.max() @@ -1211,9 +1213,9 @@ def warp(image, inverse_map=None, map_args={}, output_shape=None, order=1, - 3: Bi-cubic - 4: Bi-quartic - 5: Bi-quintic - mode : {'constant', 'nearest', 'reflect', 'mirror', 'wrap'}, optional + mode : {'constant', 'edge', 'symmetric', 'reflect', 'wrap'}, optional Points outside the boundaries of the input are filled according - to the given mode. + to the given mode. Modes match the behaviour of `numpy.pad`. cval : float, optional Used in conjunction with mode 'constant', the value outside the image boundaries. @@ -1294,7 +1296,7 @@ def warp(image, inverse_map=None, map_args={}, output_shape=None, order=1, >>> warped = warp(cube, coords) """ - + mode = _mode_deprecations(mode) image = _convert_warp_input(image, preserve_range) input_shape = np.array(image.shape) diff --git a/skimage/transform/_warps.py b/skimage/transform/_warps.py index 8f968777..02d66d91 100644 --- a/skimage/transform/_warps.py +++ b/skimage/transform/_warps.py @@ -4,6 +4,18 @@ from scipy import ndimage as ndi from ..measure import block_reduce from ._geometric import (warp, SimilarityTransform, AffineTransform, _convert_warp_input, _clip_warp_output) +from .._shared.utils import _mode_deprecations + + +def _to_ndimage_mode(mode): + """ Convert from a numpy.pad mode name to the corresponding ndimage + mode. """ + mode = _mode_deprecations(mode.lower()) + mode_translation_dict = dict(edge='nearest', symmetric='reflect', + reflect='mirror') + if mode in mode_translation_dict: + mode = mode_translation_dict[mode] + return mode def resize(image, output_shape, order=1, mode='constant', cval=0, clip=True, @@ -35,9 +47,9 @@ def resize(image, output_shape, order=1, mode='constant', cval=0, clip=True, order : int, optional The order of the spline interpolation, default is 1. The order has to be in the range 0-5. See `skimage.transform.warp` for detail. - mode : {'constant', 'nearest', 'reflect', 'mirror', 'wrap'}, optional + mode : {'constant', 'edge', 'symmetric', 'reflect', 'wrap'}, optional Points outside the boundaries of the input are filled according - to the given mode. + to the given mode. Modes match the behaviour of `numpy.pad`. cval : float, optional Used in conjunction with mode 'constant', the value outside the image boundaries. @@ -51,10 +63,10 @@ def resize(image, output_shape, order=1, mode='constant', cval=0, clip=True, Note ---- - Modes 'mirror' and 'reflect' are similar, but differ in whether the edge + Modes 'reflect' and 'symmetric' are similar, but differ in whether the edge voxels are duplicated during the reflection. As an example, if an array has values [0, 1, 2] and was padded to the right by four values using - reflect, the result would be [0, 1, 2, 2, 1, 0, 0], while for mirror it + symmetric, the result would be [0, 1, 2, 2, 1, 0, 0], while for reflect it would be [0, 1, 2, 1, 0, 1, 2]. Examples @@ -76,6 +88,7 @@ def resize(image, output_shape, order=1, mode='constant', cval=0, clip=True, # 3-dimensional interpolation if len(output_shape) == 3 and (image.ndim == 2 or output_shape[2] != image.shape[2]): + mode = _to_ndimage_mode(mode) dim = output_shape[2] if image.ndim == 2: image = image[:, :, np.newaxis] @@ -146,9 +159,9 @@ def rescale(image, scale, order=1, mode='constant', cval=0, clip=True, order : int, optional The order of the spline interpolation, default is 1. The order has to be in the range 0-5. See `skimage.transform.warp` for detail. - mode : {'constant', 'nearest', 'reflect', 'mirror', 'wrap'}, optional + mode : {'constant', 'edge', 'symmetric', 'reflect', 'wrap'}, optional Points outside the boundaries of the input are filled according - to the given mode. + to the given mode. Modes match the behaviour of `numpy.pad`. cval : float, optional Used in conjunction with mode 'constant', the value outside the image boundaries. @@ -214,9 +227,9 @@ def rotate(image, angle, resize=False, center=None, order=1, mode='constant', order : int, optional The order of the spline interpolation, default is 1. The order has to be in the range 0-5. See `skimage.transform.warp` for detail. - mode : {'constant', 'nearest', 'reflect', 'mirror', 'wrap'}, optional + mode : {'constant', 'edge', 'symmetric', 'reflect', 'wrap'}, optional Points outside the boundaries of the input are filled according - to the given mode. + to the given mode. Modes match the behaviour of `numpy.pad`. cval : float, optional Used in conjunction with mode 'constant', the value outside the image boundaries. @@ -368,9 +381,9 @@ def swirl(image, center=None, strength=1, radius=100, rotation=0, order : int, optional The order of the spline interpolation, default is 1. The order has to be in the range 0-5. See `skimage.transform.warp` for detail. - mode : {'constant', 'nearest', 'reflect', 'mirror', 'wrap'}, optional + mode : {'constant', 'edge', 'symmetric', 'reflect', 'wrap'}, optional Points outside the boundaries of the input are filled according - to the given mode. + to the given mode. Modes match the behaviour of `numpy.pad`. cval : float, optional Used in conjunction with mode 'constant', the value outside the image boundaries. diff --git a/skimage/transform/_warps_cy.pyx b/skimage/transform/_warps_cy.pyx index caab79fd..befc1e89 100644 --- a/skimage/transform/_warps_cy.pyx +++ b/skimage/transform/_warps_cy.pyx @@ -70,18 +70,19 @@ def _warp_fast(cnp.ndarray image, cnp.ndarray H, output_shape=None, * 1: Bi-linear (default) * 2: Bi-quadratic * 3: Bi-cubic - mode : {'constant', 'reflect', 'mirror', 'wrap', 'nearest'}, optional - How to handle values outside the image borders (default is constant). + mode : {'constant', 'edge', 'symmetric', 'reflect', 'wrap'}, optional + Points outside the boundaries of the input are filled according + to the given mode. Modes match the behaviour of `numpy.pad`. cval : string, optional (default 0) Used in conjunction with mode 'C' (constant), the value outside the image boundaries. Note ---- - Modes 'mirror' and 'reflect' are similar, but differ in whether the edge + Modes 'reflect' and 'symmetric' are similar, but differ in whether the edge voxels are duplicated during the reflection. As an example, if an array has values [0, 1, 2] and was padded to the right by four values using - reflect, the result would be [0, 1, 2, 2, 1, 0, 0], while for mirror it + symmetric, the result would be [0, 1, 2, 2, 1, 0, 0], while for reflect it would be [0, 1, 2, 1, 0, 1, 2]. """ @@ -89,9 +90,9 @@ def _warp_fast(cnp.ndarray image, cnp.ndarray H, output_shape=None, cdef double[:, ::1] img = np.ascontiguousarray(image, dtype=np.double) cdef double[:, ::1] M = np.ascontiguousarray(H) - if mode not in ('constant', 'wrap', 'reflect', 'mirror', 'nearest'): + if mode not in ('constant', 'wrap', 'symmetric', 'reflect', 'edge'): raise ValueError("Invalid mode specified. Please use `constant`, " - "`nearest`, `wrap`, `mirror` or `reflect`.") + "`edge`, `wrap`, `reflect` or `symmetric`.") cdef char mode_c = ord(mode[0].upper()) cdef Py_ssize_t out_r, out_c diff --git a/skimage/transform/pyramids.py b/skimage/transform/pyramids.py index fe2d26d1..958e9d65 100644 --- a/skimage/transform/pyramids.py +++ b/skimage/transform/pyramids.py @@ -45,7 +45,7 @@ def pyramid_reduce(image, downscale=2, sigma=None, order=1, order : int, optional Order of splines used in interpolation of downsampling. See `skimage.transform.warp` for detail. - mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional + mode : {'reflect', 'constant', 'edge', 'symmetric', 'wrap'}, optional The mode parameter determines how the array borders are handled, where cval is the value when mode is equal to 'constant'. cval : float, optional @@ -99,7 +99,7 @@ def pyramid_expand(image, upscale=2, sigma=None, order=1, order : int, optional Order of splines used in interpolation of upsampling. See `skimage.transform.warp` for detail. - mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional + mode : {'reflect', 'constant', 'edge', 'symmetric', 'wrap'}, optional The mode parameter determines how the array borders are handled, where cval is the value when mode is equal to 'constant'. cval : float, optional @@ -164,7 +164,7 @@ def pyramid_gaussian(image, max_layer=-1, downscale=2, sigma=None, order=1, order : int, optional Order of splines used in interpolation of downsampling. See `skimage.transform.warp` for detail. - mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional + mode : {'reflect', 'constant', 'edge', 'symmetric', 'wrap'}, optional The mode parameter determines how the array borders are handled, where cval is the value when mode is equal to 'constant'. cval : float, optional @@ -245,7 +245,7 @@ def pyramid_laplacian(image, max_layer=-1, downscale=2, sigma=None, order=1, order : int, optional Order of splines used in interpolation of downsampling. See `skimage.transform.warp` for detail. - mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional + mode : {'reflect', 'constant', 'edge', 'symmetric', 'wrap'}, optional The mode parameter determines how the array borders are handled, where cval is the value when mode is equal to 'constant'. cval : float, optional From 81764d8ed57829ebed43a3f33b73c3d3b963a5f7 Mon Sep 17 00:00:00 2001 From: "Gregory R. Lee" Date: Thu, 13 Aug 2015 22:58:53 -0400 Subject: [PATCH 15/19] BUG: update the edge modes in the example to match the current naming convention --- doc/examples/plot_edge_modes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/examples/plot_edge_modes.py b/doc/examples/plot_edge_modes.py index f48d7aed..d68abf02 100644 --- a/doc/examples/plot_edge_modes.py +++ b/doc/examples/plot_edge_modes.py @@ -19,7 +19,7 @@ img[:2, :2] += 1 img[:1, :1] += 2 img[8, 8] = 4 -modes = ['constant', 'nearest', 'wrap', 'reflect', 'mirror'] +modes = ['constant', 'edge', 'wrap', 'reflect', 'symmetric'] fig, axes = plt.subplots(1, 5, figsize=(15, 5)) for n, mode in enumerate(modes): img_extended = extend_image(img, pad=img.shape[0], mode=mode) From c7a82f8cebc9344c0bf309d9e50e56ed95719fcc Mon Sep 17 00:00:00 2001 From: "Gregory R. Lee" Date: Thu, 13 Aug 2015 23:19:56 -0400 Subject: [PATCH 16/19] MAINT: minor spacing issues and typos fixed --- skimage/_shared/interpolation.pyx | 4 ++-- skimage/transform/_warps.py | 2 +- skimage/transform/_warps_cy.pyx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/skimage/_shared/interpolation.pyx b/skimage/_shared/interpolation.pyx index f5110480..583fe43c 100644 --- a/skimage/_shared/interpolation.pyx +++ b/skimage/_shared/interpolation.pyx @@ -5,13 +5,13 @@ from .utils import _mode_deprecations def coord_map_py(Py_ssize_t dim, long coord, mode): - """ interpolation.coord_map python wrapper """ + """interpolation.coord_map python wrapper""" cdef char mode_c = ord(mode[0].upper()) return coord_map(dim, coord, mode_c) def extend_image(image, pad=10, mode='constant', cval=0): - """ Pad a 2D image by ``pad`` pixels on each side. + """Pad a 2D image by ``pad`` pixels on each side. Parameters ---------- diff --git a/skimage/transform/_warps.py b/skimage/transform/_warps.py index 02d66d91..830c98ed 100644 --- a/skimage/transform/_warps.py +++ b/skimage/transform/_warps.py @@ -64,7 +64,7 @@ def resize(image, output_shape, order=1, mode='constant', cval=0, clip=True, Note ---- Modes 'reflect' and 'symmetric' are similar, but differ in whether the edge - voxels are duplicated during the reflection. As an example, if an array + pixels are duplicated during the reflection. As an example, if an array has values [0, 1, 2] and was padded to the right by four values using symmetric, the result would be [0, 1, 2, 2, 1, 0, 0], while for reflect it would be [0, 1, 2, 1, 0, 1, 2]. diff --git a/skimage/transform/_warps_cy.pyx b/skimage/transform/_warps_cy.pyx index befc1e89..a3167016 100644 --- a/skimage/transform/_warps_cy.pyx +++ b/skimage/transform/_warps_cy.pyx @@ -80,7 +80,7 @@ def _warp_fast(cnp.ndarray image, cnp.ndarray H, output_shape=None, Note ---- Modes 'reflect' and 'symmetric' are similar, but differ in whether the edge - voxels are duplicated during the reflection. As an example, if an array + pixels are duplicated during the reflection. As an example, if an array has values [0, 1, 2] and was padded to the right by four values using symmetric, the result would be [0, 1, 2, 2, 1, 0, 0], while for reflect it would be [0, 1, 2, 1, 0, 1, 2]. From 130331751213bc23b469dc0856df01c96988b405 Mon Sep 17 00:00:00 2001 From: "Gregory R. Lee" Date: Fri, 14 Aug 2015 09:38:02 -0400 Subject: [PATCH 17/19] BUG: fix one additional location where ndimage mode conversion was needed --- skimage/transform/_geometric.py | 15 +++++++++++++-- skimage/transform/_warps.py | 18 ++++-------------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/skimage/transform/_geometric.py b/skimage/transform/_geometric.py index db115c08..3d459b36 100644 --- a/skimage/transform/_geometric.py +++ b/skimage/transform/_geometric.py @@ -12,6 +12,17 @@ from ..util import img_as_float from ._warps_cy import _warp_fast +def _to_ndimage_mode(mode): + """ Convert from a numpy.pad mode name to the corresponding ndimage + mode. """ + mode = _mode_deprecations(mode.lower()) + mode_translation_dict = dict(edge='nearest', symmetric='reflect', + reflect='mirror') + if mode in mode_translation_dict: + mode = mode_translation_dict[mode] + return mode + + def _center_and_normalize_points(points): """Center and normalize image points. @@ -1142,7 +1153,6 @@ def _clip_warp_output(input_image, output_image, order, mode, cval, clip): produce values outside the given input range. """ - mode = _mode_deprecations(mode) if clip and order != 0: min_val = input_image.min() max_val = input_image.max() @@ -1390,8 +1400,9 @@ def warp(image, inverse_map=None, map_args={}, output_shape=None, order=1, # Pre-filtering not necessary for order 0, 1 interpolation prefilter = order > 1 + ndi_mode = _to_ndimage_mode(mode) warped = ndi.map_coordinates(image, coords, prefilter=prefilter, - mode=mode, order=order, cval=cval) + mode=ndi_mode, order=order, cval=cval) _clip_warp_output(image, warped, order, mode, cval, clip) diff --git a/skimage/transform/_warps.py b/skimage/transform/_warps.py index 830c98ed..a5d05078 100644 --- a/skimage/transform/_warps.py +++ b/skimage/transform/_warps.py @@ -3,21 +3,11 @@ from scipy import ndimage as ndi from ..measure import block_reduce from ._geometric import (warp, SimilarityTransform, AffineTransform, - _convert_warp_input, _clip_warp_output) + _convert_warp_input, _clip_warp_output, + _to_ndimage_mode) from .._shared.utils import _mode_deprecations -def _to_ndimage_mode(mode): - """ Convert from a numpy.pad mode name to the corresponding ndimage - mode. """ - mode = _mode_deprecations(mode.lower()) - mode_translation_dict = dict(edge='nearest', symmetric='reflect', - reflect='mirror') - if mode in mode_translation_dict: - mode = mode_translation_dict[mode] - return mode - - def resize(image, output_shape, order=1, mode='constant', cval=0, clip=True, preserve_range=False): """Resize image to match a certain size. @@ -88,7 +78,7 @@ def resize(image, output_shape, order=1, mode='constant', cval=0, clip=True, # 3-dimensional interpolation if len(output_shape) == 3 and (image.ndim == 2 or output_shape[2] != image.shape[2]): - mode = _to_ndimage_mode(mode) + ndi_mode = _to_ndimage_mode(mode) dim = output_shape[2] if image.ndim == 2: image = image[:, :, np.newaxis] @@ -105,7 +95,7 @@ def resize(image, output_shape, order=1, mode='constant', cval=0, clip=True, image = _convert_warp_input(image, preserve_range) out = ndi.map_coordinates(image, coord_map, order=order, - mode=mode, cval=cval) + mode=ndi_mode, cval=cval) _clip_warp_output(image, out, order, mode, cval, clip) From beff4d5845d514334c7f82a88a068f2505e1fca1 Mon Sep 17 00:00:00 2001 From: "Gregory R. Lee" Date: Fri, 14 Aug 2015 10:10:50 -0400 Subject: [PATCH 18/19] DOC: update TODO.txt to mention eventual removal of _mode_deprecations --- TODO.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/TODO.txt b/TODO.txt index 98e8653b..31c3e390 100644 --- a/TODO.txt +++ b/TODO.txt @@ -11,6 +11,10 @@ Version 0.13 * Remove deprecated edge filters `hsobel`, `vsobel`, `hscharr`, `vscharr`, `hprewitt`, `vprewitt`, `roberts_positive_diagonal`, `roberts_negative_diagonal` in `skimage/filters/edges.py` +* Remove supported for renamed edge mode, 'nearest' (it is now 'edge'). This + involves removing the function _mode_deprecations from skimage._shared.utils + as well as any uses of _mode_deprecations from restoration/_denoise.py, + _shared/interpolation.pyx, transform/_geometric.py, and transform/_warps.py Version 0.12 ------------ From 49b4f69ac0eab8ce01dbf1097079bf9b90026f46 Mon Sep 17 00:00:00 2001 From: "Gregory R. Lee" Date: Tue, 18 Aug 2015 12:22:10 -0400 Subject: [PATCH 19/19] MAINT: remove unused import --- skimage/transform/_warps.py | 1 - 1 file changed, 1 deletion(-) diff --git a/skimage/transform/_warps.py b/skimage/transform/_warps.py index a5d05078..2f2cf553 100644 --- a/skimage/transform/_warps.py +++ b/skimage/transform/_warps.py @@ -5,7 +5,6 @@ from ..measure import block_reduce from ._geometric import (warp, SimilarityTransform, AffineTransform, _convert_warp_input, _clip_warp_output, _to_ndimage_mode) -from .._shared.utils import _mode_deprecations def resize(image, output_shape, order=1, mode='constant', cval=0, clip=True,