Merge pull request #1905 from stefanv/novice_undo

Add comparison and reset capability to novice module
This commit is contained in:
Steven Silvester
2016-03-03 18:38:17 -06:00
10 changed files with 91 additions and 14 deletions
+22 -1
View File
@@ -10,7 +10,8 @@ from ..exposure import is_low_contrast
from .._shared.utils import all_warnings, warn
__all__ = ['imread', 'imread_collection', 'imsave', 'imshow', 'show']
__all__ = ['imread', 'imsave', 'imshow', 'show',
'imread_collection', 'imshow_collection']
def imread(fname, as_grey=False, plugin=None, flatten=None,
@@ -155,6 +156,26 @@ def imshow(arr, plugin=None, **plugin_args):
return call_plugin('imshow', arr, plugin=plugin, **plugin_args)
def imshow_collection(ic, plugin=None, **plugin_args):
"""Display a collection of images.
Parameters
----------
ic : ImageCollection
Collection to display.
plugin : str
Name of plugin to use. By default, the different plugins are
tried until a suitable candidate is found.
Other parameters
----------------
plugin_args : keywords
Passed to the given plugin.
"""
return call_plugin('imshow_collection', ic, plugin=plugin, **plugin_args)
def show():
'''Display pending images.
+1 -2
View File
@@ -1,4 +1,3 @@
[matplotlib]
description = Display or save images using Matplotlib
provides = imshow, imread, _app_show
provides = imshow, imread, imshow_collection, _app_show
+13
View File
@@ -147,6 +147,7 @@ def imshow(im, ax=None, show_cbar=None, **kwargs):
if kwargs.get('cmap', None) == 'viridis':
kwargs['cmap'] = viridis
lo, hi, cmap = _get_display_range(im)
kwargs.setdefault('interpolation', 'nearest')
kwargs.setdefault('cmap', cmap)
kwargs.setdefault('vmin', lo)
@@ -160,8 +161,20 @@ def imshow(im, ax=None, show_cbar=None, **kwargs):
plt.colorbar(ax_im, cax=cax)
ax.set_adjustable('box-forced')
ax.get_figure().tight_layout()
return ax_im
def imshow_collection(ic, *args, **kwargs):
"""Display all images in the collection.
"""
fig, axes = plt.subplots(1, len(ic))
for n, image in enumerate(ic):
kwargs['ax'] = axes[n]
imshow(image, *args, **kwargs)
imread = plt.imread
show = plt.show
+1 -1
View File
@@ -1,3 +1,3 @@
[test]
description = Test plugin
provides = imsave, imshow, imread, imread_collection
provides = imsave, imshow, imread, imread_collection, imshow_collection
+7
View File
@@ -1,6 +1,8 @@
# This mock-up is called by ../tests/test_plugin.py
# to verify the behaviour of the plugin infrastructure
from skimage.io import ImageCollection
def imread(fname, dtype=None):
assert fname == 'test.png'
@@ -20,3 +22,8 @@ def imshow(arr, plugin_arg=None):
def imread_collection(x, conserve_memory=True):
assert conserve_memory == False
assert x == '*.png'
return ImageCollection([0, 1], load_func=lambda x: x)
def imshow_collection(x):
assert len(x) == 2
+8 -5
View File
@@ -46,7 +46,8 @@ plugin_meta_data = {}
preferred_plugins = {
# Default plugins for all types (overridden by specific types below).
'all': ['pil', 'matplotlib', 'qt', 'freeimage'],
'imshow': ['matplotlib']
'imshow': ['matplotlib'],
'imshow_collection': ['matplotlib']
}
@@ -59,13 +60,15 @@ def _clear_plugins():
'imsave': [],
'imshow': [],
'imread_collection': [],
'imshow_collection': [],
'_app_show': []}
_clear_plugins()
def _load_preferred_plugins():
# Load preferred plugin for each io function.
io_types = ['imsave', 'imshow', 'imread_collection', 'imread']
io_types = ['imsave', 'imshow', 'imread_collection', 'imshow_collection',
'imread']
for p_type in io_types:
_set_plugin(p_type, preferred_plugins['all'])
@@ -190,8 +193,8 @@ def call_plugin(kind, *args, **kwargs):
if len(plugin_funcs) == 0:
msg = ("No suitable plugin registered for %s.\n\n"
"You may load I/O plugins with the `skimage.io.use_plugin` "
"command. A list of all available plugins can be found using "
"`skimage.io.plugins()`.")
"command. A list of all available plugins are shown in the "
"`skimage.io` docstring.")
raise RuntimeError(msg % kind)
plugin = kwargs.pop('plugin', None)
@@ -216,7 +219,7 @@ def use_plugin(name, kind=None):
----------
name : str
Name of plugin.
kind : {'imsave', 'imread', 'imshow', 'imread_collection'}, optional
kind : {'imsave', 'imread', 'imshow', 'imread_collection', 'imshow_collection'}, optional
Set the plugin for this function. By default,
the plugin is set for all functions.
+2 -1
View File
@@ -41,7 +41,8 @@ def test_show():
def test_collection():
io.imread_collection('*.png', conserve_memory=False, plugin='test')
ic = io.imread_collection('*.png', conserve_memory=False, plugin='test')
io.imshow_collection(ic)
def test_use():
+9 -2
View File
@@ -56,9 +56,9 @@ Changing `size` resizes the picture.
>>> picture.size = (45, 30)
We can preview the changes we made to the picture with our earlier command:
We can preview the changes we made to the picture with the ``compare`` command:
>>> picture.show() # doctest: +SKIP
>>> picture.compare() # doctest: +SKIP
You can iterate over pixels, which have RGB values between 0 and 255,
and know their location in the picture.
@@ -88,6 +88,13 @@ True
>>> picture.modified
False
An image can also be restored to its original state after modification:
>>> picture[0:20, 0:20] = (0, 0, 0)
>>> picture.compare() # doctest: +SKIP
>>> picture.reset()
>>> picture.compare() # doctest: +SKIP
"""
from ._novice import Picture, open, colors, color_dict
+17 -2
View File
@@ -7,6 +7,7 @@ from .. import io, img_as_ubyte
from ..transform import resize
from ..color import color_dict
from ..io.util import file_or_url_context, is_url
from ..io.collection import ImageCollection
import six
from six.moves.urllib import request
@@ -303,8 +304,9 @@ class Picture(object):
@array.setter
def array(self, array):
self._array = array
self._xy_array = array_to_xy_origin(array)
self._array = array.astype(np.uint8)
self._xy_array = array_to_xy_origin(self._array)
self._array_backup = self._array.copy()
@property
def xy_array(self):
@@ -329,6 +331,12 @@ class Picture(object):
self._path = os.path.abspath(path)
self._format = imghdr.what(path)
def reset(self):
"""Reset image to its original state, removing modifications.
"""
self.array = self._array_backup
@property
def path(self):
"""The path to the picture."""
@@ -388,6 +396,13 @@ class Picture(object):
io.imshow(self.array)
io.show()
def compare(self):
"""Compare the image to its unmodified version."""
images = [self._array_backup, self.array]
ic = ImageCollection([0, 1], load_func=lambda x: images[x])
io.imshow_collection(images)
io.show()
def _makepixel(self, x, y):
"""Create a Pixel object for a given x, y location."""
rgb = self.xy_array[x, y]
+11
View File
@@ -2,6 +2,7 @@ import os
import tempfile
import numpy as np
from nose.tools import assert_true
from numpy.testing import assert_equal, raises, assert_allclose
from skimage import novice
from skimage.novice._novice import (array_to_xy_origin, xy_to_array_origin,
@@ -135,8 +136,18 @@ def test_modified_on_set_pixel():
assert pic.modified
def test_reset():
pic = novice.Picture(SMALL_IMAGE_PATH)
v = pic[0, 0]
pic[0, 0] = (1, 1, 1)
pic.reset()
assert_true(pic[0, 0] == v)
def test_update_on_save():
pic = novice.Picture(array=np.zeros((3, 3, 3)))
pic[0, 0] = (255, 255, 255) # prevent attempting to save low-contrast image
with all_warnings(): # precision loss
pic.size = (6, 6)
assert pic.modified