Source code for sofia_redux.toolkit.image.resize

# Licensed under a 3-clause BSD style license - see LICENSE.rst

import numpy as np
from numpy.lib import NumpyVersion
import scipy
from scipy import ndimage

from sofia_redux.toolkit.image.utilities import (
    to_ndimage_mode, clip_output)


__all__ = ['resize']


[docs] def resize(image, output_shape, order=None, mode='reflect', cval=0, clip=True, anti_aliasing=None, anti_aliasing_sigma=None): """ Replacement for `skimage.resize`. Parameters ---------- image : numpy.ndarray Input image. output_shape : iterable Size of the generated output image `(rows, cols[, ...][, dim])`. If `dim` is not provided, the number of channels is preserved. In case the number of input channels does not equal the number of output channels a n-dimensional interpolation is applied. order : int, optional The order of the spline interpolation, default is 0 if image.dtype is bool and 1 otherwise. The order has to be in the range 0-5. mode : str, optional One of {'constant', 'edge', 'symmetric', 'reflect', 'wrap'}. Points outside the boundaries of the input are filled according 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. clip : bool, optional Whether to clip the output to the range of values of the input image. This is enabled by default, since higher order interpolation may produce values outside the given input range. anti_aliasing : bool, optional Whether to apply a Gaussian filter to smooth the image prior to downsampling. It is crucial to filter when downsampling the image to avoid aliasing artifacts. If not specified, it is set to True when downsampling an image whose data type is not bool. anti_aliasing_sigma : {float, tuple of floats}, optional Standard deviation for Gaussian filtering used when anti-aliasing. By default, this value is chosen as (s - 1) / 2 where s is the downsampling factor, where s > 1. For the up-size case, s < 1, no anti-aliasing is performed prior to rescaling. Returns ------- resized : numpy.ndarray Resized version of the input. """ input_shape = image.shape input_type = image.dtype if order is None: order = 0 if input_type == bool else 1 if input_type == np.float16: image = image.astype(np.float32) if anti_aliasing is None: anti_aliasing = (not input_type == bool and any(x < y for x, y in zip(output_shape, input_shape))) if input_type == bool and anti_aliasing: raise ValueError("anti_aliasing must be False for boolean images") factors = np.divide(input_shape, output_shape) image = image.astype(float) bounds = np.array([np.nanmin(image), np.nanmax(image)]) if clip else None ndi_mode = to_ndimage_mode(mode) if anti_aliasing: if anti_aliasing_sigma is None: anti_aliasing_sigma = np.maximum(0, (factors - 1) / 2) else: anti_aliasing_sigma = \ np.atleast_1d(anti_aliasing_sigma) * np.ones_like(factors) if np.any(anti_aliasing_sigma < 0): raise ValueError("Anti-aliasing standard deviation must be " "greater than or equal to zero") image = ndimage.gaussian_filter(image, anti_aliasing_sigma, cval=cval, mode=ndi_mode) if NumpyVersion(scipy.__version__) >= '1.6.0': # pragma: no cover # The grid_mode kwarg was introduced in SciPy 1.6.0 zoom_factors = [1 / f for f in factors] out = ndimage.zoom(image, zoom_factors, order=order, mode=ndi_mode, cval=cval, grid_mode=True) else: # pragma: no cover # Just do N-D interpolation coord_arrays = [factors[i] * (np.arange(d) + 0.5) - 0.5 for i, d in enumerate(output_shape)] coord_map = np.array(np.meshgrid(*coord_arrays, sparse=False, indexing='ij')) out = ndimage.map_coordinates(image, coord_map, order=order, mode=ndi_mode, cval=cval) clip_output(bounds, out, mode, cval, clip) return out