Remove deprecated modules and functions from bioxel package
- Deleted _ni_support.py, _utils.py, and dtype.py as they contained unused or redundant functions. - Removed the resize function and related utilities from _warps.py to streamline image processing. - Cleaned up the skimage module by removing unnecessary imports and functions.
This commit is contained in:
@@ -7,8 +7,7 @@ try:
|
||||
except ImportError:
|
||||
vdb = None
|
||||
|
||||
from . import scipy
|
||||
from . import scipy as ndi
|
||||
from scipy import ndimage as ndi
|
||||
|
||||
# 3rd-party
|
||||
import transforms3d
|
||||
@@ -83,21 +82,17 @@ class Layer():
|
||||
for f in range(self.frame_count):
|
||||
mask_frame = mask[f, :, :, :]
|
||||
if smooth > 0:
|
||||
mask_frame = scipy.median_filter(mask_frame.astype(np.float32),
|
||||
mode="nearest",
|
||||
size=smooth)
|
||||
# mask_frame = scipy.median_filter(
|
||||
# mask_frame.astype(np.float32), size=2)
|
||||
mask_frame = ndi.median_filter(mask_frame.astype(np.float32),
|
||||
mode="nearest",
|
||||
size=smooth)
|
||||
mask_frames += (mask_frame,)
|
||||
elif mask.ndim == 3:
|
||||
for f in range(self.frame_count):
|
||||
mask_frame = mask[:, :, :]
|
||||
if smooth > 0:
|
||||
mask_frame = scipy.median_filter(mask_frame.astype(np.float32),
|
||||
mode="nearest",
|
||||
size=smooth)
|
||||
# mask_frame = scipy.median_filter(
|
||||
# mask_frame.astype(np.float32), size=2)
|
||||
mask_frame = ndi.median_filter(mask_frame.astype(np.float32),
|
||||
mode="nearest",
|
||||
size=smooth)
|
||||
mask_frames += (mask_frame,)
|
||||
else:
|
||||
raise Exception("Mask shape order should be TXYZ or XYZ")
|
||||
@@ -127,9 +122,9 @@ class Layer():
|
||||
|
||||
frame = data[f, :, :, :, :]
|
||||
if smooth > 0:
|
||||
frame = scipy.median_filter(frame.astype(np.float32),
|
||||
mode="nearest",
|
||||
size=smooth)
|
||||
frame = ndi.median_filter(frame.astype(np.float32),
|
||||
mode="nearest",
|
||||
size=smooth)
|
||||
|
||||
factors = np.divide(self.shape, shape)
|
||||
zoom_factors = [1 / f for f in factors]
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
from ._interpolation import zoom
|
||||
from ._filters import (gaussian_filter,
|
||||
median_filter,
|
||||
maximum_filter,
|
||||
minimum_filter)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,314 +0,0 @@
|
||||
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
|
||||
@@ -1,120 +0,0 @@
|
||||
# Copyright (C) 2003-2005 Peter J. Verveer
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
#
|
||||
# 3. The name of the author may not be used to endorse or promote
|
||||
# products derived from this software without specific prior
|
||||
# written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
from collections.abc import Iterable
|
||||
import operator
|
||||
import warnings
|
||||
import numpy as np
|
||||
|
||||
|
||||
def _extend_mode_to_code(mode):
|
||||
"""Convert an extension mode to the corresponding integer code.
|
||||
"""
|
||||
if mode == 'nearest':
|
||||
return 0
|
||||
elif mode == 'wrap':
|
||||
return 1
|
||||
elif mode in ['reflect', 'grid-mirror']:
|
||||
return 2
|
||||
elif mode == 'mirror':
|
||||
return 3
|
||||
elif mode == 'constant':
|
||||
return 4
|
||||
elif mode == 'grid-wrap':
|
||||
return 5
|
||||
elif mode == 'grid-constant':
|
||||
return 6
|
||||
else:
|
||||
raise RuntimeError('boundary mode not supported')
|
||||
|
||||
|
||||
def _normalize_sequence(input, rank):
|
||||
"""If input is a scalar, create a sequence of length equal to the
|
||||
rank by duplicating the input. If input is a sequence,
|
||||
check if its length is equal to the length of array.
|
||||
"""
|
||||
is_str = isinstance(input, str)
|
||||
if not is_str and isinstance(input, Iterable):
|
||||
normalized = list(input)
|
||||
if len(normalized) != rank:
|
||||
err = "sequence argument must have length equal to input rank"
|
||||
raise RuntimeError(err)
|
||||
else:
|
||||
normalized = [input] * rank
|
||||
return normalized
|
||||
|
||||
|
||||
def _get_output(output, input, shape=None, complex_output=False):
|
||||
if shape is None:
|
||||
shape = input.shape
|
||||
if output is None:
|
||||
if not complex_output:
|
||||
output = np.zeros(shape, dtype=input.dtype.name)
|
||||
else:
|
||||
complex_type = np.promote_types(input.dtype, np.complex64)
|
||||
output = np.zeros(shape, dtype=complex_type)
|
||||
elif isinstance(output, (type, np.dtype)):
|
||||
# Classes (like `np.float32`) and dtypes are interpreted as dtype
|
||||
if complex_output and np.dtype(output).kind != 'c':
|
||||
warnings.warn(
|
||||
"promoting specified output dtype to complex", stacklevel=3)
|
||||
output = np.promote_types(output, np.complex64)
|
||||
output = np.zeros(shape, dtype=output)
|
||||
elif isinstance(output, str):
|
||||
output = np.dtype(output)
|
||||
if complex_output and output.kind != 'c':
|
||||
raise RuntimeError("output must have complex dtype")
|
||||
elif not issubclass(output.type, np.number):
|
||||
raise RuntimeError("output must have numeric dtype")
|
||||
output = np.zeros(shape, dtype=output)
|
||||
elif output.shape != shape:
|
||||
raise RuntimeError("output shape not correct")
|
||||
elif complex_output and output.dtype.kind != 'c':
|
||||
raise RuntimeError("output must have complex dtype")
|
||||
return output
|
||||
|
||||
|
||||
def _check_axes(axes, ndim):
|
||||
if axes is None:
|
||||
return tuple(range(ndim))
|
||||
elif np.isscalar(axes):
|
||||
axes = (operator.index(axes),)
|
||||
elif isinstance(axes, Iterable):
|
||||
for ax in axes:
|
||||
axes = tuple(operator.index(ax) for ax in axes)
|
||||
if ax < -ndim or ax > ndim - 1:
|
||||
raise ValueError(f"specified axis: {ax} is out of range")
|
||||
axes = tuple(ax % ndim if ax < 0 else ax for ax in axes)
|
||||
else:
|
||||
message = "axes must be an integer, iterable of integers, or None"
|
||||
raise ValueError(message)
|
||||
if len(tuple(set(axes))) != len(axes):
|
||||
raise ValueError("axes must be unique")
|
||||
return axes
|
||||
@@ -1,10 +0,0 @@
|
||||
|
||||
def normalize_axis_index(axis, ndim):
|
||||
# Check if `axis` is in the correct range and normalize it
|
||||
if axis < -ndim or axis >= ndim:
|
||||
msg = f"axis {axis} is out of bounds for array of dimension {ndim}"
|
||||
raise Exception(msg)
|
||||
|
||||
if axis < 0:
|
||||
axis = axis + ndim
|
||||
return axis
|
||||
@@ -1 +0,0 @@
|
||||
from ._warps import resize
|
||||
@@ -1,37 +0,0 @@
|
||||
import numpy as np
|
||||
|
||||
|
||||
def convert_to_float(image, preserve_range):
|
||||
"""Convert input image to float image with the appropriate range.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : ndarray
|
||||
Input image.
|
||||
preserve_range : bool
|
||||
Determines if the range of the image should be kept or transformed
|
||||
using img_as_float. Also see
|
||||
https://scikit-image.org/docs/dev/user_guide/data_types.html
|
||||
|
||||
Notes
|
||||
-----
|
||||
* Input images with `float32` data type are not upcast.
|
||||
|
||||
Returns
|
||||
-------
|
||||
image : ndarray
|
||||
Transformed version of the input.
|
||||
|
||||
"""
|
||||
if image.dtype == np.float16:
|
||||
return image.astype(np.float32)
|
||||
if preserve_range:
|
||||
# Convert image to double only if it is not single or double
|
||||
# precision float
|
||||
if image.dtype.char not in 'df':
|
||||
image = image.astype(float)
|
||||
else:
|
||||
from .dtype import img_as_float
|
||||
|
||||
image = img_as_float(image)
|
||||
return image
|
||||
@@ -1,319 +0,0 @@
|
||||
import warnings
|
||||
import numpy as np
|
||||
from .. import scipy as ndi
|
||||
from ._utils import convert_to_float
|
||||
|
||||
|
||||
def _clip_warp_output(input_image, output_image, mode, cval, clip):
|
||||
"""Clip output image to range of values of input image.
|
||||
|
||||
Note that this function modifies the values of `output_image` in-place
|
||||
and it is only modified if ``clip=True``.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
input_image : ndarray
|
||||
Input image.
|
||||
output_image : ndarray
|
||||
Output image, which is modified in-place.
|
||||
|
||||
Other parameters
|
||||
----------------
|
||||
mode : {'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
|
||||
Used in conjunction with mode 'constant', the value outside
|
||||
the image boundaries.
|
||||
clip : bool
|
||||
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.
|
||||
|
||||
"""
|
||||
if clip:
|
||||
min_val = np.min(input_image)
|
||||
if np.isnan(min_val):
|
||||
# NaNs detected, use NaN-safe min/max
|
||||
min_func = np.nanmin
|
||||
max_func = np.nanmax
|
||||
min_val = min_func(input_image)
|
||||
else:
|
||||
min_func = np.min
|
||||
max_func = np.max
|
||||
max_val = max_func(input_image)
|
||||
|
||||
# Check if cval has been used such that it expands the effective input
|
||||
# range
|
||||
preserve_cval = (
|
||||
mode == 'constant'
|
||||
and not min_val <= cval <= max_val
|
||||
and min_func(output_image) <= cval <= max_func(output_image)
|
||||
)
|
||||
|
||||
# expand min/max range to account for cval
|
||||
if preserve_cval:
|
||||
# cast cval to the same dtype as the input image
|
||||
cval = input_image.dtype.type(cval)
|
||||
min_val = min(min_val, cval)
|
||||
max_val = max(max_val, cval)
|
||||
|
||||
# Convert array-like types to ndarrays (gh-7159)
|
||||
min_val, max_val = np.asarray(min_val), np.asarray(max_val)
|
||||
np.clip(output_image, min_val, max_val, out=output_image)
|
||||
|
||||
|
||||
def _validate_interpolation_order(image_dtype, order):
|
||||
"""Validate and return spline interpolation's order.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image_dtype : dtype
|
||||
Image dtype.
|
||||
order : int, optional
|
||||
The order of the spline interpolation. The order has to be in
|
||||
the range 0-5. See `skimage.transform.warp` for detail.
|
||||
|
||||
Returns
|
||||
-------
|
||||
order : int
|
||||
if input order is None, returns 0 if image_dtype is bool and 1
|
||||
otherwise. Otherwise, image_dtype is checked and input order
|
||||
is validated accordingly (order > 0 is not supported for bool
|
||||
image dtype)
|
||||
|
||||
"""
|
||||
|
||||
if order is None:
|
||||
return 0 if image_dtype == bool else 1
|
||||
|
||||
if order < 0 or order > 5:
|
||||
raise ValueError(
|
||||
"Spline interpolation order has to be in the " "range 0-5.")
|
||||
|
||||
if image_dtype == bool and order != 0:
|
||||
raise ValueError(
|
||||
"Input image dtype is bool. Interpolation is not defined "
|
||||
"with bool data type. Please set order to 0 or explicitly "
|
||||
"cast input image to another data type."
|
||||
)
|
||||
|
||||
return order
|
||||
|
||||
|
||||
def _preprocess_resize_output_shape(image, output_shape):
|
||||
"""Validate resize output shape according to input image.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image: ndarray
|
||||
Image to be resized.
|
||||
output_shape: iterable
|
||||
Size of the generated output image `(rows, cols[, ...][, dim])`. If
|
||||
`dim` is not provided, the number of channels is preserved.
|
||||
|
||||
Returns
|
||||
-------
|
||||
image: ndarray
|
||||
The input image, but with additional singleton dimensions appended in
|
||||
the case where ``len(output_shape) > input.ndim``.
|
||||
output_shape: tuple
|
||||
The output image converted to tuple.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError:
|
||||
If output_shape length is smaller than the image number of
|
||||
dimensions
|
||||
|
||||
Notes
|
||||
-----
|
||||
The input image is reshaped if its number of dimensions is not
|
||||
equal to output_shape_length.
|
||||
|
||||
"""
|
||||
output_shape = tuple(output_shape)
|
||||
output_ndim = len(output_shape)
|
||||
input_shape = image.shape
|
||||
if output_ndim > image.ndim:
|
||||
# append dimensions to input_shape
|
||||
input_shape += (1,) * (output_ndim - image.ndim)
|
||||
image = np.reshape(image, input_shape)
|
||||
elif output_ndim == image.ndim - 1:
|
||||
# multichannel case: append shape of last axis
|
||||
output_shape = output_shape + (image.shape[-1],)
|
||||
elif output_ndim < image.ndim:
|
||||
raise ValueError(
|
||||
"output_shape length cannot be smaller than the "
|
||||
"image number of dimensions"
|
||||
)
|
||||
|
||||
return image, output_shape
|
||||
|
||||
|
||||
def _to_ndimage_mode(mode):
|
||||
"""Convert from `numpy.pad` mode name to the corresponding ndimage mode."""
|
||||
mode_translation_dict = dict(
|
||||
constant='constant',
|
||||
edge='nearest',
|
||||
symmetric='reflect',
|
||||
reflect='mirror',
|
||||
wrap='wrap',
|
||||
)
|
||||
if mode not in mode_translation_dict:
|
||||
raise ValueError(
|
||||
f"Unknown mode: '{mode}', or cannot translate mode. The "
|
||||
f"mode should be one of 'constant', 'edge', 'symmetric', "
|
||||
f"'reflect', or 'wrap'. See the documentation of numpy.pad for "
|
||||
f"more info."
|
||||
)
|
||||
return _fix_ndimage_mode(mode_translation_dict[mode])
|
||||
|
||||
|
||||
def _fix_ndimage_mode(mode):
|
||||
# SciPy 1.6.0 introduced grid variants of constant and wrap which
|
||||
# have less surprising behavior for images. Use these when available
|
||||
grid_modes = {'constant': 'grid-constant', 'wrap': 'grid-wrap'}
|
||||
return grid_modes.get(mode, mode)
|
||||
|
||||
|
||||
def resize(
|
||||
image,
|
||||
output_shape,
|
||||
order=None,
|
||||
mode='reflect',
|
||||
cval=0,
|
||||
clip=True,
|
||||
preserve_range=False,
|
||||
anti_aliasing=None,
|
||||
anti_aliasing_sigma=None,
|
||||
):
|
||||
"""Resize image to match a certain size.
|
||||
|
||||
Performs interpolation to up-size or down-size N-dimensional images. Note
|
||||
that anti-aliasing should be enabled when down-sizing images to avoid
|
||||
aliasing artifacts. For downsampling with an integer factor also see
|
||||
`skimage.transform.downscale_local_mean`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : 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.
|
||||
|
||||
Returns
|
||||
-------
|
||||
resized : ndarray
|
||||
Resized version of the input.
|
||||
|
||||
Other parameters
|
||||
----------------
|
||||
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. See `skimage.transform.warp` for detail.
|
||||
mode : {'constant', 'edge', 'symmetric', 'reflect', 'wrap'}, optional
|
||||
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.
|
||||
preserve_range : bool, optional
|
||||
Whether to keep the original range of values. Otherwise, the input
|
||||
image is converted according to the conventions of `img_as_float`.
|
||||
Also see https://scikit-image.org/docs/dev/user_guide/data_types.html
|
||||
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.
|
||||
It is also set to False when using nearest neighbor interpolation
|
||||
(``order`` == 0) with integer input data type.
|
||||
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.
|
||||
|
||||
Notes
|
||||
-----
|
||||
Modes 'reflect' and 'symmetric' are similar, but differ in whether the edge
|
||||
pixels are duplicated during the reflection. As an example, if an array
|
||||
has values [0, 1, 2] and was padded to the right by four values using
|
||||
symmetric, the result would be [0, 1, 2, 2, 1, 0, 0], while for reflect it
|
||||
would be [0, 1, 2, 1, 0, 1, 2].
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from skimage import data
|
||||
>>> from skimage.transform import resize
|
||||
>>> image = data.camera()
|
||||
>>> resize(image, (100, 100)).shape
|
||||
(100, 100)
|
||||
|
||||
"""
|
||||
|
||||
image, output_shape = _preprocess_resize_output_shape(image, output_shape)
|
||||
input_shape = image.shape
|
||||
input_type = image.dtype
|
||||
|
||||
if input_type == np.float16:
|
||||
image = image.astype(np.float32)
|
||||
|
||||
if anti_aliasing is None:
|
||||
anti_aliasing = (
|
||||
not input_type == bool
|
||||
and not (np.issubdtype(input_type, np.integer) and order == 0)
|
||||
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)
|
||||
order = _validate_interpolation_order(input_type, order)
|
||||
if order > 0:
|
||||
image = convert_to_float(image, preserve_range)
|
||||
|
||||
# Translate modes used by np.pad to those used by scipy.ndimage
|
||||
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"
|
||||
)
|
||||
elif np.any((anti_aliasing_sigma > 0) & (factors <= 1)):
|
||||
warnings.warn(
|
||||
"Anti-aliasing standard deviation greater than zero but "
|
||||
"not down-sampling along all axes",
|
||||
stacklevel=2
|
||||
)
|
||||
filtered = ndi.gaussian_filter(
|
||||
image, anti_aliasing_sigma, cval=cval, mode=ndi_mode
|
||||
)
|
||||
else:
|
||||
filtered = image
|
||||
|
||||
zoom_factors = [1 / f for f in factors]
|
||||
out = ndi.zoom(
|
||||
filtered, zoom_factors, order=order, mode=ndi_mode, cval=cval, grid_mode=True
|
||||
)
|
||||
|
||||
_clip_warp_output(image, out, mode, cval, clip)
|
||||
|
||||
return out
|
||||
@@ -1,605 +0,0 @@
|
||||
import warnings
|
||||
from warnings import warn
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
__all__ = [
|
||||
'img_as_float32',
|
||||
'img_as_float64',
|
||||
'img_as_float',
|
||||
'img_as_int',
|
||||
'img_as_uint',
|
||||
'img_as_ubyte',
|
||||
'img_as_bool',
|
||||
'dtype_limits',
|
||||
]
|
||||
|
||||
# Some of these may or may not be aliases depending on architecture & platform
|
||||
_integer_types = (
|
||||
np.int8,
|
||||
np.byte,
|
||||
np.int16,
|
||||
np.short,
|
||||
np.int32,
|
||||
np.int64,
|
||||
np.longlong,
|
||||
np.int_,
|
||||
np.intp,
|
||||
np.intc,
|
||||
int,
|
||||
np.uint8,
|
||||
np.ubyte,
|
||||
np.uint16,
|
||||
np.ushort,
|
||||
np.uint32,
|
||||
np.uint64,
|
||||
np.ulonglong,
|
||||
np.uint,
|
||||
np.uintp,
|
||||
np.uintc,
|
||||
)
|
||||
_integer_ranges = {t: (np.iinfo(t).min, np.iinfo(t).max)
|
||||
for t in _integer_types}
|
||||
dtype_range = {
|
||||
bool: (False, True),
|
||||
np.bool_: (False, True),
|
||||
float: (-1, 1),
|
||||
np.float16: (-1, 1),
|
||||
np.float32: (-1, 1),
|
||||
np.float64: (-1, 1),
|
||||
}
|
||||
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings('ignore', category=DeprecationWarning)
|
||||
|
||||
# np.bool8 is a deprecated alias of np.bool_
|
||||
if hasattr(np, 'bool8'):
|
||||
dtype_range[np.bool8] = (False, True)
|
||||
|
||||
dtype_range.update(_integer_ranges)
|
||||
|
||||
_supported_types = list(dtype_range.keys())
|
||||
|
||||
|
||||
def dtype_limits(image, clip_negative=False):
|
||||
"""Return intensity limits, i.e. (min, max) tuple, of the image's dtype.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : ndarray
|
||||
Input image.
|
||||
clip_negative : bool, optional
|
||||
If True, clip the negative range (i.e. return 0 for min intensity)
|
||||
even if the image dtype allows negative values.
|
||||
|
||||
Returns
|
||||
-------
|
||||
imin, imax : tuple
|
||||
Lower and upper intensity limits.
|
||||
"""
|
||||
imin, imax = dtype_range[image.dtype.type]
|
||||
if clip_negative:
|
||||
imin = 0
|
||||
return imin, imax
|
||||
|
||||
|
||||
def _dtype_itemsize(itemsize, *dtypes):
|
||||
"""Return first of `dtypes` with itemsize greater than `itemsize`
|
||||
|
||||
Parameters
|
||||
----------
|
||||
itemsize: int
|
||||
The data type object element size.
|
||||
|
||||
Other Parameters
|
||||
----------------
|
||||
*dtypes:
|
||||
Any Object accepted by `np.dtype` to be converted to a data
|
||||
type object
|
||||
|
||||
Returns
|
||||
-------
|
||||
dtype: data type object
|
||||
First of `dtypes` with itemsize greater than `itemsize`.
|
||||
|
||||
"""
|
||||
return next(dt for dt in dtypes if np.dtype(dt).itemsize >= itemsize)
|
||||
|
||||
|
||||
def _dtype_bits(kind, bits, itemsize=1):
|
||||
"""Return dtype of `kind` that can store a `bits` wide unsigned int
|
||||
|
||||
Parameters:
|
||||
kind: str
|
||||
Data type kind.
|
||||
bits: int
|
||||
Desired number of bits.
|
||||
itemsize: int
|
||||
The data type object element size.
|
||||
|
||||
Returns
|
||||
-------
|
||||
dtype: data type object
|
||||
Data type of `kind` that can store a `bits` wide unsigned int
|
||||
|
||||
"""
|
||||
|
||||
s = next(
|
||||
i
|
||||
for i in (itemsize,) + (2, 4, 8)
|
||||
if bits < (i * 8) or (bits == (i * 8) and kind == 'u')
|
||||
)
|
||||
|
||||
return np.dtype(kind + str(s))
|
||||
|
||||
|
||||
def _scale(a, n, m, copy=True):
|
||||
"""Scale an array of unsigned/positive integers from `n` to `m` bits.
|
||||
|
||||
Numbers can be represented exactly only if `m` is a multiple of `n`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
a : ndarray
|
||||
Input image array.
|
||||
n : int
|
||||
Number of bits currently used to encode the values in `a`.
|
||||
m : int
|
||||
Desired number of bits to encode the values in `out`.
|
||||
copy : bool, optional
|
||||
If True, allocates and returns new array. Otherwise, modifies
|
||||
`a` in place.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : array
|
||||
Output image array. Has the same kind as `a`.
|
||||
"""
|
||||
kind = a.dtype.kind
|
||||
if n > m and a.max() < 2**m:
|
||||
mnew = int(np.ceil(m / 2) * 2)
|
||||
if mnew > m:
|
||||
dtype = f'int{mnew}'
|
||||
else:
|
||||
dtype = f'uint{mnew}'
|
||||
n = int(np.ceil(n / 2) * 2)
|
||||
warn(
|
||||
f'Downcasting {a.dtype} to {dtype} without scaling because max '
|
||||
f'value {a.max()} fits in {dtype}',
|
||||
stacklevel=3,
|
||||
)
|
||||
return a.astype(_dtype_bits(kind, m))
|
||||
elif n == m:
|
||||
return a.copy() if copy else a
|
||||
elif n > m:
|
||||
# downscale with precision loss
|
||||
if copy:
|
||||
b = np.empty(a.shape, _dtype_bits(kind, m))
|
||||
np.floor_divide(a, 2 ** (n - m), out=b,
|
||||
dtype=a.dtype, casting='unsafe')
|
||||
return b
|
||||
else:
|
||||
a //= 2 ** (n - m)
|
||||
return a
|
||||
elif m % n == 0:
|
||||
# exact upscale to a multiple of `n` bits
|
||||
if copy:
|
||||
b = np.empty(a.shape, _dtype_bits(kind, m))
|
||||
np.multiply(a, (2**m - 1) // (2**n - 1), out=b, dtype=b.dtype)
|
||||
return b
|
||||
else:
|
||||
a = a.astype(_dtype_bits(kind, m, a.dtype.itemsize), copy=False)
|
||||
a *= (2**m - 1) // (2**n - 1)
|
||||
return a
|
||||
else:
|
||||
# upscale to a multiple of `n` bits,
|
||||
# then downscale with precision loss
|
||||
o = (m // n + 1) * n
|
||||
if copy:
|
||||
b = np.empty(a.shape, _dtype_bits(kind, o))
|
||||
np.multiply(a, (2**o - 1) // (2**n - 1), out=b, dtype=b.dtype)
|
||||
b //= 2 ** (o - m)
|
||||
return b
|
||||
else:
|
||||
a = a.astype(_dtype_bits(kind, o, a.dtype.itemsize), copy=False)
|
||||
a *= (2**o - 1) // (2**n - 1)
|
||||
a //= 2 ** (o - m)
|
||||
return a
|
||||
|
||||
|
||||
def _convert(image, dtype, force_copy=False, uniform=False):
|
||||
"""
|
||||
Convert an image to the requested data-type.
|
||||
|
||||
Warnings are issued in case of precision loss, or when negative values
|
||||
are clipped during conversion to unsigned integer types (sign loss).
|
||||
|
||||
Floating point values are expected to be normalized and will be clipped
|
||||
to the range [0.0, 1.0] or [-1.0, 1.0] when converting to unsigned or
|
||||
signed integers respectively.
|
||||
|
||||
Numbers are not shifted to the negative side when converting from
|
||||
unsigned to signed integer types. Negative values will be clipped when
|
||||
converting to unsigned integers.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : ndarray
|
||||
Input image.
|
||||
dtype : dtype
|
||||
Target data-type.
|
||||
force_copy : bool, optional
|
||||
Force a copy of the data, irrespective of its current dtype.
|
||||
uniform : bool, optional
|
||||
Uniformly quantize the floating point range to the integer range.
|
||||
By default (uniform=False) floating point values are scaled and
|
||||
rounded to the nearest integers, which minimizes back and forth
|
||||
conversion errors.
|
||||
|
||||
.. versionchanged:: 0.15
|
||||
``_convert`` no longer warns about possible precision or sign
|
||||
information loss. See discussions on these warnings at:
|
||||
https://github.com/scikit-image/scikit-image/issues/2602
|
||||
https://github.com/scikit-image/scikit-image/issues/543#issuecomment-208202228
|
||||
https://github.com/scikit-image/scikit-image/pull/3575
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] DirectX data conversion rules.
|
||||
https://msdn.microsoft.com/en-us/library/windows/desktop/dd607323%28v=vs.85%29.aspx
|
||||
.. [2] Data Conversions. In "OpenGL ES 2.0 Specification v2.0.25",
|
||||
pp 7-8. Khronos Group, 2010.
|
||||
.. [3] Proper treatment of pixels as integers. A.W. Paeth.
|
||||
In "Graphics Gems I", pp 249-256. Morgan Kaufmann, 1990.
|
||||
.. [4] Dirty Pixels. J. Blinn. In "Jim Blinn's corner: Dirty Pixels",
|
||||
pp 47-57. Morgan Kaufmann, 1998.
|
||||
|
||||
"""
|
||||
image = np.asarray(image)
|
||||
dtypeobj_in = image.dtype
|
||||
if dtype is np.floating:
|
||||
dtypeobj_out = np.dtype('float64')
|
||||
else:
|
||||
dtypeobj_out = np.dtype(dtype)
|
||||
dtype_in = dtypeobj_in.type
|
||||
dtype_out = dtypeobj_out.type
|
||||
kind_in = dtypeobj_in.kind
|
||||
kind_out = dtypeobj_out.kind
|
||||
itemsize_in = dtypeobj_in.itemsize
|
||||
itemsize_out = dtypeobj_out.itemsize
|
||||
|
||||
# Below, we do an `issubdtype` check. Its purpose is to find out
|
||||
# whether we can get away without doing any image conversion. This happens
|
||||
# when:
|
||||
#
|
||||
# - the output and input dtypes are the same or
|
||||
# - when the output is specified as a type, and the input dtype
|
||||
# is a subclass of that type (e.g. `np.floating` will allow
|
||||
# `float32` and `float64` arrays through)
|
||||
|
||||
if np.issubdtype(dtype_in, dtype):
|
||||
if force_copy:
|
||||
image = image.copy()
|
||||
return image
|
||||
|
||||
if not (dtype_in in _supported_types and dtype_out in _supported_types):
|
||||
raise ValueError(
|
||||
f'Cannot convert from {dtypeobj_in} to ' f'{dtypeobj_out}.')
|
||||
|
||||
if kind_in in 'ui':
|
||||
imin_in = np.iinfo(dtype_in).min
|
||||
imax_in = np.iinfo(dtype_in).max
|
||||
if kind_out in 'ui':
|
||||
imin_out = np.iinfo(dtype_out).min
|
||||
imax_out = np.iinfo(dtype_out).max
|
||||
|
||||
# any -> binary
|
||||
if kind_out == 'b':
|
||||
return image > dtype_in(dtype_range[dtype_in][1] / 2)
|
||||
|
||||
# binary -> any
|
||||
if kind_in == 'b':
|
||||
result = image.astype(dtype_out)
|
||||
if kind_out != 'f':
|
||||
result *= dtype_out(dtype_range[dtype_out][1])
|
||||
return result
|
||||
|
||||
# float -> any
|
||||
if kind_in == 'f':
|
||||
if kind_out == 'f':
|
||||
# float -> float
|
||||
return image.astype(dtype_out)
|
||||
|
||||
if np.min(image) < -1.0 or np.max(image) > 1.0:
|
||||
raise ValueError("Images of type float must be between -1 and 1.")
|
||||
# floating point -> integer
|
||||
# use float type that can represent output integer type
|
||||
computation_type = _dtype_itemsize(
|
||||
itemsize_out, dtype_in, np.float32, np.float64
|
||||
)
|
||||
|
||||
if not uniform:
|
||||
if kind_out == 'u':
|
||||
image_out = np.multiply(
|
||||
image, imax_out, dtype=computation_type)
|
||||
else:
|
||||
image_out = np.multiply(
|
||||
image, (imax_out - imin_out) / 2, dtype=computation_type
|
||||
)
|
||||
image_out -= 1.0 / 2.0
|
||||
np.rint(image_out, out=image_out)
|
||||
np.clip(image_out, imin_out, imax_out, out=image_out)
|
||||
elif kind_out == 'u':
|
||||
image_out = np.multiply(
|
||||
image, imax_out + 1, dtype=computation_type)
|
||||
np.clip(image_out, 0, imax_out, out=image_out)
|
||||
else:
|
||||
image_out = np.multiply(
|
||||
image, (imax_out - imin_out + 1.0) / 2.0, dtype=computation_type
|
||||
)
|
||||
np.floor(image_out, out=image_out)
|
||||
np.clip(image_out, imin_out, imax_out, out=image_out)
|
||||
return image_out.astype(dtype_out)
|
||||
|
||||
# signed/unsigned int -> float
|
||||
if kind_out == 'f':
|
||||
# use float type that can exactly represent input integers
|
||||
computation_type = _dtype_itemsize(
|
||||
itemsize_in, dtype_out, np.float32, np.float64
|
||||
)
|
||||
|
||||
if kind_in == 'u':
|
||||
# using np.divide or np.multiply doesn't copy the data
|
||||
# until the computation time
|
||||
image = np.multiply(image, 1.0 / imax_in, dtype=computation_type)
|
||||
# DirectX uses this conversion also for signed ints
|
||||
# if imin_in:
|
||||
# np.maximum(image, -1.0, out=image)
|
||||
elif kind_in == 'i':
|
||||
# From DirectX conversions:
|
||||
# The most negative value maps to -1.0f
|
||||
# Every other value is converted to a float (call it c)
|
||||
# and then result = c * (1.0f / (2⁽ⁿ⁻¹⁾-1)).
|
||||
|
||||
image = np.multiply(image, 1.0 / imax_in, dtype=computation_type)
|
||||
np.maximum(image, -1.0, out=image)
|
||||
|
||||
else:
|
||||
image = np.add(image, 0.5, dtype=computation_type)
|
||||
image *= 2 / (imax_in - imin_in)
|
||||
|
||||
return np.asarray(image, dtype_out)
|
||||
|
||||
# unsigned int -> signed/unsigned int
|
||||
if kind_in == 'u':
|
||||
if kind_out == 'i':
|
||||
# unsigned int -> signed int
|
||||
image = _scale(image, 8 * itemsize_in, 8 * itemsize_out - 1)
|
||||
return image.view(dtype_out)
|
||||
else:
|
||||
# unsigned int -> unsigned int
|
||||
return _scale(image, 8 * itemsize_in, 8 * itemsize_out)
|
||||
|
||||
# signed int -> unsigned int
|
||||
if kind_out == 'u':
|
||||
image = _scale(image, 8 * itemsize_in - 1, 8 * itemsize_out)
|
||||
result = np.empty(image.shape, dtype_out)
|
||||
np.maximum(image, 0, out=result, dtype=image.dtype, casting='unsafe')
|
||||
return result
|
||||
|
||||
# signed int -> signed int
|
||||
if itemsize_in > itemsize_out:
|
||||
return _scale(image, 8 * itemsize_in - 1, 8 * itemsize_out - 1)
|
||||
|
||||
image = image.astype(_dtype_bits('i', itemsize_out * 8))
|
||||
image -= imin_in
|
||||
image = _scale(image, 8 * itemsize_in, 8 * itemsize_out, copy=False)
|
||||
image += imin_out
|
||||
return image.astype(dtype_out)
|
||||
|
||||
|
||||
def convert(image, dtype, force_copy=False, uniform=False):
|
||||
warn(
|
||||
"The use of this function is discouraged as its behavior may change "
|
||||
"dramatically in scikit-image 1.0. This function will be removed "
|
||||
"in scikit-image 1.0.",
|
||||
FutureWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return _convert(image=image, dtype=dtype, force_copy=force_copy, uniform=uniform)
|
||||
|
||||
|
||||
if _convert.__doc__ is not None:
|
||||
convert.__doc__ = (
|
||||
_convert.__doc__
|
||||
+ """
|
||||
|
||||
Warns
|
||||
-----
|
||||
FutureWarning:
|
||||
.. versionadded:: 0.17
|
||||
|
||||
The use of this function is discouraged as its behavior may change
|
||||
dramatically in scikit-image 1.0. This function will be removed
|
||||
in scikit-image 1.0.
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def img_as_float32(image, force_copy=False):
|
||||
"""Convert an image to single-precision (32-bit) floating point format.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : ndarray
|
||||
Input image.
|
||||
force_copy : bool, optional
|
||||
Force a copy of the data, irrespective of its current dtype.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray of float32
|
||||
Output image.
|
||||
|
||||
Notes
|
||||
-----
|
||||
The range of a floating point image is [0.0, 1.0] or [-1.0, 1.0] when
|
||||
converting from unsigned or signed datatypes, respectively.
|
||||
If the input image has a float type, intensity values are not modified
|
||||
and can be outside the ranges [0.0, 1.0] or [-1.0, 1.0].
|
||||
|
||||
"""
|
||||
return _convert(image, np.float32, force_copy)
|
||||
|
||||
|
||||
def img_as_float64(image, force_copy=False):
|
||||
"""Convert an image to double-precision (64-bit) floating point format.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : ndarray
|
||||
Input image.
|
||||
force_copy : bool, optional
|
||||
Force a copy of the data, irrespective of its current dtype.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray of float64
|
||||
Output image.
|
||||
|
||||
Notes
|
||||
-----
|
||||
The range of a floating point image is [0.0, 1.0] or [-1.0, 1.0] when
|
||||
converting from unsigned or signed datatypes, respectively.
|
||||
If the input image has a float type, intensity values are not modified
|
||||
and can be outside the ranges [0.0, 1.0] or [-1.0, 1.0].
|
||||
|
||||
"""
|
||||
return _convert(image, np.float64, force_copy)
|
||||
|
||||
|
||||
def img_as_float(image, force_copy=False):
|
||||
"""Convert an image to floating point format.
|
||||
|
||||
This function is similar to `img_as_float64`, but will not convert
|
||||
lower-precision floating point arrays to `float64`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : ndarray
|
||||
Input image.
|
||||
force_copy : bool, optional
|
||||
Force a copy of the data, irrespective of its current dtype.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray of float
|
||||
Output image.
|
||||
|
||||
Notes
|
||||
-----
|
||||
The range of a floating point image is [0.0, 1.0] or [-1.0, 1.0] when
|
||||
converting from unsigned or signed datatypes, respectively.
|
||||
If the input image has a float type, intensity values are not modified
|
||||
and can be outside the ranges [0.0, 1.0] or [-1.0, 1.0].
|
||||
|
||||
"""
|
||||
return _convert(image, np.floating, force_copy)
|
||||
|
||||
|
||||
def img_as_uint(image, force_copy=False):
|
||||
"""Convert an image to 16-bit unsigned integer format.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : ndarray
|
||||
Input image.
|
||||
force_copy : bool, optional
|
||||
Force a copy of the data, irrespective of its current dtype.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray of uint16
|
||||
Output image.
|
||||
|
||||
Notes
|
||||
-----
|
||||
Negative input values will be clipped.
|
||||
Positive values are scaled between 0 and 65535.
|
||||
|
||||
"""
|
||||
return _convert(image, np.uint16, force_copy)
|
||||
|
||||
|
||||
def img_as_int(image, force_copy=False):
|
||||
"""Convert an image to 16-bit signed integer format.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : ndarray
|
||||
Input image.
|
||||
force_copy : bool, optional
|
||||
Force a copy of the data, irrespective of its current dtype.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray of int16
|
||||
Output image.
|
||||
|
||||
Notes
|
||||
-----
|
||||
The values are scaled between -32768 and 32767.
|
||||
If the input data-type is positive-only (e.g., uint8), then
|
||||
the output image will still only have positive values.
|
||||
|
||||
"""
|
||||
return _convert(image, np.int16, force_copy)
|
||||
|
||||
|
||||
def img_as_ubyte(image, force_copy=False):
|
||||
"""Convert an image to 8-bit unsigned integer format.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : ndarray
|
||||
Input image.
|
||||
force_copy : bool, optional
|
||||
Force a copy of the data, irrespective of its current dtype.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray of ubyte (uint8)
|
||||
Output image.
|
||||
|
||||
Notes
|
||||
-----
|
||||
Negative input values will be clipped.
|
||||
Positive values are scaled between 0 and 255.
|
||||
|
||||
"""
|
||||
return _convert(image, np.uint8, force_copy)
|
||||
|
||||
|
||||
def img_as_bool(image, force_copy=False):
|
||||
"""Convert an image to boolean format.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : ndarray
|
||||
Input image.
|
||||
force_copy : bool, optional
|
||||
Force a copy of the data, irrespective of its current dtype.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray of bool (`bool_`)
|
||||
Output image.
|
||||
|
||||
Notes
|
||||
-----
|
||||
The upper half of the input dtype's positive range is True, and the lower
|
||||
half is False. All negative values (if present) are False.
|
||||
|
||||
"""
|
||||
return _convert(image, bool, force_copy)
|
||||
Reference in New Issue
Block a user