# -*- python -*-
#
# spatial_image.visu : spatial nd images
#
# Copyright 2006 - 2011 INRIA - CIRAD - INRA
#
# File author(s): Jerome Chopard <jerome.chopard@sophia.inria.fr>
# Eric Moscardi <eric.moscardi@gmail.com>
# File Contributor(s):
# Manual Forero
#
# 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
################################################################################
"""
This module provide a simple viewer to display 3D stacks
"""
__license__= "Cecill-C"
__revision__=" $Id: $ "
__all__ = ["display","SlideViewer"]
def load_local(mod,modules):
modules = modules.split()
modules = ''.join(modules).split(',')
for m in modules:
globals()[m] = mod.__getattribute__(m)
from openalea.image.spatial_image import SpatialImage
import numpy as np
from openalea.vpltk.qt import QtCore, QtGui
load_local(QtCore,'Qt,QObject,SIGNAL')
load_local(QtGui,"""QApplication,QLabel,QMainWindow,QComboBox,
QSlider,QToolBar""")
from palette import palette_names,palette_factory
from pixmap_view import PixmapStackView,ScalableLabel
from slide_viewer_ui import Ui_MainWindow
if 'bw' in palette_names:
palette_names.remove('bw')
palette_names.sort()
[docs]class SlideViewer (QMainWindow) :
"""Display each image in a stack using a slider
A pure QWidget (instead of QMainWindow) is also available, see openalea.image.gui.slide_viewer_widget.
"""
viewer_count = 0
def __init__ (self, parent=None) :
QMainWindow.__init__(self, parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.axis = 2
#central label
self._im_view = PixmapStackView()
self._label = ScalableLabel()
self.setCentralWidget(self._label)
#mouse handling
self._label.setMouseTracking(True)
self._last_mouse_x = 0
self._last_mouse_y = 0
QObject.connect(self._label,
SIGNAL("mouse_press"),
self.mouse_pressed)
QObject.connect(self._label,
SIGNAL("mouse_move"),
self.mouse_pressed)
#toolbar
QObject.connect(self.ui.action_close,
SIGNAL("triggered(bool)"),
self.close)
QObject.connect(self.ui.action_snapshot,
SIGNAL("triggered(bool)"),
self.snapshot)
QObject.connect(self.ui.action_rotate_left,
SIGNAL("triggered(bool)"),
self.rotate_left)
QObject.connect(self.ui.action_rotate_right,
SIGNAL("triggered(bool)"),
self.rotate_right)
#palette
self._palette_select = QComboBox()
self.ui.toolbar.addWidget(self._palette_select)
for palname in palette_names :
self._palette_select.addItem(palname)
QObject.connect(self._palette_select,
SIGNAL("currentIndexChanged(int)"),
self.palette_name_changed)
#axis
self._axis = QComboBox(self)
self.ui.toolbar.addWidget(self._axis)
self._axis.addItem("Z-axis")
self._axis.addItem("Y-axis")
self._axis.addItem("X-axis")
self.connect(self._axis, SIGNAL('currentIndexChanged(int)'), self.change_axis )
#slider
self._bot_toolbar = QToolBar("slider")
self._img_slider = QSlider(Qt.Horizontal)
self._img_slider.setEnabled(False)
QObject.connect(self._img_slider,
SIGNAL("valueChanged(int)"),
self.slice_changed)
self._bot_toolbar.addWidget(self._img_slider)
self.addToolBar(Qt.BottomToolBarArea,self._bot_toolbar)
#statusbar
self._lab_coord = QLabel("coords:")
self._lab_xcoord = QLabel("% 4d" % 0)
self._lab_ycoord = QLabel("% 4d" % 0)
self._lab_zcoord = QLabel("% 4d" % 0)
self._lab_intens = QLabel("intens: None")
self.ui.statusbar.addPermanentWidget(self._lab_coord)
self.ui.statusbar.addPermanentWidget(self._lab_xcoord)
self.ui.statusbar.addPermanentWidget(self._lab_ycoord)
self.ui.statusbar.addPermanentWidget(self._lab_zcoord)
self.ui.statusbar.addPermanentWidget(self._lab_intens)
self.set_title("<"+str(self.viewer_count)+">")
SlideViewer.viewer_count += 1
##############################################
#
# update GUI
#
##############################################
[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 fill_infos (self) :
x,y = self._label.pixmap_coordinates(self._last_mouse_x,
self._last_mouse_y)
img = self._im_view.image()
if img is not None :
i,j,k = self._im_view.data_coordinates(x,y)
self._lab_xcoord.setText("% 4d" % i)
self._lab_ycoord.setText("% 4d" % j)
self._lab_zcoord.setText("% 4d" % k)
imax,jmax,kmax = img.shape[:3]
if self.axis==0 : #axis x
if 0 <= i < jmax and 0 <= j < kmax and 0 <= k < imax :
self._lab_intens.setText("intens: %s" % self.get_pixel_value_str(img,k,i,j))
else :
self._lab_intens.setText("intens: None")
elif self.axis==1 : #axis y
if 0 <= i < imax and 0 <= j < kmax and 0 <= k < jmax :
self._lab_intens.setText("intens: %s" % self.get_pixel_value_str(img,i,k,j))
else :
self._lab_intens.setText("intens: None")
else : #axis z
if 0 <= i < imax and 0 <= j < jmax and 0 <= k < kmax :
self._lab_intens.setText("intens: %s" % self.get_pixel_value_str(img,i,j,k))
else :
self._lab_intens.setText("intens: None")
##############################################
#
# accessors
#
##############################################
[docs] def set_image (self, img) :
self._im_view.set_image(img)
try :
self.resolution = img.resolution[:]
except AttributeError :
pass
self._img_slider.setRange(0,self._im_view.nb_slices() - 1)
self._img_slider.setEnabled(True)
self.slice_changed(self._img_slider.value() )
[docs] def set_palette (self, palette, palette_name = None) :
if palette_name is not None :
ind = self._palette_select.findText(palette_name)
self._palette_select.setCurrentIndex(ind)
self._im_view.set_palette(palette,self.axis)
self.update_pix()
[docs] def set_title(self, title=None):
if title is not None :
self.setWindowTitle(title)
[docs] def change_axis(self,ind):
self.axis = 2-ind
try :
res = list(self.resolution)
del res[self.axis]
tr = self._im_view._transform
if tr % 180 :
self._label._resolution=res[1],res[0]
else :
self._label.set_resolution(*res)
except AttributeError :
pass
self._im_view._reconstruct_pixmaps(self.axis)
self._img_slider.setRange(0,self._im_view.nb_slices() - 1)
self._img_slider.setEnabled(True)
self.update_pix()
#self.fill_infos()
##############################################
#
# slots
#
##############################################
[docs] def palette_name_changed (self, palette_index) :
palname = str(self._palette_select.currentText() )
img = self._im_view.image()
if img is not None :
self.set_palette(palette_factory(str(palname),img.max()) )
[docs] def slice_changed (self, ind) :
self._im_view.set_current_slice(ind)
self.update_pix()
self.fill_infos()
[docs] def snapshot (self) :
"""write the current image
"""
pix = self._im_view.pixmap()
if pix is not None :
pix.save("slice%.4d.png" % self._img_slider.value() )
[docs] def wheelEvent (self, event) :
inc = event.delta() / 8 / 15
self._img_slider.setValue(self._img_slider.value() + 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()
[docs] def mouse_pressed (self, event) :
self._last_mouse_x = event.x()
self._last_mouse_y = event.y()
self.fill_infos()
[docs]def display (image, palette_name = "grayscale", title = None , color_index_max = None) :
"""
"""
w = SlideViewer()
if not isinstance(image,SpatialImage):
image = SpatialImage(image)
if image.ndim < 3 :
image = image.reshape(image.shape + (1,))
if color_index_max is None :
cmax = image.max()
else :
cmax = color_index_max
palette = palette_factory(palette_name,cmax)
w.set_palette(palette,palette_name)
w.set_image(image)
w.set_title(title)
w.show()
return w