Merge pull request #750 from ahojnnes/misc

Misc cleanups.
This commit is contained in:
Stefan van der Walt
2013-10-02 08:57:33 -07:00
8 changed files with 107 additions and 51 deletions
+2 -2
View File
@@ -684,9 +684,9 @@ def gray2rgb(image):
"""
if np.squeeze(image).ndim == 3 and image.shape[2] in (3, 4):
return image
elif is_gray(image):
elif image.ndim != 1 and np.squeeze(image).ndim in (1, 2, 3):
image = image[..., np.newaxis]
return np.concatenate((image,)*3, axis=-1)
return np.concatenate(3 * (image,), axis=-1)
else:
raise ValueError("Input image expected to be RGB, RGBA or gray.")
+4 -4
View File
@@ -37,7 +37,7 @@ def _denoise_tv_chambolle_3d(im, weight=100, eps=2.e-4, n_iter_max=200):
>>> mask = (x - 22)**2 + (y - 20)**2 + (z - 17)**2 < 8**2
>>> mask = mask.astype(np.float)
>>> mask += 0.2 * np.random.randn(*mask.shape)
>>> res = denoise_tv(mask, weight=100)
>>> res = denoise_tv_chambolle(mask, weight=100)
"""
@@ -127,7 +127,7 @@ def _denoise_tv_chambolle_2d(im, weight=50, eps=2.e-4, n_iter_max=200):
>>> from skimage import color, data
>>> lena = color.rgb2gray(data.lena())
>>> lena += 0.5 * lena.std() * np.random.randn(*lena.shape)
>>> denoised_lena = denoise_tv(lena, weight=60)
>>> denoised_lena = denoise_tv_chambolle(lena, weight=60)
"""
@@ -227,7 +227,7 @@ def denoise_tv_chambolle(im, weight=50, eps=2.e-4, n_iter_max=200,
>>> from skimage import color, data
>>> lena = color.rgb2gray(data.lena())
>>> lena += 0.5 * lena.std() * np.random.randn(*lena.shape)
>>> denoised_lena = denoise_tv(lena, weight=60)
>>> denoised_lena = denoise_tv_chambolle(lena, weight=60)
3D example on synthetic data:
@@ -235,7 +235,7 @@ def denoise_tv_chambolle(im, weight=50, eps=2.e-4, n_iter_max=200,
>>> mask = (x - 22)**2 + (y - 20)**2 + (z - 17)**2 < 8**2
>>> mask = mask.astype(np.float)
>>> mask += 0.2*np.random.randn(*mask.shape)
>>> res = denoise_tv(mask, weight=100)
>>> res = denoise_tv_chambolle(mask, weight=100)
"""
+56 -26
View File
@@ -951,11 +951,11 @@ def warp(image, inverse_map=None, map_args={}, output_shape=None, order=1,
----------
image : 2-D or 3-D array
Input image.
inverse_map : transformation object, callable ``xy = f(xy, **kwargs)``
inverse_map : transformation object, callable ``xy = f(xy, **kwargs)``, (3, 3) array
Inverse coordinate map. A function that transforms a (N, 2) array of
``(x, y)`` coordinates in the *output image* into their corresponding
coordinates in the *source image* (e.g. a transformation object or its
inverse).
inverse). See example section for usage.
map_args : dict, optional
Keyword arguments passed to `inverse_map`.
output_shape : tuple (rows, cols), optional
@@ -976,26 +976,46 @@ def warp(image, inverse_map=None, map_args={}, output_shape=None, order=1,
Used in conjunction with mode 'constant', the value outside
the image boundaries.
Notes
-----
In case of a `SimilarityTransform`, `AffineTransform` and
`ProjectiveTransform` and `order` in [0, 3] this function uses the
underlying transformation matrix to warp the image with a much faster
routine.
Examples
--------
Shift an image to the right:
>>> from skimage.transform import warp
>>> from skimage import data
>>> image = data.camera()
>>>
>>> def shift_right(xy):
... xy[:, 0] -= 10
... return xy
>>>
>>> warp(image, shift_right)
Use a geometric transform to warp an image:
The following image warps are all equal but differ substantially in
execution time.
Use a geometric transform to warp an image (fast):
>>> from skimage.transform import SimilarityTransform
>>> tform = SimilarityTransform(scale=0.1, rotation=0.1)
>>> tform = SimilarityTransform(translation=(0, -10))
>>> warp(image, tform)
Shift an image to the right with a callable (slow):
>>> def shift(xy):
... xy[:, 1] -= 10
... return xy
>>> warp(image, shift_right)
Use a transformation matrix to warp an image (fast):
>>> matrix = np.array([[1, 0, 0], [0, 1, -10], [0, 0, 1]])
>>> warp(image, matrix)
>>> from skimage.transform import ProjectiveTransform
>>> warp(image, ProjectiveTransform(matrix=matrix))
You can also use the inverse of a geometric transformation (fast):
>>> warp(image, tform.inverse)
"""
# Backward API compatibility
if reverse_map is not None:
@@ -1015,16 +1035,21 @@ def warp(image, inverse_map=None, map_args={}, output_shape=None, order=1,
if order in range(4) and not map_args:
matrix = None
if inverse_map in HOMOGRAPHY_TRANSFORMS:
if isinstance(inverse_map, np.ndarray) and inverse_map.shape == (3, 3):
matrix = inverse_map
elif inverse_map in HOMOGRAPHY_TRANSFORMS:
matrix = inverse_map._matrix
elif hasattr(inverse_map, '__name__') \
and inverse_map.__name__ == 'inverse' \
and get_bound_method_class(inverse_map) in HOMOGRAPHY_TRANSFORMS:
elif (hasattr(inverse_map, '__name__')
and inverse_map.__name__ == 'inverse'
and get_bound_method_class(inverse_map)
in HOMOGRAPHY_TRANSFORMS):
matrix = np.linalg.inv(six.get_method_self(inverse_map)._matrix)
if matrix is not None:
matrix = matrix.astype(np.double)
# transform all bands
dims = []
for dim in range(image.shape[2]):
@@ -1042,25 +1067,30 @@ def warp(image, inverse_map=None, map_args={}, output_shape=None, order=1,
rows, cols = output_shape[:2]
if isinstance(inverse_map, np.ndarray) and inverse_map.shape == (3, 3):
inverse_map = ProjectiveTransform(matrix=inverse_map)
def coord_map(*args):
return inverse_map(*args, **map_args)
coords = warp_coords(coord_map, (rows, cols, bands))
# Prefilter not necessary for order 1 interpolation
# Prefilter not necessary for order 0, 1 interpolation
prefilter = order > 1
out = ndimage.map_coordinates(image, coords, prefilter=prefilter,
mode=mode, order=order, cval=cval)
# The spline filters sometimes return results outside [0, 1],
# so clip to ensure valid data
clipped = np.clip(out, 0, 1)
# The spline filters sometimes return results outside [0, 1],
# so clip to ensure valid data
clipped = np.clip(out, 0, 1)
if mode == 'constant' and not (0 <= cval <= 1):
clipped[out == cval] = cval
if mode == 'constant' and not (0 <= cval <= 1):
clipped[out == cval] = cval
if clipped.ndim == 3 and orig_ndim == 2:
# remove singleton dim introduced by atleast_3d
return clipped[..., 0]
out = clipped
if out.ndim == 3 and orig_ndim == 2:
# remove singleton dimension introduced by atleast_3d
return out[..., 0]
else:
return clipped
return out
+32 -7
View File
@@ -11,10 +11,9 @@ from skimage import transform as tf, data, img_as_float
from skimage.color import rgb2gray
def test_warp():
x = np.zeros((5, 5), dtype=np.uint8)
x[2, 2] = 255
x = img_as_float(x)
def test_warp_tform():
x = np.zeros((5, 5), dtype=np.double)
x[2, 2] = 1
theta = - np.pi / 2
tform = SimilarityTransform(scale=1, rotation=theta, translation=(0, 4))
@@ -25,10 +24,36 @@ def test_warp():
assert_array_almost_equal(x90, np.rot90(x))
def test_warp_callable():
x = np.zeros((5, 5), dtype=np.double)
x[2, 2] = 1
refx = np.zeros((5, 5), dtype=np.double)
refx[1, 1] = 1
shift = lambda xy: xy + 1
outx = warp(x, shift, order=1)
assert_array_almost_equal(outx, refx)
def test_warp_matrix():
x = np.zeros((5, 5), dtype=np.double)
x[2, 2] = 1
refx = np.zeros((5, 5), dtype=np.double)
refx[1, 1] = 1
matrix = np.array([[1, 0, 1], [0, 1, 1], [0, 0, 1]])
# _warp_fast
outx = warp(x, matrix, order=1)
assert_array_almost_equal(outx, refx)
# check for ndimage.map_coordinates
outx = warp(x, matrix, order=5)
def test_homography():
x = np.zeros((5, 5), dtype=np.uint8)
x[1, 1] = 255
x = img_as_float(x)
x = np.zeros((5, 5), dtype=np.double)
x[1, 1] = 1
theta = -np.pi / 2
M = np.array([[np.cos(theta), - np.sin(theta), 0],
[np.sin(theta), np.cos(theta), 4],
+3 -3
View File
@@ -3,7 +3,7 @@ import numpy as np
def regular_grid(ar_shape, n_points):
"""Find `n_points` regularly spaced along `ar_shape`.
The returned points (as slices) should be as close to cubically-spaced as
possible. Essentially, the points are spaced by the Nth root of the input
array size, where N is the number of dimensions. However, if an array
@@ -13,7 +13,7 @@ def regular_grid(ar_shape, n_points):
Parameters
----------
ar_shape : array-like of ints
The shape of the space embedding the grid. `len(ar_shape)` is the
The shape of the space embedding the grid. ``len(ar_shape)`` is the
number of dimensions.
n_points : int
The (approximate) number of points to embed in the space.
@@ -66,7 +66,7 @@ def regular_grid(ar_shape, n_points):
break
starts = stepsizes // 2
stepsizes = np.round(stepsizes)
slices = [slice(start, None, step) for
slices = [slice(start, None, step) for
start, step in zip(starts, stepsizes)]
slices = [slices[i] for i in unsort_dim_idxs]
return slices
+3 -2
View File
@@ -10,7 +10,7 @@ def montage2d(arr_in, fill='mean', rescale_intensity=False, grid_shape=None):
"""Create a 2-dimensional 'montage' from a 3-dimensional input array
representing an ensemble of equally shaped 2-dimensional images.
For example, montage2d(arr_in, fill) with the following `arr_in`
For example, ``montage2d(arr_in, fill)`` with the following `arr_in`
+---+---+---+
| 1 | 2 | 3 |
@@ -37,7 +37,8 @@ def montage2d(arr_in, fill='mean', rescale_intensity=False, grid_shape=None):
rescale_intensity: bool, optional
Whether to rescale the intensity of each image to [0, 1].
grid_shape: tuple, optional
The desired grid shape for the montage (tiles_y, tiles_x). Tthe default aspect ratio is square.
The desired grid shape for the montage (tiles_y, tiles_x).
The default aspect ratio is square.
Returns
-------
+5 -5
View File
@@ -208,11 +208,11 @@ def view_as_windows(arr_in, window_shape, step=1):
# -- basic checks on arguments
if not isinstance(arr_in, np.ndarray):
raise TypeError("'arr_in' must be a numpy ndarray")
raise TypeError("`arr_in` must be a numpy ndarray")
if not isinstance(window_shape, tuple):
raise TypeError("'window_shape' must be a tuple")
raise TypeError("`window_shape` must be a tuple")
if not (len(window_shape) == arr_in.ndim):
raise ValueError("'window_shape' is incompatible with 'arr_in.shape'")
raise ValueError("`window_shape` is incompatible with `arr_in.shape`")
if step < 1:
raise ValueError("`step` must be >= 1")
@@ -221,10 +221,10 @@ def view_as_windows(arr_in, window_shape, step=1):
window_shape = np.array(window_shape, dtype=arr_shape.dtype)
if ((arr_shape - window_shape) < 0).any():
raise ValueError("'window_shape' is too large")
raise ValueError("`window_shape` is too large")
if ((window_shape - 1) < 0).any():
raise ValueError("'window_shape' is too small")
raise ValueError("`window_shape` is too small")
# -- build rolling window view
arr_in = np.ascontiguousarray(arr_in)
+2 -2
View File
@@ -9,12 +9,12 @@ def unique_rows(ar):
Parameters
----------
ar : 2D np.ndarray
ar : 2-D ndarray
The input array.
Returns
-------
ar_out : 2D np.ndarray
ar_out : 2-D ndarray
A copy of the input array with repeated rows removed.
Raises