Skip to content

Commit 8955bbf

Browse files
committed
Merge pull request #1302 from ahojnnes/warp
Clip to min and max range of input image, add missing clip parameter to ...
2 parents 6b0c3f7 + e38ed91 commit 8955bbf

8 files changed

Lines changed: 182 additions & 78 deletions

File tree

skimage/feature/tests/__init__.py

Whitespace-only changes.

skimage/feature/tests/test_match.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def test_binary_descriptors_lena_rotation_crosscheck_false():
3232
img = data.lena()
3333
img = rgb2gray(img)
3434
tform = tf.SimilarityTransform(scale=1, rotation=0.15, translation=(0, 0))
35-
rotated_img = tf.warp(img, tform)
35+
rotated_img = tf.warp(img, tform, clip=False)
3636

3737
extractor = BRIEF(descriptor_size=512)
3838

@@ -65,7 +65,7 @@ def test_binary_descriptors_lena_rotation_crosscheck_true():
6565
img = data.lena()
6666
img = rgb2gray(img)
6767
tform = tf.SimilarityTransform(scale=1, rotation=0.15, translation=(0, 0))
68-
rotated_img = tf.warp(img, tform)
68+
rotated_img = tf.warp(img, tform, clip=False)
6969

7070
extractor = BRIEF(descriptor_size=512)
7171

skimage/feature/tests/test_orb.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import numpy as np
2-
from numpy.testing import assert_array_equal, assert_almost_equal
2+
from numpy.testing import assert_equal, assert_almost_equal, run_module_suite
33
from skimage.feature import ORB
4-
from skimage.data import lena
4+
from skimage import data
55
from skimage.color import rgb2gray
66

77

8-
img = rgb2gray(lena())
8+
img = rgb2gray(data.lena())
99

1010

1111
def test_keypoints_orb_desired_no_of_keypoints():
@@ -42,7 +42,6 @@ def test_keypoints_orb_desired_no_of_keypoints():
4242

4343

4444
def test_keypoints_orb_less_than_desired_no_of_keypoints():
45-
img = rgb2gray(lena())
4645
detector_extractor = ORB(n_keypoints=15, fast_n=12,
4746
fast_threshold=0.33, downscale=2, n_scales=2)
4847
detector_extractor.detect(img)
@@ -102,14 +101,13 @@ def test_descriptor_orb():
102101
detector_extractor.extract(img, detector_extractor.keypoints,
103102
detector_extractor.scales,
104103
detector_extractor.orientations)
105-
assert_array_equal(exp_descriptors,
106-
detector_extractor.descriptors[100:120, 10:20])
104+
assert_equal(exp_descriptors,
105+
detector_extractor.descriptors[100:120, 10:20])
107106

108107
detector_extractor.detect_and_extract(img)
109-
assert_array_equal(exp_descriptors,
110-
detector_extractor.descriptors[100:120, 10:20])
108+
assert_equal(exp_descriptors,
109+
detector_extractor.descriptors[100:120, 10:20])
111110

112111

113112
if __name__ == '__main__':
114-
from numpy import testing
115-
testing.run_module_suite()
113+
run_module_suite()

skimage/novice/_novice.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -353,8 +353,9 @@ def size(self, value):
353353
if (value[0] != self.width) or (value[1] != self.height):
354354
# skimage dimensions are flipped: y, x
355355
new_size = (int(value[1]), int(value[0]))
356-
new_array = resize(self.array, new_size, order=0)
357-
self.array = img_as_ubyte(new_array)
356+
new_array = resize(self.array, new_size, order=0,
357+
preserve_range=True)
358+
self.array = new_array.astype(np.uint8)
358359

359360
self._array_modified()
360361

skimage/transform/_geometric.py

Lines changed: 85 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
import numpy as np
55
from 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
910
from ._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+
9971054
def 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

Comments
 (0)