mirror of
https://github.com/wassname/scikit-image.git
synced 2026-08-20 12:50:52 +08:00
Merge pull request #575 from tonysyu/feature/viewer-linking
Linked image viewers and docked plugins
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
"""
|
||||
Base class for Plugins that interact with ImageViewer.
|
||||
"""
|
||||
from ..qt import QtGui
|
||||
from ..qt.QtCore import Qt
|
||||
from warnings import warn
|
||||
|
||||
import numpy as np
|
||||
|
||||
from ..qt import QtGui
|
||||
from ..qt.QtCore import Qt, Signal
|
||||
from ..utils import RequiredAttr, init_qtapp
|
||||
|
||||
|
||||
@@ -71,14 +74,24 @@ class Plugin(QtGui.QDialog):
|
||||
name = 'Plugin'
|
||||
image_viewer = RequiredAttr("%s is not attached to ImageViewer" % name)
|
||||
|
||||
def __init__(self, image_filter=None, height=0, width=400, useblit=True):
|
||||
# Signals used when viewers are linked to the Plugin output.
|
||||
image_changed = Signal(np.ndarray)
|
||||
_started = Signal(int)
|
||||
|
||||
def __init__(self, image_filter=None, height=0, width=400, useblit=True,
|
||||
dock='bottom'):
|
||||
init_qtapp()
|
||||
super(Plugin, self).__init__()
|
||||
|
||||
self.dock = dock
|
||||
|
||||
self.image_viewer = None
|
||||
# If subclass defines `image_filter` method ignore input.
|
||||
if not hasattr(self, 'image_filter'):
|
||||
self.image_filter = image_filter
|
||||
elif image_filter is not None:
|
||||
warn("If the Plugin class defines an `image_filter` method, "
|
||||
"then the `image_filter` argument is ignored.")
|
||||
|
||||
self.setWindowTitle(self.name)
|
||||
self.layout = QtGui.QGridLayout(self)
|
||||
@@ -109,7 +122,7 @@ class Plugin(QtGui.QDialog):
|
||||
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)
|
||||
self.arguments = [self.image_viewer.original_image]
|
||||
|
||||
# Call filter so that filtered image matches widget values
|
||||
self.filter_image()
|
||||
@@ -155,12 +168,22 @@ class Plugin(QtGui.QDialog):
|
||||
kwargs = dict([(name, self._get_value(a))
|
||||
for name, a in self.keyword_arguments.items()])
|
||||
filtered = self.image_filter(*arguments, **kwargs)
|
||||
|
||||
self.display_filtered_image(filtered)
|
||||
self.image_changed.emit(filtered)
|
||||
|
||||
def _get_value(self, param):
|
||||
# If param is a widget, return its `val` attribute.
|
||||
return param if not hasattr(param, 'val') else param.val
|
||||
|
||||
def _update_original_image(self, image):
|
||||
"""Update the original image argument passed to the filter function.
|
||||
|
||||
This method is called by the viewer when the original image is updated.
|
||||
"""
|
||||
self.arguments[0] = image
|
||||
self.filter_image()
|
||||
|
||||
@property
|
||||
def filtered_image(self):
|
||||
"""Return filtered image."""
|
||||
@@ -183,6 +206,17 @@ class Plugin(QtGui.QDialog):
|
||||
"""
|
||||
setattr(self, name, value)
|
||||
|
||||
def show(self, main_window=True):
|
||||
"""Show plugin."""
|
||||
super(Plugin, self).show()
|
||||
self.activateWindow()
|
||||
self.raise_()
|
||||
|
||||
# Emit signal with x-hint so new windows can be displayed w/o overlap.
|
||||
size = self.frameGeometry()
|
||||
x_hint = size.x() + size.width()
|
||||
self._started.emit(x_hint)
|
||||
|
||||
def closeEvent(self, event):
|
||||
"""On close disconnect all artists and events from ImageViewer.
|
||||
|
||||
|
||||
@@ -10,8 +10,9 @@ from ..canvastools import RectangleTool
|
||||
class ColorHistogram(PlotPlugin):
|
||||
name = 'Color Histogram'
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
def __init__(self, max_pct=0.99, **kwargs):
|
||||
super(ColorHistogram, self).__init__(height=400, **kwargs)
|
||||
self.max_pct = max_pct
|
||||
|
||||
print(self.help())
|
||||
|
||||
@@ -30,7 +31,7 @@ class ColorHistogram(PlotPlugin):
|
||||
normed=True)
|
||||
|
||||
# Clip bin heights that dominate a-b histogram
|
||||
max_val = pct_total_area(hist, percentile=99)
|
||||
max_val = pct_total_area(hist, percentile=self.max_pct)
|
||||
hist = exposure.rescale_intensity(hist, in_range=(0, max_val))
|
||||
self.ax.imshow(hist, extent=ab_extents, cmap=plt.cm.gray)
|
||||
|
||||
@@ -55,12 +56,12 @@ class ColorHistogram(PlotPlugin):
|
||||
self.image_viewer.image = color.lab2rgb(lab_masked)
|
||||
|
||||
|
||||
def pct_total_area(image, percentile=80):
|
||||
def pct_total_area(image, percentile=0.80):
|
||||
"""Return threshold value based on percentage of total area.
|
||||
|
||||
The specified percent of pixels less than the given intensity threshold.
|
||||
"""
|
||||
idx = int((image.size - 1) * percentile / 100.0)
|
||||
idx = int((image.size - 1) * percentile)
|
||||
sorted_pixels = np.sort(image.flat)
|
||||
return sorted_pixels[idx]
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ from warnings import warn
|
||||
|
||||
from skimage.util.dtype import dtype_range
|
||||
from .base import Plugin
|
||||
from ..utils import ClearColormap
|
||||
from ..utils import ClearColormap, update_axes_image
|
||||
|
||||
|
||||
__all__ = ['OverlayPlugin']
|
||||
@@ -66,7 +66,8 @@ class OverlayPlugin(Plugin):
|
||||
self._overlay_plot = ax.imshow(image, cmap=self.cmap,
|
||||
vmin=vmin, vmax=vmax)
|
||||
else:
|
||||
self._overlay_plot.set_array(image)
|
||||
update_axes_image(self._overlay_plot, image)
|
||||
|
||||
self.image_viewer.redraw()
|
||||
|
||||
@property
|
||||
|
||||
@@ -17,6 +17,13 @@ class PlotPlugin(Plugin):
|
||||
See base Plugin class for additional details.
|
||||
"""
|
||||
|
||||
def __init__(self, image_filter=None, height=150, width=400, **kwargs):
|
||||
super(PlotPlugin, self).__init__(image_filter=image_filter,
|
||||
height=height, width=width, **kwargs)
|
||||
|
||||
self._height = height
|
||||
self._width = width
|
||||
|
||||
def attach(self, image_viewer):
|
||||
super(PlotPlugin, self).attach(image_viewer)
|
||||
# Add plot for displaying intensity profile.
|
||||
@@ -26,10 +33,12 @@ class PlotPlugin(Plugin):
|
||||
"""Redraw plot."""
|
||||
self.canvas.draw_idle()
|
||||
|
||||
def add_plot(self, height=4, width=4):
|
||||
self.fig, self.ax = new_plot(figsize=(height, width))
|
||||
def add_plot(self):
|
||||
self.fig, self.ax = new_plot()
|
||||
self.fig.set_figwidth(self._width / float(self.fig.dpi))
|
||||
self.fig.set_figheight(self._height / float(self.fig.dpi))
|
||||
|
||||
self.canvas = self.fig.canvas
|
||||
self.canvas.setMinimumHeight(150)
|
||||
#TODO: Converted color is slightly different than Qt background.
|
||||
qpalette = QtGui.QPalette()
|
||||
qcolor = qpalette.color(QtGui.QPalette.Window)
|
||||
|
||||
Reference in New Issue
Block a user