44import numpy as np
55from scipy import ndimage , spatial
66
7- from skimage ._shared .utils import get_bound_method_class , safe_as_int
8- from skimage .util import img_as_float
7+ from .._shared .utils import get_bound_method_class , safe_as_int
8+ from ..util import img_as_float
9+ from ..exposure import rescale_intensity
910from ._warps_cy import _warp_fast
1011
1112
@@ -994,8 +995,64 @@ def warp_coords(coord_map, shape, dtype=np.float64):
994995 return coords
995996
996997
998+ def _convert_warp_input (image , preserve_range ):
999+ """Convert input image to double image with the appropriate range."""
1000+ if preserve_range :
1001+ image = image .astype (np .double )
1002+ else :
1003+ image = img_as_float (image )
1004+ return image
1005+
1006+
1007+ def _clip_warp_output (input_image , output_image , order , mode , cval , clip ):
1008+ """Clip output image to range of values of input image.
1009+
1010+ Note that this function modifies the values of `output_image` in-place
1011+ and it is only modified if ``clip=True``.
1012+
1013+ Parameters
1014+ ----------
1015+ input_image : ndarray
1016+ Input image.
1017+ output_image : ndarray
1018+ Output image, which is modified in-place.
1019+
1020+ Other parameters
1021+ ----------------
1022+ order : int, optional
1023+ The order of the spline interpolation, default is 1. The order has to
1024+ be in the range 0-5. See `skimage.transform.warp` for detail.
1025+ mode : string, optional
1026+ Points outside the boundaries of the input are filled according
1027+ to the given mode ('constant', 'nearest', 'reflect' or 'wrap').
1028+ cval : float, optional
1029+ Used in conjunction with mode 'constant', the value outside
1030+ the image boundaries.
1031+ clip : bool, optional
1032+ Whether to clip the output to the range of values of the input image.
1033+ This is enabled by default, since higher order interpolation may
1034+ produce values outside the given input range.
1035+
1036+ """
1037+
1038+ if clip and order != 0 :
1039+ min_val = input_image .min ()
1040+ max_val = input_image .max ()
1041+
1042+ preserve_cval = mode == 'constant' and not \
1043+ (min_val <= cval <= max_val )
1044+
1045+ if preserve_cval :
1046+ cval_mask = output_image == cval
1047+
1048+ np .clip (output_image , min_val , max_val , out = output_image )
1049+
1050+ if preserve_cval :
1051+ output_image [cval_mask ] = cval
1052+
1053+
9971054def warp (image , inverse_map = None , map_args = {}, output_shape = None , order = 1 ,
998- mode = 'constant' , cval = 0. , clip = True ):
1055+ mode = 'constant' , cval = 0. , clip = True , preserve_range = False ):
9991056 """Warp an image according to a given coordinate transformation.
10001057
10011058 Parameters
@@ -1055,17 +1112,25 @@ def warp(image, inverse_map=None, map_args={}, output_shape=None, order=1,
10551112 Used in conjunction with mode 'constant', the value outside
10561113 the image boundaries.
10571114 clip : bool, optional
1058- Whether to clip the output to the float range of ``[0, 1]``, or
1059- ``[-1, 1]`` for input images with negative values. This is enabled by
1060- default, since higher order interpolation may produce values outside
1061- the given input range.
1115+ Whether to clip the output to the range of values of the input image.
1116+ This is enabled by default, since higher order interpolation may
1117+ produce values outside the given input range.
1118+ preserve_range : bool, optional
1119+ Whether to keep the original range of values. Otherwise, the input
1120+ image is converted according to the conventions of `img_as_float`.
1121+
1122+ Returns
1123+ -------
1124+ warped : double ndarray
1125+ The warped input image.
10621126
10631127 Notes
10641128 -----
1065- In case of a `SimilarityTransform`, `AffineTransform` and
1066- `ProjectiveTransform` and `order` in [0, 3] this function uses the
1067- underlying transformation matrix to warp the image with a much faster
1068- routine.
1129+ - The input image is converted to a `double` image.
1130+ - In case of a `SimilarityTransform`, `AffineTransform` and
1131+ `ProjectiveTransform` and `order` in [0, 3] this function uses the
1132+ underlying transformation matrix to warp the image with a much faster
1133+ routine.
10691134
10701135 Examples
10711136 --------
@@ -1124,15 +1189,16 @@ def warp(image, inverse_map=None, map_args={}, output_shape=None, order=1,
11241189
11251190 """
11261191
1127- image = img_as_float (image )
1192+ image = _convert_warp_input (image , preserve_range )
1193+
11281194 input_shape = np .array (image .shape )
11291195
11301196 if output_shape is None :
11311197 output_shape = input_shape
11321198 else :
11331199 output_shape = safe_as_int (output_shape )
11341200
1135- out = None
1201+ warped = None
11361202
11371203 if order == 2 :
11381204 # When fixing this issue, make sure to fix the branches further
@@ -1168,7 +1234,7 @@ def warp(image, inverse_map=None, map_args={}, output_shape=None, order=1,
11681234 if matrix is not None :
11691235 matrix = matrix .astype (np .double )
11701236 if image .ndim == 2 :
1171- out = _warp_fast (image , matrix ,
1237+ warped = _warp_fast (image , matrix ,
11721238 output_shape = output_shape ,
11731239 order = order , mode = mode , cval = cval )
11741240 elif image .ndim == 3 :
@@ -1177,9 +1243,9 @@ def warp(image, inverse_map=None, map_args={}, output_shape=None, order=1,
11771243 dims .append (_warp_fast (image [..., dim ], matrix ,
11781244 output_shape = output_shape ,
11791245 order = order , mode = mode , cval = cval ))
1180- out = np .dstack (dims )
1246+ warped = np .dstack (dims )
11811247
1182- if out is None :
1248+ if warped is None :
11831249 # use ndimage.map_coordinates
11841250
11851251 if (isinstance (inverse_map , np .ndarray )
@@ -1216,24 +1282,10 @@ def coord_map(*args):
12161282 # Pre-filtering not necessary for order 0, 1 interpolation
12171283 prefilter = order > 1
12181284
1219- out = ndimage .map_coordinates (image , coords , prefilter = prefilter ,
1285+ warped = ndimage .map_coordinates (image , coords , prefilter = prefilter ,
12201286 mode = mode , order = order , cval = cval )
12211287
1222- if clip :
1223- # The spline filters sometimes return results outside [0, 1],
1224- # so clip to ensure valid data
1225-
1226- if np .min (image ) < 0 :
1227- min_val = - 1
1228- else :
1229- min_val = 0
1230- max_val = 1
1231-
1232- clipped = np .clip (out , min_val , max_val )
1233-
1234- if mode == 'constant' and not (0 <= cval <= 1 ):
1235- clipped [out == cval ] = cval
12361288
1237- out = clipped
1289+ _clip_warp_output ( image , warped , order , mode , cval , clip )
12381290
1239- return out
1291+ return warped
0 commit comments