def setRenderSettings(self, renderSettings): if renderSettings is not None: self.slices = renderSettings["slices"] self.multiRenderWidget.setSlices(self.slices) cameraWrapper = renderSettings["camera"] cameraWrapper.applyToObject(self.multiRenderWidget.renderer.GetActiveCamera()) transformationsWrapped = renderSettings["transformations"] if transformationsWrapped is not None: transformations = TransformationList() transformations.setPythonVersion(transformationsWrapped) self.multiRenderWidget.transformations = transformations self.clippingBox = renderSettings["clippingBox"] self.clippingPlanes = renderSettings["clippingPlanes"] self.updateVisualization() self.slicesChanged.emit(self.slices) self.clippingBoxChanged.emit(self.clippingBox) else: self.slices = [False, False, False] self.clippingBox = False self.clippingPlanes = True
def setRenderSettings(self, renderSettings): if renderSettings is not None: self.slices = renderSettings["slices"] self.multiRenderWidget.setSlices(self.slices) cameraWrapper = renderSettings["camera"] cameraWrapper.applyToObject( self.multiRenderWidget.renderer.GetActiveCamera()) transformationsWrapped = renderSettings["transformations"] if transformationsWrapped is not None: transformations = TransformationList() transformations.setPythonVersion(transformationsWrapped) self.multiRenderWidget.transformations = transformations self.clippingBox = renderSettings["clippingBox"] self.clippingPlanes = renderSettings["clippingPlanes"] self.updateVisualization() self.slicesChanged.emit(self.slices) self.clippingBoxChanged.emit(self.clippingBox) else: self.slices = [False, False, False] self.clippingBox = False self.clippingPlanes = True
def __init__(self): super(MultiRenderWidget, self).__init__() # Default volume renderer self.renderer = vtkRenderer() self.renderer.SetBackground2(0.4, 0.4, 0.4) self.renderer.SetBackground(0.1, 0.1, 0.1) self.renderer.SetGradientBackground(True) self.renderer.SetInteractive(1) self.renderer.SetLayer(0) # Overlay renderer which is synced with the default renderer self.rendererOverlay = vtkRenderer() self.rendererOverlay.SetLayer(1) self.rendererOverlay.SetInteractive(0) self.renderer.GetActiveCamera().AddObserver("ModifiedEvent", self._syncCameras) self.rwi = QVTKRenderWindowInteractor(parent=self) self.rwi.SetInteractorStyle(vtkInteractorStyleTrackballCamera()) self.rwi.GetRenderWindow().AddRenderer(self.renderer) self.rwi.GetRenderWindow().AddRenderer(self.rendererOverlay) self.rwi.GetRenderWindow().SetNumberOfLayers(2) self.rwi.SetDesiredUpdateRate(0) self._imagePlaneWidgets = [vtkImagePlaneWidget() for i in range(3)] for index in range(3): self._imagePlaneWidgets[index].DisplayTextOn() self._imagePlaneWidgets[index].SetInteractor(self.rwi) self.mapper = vtkOpenGLGPUMultiVolumeRayCastMapper() self.mapper.SetBlendModeToComposite() self.volume = vtkVolume() self.volume.SetMapper(self.mapper) self.renderer.AddViewProp(self.volume) self.fixedGridItems = [] self.movingGridItems = [] self.orientationGridItems = [] # Create two empty datasets self.fixedImageData = CreateEmptyImageData() self.movingImageData = CreateEmptyImageData() self.fixedVolumeProperty = vtkVolumeProperty() self.movingVolumeProperty = vtkVolumeProperty() color, opacityFunction = CreateEmptyFunctions() self.fixedVolumeProperty.SetColor(color) self.fixedVolumeProperty.SetScalarOpacity(opacityFunction) self.movingVolumeProperty.SetColor(color) self.movingVolumeProperty.SetScalarOpacity(opacityFunction) self.visualization = None # MultiVolumeVisualization self.clippingBox = ClippingBox() self.clippingBox.setWidget(self) self.mapper.SetInputData(0, self.fixedImageData) self.mapper.SetInputData(1, self.movingImageData) self._transformations = TransformationList() self._transformations.transformationChanged.connect(self.updateTransformation) self._shouldResetCamera = False self.setMinimumWidth(340) self.setMinimumHeight(340) layout = QGridLayout(self) layout.setSpacing(0) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.rwi, 0, 0) self.setLayout(layout)
class MultiRenderWidget(QWidget): """ MultiRenderWidget is a widget that can display two datasets: fixed and moving dataset. It uses the given volume property to derive how the volumes should be displayed. This widget also has its own controls that define how the volumes from the other widgets will be mixed into one visualization. The hard thing is to find out how to share volumes / volume properties / resources between widgets while still being linked together. So for instance when a volume is clipped in one of the single views it should be immediately visible in this widget. And the problem with the volume properties is that the volume property for this widget should be linked to the other widgets so that when they update their volume properties, this volume property will also be updated. But it can't be the same... There can be a few visualization modes: * 'simple' mix mode * colorized mix mode Simple mix mode is a mode that displays both datasets in the same way as they are visualized in the other views. Two controls are given to provide a way of setting the opacity of both volumes so that the user can mix the datasets to a nice visualization. Colorized mix mode makes grayscale visualizations of the """ dataChanged = Signal() updated = Signal() def __init__(self): super(MultiRenderWidget, self).__init__() # Default volume renderer self.renderer = vtkRenderer() self.renderer.SetBackground2(0.4, 0.4, 0.4) self.renderer.SetBackground(0.1, 0.1, 0.1) self.renderer.SetGradientBackground(True) self.renderer.SetInteractive(1) self.renderer.SetLayer(0) # Overlay renderer which is synced with the default renderer self.rendererOverlay = vtkRenderer() self.rendererOverlay.SetLayer(1) self.rendererOverlay.SetInteractive(0) self.renderer.GetActiveCamera().AddObserver("ModifiedEvent", self._syncCameras) self.rwi = QVTKRenderWindowInteractor(parent=self) self.rwi.SetInteractorStyle(vtkInteractorStyleTrackballCamera()) self.rwi.GetRenderWindow().AddRenderer(self.renderer) self.rwi.GetRenderWindow().AddRenderer(self.rendererOverlay) self.rwi.GetRenderWindow().SetNumberOfLayers(2) self.rwi.SetDesiredUpdateRate(0) self._imagePlaneWidgets = [vtkImagePlaneWidget() for i in range(3)] for index in range(3): self._imagePlaneWidgets[index].DisplayTextOn() self._imagePlaneWidgets[index].SetInteractor(self.rwi) self.mapper = vtkOpenGLGPUMultiVolumeRayCastMapper() self.mapper.SetBlendModeToComposite() self.volume = vtkVolume() self.volume.SetMapper(self.mapper) self.renderer.AddViewProp(self.volume) self.fixedGridItems = [] self.movingGridItems = [] self.orientationGridItems = [] # Create two empty datasets self.fixedImageData = CreateEmptyImageData() self.movingImageData = CreateEmptyImageData() self.fixedVolumeProperty = vtkVolumeProperty() self.movingVolumeProperty = vtkVolumeProperty() color, opacityFunction = CreateEmptyFunctions() self.fixedVolumeProperty.SetColor(color) self.fixedVolumeProperty.SetScalarOpacity(opacityFunction) self.movingVolumeProperty.SetColor(color) self.movingVolumeProperty.SetScalarOpacity(opacityFunction) self.visualization = None # MultiVolumeVisualization self.clippingBox = ClippingBox() self.clippingBox.setWidget(self) self.mapper.SetInputData(0, self.fixedImageData) self.mapper.SetInputData(1, self.movingImageData) self._transformations = TransformationList() self._transformations.transformationChanged.connect(self.updateTransformation) self._shouldResetCamera = False self.setMinimumWidth(340) self.setMinimumHeight(340) layout = QGridLayout(self) layout.setSpacing(0) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.rwi, 0, 0) self.setLayout(layout) def render(self): if self._shouldResetCamera: self.renderer.ResetCamera() self._shouldResetCamera = False self.rwi.Render() # Prevent warning messages on OSX by not asking to render # when the render window has never rendered before if not self.rwi.GetRenderWindow().GetNeverRendered(): self.rwi.GetRenderWindow().Render() @Slot(object) def setFixedData(self, imageData): self._cleanUpGrids() self.fixedImageData = imageData if self.fixedImageData is None: self.fixedImageData = CreateEmptyImageData() if self.movingImageData is None: self.movingImageData = CreateEmptyImageData() self.mapper.SetInputData(0, self.fixedImageData) self.mapper.SetInputData(1, self.movingImageData) for index in range(3): self._imagePlaneWidgets[index].SetInputData(self.fixedImageData) self._imagePlaneWidgets[index].SetPlaneOrientation(index) self._updateGrids() self._createClippingBox() self._shouldResetCamera = True @Slot(object) def setMovingData(self, imageData): self._cleanUpGrids() self.movingImageData = imageData if self.movingImageData is None: self.movingImageData = CreateEmptyImageData() if self.fixedImageData is None: self.fixedImageData = CreateEmptyImageData() self.mapper.SetInputData(0, self.fixedImageData) self.mapper.SetInputData(1, self.movingImageData) self._updateGrids() self._shouldResetCamera = True def setVolumeVisualization(self, visualization): self.visualization = visualization if self.visualization is None: color, opacityFunction = CreateEmptyFunctions() self.fixedVolumeProperty = vtkVolumeProperty() self.fixedVolumeProperty.SetColor(color) self.fixedVolumeProperty.SetScalarOpacity(opacityFunction) self.movingVolumeProperty = vtkVolumeProperty() self.movingVolumeProperty.SetColor(color) self.movingVolumeProperty.SetScalarOpacity(opacityFunction) else: self.fixedVolumeProperty = self.visualization.fixedVolProp self.movingVolumeProperty = self.visualization.movingVolProp self.visualization.setMapper(self.mapper) if self.visualization.fixedVisualization: self._updateMapper(self.visualization.fixedVisualization, 1) if self.visualization.movingVisualization: self._updateMapper(self.visualization.movingVisualization, 2) self._updateVolumeProperties() def _updateGrids(self): if not self._hasImageData(): return if self._hasMovingImageData(): self.movingGridItems = CreateBounds(self.movingImageData.GetBounds()) boundsFixed = self.fixedImageData.GetBounds() boundsMoving = self.movingImageData.GetBounds() maxBounds = map(lambda x, y: max(x, y), boundsFixed, boundsMoving) self.orientationGridItems = CreateOrientationGrid(maxBounds, self.renderer.GetActiveCamera()) for item in (self.movingGridItems + self.fixedGridItems + self.orientationGridItems): self.renderer.AddViewProp(item) def _cleanUpGrids(self): for item in (self.fixedGridItems + self.movingGridItems + self.orientationGridItems): self.renderer.RemoveViewProp(item) self.fixedGridItems = [] self.movingGridItems = [] self.orientationGridItems = [] def _createClippingBox(self): if not self._hasImageData(): self.clippingBox.showClippingBox(False) else: if self._hasFixedImageData(): self.clippingBox.setImageData(self.fixedImageData) elif self._hasMovingImageData(): self.clippingBox.setImageData(self.movingImageData) else: self.clippingBox.enable(False) def _hasImageData(self): return self._hasFixedImageData() or self._hasMovingImageData() def _hasFixedImageData(self): return self._isActualImageData(self.fixedImageData) def _hasMovingImageData(self): return self._isActualImageData(self.movingImageData) def _isActualImageData(self, imageData): dimensions = imageData.GetDimensions() return dimensions != (3, 3, 3) # Properties @property def transformations(self): return self._transformations @transformations.setter def transformations(self, value): self._transformations.copyFromTransformations(value) # Slots @Slot(object) def setSlices(self, slices): for sliceIndex in range(len(slices)): if slices[sliceIndex]: self._imagePlaneWidgets[sliceIndex].On() else: self._imagePlaneWidgets[sliceIndex].Off() def showClippingBox(self, show): self.clippingBox.showClippingBox(show) self.render() def showClippingPlanes(self, show): self.clippingBox.showClippingPlanes(show) self.render() def resetClippingBox(self): self.clippingBox.resetClippingBox() self.render() @Slot() def updateTransformation(self): transform = self._transformations.completeTransform() self.mapper.SetSecondInputUserTransform(transform) for item in self.movingGridItems: item.SetUserTransform(transform) self.render() # Private methods def _updateMapper(self, volVis, volNr): shaderType = volVis.shaderType() if volNr == 1: self.mapper.SetShaderType1(shaderType) if shaderType == 2: # MIDA lowerBound = (volVis.lowerBound - volVis.minimum) / (volVis.maximum - volVis.minimum) upperBound = (volVis.upperBound - volVis.minimum) / (volVis.maximum - volVis.minimum) self.mapper.SetLowerBound1(lowerBound) self.mapper.SetUpperBound1(upperBound) self.mapper.SetBrightness1(volVis.brightness / 100.0) if shaderType == 1: # MIP lowerBound = (volVis.lowerBound - volVis.minimum) / (volVis.maximum - volVis.minimum) upperBound = (volVis.upperBound - volVis.minimum) / (volVis.maximum - volVis.minimum) self.mapper.SetLowerBound1(lowerBound) self.mapper.SetUpperBound1(upperBound) else: self.mapper.SetShaderType2(shaderType) if shaderType == 2: # MIDA lowerBound = (volVis.lowerBound - volVis.minimum) / (volVis.maximum - volVis.minimum) upperBound = (volVis.upperBound - volVis.minimum) / (volVis.maximum - volVis.minimum) self.mapper.SetLowerBound2(lowerBound) self.mapper.SetUpperBound2(upperBound) self.mapper.SetBrightness2(volVis.brightness / 100.0) if shaderType == 1: # MIP lowerBound = (volVis.lowerBound - volVis.minimum) / (volVis.maximum - volVis.minimum) upperBound = (volVis.upperBound - volVis.minimum) / (volVis.maximum - volVis.minimum) self.mapper.SetLowerBound2(lowerBound) self.mapper.SetUpperBound2(upperBound) def _updateVolumeProperties(self): """ Private method to update the volume properties. """ if self.volume.GetProperty() != self.fixedVolumeProperty: self.volume.SetProperty(self.fixedVolumeProperty) if self.mapper.GetProperty2() != self.movingVolumeProperty: self.mapper.SetProperty2(self.movingVolumeProperty) self.render() def _syncCameras(self, camera, ev): """ Camera modified event callback. Copies the parameters of the renderer camera into the camera of the overlay so they stay synced at all times. """ self.rendererOverlay.GetActiveCamera().ShallowCopy(camera)
def setUp(self): self.transformList = TransformationList()
class TransformationListTest(unittest.TestCase): def setUp(self): self.transformList = TransformationList() def tearDown(self): del self.transformList def testTransformationList(self): transform = vtkTransform() transformation = Transformation(transform, Transformation.TypeDeformable, "filename") self.transformList.append(transformation) self.assertEquals(len(self.transformList._transformations), 1) completeTransform = self.transformList.completeTransform() self.assertIsNotNone(completeTransform) matrix = completeTransform.GetMatrix() self.assertEquals(matrix.GetElement(0, 0), 1) self.assertEquals(matrix.GetElement(1, 1), 1) self.assertEquals(matrix.GetElement(2, 2), 1) self.assertEquals(matrix.GetElement(3, 3), 1) self.assertEquals(matrix.GetElement(1, 3), 0) transform = vtkTransform() transform.Scale(2.0, 2.0, 2.0) transformation = Transformation(transform, Transformation.TypeDeformable, "filename") self.transformList.append(transformation) self.assertEquals(len(self.transformList._transformations), 2) self.assertNotEquals(self.transformList[0], self.transformList[1]) completeTransform = self.transformList.completeTransform() matrix = completeTransform.GetMatrix() self.assertEquals(matrix.GetElement(0, 0), 2) self.assertEquals(matrix.GetElement(1, 1), 2) self.assertEquals(matrix.GetElement(2, 2), 2) self.assertEquals(matrix.GetElement(3, 3), 1) self.assertEquals(matrix.GetElement(1, 3), 0) transform = vtkTransform() transform.Translate(3.0, 3.0, 3.0) transformation = Transformation(transform, Transformation.TypeDeformable, "filename") self.transformList.append(transformation) self.assertEquals(len(self.transformList._transformations), 3) self.assertNotEquals(self.transformList[1], self.transformList[2]) completeTransform = self.transformList.completeTransform() matrix = completeTransform.GetMatrix() self.assertEquals(matrix.GetElement(0, 0), 2) self.assertEquals(matrix.GetElement(1, 1), 2) self.assertEquals(matrix.GetElement(2, 2), 2) self.assertEquals(matrix.GetElement(3, 3), 1) self.assertEquals(matrix.GetElement(0, 3), 3) self.assertEquals(matrix.GetElement(1, 3), 3) self.assertEquals(matrix.GetElement(2, 3), 3) transform = vtkTransform() transform.RotateX(90.0) transformation = Transformation(transform, Transformation.TypeDeformable, "filename") self.transformList.append(transformation) prevTransform = self.transformList.transform(2) prevMatrix = prevTransform.GetMatrix() self.assertEquals(prevMatrix.GetElement(0, 0), 2) self.assertEquals(prevMatrix.GetElement(1, 1), 2) self.assertEquals(prevMatrix.GetElement(2, 2), 2) self.assertEquals(prevMatrix.GetElement(3, 3), 1) self.assertEquals(prevMatrix.GetElement(0, 3), 3) self.assertEquals(prevMatrix.GetElement(1, 3), 3) self.assertEquals(prevMatrix.GetElement(2, 3), 3) transform = vtkTransform() transformation = Transformation(transform, Transformation.TypeDeformable, "Other name") self.transformList.append(transformation) trans = self.transformList.completeTransform() matrix = trans.GetMatrix() self.assertEquals(matrix.GetElement(0, 0), 1) self.assertEquals(matrix.GetElement(1, 1), 1) self.assertEquals(matrix.GetElement(2, 2), 1) self.assertEquals(matrix.GetElement(3, 3), 1) self.assertEquals(matrix.GetElement(1, 3), 0)