mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-04 03:19:28 +08:00
Merge pull request #1083 from adamfeuer/import_export_pil_image_objects
pil_plugin can import and export PIL image objects from memory
This commit is contained in:
@@ -182,3 +182,6 @@
|
||||
|
||||
- Axel Donath
|
||||
Blob Detection
|
||||
|
||||
- Adam Feuer
|
||||
PIL Image import and export improvements
|
||||
|
||||
@@ -19,9 +19,28 @@ from six import string_types
|
||||
def imread(fname, dtype=None):
|
||||
"""Load an image from file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fname : str
|
||||
File name.
|
||||
dtype : numpy dtype object or string specifier
|
||||
Specifies data type of array elements.
|
||||
|
||||
|
||||
"""
|
||||
im = Image.open(fname)
|
||||
fp = im.fp
|
||||
return pil_to_ndarray(im, dtype)
|
||||
|
||||
|
||||
def pil_to_ndarray(im, dtype=None):
|
||||
"""Import a PIL Image object to an ndarray, in memory.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
Refer to ``imread``.
|
||||
|
||||
"""
|
||||
fp = im.fp if hasattr(im, 'fp') else None
|
||||
if im.mode == 'P':
|
||||
if _palette_is_grayscale(im):
|
||||
im = im.convert('L')
|
||||
@@ -37,7 +56,8 @@ def imread(fname, dtype=None):
|
||||
elif 'A' in im.mode:
|
||||
im = im.convert('RGBA')
|
||||
im = np.array(im, dtype=dtype)
|
||||
fp.close()
|
||||
if fp is not None:
|
||||
fp.close()
|
||||
return im
|
||||
|
||||
|
||||
@@ -65,24 +85,12 @@ def _palette_is_grayscale(pil_image):
|
||||
return np.allclose(np.diff(valid_palette), 0)
|
||||
|
||||
|
||||
def imsave(fname, arr, format_str=None):
|
||||
"""Save an image to disk.
|
||||
def ndarray_to_pil(arr, format_str=None):
|
||||
"""Export an ndarray to a PIL object.
|
||||
|
||||
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
|
||||
|
||||
Notes
|
||||
-----
|
||||
Currently, only 8-bit precision is supported.
|
||||
Refer to ``imsave``.
|
||||
|
||||
"""
|
||||
arr = np.asarray(arr).squeeze()
|
||||
@@ -109,10 +117,6 @@ def imsave(fname, arr, format_str=None):
|
||||
# Force all integers to bytes
|
||||
arr = arr.astype(np.uint8)
|
||||
|
||||
# default to PNG if file-like object
|
||||
if not isinstance(fname, string_types) and format_str is None:
|
||||
format_str = "PNG"
|
||||
|
||||
try:
|
||||
img = Image.frombytes(mode, (arr.shape[1], arr.shape[0]),
|
||||
arr.tostring())
|
||||
@@ -120,6 +124,34 @@ def imsave(fname, arr, format_str=None):
|
||||
img = Image.fromstring(mode, (arr.shape[1], arr.shape[0]),
|
||||
arr.tostring())
|
||||
|
||||
return img
|
||||
|
||||
|
||||
def imsave(fname, arr, format_str=None):
|
||||
"""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
|
||||
|
||||
Notes
|
||||
-----
|
||||
Currently, only 8-bit precision is supported.
|
||||
|
||||
"""
|
||||
# default to PNG if file-like object
|
||||
if not isinstance(fname, string_types) and format_str is None:
|
||||
format_str = "PNG"
|
||||
|
||||
img = ndarray_to_pil(arr, format_str=None)
|
||||
img.save(fname, format=format_str)
|
||||
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ from six import BytesIO
|
||||
|
||||
try:
|
||||
from PIL import Image
|
||||
from skimage.io._plugins.pil_plugin import _palette_is_grayscale
|
||||
from skimage.io._plugins.pil_plugin import pil_to_ndarray, ndarray_to_pil, _palette_is_grayscale
|
||||
use_plugin('pil')
|
||||
except ImportError:
|
||||
PIL_available = False
|
||||
@@ -113,26 +113,40 @@ def test_imread_uint16_big_endian():
|
||||
|
||||
|
||||
class TestSave:
|
||||
def roundtrip(self, dtype, x, scaling=1):
|
||||
def roundtrip_file(self, x):
|
||||
f = NamedTemporaryFile(suffix='.png')
|
||||
fname = f.name
|
||||
f.close()
|
||||
imsave(fname, x)
|
||||
y = imread(fname)
|
||||
return y
|
||||
|
||||
def roundtrip_pil_image(self, x):
|
||||
pil_image = ndarray_to_pil(x)
|
||||
y = pil_to_ndarray(pil_image)
|
||||
return y
|
||||
|
||||
def verify_roundtrip(self, dtype, x, y, scaling=1):
|
||||
assert_array_almost_equal((x * scaling).astype(np.int32), y)
|
||||
|
||||
@skipif(not PIL_available)
|
||||
def test_imsave_roundtrip(self):
|
||||
def verify_imsave_roundtrip(self, roundtrip_function):
|
||||
for shape in [(10, 10), (10, 10, 3), (10, 10, 4)]:
|
||||
for dtype in (np.uint8, np.uint16, np.float32, np.float64):
|
||||
x = np.ones(shape, dtype=dtype) * np.random.rand(*shape)
|
||||
|
||||
if np.issubdtype(dtype, float):
|
||||
yield self.roundtrip, dtype, x, 255
|
||||
yield self.verify_roundtrip, dtype, x, roundtrip_function(x), 255
|
||||
else:
|
||||
x = (x * 255).astype(dtype)
|
||||
yield self.roundtrip, dtype, x
|
||||
yield self.verify_roundtrip, dtype, x, roundtrip_function(x)
|
||||
|
||||
@skipif(not PIL_available)
|
||||
def test_imsave_roundtrip_file(self):
|
||||
self.verify_imsave_roundtrip(self.roundtrip_file)
|
||||
|
||||
@skipif(not PIL_available)
|
||||
def test_imsave_roundtrip_pil_image(self):
|
||||
self.verify_imsave_roundtrip(self.roundtrip_pil_image)
|
||||
|
||||
|
||||
@skipif(not PIL_available)
|
||||
@@ -151,5 +165,14 @@ def test_imsave_filelike():
|
||||
assert_allclose(out, image)
|
||||
|
||||
|
||||
@skipif(not PIL_available)
|
||||
def test_imexport_imimport():
|
||||
shape = (2, 2)
|
||||
image = np.zeros(shape)
|
||||
pil_image = ndarray_to_pil(image)
|
||||
out = pil_to_ndarray(pil_image)
|
||||
assert out.shape == shape
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_module_suite()
|
||||
|
||||
Reference in New Issue
Block a user