feat: rewrite resize
add more nodes
This commit is contained in:
313
bioxelnodes/scipy/_interpolation.py
Normal file
313
bioxelnodes/scipy/_interpolation.py
Normal file
@@ -0,0 +1,313 @@
|
||||
import numpy as np
|
||||
import warnings
|
||||
|
||||
from . import _ni_support
|
||||
from . import _nd_image
|
||||
from ._utils import normalize_axis_index
|
||||
|
||||
|
||||
def _prepad_for_spline_filter(input, mode, cval):
|
||||
if mode in ['nearest', 'grid-constant']:
|
||||
npad = 12
|
||||
if mode == 'grid-constant':
|
||||
padded = np.pad(input, npad, mode='constant',
|
||||
constant_values=cval)
|
||||
elif mode == 'nearest':
|
||||
padded = np.pad(input, npad, mode='edge')
|
||||
else:
|
||||
# other modes have exact boundary conditions implemented so
|
||||
# no prepadding is needed
|
||||
npad = 0
|
||||
padded = input
|
||||
return padded, npad
|
||||
|
||||
def spline_filter1d(input, order=3, axis=-1, output=np.float64,
|
||||
mode='mirror'):
|
||||
"""
|
||||
Calculate a 1-D spline filter along the given axis.
|
||||
|
||||
The lines of the array along the given axis are filtered by a
|
||||
spline filter. The order of the spline must be >= 2 and <= 5.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
%(input)s
|
||||
order : int, optional
|
||||
The order of the spline, default is 3.
|
||||
axis : int, optional
|
||||
The axis along which the spline filter is applied. Default is the last
|
||||
axis.
|
||||
output : ndarray or dtype, optional
|
||||
The array in which to place the output, or the dtype of the returned
|
||||
array. Default is ``numpy.float64``.
|
||||
%(mode_interp_mirror)s
|
||||
|
||||
Returns
|
||||
-------
|
||||
spline_filter1d : ndarray
|
||||
The filtered input.
|
||||
|
||||
See Also
|
||||
--------
|
||||
spline_filter : Multidimensional spline filter.
|
||||
|
||||
Notes
|
||||
-----
|
||||
All of the interpolation functions in `ndimage` do spline interpolation of
|
||||
the input image. If using B-splines of `order > 1`, the input image
|
||||
values have to be converted to B-spline coefficients first, which is
|
||||
done by applying this 1-D filter sequentially along all
|
||||
axes of the input. All functions that require B-spline coefficients
|
||||
will automatically filter their inputs, a behavior controllable with
|
||||
the `prefilter` keyword argument. For functions that accept a `mode`
|
||||
parameter, the result will only be correct if it matches the `mode`
|
||||
used when filtering.
|
||||
|
||||
For complex-valued `input`, this function processes the real and imaginary
|
||||
components independently.
|
||||
|
||||
.. versionadded:: 1.6.0
|
||||
Complex-valued support added.
|
||||
|
||||
Examples
|
||||
--------
|
||||
We can filter an image using 1-D spline along the given axis:
|
||||
|
||||
>>> from scipy.ndimage import spline_filter1d
|
||||
>>> import numpy as np
|
||||
>>> import matplotlib.pyplot as plt
|
||||
>>> orig_img = np.eye(20) # create an image
|
||||
>>> orig_img[10, :] = 1.0
|
||||
>>> sp_filter_axis_0 = spline_filter1d(orig_img, axis=0)
|
||||
>>> sp_filter_axis_1 = spline_filter1d(orig_img, axis=1)
|
||||
>>> f, ax = plt.subplots(1, 3, sharex=True)
|
||||
>>> for ind, data in enumerate([[orig_img, "original image"],
|
||||
... [sp_filter_axis_0, "spline filter (axis=0)"],
|
||||
... [sp_filter_axis_1, "spline filter (axis=1)"]]):
|
||||
... ax[ind].imshow(data[0], cmap='gray_r')
|
||||
... ax[ind].set_title(data[1])
|
||||
>>> plt.tight_layout()
|
||||
>>> plt.show()
|
||||
|
||||
"""
|
||||
if order < 0 or order > 5:
|
||||
raise RuntimeError('spline order not supported')
|
||||
input = np.asarray(input)
|
||||
complex_output = np.iscomplexobj(input)
|
||||
output = _ni_support._get_output(output, input,
|
||||
complex_output=complex_output)
|
||||
if complex_output:
|
||||
spline_filter1d(input.real, order, axis, output.real, mode)
|
||||
spline_filter1d(input.imag, order, axis, output.imag, mode)
|
||||
return output
|
||||
if order in [0, 1]:
|
||||
output[...] = np.array(input)
|
||||
else:
|
||||
mode = _ni_support._extend_mode_to_code(mode)
|
||||
axis = normalize_axis_index(axis, input.ndim)
|
||||
_nd_image.spline_filter1d(input, order, axis, output, mode)
|
||||
return output
|
||||
|
||||
|
||||
def spline_filter(input, order=3, output=np.float64, mode='mirror'):
|
||||
"""
|
||||
Multidimensional spline filter.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
%(input)s
|
||||
order : int, optional
|
||||
The order of the spline, default is 3.
|
||||
output : ndarray or dtype, optional
|
||||
The array in which to place the output, or the dtype of the returned
|
||||
array. Default is ``numpy.float64``.
|
||||
%(mode_interp_mirror)s
|
||||
|
||||
Returns
|
||||
-------
|
||||
spline_filter : ndarray
|
||||
Filtered array. Has the same shape as `input`.
|
||||
|
||||
See Also
|
||||
--------
|
||||
spline_filter1d : Calculate a 1-D spline filter along the given axis.
|
||||
|
||||
Notes
|
||||
-----
|
||||
The multidimensional filter is implemented as a sequence of
|
||||
1-D spline filters. The intermediate arrays are stored
|
||||
in the same data type as the output. Therefore, for output types
|
||||
with a limited precision, the results may be imprecise because
|
||||
intermediate results may be stored with insufficient precision.
|
||||
|
||||
For complex-valued `input`, this function processes the real and imaginary
|
||||
components independently.
|
||||
|
||||
.. versionadded:: 1.6.0
|
||||
Complex-valued support added.
|
||||
|
||||
Examples
|
||||
--------
|
||||
We can filter an image using multidimentional splines:
|
||||
|
||||
>>> from scipy.ndimage import spline_filter
|
||||
>>> import numpy as np
|
||||
>>> import matplotlib.pyplot as plt
|
||||
>>> orig_img = np.eye(20) # create an image
|
||||
>>> orig_img[10, :] = 1.0
|
||||
>>> sp_filter = spline_filter(orig_img, order=3)
|
||||
>>> f, ax = plt.subplots(1, 2, sharex=True)
|
||||
>>> for ind, data in enumerate([[orig_img, "original image"],
|
||||
... [sp_filter, "spline filter"]]):
|
||||
... ax[ind].imshow(data[0], cmap='gray_r')
|
||||
... ax[ind].set_title(data[1])
|
||||
>>> plt.tight_layout()
|
||||
>>> plt.show()
|
||||
|
||||
"""
|
||||
if order < 2 or order > 5:
|
||||
raise RuntimeError('spline order not supported')
|
||||
input = np.asarray(input)
|
||||
complex_output = np.iscomplexobj(input)
|
||||
output = _ni_support._get_output(output, input,
|
||||
complex_output=complex_output)
|
||||
if complex_output:
|
||||
spline_filter(input.real, order, output.real, mode)
|
||||
spline_filter(input.imag, order, output.imag, mode)
|
||||
return output
|
||||
if order not in [0, 1] and input.ndim > 0:
|
||||
for axis in range(input.ndim):
|
||||
spline_filter1d(input, order, axis, output=output, mode=mode)
|
||||
input = output
|
||||
else:
|
||||
output[...] = input[...]
|
||||
return output
|
||||
|
||||
|
||||
def zoom(input, zoom, output=None, order=3, mode='constant', cval=0.0,
|
||||
prefilter=True, *, grid_mode=False):
|
||||
"""
|
||||
Zoom an array.
|
||||
|
||||
The array is zoomed using spline interpolation of the requested order.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
%(input)s
|
||||
zoom : float or sequence
|
||||
The zoom factor along the axes. If a float, `zoom` is the same for each
|
||||
axis. If a sequence, `zoom` should contain one value for each axis.
|
||||
%(output)s
|
||||
order : int, optional
|
||||
The order of the spline interpolation, default is 3.
|
||||
The order has to be in the range 0-5.
|
||||
%(mode_interp_constant)s
|
||||
%(cval)s
|
||||
%(prefilter)s
|
||||
grid_mode : bool, optional
|
||||
If False, the distance from the pixel centers is zoomed. Otherwise, the
|
||||
distance including the full pixel extent is used. For example, a 1d
|
||||
signal of length 5 is considered to have length 4 when `grid_mode` is
|
||||
False, but length 5 when `grid_mode` is True. See the following
|
||||
visual illustration:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
| pixel 1 | pixel 2 | pixel 3 | pixel 4 | pixel 5 |
|
||||
|<-------------------------------------->|
|
||||
vs.
|
||||
|<----------------------------------------------->|
|
||||
|
||||
The starting point of the arrow in the diagram above corresponds to
|
||||
coordinate location 0 in each mode.
|
||||
|
||||
Returns
|
||||
-------
|
||||
zoom : ndarray
|
||||
The zoomed input.
|
||||
|
||||
Notes
|
||||
-----
|
||||
For complex-valued `input`, this function zooms the real and imaginary
|
||||
components independently.
|
||||
|
||||
.. versionadded:: 1.6.0
|
||||
Complex-valued support added.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from scipy import ndimage, datasets
|
||||
>>> import matplotlib.pyplot as plt
|
||||
|
||||
>>> fig = plt.figure()
|
||||
>>> ax1 = fig.add_subplot(121) # left side
|
||||
>>> ax2 = fig.add_subplot(122) # right side
|
||||
>>> ascent = datasets.ascent()
|
||||
>>> result = ndimage.zoom(ascent, 3.0)
|
||||
>>> ax1.imshow(ascent, vmin=0, vmax=255)
|
||||
>>> ax2.imshow(result, vmin=0, vmax=255)
|
||||
>>> plt.show()
|
||||
|
||||
>>> print(ascent.shape)
|
||||
(512, 512)
|
||||
|
||||
>>> print(result.shape)
|
||||
(1536, 1536)
|
||||
"""
|
||||
if order < 0 or order > 5:
|
||||
raise RuntimeError('spline order not supported')
|
||||
input = np.asarray(input)
|
||||
if input.ndim < 1:
|
||||
raise RuntimeError('input and output rank must be > 0')
|
||||
zoom = _ni_support._normalize_sequence(zoom, input.ndim)
|
||||
output_shape = tuple(
|
||||
[int(round(ii * jj)) for ii, jj in zip(input.shape, zoom)])
|
||||
complex_output = np.iscomplexobj(input)
|
||||
output = _ni_support._get_output(output, input, shape=output_shape,
|
||||
complex_output=complex_output)
|
||||
if complex_output:
|
||||
# import under different name to avoid confusion with zoom parameter
|
||||
from scipy.ndimage._interpolation import zoom as _zoom
|
||||
|
||||
kwargs = dict(order=order, mode=mode, prefilter=prefilter)
|
||||
_zoom(input.real, zoom, output=output.real,
|
||||
cval=np.real(cval), **kwargs)
|
||||
_zoom(input.imag, zoom, output=output.imag,
|
||||
cval=np.imag(cval), **kwargs)
|
||||
return output
|
||||
if prefilter and order > 1:
|
||||
padded, npad = _prepad_for_spline_filter(input, mode, cval)
|
||||
filtered = spline_filter(padded, order, output=np.float64, mode=mode)
|
||||
else:
|
||||
npad = 0
|
||||
filtered = input
|
||||
if grid_mode:
|
||||
# warn about modes that may have surprising behavior
|
||||
suggest_mode = None
|
||||
if mode == 'constant':
|
||||
suggest_mode = 'grid-constant'
|
||||
elif mode == 'wrap':
|
||||
suggest_mode = 'grid-wrap'
|
||||
if suggest_mode is not None:
|
||||
warnings.warn(
|
||||
(f"It is recommended to use mode = {suggest_mode} instead of {mode} "
|
||||
f"when grid_mode is True."),
|
||||
stacklevel=2
|
||||
)
|
||||
mode = _ni_support._extend_mode_to_code(mode)
|
||||
|
||||
zoom_div = np.array(output_shape)
|
||||
zoom_nominator = np.array(input.shape)
|
||||
if not grid_mode:
|
||||
zoom_div -= 1
|
||||
zoom_nominator -= 1
|
||||
|
||||
# Zooming to infinite values is unpredictable, so just choose
|
||||
# zoom factor 1 instead
|
||||
zoom = np.divide(zoom_nominator, zoom_div,
|
||||
out=np.ones_like(input.shape, dtype=np.float64),
|
||||
where=zoom_div != 0)
|
||||
zoom = np.ascontiguousarray(zoom)
|
||||
_nd_image.zoom_shift(filtered, zoom, None, output, order, mode, cval, npad,
|
||||
grid_mode)
|
||||
return output
|
||||
Reference in New Issue
Block a user