mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-07 01:56:59 +08:00
Merge pull request #1072 from blink1073/add-viewer-tests
Add Viewer Tests
This commit is contained in:
@@ -115,7 +115,7 @@ class CanvasToolBase(object):
|
||||
@property
|
||||
def geometry(self):
|
||||
"""Geometry information that gets passed to callback functions."""
|
||||
raise NotImplementedError
|
||||
return None
|
||||
|
||||
|
||||
class ToolHandles(object):
|
||||
|
||||
@@ -69,7 +69,7 @@ class LineTool(CanvasToolBase):
|
||||
|
||||
@property
|
||||
def end_points(self):
|
||||
return self._end_pts
|
||||
return self._end_pts.astype(int)
|
||||
|
||||
@end_points.setter
|
||||
def end_points(self, pts):
|
||||
@@ -191,7 +191,7 @@ class ThickLineTool(LineTool):
|
||||
self.callback_on_change(self.geometry)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == '__main__': # pragma: no cover
|
||||
import matplotlib.pyplot as plt
|
||||
from skimage import data
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@ class CenteredWindow(object):
|
||||
return [slice(ymin, ymax), slice(xmin, xmax)]
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == '__main__': # pragma: no cover
|
||||
np.testing.rundocs()
|
||||
from skimage import data
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ class RectangleTool(CanvasToolBase, RectangleSelector):
|
||||
return self.extents
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == '__main__': # pragma: no cover
|
||||
import matplotlib.pyplot as plt
|
||||
from skimage import data
|
||||
|
||||
|
||||
@@ -239,7 +239,8 @@ class Plugin(QtGui.QDialog):
|
||||
|
||||
def clean_up(self):
|
||||
self.remove_image_artists()
|
||||
self.image_viewer.plugins.remove(self)
|
||||
if self in self.image_viewer.plugins:
|
||||
self.image_viewer.plugins.remove(self)
|
||||
self.image_viewer.reset_image()
|
||||
self.image_viewer.redraw()
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ class LineProfile(PlotPlugin):
|
||||
if self._limit_type == 'image':
|
||||
self.limits = (np.min(image), np.max(image))
|
||||
elif self._limit_type == 'dtype':
|
||||
self._limit_type = dtype_range[image.dtype.type]
|
||||
self.limits = dtype_range[image.dtype.type]
|
||||
elif self._limit_type is None or len(self._limit_type) == 2:
|
||||
self.limits = self._limit_type
|
||||
else:
|
||||
@@ -91,6 +91,7 @@ class LineProfile(PlotPlugin):
|
||||
profile: list of 1d arrays
|
||||
Profile of intensity values. Length 1 (grayscale) or 3 (rgb).
|
||||
"""
|
||||
self._update_data()
|
||||
profiles = [data.get_ydata() for data in self.profile]
|
||||
return self.line_tool.end_points, profiles
|
||||
|
||||
@@ -103,8 +104,15 @@ class LineProfile(PlotPlugin):
|
||||
def line_changed(self, end_points):
|
||||
x, y = np.transpose(end_points)
|
||||
self.line_tool.end_points = end_points
|
||||
scan = measure.profile_line(self.image_viewer.original_image,
|
||||
*end_points[:, ::-1],
|
||||
self._update_data()
|
||||
self.ax.relim()
|
||||
|
||||
self._autoscale_view()
|
||||
self.redraw()
|
||||
|
||||
def _update_data(self):
|
||||
scan = measure.profile_line(self.image_viewer.image,
|
||||
*self.line_tool.end_points[:, ::-1],
|
||||
linewidth=self.line_tool.linewidth)
|
||||
self.scan_data = scan
|
||||
if scan.ndim == 1:
|
||||
@@ -117,11 +125,6 @@ class LineProfile(PlotPlugin):
|
||||
self.profile[i].set_xdata(np.arange(scan.shape[0]))
|
||||
self.profile[i].set_ydata(scan[:, i])
|
||||
|
||||
self.ax.relim()
|
||||
|
||||
self._autoscale_view()
|
||||
self.redraw()
|
||||
|
||||
def reset_axes(self, scan_data):
|
||||
# Clear lines out
|
||||
for line in self.ax.lines:
|
||||
@@ -147,7 +150,7 @@ class LineProfile(PlotPlugin):
|
||||
The line scan values across the image.
|
||||
"""
|
||||
end_points = self.line_tool.end_points
|
||||
line_image = np.zeros(self.image_viewer.original_image.shape[:2],
|
||||
line_image = np.zeros(self.image_viewer.image.shape[:2],
|
||||
np.uint8)
|
||||
width = self.line_tool.linewidth
|
||||
if width > 1:
|
||||
@@ -162,4 +165,3 @@ class LineProfile(PlotPlugin):
|
||||
rr, cc = draw.line(y1, x1, y2, x2)
|
||||
line_image[rr, cc] = 255
|
||||
return line_image, self.scan_data
|
||||
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import numpy as np
|
||||
import skimage
|
||||
import skimage.data as data
|
||||
from skimage.filter.rank import median
|
||||
from skimage.morphology import disk
|
||||
from numpy.testing import assert_equal, assert_allclose, assert_almost_equal
|
||||
from numpy.testing.decorators import skipif
|
||||
|
||||
try:
|
||||
from skimage.viewer.qt import qt_api
|
||||
from skimage.viewer import ImageViewer
|
||||
from skimage.viewer.plugins import (
|
||||
LineProfile, Measure, CannyPlugin, LabelPainter, Crop, ColorHistogram,
|
||||
PlotPlugin)
|
||||
from skimage.viewer.plugins.base import Plugin
|
||||
from skimage.viewer.widgets import Slider
|
||||
viewer_available = not qt_api is None
|
||||
except ImportError:
|
||||
viewer_available = False
|
||||
|
||||
|
||||
def setup_line_profile(image, limits='image'):
|
||||
viewer = ImageViewer(skimage.img_as_float(image))
|
||||
plugin = LineProfile(limits=limits)
|
||||
viewer += plugin
|
||||
return plugin
|
||||
|
||||
|
||||
@skipif(not viewer_available)
|
||||
def test_line_profile():
|
||||
""" Test a line profile using an ndim=2 image"""
|
||||
plugin = setup_line_profile(data.camera())
|
||||
line_image, scan_data = plugin.output()
|
||||
for inp in [line_image.nonzero()[0].size,
|
||||
line_image.sum() / line_image.max(),
|
||||
scan_data.size]:
|
||||
assert_equal(inp, 172)
|
||||
assert_equal(line_image.shape, (512, 512))
|
||||
assert_allclose(scan_data.max(), 0.9176, rtol=1e-3)
|
||||
assert_allclose(scan_data.mean(), 0.2812, rtol=1e-3)
|
||||
|
||||
|
||||
@skipif(not viewer_available)
|
||||
def test_line_profile_rgb():
|
||||
""" Test a line profile using an ndim=3 image"""
|
||||
plugin = setup_line_profile(data.chelsea(), limits=None)
|
||||
for i in range(6):
|
||||
plugin.line_tool._thicken_scan_line()
|
||||
line_image, scan_data = plugin.output()
|
||||
assert_equal(line_image[line_image == 128].size, 750)
|
||||
assert_equal(line_image[line_image == 255].size, 151)
|
||||
assert_equal(line_image.shape, (300, 451))
|
||||
assert_equal(scan_data.shape, (151, 3))
|
||||
assert_allclose(scan_data.max(), 0.772, rtol=1e-3)
|
||||
assert_allclose(scan_data.mean(), 0.4359, rtol=1e-3)
|
||||
|
||||
|
||||
@skipif(not viewer_available)
|
||||
def test_line_profile_dynamic():
|
||||
"""Test a line profile updating after an image transform"""
|
||||
image = data.coins()[:-50, :] # shave some off to make the line lower
|
||||
image = skimage.img_as_float(image)
|
||||
viewer = ImageViewer(image)
|
||||
|
||||
lp = LineProfile(limits='dtype')
|
||||
viewer += lp
|
||||
|
||||
line = lp.get_profiles()[-1][0]
|
||||
assert line.size == 129
|
||||
assert_almost_equal(np.std(viewer.image), 0.208, 3)
|
||||
assert_almost_equal(np.std(line), 0.229, 3)
|
||||
assert_almost_equal(np.max(line) - np.min(line), 0.725, 1)
|
||||
|
||||
viewer.image = skimage.img_as_float(median(image,
|
||||
selem=disk(radius=3)))
|
||||
|
||||
line = lp.get_profiles()[-1][0]
|
||||
assert_almost_equal(np.std(viewer.image), 0.198, 3)
|
||||
assert_almost_equal(np.std(line), 0.220, 3)
|
||||
assert_almost_equal(np.max(line) - np.min(line), 0.639, 1)
|
||||
|
||||
|
||||
@skipif(not viewer_available)
|
||||
def test_measure():
|
||||
image = data.camera()
|
||||
viewer = ImageViewer(image)
|
||||
m = Measure()
|
||||
viewer += m
|
||||
|
||||
m.line_changed([(0, 0), (10, 10)])
|
||||
assert_equal(str(m._length.text), '14.1')
|
||||
assert_equal(str(m._angle.text[:5]), '135.0')
|
||||
|
||||
|
||||
@skipif(not viewer_available)
|
||||
def test_canny():
|
||||
image = data.camera()
|
||||
viewer = ImageViewer(image)
|
||||
c = CannyPlugin()
|
||||
viewer += c
|
||||
|
||||
canny_edges = viewer.show(False)
|
||||
viewer.close()
|
||||
edges = canny_edges[0][0]
|
||||
assert edges.sum() == 2852
|
||||
|
||||
|
||||
@skipif(not viewer_available)
|
||||
def test_label_painter():
|
||||
image = data.camera()
|
||||
moon = data.moon()
|
||||
viewer = ImageViewer(image)
|
||||
lp = LabelPainter()
|
||||
viewer += lp
|
||||
|
||||
assert_equal(lp.radius, 5)
|
||||
lp.label = 1
|
||||
assert_equal(str(lp.label), '1')
|
||||
lp.label = 2
|
||||
assert_equal(str(lp.paint_tool.label), '2')
|
||||
assert_equal(lp.paint_tool.radius, 5)
|
||||
lp._on_new_image(moon)
|
||||
assert_equal(lp.paint_tool.shape, moon.shape)
|
||||
|
||||
|
||||
@skipif(not viewer_available)
|
||||
def test_crop():
|
||||
image = data.camera()
|
||||
viewer = ImageViewer(image)
|
||||
c = Crop()
|
||||
viewer += c
|
||||
|
||||
c.crop((0, 100, 0, 100))
|
||||
assert_equal(viewer.image.shape, (101, 101))
|
||||
|
||||
|
||||
@skipif(not viewer_available)
|
||||
def test_color_histogram():
|
||||
image = skimage.img_as_float(data.load('color.png'))
|
||||
viewer = ImageViewer(image)
|
||||
ch = ColorHistogram(dock='right')
|
||||
viewer += ch
|
||||
|
||||
assert_almost_equal(viewer.image.std(), 0.352, 3),
|
||||
ch.ab_selected((0, 100, 0, 100)),
|
||||
assert_almost_equal(viewer.image.std(), 0.325, 3)
|
||||
|
||||
|
||||
@skipif(not viewer_available)
|
||||
def test_plot_plugin():
|
||||
viewer = ImageViewer(data.moon())
|
||||
plugin = PlotPlugin(image_filter=lambda x: x)
|
||||
viewer += plugin
|
||||
|
||||
assert_equal(viewer.image, data.moon())
|
||||
plugin._update_original_image(data.coins())
|
||||
assert_equal(viewer.image, data.coins())
|
||||
viewer.close()
|
||||
|
||||
|
||||
@skipif(not viewer_available)
|
||||
def test_plugin():
|
||||
img = skimage.img_as_float(data.moon())
|
||||
viewer = ImageViewer(img)
|
||||
|
||||
def median_filter(img, radius=3):
|
||||
return median(img, selem=disk(radius=radius))
|
||||
|
||||
plugin = Plugin(image_filter=median_filter)
|
||||
viewer += plugin
|
||||
|
||||
plugin += Slider('radius', 1, 5)
|
||||
|
||||
assert_almost_equal(np.std(viewer.image), 12.556, 3)
|
||||
|
||||
plugin.filter_image()
|
||||
|
||||
assert_almost_equal(np.std(viewer.image), 12.931, 3)
|
||||
|
||||
plugin.show()
|
||||
plugin.close()
|
||||
plugin.clean_up()
|
||||
img, _ = plugin.output()
|
||||
assert_equal(img, viewer.image)
|
||||
@@ -0,0 +1,213 @@
|
||||
from collections import namedtuple
|
||||
|
||||
import numpy as np
|
||||
from skimage import data
|
||||
from numpy.testing import assert_equal
|
||||
from numpy.testing.decorators import skipif
|
||||
|
||||
try:
|
||||
from skimage.viewer.qt import qt_api
|
||||
from skimage.viewer import ImageViewer
|
||||
from skimage.viewer.canvastools import (
|
||||
LineTool, ThickLineTool, RectangleTool, PaintTool)
|
||||
from skimage.viewer.canvastools.base import CanvasToolBase
|
||||
viewer_available = not qt_api is None
|
||||
except ImportError:
|
||||
viewer_available = False
|
||||
|
||||
|
||||
def get_end_points(image):
|
||||
h, w = image.shape[0:2]
|
||||
x = [w / 3, 2 * w / 3]
|
||||
y = [h / 2] * 2
|
||||
return np.transpose([x, y])
|
||||
|
||||
|
||||
def create_mouse_event(ax, button=1, xdata=0, ydata=0, key=None):
|
||||
"""
|
||||
*name*
|
||||
the event name
|
||||
|
||||
*canvas*
|
||||
the FigureCanvas instance generating the event
|
||||
|
||||
*guiEvent*
|
||||
the GUI event that triggered the matplotlib event
|
||||
|
||||
*x*
|
||||
x position - pixels from left of canvas
|
||||
|
||||
*y*
|
||||
y position - pixels from bottom of canvas
|
||||
|
||||
*inaxes*
|
||||
the :class:`~matplotlib.axes.Axes` instance if mouse is over axes
|
||||
|
||||
*xdata*
|
||||
x coord of mouse in data coords
|
||||
|
||||
*ydata*
|
||||
y coord of mouse in data coords
|
||||
|
||||
*button*
|
||||
button pressed None, 1, 2, 3, 'up', 'down' (up and down are used
|
||||
for scroll events)
|
||||
|
||||
*key*
|
||||
the key depressed when the mouse event triggered (see
|
||||
:class:`KeyEvent`)
|
||||
|
||||
*step*
|
||||
number of scroll steps (positive for 'up', negative for 'down')
|
||||
"""
|
||||
event = namedtuple('Event',
|
||||
('name canvas guiEvent x y inaxes xdata ydata '
|
||||
'button key step'))
|
||||
event.button = button
|
||||
event.x, event.y = ax.transData.transform((xdata, ydata))
|
||||
event.xdata, event.ydata = xdata, ydata
|
||||
event.inaxes = ax
|
||||
event.canvas = ax.figure.canvas
|
||||
event.key = key
|
||||
event.step = 1
|
||||
event.guiEvent = None
|
||||
event.name = 'Custom'
|
||||
return event
|
||||
|
||||
|
||||
@skipif(not viewer_available)
|
||||
def test_line_tool():
|
||||
img = data.camera()
|
||||
viewer = ImageViewer(img)
|
||||
|
||||
tool = LineTool(viewer.ax, maxdist=10)
|
||||
tool.end_points = get_end_points(img)
|
||||
assert_equal(tool.end_points, np.array([[170, 256], [341, 256]]))
|
||||
|
||||
# grab a handle and move it
|
||||
grab = create_mouse_event(viewer.ax, xdata=170, ydata=256)
|
||||
tool.on_mouse_press(grab)
|
||||
move = create_mouse_event(viewer.ax, xdata=180, ydata=260)
|
||||
tool.on_move(move)
|
||||
tool.on_mouse_release(move)
|
||||
assert_equal(tool.geometry, np.array([[180, 260], [341, 256]]))
|
||||
|
||||
# create a new line
|
||||
new = create_mouse_event(viewer.ax, xdata=10, ydata=10)
|
||||
tool.on_mouse_press(new)
|
||||
move = create_mouse_event(viewer.ax, xdata=100, ydata=100)
|
||||
tool.on_move(move)
|
||||
tool.on_mouse_release(move)
|
||||
assert_equal(tool.geometry, np.array([[100, 100], [10, 10]]))
|
||||
|
||||
|
||||
@skipif(not viewer_available)
|
||||
def test_thick_line_tool():
|
||||
img = data.camera()
|
||||
viewer = ImageViewer(img)
|
||||
|
||||
tool = ThickLineTool(viewer.ax, maxdist=10)
|
||||
tool.end_points = get_end_points(img)
|
||||
|
||||
scroll_up = create_mouse_event(viewer.ax, button='up')
|
||||
tool.on_scroll(scroll_up)
|
||||
assert_equal(tool.linewidth, 2)
|
||||
|
||||
scroll_down = create_mouse_event(viewer.ax, button='down')
|
||||
tool.on_scroll(scroll_down)
|
||||
assert_equal(tool.linewidth, 1)
|
||||
|
||||
key_up = create_mouse_event(viewer.ax, key='+')
|
||||
tool.on_key_press(key_up)
|
||||
assert_equal(tool.linewidth, 2)
|
||||
|
||||
key_down = create_mouse_event(viewer.ax, key='-')
|
||||
tool.on_key_press(key_down)
|
||||
assert_equal(tool.linewidth, 1)
|
||||
|
||||
|
||||
@skipif(not viewer_available)
|
||||
def test_rect_tool():
|
||||
img = data.camera()
|
||||
viewer = ImageViewer(img)
|
||||
|
||||
tool = RectangleTool(viewer.ax, maxdist=10)
|
||||
tool.extents = (100, 150, 100, 150)
|
||||
|
||||
assert_equal(tool.corners,
|
||||
((100, 150, 150, 100), (100, 100, 150, 150)))
|
||||
assert_equal(tool.extents, (100, 150, 100, 150))
|
||||
assert_equal(tool.edge_centers,
|
||||
((100, 125.0, 150, 125.0), (125.0, 100, 125.0, 150)))
|
||||
assert_equal(tool.geometry, (100, 150, 100, 150))
|
||||
|
||||
# grab a corner and move it
|
||||
grab = create_mouse_event(viewer.ax, xdata=100, ydata=100)
|
||||
tool.press(grab)
|
||||
move = create_mouse_event(viewer.ax, xdata=120, ydata=120)
|
||||
tool.onmove(move)
|
||||
tool.release(move)
|
||||
assert_equal(tool.geometry, [120, 150, 120, 150])
|
||||
|
||||
# create a new line
|
||||
new = create_mouse_event(viewer.ax, xdata=10, ydata=10)
|
||||
tool.press(new)
|
||||
move = create_mouse_event(viewer.ax, xdata=100, ydata=100)
|
||||
tool.onmove(move)
|
||||
tool.release(move)
|
||||
assert_equal(tool.geometry, [10, 100, 10, 100])
|
||||
|
||||
|
||||
@skipif(not viewer_available)
|
||||
def test_paint_tool():
|
||||
img = data.moon()
|
||||
viewer = ImageViewer(img)
|
||||
|
||||
tool = PaintTool(viewer.ax, img.shape)
|
||||
|
||||
tool.radius = 10
|
||||
assert_equal(tool.radius, 10)
|
||||
tool.label = 2
|
||||
assert_equal(tool.label, 2)
|
||||
assert_equal(tool.shape, img.shape)
|
||||
|
||||
start = create_mouse_event(viewer.ax, xdata=100, ydata=100)
|
||||
tool.on_mouse_press(start)
|
||||
move = create_mouse_event(viewer.ax, xdata=110, ydata=110)
|
||||
tool.on_move(move)
|
||||
tool.on_mouse_release(move)
|
||||
assert_equal(tool.overlay[tool.overlay == 2].size, 761)
|
||||
|
||||
tool.label = 5
|
||||
start = create_mouse_event(viewer.ax, xdata=20, ydata=20)
|
||||
tool.on_mouse_press(start)
|
||||
move = create_mouse_event(viewer.ax, xdata=40, ydata=40)
|
||||
tool.on_move(move)
|
||||
tool.on_mouse_release(move)
|
||||
assert_equal(tool.overlay[tool.overlay == 5].size, 881)
|
||||
assert_equal(tool.overlay[tool.overlay == 2].size, 761)
|
||||
|
||||
enter = create_mouse_event(viewer.ax, key='enter')
|
||||
tool.on_mouse_press(enter)
|
||||
|
||||
tool.overlay = tool.overlay * 0
|
||||
assert_equal(tool.overlay.sum(), 0)
|
||||
|
||||
|
||||
@skipif(not viewer_available)
|
||||
def test_base_tool():
|
||||
img = data.moon()
|
||||
viewer = ImageViewer(img)
|
||||
|
||||
tool = CanvasToolBase(viewer.ax)
|
||||
tool.set_visible(False)
|
||||
tool.set_visible(True)
|
||||
|
||||
enter = create_mouse_event(viewer.ax, key='enter')
|
||||
tool._on_key_press(enter)
|
||||
|
||||
tool.redraw()
|
||||
tool.remove()
|
||||
|
||||
tool = CanvasToolBase(viewer.ax, useblit=False)
|
||||
tool.redraw()
|
||||
@@ -0,0 +1,43 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy.testing.decorators import skipif
|
||||
|
||||
try:
|
||||
from skimage.viewer.qt import qt_api, QtCore, QtGui
|
||||
from skimage.viewer import utils
|
||||
from skimage.viewer.utils import dialogs
|
||||
except ImportError:
|
||||
qt_api = None
|
||||
|
||||
|
||||
@skipif(qt_api is None)
|
||||
def test_event_loop():
|
||||
utils.init_qtapp()
|
||||
timer = QtCore.QTimer()
|
||||
timer.singleShot(10, QtGui.QApplication.quit)
|
||||
utils.start_qtapp()
|
||||
|
||||
|
||||
@skipif(qt_api is None)
|
||||
def test_format_filename():
|
||||
fname = dialogs._format_filename(('apple', 2))
|
||||
assert fname == 'apple'
|
||||
fname = dialogs._format_filename('')
|
||||
assert fname is None
|
||||
|
||||
|
||||
@skipif(qt_api is None)
|
||||
def test_open_file_dialog():
|
||||
utils.init_qtapp()
|
||||
timer = QtCore.QTimer()
|
||||
timer.singleShot(10, QtGui.QApplication.quit)
|
||||
filename = dialogs.open_file_dialog()
|
||||
assert filename is None
|
||||
|
||||
|
||||
@skipif(qt_api is None)
|
||||
def test_save_file_dialog():
|
||||
utils.init_qtapp()
|
||||
timer = QtCore.QTimer()
|
||||
timer.singleShot(10, QtGui.QApplication.quit)
|
||||
filename = dialogs.save_file_dialog()
|
||||
assert filename is None
|
||||
@@ -1,48 +1,83 @@
|
||||
import skimage
|
||||
import skimage.data as data
|
||||
from skimage.viewer import ImageViewer
|
||||
from skimage.viewer.qt import qt_api
|
||||
from numpy.testing import assert_equal, assert_allclose
|
||||
|
||||
from skimage import data
|
||||
from skimage.transform import pyramid_gaussian
|
||||
from skimage.filter import sobel
|
||||
from numpy.testing import assert_equal
|
||||
from numpy.testing.decorators import skipif
|
||||
|
||||
|
||||
def setup_line_profile(image):
|
||||
from skimage.viewer.plugins.lineprofile import LineProfile
|
||||
viewer = ImageViewer(skimage.img_as_float(image))
|
||||
plugin = LineProfile()
|
||||
viewer += plugin
|
||||
return plugin
|
||||
try:
|
||||
from skimage.viewer.qt import qt_api, QtGui, QtCore
|
||||
from skimage.viewer.plugins import OverlayPlugin
|
||||
from skimage.viewer.plugins.overlayplugin import recent_mpl_version
|
||||
from skimage.viewer import ImageViewer, CollectionViewer
|
||||
viewer_available = not qt_api is None
|
||||
except ImportError:
|
||||
viewer_available = False
|
||||
|
||||
|
||||
@skipif(qt_api is None)
|
||||
def test_line_profile():
|
||||
""" Test a line profile using an ndim=2 image"""
|
||||
plugin = setup_line_profile(data.camera())
|
||||
line_image, scan_data = plugin.output()
|
||||
for inp in [line_image.nonzero()[0].size,
|
||||
line_image.sum() / line_image.max(),
|
||||
scan_data.size]:
|
||||
assert_equal(inp, 172)
|
||||
assert_equal(line_image.shape, (512, 512))
|
||||
assert_allclose(scan_data.max(), 0.9139, rtol=1e-3)
|
||||
assert_allclose(scan_data.mean(), 0.2828, rtol=1e-3)
|
||||
@skipif(not viewer_available)
|
||||
def test_viewer():
|
||||
lena = data.lena()
|
||||
coins = data.coins()
|
||||
|
||||
view = ImageViewer(lena)
|
||||
import tempfile
|
||||
_, filename = tempfile.mkstemp(suffix='.png')
|
||||
|
||||
view.show(False)
|
||||
view.close()
|
||||
view.save_to_file(filename)
|
||||
view.open_file(filename)
|
||||
assert_equal(view.image, lena)
|
||||
view.image = coins
|
||||
assert_equal(view.image, coins),
|
||||
view.save_to_file(filename),
|
||||
view.open_file(filename),
|
||||
view.reset_image(),
|
||||
assert_equal(view.image, coins)
|
||||
|
||||
|
||||
@skipif(qt_api is None)
|
||||
def test_line_profile_rgb():
|
||||
""" Test a line profile using an ndim=3 image"""
|
||||
plugin = setup_line_profile(data.chelsea())
|
||||
for i in range(6):
|
||||
plugin.line_tool._thicken_scan_line()
|
||||
line_image, scan_data = plugin.output()
|
||||
assert_equal(line_image[line_image == 128].size, 755)
|
||||
assert_equal(line_image[line_image == 255].size, 151)
|
||||
assert_equal(line_image.shape, (300, 451))
|
||||
assert_equal(scan_data.shape, (152, 3))
|
||||
assert_allclose(scan_data.max(), 0.772, rtol=1e-3)
|
||||
assert_allclose(scan_data.mean(), 0.4355, rtol=1e-3)
|
||||
def make_key_event(key):
|
||||
return QtGui.QKeyEvent(QtCore.QEvent.KeyPress, key,
|
||||
QtCore.Qt.NoModifier)
|
||||
|
||||
|
||||
@skipif(not viewer_available)
|
||||
def test_collection_viewer():
|
||||
|
||||
img = data.lena()
|
||||
img_collection = tuple(pyramid_gaussian(img))
|
||||
|
||||
view = CollectionViewer(img_collection)
|
||||
make_key_event(48)
|
||||
|
||||
view.update_index('', 2),
|
||||
assert_equal(view.image, img_collection[2])
|
||||
view.keyPressEvent(make_key_event(53))
|
||||
assert_equal(view.image, img_collection[5])
|
||||
view._format_coord(10, 10)
|
||||
|
||||
|
||||
@skipif(not viewer_available or not recent_mpl_version())
|
||||
def test_viewer_with_overlay():
|
||||
img = data.coins()
|
||||
ov = OverlayPlugin(image_filter=sobel)
|
||||
viewer = ImageViewer(img)
|
||||
viewer += ov
|
||||
|
||||
import tempfile
|
||||
_, filename = tempfile.mkstemp(suffix='.png')
|
||||
|
||||
ov.color = 2
|
||||
assert_equal(ov.color, 'yellow')
|
||||
viewer.save_to_file(filename)
|
||||
ov.display_filtered_image(img)
|
||||
assert_equal(ov.overlay, img)
|
||||
ov.overlay = None
|
||||
assert_equal(ov.overlay, None)
|
||||
ov.overlay = img
|
||||
assert_equal(ov.overlay, img)
|
||||
assert_equal(ov.filtered_image, img)
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from numpy.testing import run_module_suite
|
||||
run_module_suite()
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
|
||||
import os
|
||||
from skimage import data, img_as_float, io
|
||||
from numpy.testing import assert_almost_equal, assert_equal
|
||||
from numpy.testing.decorators import skipif
|
||||
|
||||
try:
|
||||
from skimage.viewer.qt import qt_api, QtGui, QtCore
|
||||
from skimage.viewer import ImageViewer
|
||||
from skimage.viewer.widgets import (
|
||||
Slider, OKCancelButtons, SaveButtons, ComboBox, Text)
|
||||
from skimage.viewer.plugins.base import Plugin
|
||||
viewer_available = not qt_api is None
|
||||
except ImportError:
|
||||
viewer_available = False
|
||||
|
||||
|
||||
def get_image_viewer():
|
||||
image = data.coins()
|
||||
viewer = ImageViewer(img_as_float(image))
|
||||
viewer += Plugin()
|
||||
return viewer
|
||||
|
||||
|
||||
@skipif(not viewer_available)
|
||||
def test_combo_box():
|
||||
viewer = get_image_viewer()
|
||||
cb = ComboBox('hello', ('a', 'b', 'c'))
|
||||
viewer.plugins[0] += cb
|
||||
|
||||
assert_equal(str(cb.val), 'a')
|
||||
assert_equal(cb.index, 0)
|
||||
cb.index = 2
|
||||
assert_equal(str(cb.val), 'c'),
|
||||
assert_equal(cb.index, 2)
|
||||
|
||||
|
||||
@skipif(not viewer_available)
|
||||
def test_text_widget():
|
||||
viewer = get_image_viewer()
|
||||
txt = Text('hello', 'hello, world!')
|
||||
viewer.plugins[0] += txt
|
||||
|
||||
assert_equal(str(txt.text), 'hello, world!')
|
||||
txt.text = 'goodbye, world!'
|
||||
assert_equal(str(txt.text), 'goodbye, world!')
|
||||
|
||||
|
||||
@skipif(not viewer_available)
|
||||
def test_slider_int():
|
||||
viewer = get_image_viewer()
|
||||
sld = Slider('radius', 2, 10, value_type='int')
|
||||
viewer.plugins[0] += sld
|
||||
|
||||
assert_equal(sld.val, 4)
|
||||
sld.val = 6
|
||||
assert_equal(sld.val, 6)
|
||||
sld.editbox.setText('5')
|
||||
sld._on_editbox_changed()
|
||||
assert_equal(sld.val, 5)
|
||||
|
||||
|
||||
@skipif(not viewer_available)
|
||||
def test_slider_float():
|
||||
viewer = get_image_viewer()
|
||||
sld = Slider('alpha', 2.1, 3.1, value=2.1, value_type='float',
|
||||
orientation='vertical', update_on='move')
|
||||
viewer.plugins[0] += sld
|
||||
|
||||
assert_equal(sld.val, 2.1)
|
||||
sld.val = 2.5
|
||||
assert_almost_equal(sld.val, 2.5, 2)
|
||||
sld.editbox.setText('0.1')
|
||||
sld._on_editbox_changed()
|
||||
assert_almost_equal(sld.val, 2.5, 2)
|
||||
|
||||
|
||||
@skipif(not viewer_available)
|
||||
def test_save_buttons():
|
||||
viewer = get_image_viewer()
|
||||
sv = SaveButtons()
|
||||
viewer.plugins[0] += sv
|
||||
|
||||
import tempfile
|
||||
_, filename = tempfile.mkstemp(suffix='.png')
|
||||
os.remove(filename)
|
||||
|
||||
timer = QtCore.QTimer()
|
||||
timer.singleShot(100, lambda: QtGui.QApplication.quit())
|
||||
|
||||
sv.save_to_stack()
|
||||
sv.save_to_file(filename)
|
||||
|
||||
img = img_as_float(data.imread(filename))
|
||||
assert_almost_equal(img, viewer.image)
|
||||
|
||||
img = io.pop()
|
||||
assert_almost_equal(img, viewer.image)
|
||||
|
||||
|
||||
@skipif(not viewer_available)
|
||||
def test_ok_buttons():
|
||||
viewer = get_image_viewer()
|
||||
ok = OKCancelButtons()
|
||||
viewer.plugins[0] += ok
|
||||
|
||||
ok.update_original_image(),
|
||||
ok.close_plugin()
|
||||
|
||||
@@ -174,9 +174,10 @@ class ImageViewer(QtGui.QMainWindow):
|
||||
h = viewer_size.height()
|
||||
self.resize(w + dx, h + dy)
|
||||
|
||||
def open_file(self):
|
||||
def open_file(self, filename=None):
|
||||
"""Open image file and display in viewer."""
|
||||
filename = dialogs.open_file_dialog()
|
||||
if filename is None:
|
||||
filename = dialogs.open_file_dialog()
|
||||
if filename is None:
|
||||
return
|
||||
image = io.imread(filename)
|
||||
@@ -187,7 +188,7 @@ class ImageViewer(QtGui.QMainWindow):
|
||||
self.image = image.copy() # update displayed image
|
||||
self.original_image_changed.emit(image)
|
||||
|
||||
def save_to_file(self):
|
||||
def save_to_file(self, filename=None):
|
||||
"""Save current image to file.
|
||||
|
||||
The current behavior is not ideal: It saves the image displayed on
|
||||
@@ -195,7 +196,8 @@ class ImageViewer(QtGui.QMainWindow):
|
||||
not preserved (resizing the viewer window will alter the size of the
|
||||
saved image).
|
||||
"""
|
||||
filename = dialogs.save_file_dialog()
|
||||
if filename is None:
|
||||
filename = dialogs.save_file_dialog()
|
||||
if filename is None:
|
||||
return
|
||||
if len(self.ax.images) == 1:
|
||||
|
||||
@@ -244,7 +244,7 @@ class ComboBox(BaseWidget):
|
||||
|
||||
@property
|
||||
def val(self):
|
||||
return self._combo_box.value()
|
||||
return self._combo_box.currentText()
|
||||
|
||||
@property
|
||||
def index(self):
|
||||
|
||||
@@ -81,8 +81,9 @@ class SaveButtons(BaseWidget):
|
||||
NOTE: The io stack only works in interactive sessions.''')
|
||||
notify(msg)
|
||||
|
||||
def save_to_file(self):
|
||||
filename = dialogs.save_file_dialog()
|
||||
def save_to_file(self, filename=None):
|
||||
if filename is None:
|
||||
filename = dialogs.save_file_dialog()
|
||||
if filename is None:
|
||||
return
|
||||
image = self.plugin.filtered_image
|
||||
|
||||
Reference in New Issue
Block a user