Beispiel #1
0
def warp(image, inverse_map=None, map_args={}, output_shape=None, order=1,
         mode='constant', cval=0., reverse_map=None):
    """Warp an image according to a given coordinate transformation.

    Parameters
    ----------
    image : 2-D or 3-D array
        Input image.
    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). See example section for usage.
    map_args : dict, optional
        Keyword arguments passed to `inverse_map`.
    output_shape : tuple (rows, cols), optional
        Shape of the output image generated. By default the shape of the input
        image is preserved.
    order : int, optional
        The order of interpolation. The order has to be in the range 0-5:
        * 0: Nearest-neighbor
        * 1: Bi-linear (default)
        * 2: Bi-quadratic
        * 3: Bi-cubic
        * 4: Bi-quartic
        * 5: Bi-quintic
    mode : string, optional
        Points outside the boundaries of the input are filled according
        to the given mode ('constant', 'nearest', 'reflect' or 'wrap').
    cval : float, optional
        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
    --------
    >>> from skimage.transform import warp
    >>> from skimage import data
    >>> image = data.camera()

    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(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:
        inverse_map = reverse_map

    if image.ndim < 2:
        raise ValueError("Input must have more than 1 dimension.")

    orig_ndim = image.ndim
    image = np.atleast_3d(img_as_float(image))
    ishape = np.array(image.shape)
    bands = ishape[2]

    out = None

    # use fast Cython version for specific interpolation orders and input
    if order in range(4) and not map_args:

        matrix = None

        # inverse_map is a transformation matrix as numpy array
        if isinstance(inverse_map, np.ndarray) and inverse_map.shape == (3, 3):
            matrix = inverse_map

        # inverse_map is a homography
        elif isinstance(inverse_map, HOMOGRAPHY_TRANSFORMS):
            matrix = inverse_map._matrix

        # inverse_map is the inverse of a homography
        elif (hasattr(inverse_map, '__name__')
              and inverse_map.__name__ == 'inverse'
              and isinstance(get_bound_method_class(inverse_map),
                             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]):
                dims.append(_warp_fast(image[..., dim], matrix,
                            output_shape=output_shape,
                            order=order, mode=mode, cval=cval))
            out = np.dstack(dims)
            if orig_ndim == 2:
                out = out[..., 0]

    if out is None:  # use ndimage.map_coordinates

        if output_shape is None:
            output_shape = ishape

        rows, cols = output_shape[:2]

        # inverse_map is a transformation matrix as numpy array
        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))

        # Pre-filtering 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)

    if mode == 'constant' and not (0 <= cval <= 1):
        clipped[out == cval] = cval

    out = clipped

    if out.ndim == 3 and orig_ndim == 2:
        # remove singleton dimension introduced by atleast_3d
        return out[..., 0]
    else:
        return out
Beispiel #2
0
def warp(image, inverse_map=None, map_args={}, output_shape=None, order=1,
         mode='constant', cval=0., reverse_map=None):
    """Warp an image according to a given coordinate transformation.

    Parameters
    ----------
    image : 2-D or 3-D array
        Input image.
    inverse_map : transformation object, callable ``xy = f(xy, **kwargs)``
        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).
    map_args : dict, optional
        Keyword arguments passed to `inverse_map`.
    output_shape : tuple (rows, cols), optional
        Shape of the output image generated. By default the shape of the input
        image is preserved.
    order : int, optional
        The order of the spline interpolation, default is 3. The order has to
        be in the range 0-5.
    mode : string, optional
        Points outside the boundaries of the input are filled according
        to the given mode ('constant', 'nearest', 'reflect' or 'wrap').
    cval : float, optional
        Used in conjunction with mode 'constant', the value outside
        the image boundaries.

    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:

    >>> from skimage.transform import SimilarityTransform
    >>> tform = SimilarityTransform(scale=0.1, rotation=0.1)
    >>> warp(image, tform)

    """
    # Backward API compatibility
    if reverse_map is not None:
        inverse_map = reverse_map

    if image.ndim < 2:
        raise ValueError("Input must have more than 1 dimension.")

    orig_ndim = image.ndim
    image = np.atleast_3d(img_as_float(image))
    ishape = np.array(image.shape)
    bands = ishape[2]

    out = None

    # use fast Cython version for specific interpolation orders
    if order in range(4) and not map_args:
        matrix = None

        if 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:

            matrix = np.linalg.inv(six.get_method_self(inverse_map)._matrix)

        if matrix is not None:
            # transform all bands
            dims = []
            for dim in range(image.shape[2]):
                dims.append(_warp_fast(image[..., dim], matrix,
                            output_shape=output_shape,
                            order=order, mode=mode, cval=cval))
            out = np.dstack(dims)
            if orig_ndim == 2:
                out = out[..., 0]

    if out is None:  # use ndimage.map_coordinates

        if output_shape is None:
            output_shape = ishape

        rows, cols = output_shape[:2]

        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 = 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)

    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]
    else:
        return clipped