mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-12 03:52:02 +08:00
io: Add imsave using PIL.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
[pil]
|
||||
description = Image reading via the Python Imaging Library
|
||||
provides = imread
|
||||
provides = imread, imsave
|
||||
|
||||
|
||||
@@ -6,44 +6,90 @@ import numpy as np
|
||||
try:
|
||||
from PIL import Image
|
||||
except ImportError:
|
||||
print 'Could not load Python Imaging Library'
|
||||
else:
|
||||
def imread(fname, as_grey=False, dtype=None):
|
||||
"""Load an image from file.
|
||||
raise ImportError("The Python Image Library could not be found. "
|
||||
"Please refer to http://pypi.python.org/pypi/PIL/ "
|
||||
"for further instructions.")
|
||||
|
||||
"""
|
||||
im = Image.open(fname)
|
||||
if im.mode == 'P':
|
||||
if palette_is_grayscale(im):
|
||||
im = im.convert('L')
|
||||
else:
|
||||
im = im.convert('RGB')
|
||||
def imread(fname, as_grey=False, dtype=None):
|
||||
"""Load an image from file.
|
||||
|
||||
if as_grey and not \
|
||||
im.mode in ('1', 'L', 'I', 'F', 'I;16', 'I;16L', 'I;16B'):
|
||||
im = im.convert('F')
|
||||
"""
|
||||
im = Image.open(fname)
|
||||
if im.mode == 'P':
|
||||
if _palette_is_grayscale(im):
|
||||
im = im.convert('L')
|
||||
else:
|
||||
im = im.convert('RGB')
|
||||
|
||||
return np.array(im, dtype=dtype)
|
||||
if as_grey and not \
|
||||
im.mode in ('1', 'L', 'I', 'F', 'I;16', 'I;16L', 'I;16B'):
|
||||
im = im.convert('F')
|
||||
|
||||
def palette_is_grayscale(pil_image):
|
||||
"""Return True if PIL image in palette mode is grayscale.
|
||||
return np.array(im, dtype=dtype)
|
||||
|
||||
Parameters
|
||||
----------
|
||||
pil_image : PIL image
|
||||
PIL Image that is in Palette mode.
|
||||
def _palette_is_grayscale(pil_image):
|
||||
"""Return True if PIL image in palette mode is grayscale.
|
||||
|
||||
Returns
|
||||
-------
|
||||
is_grayscale : bool
|
||||
True if all colors in image palette are gray.
|
||||
"""
|
||||
assert pil_image.mode == 'P'
|
||||
# get palette as an array with R, G, B columns
|
||||
palette = np.asarray(pil_image.getpalette()).reshape((256, 3))
|
||||
# Not all palette colors are used; unused colors have junk values.
|
||||
start, stop = pil_image.getextrema()
|
||||
valid_palette = palette[start:stop]
|
||||
# Image is grayscale if channel differences (R - G and G - B)
|
||||
# are all zero.
|
||||
return np.allclose(np.diff(valid_palette), 0)
|
||||
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.
|
||||
"""
|
||||
assert pil_image.mode == 'P'
|
||||
# get palette as an array with R, G, B columns
|
||||
palette = np.asarray(pil_image.getpalette()).reshape((256, 3))
|
||||
# Not all palette colors are used; unused colors have junk values.
|
||||
start, stop = pil_image.getextrema()
|
||||
valid_palette = palette[start:stop]
|
||||
# Image is grayscale if channel differences (R - G and G - B)
|
||||
# are all zero.
|
||||
return np.allclose(np.diff(valid_palette), 0)
|
||||
|
||||
def imsave(fname, arr):
|
||||
"""Save an image to disk.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fname : str
|
||||
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].
|
||||
|
||||
Notes
|
||||
-----
|
||||
Currently, only 8-bit precision is supported.
|
||||
|
||||
"""
|
||||
arr = np.asarray(arr).squeeze()
|
||||
|
||||
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.")
|
||||
|
||||
# Image is floating point, assume in [0, 1]
|
||||
if np.issubdtype(arr.dtype, float):
|
||||
arr = arr * 255
|
||||
|
||||
arr = arr.astype(np.uint8)
|
||||
|
||||
if arr.ndim == 2:
|
||||
mode = 'L'
|
||||
|
||||
elif arr.shape[2] in (3, 4):
|
||||
mode = {3: 'RGB', 4: 'RGBA'}[arr.shape[2]]
|
||||
|
||||
# Force all integers to bytes
|
||||
arr = arr.astype(np.uint8)
|
||||
|
||||
img = Image.fromstring(mode, (arr.shape[1], arr.shape[0]), arr.tostring())
|
||||
img.save(fname)
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import os.path
|
||||
import numpy as np
|
||||
from numpy.testing import *
|
||||
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
from scikits.image import data_dir
|
||||
from scikits.image.io import imread
|
||||
from scikits.image.io._plugins.pil_plugin import palette_is_grayscale
|
||||
from scikits.image.io import imread, imsave
|
||||
from scikits.image.io._plugins.pil_plugin import _palette_is_grayscale
|
||||
|
||||
def test_imread_flatten():
|
||||
# a color image is flattened and returned as float32
|
||||
@@ -26,6 +29,26 @@ def test_imread_palette():
|
||||
def test_palette_is_gray():
|
||||
from PIL import Image
|
||||
gray = Image.open(os.path.join(data_dir, 'palette_gray.png'))
|
||||
assert palette_is_grayscale(gray)
|
||||
assert _palette_is_grayscale(gray)
|
||||
color = Image.open(os.path.join(data_dir, 'palette_color.png'))
|
||||
assert not palette_is_grayscale(color)
|
||||
assert not _palette_is_grayscale(color)
|
||||
|
||||
class TestSave:
|
||||
def roundtrip(self, dtype, x, scaling=1):
|
||||
f = NamedTemporaryFile(suffix='.png')
|
||||
imsave(f.name, x)
|
||||
f.seek(0)
|
||||
y = imread(f.name)
|
||||
|
||||
assert_array_almost_equal((x * scaling).astype(np.int32), y)
|
||||
|
||||
def test_imsave_roundtrip(self):
|
||||
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.random(shape)
|
||||
|
||||
if np.issubdtype(dtype, float):
|
||||
yield self.roundtrip, dtype, x, 255
|
||||
else:
|
||||
x = (x * 255).astype(dtype)
|
||||
yield self.roundtrip, dtype, x
|
||||
Reference in New Issue
Block a user