Merge pull request #862 from tonysyu/refactor/imread_collection

Add `imread_collection` automatically if plugin provides `imread`
This commit is contained in:
Juan Nunez-Iglesias
2014-01-15 15:49:58 -08:00
3 changed files with 98 additions and 19 deletions
+31 -4
View File
@@ -2,18 +2,18 @@
from __future__ import with_statement
__all__ = ['MultiImage', 'ImageCollection', 'imread', 'concatenate_images']
from glob import glob
import re
from copy import copy
import numpy as np
from ._io import imread
import six
__all__ = ['MultiImage', 'ImageCollection', 'concatenate_images',
'imread_collection_wrapper']
def concatenate_images(ic):
"""Concatenate all images in the image collection into an array.
@@ -312,6 +312,7 @@ class ImageCollection(object):
self._cached = None
if load_func is None:
from ._io import imread
self.load_func = imread
else:
self.load_func = load_func
@@ -430,3 +431,29 @@ class ImageCollection(object):
If images in the `ImageCollection` don't have identical shapes.
"""
return concatenate_images(self)
def imread_collection_wrapper(imread):
def imread_collection(load_pattern, conserve_memory=True):
"""Return an `ImageCollection` from files matching the given pattern.
Note that files are always stored in alphabetical order. Also note that
slicing returns a new ImageCollection, *not* a view into the data.
See `skimage.io.ImageCollection` for details.
Parameters
----------
load_pattern : str or list
Pattern glob or filenames to load. The path can be absolute or
relative. Multiple patterns should be separated by a colon,
e.g. '/tmp/work/*.png:/tmp/other/*.jpg'. Also see
implementation notes below.
conserve_memory : bool, optional
If True, never keep more than one in memory at a specific
time. Otherwise, images will be cached once they are loaded.
"""
return ImageCollection(load_pattern, conserve_memory=conserve_memory,
load_func=imread)
return imread_collection
+46 -9
View File
@@ -1,5 +1,19 @@
"""Handle image reading, writing and plotting plugins.
To improve performance, plugins are only loaded as needed. As a result, there
can be multiple states for a given plugin:
available: Defined in an *ini file located in `skimage.io._plugins`.
See also `skimage.io.available_plugins`.
partial definition: Specified in an *ini file, but not defined in the
corresponding plugin module. This will raise an error when loaded.
available but not on this system: Defined in `skimage.io._plugins`, but
a dependent library (e.g. Qt, PIL) is not available on your system.
This will raise an error when loaded.
loaded: The real availability is determined when it's explicitly loaded,
either because it's one of the default plugins, or because it's
loaded explicitly by the user.
"""
try:
@@ -10,6 +24,8 @@ except ImportError:
import os.path
from glob import glob
from .collection import imread_collection_wrapper
__all__ = ['use_plugin', 'call_plugin', 'plugin_info', 'plugin_order',
'reset_plugins', 'find_available_plugins', 'available_plugins']
@@ -18,11 +34,14 @@ __all__ = ['use_plugin', 'call_plugin', 'plugin_info', 'plugin_order',
# The plugin store will save a list of *loaded* io functions for each io type
# (e.g. 'imread', 'imsave', etc.). Plugins are loaded as requested.
plugin_store = None
# Dictionary mapping plugin names to a list of functions they provide.
plugin_provides = {}
# The module names for the plugins in `skimage.io._plugins`.
plugin_module_name = {}
# Meta-data about plugins provided by *.ini files.
plugin_meta_data = {}
# For each plugin type, default to the first available plugin as defined by
# the following preferences.
preferred_plugins = {
# Default plugins for all types (overridden by specific types below).
'all': ['matplotlib', 'pil', 'qt', 'freeimage', 'null'],
@@ -105,7 +124,14 @@ def _scan_plugins():
print("Plugin `%s` wants to provide non-existent `%s`." \
" Ignoring." % (name, p))
# Add plugins that provide 'imread' as provider of 'imread_collection'.
need_to_add_collection = ('imread_collection' not in valid_provides and
'imread' in valid_provides)
if need_to_add_collection:
valid_provides.append('imread_collection')
plugin_provides[name] = valid_provides
plugin_module_name[name] = os.path.basename(filename)[:-4]
_scan_plugins()
@@ -135,7 +161,7 @@ def find_available_plugins(loaded=False):
d = {}
for plugin in plugin_provides:
if not loaded or plugin in active_plugins:
d[plugin] = [f for f in plugin_provides[plugin] \
d[plugin] = [f for f in plugin_provides[plugin]
if not f.startswith('_')]
return d
@@ -240,6 +266,14 @@ def use_plugin(name, kind=None):
plugin_store[k] = funcs
def _inject_imread_collection_if_needed(module):
"""Add `imread_collection` to module if not already present."""
if not hasattr(module, 'imread_collection') and hasattr(module, 'imread'):
imread = getattr(module, 'imread')
func = imread_collection_wrapper(imread)
setattr(module, 'imread_collection', func)
def _load(plugin):
"""Load the given plugin.
@@ -264,14 +298,17 @@ def _load(plugin):
provides = plugin_provides[plugin]
for p in provides:
if not hasattr(plugin_module, p):
if p == 'imread_collection':
_inject_imread_collection_if_needed(plugin_module)
elif not hasattr(plugin_module, p):
print("Plugin %s does not provide %s as advertised. Ignoring." % \
(plugin, p))
else:
store = plugin_store[p]
func = getattr(plugin_module, p)
if not (plugin, func) in store:
store.append((plugin, func))
continue
store = plugin_store[p]
func = getattr(plugin_module, p)
if not (plugin, func) in store:
store.append((plugin, func))
def plugin_info(plugin):
+21 -6
View File
@@ -1,5 +1,6 @@
import os
import warnings
from contextlib import contextmanager
import numpy as np
from numpy.testing import raises
@@ -8,28 +9,42 @@ from skimage import io
from skimage import data_dir
@contextmanager
def warnings_as_errors():
# Temporarily set warnings as errors so we can test the warning is raised.
with warnings.catch_warnings():
warnings.filterwarnings('error')
yield
@raises(Warning)
def test_null_imread():
path = os.path.join(data_dir, 'color.png')
with warnings.catch_warnings(): # Temporarily set warnings as errors.
warnings.filterwarnings('error')
with warnings_as_errors():
io.imread(path, plugin='null')
@raises(Warning)
def test_null_imsave():
with warnings.catch_warnings(): # Temporarily set warnings as errors.
warnings.filterwarnings('error')
with warnings_as_errors():
io.imsave('dummy.png', np.zeros((3, 3)), plugin='null')
@raises(Warning)
def test_null_imshow():
with warnings.catch_warnings(): # Temporarily set warnings as errors.
warnings.filterwarnings('error')
with warnings_as_errors():
io.imshow(np.zeros((3, 3)), plugin='null')
@raises(Warning)
def test_null_imread_collection():
# Note that the null plugin doesn't define an `imread_collection` plugin
# but this function is dynamically added by the plugin manager.
path = os.path.join(data_dir, '*.png')
with warnings_as_errors():
collection = io.imread_collection(path, plugin='null')
collection[0]
if __name__ == '__main__':
from numpy.testing import run_module_suite
run_module_suite()