From f47312a3d1f730ca8766dcbe4a2bbefc0b14fcfd Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Mon, 23 Jul 2012 00:12:21 -0400 Subject: [PATCH] API Change: Attach ImageViewer to Plugin after init. Plugin is now added to the viewer using an inplace add on the viewer instead of on initialization of the plugin. This change means that operations requiring the viewer must be delayed until attach operation. --- skimage/viewer/plugins/base.py | 25 +++++++------ skimage/viewer/plugins/canny.py | 13 ++++--- skimage/viewer/plugins/lineprofile.py | 47 +++++++++++++------------ skimage/viewer/plugins/overlayplugin.py | 7 ++-- skimage/viewer/plugins/plotplugin.py | 5 +-- skimage/viewer/viewers/core.py | 4 +++ viewer_examples/plugins/canny.py | 2 +- viewer_examples/plugins/lineprofile.py | 2 +- 8 files changed, 61 insertions(+), 44 deletions(-) diff --git a/skimage/viewer/plugins/base.py b/skimage/viewer/plugins/base.py index 17387b8b..ba68ecb6 100644 --- a/skimage/viewer/plugins/base.py +++ b/skimage/viewer/plugins/base.py @@ -1,4 +1,5 @@ from PyQt4 import QtGui +from PyQt4.QtCore import Qt import matplotlib as mpl @@ -23,17 +24,13 @@ class Plugin(QtGui.QDialog): ---------- image_viewer : ImageViewer Window containing image used in measurement. - image : array - Image used in measurement/manipulation. """ name = 'Plugin' draws_on_image = False - def __init__(self, image_viewer, image_filter=None, height=100, width=400, - useblit=None): - self.image_viewer = image_viewer - QtGui.QDialog.__init__(self, image_viewer) - self.image_viewer.plugins.append(self) + def __init__(self, image_filter=None, height=100, width=400, useblit=None): + QtGui.QDialog.__init__(self) + self.image_viewer = None self.setWindowTitle(self.name) self.layout = QtGui.QGridLayout(self) @@ -42,18 +39,24 @@ class Plugin(QtGui.QDialog): if image_filter is not None: self.image_filter = image_filter - #TODO: Always passing image as first argument may be bad assumption. - self.arguments = [image_viewer.original_image] + self.arguments = [] self.keyword_arguments= {} - self.image = self.image_viewer.image - if useblit is None: useblit = True if mpl.backends.backend.endswith('Agg') else False self.useblit = useblit self.cids = [] self.artists = [] + def attach(self, image_viewer): + self.setParent(image_viewer) + self.setWindowFlags(Qt.Dialog) + + self.image_viewer = image_viewer + self.image_viewer.plugins.append(self) + #TODO: Always passing image as first argument may be bad assumption. + self.arguments.append(self.image_viewer.original_image) + if self.draws_on_image: self.connect_event('draw_event', self.on_draw) diff --git a/skimage/viewer/plugins/canny.py b/skimage/viewer/plugins/canny.py index 97465e6a..5ec6e415 100644 --- a/skimage/viewer/plugins/canny.py +++ b/skimage/viewer/plugins/canny.py @@ -8,15 +8,18 @@ class CannyPlugin(OverlayPlugin): name = 'Canny Filter' - def __init__(self, image_viewer, *args, **kwargs): - height = kwargs.get('height', 100) - width = kwargs.get('width', 400) - super(CannyPlugin, self).__init__(image_viewer, - width=width, height=height) + def __init__(self, *args, **kwargs): + kwargs.setdefault('height', 100) + kwargs.setdefault('width', 400) + super(CannyPlugin, self).__init__(**kwargs) + self.add_widget(Slider('sigma', 0, 5, update_on='release')) self.add_widget(Slider('low threshold', 0, 255, update_on='release')) self.add_widget(Slider('high threshold', 0, 255, update_on='release')) self.add_widget(ComboBox('color', self.color_names, ptype='plugin')) + + def attach(self, image_viewer): + super(CannyPlugin, self).attach(image_viewer) # Update image overlay to default slider values. self.filter_image() diff --git a/skimage/viewer/plugins/lineprofile.py b/skimage/viewer/plugins/lineprofile.py index 32ea967d..f41407b3 100644 --- a/skimage/viewer/plugins/lineprofile.py +++ b/skimage/viewer/plugins/lineprofile.py @@ -33,43 +33,46 @@ class LineProfile(PlotPlugin): name = 'Line Profile' draws_on_image = True - def __init__(self, image_viewer, useblit=None, - linewidth=1, epsilon=5, limits='image'): - super(LineProfile, self).__init__(image_viewer, height=200, width=600, + def __init__(self, useblit=None, linewidth=1, epsilon=5, limits='image'): + super(LineProfile, self).__init__(height=200, width=600, useblit=useblit) - self.linewidth = linewidth self.epsilon = epsilon + self._active_pt = None + self._limit_type = limits + self.line_kwargs = dict(color='y', lw=linewidth, alpha=0.5, marker='s', + markersize=5, solid_capstyle='butt') + print self.help() - if limits == 'image': - self.limits = (np.min(self.image), np.max(self.image)) - elif limits == 'dtype': - self.limits = dtype_range[self.image.dtype.type] - elif limits is None or len(limits) == 2: - self.limits = limits + def attach(self, image_viewer): + super(LineProfile, self).attach(image_viewer) + + image = image_viewer.original_image + + if self._limit_type == 'image': + self.limits = (np.min(image), np.max(image)) + elif self._limit_type == 'dtype': + self.self._limit_type = dtype_range[image.dtype.type] + elif self._limit_type is None or len(self._limit_type) == 2: + self.limits = self._limit_type else: - raise ValueError("Unrecognized `limits`: %s" % limits) + raise ValueError("Unrecognized `limits`: %s" % self._limit_type) - if not limits is None: + if not self._limit_type is None: self.ax.set_ylim(self.limits) - h, w = self.image.shape - + h, w = image.shape self._init_end_pts = np.array([[w/3, h/2], [2*w/3, h/2]]) self.end_pts = self._init_end_pts.copy() x, y = np.transpose(self.end_pts) - self.scan_line = self.image_viewer.ax.plot(x, y, 'y-s', markersize=5, - lw=linewidth, alpha=0.5, - solid_capstyle='butt')[0] + self.scan_line = image_viewer.ax.plot(x, y, **self.line_kwargs)[0] self.artists.append(self.scan_line) - scan_data = profile_line(self.image, self.end_pts) + scan_data = profile_line(image, self.end_pts) self.profile = self.ax.plot(scan_data, 'k-')[0] self._autoscale_view() - self._active_pt = None - self.connect_event('key_press_event', self.on_key_press) self.connect_event('button_press_event', self.on_mouse_press) self.connect_event('button_release_event', self.on_mouse_release) @@ -77,7 +80,6 @@ class LineProfile(PlotPlugin): self.connect_event('scroll_event', self.on_scroll) self.image_viewer.redraw() - print self.help() def help(self): helpstr = ("Line profile tool", @@ -169,7 +171,8 @@ class LineProfile(PlotPlugin): self.scan_line.set_data(np.transpose(self.end_pts)) self.scan_line.set_linewidth(self.linewidth) - scan = profile_line(self.image, self.end_pts, linewidth=self.linewidth) + scan = profile_line(self.image_viewer.original_image, self.end_pts, + linewidth=self.linewidth) self.profile.set_xdata(np.arange(scan.shape[0])) self.profile.set_ydata(scan) diff --git a/skimage/viewer/plugins/overlayplugin.py b/skimage/viewer/plugins/overlayplugin.py index e9a6a42a..3b051e1a 100644 --- a/skimage/viewer/plugins/overlayplugin.py +++ b/skimage/viewer/plugins/overlayplugin.py @@ -16,12 +16,15 @@ class OverlayPlugin(Plugin): 'green': (0, 1, 0), 'cyan': (0, 1, 1)} - def __init__(self, image_viewer, **kwargs): - Plugin.__init__(self, image_viewer, **kwargs) + def __init__(self, **kwargs): + super(OverlayPlugin, self).__init__(**kwargs) self._overlay_plot = None self._overlay = None self.cmap = None self.color_names = self.colors.keys() + + def attach(self, image_viewer): + super(OverlayPlugin, self).attach(image_viewer) #TODO: `color` doesn't update GUI widget when set manually. self.color = 0 diff --git a/skimage/viewer/plugins/plotplugin.py b/skimage/viewer/plugins/plotplugin.py index 38762dc4..66afa676 100644 --- a/skimage/viewer/plugins/plotplugin.py +++ b/skimage/viewer/plugins/plotplugin.py @@ -40,8 +40,9 @@ class PlotPlugin(Plugin): image : array Image used in measurement/manipulation. """ - def __init__(self, image_viewer, **kwargs): - Plugin.__init__(self, image_viewer, **kwargs) + + def attach(self, image_viewer): + super(PlotPlugin, self).attach(image_viewer) # Add plot for displaying intensity profile. self.add_plot() diff --git a/skimage/viewer/viewers/core.py b/skimage/viewer/viewers/core.py index ac004987..fe22d750 100644 --- a/skimage/viewer/viewers/core.py +++ b/skimage/viewer/viewers/core.py @@ -96,6 +96,10 @@ class ImageViewer(QtGui.QMainWindow): self.connect_event('motion_notify_event', self.update_status_bar) + def __iadd__(self, plugin): + plugin.attach(self) + return self + def closeEvent(self, ce): self.close() diff --git a/viewer_examples/plugins/canny.py b/viewer_examples/plugins/canny.py index e84a8270..eaa33330 100644 --- a/viewer_examples/plugins/canny.py +++ b/viewer_examples/plugins/canny.py @@ -5,5 +5,5 @@ from skimage.viewer.plugins.canny import CannyPlugin image = data.camera() viewer = ImageViewer(image) -CannyPlugin(viewer) +viewer += CannyPlugin() viewer.show() diff --git a/viewer_examples/plugins/lineprofile.py b/viewer_examples/plugins/lineprofile.py index 310c23e4..2f1b2cdc 100644 --- a/viewer_examples/plugins/lineprofile.py +++ b/viewer_examples/plugins/lineprofile.py @@ -5,5 +5,5 @@ from skimage.viewer.plugins.lineprofile import LineProfile image = data.camera() viewer = ImageViewer(image) -LineProfile(viewer) +viewer += LineProfile() viewer.show()