mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-16 11:21:25 +08:00
Merge plugin branch.
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
"""Utilities to read and write images in various formats."""
|
||||
|
||||
import pil_plugin
|
||||
import matplotlib_plugin
|
||||
|
||||
from plugin import register as register_plugin
|
||||
|
||||
from pil_imread import *
|
||||
from sift import *
|
||||
from collection import *
|
||||
|
||||
from io import *
|
||||
|
||||
@@ -8,7 +8,7 @@ from glob import glob
|
||||
import os.path
|
||||
|
||||
import numpy as np
|
||||
from pil_imread import imread
|
||||
from io import imread
|
||||
|
||||
from PIL import Image
|
||||
|
||||
@@ -266,7 +266,8 @@ class ImageCollection(object):
|
||||
n = self._check_imgnum(n)
|
||||
idx = n % len(self.data)
|
||||
|
||||
if (self.conserve_memory and n != self._cached) or (self.data[idx] is None):
|
||||
if (self.conserve_memory and n != self._cached) or \
|
||||
(self.data[idx] is None):
|
||||
self.data[idx] = imread(self.files[n], self.as_grey,
|
||||
dtype=self._dtype)
|
||||
self._cached = n
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
__all__ = ['imread', 'imsave', 'imshow']
|
||||
|
||||
from scikits.image.io import plugin as _plugin
|
||||
|
||||
def imread(fname, as_grey=False, dtype=None, plugin=None, flatten=None,
|
||||
**plugin_args):
|
||||
"""Load an image from file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fname : string
|
||||
Image file name, e.g. ``test.jpg``.
|
||||
as_grey : bool
|
||||
If True, convert color images to grey-scale. If `dtype` is not given,
|
||||
converted color images are returned as 32-bit float images.
|
||||
Images that are already in grey-scale format are not converted.
|
||||
dtype : dtype, optional
|
||||
NumPy data-type specifier. If given, the returned image has this type.
|
||||
If None (default), the data-type is determined automatically.
|
||||
plugin : str
|
||||
Name of plugin to use. By default, the different plugins are
|
||||
tried (starting with the Python Imaging Library) until a suitable
|
||||
candidate is found.
|
||||
|
||||
Other Parameters
|
||||
----------------
|
||||
flatten : bool
|
||||
Backward compatible keyword, superseded by `as_grey`.
|
||||
|
||||
Returns
|
||||
-------
|
||||
img_array : ndarray
|
||||
The different colour bands/channels are stored in the
|
||||
third dimension, such that a grey-image is MxN, an
|
||||
RGB-image MxNx3 and an RGBA-image MxNx4.
|
||||
|
||||
Other parameters
|
||||
----------------
|
||||
plugin_args : keywords
|
||||
Passed to the given plugin.
|
||||
|
||||
"""
|
||||
# Backward compatibility
|
||||
if flatten is not None:
|
||||
as_grey = flatten
|
||||
|
||||
return _plugin.call('read', fname, as_grey=as_grey, dtype=dtype,
|
||||
plugin=plugin, **plugin_args)
|
||||
|
||||
def imsave(fname, arr, plugin=None, **plugin_args):
|
||||
"""Save an image to file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fname : str
|
||||
Target filename.
|
||||
arr : ndarray of shape (M,N) or (M,N,3) or (M,N,4)
|
||||
Image data.
|
||||
plugin : str
|
||||
Name of plugin to use. By default, the different plugins are
|
||||
tried (starting with the Python Imaging Library) until a suitable
|
||||
candidate is found.
|
||||
|
||||
Other parameters
|
||||
----------------
|
||||
plugin_args : keywords
|
||||
Passed to the given plugin.
|
||||
|
||||
"""
|
||||
return _plugin.call('save', fname, arr, plugin=plugin, **plugin_args)
|
||||
|
||||
def imshow(arr, plugin=None, **plugin_args):
|
||||
"""Display an image.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
arr : ndarray
|
||||
Image data.
|
||||
plugin : str
|
||||
Name of plugin to use. By default, the different plugins are
|
||||
tried (starting with the Python Imaging Library) until a suitable
|
||||
candidate is found.
|
||||
|
||||
Other parameters
|
||||
----------------
|
||||
plugin_args : keywords
|
||||
Passed to the given plugin.
|
||||
|
||||
"""
|
||||
return _plugin.call('show', arr, plugin=plugin, **plugin_args)
|
||||
@@ -0,0 +1,8 @@
|
||||
import plugin
|
||||
|
||||
try:
|
||||
import matplotlib.pyplot as plt
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
plugin.register('matplotlib', show=plt.imshow, save=plt.imsave)
|
||||
@@ -1,67 +0,0 @@
|
||||
__all__ = ['imread']
|
||||
|
||||
import numpy as np
|
||||
|
||||
def imread(fname, flatten=False, dtype=None):
|
||||
"""Load an image from file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fname : string
|
||||
Image file name, e.g. ``test.jpg``.
|
||||
flatten : bool
|
||||
If True, convert color images to grey-scale. If `dtype` is not given,
|
||||
converted color images are returned as 32-bit float images.
|
||||
Images that are already in grey-scale format are not converted.
|
||||
dtype : dtype, optional
|
||||
NumPy data-type specifier. If given, the returned image has this type.
|
||||
If None (default), the data-type is determined automatically.
|
||||
|
||||
Returns
|
||||
-------
|
||||
img_array : ndarray
|
||||
The different colour bands/channels are stored in the
|
||||
third dimension, such that a grey-image is MxN, an
|
||||
RGB-image MxNx3 and an RGBA-image MxNx4.
|
||||
|
||||
"""
|
||||
try:
|
||||
from PIL import Image
|
||||
except ImportError:
|
||||
raise ImportError("Could not import the Python Imaging Library (PIL)"
|
||||
" required to load image files. Please refer to"
|
||||
" http://pypi.python.org/pypi/PIL/ for installation"
|
||||
" instructions.")
|
||||
|
||||
im = Image.open(fname)
|
||||
if im.mode == 'P':
|
||||
if palette_is_grayscale(im):
|
||||
im = im.convert('L')
|
||||
else:
|
||||
im = im.convert('RGB')
|
||||
if flatten and not im.mode in ('1', 'L', 'I', 'F', 'I;16', 'I;16L', 'I;16B'):
|
||||
im = im.convert('F')
|
||||
return np.array(im, dtype=dtype)
|
||||
|
||||
|
||||
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.
|
||||
"""
|
||||
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)
|
||||
@@ -0,0 +1,54 @@
|
||||
__all__ = ['imread']
|
||||
|
||||
import numpy as np
|
||||
import plugin
|
||||
|
||||
try:
|
||||
from PIL import Image
|
||||
has_pil = True
|
||||
except ImportError:
|
||||
has_pil = False
|
||||
|
||||
def imread(fname, as_grey=False, dtype=None):
|
||||
"""Load an image from file.
|
||||
|
||||
"""
|
||||
im = Image.open(fname)
|
||||
if im.mode == 'P':
|
||||
if palette_is_grayscale(im):
|
||||
im = im.convert('L')
|
||||
else:
|
||||
im = im.convert('RGB')
|
||||
|
||||
if as_grey and not \
|
||||
im.mode in ('1', 'L', 'I', 'F', 'I;16', 'I;16L', 'I;16B'):
|
||||
im = im.convert('F')
|
||||
|
||||
return np.array(im, dtype=dtype)
|
||||
|
||||
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.
|
||||
"""
|
||||
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)
|
||||
|
||||
|
||||
if has_pil:
|
||||
plugin.register('PIL', read=imread)
|
||||
@@ -0,0 +1,143 @@
|
||||
"""Handle image reading, writing and plotting plugins.
|
||||
|
||||
"""
|
||||
|
||||
__all__ = ['register', 'use']
|
||||
|
||||
import warnings
|
||||
|
||||
plugin_store = {'read': [],
|
||||
'save': [],
|
||||
'show': []}
|
||||
|
||||
def register(name, **kwds):
|
||||
"""Register an image I/O plugin.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
Name of this plugin.
|
||||
read : callable, optional
|
||||
Function with signature
|
||||
``read(filename, as_grey=False, dtype=None, **plugin_specific_args)``
|
||||
that reads images.
|
||||
save : callable, optional
|
||||
Function with signature
|
||||
``write(filename, arr, **plugin_specific_args)``
|
||||
that writes an image to disk.
|
||||
show : callable, optional
|
||||
Function with signature
|
||||
``show(X, **plugin_specific_args)`` that displays an image.
|
||||
|
||||
"""
|
||||
for kind in kwds:
|
||||
if kind not in plugin_store.keys():
|
||||
raise ValueError('Tried to register invalid plugin method.')
|
||||
|
||||
func = kwds[kind]
|
||||
if not callable(func):
|
||||
raise ValueError('Can only register functions as plugins.')
|
||||
|
||||
plugin_store[kind].append((name, func))
|
||||
|
||||
|
||||
def call(kind, *args, **kwargs):
|
||||
"""Find the appropriate plugin of 'kind' and execute it.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
kind : {'show', 'save', 'read'}
|
||||
Function to look up.
|
||||
plugin : str, optional
|
||||
Plugin to load. Defaults to None, in which case the first
|
||||
matching plugin is used.
|
||||
*args, **kwargs : arguments and keyword arguments
|
||||
Passed to the plugin function.
|
||||
|
||||
"""
|
||||
if not kind in plugin_store:
|
||||
raise ValueError('Invalid function (%s) requested.' % kind)
|
||||
|
||||
plugin_funcs = plugin_store[kind]
|
||||
if len(plugin_funcs) == 0:
|
||||
raise RuntimeError('No suitable plugin registered for %s' % kind)
|
||||
|
||||
plugin = kwargs.pop('plugin', None)
|
||||
if plugin is None:
|
||||
_, func = plugin_funcs[0]
|
||||
else:
|
||||
try:
|
||||
func = [f for (p,f) in plugin_funcs if p == plugin][0]
|
||||
except IndexError:
|
||||
raise RuntimeError('Could not find the plugin "%s" for %s.' % \
|
||||
(plugin, kind))
|
||||
|
||||
return func(*args, **kwargs)
|
||||
|
||||
def use(name, kind=None):
|
||||
"""Set the default plugin for a specified operation.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
Name of plugin.
|
||||
kind : {'save', 'read', 'show'}, optional
|
||||
Set the plugin for this function. By default,
|
||||
the plugin is set for all functions.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Use Python Imaging Library to read images:
|
||||
|
||||
>>> from scikits.image.io import plugin
|
||||
>>> plugin.use('PIL', 'read')
|
||||
|
||||
"""
|
||||
if kind is None:
|
||||
kind = plugin_store.keys()
|
||||
else:
|
||||
kind = [kind]
|
||||
|
||||
for k in kind:
|
||||
if not k in plugin_store:
|
||||
raise RuntimeError("Could not find plugin for '%s'" % k)
|
||||
|
||||
funcs = plugin_store[k]
|
||||
|
||||
# Shuffle the plugins so that the requested plugin stands first
|
||||
# in line
|
||||
funcs = [(n, f) for (n, f) in funcs if n == name] + \
|
||||
[(n, f) for (n, f) in funcs if n != name]
|
||||
|
||||
n, f = funcs[0]
|
||||
if not n == name:
|
||||
warnings.warn(RuntimeWarning('Could not set plugin "%s" for'
|
||||
' function "%s".' % (name, k)))
|
||||
|
||||
plugin_store[k] = funcs
|
||||
|
||||
def available(kind=None):
|
||||
"""List available plugins.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
kind : {'show', 'save', 'read'}, optional
|
||||
Display the plugin list for the given function type. If not specified,
|
||||
return a dictionary with the plugins for all functions.
|
||||
|
||||
"""
|
||||
if kind is None:
|
||||
kind = plugin_store.keys()
|
||||
else:
|
||||
kind = [kind]
|
||||
|
||||
d = {}
|
||||
for k in kind:
|
||||
if not k in plugin_store:
|
||||
raise ValueError('No function "%s" exists in the plugin registry.'
|
||||
% kind)
|
||||
|
||||
d[k] = [name for (name, func) in plugin_store[k]]
|
||||
|
||||
return d
|
||||
@@ -3,7 +3,7 @@ import numpy as np
|
||||
|
||||
from scikits.image import data_dir
|
||||
from scikits.image.io import imread
|
||||
from scikits.image.io.pil_imread import palette_is_grayscale
|
||||
from scikits.image.io.pil_plugin import palette_is_grayscale
|
||||
|
||||
def test_imread_flatten():
|
||||
# a color image is flattened and returned as float32
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
from numpy.testing import *
|
||||
|
||||
from scikits.image import io
|
||||
from scikits.image.io import plugin
|
||||
|
||||
from copy import deepcopy
|
||||
|
||||
def read(fname, as_grey=False, dtype=None):
|
||||
assert fname == 'test.png'
|
||||
assert as_grey == True
|
||||
assert dtype == 'i4'
|
||||
|
||||
def save(fname, arr):
|
||||
assert fname == 'test.png'
|
||||
assert arr == [1, 2, 3]
|
||||
|
||||
def show(arr, plugin_arg=None):
|
||||
assert arr == [1, 2, 3]
|
||||
assert plugin_arg == (1, 2)
|
||||
|
||||
def show_other(arr):
|
||||
return "other"
|
||||
|
||||
def setup_module(self):
|
||||
self.backup_plugin_store = deepcopy(plugin.plugin_store)
|
||||
plugin.register('test', read=read, save=save, show=show)
|
||||
plugin.register('other', show=show_other)
|
||||
|
||||
def teardown_module(self):
|
||||
plugin.plugin_store = self.backup_plugin_store
|
||||
|
||||
class TestPlugin:
|
||||
def test_read(self):
|
||||
io.imread('test.png', as_grey=True, dtype='i4', plugin='test')
|
||||
|
||||
def test_save(self):
|
||||
io.imsave('test.png', [1, 2, 3], plugin='test')
|
||||
|
||||
def test_show(self):
|
||||
io.imshow([1, 2, 3], plugin_arg=(1, 2), plugin='test')
|
||||
|
||||
def test_use(self):
|
||||
plugin.use('other', 'show')
|
||||
assert io.imshow(None) == 'other'
|
||||
|
||||
def test_available(self):
|
||||
plugin.use('other', 'show')
|
||||
d = plugin.available('show')
|
||||
assert d['show'][0] == 'other'
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_module_suite()
|
||||
Reference in New Issue
Block a user