##############################################################################
# Braviz, Brain Data interactive visualization #
# Copyright (C) 2014 Diego Angulo #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU Lesser General Public License as #
# published by the Free Software Foundation, either version 3 of the #
# License, or (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU Lesser General Public License for more details. #
# #
# You should have received a copy of the GNU Lesser General Public License#
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
##############################################################################
from __future__ import division
import vtk
from vtk.qt4.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
from PyQt4 import QtCore
from PyQt4.QtGui import QFrame, QHBoxLayout, QApplication
from PyQt4.QtCore import pyqtSignal
from braviz.visualization.simple_vtk import OrientationAxes, persistentImagePlane, cursors, estimate_window_level
from braviz.visualization.fmri_view import fMRI_blender
from braviz.interaction.structure_metrics import solve_laterality
import braviz.readAndFilter.tabular_data
import braviz.readAndFilter.config_file
import seaborn as sbs
from itertools import izip
from braviz.interaction import structure_metrics
from functools import wraps
import numpy as np
import logging
__author__ = 'Diego'
_axis_dict = {"axial": 2, "sagital": 0, "coronal": 1}
# TODO: Abstract viewer classes
[docs]def do_and_render(f):
"""
Wraps drawing methods, adding an optional call to *Render* at the end.
It adds the *skip_render* kwarg argument, which if True will avoid the call to Render. This is
useful to avoid repeated call renders when performing several draw operations.
requires the class to have the renderer accessible as self.ren
Args:
f (function) : Function that changes vtk scene
"""
@wraps(f)
def wrapped(*args, **kwargs):
if "skip_render" in kwargs:
skip = kwargs.pop("skip_render")
else:
skip = False
try:
f(*args, **kwargs)
except Exception:
raise
finally:
if not skip:
self = args[0]
rw = self.ren.GetRenderWindow()
rw.Render()
return wrapped
[docs]class SubjectViewer(object):
"""
A general viewer to show data on a particular subject
It provides access to
- Images
- fMRI Contours
- Segmentation reconstruction models
- Surface parcellations
- Tractographies
- Tracula Bundles
"""
def __init__(self, render_window_interactor, reader, widget):
"""
Creates the viewer
Args:
render_window_interactor (vtkRenderWindowInteractor) : The intaractor that will be used with this viewer
reader (braviz.visualization.base_reader.BaseReader) : Braviz reader
widget (QObject) : Must implement *slice_change_handle* and *window_level_change_handle*
"""
# render_window_interactor.Initialize()
# render_window_interactor.Start()
self.iren = render_window_interactor
self.ren_win = render_window_interactor.GetRenderWindow()
self.ren = vtk.vtkRenderer()
self.ren.SetBackground((0.75, 0.75, 0.75))
self.ren.GradientBackgroundOn()
self.ren.SetBackground2((0.5, 0.5, 0.5))
self.ren.SetBackground((0.2, 0.2, 0.2))
self.ren.SetUseDepthPeeling(1)
self.ren_win.SetMultiSamples(0)
self.ren_win.AlphaBitPlanesOn()
self.ren.SetOcclusionRatio(0.1)
self.ren_win.AddRenderer(self.ren)
self.iren.SetInteractorStyle(vtk.vtkInteractorStyleTrackballCamera())
self.axes = OrientationAxes()
self.axes.initialize(self.iren)
self.light = vtk.vtkLight()
self.ren.AddLight(self.light)
self.light.SetLightTypeToHeadlight()
self.reader = reader
# state
self.__current_subject = None
self.__current_space = "subject"
self.picker = vtk.vtkCellPicker()
self.picker.SetTolerance(0.0005)
self.iren.SetPicker(self.picker)
# internal data
self.__model_manager = ModelManager(self.reader, self.ren)
self.__tractography_manager = TractographyManager(
self.reader, self.ren)
self.__image_manager = ImageManager(self.reader, self.ren, widget=widget, interactor=self.iren,
picker=self.picker)
self.__surface_manager = SurfaceManager(
self.reader, self.ren, self.iren, picker=self.picker)
self.__contours_manager = FmriContours(self.ren)
self.__tracula_manager = TraculaManager(
self.reader, self.ren, self.__current_subject, self.__current_space)
fmri_lut = self.reader.get("fmri", None, lut=True)
self.__contours_manager.set_lut(fmri_lut)
self.__contours_paradigm = None
self.__contours_contrast = None
self.set_contours_visibility(False, skip_render=True)
self.__contours_img = None
# reset camera and render
# self.reset_camera(0)
# self.ren.Render()
# widget, signal handling
self.__widget = widget
@property
def models(self):
"""
Access to :class:`ModelManager`
"""
return self.__model_manager
@property
def tractography(self):
"""
Access to :class:`TractographyManager`
"""
return self.__tractography_manager
@property
def image(self):
"""
Access to :class:`ImageManager`
"""
return self.__image_manager
@property
def surface(self):
"""
Access to :class:`SurfaceManager`
"""
return self.__surface_manager
@property
def contours(self):
"""
Access to :class:`FmriContours`
"""
return self.__contours_manager
@property
def tracula(self):
"""
Access to :class:`TraculaManager`
"""
return self.__tracula_manager
[docs] def show_cone(self):
"""Useful for testing"""
log = logging.getLogger(__name__)
log.warning("Showing cone... this should only happen during testing")
cone = vtk.vtkConeSource()
cone.SetResolution(8)
cone_mapper = vtk.vtkPolyDataMapper()
cone_mapper.SetInputConnection(cone.GetOutputPort())
cone_actor = vtk.vtkActor()
cone_actor.SetMapper(cone_mapper)
self.ren.AddActor(cone_actor)
self.ren_win.Render()
[docs] def change_subject(self, new_subject):
"""
Changes the subject associated to the viewer
Args:
new_subject : new subject id
"""
self.__current_subject = new_subject
errors = []
log = logging.getLogger(__name__)
# update image
try:
self.image.change_subject(new_subject, skip_render=True)
except Exception as e:
log.exception(e)
errors.append("Image")
# update models
try:
self.models.reload_models(subj=new_subject, skip_render=True)
except Exception as e:
log.exception(e)
errors.append("Models")
# update fibers
try:
self.tractography.set_subject(new_subject, skip_render=True)
except Exception as e:
log.exception(e)
errors.append("Fibers")
# update surfaces
try:
self.surface.set_subject(new_subject, skip_render=True)
except Exception as e:
log.exception(e)
errors.append("Surfaces")
# update fmri
try:
self.set_fmri_contours_image(skip_render=True)
except Exception as e:
log.exception(e)
errors.append("Contours")
try:
self.tracula.reload_bundles(
self.__current_subject, self.__current_space, skip_render=True)
except Exception as e:
log.exception(e)
errors.append("Tracula")
self.ren_win.Render()
if len(errors) > 0:
log.error("Couldn't load " + ", ".join(errors))
raise Exception("Couldn't load " + ", ".join(errors))
@do_and_render
[docs] def change_current_space(self, new_space):
"""
Changes the current coordinate system
Args:
new_space (str) : New coordinate system
"""
if self.__current_space == new_space:
return
self.__current_space = new_space
log = logging.getLogger(__name__)
try:
self.image.change_space(new_space, skip_render=True)
except Exception as e:
log.error(e)
try:
self.models.reload_models(space=new_space, skip_render=True)
except Exception as e:
log.error(e)
try:
self.tractography.set_current_space(new_space, skip_render=True)
except Exception as e:
log.error(e)
try:
self.surface.set_space(new_space, skip_render=True)
except Exception as e:
log.error(e)
try:
self.tracula.reload_bundles(
self.__current_subject, new_space, skip_render=True)
except Exception as e:
log.error(e)
__camera_positions_dict = {
0: ((-3.5, 0, 13), (157, 154, 130), (0, 0, 1)),
2: ((-3.5, 0, 10), (250, 0, 10), (0, 0, 1)),
1: ((-3.5, 0, 10), (-250, 0, 10), (0, 0, 1)),
4: ((-3.5, 0, 10), (-3.5, -200, 10), (0, 0, 1)),
3: ((-3.5, 0, 10), (-3.5, 200, 10), (0, 0, 1)),
5: ((-3, 0, 3), (-3, 0, 252), (0, 1, 0)),
6: ((-3, 0, 3), (-3, 0, -252), (0, 1, 0)),
}
[docs] def reset_camera(self, position):
"""
resets the current camera to standard locations.
Args:
position (int) :
- 0: initial 3d view
- 1: left
- 2: right
- 3: front
- 4: back
- 5: top
- 6: bottom
"""
focal, position, viewup = self.__camera_positions_dict[position]
cam1 = self.ren.GetActiveCamera()
cam1.SetFocalPoint(focal)
cam1.SetPosition(position)
cam1.SetViewUp(viewup)
self.ren.ResetCameraClippingRange()
self.ren_win.Render()
[docs] def set_camera(self, focal_point, position, view_up):
"""
Sets the camera position
Args:
focal_point (tuple) : Focal point
position (tuple) : Camera position
view_up (tuple) : View up vector
"""
cam1 = self.ren.GetActiveCamera()
cam1.SetFocalPoint(focal_point)
cam1.SetPosition(position)
cam1.SetViewUp(view_up)
self.ren.ResetCameraClippingRange()
self.ren_win.Render()
[docs] def print_camera(self):
"""
Logs information about the current camera position
Data is send to the current logger with *info* level
"""
cam1 = self.ren.GetActiveCamera()
log = logging.getLogger(__name__)
log.info("Camera coordinates:")
log.info("focal: ")
log.info(cam1.GetFocalPoint())
log.info("position: ")
log.info(cam1.GetPosition())
log.info("viewUp: ")
log.info(cam1.GetViewUp())
[docs] def get_camera_parameters(self):
"""
Gets current camera parameters
Returs:
focal_point, position, view_up
"""
cam1 = self.ren.GetActiveCamera()
fp = cam1.GetFocalPoint()
pos = cam1.GetPosition()
vu = cam1.GetViewUp()
return fp, pos, vu
@do_and_render
[docs] def set_fmri_contours_image(self, paradigm=None, contrast=None):
"""
Sets the image to use for calculating fMRI contours
Args:
paradigm (str) : Name of fMRI paradigm
contrast (int): Index (Matlab style) of desired contrast
"""
if paradigm is None:
paradigm = self.__contours_paradigm
else:
self.__contours_paradigm = paradigm
if contrast is None:
contrast = self.__contours_contrast
else:
self.__contours_contrast = contrast
log = logging.getLogger(__name__)
if self.__contours_hidden:
return
if paradigm is None:
self.__contours_img = None
else:
try:
fmri_img = self.reader.get("fmri", self.__current_subject, space=self.__current_space,
name=paradigm, contrast=contrast, format="vtk")
except Exception as e:
self.__contours_img = None
log.exception(e)
else:
self.__contours_img = fmri_img
if self.__contours_img is None:
self.contours.actor.SetVisibility(0)
else:
self.contours.set_image(fmri_img)
if not self.__contours_hidden:
self.contours.actor.SetVisibility(1)
@do_and_render
[docs] def set_contours_visibility(self, visible):
"""
Toggle visibility of fMRI contours
Args:
visible (bool) : If ``True`` contours will show, if ``False`` contours will be hidden,
"""
self.__contours_hidden = not visible
if self.__contours_hidden:
self.contours.actor.SetVisibility(0)
else:
self.set_fmri_contours_image(
self.__contours_paradigm, self.__contours_contrast, skip_render=True)
self.contours.actor.SetVisibility(1)
[docs]class FilterArrows(QtCore.QObject):
"""
A Qt event filter to prevent the main vtk widget from swallowing certain keys. By default this are the arrows,
but additional keys can be added in the constructor.
"""
key_pressed = pyqtSignal(QtCore.QEvent)
def __init__(self, parent=None, other_keys=tuple()):
"""
Construct the Qt Event Filter to avoid certain key presses from arriving to the VTK widget
Args:
parent (QOject) : Parent of the current object
other_keys (list) : List of additional keys to filter out
"""
super(FilterArrows, self).__init__(parent)
keys = {QtCore.Qt.Key_Left, QtCore.Qt.Key_Right,
QtCore.Qt.Key_Up, QtCore.Qt.Key_Down}
keys.update(other_keys)
self.__filter_keys = frozenset(keys)
def eventFilter(self, QObject, QEvent):
if QEvent.type() == QEvent.KeyPress:
q_event_key = QEvent.key()
if q_event_key in self.__filter_keys:
# print "intercepted key"
self.key_pressed.emit(QEvent)
return True
return False
[docs]class ImageManager(object):
"""
Controls an ImagePlaneWidget
"""
def __init__(self, reader, ren, widget, interactor, initial_subj=None, initial_space="subject", picker=None):
"""
Initializes the ImageManager
Args:
reader (braviz.visualization.base_reader.BaseReader) : Braviz reader
ren (vtkRenderer) : Renderer in which to draw the plane
widget (QObject) : Must implement *slice_change_handle* and *window_level_change_handle*
interactor (vtkRenderWindowInteractor) : The render window interactor of the output window
initial_subj : Code of initial subject, if None an arbitrary subject will be selected
initial_space (str) : Initial coordinate system
picker (vtkPicker) : A vtkPicker may be used to pick on several objects. If None a new picker is created
"""
self.ren = ren
self.reader = reader
if initial_subj is None:
conf = braviz.readAndFilter.config_file.get_apps_config()
initial_subj = conf.get_default_subject()
self.__current_subject = initial_subj
self.__current_space = initial_space
self.__current_image_class = None
self.__current_image_name = None
self.__current_contrast = None
self.__current_image_orientation = 0
self.__past_window_levels = {}
self.__image_plane_widget = None
self.__window_level_lut = vtk.vtkWindowLevelLookupTable()
self.__fmri_blender = fMRI_blender()
self.__widget = widget
self.__outline_filter = None
self.__picker = picker
# Should only change when user selects to hide the image
self.__hidden = False
self.iren = interactor
@property
def image_plane_widget(self):
"""
Get the vtkImagePlaneWidget
"""
if self.__image_plane_widget is None:
self._create_image_plane_widget()
return self.__image_plane_widget
@do_and_render
[docs] def hide_image(self):
"""
Hide the plane widget
"""
self.__hidden = True
if self.__image_plane_widget is not None:
self.__image_plane_widget.Off()
# self.image_plane_widget.SetVisibility(0)
@do_and_render
[docs] def show_image(self):
"""
Show the plane widget
"""
self.__hidden = False
self.change_image_modality(
self.__current_image_class, self.__current_image_name, True, self.__current_contrast)
@do_and_render
def _create_image_plane_widget(self):
"""
Creates the internal plane widget
"""
if self.__image_plane_widget is not None:
# already created
return
self.__image_plane_widget = persistentImagePlane(
self.__current_image_orientation)
self.__image_plane_widget.SetInteractor(self.iren)
self.__image_plane_widget.On()
self.__window_level_lut = vtk.vtkWindowLevelLookupTable()
self.__window_level_lut.DeepCopy(self.__image_plane_widget.GetLookupTable())
def slice_change_handler(source, event):
new_slice = self.__image_plane_widget.GetSliceIndex()
self.__widget.slice_change_handle(new_slice)
def detect_window_level_event(source, event):
window, level = self.__image_plane_widget.GetWindow(
), self.__image_plane_widget.GetLevel()
self.__widget.window_level_change_handle(window, level)
self.__image_plane_widget.AddObserver(
self.__image_plane_widget.slice_change_event, slice_change_handler)
self.__image_plane_widget.AddObserver(
"WindowLevelEvent", detect_window_level_event)
if self.__picker is not None:
self.__image_plane_widget.SetPicker(self.__picker)
outline = vtk.vtkOutlineFilter()
outlineMapper = vtk.vtkPolyDataMapper()
outlineMapper.SetInputConnection(outline.GetOutputPort())
outlineActor = vtk.vtkActor()
outlineActor.SetMapper(outlineMapper)
outlineActor.GetProperty().SetColor(0, 0, 0)
self.ren.AddActor(outlineActor)
self.__outline_filter = outline
@do_and_render
[docs] def change_subject(self, new_subject, force=False):
"""
Change subject associated to the plane
Args:
new_subject : Id of new subject
"""
self.__current_subject = new_subject
if not self.__hidden or force:
self.change_image_modality(self.__current_image_class, self.__current_image_name, force_reload=True,
contrast=self.__current_contrast)
@do_and_render
[docs] def change_space(self, new_space):
"""
Change current coordinate system
new_space (str) : new coordinate system, see :meth:`~braviz.readAndFilter.base_reader.BaseReader.get`
"""
if self.__current_space == new_space:
return
self.__current_space = new_space
if not self.__hidden:
self.change_image_modality(self.__current_image_class, self.__current_image_name, force_reload=True,
skip_render=True)
@do_and_render
[docs] def change_image_modality(self, image_class, image_name, force_reload=False, contrast=1):
"""Changes the modality of the current image;
In the case of fMRI modality should be fMRI and paradigm the name of the paradigm
Args:
image_class (str) : New image class, may be one of ``["image","label","dti","fmri"]``
image_name (str) : New image modality name. Use ``None`` if *image_class* is ``"dti"``,
otherwise it should be inside the index of the given class.
In case of *FMRI* the paradigm should be entered here
See :meth:`~braviz.readAndFilter.base_reader.BaseReader.get`
force_reload (bool) : if True, forces the plane to reload the image if it appears to be the same as before
contrast (int) : contrast to show in case image_class is ``"fmri"``
"""
if image_name is not None:
image_name = image_name.upper()
if image_class is not None:
image_class = image_class.upper()
if (self.__current_image_class is not None) and (image_class == self.__current_image_class) and \
(contrast == self.__current_contrast) and \
(self.__current_image_name == image_name) and not force_reload:
# nothing to do
return
# save window and level values (only for standard image class)
if self.__current_image_class == "IMAGE" and \
(self.__image_plane_widget is not None) and self.__image_plane_widget.GetEnabled():
window_level = [0, 0]
self.__image_plane_widget.GetWindowLevel(window_level)
self.__past_window_levels[self.__current_image_name] = window_level
self.__current_image_name = image_name
self.__current_image_class = image_class
self.__current_contrast = contrast
if image_class is None:
if self.__image_plane_widget is not None:
self.__image_plane_widget.Off()
return
if self.__current_subject is None:
return
if self.__image_plane_widget is None:
self._create_image_plane_widget()
self.__image_plane_widget.On()
# update image labels:
log = logging.getLogger(__name__)
try:
if image_name == "WMPARC":
ref = "WMPARC"
else:
ref = "APARC"
aparc_img = self.reader.get("LABEL", self.__current_subject, name=ref,
format="VTK", space=self.__current_space)
aparc_lut = self.reader.get("LABEL", self.__current_subject, name=ref, lut=True)
self.__image_plane_widget.addLabels(aparc_img)
self.__image_plane_widget.setLabelsLut(aparc_lut)
except Exception as e:
log.warning(e)
log.warning("APARC image not found")
# raise Exception("Aparc not available")
self.__image_plane_widget.addLabels(None)
if image_class == "FMRI":
try:
mri_image = self.reader.get("IMAGE", self.__current_subject, format="VTK", name="MRI",
space=self.__current_space)
fmri_image = self.reader.get("fMRI", self.__current_subject, format="VTK", space=self.__current_space,
name=image_name, contrast=contrast)
except Exception:
fmri_image = None
mri_image = None
log.warning("FMRI IMAGE NOT FOUND pdgm = %s" % image_name)
if fmri_image is None or mri_image is None:
self.image_plane_widget.Off()
# raise
raise Exception(
"%s not available for subject %s" % (image_name, self.__current_subject))
fmri_lut = self.reader.get(
"fMRI", self.__current_subject, lut=True)
# we need to load the mri image first to get a valid
# window_level
w_l = self.__past_window_levels.get("MRI")
if w_l is None:
w_l = estimate_window_level(mri_image)
self.__window_level_lut.SetWindow(w_l[0])
self.__window_level_lut.SetLevel(w_l[1])
self.__fmri_blender.set_luts(self.__window_level_lut, fmri_lut)
new_image = self.__fmri_blender.set_images(mri_image, fmri_image)
self.__image_plane_widget.SetInputData(new_image)
self.__outline_filter.SetInputData(new_image)
self.__image_plane_widget.GetColorMap().SetLookupTable(None)
self.__image_plane_widget.SetResliceInterpolateToCubic()
self.__current_image_class = image_class
self.__current_image_name = image_name
self.__image_plane_widget.text1_value_from_img(fmri_image)
if not self.__hidden:
self.__image_plane_widget.On()
return
elif image_class == "DTI":
try:
dti_image = self.reader.get(
"DTI", self.__current_subject, format="VTK", space=self.__current_space)
fa_image = self.reader.get("IMAGE", self.__current_subject, format="VTK", space=self.__current_space,
name="FA")
except Exception:
log.warning("DTI, not available")
self.image_plane_widget.Off()
raise Exception("DTI, not available")
self.__image_plane_widget.SetInputData(dti_image)
self.__outline_filter.SetInputData(dti_image)
self.__image_plane_widget.SetResliceInterpolateToCubic()
self.__image_plane_widget.text1_value_from_img(fa_image)
self.__image_plane_widget.GetColorMap().SetLookupTable(None)
if not self.__hidden:
self.__image_plane_widget.On()
return
# Other images
self.__image_plane_widget.text1_to_std()
try:
new_image = self.reader.get(image_class, self.__current_subject, space=self.__current_space,
name=image_name, format="VTK")
except Exception:
self.image_plane_widget.Off()
raise
self.__image_plane_widget.SetInputData(new_image)
self.__outline_filter.SetInputData(new_image)
if image_class == "IMAGE":
lut = self.__window_level_lut
self.__image_plane_widget.SetLookupTable(lut)
self.__image_plane_widget.SetResliceInterpolateToCubic()
w_l = self.__past_window_levels.get(image_name)
if w_l is None:
self.reset_window_level(skip_render=True)
else:
self.__image_plane_widget.SetWindowLevel(
*w_l)
elif image_class == "LABEL":
lut = self.reader.get("LABEL", self.__current_subject, lut=True, name=image_name)
self.__image_plane_widget.SetLookupTable(lut)
# Important:
self.__image_plane_widget.SetResliceInterpolateToNearestNeighbour()
# self.__current_image = modality
if self.__hidden is False:
self.image_plane_widget.On()
@do_and_render
[docs] def change_image_orientation(self, orientation):
"""
Changes the orientation of the current image
Args:
orientation (int) : 0 for X, 1 for Y and 2 for Z
"""
log = logging.getLogger(__name__)
if self.__image_plane_widget is None:
self.__current_image_orientation = orientation
log.warning("Set an image first")
return
self.__image_plane_widget.set_orientation(orientation)
self.__current_image_orientation = orientation
[docs] def get_number_of_image_slices(self):
"""
Gets the number of slices in the current orientation
Returns:
The number of available slicer for the current image and orientation
"""
if self.__image_plane_widget is None:
return 0
img = self.__image_plane_widget.GetInput()
if img is None:
return 0
dimensions = img.GetDimensions()
return dimensions[self.__current_image_orientation]
[docs] def get_current_image_slice(self):
"""
Get the index of the actual slice
Returns:
The index of the current slice
"""
if self.__image_plane_widget is None:
return 0
return self.__image_plane_widget.GetSliceIndex()
@do_and_render
[docs] def set_image_slice(self, new_slice):
"""
Sets the image slice
Args:
new_slice (int) : Number of the desired slice
"""
if self.__image_plane_widget is None:
return
self.__image_plane_widget.SetSliceIndex(int(new_slice))
self.__image_plane_widget.InvokeEvent(
self.__image_plane_widget.slice_change_event)
[docs] def get_current_image_window(self):
"""
Current window
Returns:
Current window value
"""
if self.__image_plane_widget is None:
return 0
return self.__image_plane_widget.GetWindow()
[docs] def get_current_image_level(self):
"""
Current level
Returns:
Current level value
"""
if self.__image_plane_widget is None:
return 0
return self.__image_plane_widget.GetLevel()
@do_and_render
[docs] def set_image_window(self, new_window):
"""
Changes window value
Args:
new_window (float) : New window value
"""
if self.__image_plane_widget is None:
return
self.__image_plane_widget.SetWindowLevel(
new_window, self.get_current_image_level())
@do_and_render
[docs] def set_image_level(self, new_level):
"""
Changes level value
Args:
new_level (float) : New level value
"""
if self.__image_plane_widget is None:
return
self.__image_plane_widget.SetWindowLevel(
self.get_current_image_window(), new_level)
@do_and_render
[docs] def reset_window_level(self, _=None):
"""
Resets window and level to standard values
"""
if self.__image_plane_widget is None:
return
if self.__current_image_class == "IMAGE":
img = self.__image_plane_widget.GetInput()
window, level = estimate_window_level(img)
self.__image_plane_widget.SetWindowLevel(window, level)
self.__image_plane_widget.InvokeEvent("WindowLevelEvent")
[docs]class ModelManager(object):
"""
A manager for segmented structure models
"""
def __init__(self, reader, ren, initial_subj=None, initial_space="subject"):
"""
Initializes a model manager
Args:
reader (braviz.visualization.base_reader.BaseReader) : Braviz reader
ren (vtkRenderer) : Renderer in which to draw the models
initial_subj : Code of initial subject, if None an arbitrary subject will be selected
initial_space (str) : Initial coordinate system
"""
conf = braviz.readAndFilter.config_file.get_apps_config()
lat_var = conf.get_laterality()
self.lat_idx = braviz.readAndFilter.tabular_data.get_var_idx(
lat_var[0])
self.left_handed = lat_var[1]
self.ren = ren
if initial_subj is None:
conf = braviz.readAndFilter.config_file.get_apps_config()
initial_subj = conf.get_default_subject()
self.__active_models_set = set()
self.__pd_map_act = dict()
self.__available_models = set()
self.__current_subject = initial_subj
self.__reader = reader
self.__current_space = initial_space
self.__actor_to_model = {} # for picking
self.__laterality = None
# visual attributes
self.__opacity = 1
self.__current_color = None
self.reload_models(
subj=initial_subj, space=initial_space, skip_render=True)
def __get_laterality(self):
log = logging.getLogger(__file__)
try:
label = braviz.readAndFilter.tabular_data.get_var_value(
self.lat_idx, self.__current_subject)
except Exception:
log.warning(
"Laterality no found for subject %s, assuming right handed" % self.__current_subject)
label = 1
if label is None or (int(label) == self.left_handed):
return "l"
else:
return "r"
@do_and_render
[docs] def reload_models(self, subj=None, space=None):
"""
Reloads all models
Args:
subj : Code for new subject, if ``None`` the subject is not changed
space (str) : new coordinate system, if ``None`` the coordinates are not changed
"""
if subj is not None:
self.__current_subject = subj
try:
self.__available_models = set(
self.__reader.get("MODEL", subj, index=True))
except Exception:
self.__available_models = set()
self.__laterality = self.__get_laterality()
if space is not None:
self.__current_space = space
if (space is not None) or (subj is not None):
self.__refresh_models()
def __refresh_models(self):
for mod_name in self.__active_models_set:
self.__addModel(mod_name)
if len(self.__available_models) == 0:
log = logging.getLogger(__name__)
log.warning("No models found")
# raise Exception("No models found")
def __addModel(self, model_name):
# if already exists make visible
trio = self.__pd_map_act.get(model_name)
if trio is not None:
model, mapper, actor = trio
rl_name = solve_laterality(self.__laterality, model_name)
if rl_name in self.__available_models:
model = self.__reader.get(
'MODEL', self.__current_subject, name=rl_name, space=self.__current_space)
mapper.SetInputData(model)
actor.SetVisibility(1)
self.__pd_map_act[model_name] = (model, mapper, actor)
else:
actor.SetVisibility(0) # Hide
else:
# New model
rl_name = solve_laterality(self.__laterality, model_name)
if rl_name in self.__available_models:
model = self.__reader.get(
'MODEL', self.__current_subject, name=rl_name, space=self.__current_space)
model_mapper = vtk.vtkPolyDataMapper()
model_actor = vtk.vtkActor()
model_properties = model_actor.GetProperty()
if self.__current_color is None:
model_color = self.__reader.get(
'MODEL', None, name=rl_name, color='T')
model_properties.SetColor(list(model_color[0:3]))
else:
model_properties.SetColor(self.__current_color)
model_properties.SetOpacity(self.__opacity)
model_properties.LightingOn()
model_mapper.SetInputData(model)
model_actor.SetMapper(model_mapper)
self.ren.AddActor(model_actor)
self.__pd_map_act[model_name] = (
model, model_mapper, model_actor)
self.__actor_to_model[id(model_actor)] = model_name
# actor=self.__pd_map_act[model_name][2]
# model_volume=self.__reader.get('model',self.currSubj,name=model_name,volume=1)
# add_solid_balloon(balloon_widget, actor, model_name,model_volume)
def __removeModel(self, model_name):
"""Deletes internal data structures
"""
# check that it actually exists
trio = self.__pd_map_act.get(model_name)
if trio is None:
return
model, mapper, actor = trio
self.ren.RemoveActor(actor)
del self.__pd_map_act[model_name]
del self.__actor_to_model[id(actor)]
# balloon_widget.RemoveBalloon(actor)
del actor
del mapper
del model
def __hide_model(self, model_name):
trio = self.__pd_map_act.get(model_name)
if trio is None:
return
actor = trio[2]
actor.SetVisibility(0)
@do_and_render
[docs] def set_models(self, new_model_set):
"""
Sets the currently shown models
Args:
new_model_set (set) : An iterable of strings with names of valid models.
"""
new_set = set(new_model_set)
current_models = self.__active_models_set
to_add = new_set - current_models
to_hide = current_models - new_set
# print "act:", self.__active_models_set
# print "new" , new_set
# print "hide", to_hide
for mod_name in to_add:
self.__addModel(mod_name)
for mod_name in to_hide:
self.__hide_model(mod_name)
self.__active_models_set = new_set
@do_and_render
[docs] def set_opacity(self, int_opacity):
"""
Opacity for displaying the models
Args:
int_opacity (int) : A number from 0 to 100; where 0 is invisible and 100 is opaque
"""
float_opacity = int_opacity / 100
self.__opacity = float_opacity
for _, _, ac in self.__pd_map_act.itervalues():
prop = ac.GetProperty()
prop.SetOpacity(float_opacity)
[docs] def get_opacity(self):
"""
Gets actual opacity
Returns:
An integer from 0 to 100 indicating the current opacity percentage
"""
return self.__opacity * 100
@do_and_render
[docs] def set_color(self, float_rgb_color):
"""
Sets the color for displaying the models
Args:
float_rgb_color (tuple) : An rgb value, if ``None`` the freesurfer lookuptable is used
"""
self.__current_color = float_rgb_color
for k, (_, _, ac) in self.__pd_map_act.iteritems():
prop = ac.GetProperty()
if self.__current_color is None:
rl_name = solve_laterality(self.__laterality, k)
model_color = self.__reader.get(
'MODEL', None, name=rl_name, color='T')
prop.SetColor(list(model_color[0:3]))
else:
prop.SetColor(self.__current_color)
[docs] def get_scalar_metrics(self, metric_name):
"""
Get an scalar metric from the current models
Args:
metric_name (str): May be
- ``volume`` : Total volume occupied by all models
- ``area`` : Sum of superficial areas of all models
- ``fa_inside`` : Mean value of FA inside the current models
- ``md_inside`` : Mean value of MD inside the current models
- ``nfibers`` : Number of fibers that cross any of the current models
- ``lfibers`` : Mean length of fibers that cross any of the current models
- ``fa-fibers`` : Mean FA of fibers that cross any of the current models
Returns:
Scalar value or ``nan`` if there was an error
"""
models = self.__active_models_set
rl_models = [solve_laterality(self.__laterality, m) for m in models]
try:
value = structure_metrics.get_mult_struct_metric(self.__reader, rl_models,
self.__current_subject, metric_name)
except Exception as e:
log = logging.getLogger(__name__)
log.error(e)
value = float("nan")
raise
return value
[docs]class TractographyManager(object):
"""
A manager for tractography data
"""
def __init__(self, reader, ren, initial_subj=None, initial_space="subject"):
"""
Initializes the tractography manager
Args:
reader (braviz.visualization.base_reader.BaseReader) : Braviz reader
ren (vtkRenderer) : Renderer in which to draw the planeow
initial_subj : Code of initial subject, if None an arbitrary subject will be selected
initial_space (str) : Initial coordinate system
"""
self.reader = reader
self.ren = ren
if initial_subj is None:
initial_subj = reader.get("ids", None)[0]
self.__current_subject = initial_subj
self.__current_space = initial_space
self.__current_color = "orient"
self.__current_color_parameters = {"color": "orient", "scalars": None}
self.__opacity = 1.0
self.__lut = None
self.__show_color_bar = False
self.__ad_hoc_pd_mp_ac = None
self.__ad_hoc_fiber_checks = None
self.__ad_hoc_throug_all = True
self.__ad_hoc_visibility = False
self.__db_tracts = dict()
self.__active_db_tracts = set()
self.__bundle_colors = None
self.__bundle_labels = None
self.__color_bar_actor = None
self.__color_bar_widget = None
@do_and_render
[docs] def set_subject(self, subj):
"""
Sets the subject associated to the manager
Args:
subj : New subject
"""
self.__current_subject = subj
self.__reload_fibers()
@do_and_render
[docs] def set_current_space(self, space):
"""
Set current coordinate system
new_space (str) : new coordinate system, see :meth:`~braviz.readAndFilter.base_reader.BaseReader.get`
"""
self.__current_space = space
self.__reload_fibers()
@do_and_render
[docs] def set_bundle_from_checkpoints(self, checkpoints, through_all):
"""
Creates a fiber bundle based on a list of structures
Args:
checkpoints (list) : Structure model names list
through_all (bool): If ``True`` the bundle will contain lines that pass though all checkpoints,
otherwise it will contain lines that pass through any checkpoint
"""
checkpoints = list(checkpoints)
self.__ad_hoc_fiber_checks = checkpoints
self.__ad_hoc_throug_all = through_all
self.__ad_hoc_visibility = True
self.__ad_hock_checkpoints = checkpoints
if self.__ad_hoc_pd_mp_ac is None:
mapper = vtk.vtkPolyDataMapper()
actor = vtk.vtkActor()
self.ren.AddActor(actor)
actor.SetMapper(mapper)
else:
_, mapper, actor = self.__ad_hoc_pd_mp_ac
if through_all is True:
operation = "and"
else:
operation = "or"
try:
poly_data = self.reader.get("Fibers", self.__current_subject, waypoint=checkpoints, operation=operation,
space=self.__current_space, **self.__current_color_parameters)
except Exception as e:
actor.SetVisibility(0)
poly_data = None
self.__ad_hoc_pd_mp_ac = (poly_data, mapper, actor)
log = logging.getLogger(__name__)
log.warning("Fibers not found")
log.error(e.message)
raise
else:
actor.GetProperty().SetOpacity(self.__opacity)
mapper.SetInputData(poly_data)
actor.SetVisibility(1)
if self.__current_color == "bundle":
colors = self.get_bundle_colors()
c = colors[0]
actor.GetProperty().SetColor(*c)
self.__set_lut_in_maper(mapper)
self.__ad_hoc_pd_mp_ac = (poly_data, mapper, actor)
return
@do_and_render
[docs] def hide_checkpoints_bundle(self):
"""
Hide the checkpoints bundle created with :meth:`set_bundle_from_checkpoints`
"""
if self.__ad_hoc_pd_mp_ac is None:
return
act = self.__ad_hoc_pd_mp_ac[2]
act.SetVisibility(0)
self.__ad_hoc_visibility = False
def __set_lut_in_maper(self, mapper):
if self.__current_color == "bundle":
mapper.SetScalarVisibility(0)
return
mapper.SetScalarVisibility(1)
# print "setting lut"
if self.__lut is None:
mapper.SetColorModeToDefault()
else:
mapper.SetScalarVisibility(1)
mapper.UseLookupTableScalarRangeOn()
mapper.SetColorModeToMapScalars()
mapper.SetLookupTable(self.__lut)
@do_and_render
[docs] def add_from_database(self, b_id):
"""
Add a bundle from the database
See :mod:`braviz.readAndFilter.bundles_db`
Args:
b_id (int) : Bundle id in the database
"""
self.__active_db_tracts.add(b_id)
if b_id not in self.__db_tracts:
mapper = vtk.vtkPolyDataMapper()
actor = vtk.vtkActor()
actor.SetMapper(mapper)
self.ren.AddActor(actor)
self.__db_tracts[b_id] = (None, mapper, actor)
_, mapper, actor = self.__db_tracts[b_id]
try:
poly_data = self.get_polydata(b_id)
mapper.SetInputData(poly_data)
except Exception as e:
log = logging.getLogger(__name__)
log.error(e.message)
log.warning("Couldn't load fibers from db")
actor.SetVisibility(0)
raise
self.__db_tracts[b_id] = (poly_data, mapper, actor)
actor.SetVisibility(1)
actor.GetProperty().SetOpacity(self.__opacity)
if self.__current_color == "bundle":
colors = self.get_bundle_colors()
c = colors[self.__bundle_labels[b_id]]
actor.GetProperty().SetColor(*c)
self.__set_lut_in_maper(mapper)
[docs] def get_bundle_colors(self):
"""
Get a set of colors for coloring each active bundle in a different color
Returns:
A color palette with length equal to the number of active bundles
"""
# reserve one color for ad_hoc bundles
number_of_bundles = len(self.__active_db_tracts) + 1
if self.__bundle_colors is not None and len(self.__bundle_colors) == number_of_bundles:
return self.__bundle_colors
colors = sbs.color_palette("Set2", number_of_bundles)
self.__bundle_colors = colors
# print colors
return colors
@do_and_render
[docs] def set_show_color_bar(self, value):
"""
Activates a vtk color bar
Args:
value (bool) : If ``True`` the bar is activated, if ``False`` it is hidden
"""
self.__show_color_bar = bool(value)
self.__set_color_bar()
[docs] def get_show_color_bar(self):
"""
Status of the color bar
Returns:
``True`` if the color bar is active, ``False`` otherwise
"""
return self.__show_color_bar
[docs] def get_polydata(self, b_id):
"""
Gets the polydata object associated to a database bundle.
The current subject, coordinate system and scalars are maintained
Args:
b_id (int) : Bundle database id
Returns:
vtkPolyData from the requested bundle
"""
poly = self.reader.get("FIBERS", self.__current_subject, space=self.__current_space,
db_id=b_id, **self.__current_color_parameters)
return poly
@do_and_render
[docs] def hide_database_tract(self, bid):
"""
Hides a bundle previously added from the database
Args:
bid (int) : Bundle database id
"""
trio = self.__db_tracts.get(bid)
if trio is None:
return
actor = trio[2]
actor.SetVisibility(0)
self.__active_db_tracts.remove(bid)
@do_and_render
[docs] def change_color(self, new_color):
"""
Sets the coloring scheme for the rendered data.
Args:
new_color (str) : New coloring scheme, the following values are accepted
- ``bundle`` : A different color for each bundle
- ``orient`` : Color tractography based on local orientation
- ``rand`` : A different color for each line
- ``fa_p`` : Use FA values at each point and a lookuptable
- ``fa_l`` : Use mean fa of each line and a lookuptable
- ``md_p`` : Use MD values at each point and a lookuptable
- ``md_l`` : Use mean MD of each line and a lookuptable
- ``length``: Use length of each line and a lookuptable
- ``aparc``: Use the *aparc* label at each point and the freesurfer lookuptable
- ``wmparc``: Use the *wmparc* label at each point and the freesurfer lookuptable
"""
if self.__current_color == new_color:
return
self.__current_color = new_color
self.__lut = None
if new_color in ("bundle", "orient"):
self.__current_color_parameters["color"] = "orient"
self.__current_color_parameters["scalars"] = None
elif new_color == "rand":
self.__current_color_parameters["color"] = "rand"
self.__current_color_parameters["scalars"] = None
else:
self.__current_color_parameters["color"] = None
self.__current_color_parameters["scalars"] = new_color
self.__lut = self.reader.get(
"Fibers", None, scalars=new_color, lut=True)
# print self.__current_color
self.__set_color_bar()
self.__reload_fibers()
def __set_color_bar(self):
scalars = self.__current_color_parameters.get("scalars")
if (not self.__show_color_bar) or (scalars is None):
if self.__color_bar_actor is None:
return
else:
self.__color_bar_actor.SetVisibility(0)
else:
if self.__color_bar_actor is None:
self.__color_bar_actor = vtk.vtkScalarBarActor()
self.__color_bar_actor.SetNumberOfLabels(4)
self.__color_bar_widget = vtk.vtkScalarBarWidget()
self.__color_bar_widget.SetScalarBarActor(
self.__color_bar_actor)
self.__color_bar_widget.RepositionableOn()
iren = self.ren.GetRenderWindow().GetInteractor()
self.__color_bar_widget.SetInteractor(iren)
self.__color_bar_widget.On()
rep = self.__color_bar_widget.GetRepresentation()
coord1 = rep.GetPositionCoordinate()
coord2 = rep.GetPosition2Coordinate()
coord1.SetValue(0.85, 0.05)
coord2.SetValue(0.1, 0.9)
self.__color_bar_actor.SetVisibility(1)
self.__color_bar_actor.SetLookupTable(self.__lut)
# self.__color_bar_actor.SetTitle(scalars[:2].upper())
self.__color_bar_actor.SetTitle("")
self.__color_bar_widget.On()
def __reload_fibers(self):
# reload ad_hoc
log = logging.getLogger(__name__)
if self.__ad_hoc_visibility is True:
try:
self.set_bundle_from_checkpoints(
self.__ad_hoc_fiber_checks, self.__ad_hoc_throug_all)
except Exception as e:
log.exception(e)
# reload db
for bid in self.__active_db_tracts:
try:
self.add_from_database(bid)
except Exception as e:
log.exception(e)
@do_and_render
[docs] def set_active_db_tracts(self, new_set):
"""
Selects active database tracts
Args:
new_set (list) : List of database ids
"""
new_set = set(new_set)
to_hide = self.__active_db_tracts - new_set
to_add = new_set - self.__active_db_tracts
errors = 0
self.__bundle_labels = {b: i+1 for i,b in enumerate(new_set)}
for i in to_hide:
self.hide_database_tract(i)
self.__active_db_tracts = new_set
for i in to_add:
try:
self.add_from_database(i)
except Exception as e:
log = logging.getLogger(__name__)
log.error(e)
errors += 1
if errors > 0:
log = logging.getLogger(__name__)
log.warning("Couldn't load all tracts")
if self.__current_color == "bundle":
# we need to refresh all active bundles to get colors right
self.__reload_fibers()
@do_and_render
[docs] def set_opacity(self, float_opacity):
"""
Sets opacity for the displayed bundles
Args:
float_opacity (float) : From 0 to 1; where 0 is transparent and 1 is opaque
"""
self.__opacity = float_opacity
self.__reload_fibers()
[docs] def get_scalar_from_db(self, scalar, bid):
"""
Gets an scalar metric from an active database bundle
Args:
scalar (str) : Scalar metric, available options are:
- ``number`` : Number of lines
- ``mean_length`` : Mean length of lines
- ``mean_fa`` : Mean FA of the bundle
- ``mean_md`` : Mean MD of the bundle
bid (int) : Database id
Returns:
Scalar value or ``nan`` if there was an error
"""
if bid in self.__active_db_tracts:
try:
if scalar in ("number", "mean_length"):
pd = self.__db_tracts[bid][0]
return structure_metrics.get_scalar_from_fiber_ploydata(pd, scalar)
elif scalar == "mean_fa":
fiber = self.reader.get("FIBERS", self.__current_subject, space=self.__current_space,
db_id=bid, color=None, scalars="fa_p")
n = structure_metrics.get_scalar_from_fiber_ploydata(
fiber, "mean_color")
return n
elif scalar == "mean_md":
fiber = self.reader.get("FIBERS", self.__current_subject, space=self.__current_space,
db_id=bid, color=None, scalars="md_p")
n = structure_metrics.get_scalar_from_fiber_ploydata(
fiber, "mean_color")
return n
except Exception as e:
log = logging.getLogger(__name__)
log.exception(e)
return float("nan")
[docs] def get_scalar_from_structs(self, scalar):
"""
Gets an scalar metric from the active checkpoints bundle
see :meth:`set_bundle_from_checkpoints`
Args:
scalar (str) : Scalar metric, available options are:
- ``number`` : Number of lines
- ``mean_length`` : Mean length of lines
- ``mean_fa`` : Mean FA of the bundle
- ``mean_md`` : Mean MD of the bundle
Returns:
Scalar value or ``nan`` if there was an error
"""
if self.__ad_hoc_visibility is False:
return float("nan")
try:
if scalar in ("number", "mean_length"):
fiber = self.__ad_hoc_pd_mp_ac[0]
n = structure_metrics.get_scalar_from_fiber_ploydata(
fiber, scalar)
return n
elif scalar == "mean_fa":
operation = "and" if self.__ad_hoc_throug_all else "or"
fiber = self.reader.get("Fibers", self.__current_subject, waypoint=self.__ad_hock_checkpoints,
operation=operation, space=self.__current_space, color=None, scalars="fa_p")
n = structure_metrics.get_scalar_from_fiber_ploydata(
fiber, "mean_color")
return n
elif scalar == "mean_md":
operation = "and" if self.__ad_hoc_throug_all else "or"
fiber = self.reader.get("Fibers", self.__current_subject, waypoint=self.__ad_hock_checkpoints,
operation=operation, space=self.__current_space, color=None, scalars="md_p")
n = structure_metrics.get_scalar_from_fiber_ploydata(
fiber, "mean_color")
return n
except Exception:
return float("nan")
return float("nan")
[docs]class TraculaManager(object):
"""
A data manager for Tracula bundles
"""
def __init__(self, reader, ren, initial_subj=None, initial_space="subject"):
"""
Initializes the manager
Args:
reader (braviz.visualization.base_reader.BaseReader) : Braviz reader
ren (vtkRenderer) : Renderer in which to draw the models
initial_subj : Code of initial subject, if None an arbitrary subject will be selected
initial_space (str) : Initial coordinate system
"""
self.ren = ren
if initial_subj is None:
initial_subj = reader.get("ids", None)[0]
self.__active_bundles_set = set()
self.__pd_map_act = dict()
self.__current_subject = initial_subj
self.__reader = reader
self.__current_space = initial_space
self.__actor_to_model = {} # for picking
# visual attributes
self.__opacity = 1
self.reload_bundles(
subj=initial_subj, space=initial_space, skip_render=True)
@do_and_render
[docs] def reload_bundles(self, subj, space):
"""
Reloads all bundles
Args:
subj : Code for new subject, if ``None`` the subject is not changed
space (str) : new coordinate system, if ``None`` the coordinates are not changed
"""
self.__current_subject = subj
self.__current_space = space
log = logging.getLogger(__name__)
for b in self.__active_bundles_set:
try:
self.__load_bundle(b)
except Exception as e:
log.exception(e)
self.__hide_bundle(b)
@do_and_render
[docs] def set_bundles(self, bundle_names):
"""
Sets the currently shown bundles
Args:
bundle_names (set) : An iterable of strings with names of tracula bundles.
"""
wanted_bundles = frozenset(bundle_names)
to_add = wanted_bundles - self.__active_bundles_set
to_hide = self.__active_bundles_set - wanted_bundles
for b in to_add:
self.__load_bundle(b)
for b in to_hide:
self.__hide_bundle(b)
self.__active_bundles_set = wanted_bundles
@do_and_render
[docs] def set_opacity(self, int_opacity):
"""
Opacity for displaying the models
Args:
int_opacity (int) : A number from 0 to 100; where 0 is invisible and 100 is opaque
"""
for b in self.__active_bundles_set:
_, _, ac = self.__pd_map_act[b]
ac.GetProperty().SetOpacity(int_opacity / 100)
def __load_bundle(self, bundle_name):
trio = self.__pd_map_act.get(bundle_name)
if trio is None:
color = self.__reader.get(
"TRACULA", self.__current_subject, name=bundle_name, color=True)
mapper = vtk.vtkPolyDataMapper()
mapper.ScalarVisibilityOff()
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.GetProperty().SetColor(color)
self.ren.AddActor(actor)
else:
pd, mapper, actor = trio
try:
pd = self.__reader.get(
"TRACULA", self.__current_subject, name=bundle_name, space=self.__current_space)
except Exception as e:
log = logging.getLogger(__name__)
log.exception(e)
actor.SetVisibility(0)
pd = None
else:
mapper.SetInputData(pd)
actor.SetVisibility(1)
self.__pd_map_act[bundle_name] = (pd, mapper, actor)
def __hide_bundle(self, bundle_name):
trio = self.__pd_map_act.get(bundle_name)
if trio is None:
return
ac = trio[2]
ac.SetVisibility(0)
@property
def active_bundles(self):
"""
Gets the set of active bundles
Returns:
A frozenSet of currently active bundles
"""
return self.__active_bundles_set
[docs]class SurfaceManager(object):
"""
A data manager for freesurfer sufaces parcelations
"""
def __init__(self, reader, ren, iren, initial_subj=None, initial_space="subject", picker=None,
persistent_cone=False):
"""
Initializes the manager
Args:
reader (braviz.visualization.base_reader.BaseReader) : Braviz reader
ren (vtkRenderer) : Renderer in which to draw the plane
iren (vtkRenderWindowInteractor) : The render window interactor of the output window
initial_subj : Code of initial subject, if None an arbitrary subject will be selected
initial_space (str) : Initial coordinate system
picker (vtkPicker) : A vtkPicker may be used to pick on several objects. If None a new picker is created
persistent_cone (bool) : If ``True`` the cone used for picking will not disappear at the end of
the operation
"""
self.ren = ren
self.reader = reader
self.picker = picker
self.iren = iren
self.picking_event = vtk.vtkCommand.UserEvent + 1
self.__persistent_cone = persistent_cone
self.__last_picked_pos = None
self.__left_active = False
self.__right_active = False
self.__current_surface = "white"
self.__current_scalars = "curv"
self.__lut = None
self.__surf_trios = {}
self.__current_space = initial_space
self.__subject = initial_subj
self.__opacity = 100
self.__active_color_bar = False
self.__color_bar_actor = None
self.__color_bar_widget = None
# for interaction
if self.picker is not None:
self.__picking_dict = dict()
self.__cone_trio = None
self.__locators = dict()
self.__active_picking = False
self.__picking_events = dict()
self.__picking_text = None
self.__create_pick_cone()
self.__create_pick_text()
self.__setup_picking()
self.__update_lut()
def __create_pick_cone(self):
coneSource = vtk.vtkConeSource()
coneSource.CappingOn()
coneSource.SetHeight(12)
coneSource.SetRadius(5)
coneSource.SetResolution(31)
coneSource.SetCenter(6, 0, 0)
coneSource.SetDirection(-1, 0, 0)
coneMapper = vtk.vtkDataSetMapper()
coneMapper.SetInputConnection(coneSource.GetOutputPort())
redCone = vtk.vtkActor()
redCone.PickableOff()
redCone.SetMapper(coneMapper)
redCone.GetProperty().SetColor(1, 0, 0)
redCone.SetVisibility(0)
self.ren.AddActor(redCone)
self.__cone_trio = coneSource, coneMapper, redCone
def __create_pick_text(self):
text2 = vtk.vtkTextActor()
cor = text2.GetPositionCoordinate()
cor.SetCoordinateSystemToNormalizedDisplay()
text2.SetPosition([0.99, 0.01])
text2.SetInput('probando')
tprop = text2.GetTextProperty()
tprop.SetJustificationToRight()
tprop.SetFontSize(18)
self.ren.AddActor(text2)
text2.SetVisibility(0)
self.__picking_text = text2
def __point_cone(self, nx, ny, nz):
actor = self.__cone_trio[2]
actor.SetOrientation(0.0, 0.0, 0.0)
n = np.sqrt(nx ** 2 + ny ** 2 + nz ** 2)
if nx < 0.0:
actor.RotateWXYZ(180, 0, 1, 0)
n = -n
actor.RotateWXYZ(180, (nx + n) * 0.5, ny * 0.5, nz * 0.5)
def __setup_picking(self):
log = logging.getLogger(__name__)
def get_message(picker):
hemi = self.__picking_dict[id(picker.GetProp3D())]
pd = self.__surf_trios[hemi][0]
ptId = picker.GetPointId()
point_data = pd.GetPointData()
scalars = point_data.GetScalars()
scalar = self.__current_scalars
t = scalars.GetTuple(ptId)
annotations = {'aparc', 'aparc.a2009s', 'BA', "aparc.DKTatlas40"}
if scalar in annotations:
label = self.__lut.GetAnnotation(int(t[0]))
return "%s-Label: %s" % (scalar, label)
return "%s = %f" % (scalar, t[0])
def picking(caller, event):
active_picking = self.__active_picking
if event == 'MouseMoveEvent' and not active_picking:
return
if event == 'LeftButtonReleaseEvent':
self.__active_picking = False
if self.__persistent_cone is False:
self.__cone_trio[2].SetVisibility(0)
self.__picking_text.SetVisibility(0)
log.debug("done picking")
return
x, y = caller.GetEventPosition()
picked = self.picker.Pick(x, y, 0, self.ren)
p = self.picker.GetPickPosition()
n = self.picker.GetPickNormal()
picked_prop = self.picker.GetProp3D()
if picked and (id(picked_prop) in self.__picking_dict):
self.__active_picking = True
redCone = self.__cone_trio[2]
redCone.InvokeEvent(self.picking_event)
redCone.SetPosition(p)
self.__last_picked_pos = p
self.__point_cone(*n)
self.__picking_text.SetVisibility(1)
redCone.SetVisibility(1)
message = get_message(self.picker)
self.__picking_text.SetInput(message)
event_id = self.__picking_events[event]
command = caller.GetCommand(event_id)
command.SetAbortFlag(1)
self.iren.Render()
else:
self.__active_picking = False
if self.__persistent_cone is False:
self.__cone_trio[2].SetVisibility(0)
self.__picking_text.SetVisibility(0)
return
iren = self.iren
self.__picking_events["LeftButtonPressEvent"] = iren.AddObserver(vtk.vtkCommand.LeftButtonPressEvent, picking,
10)
iren.AddObserver(vtk.vtkCommand.LeftButtonReleaseEvent, picking, 10)
self.__picking_events["MouseMoveEvent"] = iren.AddObserver(
vtk.vtkCommand.MouseMoveEvent, picking, 10)
def __update_hemisphere(self, h):
# print "updating hemisphere ",h
if h == "l":
active = self.__left_active
elif h == "r":
active = self.__right_active
else:
log = logging.getLogger(__name__)
log.error("Unknown hemisphere %s" % h)
raise Exception("Unknown hemisphere %s" % h)
trio = self.__surf_trios.get(h)
if not active:
if trio is None:
return
ac = trio[2]
ac.SetVisibility(0)
return
if trio is None:
mapper = vtk.vtkPolyDataMapper()
mapper.SetLookupTable(self.__lut)
actor = vtk.vtkActor()
actor.SetMapper(mapper)
self.ren.AddActor(actor)
self.__picking_dict[id(actor)] = h
locator = vtk.vtkCellTreeLocator()
locator.LazyEvaluationOn()
self.__locators[h] = locator
if self.picker is not None:
self.picker.AddLocator(locator)
self.picker.AddPickList(actor)
else:
surf, mapper, actor = trio
try:
surf = self.reader.get("surf", self.__subject, name=self.__current_surface, hemi=h,
scalars=self.__current_scalars,
space=self.__current_space)
except Exception as e:
log = logging.getLogger(__name__)
log.exception(e)
actor.SetVisibility(0)
surf = None
else:
mapper.SetInputData(surf)
actor.SetVisibility(1)
actor.GetProperty().SetOpacity(self.__opacity / 100)
self.__locators[h].SetDataSet(surf)
trio = surf, mapper, actor
self.__surf_trios[h] = trio
def __update_lut(self):
ref = self.__subject
lut = self.reader.get(
"SURF_SCALAR", ref, scalars=self.__current_scalars, lut=True, hemi="l")
for trio in self.__surf_trios.itervalues():
mapper = trio[1]
mapper.SetLookupTable(lut)
self.__lut = lut
if (self.__color_bar_actor is not None) and self.__active_color_bar:
self.__color_bar_actor.SetLookupTable(lut)
def __update_both(self):
self.__update_hemisphere("r")
self.__update_hemisphere("l")
@do_and_render
[docs] def set_hemispheres(self, left=None, right=None):
"""
Sets the active hemisphers
Args:
left (bool) : If ``True`` the left hemisphere is activated, if ``False`` it is deactivated,
if ``None`` it is unchanged
right (bool) : If ``True`` the right hemisphere is activated, if ``False`` it is deactivated,
if ``None`` it is unchanged
"""
if left is not None:
left = bool(left)
if left != self.__left_active:
self.__left_active = left
self.__update_hemisphere("l")
if right is not None:
right = bool(right)
if right != self.__right_active:
self.__right_active = right
self.__update_hemisphere("r")
@do_and_render
[docs] def set_scalars(self, scalars):
"""
Sets the current scalars to use for the surfaces
Args:
scalars (str) : See :meth:`braviz.readAndFilter.base_reader.BaseReader.get` for options
"""
if scalars == self.__current_scalars:
return
self.__current_scalars = scalars
self.__update_both()
self.__update_lut()
@do_and_render
[docs] def set_surface(self, surface):
"""
Sets the current surface to display at both hemispheres
Args:
surface (str) : See :meth:`braviz.readAndFilter.base_reader.BaseReader.get` for options
"""
surface = surface.lower()
if surface == self.__current_surface:
return
self.__current_surface = surface
self.__update_both()
@do_and_render
[docs] def show_color_bar(self, show):
"""
Activates a vtk color bar
Args:
value (bool) : If ``True`` the bar is activated, if ``False`` it is hidden
"""
if show == self.__active_color_bar:
return
self.__active_color_bar = show
if not show:
if self.__color_bar_actor is None:
return
self.__color_bar_actor.SetVisibility(0)
return
if self.__color_bar_actor is None:
self.__color_bar_actor = vtk.vtkScalarBarActor()
self.__color_bar_actor.SetNumberOfLabels(4)
self.__color_bar_widget = vtk.vtkScalarBarWidget()
self.__color_bar_widget.SetScalarBarActor(self.__color_bar_actor)
self.__color_bar_widget.RepositionableOn()
iren = self.iren
self.__color_bar_widget.SetInteractor(iren)
self.__color_bar_widget.On()
rep = self.__color_bar_widget.GetRepresentation()
coord1 = rep.GetPositionCoordinate()
coord2 = rep.GetPosition2Coordinate()
coord1.SetValue(0.01, 0.05)
coord2.SetValue(0.1, 0.9)
self.__color_bar_actor.SetVisibility(1)
self.__color_bar_actor.SetLookupTable(self.__lut)
self.__color_bar_actor.SetTitle("")
@do_and_render
[docs] def set_subject(self, new_subject):
"""
Change subject associated to the manager
Args:
new_subject : Id of new subject
"""
self.__subject = new_subject
self.__update_both()
@do_and_render
[docs] def set_space(self, new_space):
"""
Change current coordinate system
new_space (str) : new coordinate system, see :meth:`~braviz.readAndFilter.base_reader.BaseReader.get`
"""
self.__current_space = new_space
self.__update_both()
@do_and_render
[docs] def set_opacity(self, int_opacity):
"""
Opacity for displaying the surfaces
Args:
int_opacity (int) : A number from 0 to 100; where 0 is invisible and 100 is opaque
"""
if int_opacity == self.__opacity:
return
self.__opacity = int_opacity
for trio in self.__surf_trios.itervalues():
ac = trio[2]
opac = self.__opacity / 100
ac.GetProperty().SetOpacity(opac)
[docs] def hide_cone(self):
"""
Hides the picking cone
"""
self.__cone_trio[2].SetVisibility(0)
self.__picking_text.SetVisibility(0)
[docs] def get_last_picked_pos(self):
"""
Coordinates of the last picked position
Returns:
A tuple with the coordinates of the last pickedposition
"""
return self.__last_picked_pos
@property
def pick_cone_actor(self):
"""
Access to the pick cone actor
"""
return self.__cone_trio[2]
[docs]class OrthogonalPlanesViewer(object):
"""
A viewer with three orthogonal planes
It provides access to
- Images
- Surfaces
- A sphere
"""
def __init__(self, render_window_interactor, reader, widget):
"""
Initializes the viewer
Args:
render_window_interactor (vtkRenderWindowInteractor) : The intaractor that will be used with this viewer
widget (QObject) : Must implement *slice_change_handle* and *window_level_change_handle*
"""
# render_window_interactor.Initialize()
# render_window_interactor.Start()
self.iren = render_window_interactor
self.ren_win = render_window_interactor.GetRenderWindow()
self.ren = vtk.vtkRenderer()
self.ren.SetBackground((0.75, 0.75, 0.75))
self.ren.GradientBackgroundOn()
self.ren.SetBackground2((0.5, 0.5, 0.5))
self.ren.SetBackground((0.2, 0.2, 0.2))
self.ren.SetUseDepthPeeling(1)
self.ren_win.SetMultiSamples(0)
self.ren_win.AlphaBitPlanesOn()
self.ren.SetOcclusionRatio(0.1)
self.ren_win.AddRenderer(self.ren)
self.iren.SetInteractorStyle(vtk.vtkInteractorStyleTrackballCamera())
self.axes = OrientationAxes()
self.axes.initialize(self.iren)
self.light = vtk.vtkLight()
self.ren.AddLight(self.light)
self.light.SetLightTypeToHeadlight()
self.reader = reader
self.__widget = widget
self.picker = vtk.vtkCellPicker()
self.picker.SetTolerance(0.0005)
self.iren.SetPicker(self.picker)
# state
self.__current_subject = None
self.__current_space = "subject"
self.__current_class = None
self.__current_name = None
# internal data
self.__cursor = AdditionalCursors(self.ren)
self.__x_image_manager = ImageManager(self.reader, self.ren, widget=widget, interactor=self.iren,
picker=self.picker)
self.__y_image_manager = ImageManager(self.reader, self.ren, widget=widget, interactor=self.iren,
picker=self.picker)
self.__z_image_manager = ImageManager(self.reader, self.ren, widget=widget, interactor=self.iren,
picker=self.picker)
self.__image_planes = (
self.__x_image_manager, self.__y_image_manager, self.__z_image_manager)
self.x_image.change_image_orientation(0, skip_render=True)
self.y_image.change_image_orientation(1, skip_render=True)
self.z_image.change_image_orientation(2, skip_render=True)
self.hide_image(skip_render=True)
self.__sphere = SphereProp(self.ren)
self.__cortex = SurfaceManager(self.reader, self.ren, self.iren, self.__current_subject, self.__current_space,
picker=self.picker, persistent_cone=True)
self.__active_cursor_plane = True
[docs] def finish_initializing(self):
"""
Finish viewer initialization, only call this after calling "show" on the widget or its parents
"""
self._link_window_level()
self._connect_cursors()
self.ren.ResetCameraClippingRange()
self.ren.ResetCamera()
def _link_window_level(self):
"""
Link window and level of all planes
call after initializing the planes
"""
if self.__current_class == "IMAGE":
self.y_image.image_plane_widget.SetLookupTable(
self.x_image.image_plane_widget.GetLookupTable())
self.z_image.image_plane_widget.SetLookupTable(
self.x_image.image_plane_widget.GetLookupTable())
def _connect_cursors(self):
"""
Connects the additional cursors
"""
def draw_cursor2(caller, event):
self.cortex.hide_cone()
self.__active_cursor_plane = True
if caller == self.x_image.image_plane_widget:
axis = 0
elif caller == self.y_image.image_plane_widget:
axis = 1
else:
axis = 2
pw = self.image_planes[axis].image_plane_widget
coords = pw.GetCurrentCursorPosition()
assert coords is not None
self.__cursor.set_axis_coords(axis, coords)
def slice_movement(caller, event):
self.cortex.hide_cone()
self.__active_cursor_plane = True
last_pos = self.__cursor.get_coords()
if last_pos is None:
return
last_pos = np.array(last_pos)
if caller == self.x_image.image_plane_widget:
axis = 0
elif caller == self.y_image.image_plane_widget:
axis = 1
else:
axis = 2
sl = self.image_planes[axis].get_current_image_slice()
last_pos[axis] = sl
self.__cursor.set_axis_coords(axis, last_pos)
self.x_image.image_plane_widget.AddObserver(
self.x_image.image_plane_widget.cursor_change_event, draw_cursor2)
self.y_image.image_plane_widget.AddObserver(
self.y_image.image_plane_widget.cursor_change_event, draw_cursor2)
self.z_image.image_plane_widget.AddObserver(
self.z_image.image_plane_widget.cursor_change_event, draw_cursor2)
self.x_image.image_plane_widget.AddObserver(
self.x_image.image_plane_widget.slice_change_event, slice_movement)
self.y_image.image_plane_widget.AddObserver(
self.y_image.image_plane_widget.slice_change_event, slice_movement)
self.z_image.image_plane_widget.AddObserver(
self.z_image.image_plane_widget.slice_change_event, slice_movement)
def change_cursor_to_cone(caller, event):
self.__active_cursor_plane = False
self.__cursor.hide()
self.cortex.pick_cone_actor.AddObserver(
self.cortex.picking_event, change_cursor_to_cone)
@do_and_render
[docs] def show_image(self):
"""
Shows all planes
"""
for im in self.__image_planes:
im.show_image(skip_render=True)
@do_and_render
[docs] def hide_image(self):
"""
Hide all planes
"""
for im in self.__image_planes:
im.hide_image(skip_render=True)
@do_and_render
[docs] def change_subject(self, subj):
"""
Changes the subject associated to the viewer
Args:
new_subject : new subject id
"""
ex = None
for im in self.__image_planes:
try:
im.change_subject(subj, skip_render=True, force=True)
except Exception as e:
ex = e
try:
self.__cortex.set_subject(subj, skip_render=True)
except Exception:
log = logging.getLogger(__file__)
log.warning("Cortex not found for subject %s" % subj)
if ex is not None:
raise ex
self.__cursor.set_image(self.x_image.image_plane_widget.GetInput())
self._link_window_level()
@do_and_render
[docs] def change_image_modality(self, image_class, image_name, contrast=1):
"""
Change image modality in all planes
See :meth:`ImageManager.change_image_modality`
Args:
image_class (str): New image class (IMAGE, LABELS or FMRI)
image_name (str): New image name, for fMRI enter the paradigm here
contrast (int): If modality is fMRI the index of the contrast
"""
log = logging.getLogger(__name__)
if image_class is not None:
image_class = image_class.upper()
if image_name is not None:
image_name = image_name.upper()
for im in self.__image_planes:
try:
im.change_image_modality(
image_class, image_name, skip_render=True, contrast=contrast)
except Exception as e:
log.exception(e)
self.__current_class = image_class
self.__current_name = image_name
self.__cursor.set_image(self.x_image.image_plane_widget.GetInput())
self._link_window_level()
[docs] def get_number_of_slices(self):
"""
Get number of slices in each plane
Returns:
A tuple with the image dimension
"""
n_slices = self.x_image.image_plane_widget.GetInput().GetDimensions()
return n_slices
[docs] def get_current_slice(self):
"""
Get current slices of all planes
Returns:
A tuple with the current slice of each plane (x,y,z)
"""
return (self.x_image.get_current_image_slice(),
self.y_image.get_current_image_slice(),
self.z_image.get_current_image_slice(),)
[docs] def get_camera_parameters(self):
"""
Gets current camera parameters
Returns:
focal_point, position, view_up
"""
cam1 = self.ren.GetActiveCamera()
fp = cam1.GetFocalPoint()
pos = cam1.GetPosition()
vu = cam1.GetViewUp()
return fp, pos, vu
[docs] def set_camera(self, focal_point, position, view_up):
"""
Sets the camera position
Args:
focal_point (tuple) : Focal point
position (tuple) : Camera position
view_up (tuple) : View up vector
"""
cam1 = self.ren.GetActiveCamera()
cam1.SetFocalPoint(focal_point)
cam1.SetPosition(position)
cam1.SetViewUp(view_up)
self.ren.ResetCameraClippingRange()
self.ren_win.Render()
@property
def image_planes(self):
"""
Access to the image planes array
"""
return self.__image_planes
@property
def x_image(self):
"""
Access to the image manager perpendicular to x
"""
return self.__x_image_manager
@property
def y_image(self):
"""
Access to the image manager perpendicular to y
"""
return self.__y_image_manager
@property
def z_image(self):
"""
Access to the image manager perpendicular to z
"""
return self.__z_image_manager
@property
def sphere(self):
"""
Access to the sphere
"""
return self.__sphere
@property
def cortex(self):
"""
Access to the surface manager
"""
return self.__cortex
[docs] def current_position(self):
"""
Last picked position, either on the planes or on the surface
Returns:
Coordinates of the last picked position
"""
if self.__active_cursor_plane:
return self.__cursor.get_position()
else:
return self.cortex.get_last_picked_pos()
@do_and_render
[docs] def change_space(self, new_space):
"""
Changes the current coordinate system
Args:
new_space (str) : New coordinate system
"""
for im in self.image_planes:
im.change_space(new_space, skip_render=True)
self.cortex.set_space(new_space, skip_render=True)
self.__current_space = new_space
self.__cursor.set_image(self.x_image.image_plane_widget.GetInput())
self.iren.Render()
[docs]class MeasurerViewer(object):
"""
A viewer that allows the user to measure the distance between two points on images using a vtkMeasureWidget
"""
camera_positions = {
0: ((-5.5, -5.5, 4.5), (535, -5.5, 4.5), (0, 0, 1)), # SAGITAL
1: ((-5.5, -8, 2.8), (-5.5, 530, 2.8), (1, 0, 0)), # CORONAL
2: ((-3.5, 0, 10), (-3.5, 0, 550), (0, 1, 0)), # AXIAL
}
def __init__(self, render_window_interactor, reader, widget):
"""
Initializes the viewer
Args:
render_window_interactor (vtkRenderWindowInteractor) : The intaractor that will be used with this viewer
widget (QObject) : Must implement *slice_change_handle*, *window_level_change_handle*
and *distance_changed_handle*
"""
self.iren = render_window_interactor
self.ren_win = render_window_interactor.GetRenderWindow()
self.ren = vtk.vtkRenderer()
self.ren.SetBackground((0.75, 0.75, 0.75))
self.ren.GradientBackgroundOn()
self.ren.SetBackground2((0.5, 0.5, 0.5))
self.ren.SetBackground((0.2, 0.2, 0.2))
self.ren.SetUseDepthPeeling(1)
self.ren_win.SetMultiSamples(0)
self.ren_win.AlphaBitPlanesOn()
self.ren.SetOcclusionRatio(0.1)
self.ren_win.AddRenderer(self.ren)
self.iren.SetInteractorStyle(vtk.vtkInteractorStyleTrackballCamera())
self.axes = OrientationAxes()
self.axes.initialize(self.iren)
self.light = vtk.vtkLight()
self.ren.AddLight(self.light)
self.light.SetLightTypeToHeadlight()
self.reader = reader
self.__widget = widget
self.picker = vtk.vtkCellPicker()
self.picker.SetTolerance(0.0005)
self.iren.SetPicker(self.picker)
self.__measure_axis = None
self.__pax1, self.__pax2 = None, None # perpendicular to measure axis
self.set_measure_axis("axial", skip_render=True)
# state
self.__current_subject = None
self.__current_space = "talairach"
self.__current_modality = None
self.__current_class = None
# internal data
self.__x_image_manager = ImageManager(self.reader, self.ren, widget=widget, interactor=self.iren,
picker=self.picker)
self.__y_image_manager = ImageManager(self.reader, self.ren, widget=widget, interactor=self.iren,
picker=self.picker)
self.__z_image_manager = ImageManager(self.reader, self.ren, widget=widget, interactor=self.iren,
picker=self.picker)
self.__image_planes = (
self.__x_image_manager, self.__y_image_manager, self.__z_image_manager)
self.x_image.change_image_orientation(0, skip_render=True)
self.y_image.change_image_orientation(1, skip_render=True)
self.z_image.change_image_orientation(2, skip_render=True)
# for pw in self.__image_planes:
# pw.image_plane_widget.InteractionOff()
self.hide_image(skip_render=True)
self.__placed = False
self.measure_widget = vtk.vtkDistanceWidget()
self.measure_widget.KeyPressActivationOff()
self.measure_repr = vtk.vtkDistanceRepresentation3D()
self.measure_repr.GetLineProperty().SetLineWidth(2)
self.measure_repr.SetLabelFormat("")
self.measure_repr.RulerModeOn()
self.measure_repr.SetRulerDistance(5.0)
self.measure_widget.SetRepresentation(self.measure_repr)
self.measure_widget.SetInteractor(self.iren)
self.obs_id, self.obs_id2, self.obs_id3 = None, None, None
def _restrict_points_to_plane(self, caller, event):
"""
Restrict the measure widget points to the plane surfaces
"""
modifiers = QApplication.keyboardModifiers()
straight = False
if QtCore.Qt.ControlModifier & modifiers:
straight = True
ax = self.__measure_axis
slice_coords = self.image_planes[
ax].image_plane_widget.GetSlicePosition()
plane_point = np.zeros(3)
plane_point[ax] = slice_coords
pa1, pa2 = self.__pax1, self.__pax2
representation = caller.GetRepresentation()
r1 = representation.GetPoint1Representation()
r2 = representation.GetPoint2Representation()
r1i = r1.GetInteractionState()
r2i = r2.GetInteractionState()
camera = self.ren.GetActiveCamera()
view_vec = np.array(camera.GetDirectionOfProjection())
if r1i > 0 or not self.__placed:
p1 = np.zeros(3)
representation.GetPoint1WorldPosition(p1)
if np.dot(view_vec, p1) != 0:
t = (slice_coords - p1[ax]) / view_vec[ax]
p1 = p1 + view_vec * t
else:
p1[ax] = slice_coords
if straight and self.__placed:
ref = np.zeros(3)
representation.GetPoint2WorldPosition(ref)
dif = np.abs(p1 - ref)
if dif[pa1] > dif[pa2]:
p1[pa2] = ref[pa2]
else:
p1[pa1] = ref[pa1]
representation.SetPoint1WorldPosition(p1)
self.__placed = True
else:
p2 = np.zeros(3)
representation.GetPoint2WorldPosition(p2)
if np.dot(view_vec, p2) != 0:
t = (slice_coords - p2[ax]) / view_vec[ax]
p2 = p2 + view_vec * t
else:
p2[ax] = slice_coords
if straight:
ref = np.zeros(3)
representation.GetPoint1WorldPosition(ref)
dif = np.abs(p2 - ref)
if dif[pa1] > dif[pa2]:
p2[pa2] = ref[pa2]
else:
p2[pa1] = ref[pa1]
representation.SetPoint2WorldPosition(p2)
[docs] def finish_initializing(self):
"""
Finish viewer initialization, only call this after calling "show" on the widget or its parents
"""
self.measure_widget.SetPriority(
self.x_image.image_plane_widget.GetPriority() + 1)
self.obs_id = self.measure_widget.AddObserver(
vtk.vtkCommand.PlacePointEvent, self._restrict_points_to_plane)
self.obs_id2 = self.measure_widget.AddObserver(
vtk.vtkCommand.InteractionEvent, self._restrict_points_to_plane)
self.obs_id3 = self.measure_widget.AddObserver(vtk.vtkCommand.InteractionEvent,
self.emit_distance_changed_signal)
self._link_window_level()
self.ren.ResetCameraClippingRange()
self.ren.ResetCamera()
self.measure_widget.On()
def _link_window_level(self):
"""
Link window and level of all planes
call after initializing the planes
"""
if self.__current_class == "IMAGE":
self.y_image.image_plane_widget.SetLookupTable(
self.x_image.image_plane_widget.GetLookupTable())
self.z_image.image_plane_widget.SetLookupTable(
self.x_image.image_plane_widget.GetLookupTable())
def slice_movement(caller, event):
if caller == self.x_image.image_plane_widget:
axis = 0
elif caller == self.y_image.image_plane_widget:
axis = 1
else:
axis = 2
sl = self.image_planes[axis].get_current_image_slice()
if axis == self.__measure_axis and self.__placed:
c = self.image_planes[
axis].image_plane_widget.GetSlicePosition()
p1, p2 = np.zeros(3), np.zeros(3)
self.measure_repr.GetPoint1WorldPosition(p1)
self.measure_repr.GetPoint2WorldPosition(p2)
p1[axis] = c
p2[axis] = c
self.measure_repr.SetPoint1WorldPosition(p1)
self.measure_repr.SetPoint2WorldPosition(p2)
# self.ren_win.Render()
self.x_image.image_plane_widget.AddObserver(
self.x_image.image_plane_widget.slice_change_event, slice_movement)
self.y_image.image_plane_widget.AddObserver(
self.y_image.image_plane_widget.slice_change_event, slice_movement)
self.z_image.image_plane_widget.AddObserver(
self.z_image.image_plane_widget.slice_change_event, slice_movement)
@do_and_render
[docs] def set_measure_axis(self, axis_str):
"""
Set the measure plane to be perpendicular to the axis
Args:
axis_str (str) : "axial", "sagital" or "coronal"
"""
axis = _axis_dict[axis_str.lower()]
self.__measure_axis = axis
if axis == 0:
self.__pax1 = 1
self.__pax2 = 2
elif axis == 1:
self.__pax1 = 0
self.__pax2 = 2
else:
self.__pax1 = 0
self.__pax2 = 1
self.reset_camera(skip_render=True)
@do_and_render
[docs] def set_slice_coords(self, coords):
"""
Move the measure plane perpendicularly
Args:
coords (float) : New position across the axis perpendicular to the measure plane
"""
pw = self.image_planes[self.__measure_axis].image_plane_widget
pw.SetSlicePosition(coords)
pw.InvokeEvent(pw.slice_change_event)
[docs] def emit_distance_changed_signal(self, caller, event):
"""
Emit a Qt Signal through the associated widget
"""
d = self.distance
self.__widget.distance_changed_handle(d)
@do_and_render
[docs] def show_image(self):
"""
Shows all planes
"""
for im in self.__image_planes:
im.show_image(skip_render=True)
@do_and_render
[docs] def hide_image(self):
"""
Hide all planes
"""
for im in self.__image_planes:
im.hide_image(skip_render=True)
@do_and_render
[docs] def change_subject(self, subj):
"""
Changes the subject associated to the viewer
Args:
new_subject : new subject id
"""
log = logging.getLogger(__name__)
for im in self.__image_planes:
try:
im.change_subject(subj, skip_render=True)
except Exception as e:
log.exception(e)
self._link_window_level()
@do_and_render
[docs] def change_image_modality(self, image_class, mod, contrast=None):
"""
Change image modality in all planes
See :meth:`ImageManager.change_image_modality`
Args:
image_class (str): New image class, must be FMRI, IMAGE, LABEL or DTI
mod (str): New modality name, for fMRI enter the paradigm here
contrast (int): If modality is fMRI the index of the contrast
"""
if mod is not None:
mod = mod.upper()
if image_class is not None:
image_class = image_class.upper()
for im in self.__image_planes:
im.change_image_modality(image_class, mod, skip_render=True, contrast=contrast)
self.__current_modality = mod
self.__current_class = image_class
self._link_window_level()
[docs] def get_number_of_slices(self):
"""
Get number of slices in each plane
Returns:
A tuple with the image dimension
"""
n_slices = self.x_image.image_plane_widget.GetInput().GetDimensions()
return n_slices
[docs] def get_current_slice(self):
"""
Get current slices of all planes
Returns:
A tuple with the current slice of each plane (x,y,z)
"""
return (self.x_image.get_current_image_slice(),
self.y_image.get_current_image_slice(),
self.z_image.get_current_image_slice(),)
[docs] def get_camera_parameters(self):
"""
Gets current camera parameters
Returns:
focal_point, position, view_up
"""
cam1 = self.ren.GetActiveCamera()
fp = cam1.GetFocalPoint()
pos = cam1.GetPosition()
vu = cam1.GetViewUp()
return fp, pos, vu
@do_and_render
[docs] def reset_camera(self):
"""
Resets camera to the initial position
"""
fp, pos, vu = self.camera_positions[self.__measure_axis]
self.set_camera(fp, pos, vu, skip_render=True)
@do_and_render
[docs] def set_camera(self, focal_point, position, view_up):
"""
Sets the camera position
Args:
focal_point (tuple) : Focal point
position (tuple) : Camera position
view_up (tuple) : View up vector
"""
cam1 = self.ren.GetActiveCamera()
cam1.SetFocalPoint(focal_point)
cam1.SetPosition(position)
cam1.SetViewUp(view_up)
self.ren.ResetCameraClippingRange()
@property
def image_planes(self):
"""
Access to the image planes array
"""
return self.__image_planes
@property
def x_image(self):
"""
Access to the image manager perpendicular to x
"""
return self.__x_image_manager
@property
def y_image(self):
"""
Access to the image manager perpendicular to y
"""
return self.__y_image_manager
@property
def z_image(self):
"""
Access to the image manager perpendicular to z
"""
return self.__z_image_manager
@do_and_render
[docs] def change_space(self, new_space):
"""
Changes the current coordinate system
Args:
new_space (str) : New coordinate system
"""
for im in self.image_planes:
im.change_space(new_space, skip_render=True)
self.__current_space = new_space
self.iren.Render()
@do_and_render
[docs] def reset_measure(self):
"""
Reset the measure widget, remove both points from the scene
"""
self.measure_widget.Off()
self.measure_widget.SetWidgetStateToStart()
self.measure_widget.On()
self.__placed = False
self.__widget.distance_changed_handle(np.nan)
@property
def distance(self):
"""
Current distance measured by the measure widget
"""
if not self.__placed:
return np.nan
else:
return self.measure_repr.GetDistance()
@property
def point1(self):
"""
Get coordinates of first measure point
"""
if self.__placed:
p1 = np.zeros(3)
self.measure_repr.GetPoint1WorldPosition(p1)
return p1
else:
return None
@property
def point2(self):
"""
Get coordinates of second measure point
"""
if self.__placed:
p2 = np.zeros(3)
self.measure_repr.GetPoint2WorldPosition(p2)
return p2
else:
return None
@do_and_render
[docs] def set_points(self, p1, p2):
"""
Set coordinates for both points
Args:
p1 (tuple) : First point coordinates
p2 (tuple) : Second point coordinates
"""
self.measure_repr.SetPoint1WorldPosition(p1)
self.measure_repr.SetPoint2WorldPosition(p2)
if not self.__placed:
self.measure_widget.SetWidgetStateToManipulate()
acs = vtk.vtkPropCollection()
self.measure_repr.GetActors(acs)
self.measure_repr.VisibilityOn()
self.__placed = True
@do_and_render
[docs] def set_measure_color(self, r, g, b):
"""
Set color of the measure widget
Args:
r (int) : red
g (int) : green
b (int) : blue
"""
r, g, b = r / 255, g / 255, b / 255
self.measure_repr.GetLineProperty().SetColor(r, g, b)
self.measure_repr.GetGlyphActor().GetProperty().SetColor(r, g, b)
[docs]class AdditionalCursors(object):
"""
An additional set of cursors to use when those included in vtkImageWidget are not flexible enough
"""
def __init__(self, ren):
"""
Initializes the cursors
Args:
ren (vtkRenderer) : Renderer into which the cursors will be drawn
"""
self.__cursors = cursors()
self.__cursors.SetVisibility(0)
self.__image = None
self.__coords = None
self.__axis = None
ren.AddActor(self.__cursors)
[docs] def set_image(self, img):
"""
Image to use as reference for the cursors
Args:
img (vtkImageData) : The cursors will stick to this image
"""
self.__image = img
dim = img.GetDimensions()
sp = img.GetSpacing()
org = img.GetOrigin()
max_sp = max(sp)
self.__cursors.set_dimensions(*dim)
self.__cursors.set_spacing(*sp)
self.__cursors.set_origin(*org)
self.__cursors.set_delta(max_sp / 5)
[docs] def get_position(self):
"""
Current position of the cursors
Returns:
Coordinates of the last picked position (in mm)
"""
if self.__coords is None:
return None
pos = np.array(self.__coords)
org = np.array(self.__image.GetOrigin())
sp = np.array(self.__image.GetSpacing())
return pos * sp + org
[docs] def get_coords(self):
"""
Voxel coordinates of last picked position
Returns:
Coordinates of last picked position in voxels
"""
return self.__coords
[docs] def set_axis_coords(self, axis=None, coords=None):
"""
Set position of the cursors
Args:
axis (int) : Axis perpendicular to the cursor, 0 for x, 1 for y and 2 for z
coords (tuple) : Position of the cursor in voxels
"""
if axis is None or coords is None or self.__image is None:
self.__cursors.SetVisibility(0)
self.__coords = None
self.__cursors.SetVisibility(1)
if axis != self.__axis:
self.__cursors.change_axis(axis)
self.__axis = axis
self.__cursors.set_cursor(*coords)
self.__coords = coords
self.__cursors.SetVisibility(1)
pass
[docs] def hide(self):
"""
Hide cursor
"""
self.__cursors.SetVisibility(0)
[docs]class SphereProp(object):
"""
An sphere that can be added to any viewer to represent regions of interest
"""
def __init__(self, ren):
"""
Initializes the sphere prop
Args:
ren (vtkRenderer) : Renderer that will draw the sphere
"""
self.__source = vtk.vtkSphereSource()
self.__mapper = vtk.vtkPolyDataMapper()
self.__actor = vtk.vtkActor()
self.__center = None
self.__radius = None
self.__RESOLUTION = 20
self.__actor.SetMapper(self.__mapper)
self.__mapper.SetInputConnection(self.__source.GetOutputPort())
self.__source.SetThetaResolution(self.__RESOLUTION)
self.__source.SetPhiResolution(self.__RESOLUTION)
self.__source.LatLongTessellationOn()
self.__actor.SetVisibility(0)
self.__ren = ren
ren.AddActor(self.__actor)
[docs] def set_center(self, ctr):
"""
Set the center of the sphere
Args:
ctr (tuple) : center
"""
self.__source.SetCenter(*ctr)
self.__center = ctr
[docs] def set_radius(self, r):
"""
Set the radius of the sphere
Args:
r (float) : Sphere radius
"""
self.__source.SetRadius(r)
self.__radius = r
@property
def radius(self):
return self.__radius
@property
def center(self):
return tuple(self.__center)
@property
def visible(self):
return self.__actor.GetVisibility()
[docs] def set_repr(self, rep):
"""
Set representation of the sphere
Args:
rep (str): Options are ``"wireframe"`` or ``"surface"``
"""
if rep.startswith("w"):
self.__actor.GetProperty().SetRepresentationToWireframe()
else:
self.__actor.GetProperty().SetRepresentationToSurface()
[docs] def hide(self):
"""
Hide the sphere
"""
self.__actor.SetVisibility(0)
[docs] def show(self):
"""
Show the sphere
"""
self.__actor.SetVisibility(1)
[docs] def set_opacity(self, opac_int):
"""
Opacity of the sphere
Args:
opac_int (int) : A number from 0 to 100; where 0 is invisible and 100 is opaque
"""
opac = opac_int / 100.0
self.__actor.GetProperty().SetOpacity(opac)
[docs] def set_color(self, r, g, b):
"""
Set color of the measure widget
Args:
r (int) : red
g (int) : green
b (int) : blue
"""
r, g, b = map(lambda x: x / 255.0, (r, g, b))
self.__actor.GetProperty().SetColor(r, g, b)
[docs] def remove_from_renderer(self):
"""
Remove the sphere from the renderer
"""
self.__ren.RemoveActor(self.__actor)
[docs]class fMRI_viewer(object):
"""
A viewer for visualizaing fMRI data. It displays
- Images
- fMRI contours
"""
def __init__(self, render_window_interactor, reader, widget):
"""
Creates the fMRI viewer
Args:
render_window_interactor (vtkRenderWindowInteractor) : The intaractor that will be used with this viewer
reader (braviz.visualization.base_reader.BaseReader) : Braviz reader
widget (QObject) : Must implement *slice_change_handle*, *window_level_change_handle*
and *cursor_move_handler*
"""
self.iren = render_window_interactor
self.ren_win = render_window_interactor.GetRenderWindow()
self.ren = vtk.vtkRenderer()
self.ren.SetBackground((0.75, 0.75, 0.75))
self.ren.GradientBackgroundOn()
self.ren.SetBackground2((0.5, 0.5, 0.5))
self.ren.SetBackground((0.2, 0.2, 0.2))
self.ren.SetUseDepthPeeling(1)
self.ren_win.SetMultiSamples(0)
self.ren_win.AlphaBitPlanesOn()
self.ren.SetOcclusionRatio(0.1)
self.ren_win.AddRenderer(self.ren)
self.iren.SetInteractorStyle(vtk.vtkInteractorStyleTrackballCamera())
self.axes = OrientationAxes()
self.axes.initialize(self.iren)
self.light = vtk.vtkLight()
self.ren.AddLight(self.light)
self.light.SetLightTypeToHeadlight()
self.reader = reader
# state
self.__current_subject = None
self.__current_space = "func"
self.__current_paradigm = None
self.__current_contrast = 1
self.picker = vtk.vtkCellPicker()
self.picker.SetTolerance(0.0005)
self.iren.SetPicker(self.picker)
# internal data
self.__image_manager = ImageManager(self.reader, self.ren, widget=widget, interactor=self.iren,
picker=self.picker)
self.__cursor = AdditionalCursors(self.ren)
self.__contours = FmriContours(self.ren)
fmri_lut = self.reader.get("fMRI", self.__current_subject, lut=True)
self.__contours.set_lut(fmri_lut)
self.__image_loaded = False
# reset camera and render
self.reset_camera(0, skip_render=True)
# widget, signal handling
self.__widget = widget
[docs] def change_orientation(self, orientation_index):
"""
Changes the orientation of the Image Plane Widget
Args:
orientation_index (int) : 0 for x, 1 for y and 2 for z
"""
# find cursor position
pos = self.__cursor.get_coords()
self.image.change_image_orientation(orientation_index)
if pos is None:
new_slice = self.image.get_number_of_image_slices() // 2
else:
new_slice = int(pos[orientation_index])
self.__cursor.set_axis_coords(orientation_index, pos)
self.image.set_image_slice(new_slice)
def _connect_cursors(self):
def draw_cursor2(caller, event):
self.__active_cursor_plane = True
axis = self.image.image_plane_widget.GetPlaneOrientation()
pw = self.image.image_plane_widget
coords = pw.GetCurrentCursorPosition()
assert coords is not None
self.__cursor.set_axis_coords(axis, coords)
self.__widget.cursor_move_handler(coords)
def slice_movement(caller, event):
self.__active_cursor_plane = True
last_pos = self.__cursor.get_coords()
if last_pos is None:
return
last_pos = np.array(last_pos)
axis = self.image.image_plane_widget.GetPlaneOrientation()
sl = self.image.get_current_image_slice()
last_pos[axis] = sl
self.__cursor.set_axis_coords(axis, last_pos)
self.__widget.cursor_move_handler(last_pos)
self.image.image_plane_widget.AddObserver(
self.image.image_plane_widget.cursor_change_event, draw_cursor2)
self.image.image_plane_widget.AddObserver(
self.image.image_plane_widget.slice_change_event, slice_movement)
[docs] def current_coords(self):
"""
Get cursor coordinates
Returns:
A tuple of coordinates
"""
return self.__cursor.get_coords()
@do_and_render
[docs] def set_cursor_coords(self, coords):
"""
Set coordinates for the cursor
Args:
Coords (tuple) : New position for the cursor (in voxels)
"""
axis = self.image.image_plane_widget.GetPlaneOrientation()
self.__cursor.set_axis_coords(axis, coords)
img_slice = coords[axis]
self.image.set_image_slice(img_slice)
@property
def image(self):
"""
Access to ImageManager
"""
return self.__image_manager
@property
def contours(self):
"""
Access to FmriContours
"""
return self.__contours
@do_and_render
[docs] def change_subject(self, new_subj):
"""
Change subject associated to the plane
Args:
new_subj : Id of new subject
"""
if self.__current_subject != new_subj:
self.__current_subject = new_subj
self.update_view(skip_render=True)
@do_and_render
[docs] def change_paradigm(self, new_pdgm):
"""
Change fMRI paradigm
Args:
new_pdgm (str) : Must be one of the available fMRI paradigms
"""
if self.__current_paradigm != new_pdgm:
self.__current_paradigm = new_pdgm
self.update_view(skip_render=True)
@do_and_render
[docs] def change_contrast(self, new_contrast):
"""
Change contrast
Args:
new_contrast (int) : Index of new contrast (starting at 1)
"""
if self.__current_contrast != new_contrast:
self.__current_contrast = new_contrast
self.update_view(skip_render=True)
@do_and_render
[docs] def set_all(self, new_subject, new_pdgm, new_contrast):
"""
Set subject, paradigm and contrast
Args:
new_subject : Id of new subject
new_pdgm (str) : New paradigm, must be one of the available fMRI paradigms
new_contrast (int) : Index of new contrast (starting at 1)
"""
if self.__current_subject != new_subject:
self.__current_subject = new_subject
if self.__current_paradigm != new_pdgm:
self.__current_paradigm = new_pdgm
if self.__current_contrast != new_contrast:
self.__current_contrast = new_contrast
self.update_view(skip_render=True)
@do_and_render
[docs] def set_contour_value(self, value):
"""
Set value for the fMRI contours
Args:
value (float) : The iso-contours will be calculated at this value
"""
self.__contours.set_value(value)
@do_and_render
[docs] def set_contour_opacity(self, value):
"""
Opacity for displaying the contours
Args:
value (int) : A number from 0 to 100; where 0 is invisible and 100 is opaque
"""
opac = value / 100
self.__contours.actor.GetProperty().SetOpacity(opac)
@do_and_render
[docs] def set_contour_visibility(self, value):
"""
Set visibility of contours
Args:
value (bool) : If ``True`` show the contours, otherwise hide them
"""
self.__contours.actor.SetVisibility(value)
@do_and_render
[docs] def update_view(self):
"""
Resets all elements in the view
"""
if self.__current_subject is None or self.__current_paradigm is None or self.__current_contrast is None:
return
try:
self.image.change_subject(self.__current_subject)
except Exception:
pass
try:
self.image.change_space("func-%s" % self.__current_paradigm)
except Exception:
pass
self.image.change_image_modality(
"fMRI", self.__current_paradigm, contrast=self.__current_contrast)
if not self.__image_loaded:
self._connect_cursors()
self.__image_loaded = True
self.__cursor.set_image(self.image.image_plane_widget.GetInput())
if self.image.image_plane_widget.GetEnabled():
self.__contours.set_image(
self.image.image_plane_widget.alternative_img)
self.__contours.actor.SetVisibility(1)
else:
self.__contours.actor.SetVisibility(0)
__camera_positions_dict = {
0: ((-3.5, 0, 13), (157, 154, 130), (0, 0, 1)),
2: ((-3.5, 0, 10), (250, 0, 10), (0, 0, 1)),
1: ((-3.5, 0, 10), (-250, 0, 10), (0, 0, 1)),
4: ((-3.5, 0, 10), (-3.5, -200, 10), (0, 0, 1)),
3: ((-3.5, 0, 10), (-3.5, 200, 10), (0, 0, 1)),
5: ((-3, 0, 3), (-3, 0, 252), (0, 1, 0)),
6: ((-3, 0, 3), (-3, 0, -252), (0, 1, 0)),
}
@do_and_render
[docs] def reset_camera(self, position):
"""
resets the current camera to standard locations.
Args:
position (int) :
- 0: initial 3d view
- 1: left
- 2: right
- 3: front
- 4: back
- 5: top
- 6: bottom
"""
focal, position, viewup = self.__camera_positions_dict[position]
cam1 = self.ren.GetActiveCamera()
cam1.SetFocalPoint(focal)
cam1.SetPosition(position)
cam1.SetViewUp(viewup)
self.ren.ResetCameraClippingRange()
[docs] def get_camera_parameters(self):
"""
Gets current camera parameters
Returs:
focal_point, position, view_up
"""
cam1 = self.ren.GetActiveCamera()
fp = cam1.GetFocalPoint()
pos = cam1.GetPosition()
vu = cam1.GetViewUp()
return fp, pos, vu
[docs] def set_camera(self, focal_point, position, view_up):
"""
Sets the camera position
Args:
focal_point (tuple) : Focal point
position (tuple) : Camera position
view_up (tuple) : View up vector
"""
cam1 = self.ren.GetActiveCamera()
cam1.SetFocalPoint(focal_point)
cam1.SetPosition(position)
cam1.SetViewUp(view_up)
self.ren.ResetCameraClippingRange()
self.ren_win.Render()
[docs]class FmriContours(object):
"""
Display contours calculated over an fMRI statistic map.
"""
def __init__(self, ren):
"""
Initialize the contours manager
Args:
ren (vtkRenderer) : Renderer that will draw the contours
"""
self.__contour_filter = vtk.vtkContourFilter()
self.__contour_filter.UseScalarTreeOn()
self.__contour_filter.ComputeNormalsOff()
self.__mapper = vtk.vtkPolyDataMapper()
self.__mapper.SetInputConnection(self.__contour_filter.GetOutputPort())
self.__actor = vtk.vtkActor()
self.__actor.SetMapper(self.__mapper)
ren.AddActor(self.__actor)
self.__value = None
self.__contour_filter.SetValue(0, 5)
self.__contour_filter.SetValue(1, -5)
self.__img = None
self.__lut = None
[docs] def set_value(self, value):
"""
Sets the value at which contours are generated
Args:
value (float) : Statistical value for creating contours
"""
self.__value = value
self.__contour_filter.SetValue(0, value)
self.__contour_filter.SetValue(1, -1 * value)
[docs] def set_image(self, img):
"""
Sets the statistical map
Args:
img (vtkImageData) : Data used for contours generation
"""
self.__img = img
self.__contour_filter.SetInputData(img)
self.__contour_filter.Update()
[docs] def set_lut(self, lut):
"""
Sets a lookup table for showing the contours
Notice the contour will always have the same vale, and therefore the same color.
However the lut will reflect the changes in the contour value.
Args:
lut (vtkScalarsToColors) : Table to generate contour color based on its value
"""
self.__mapper.SetLookupTable(lut)
self.__mapper.UseLookupTableScalarRangeOn()
@property
def actor(self):
"""
Get the contours actor
"""
return self.__actor
if __name__ == "__main__":
import sys
import PyQt4.QtGui as QtGui
import braviz
reader = braviz.readAndFilter.BravizAutoReader()
app = QtGui.QApplication(sys.argv)
main_window = QSubjectViewerWidget(reader, None)
main_window.show()
main_window.initialize_widget()
app.exec_()
log = logging.getLogger(__name__)
log.info("es todo")