update
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,3 +0,0 @@
|
||||
[fits]
|
||||
description = FITS image reading via PyFITS
|
||||
provides = imread, imread_collection
|
||||
@@ -1,137 +0,0 @@
|
||||
__all__ = ['imread', 'imread_collection']
|
||||
|
||||
import skimage.io as io
|
||||
|
||||
try:
|
||||
from astropy.io import fits
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"Astropy could not be found. It is needed to read FITS files.\n"
|
||||
"Please refer to https://www.astropy.org for installation\n"
|
||||
"instructions.")
|
||||
|
||||
|
||||
def imread(fname):
|
||||
"""Load an image from a FITS file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fname : string
|
||||
Image file name, e.g. ``test.fits``.
|
||||
|
||||
Returns
|
||||
-------
|
||||
img_array : ndarray
|
||||
Unlike plugins such as PIL, where different color bands/channels are
|
||||
stored in the third dimension, FITS images are grayscale-only and can
|
||||
be N-dimensional, so an array of the native FITS dimensionality is
|
||||
returned, without color channels.
|
||||
|
||||
Currently if no image is found in the file, None will be returned
|
||||
|
||||
Notes
|
||||
-----
|
||||
Currently FITS ``imread()`` always returns the first image extension when
|
||||
given a Multi-Extension FITS file; use ``imread_collection()`` (which does
|
||||
lazy loading) to get all the extensions at once.
|
||||
|
||||
"""
|
||||
|
||||
with fits.open(fname) as hdulist:
|
||||
# Iterate over FITS image extensions, ignoring any other extension types
|
||||
# such as binary tables, and get the first image data array:
|
||||
img_array = None
|
||||
for hdu in hdulist:
|
||||
if isinstance(hdu, fits.ImageHDU) or \
|
||||
isinstance(hdu, fits.PrimaryHDU):
|
||||
if hdu.data is not None:
|
||||
img_array = hdu.data
|
||||
break
|
||||
|
||||
return img_array
|
||||
|
||||
|
||||
def imread_collection(load_pattern, conserve_memory=True):
|
||||
"""Load a collection of images from one or more FITS files
|
||||
|
||||
Parameters
|
||||
----------
|
||||
load_pattern : str or list
|
||||
List of extensions to load. Filename globbing is currently
|
||||
unsupported.
|
||||
conserve_memory : bool
|
||||
If True, never keep more than one in memory at a specific
|
||||
time. Otherwise, images will be cached once they are loaded.
|
||||
|
||||
Returns
|
||||
-------
|
||||
ic : ImageCollection
|
||||
Collection of images.
|
||||
|
||||
"""
|
||||
|
||||
intype = type(load_pattern)
|
||||
if intype is not list and intype is not str:
|
||||
raise TypeError("Input must be a filename or list of filenames")
|
||||
|
||||
# Ensure we have a list, otherwise we'll end up iterating over the string:
|
||||
if intype is not list:
|
||||
load_pattern = [load_pattern]
|
||||
|
||||
# Generate a list of filename/extension pairs by opening the list of
|
||||
# files and finding the image extensions in each one:
|
||||
ext_list = []
|
||||
for filename in load_pattern:
|
||||
with fits.open(filename) as hdulist:
|
||||
for n, hdu in zip(range(len(hdulist)), hdulist):
|
||||
if isinstance(hdu, fits.ImageHDU) or \
|
||||
isinstance(hdu, fits.PrimaryHDU):
|
||||
# Ignore (primary) header units with no data (use '.size'
|
||||
# rather than '.data' to avoid actually loading the image):
|
||||
try:
|
||||
data_size = hdu.size # size is int in Astropy 3.1.2
|
||||
except TypeError:
|
||||
data_size = hdu.size()
|
||||
if data_size > 0:
|
||||
ext_list.append((filename, n))
|
||||
|
||||
return io.ImageCollection(ext_list, load_func=FITSFactory,
|
||||
conserve_memory=conserve_memory)
|
||||
|
||||
|
||||
def FITSFactory(image_ext):
|
||||
"""Load an image extension from a FITS file and return a NumPy array
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image_ext : tuple
|
||||
FITS extension to load, in the format ``(filename, ext_num)``.
|
||||
The FITS ``(extname, extver)`` format is unsupported, since this
|
||||
function is not called directly by the user and
|
||||
``imread_collection()`` does the work of figuring out which
|
||||
extensions need loading.
|
||||
|
||||
"""
|
||||
|
||||
# Expect a length-2 tuple with a filename as the first element:
|
||||
if not isinstance(image_ext, tuple):
|
||||
raise TypeError("Expected a tuple")
|
||||
|
||||
if len(image_ext) != 2:
|
||||
raise ValueError("Expected a tuple of length 2")
|
||||
|
||||
filename = image_ext[0]
|
||||
extnum = image_ext[1]
|
||||
|
||||
if type(filename) is not str or type(extnum) is not int:
|
||||
raise ValueError("Expected a (filename, extension) tuple")
|
||||
|
||||
with fits.open(filename) as hdulist:
|
||||
data = hdulist[extnum].data
|
||||
|
||||
if data is None:
|
||||
raise RuntimeError(
|
||||
f"Extension {extnum} of {filename} has no data"
|
||||
)
|
||||
|
||||
return data
|
||||
@@ -1,3 +0,0 @@
|
||||
[gdal]
|
||||
description = Image reading via the GDAL Library (www.gdal.org)
|
||||
provides = imread
|
||||
@@ -1,16 +0,0 @@
|
||||
__all__ = ['imread']
|
||||
|
||||
try:
|
||||
import osgeo.gdal as gdal
|
||||
except ImportError:
|
||||
raise ImportError("The GDAL Library could not be found. "
|
||||
"Please refer to http://www.gdal.org/ "
|
||||
"for further instructions.")
|
||||
|
||||
|
||||
def imread(fname):
|
||||
"""Load an image from file.
|
||||
"""
|
||||
ds = gdal.Open(fname)
|
||||
|
||||
return ds.ReadAsArray()
|
||||
@@ -1,3 +0,0 @@
|
||||
[imageio]
|
||||
description = Image reading via the ImageIO Library
|
||||
provides = imread, imsave
|
||||
@@ -1,15 +0,0 @@
|
||||
__all__ = ['imread', 'imsave']
|
||||
|
||||
from functools import wraps
|
||||
import numpy as np
|
||||
|
||||
try:
|
||||
# Try using the v2 API directly to avoid a warning from imageio >= 2.16.2
|
||||
from imageio.v2 import imread as imageio_imread, imsave
|
||||
except ImportError:
|
||||
from imageio import imread as imageio_imread, imsave
|
||||
|
||||
|
||||
@wraps(imageio_imread)
|
||||
def imread(*args, **kwargs):
|
||||
return np.asarray(imageio_imread(*args, **kwargs))
|
||||
@@ -1,3 +0,0 @@
|
||||
[imread]
|
||||
description = Image reading and writing via imread
|
||||
provides = imread, imsave
|
||||
@@ -1,44 +0,0 @@
|
||||
__all__ = ['imread', 'imsave']
|
||||
|
||||
from ...util.dtype import _convert
|
||||
|
||||
try:
|
||||
import imread as _imread
|
||||
except ImportError:
|
||||
raise ImportError("Imread could not be found"
|
||||
"Please refer to http://pypi.python.org/pypi/imread/ "
|
||||
"for further instructions.")
|
||||
|
||||
|
||||
def imread(fname, dtype=None):
|
||||
"""Load an image from file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fname : str
|
||||
Name of input file
|
||||
|
||||
"""
|
||||
im = _imread.imread(fname)
|
||||
if dtype is not None:
|
||||
im = _convert(im, dtype)
|
||||
return im
|
||||
|
||||
|
||||
def imsave(fname, arr, format_str=None):
|
||||
"""Save an image to disk.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fname : str
|
||||
Name of destination file.
|
||||
arr : ndarray of uint8 or uint16
|
||||
Array (image) to save.
|
||||
format_str : str,optional
|
||||
Format to save as.
|
||||
|
||||
Notes
|
||||
-----
|
||||
Currently, only 8-bit precision is supported.
|
||||
"""
|
||||
return _imread.imsave(fname, arr, formatstr=format_str)
|
||||
@@ -1,3 +0,0 @@
|
||||
[matplotlib]
|
||||
description = Display or save images using Matplotlib
|
||||
provides = imshow, imread, imshow_collection, _app_show
|
||||
@@ -1,209 +0,0 @@
|
||||
from collections import namedtuple
|
||||
import numpy as np
|
||||
from ...util import dtype as dtypes
|
||||
from ...exposure import is_low_contrast
|
||||
from ..._shared.utils import warn
|
||||
from math import floor, ceil
|
||||
|
||||
|
||||
_default_colormap = 'gray'
|
||||
_nonstandard_colormap = 'viridis'
|
||||
_diverging_colormap = 'RdBu'
|
||||
|
||||
|
||||
ImageProperties = namedtuple('ImageProperties',
|
||||
['signed', 'out_of_range_float',
|
||||
'low_data_range', 'unsupported_dtype'])
|
||||
|
||||
|
||||
def _get_image_properties(image):
|
||||
"""Determine nonstandard properties of an input image.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : array
|
||||
The input image.
|
||||
|
||||
Returns
|
||||
-------
|
||||
ip : ImageProperties named tuple
|
||||
The properties of the image:
|
||||
|
||||
- signed: whether the image has negative values.
|
||||
- out_of_range_float: if the image has floating point data
|
||||
outside of [-1, 1].
|
||||
- low_data_range: if the image is in the standard image
|
||||
range (e.g. [0, 1] for a floating point image) but its
|
||||
data range would be too small to display with standard
|
||||
image ranges.
|
||||
- unsupported_dtype: if the image data type is not a
|
||||
standard skimage type, e.g. ``numpy.uint64``.
|
||||
"""
|
||||
immin, immax = np.min(image), np.max(image)
|
||||
imtype = image.dtype.type
|
||||
try:
|
||||
lo, hi = dtypes.dtype_range[imtype]
|
||||
except KeyError:
|
||||
lo, hi = immin, immax
|
||||
|
||||
signed = immin < 0
|
||||
out_of_range_float = (np.issubdtype(image.dtype, np.floating) and
|
||||
(immin < lo or immax > hi))
|
||||
low_data_range = (immin != immax and
|
||||
is_low_contrast(image))
|
||||
unsupported_dtype = image.dtype not in dtypes._supported_types
|
||||
|
||||
return ImageProperties(signed, out_of_range_float,
|
||||
low_data_range, unsupported_dtype)
|
||||
|
||||
|
||||
def _raise_warnings(image_properties):
|
||||
"""Raise the appropriate warning for each nonstandard image type.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image_properties : ImageProperties named tuple
|
||||
The properties of the considered image.
|
||||
"""
|
||||
ip = image_properties
|
||||
if ip.unsupported_dtype:
|
||||
warn("Non-standard image type; displaying image with "
|
||||
"stretched contrast.", stacklevel=3)
|
||||
if ip.low_data_range:
|
||||
warn("Low image data range; displaying image with "
|
||||
"stretched contrast.", stacklevel=3)
|
||||
if ip.out_of_range_float:
|
||||
warn("Float image out of standard range; displaying "
|
||||
"image with stretched contrast.", stacklevel=3)
|
||||
|
||||
|
||||
def _get_display_range(image):
|
||||
"""Return the display range for a given set of image properties.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : array
|
||||
The input image.
|
||||
|
||||
Returns
|
||||
-------
|
||||
lo, hi : same type as immin, immax
|
||||
The display range to be used for the input image.
|
||||
cmap : string
|
||||
The name of the colormap to use.
|
||||
"""
|
||||
ip = _get_image_properties(image)
|
||||
immin, immax = np.min(image), np.max(image)
|
||||
if ip.signed:
|
||||
magnitude = max(abs(immin), abs(immax))
|
||||
lo, hi = -magnitude, magnitude
|
||||
cmap = _diverging_colormap
|
||||
elif any(ip):
|
||||
_raise_warnings(ip)
|
||||
lo, hi = immin, immax
|
||||
cmap = _nonstandard_colormap
|
||||
else:
|
||||
lo = 0
|
||||
imtype = image.dtype.type
|
||||
hi = dtypes.dtype_range[imtype][1]
|
||||
cmap = _default_colormap
|
||||
return lo, hi, cmap
|
||||
|
||||
|
||||
def imshow(image, ax=None, show_cbar=None, **kwargs):
|
||||
"""Show the input image and return the current axes.
|
||||
|
||||
By default, the image is displayed in grayscale, rather than
|
||||
the matplotlib default colormap.
|
||||
|
||||
Images are assumed to have standard range for their type. For
|
||||
example, if a floating point image has values in [0, 0.5], the
|
||||
most intense color will be gray50, not white.
|
||||
|
||||
If the image exceeds the standard range, or if the range is too
|
||||
small to display, we fall back on displaying exactly the range of
|
||||
the input image, along with a colorbar to clearly indicate that
|
||||
this range transformation has occurred.
|
||||
|
||||
For signed images, we use a diverging colormap centered at 0.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : array, shape (M, N[, 3])
|
||||
The image to display.
|
||||
ax : `matplotlib.axes.Axes`, optional
|
||||
The axis to use for the image, defaults to plt.gca().
|
||||
show_cbar : boolean, optional.
|
||||
Whether to show the colorbar (used to override default behavior).
|
||||
**kwargs : Keyword arguments
|
||||
These are passed directly to `matplotlib.pyplot.imshow`.
|
||||
|
||||
Returns
|
||||
-------
|
||||
ax_im : `matplotlib.pyplot.AxesImage`
|
||||
The `AxesImage` object returned by `plt.imshow`.
|
||||
"""
|
||||
import matplotlib.pyplot as plt
|
||||
from mpl_toolkits.axes_grid1 import make_axes_locatable
|
||||
|
||||
lo, hi, cmap = _get_display_range(image)
|
||||
|
||||
kwargs.setdefault('interpolation', 'nearest')
|
||||
kwargs.setdefault('cmap', cmap)
|
||||
kwargs.setdefault('vmin', lo)
|
||||
kwargs.setdefault('vmax', hi)
|
||||
|
||||
ax = ax or plt.gca()
|
||||
ax_im = ax.imshow(image, **kwargs)
|
||||
if (cmap != _default_colormap and show_cbar is not False) or show_cbar:
|
||||
divider = make_axes_locatable(ax)
|
||||
cax = divider.append_axes("right", size="5%", pad=0.05)
|
||||
plt.colorbar(ax_im, cax=cax)
|
||||
ax.get_figure().tight_layout()
|
||||
|
||||
return ax_im
|
||||
|
||||
|
||||
def imshow_collection(ic, *args, **kwargs):
|
||||
"""Display all images in the collection.
|
||||
|
||||
Returns
|
||||
-------
|
||||
fig : `matplotlib.figure.Figure`
|
||||
The `Figure` object returned by `plt.subplots`.
|
||||
"""
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
if len(ic) < 1:
|
||||
raise ValueError('Number of images to plot must be greater than 0')
|
||||
|
||||
# The target is to plot images on a grid with aspect ratio 4:3
|
||||
num_images = len(ic)
|
||||
# Two pairs of `nrows, ncols` are possible
|
||||
k = (num_images * 12)**0.5
|
||||
r1 = max(1, floor(k / 4))
|
||||
r2 = ceil(k / 4)
|
||||
c1 = ceil(num_images / r1)
|
||||
c2 = ceil(num_images / r2)
|
||||
# Select the one which is closer to 4:3
|
||||
if abs(r1 / c1 - 0.75) < abs(r2 / c2 - 0.75):
|
||||
nrows, ncols = r1, c1
|
||||
else:
|
||||
nrows, ncols = r2, c2
|
||||
|
||||
fig, axes = plt.subplots(nrows=nrows, ncols=ncols)
|
||||
ax = np.asarray(axes).ravel()
|
||||
for n, image in enumerate(ic):
|
||||
ax[n].imshow(image, *args, **kwargs)
|
||||
kwargs['ax'] = axes
|
||||
return fig
|
||||
|
||||
|
||||
def imread(*args, **kwargs):
|
||||
import matplotlib.image
|
||||
return matplotlib.image.imread(*args, **kwargs)
|
||||
|
||||
|
||||
def _app_show():
|
||||
from matplotlib.pyplot import show
|
||||
show()
|
||||
@@ -1,3 +0,0 @@
|
||||
[pil]
|
||||
description = Image reading via the Python Imaging Library
|
||||
provides = imread, imsave
|
||||
@@ -1,260 +0,0 @@
|
||||
__all__ = ['imread', 'imsave']
|
||||
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
from ...util import img_as_ubyte, img_as_uint
|
||||
|
||||
|
||||
def imread(fname, dtype=None, img_num=None, **kwargs):
|
||||
"""Load an image from file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fname : str or file
|
||||
File name or file-like-object.
|
||||
dtype : numpy dtype object or string specifier
|
||||
Specifies data type of array elements.
|
||||
img_num : int, optional
|
||||
Specifies which image to read in a file with multiple images
|
||||
(zero-indexed).
|
||||
kwargs : keyword pairs, optional
|
||||
Addition keyword arguments to pass through.
|
||||
|
||||
Notes
|
||||
-----
|
||||
Files are read using the Python Imaging Library.
|
||||
See PIL docs [1]_ for a list of supported formats.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] http://pillow.readthedocs.org/en/latest/handbook/image-file-formats.html
|
||||
"""
|
||||
if isinstance(fname, str):
|
||||
with open(fname, 'rb') as f:
|
||||
im = Image.open(f)
|
||||
return pil_to_ndarray(im, dtype=dtype, img_num=img_num)
|
||||
else:
|
||||
im = Image.open(fname)
|
||||
return pil_to_ndarray(im, dtype=dtype, img_num=img_num)
|
||||
|
||||
|
||||
def pil_to_ndarray(image, dtype=None, img_num=None):
|
||||
"""Import a PIL Image object to an ndarray, in memory.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
Refer to ``imread``.
|
||||
|
||||
"""
|
||||
try:
|
||||
# this will raise an IOError if the file is not readable
|
||||
image.getdata()[0]
|
||||
except OSError as e:
|
||||
site = "http://pillow.readthedocs.org/en/latest/installation.html#external-libraries"
|
||||
pillow_error_message = str(e)
|
||||
error_message = (f"Could not load '{image.filename}' \n"
|
||||
f"Reason: '{pillow_error_message}'\n"
|
||||
f"Please see documentation at: {site}")
|
||||
raise ValueError(error_message)
|
||||
frames = []
|
||||
grayscale = None
|
||||
i = 0
|
||||
while 1:
|
||||
try:
|
||||
image.seek(i)
|
||||
except EOFError:
|
||||
break
|
||||
|
||||
frame = image
|
||||
|
||||
if img_num is not None and img_num != i:
|
||||
image.getdata()[0]
|
||||
i += 1
|
||||
continue
|
||||
|
||||
if image.format == 'PNG' and image.mode == 'I' and dtype is None:
|
||||
dtype = 'uint16'
|
||||
|
||||
if image.mode == 'P':
|
||||
if grayscale is None:
|
||||
grayscale = _palette_is_grayscale(image)
|
||||
|
||||
if grayscale:
|
||||
frame = image.convert('L')
|
||||
else:
|
||||
if image.format == 'PNG' and 'transparency' in image.info:
|
||||
frame = image.convert('RGBA')
|
||||
else:
|
||||
frame = image.convert('RGB')
|
||||
|
||||
elif image.mode == '1':
|
||||
frame = image.convert('L')
|
||||
|
||||
elif 'A' in image.mode:
|
||||
frame = image.convert('RGBA')
|
||||
|
||||
elif image.mode == 'CMYK':
|
||||
frame = image.convert('RGB')
|
||||
|
||||
if image.mode.startswith('I;16'):
|
||||
shape = image.size
|
||||
dtype = '>u2' if image.mode.endswith('B') else '<u2'
|
||||
if 'S' in image.mode:
|
||||
dtype = dtype.replace('u', 'i')
|
||||
frame = np.fromstring(frame.tobytes(), dtype)
|
||||
frame.shape = shape[::-1]
|
||||
|
||||
else:
|
||||
frame = np.array(frame, dtype=dtype)
|
||||
|
||||
frames.append(frame)
|
||||
i += 1
|
||||
|
||||
if img_num is not None:
|
||||
break
|
||||
|
||||
if hasattr(image, 'fp') and image.fp:
|
||||
image.fp.close()
|
||||
|
||||
if img_num is None and len(frames) > 1:
|
||||
return np.array(frames)
|
||||
elif frames:
|
||||
return frames[0]
|
||||
elif img_num:
|
||||
raise IndexError(f'Could not find image #{img_num}')
|
||||
|
||||
|
||||
def _palette_is_grayscale(pil_image):
|
||||
"""Return True if PIL image in palette mode is grayscale.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
pil_image : PIL image
|
||||
PIL Image that is in Palette mode.
|
||||
|
||||
Returns
|
||||
-------
|
||||
is_grayscale : bool
|
||||
True if all colors in image palette are gray.
|
||||
"""
|
||||
if pil_image.mode != 'P':
|
||||
raise ValueError('pil_image.mode must be equal to "P".')
|
||||
# get palette as an array with R, G, B columns
|
||||
# Starting in pillow 9.1 palettes may have less than 256 entries
|
||||
palette = np.asarray(pil_image.getpalette()).reshape((-1, 3))
|
||||
# Not all palette colors are used; unused colors have junk values.
|
||||
start, stop = pil_image.getextrema()
|
||||
valid_palette = palette[start:stop + 1]
|
||||
# Image is grayscale if channel differences (R - G and G - B)
|
||||
# are all zero.
|
||||
return np.allclose(np.diff(valid_palette), 0)
|
||||
|
||||
|
||||
def ndarray_to_pil(arr, format_str=None):
|
||||
"""Export an ndarray to a PIL object.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
Refer to ``imsave``.
|
||||
|
||||
"""
|
||||
if arr.ndim == 3:
|
||||
arr = img_as_ubyte(arr)
|
||||
mode = {3: 'RGB', 4: 'RGBA'}[arr.shape[2]]
|
||||
|
||||
elif format_str in ['png', 'PNG']:
|
||||
mode = 'I;16'
|
||||
mode_base = 'I'
|
||||
|
||||
if arr.dtype.kind == 'f':
|
||||
arr = img_as_uint(arr)
|
||||
|
||||
elif arr.max() < 256 and arr.min() >= 0:
|
||||
arr = arr.astype(np.uint8)
|
||||
mode = mode_base = 'L'
|
||||
|
||||
else:
|
||||
arr = img_as_uint(arr)
|
||||
|
||||
else:
|
||||
arr = img_as_ubyte(arr)
|
||||
mode = 'L'
|
||||
mode_base = 'L'
|
||||
|
||||
try:
|
||||
array_buffer = arr.tobytes()
|
||||
except AttributeError:
|
||||
array_buffer = arr.tostring() # Numpy < 1.9
|
||||
|
||||
if arr.ndim == 2:
|
||||
im = Image.new(mode_base, arr.T.shape)
|
||||
try:
|
||||
im.frombytes(array_buffer, 'raw', mode)
|
||||
except AttributeError:
|
||||
im.fromstring(array_buffer, 'raw', mode) # PIL 1.1.7
|
||||
else:
|
||||
image_shape = (arr.shape[1], arr.shape[0])
|
||||
try:
|
||||
im = Image.frombytes(mode, image_shape, array_buffer)
|
||||
except AttributeError:
|
||||
im = Image.fromstring(mode, image_shape, array_buffer) # PIL 1.1.7
|
||||
return im
|
||||
|
||||
|
||||
def imsave(fname, arr, format_str=None, **kwargs):
|
||||
"""Save an image to disk.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fname : str or file-like object
|
||||
Name of destination file.
|
||||
arr : ndarray of uint8 or float
|
||||
Array (image) to save. Arrays of data-type uint8 should have
|
||||
values in [0, 255], whereas floating-point arrays must be
|
||||
in [0, 1].
|
||||
format_str: str
|
||||
Format to save as, this is defaulted to PNG if using a file-like
|
||||
object; this will be derived from the extension if fname is a string
|
||||
kwargs: dict
|
||||
Keyword arguments to the Pillow save function (or tifffile save
|
||||
function, for Tiff files). These are format dependent. For example,
|
||||
Pillow's JPEG save function supports an integer ``quality`` argument
|
||||
with values in [1, 95], while TIFFFile supports a ``compress``
|
||||
integer argument with values in [0, 9].
|
||||
|
||||
Notes
|
||||
-----
|
||||
Use the Python Imaging Library.
|
||||
See PIL docs [1]_ for a list of other supported formats.
|
||||
All images besides single channel PNGs are converted using `img_as_uint8`.
|
||||
Single Channel PNGs have the following behavior:
|
||||
- Integer values in [0, 255] and Boolean types -> img_as_uint8
|
||||
- Floating point and other integers -> img_as_uint16
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] http://pillow.readthedocs.org/en/latest/handbook/image-file-formats.html
|
||||
"""
|
||||
# default to PNG if file-like object
|
||||
if not isinstance(fname, str) and format_str is None:
|
||||
format_str = "PNG"
|
||||
# Check for png in filename
|
||||
if (isinstance(fname, str)
|
||||
and fname.lower().endswith(".png")):
|
||||
format_str = "PNG"
|
||||
|
||||
arr = np.asanyarray(arr)
|
||||
|
||||
if arr.dtype.kind == 'b':
|
||||
arr = arr.astype(np.uint8)
|
||||
|
||||
if arr.ndim not in (2, 3):
|
||||
raise ValueError(f"Invalid shape for image array: {arr.shape}")
|
||||
|
||||
if arr.ndim == 3:
|
||||
if arr.shape[2] not in (3, 4):
|
||||
raise ValueError("Invalid number of channels in image array.")
|
||||
|
||||
img = ndarray_to_pil(arr, format_str=format_str)
|
||||
img.save(fname, format=format_str, **kwargs)
|
||||
@@ -1,3 +0,0 @@
|
||||
[simpleitk]
|
||||
description = Image reading and writing via SimpleITK
|
||||
provides = imread, imsave
|
||||
@@ -1,21 +0,0 @@
|
||||
__all__ = ['imread', 'imsave']
|
||||
|
||||
try:
|
||||
import SimpleITK as sitk
|
||||
except ImportError:
|
||||
raise ImportError("SimpleITK could not be found. "
|
||||
"Please try "
|
||||
" easy_install SimpleITK "
|
||||
"or refer to "
|
||||
" http://simpleitk.org/ "
|
||||
"for further instructions.")
|
||||
|
||||
|
||||
def imread(fname):
|
||||
sitk_img = sitk.ReadImage(fname)
|
||||
return sitk.GetArrayFromImage(sitk_img)
|
||||
|
||||
|
||||
def imsave(fname, arr):
|
||||
sitk_img = sitk.GetImageFromArray(arr, isVector=True)
|
||||
sitk.WriteImage(sitk_img, fname)
|
||||
@@ -1,3 +0,0 @@
|
||||
[tifffile]
|
||||
description = Load and save TIFF and TIFF-based images using tifffile.py
|
||||
provides = imread, imsave
|
||||
@@ -1,74 +0,0 @@
|
||||
from tifffile import imread as tifffile_imread
|
||||
from tifffile import imwrite as tifffile_imwrite
|
||||
|
||||
__all__ = ['imread', 'imsave']
|
||||
|
||||
|
||||
def imsave(fname, arr, **kwargs):
|
||||
"""Load a tiff image to file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fname : str or file
|
||||
File name or file-like object.
|
||||
arr : ndarray
|
||||
The array to write.
|
||||
kwargs : keyword pairs, optional
|
||||
Additional keyword arguments to pass through (see ``tifffile``'s
|
||||
``imwrite`` function).
|
||||
|
||||
Notes
|
||||
-----
|
||||
Provided by the tifffile library [1]_, and supports many
|
||||
advanced image types including multi-page and floating-point.
|
||||
|
||||
This implementation will set ``photometric='RGB'`` when writing if the first
|
||||
or last axis of `arr` has length 3 or 4. To override this, explicitly
|
||||
pass the ``photometric`` kwarg.
|
||||
|
||||
This implementation will set ``planarconfig='SEPARATE'`` when writing if the
|
||||
first axis of arr has length 3 or 4. To override this, explicitly
|
||||
specify the ``planarconfig`` kwarg.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] https://pypi.org/project/tifffile/
|
||||
|
||||
"""
|
||||
if arr.shape[0] in [3, 4]:
|
||||
if 'planarconfig' not in kwargs:
|
||||
kwargs['planarconfig'] = 'SEPARATE'
|
||||
rgb = True
|
||||
else:
|
||||
rgb = arr.shape[-1] in [3, 4]
|
||||
if rgb and 'photometric' not in kwargs:
|
||||
kwargs['photometric'] = 'RGB'
|
||||
|
||||
return tifffile_imwrite(fname, arr, **kwargs)
|
||||
|
||||
|
||||
def imread(fname, **kwargs):
|
||||
"""Load a tiff image from file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fname : str or file
|
||||
File name or file-like-object.
|
||||
kwargs : keyword pairs, optional
|
||||
Additional keyword arguments to pass through (see ``tifffile``'s
|
||||
``imread`` function).
|
||||
|
||||
Notes
|
||||
-----
|
||||
Provided by the tifffile library [1]_, and supports many
|
||||
advanced image types including multi-page and floating point.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] https://pypi.org/project/tifffile/
|
||||
|
||||
"""
|
||||
if 'img_num' in kwargs:
|
||||
kwargs['key'] = kwargs.pop('img_num')
|
||||
|
||||
return tifffile_imread(fname, **kwargs)
|
||||
Reference in New Issue
Block a user