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