Source code for image.gui.slide_viewer_widget

# -*- coding: utf-8 -*-
# -*- python -*-
#
#
#       OpenAlea.OALab: Multi-Paradigm GUI
#
#       Copyright 2015 INRIA - CIRAD - INRA
#
#       File author(s): Guillaume Baty <guillaume.baty@inria.fr>
#
#       File contributor(s):
#
#       Distributed under the Cecill-C License.
#       See accompanying file LICENSE.txt or copy at
#           http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html
#
#       OpenAlea WebSite : http://openalea.gforge.inria.fr
#
###############################################################################

import weakref
import numpy as np

from openalea.vpltk.qt import QtGui, QtCore

from openalea.image.spatial_image import SpatialImage

from pixmap_view import PixmapStackView, ScalableLabel
from openalea.image.gui.pixmap import to_img
from palette import palette_names, palette_factory

if 'bw' in palette_names:
    palette_names.remove('bw')
palette_names.sort()


[docs]def to_image(data, axis=2): # Manage also colored images. if len(data.shape) == 4 and data.shape[-1] in (3, 4): if data.dtype != np.uint8: raise Exception("Only uint8 RGB[A] images supported, got %s instead" % str(data.dtype)) pal = None for z in xrange(data.shape[axis]): if axis == 0: dat = data[z, :,:] elif axis == 1: dat = data[:, z, :] else: dat = data[:, :, z] if pal is not None: dat = pal[dat] if isinstance(data, SpatialImage): dat = SpatialImage(dat) #img = QImage(dat, # data.shape[0], # data.shape[1], # QImage.Format_ARGB32) return to_img(dat)
[docs]def connect(widget, signal, method): if signal: if hasattr(signal, 'connect') and hasattr(signal, 'disconnect'): signal.connect(method) elif isinstance(signal, basestring): widget.connect(widget, QtCore.SIGNAL(signal), method) else: raise NotImplementedError, 'Signal %s support is not implemented' % signal
[docs]def disconnect(widget, signal, method): if signal: if hasattr(signal, 'connect') and hasattr(signal, 'disconnect'): signal = signal.signal elif isinstance(signal, basestring): pass else: raise NotImplementedError, 'Signal %s support is not implemented' % signal widget.disconnect(widget, QtCore.SIGNAL(signal), method)
[docs]class ImageStackViewerPanel(QtGui.QWidget): def __init__(self, parent=None): QtGui.QWidget.__init__(self) layout = QtGui.QHBoxLayout(self) self.palette_select = QtGui.QComboBox() for palname in palette_names: self.palette_select.addItem(palname) #axis self.axis = QtGui.QComboBox() self.axis.addItem("Z-axis") self.axis.addItem("Y-axis") self.axis.addItem("X-axis") #slider self.img_slider = QtGui.QSlider(QtCore.Qt.Horizontal) self.img_slider.setEnabled(False) layout.addWidget(self.palette_select) layout.addWidget(self.img_slider) layout.addWidget(self.axis) self._viewer = None
[docs] def set_stack_viewer(self, widget): if widget is self._viewer: return # Disconnect old viewer if self._viewer is not None: disconnect(self, self.img_slider.valueChanged, self._viewer.slice_changed) disconnect(self, self.axis.currentIndexChanged, self._viewer.change_axis) disconnect(self, self.palette_select.currentIndexChanged, self._on_palette_name_changed) disconnect(self._viewer, self._viewer.valueChanged, self._on_stack_changed) # Connect new one if widget is not None: self._viewer = widget connect(self, self.img_slider.valueChanged, self._viewer.slice_changed) connect(self, self.axis.currentIndexChanged, self._viewer.change_axis) connect(self, self.palette_select.currentIndexChanged, self._on_palette_name_changed) connect(self._viewer, self._viewer.stackChanged, self._on_stack_changed) self._viewer.emit_stack_changed()
def _on_palette_name_changed(self, idx): palette_name = str(self.palette_select.currentText()) if self._viewer: self._viewer.change_palette(palette_name) def _on_stack_changed(self, stack): if stack is None: return axis = stack['axis'] shape = stack['shape'] self.img_slider.setRange(0, shape[axis] - 1) self.img_slider.setEnabled(True) self.img_slider.setValue(stack['slice']) palette_name = stack['palette_name'] if palette_name: if palette_name in palette_names: self.palette_select.setCurrentIndex(palette_names.index(palette_name))
[docs]class ImageStackViewerWidget(QtGui.QWidget): """ Widget based on openalea.image.gui.slide_viewer.PixmapStackView """ valueChanged = QtCore.Signal(object) stackChanged = QtCore.Signal(object) def __init__(self): QtGui.QWidget.__init__(self) self._im_view = PixmapStackView() self._label = ScalableLabel() self._layout = QtGui.QVBoxLayout(self) self._layout.addWidget(self._label) self._label.setMouseTracking(True) self._last_mouse_x = 0 self._last_mouse_y = 0 self.connect(self._label, QtCore.SIGNAL("mouse_press"), self.mouse_pressed) self.connect(self._label, QtCore.SIGNAL("mouse_move"), self.mouse_pressed) self.axis = 2 self.inc = 1 # index increment self._palette_name = None ############################################## # Qt Control API ##############################################
[docs] def setValue(self, img): if img is self.value(): return self._im_view.set_image(img) try: self.resolution = img.resolution[:] except AttributeError: pass self._im_view._reconstruct_pixmaps() self.change_axis(0) self.slice_changed((0 + self._im_view.nb_slices() - 1) / 2) self.emit_stack_changed()
[docs] def value(self): return self._im_view.image() ############################################## # slots ##############################################
[docs] def emit_stack_changed(self): img = self.value() if img is None: self.stackChanged.emit(None) else: args = dict(shape=img.shape, axis=self.axis, slice=self._im_view.current_slice(), resolution=self.resolution, inc=self.inc, palette_name=self._palette_name) self.stackChanged.emit(args)
[docs] def change_axis(self, ind): if self.axis == ind: return try: res = list(self.resolution) del res[self.axis] tr = self._im_view._transform print res if tr % 180: self._label._resolution = res[1], res[0] else: self._label.set_resolution(*res[:2]) except AttributeError: pass self._im_view._reconstruct_pixmaps(self.axis) self.emit_stack_changed() self.update_pix() #self.fill_infos()
[docs] def mouse_pressed(self, event): self._last_mouse_x = event.x() self._last_mouse_y = event.y()
[docs] def change_palette(self, palette_name): if palette_name == self._palette_name: return self._palette_name = palette_name self.emit_stack_changed() img = self._im_view.image() if img is None: return palette = palette_factory(palette_name, img.max()) self._im_view.set_palette(palette, self.axis) self.update_pix()
[docs] def update_pix(self): pix = self._im_view.pixmap() if pix is not None: self._label.setPixmap(pix)
[docs] def get_pixel_value_str(self, img, x, y, z): px = img[x, y, z] if isinstance(px, np.ndarray): return str(px) else: return "%3d" % px
[docs] def slice_changed(self, ind): img = self.value() if img is None: return if ind >= img.shape[self.axis]: ind = img.shape[self.axis] - 1 if ind < 0: ind = 0 if self._im_view.current_slice() == ind: return self._im_view.set_current_slice(ind) self.emit_stack_changed() self.update_pix()
[docs] def snapshot(self): """write the current image """ pix = self._im_view.pixmap() if pix is not None: pix.save("slice%.4d.png" % self.panel.img_slider.value())
[docs] def wheelEvent(self, event): self.inc = event.delta() / 8 / 15 idx = self._im_view.current_slice() self.slice_changed(idx + self.inc)
[docs] def rotate_left(self): res = self._label._resolution self._label._resolution = res[1], res[0] self._im_view.rotate(-1) self.update_pix()
[docs] def rotate_right(self): res = self._label._resolution self._label._resolution = res[1], res[0] self._im_view.rotate(1) self.update_pix()
if __name__ == '__main__': from openalea.deploy.shared_data import shared_data from openalea.image.serial.basics import imread import openalea.oalab img_path = shared_data(openalea.oalab, 'icons/Crystal_Clear_app_clock.png') img = imread(img_path) import numpy matrix = numpy.zeros((100, 100, 100), dtype=numpy.uint8) matrix[90:100, :10, :10] = 1 matrix[:10, 90:100, :10] = 2 matrix[:10, :10, 90:100] = 3 img3d = SpatialImage(matrix) instance = QtGui.QApplication.instance() if instance is None: app = QtGui.QApplication([]) else: app = instance slider = ImageStackViewerWidget() slider.setValue(img) slider.show() slider_3d = ImageStackViewerWidget() slider_3d.setValue(img3d) slider_3d.show() panel = ImageStackViewerPanel() panel.show() panel.set_stack_viewer(slider) if instance is None: app.exec_()