Skip to content

Commit

Permalink
All modes in _shared.interpolation.pxd were changed to be consistent …
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
grlee77 committed Aug 14, 2015
1 parent f0f0658 commit 659b844
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 62 deletions.
51 changes: 32 additions & 19 deletions skimage/_shared/interpolation.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand All @@ -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.
Expand All @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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:
Expand All @@ -332,12 +345,12 @@ cdef inline Py_ssize_t coord_map(Py_ssize_t dim, long coord, char mode) nogil:
return <Py_ssize_t>(cmax - ((-coord - 1) % dim))
elif coord > cmax:
return <Py_ssize_t>(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 <Py_ssize_t>(-coord / cmax) % 2 != 0:
Expand Down
5 changes: 3 additions & 2 deletions skimage/_shared/interpolation.pyx
Original file line number Diff line number Diff line change
@@ -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):
Expand All @@ -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
Expand All @@ -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]
Expand Down
22 changes: 13 additions & 9 deletions skimage/_shared/tests/test_interpolation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,25 @@


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)

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)

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)
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)))
11 changes: 11 additions & 0 deletions skimage/_shared/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
6 changes: 4 additions & 2 deletions skimage/restoration/_denoise.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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.
Expand All @@ -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)

Expand Down
6 changes: 3 additions & 3 deletions skimage/restoration/_denoise_cy.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@ def _denoise_bilateral(image, Py_ssize_t win_size, sigma_range,
centres = <double*>malloc(dims * sizeof(double))
total_values = <double*>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):
Expand Down
16 changes: 9 additions & 7 deletions skimage/transform/_geometric.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
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


Expand Down Expand Up @@ -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.
Expand All @@ -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()
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)
Expand Down
33 changes: 23 additions & 10 deletions skimage/transform/_warps.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@
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,
Expand Down Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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]
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
Loading

0 comments on commit 659b844

Please sign in to comment.