Clean up imsave behavior and beef up docstring

This commit is contained in:
Steven Silvester
2014-10-09 20:18:43 -05:00
parent 8396d59268
commit 74c87b583d
+58 -39
View File
@@ -27,7 +27,10 @@ def imread(fname, dtype=None):
dtype : numpy dtype object or string specifier dtype : numpy dtype object or string specifier
Specifies data type of array elements. Specifies data type of array elements.
Notes
-----
Tiff files are handled by Christophe Golhke's tifffile.py, and support many
advanced image types including multi-page and floating point.
""" """
if hasattr(fname, 'lower') and dtype is None: if hasattr(fname, 'lower') and dtype is None:
if fname.lower().endswith(('.tiff', '.tif')): if fname.lower().endswith(('.tiff', '.tif')):
@@ -109,36 +112,43 @@ def ndarray_to_pil(arr, format_str=None):
arr = img_as_ubyte(arr) arr = img_as_ubyte(arr)
mode = {3: 'RGB', 4: 'RGBA'}[arr.shape[2]] mode = {3: 'RGB', 4: 'RGBA'}[arr.shape[2]]
elif arr.dtype.kind == 'f': elif format_str.lower() == 'png':
arr = img_as_uint(arr) if arr.dtype.kind == 'f':
mode = 'I;16' arr = img_as_uint(arr)
mode_base = 'I' mode = 'I;16'
mode_base = 'I'
elif arr.max() < 256 and arr.min() >= 0: elif arr.max() < 256 and arr.min() >= 0:
arr = arr.astype(np.uint8) arr = arr.astype(np.uint8)
mode = 'L' mode = 'L'
mode_base = 'L' mode_base = 'L'
elif arr.max() < 2**16 and arr.min() >= 0: elif arr.min() >= 0:
arr = arr.astype(np.uint16) arr = img_as_uint(arr)
mode = 'I;16' mode = 'I;16'
mode_base = 'I' mode_base = 'I'
else:
arr = img_as_int(arr)
mode = 'I'
mode_base = 'I'
else: else:
arr = img_as_int(arr) arr = img_as_ubyte(arr)
mode = 'I' mode = 'L'
mode_base = 'I' mode_base = 'L'
if arr.ndim == 2: if arr.ndim == 2:
im = Image.new(mode_base, arr.T.shape) im = Image.new(mode_base, arr.T.shape)
im.fromstring(arr.tostring(), 'raw', mode) im.fromstring(arr.tostring(), 'raw', mode)
else: else:
try: try:
im = Image.frombytes(mode, (arr.shape[1], arr.shape[0]), im = Image.frombytes(mode, (arr.shape[1], arr.shape[0]),
arr.tostring()) arr.tostring())
except AttributeError: except AttributeError:
im = Image.fromstring(mode, (arr.shape[1], arr.shape[0]), im = Image.fromstring(mode, (arr.shape[1], arr.shape[0]),
arr.tostring()) arr.tostring())
return im return im
@@ -159,28 +169,27 @@ def imsave(fname, arr, format_str=None):
Notes Notes
----- -----
Currently, only 8-bit precision is supported for PNG and JPEG. Tiff files are handled by Christophe Golhke's tifffile.py, and support many
Images that are not uint8 type will be converted using advanced image types including multi-page and floating point.
`skimage.img_as_ubyte`.
2D TIFF Files also support unit16 and float32 type images. All other image formats use the Python Imaging Libary.
See http://pillow.readthedocs.org/en/latest/handbook/image-file-formats.html
for a list of other supported formats. Integer type images are only supported for PNGs.
All images besides single channel PNGs are converted using `img_as_uint8`.
Single Channel PNGS have the following behavior:
- Boolean types -> convert to uint8
- Integer values in {0, 256} -> convert to uin8
- Integer values > 0 -> convert to uint16
- Integer values < 0 -> convert to int16
- Floating point images -> convert to uint16
""" """
# default to PNG if file-like object # default to PNG if file-like object
if not isinstance(fname, string_types) and format_str is None: if not isinstance(fname, string_types) and format_str is None:
format_str = "PNG" format_str = "PNG"
if arr.ndim not in (2, 3):
raise ValueError("Invalid shape for image array: %s" % arr.shape)
if arr.ndim == 3:
if arr.shape[2] not in (3, 4):
raise ValueError("Invalid number of channels in image array.")
arr = np.asanyarray(arr).squeeze() arr = np.asanyarray(arr).squeeze()
if arr.dtype.kind == 'b':
arr = arr.astype(np.uint8)
use_tif = False use_tif = False
if hasattr(fname, 'lower'): if hasattr(fname, 'lower'):
if fname.lower().endswith(('.tiff', '.tif')): if fname.lower().endswith(('.tiff', '.tif')):
@@ -191,10 +200,20 @@ def imsave(fname, arr, format_str=None):
if use_tif: if use_tif:
tif_imsave(fname, arr) tif_imsave(fname, arr)
return
else: if arr.ndim not in (2, 3):
img = ndarray_to_pil(arr, format_str=None) raise ValueError("Invalid shape for image array: %s" % arr.shape)
img.save(fname, format=format_str)
if arr.ndim == 3:
if arr.shape[2] not in (3, 4):
raise ValueError("Invalid number of channels in image array.")
if arr.dtype.kind == 'b':
arr = arr.astype(np.uint8)
img = ndarray_to_pil(arr, format_str=None)
img.save(fname, format=format_str)
def imshow(arr): def imshow(arr):