def createHounsfieldEditorWidget(self): if self.hounsfieldEditor: self.hounsfieldEditor.setParent(None) self.hounsfieldEditor.close() self.hounsfieldEditor.destroy() self.hounsfieldEditor = HounsfieldEditor(self, self.scene.actualHounsfieldScale["name"], self.scene.vtkImageData) self.hounsfieldEditor.show()
class VolumeView( View ): def __init__(self, mscreenParent, cubeCorners=None, parent=None, title = "Volume", planeNumber = 1): logging.debug("In ViewPlane::__init__()") self._planeOrientation = -1 self._cubeCorners = cubeCorners self.defaultHounsfeildIndex = 0 self.maxRange = None self.minRange = None self._action = False self.mouseSensibility = 2000.0 self.sliderScale = 30.0 self._mouseMoveEvent = None self.hounsfieldEditor = None self._referencedPlanes = [] super(VolumeView, self).__init__( title, mscreenParent, planeNumber) def activateAllPlanes(self): for plane in filter( lambda pl: not isinstance( pl, VolumeView ), self._mscreenParent._planes): if not plane in self._referencedPlanes: #plane.scene.addSliceChangeListener( self.onReferedPlanesChange ) plane.addSliderReleasedListeners( self.onReferedPlanesChange ) plane.addCloseListener( self.onReferedPlaneClose ) self.addReferencedPlane(plane) self.scene.addSlicePlaneWidget( plane.planeWidget() ) else: #plane.scene.removeSliceChangeListener( self.onReferedPlanesChange ) plane.removeSliderReleasedListeners( self.onReferedPlanesChange ) plane.addCloseListener( self.onReferedPlaneClose ) self.removeReferencedPlane(plane) self.scene.removeSlicePlaneWidget( plane.planeWidget() ) def desactivateAllPlanes(self): logging.debug("In SingleSlicePlane::desactivateAllPlanes()") for plane in filter( lambda pl: not isinstance( pl, VolumeView ), self._mscreenParent._planes): if plane in self._referencedPlanes: plane.scene.removeSliceChangeListener( self.onReferedPlanesChange ) plane.removeCloseListener( self.onReferedPlaneClose ) if plane in self._referencedPlanes: self._referencedPlanes.remove( plane ) self.scene.removeSlicePlaneWidget( plane.planeWidget() ) def closeEvent(self, event ): logging.debug("In SliceView::closeEvent()") self.closeAction( event ) def changeVisibility(self): self.setVisible(not self.isVisible()) if self.isVisible(): self.resizeAction() def createWidgets(self): logging.debug("In ViewPlane::createWidgets()") super( VolumeView, self ).createWidgets() self.actionDefaultBehavior = QtGui.QAction(self) icon3 = QtGui.QIcon() icon3.addPixmap(QtGui.QPixmap(":/static/default/icon/22x22/edit-select.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionDefaultBehavior.setIcon(icon3) self.actionDefaultBehavior.setCheckable(True) self.actionDefaultBehavior.setChecked(True) self.actionDefaultBehavior.setObjectName("actionDefaultBehavior") self.toolbar.addAction(self.actionDefaultBehavior) self.actionContrastAndBrightness = QtGui.QAction(self) icon2 = QtGui.QIcon() icon2.addPixmap(QtGui.QPixmap(":/static/default/icon/48x48/color-brightness-contrast.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionContrastAndBrightness.setIcon(icon2) self.actionContrastAndBrightness.setObjectName("actionContrastAndBrightness") self.actionContrastAndBrightness.setCheckable(True) self.toolbar.addAction(self.actionContrastAndBrightness) self.setWindowTitle(self.title) self.action3DPresets = QtGui.QAction(self) icon = QtGui.QIcon() icon.addPixmap(QtGui.QPixmap(":/static/default/icon/48x48/filter.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.action3DPresets.setIcon(icon) self.action3DPresets.setObjectName("action3D") self.toolbar.addAction(self.action3DPresets) self.actionSurfacePresets = QtGui.QAction(self) icon1 = QtGui.QIcon() icon1.addPixmap(QtGui.QPixmap(":/static/default/icon/48x48/superficie.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionSurfacePresets.setIcon(icon1) self.actionSurfacePresets.setObjectName("actionSurfacePresets") self.toolbar.addAction(self.actionSurfacePresets) self.createSurfaceWidget() self.actionImagePlaneWidget = QtGui.QAction( self ) icon1 = QtGui.QIcon() icon1.addPixmap( QtGui.QPixmap( ':/static/default/icon/22x22/office-chart-polar.png' ), QtGui.QIcon.Normal, QtGui.QIcon.Off ) self.actionImagePlaneWidget.setIcon( icon1 ) self.actionImagePlaneWidget.setObjectName( 'actionSlicePlaneWidgetPresets' ) self.toolbar.addAction( self.actionImagePlaneWidget ) def splitterMoved(self, a, b): self.resizeAction() def resizeAction(self): size = self.plane.size() self.scene.interactor.setGeometry(0, 0, size.width(), size.height()) self.updateGeometry() def close(self): if self._mouseMoveEvent != None: self.scene.removeObserver(self._leftButtonPressEvent, False) self.scene.removeObserver(self._leftButtonReleaseEvent, False) self.scene.removeObserver(self._mouseMoveEvent, False) if self.hounsfieldEditor: self.hounsfieldEditor.close() self.hounsfieldEditor.destroy() self._mscreenParent = None self.scene.close() self.scene = None del self.scene self.destroy() self.closeEvent = None def closeAction(self, event = None, force=False): logging.debug("In ViewPlane::closeEvent()") if self.scene.referenceCount < 1 or force: if not self.mscreenParent.removeScene(self): event.ignore() else: event.ignore() def createScene(self): super( VolumeView, self ).createScene() logging.debug("In ViewPlane::createScene()") self.scene = VtkImageVolume(QVtkWidget(self.plane), self) self.scene.cubeCorners = self._cubeCorners self.loadHounsFieldScales() self.loadSurfaces() def createActor(self, vtkImageData ): logging.debug("In ViewPlane::createActor()") self.scene.createActor(vtkImageData) def createActions(self): logging.debug("In ViewPlane::createActions()") self.closeEvent = self.closeAction self.connect( self.action3DPresets, QtCore.SIGNAL("triggered()"), self.slotAction3DPresets ) self.connect( self.actionSurfacePresets, QtCore.SIGNAL("triggered()"), self.slotActionSurfacePresets ) self.connect( self.actionContrastAndBrightness, QtCore.SIGNAL("triggered()"), self.slotActionContrastAndBrightness ) self.connect( self.actionDefaultBehavior, QtCore.SIGNAL("triggered()"), self.slotActionDefaultBehavior ) self.connect( self.actionImagePlaneWidget, QtCore.SIGNAL( 'triggered()' ), self.slotActionImagePlaneWidget ) def slotActionImagePlaneWidget( self ): logging.debug("In VolumePlane::slotActionImagePlaneWidget()") self.menu = QtGui.QMenu() for plane in filter( lambda pl: not isinstance( pl, VolumeView ), self._mscreenParent._planes ): action = QtGui.QWidgetAction( self ) action.setCheckable( True ) action.setText(plane.title) action.setData( plane ) action.setChecked( plane in self._referencedPlanes ) self.menu.addAction( action ) self.connect( self.menu, QtCore.SIGNAL('triggered(QAction*)'), self.slotActionImagePlaneChoose ) pos = QtGui.QCursor.pos() self.menu.exec_( pos ) def addReferencedPlane( self, plane ): if plane not in self._referencedPlanes: self._referencedPlanes.append( plane ) def removeReferencedPlane( self, plane ): if plane in self._referencedPlanes: self._referencedPlanes.remove( plane ) def slotActionImagePlaneChoose( self, action ): logging.debug( 'In VolumePlane::slot3DPresetChanged()' ) plane = action.data() if action.isChecked(): #plane.scene.addSliceChangeListener( self.onReferedPlanesChange ) plane.addSliderReleasedListeners( self.onReferedPlanesChange ) plane.addCloseListener( self.onReferedPlaneClose ) self.addReferencedPlane(plane) self.scene.addSlicePlaneWidget( plane.planeWidget() ) else: #plane.scene.removeSliceChangeListener( self.onReferedPlanesChange ) plane.removeSliderReleasedListeners( self.onReferedPlanesChange ) plane.addCloseListener( self.onReferedPlaneClose ) self.removeReferencedPlane(plane) self.scene.removeSlicePlaneWidget( plane.planeWidget() ) def onReferedPlaneClose( self, plane ): plane.scene.removeSliceChangeListener( self.onReferedPlanesChange ) plane.removeCloseListener( self.onReferedPlaneClose ) if plane in self._referencedPlanes: self._referencedPlanes.remove( plane ) self.scene.removeSlicePlaneWidget( plane.planeWidget() ) def onReferedPlanesChange( self, plane=None ): self.scene.window.Render() def slotAction3DPresets(self): logging.debug("In VolumePlane::slotAction3DPresets()") self.actionContrastAndBrightness.setChecked(False) self.slotActionContrastAndBrightness() presets = self.get3DPresets() self.menu = QtGui.QMenu() for preset in presets: action = QtGui.QAction(self) action.setText(preset["name"]) action.setCheckable(True) self.menu.addAction(action) if preset["id"] == self.defaultHounsfeildIndex: action.setChecked(True) self.menu.addSeparator() action = QtGui.QAction(self) action.setText("Add/Remove/Edit") self.menu.addAction(action) self.connect(self.menu, QtCore.SIGNAL("triggered ( QAction*)"), self.slot3DPresetChanged) pos = QtGui.QCursor.pos() self.menu.exec_(pos) def slot3DPresetChanged(self, action): logging.debug("In VolumePlane::slot3DPresetChanged()") presets = self.get3DPresets() exist = False for preset in presets: if preset["name"] == action.text(): self.defaultHounsfeildIndex = preset["id"] exist = True self.slotModeChanged(action.text()) break if not exist: self.createHounsfieldEditorWidget() def slotActionSurfacePresets(self): logging.debug("In VolumePlane::slotActionSurfacePresets()") self.actionContrastAndBrightness.setChecked(False) self.slotActionContrastAndBrightness() presets = self.getSurfacePresets() self.menu = QtGui.QMenu() for preset in presets: action = QtGui.QAction(self) action.setText(preset["name"]) action.setCheckable(True) self.menu.addAction(action) if preset.has_key("check") and preset["check"]: action.setChecked(True) self.menu.addSeparator() action = QtGui.QAction(self) action.setText("New Surface") self.menu.addAction(action) self.connect(self.menu, QtCore.SIGNAL("triggered ( QAction*)"), self.slotSurfacePresetChanged) pos = QtGui.QCursor.pos() self.menu.exec_(pos) def slotSurfacePresetChanged(self, action): logging.debug("In VolumePlane::slot3DPresetChanged()") presets = self.getSurfacePresets() exist = False for preset in presets: if preset["name"] == action.text(): exist = True if preset.has_key("check") and preset["check"]: preset["check"] = False self.scene.removeSurface(preset["name"]) else: preset["check"] = True self.scene.addSurface(preset["name"], preset["value"], preset["r"], preset["g"], preset["b"]) break if not exist: self.newSurface() def newSurface(self): pos = QtGui.QCursor.pos() pos.setX(pos.x()) pos.setY(pos.y()) self.surfacesWidget.move(pos) self.surfacesWidget.show() def createWindowLevel(self): scalarRange = self.scene.vtkImageData.GetScalarRange() self.minRange = scalarRange[0] self.maxRange = scalarRange[1] self._leftButtonPressEvent = None self._leftButtonReleaseEvent = None self._mouseMoveEvent = None self.createWindowLevelWidget() def createHounsfieldEditorWidget(self): if self.hounsfieldEditor: self.hounsfieldEditor.setParent(None) self.hounsfieldEditor.close() self.hounsfieldEditor.destroy() self.hounsfieldEditor = HounsfieldEditor(self, self.scene.actualHounsfieldScale["name"], self.scene.vtkImageData) self.hounsfieldEditor.show() def getActualWindow(self): return self.scene.opacityWindow def getActualLevel(self): return self.scene.opacityLevel def createWindowLevelWidget(self): self.contrastLabel = QtGui.QLabel("Contrast") self.brightnessLabel = QtGui.QLabel("Brightness") self.brightnessSlider = QtGui.QSlider() self.brightnessSlider.setOrientation(QtCore.Qt.Horizontal) self.brightnessSlider.setObjectName("brightnessSlider") self.contrastSlider = QtGui.QSlider() self.contrastSlider.setOrientation(QtCore.Qt.Horizontal) self.contrastSlider.setObjectName("contrastSlider") levelRange = self.maxRange - self.minRange self.brightnessSlider.setRange(0,levelRange*self.sliderScale) self.contrastSlider.setRange(self.sliderScale, levelRange*self.sliderScale) self.contrastBrightnessPopUp = QtGui.QFrame(self.toolbar, QtCore.Qt.FramelessWindowHint | QtCore.Qt.Tool | QtCore.Qt.Window) vLayout = QtGui.QHBoxLayout(self.contrastBrightnessPopUp) windowLayout = QtGui.QHBoxLayout() vLayout.addLayout(windowLayout) windowLayout.addWidget(self.contrastLabel) windowLayout.addWidget(self.contrastSlider) levelLayout = QtGui.QHBoxLayout() vLayout.addLayout(levelLayout) levelLayout.addWidget(self.brightnessLabel) levelLayout.addWidget(self.brightnessSlider) levelValue = self.maxRange - self.scene.opacityLevel self.contrastSlider.setValue(self.scene.opacityWindow * self.sliderScale) self.brightnessSlider.setValue(levelValue * self.sliderScale) self.createWindowLevelActions() def createSurfaceWidget(self): self.surfacesWidget = SurfaceEditor(self, self.newSurfaceCallback) def newSurfaceCallback(self, surface): presets = self.getSurfacePresets() for preset in presets: if preset["name"] == surface["name"]: return False self.surfaces.append(surface) surface["check"] = True self.scene.addSurface(surface["name"], surface["value"], surface["r"], surface["g"], surface["b"]) return True def slotActionDefaultBehavior(self): logging.debug("In VolumePlane::slotActionDefaultBehavior()") self.actionContrastAndBrightness.setChecked(False) self.slotActionContrastAndBrightness() def get3DPresets(self): result = [] i = 0 for scale in self.hounsfieldScales: result.append({"id" : i, "name" : scale["name"]}) i = i +1 return result; def getSurfacePresets(self): return self.surfaces def changeHounsfieldMode(self, mode): presets = self.get3DPresets() for preset in presets: if preset["name"] == mode: self.defaultHounsfeildIndex = preset["id"] break # self.slotModeChanged() def slotModeChanged(self, mode): logging.debug("In ViewPlane::slotModeChanged()") self.scene.changeHounsfieldMode(mode) self.resetWindowLevel(); def resetWindowLevel(self): self.actionContrastAndBrightness.setChecked(False) if self.maxRange != None: self.slotActionContrastAndBrightness() self.contrastSlider.setValue(self.scene.defaultWindow *self.sliderScale) self.brightnessSlider.setValue((self.maxRange - self.scene.defaultLevel) * self.sliderScale) def createWindowLevelActions(self): self.connect( self.contrastSlider, QtCore.SIGNAL("sliderReleased()"), self.slotActionChageValues ) self.connect( self.brightnessSlider, QtCore.SIGNAL("sliderReleased()"), self.slotActionChageValues ) def slotActionChageValues(self): contrast = self.contrastSlider.value() / self.sliderScale brightness = self.brightnessSlider.value() / self.sliderScale if abs(contrast - self.scene.opacityWindow) > 0.001 or abs(brightness - self.scene.opacityLevel) > 0.001 : level = self.maxRange - brightness self.scene.setWindowLevel(contrast, level) def slotActionContrastAndBrightness(self): logging.debug("In VolumePlane::slotActionContrastAndBrightness()") if not self.maxRange: self.createWindowLevel() if not self.actionContrastAndBrightness.isChecked(): if self._mouseMoveEvent != None: self.actionDefaultBehavior.setChecked(True) self.scene.removeObserver(self._leftButtonPressEvent, False) self.scene.removeObserver(self._leftButtonReleaseEvent, False) self.scene.removeObserver(self._mouseMoveEvent, False) self.contrastBrightnessPopUp.hide() else: self.actionDefaultBehavior.setChecked(False) self._leftButtonPressEvent = self.scene.addObserver("LeftButtonPressEvent", self.ButtonCallback) self._leftButtonReleaseEvent = self.scene.addObserver("LeftButtonReleaseEvent", self.ButtonCallback) self._mouseMoveEvent = self.scene.addObserver("MouseMoveEvent", lambda o, e, s=self.scene: self.MouseMoveCallback(o, e, s)) pos = QtGui.QCursor.pos() pos.setX(pos.x() + 22) pos.setY(pos.y()) self.contrastBrightnessPopUp.move(pos) self.contrastBrightnessPopUp.show() def ButtonCallback(self, obj, event): logging.debug("In TranslateAction::ButtonCallback()") if event == "LeftButtonPressEvent": self._action = True else: self._action = False def MouseMoveCallback(self, obj, event, vtkScene): logging.debug("In TranslateAction::MouseMoveCallback()") (lastX, lastY) = vtkScene.interactor.GetLastEventPosition() (mouseX, mouseY) = vtkScene.interactor.GetEventPosition() if self._action: cWindow = mouseX - lastX cLevel = mouseY - lastY dx = ((self.maxRange - self.minRange) / self.mouseSensibility) * cWindow dy = ((self.maxRange - self.minRange) / self.mouseSensibility) * cLevel levelRange = self.maxRange - self.minRange newWindow = min(max(dx + self.scene.opacityWindow, 1), levelRange) newLevel = min(max(self.scene.opacityLevel - dy, self.minRange), self.maxRange) self.contrastSlider.setValue(newWindow * self.sliderScale) self.brightnessSlider.setValue((self.maxRange - newLevel) * self.sliderScale) self.slotActionChageValues() def setHounsfieldScalePreview(self, scale): self.scene.setHounsfieldFromMap(scale) def setWindowLevel(self, window, level): self.contrastSlider.setValue(window * self.sliderScale) self.brightnessSlider.setValue((self.maxRange - level) * self.sliderScale) self.slotActionChageValues() def loadHounsFieldScales(self): self.hounsfieldScales = load_yaml_file(HOUNSFIELD_FILE_PATH) self.hounsfieldScales.append({"name" : "None"}) self.scene.loadHounsfieldScales(self.hounsfieldScales) def loadSurfaces(self): self.surfaces = [{"id": 0, "name" : "Bone", "value" : 600, "r" : 1.0, "g" : 1.0, "b" :0.6}, {"id": 1, "name" : "Skin", "value" : -500, "r" : 1.0, "g" : 0.55, "b" :0.654}, {"id": 1, "name" : "Metal", "value" : 2000, "r" : 0.686, "g" : 0.686, "b" :0.686}] def updateWidgets(self): logging.debug("In ViewPlane::updateWidgets()") self.planeSlide.setVisible(False) self.setWindowTitle(self.title) def reset(self): logging.debug("In ViewPlane::reset()") self.splitter.setSizes([1,0]) self.resizeAction() self.scene.reset() @property def mscreenParent(self): logging.debug("In ViewPlane::mscreenParent.getter()") return self._mscreenParent @mscreenParent.setter def mscreenParent(self, mscreenParent): logging.debug("In ViewPlane::mscreenParent.setter()") self._mscreenParent = mscreenParent def load(self, data): logging.debug("In ViewPlane::id.load()") if data.has_key("id"): self.setSceneId(data["id"]) if data.has_key("hounsfieldMode"): mode = data["hounsfieldMode"] self.slotModeChanged(mode) presets = self.get3DPresets() for preset in presets: if preset["name"] == mode: self.defaultHounsfeildIndex = preset["id"] break if data.has_key("window"): window = data["window"] level = data["level"] self.scene.setWindowLevel(window, level) self.resetWindowLevel() if data.has_key("sliceWidgets") and ( data.has_key("id") and data["id"] == self.scene._id ): lst = [ plane for plane in self._mscreenParent._planes if plane.scene._id in data["sliceWidgets"] ] for plane in lst: plane.addSliderReleasedListeners( self.onReferedPlanesChange ) plane.addCloseListener( self.onReferedPlaneClose ) self.addReferencedPlane(plane) self.scene.addSlicePlaneWidget( plane.planeWidget() ) @property def id(self): logging.debug("In ViewPlane::id.getter()") return self._id def setSceneId(self, id): self.scene.id = id @property def planeOrientation(self): logging.debug("In ViewPlane::planeOrientation.getter()") return self._planeOrientation @property def mainImageData(self): return self._mscreenParent.mainImageData def getScreen(self): return self._mscreenParent