def _createMagnifiedPixmap(self, xyz, inputImageDataConnection, outputSize, crosshairColor, imageZoom=10): # Use existing instance of objects to avoid instanciating one at each event. imageCrop = self.imageCrop painter = self.painter pen = self.pen def _roundInt(value): try: return int(round(value)) except ValueError: return 0 imageCrop.SetInputConnection(inputImageDataConnection) xyzInt = [0, 0, 0] xyzInt = [_roundInt(value) for value in xyz] producer = inputImageDataConnection.GetProducer() dims = producer.GetOutput().GetDimensions() minDim = min(dims[0],dims[1]) imageSize = _roundInt(minDim/imageZoom/2.0) imin = max(0,xyzInt[0]-imageSize) imax = min(dims[0]-1, xyzInt[0]+imageSize) jmin = max(0,xyzInt[1]-imageSize) jmax = min(dims[1]-1, xyzInt[1]+imageSize) if (imin <= imax) and (jmin <= jmax): imageCrop.SetVOI(imin, imax, jmin, jmax, 0,0) imageCrop.Update() vtkImage = imageCrop.GetOutput() if vtkImage: qImage = qt.QImage() slicer.qMRMLUtils().vtkImageDataToQImage(vtkImage, qImage) imagePixmap = qt.QPixmap.fromImage(qImage) imagePixmap = imagePixmap.scaled(outputSize, qt.Qt.KeepAspectRatio, qt.Qt.FastTransformation) # draw crosshair painter.begin(imagePixmap) pen = qt.QPen() pen.setColor(crosshairColor) painter.setPen(pen) painter.drawLine(0, imagePixmap.height()/2, imagePixmap.width(), imagePixmap.height()/2) painter.drawLine(imagePixmap.width()/2,0, imagePixmap.width()/2, imagePixmap.height()) painter.end() return imagePixmap return None
def editMarkups(self, selectOption, fiducialsNode, curveNode, viewNode): layoutManager = slicer.app.layoutManager() threeDWidget = layoutManager.viewWidget(viewNode) threeDView = threeDWidget.threeDView() aspectRatio = threeDWidget.width / threeDWidget.height className = "vtkMRMLMarkupsDisplayableManager" markupsDisplayableManager = threeDView.displayableManagerByClassName( className) fiducialsWidget = markupsDisplayableManager.GetWidget( fiducialsNode.GetDisplayNode()) fiducialsRepresentation = fiducialsWidget.GetRepresentation() cameraNode = slicer.modules.cameras.logic().GetViewActiveCameraNode( viewNode) camera = cameraNode.GetCamera() raswToXYZW = vtk.vtkMatrix4x4() modelView = camera.GetModelViewTransformMatrix() projection = camera.GetProjectionTransformMatrix( aspectRatio, 1, 100) # near/far are arbitrary raswToXYZW.Multiply4x4(projection, modelView, raswToXYZW) def rasToColumnRow(ras): rasw = *ras, 1 xyzw = raswToXYZW.MultiplyPoint(rasw) x, y = [xyzw[0], xyzw[1]] if viewNode.GetRenderMode() == viewNode.Perspective: x, y = [x / xyzw[3], y / xyzw[3]] column = (x + 1) / 2 * threeDWidget.width row = (1 - (y + 1) / 2) * threeDWidget.height return column, row selectionPolygon = qt.QPolygonF() for index in range(curveNode.GetNumberOfControlPoints()): ras = [0] * 3 curveNode.GetNthControlPointPositionWorld(index, ras) column, row = rasToColumnRow(ras) point = qt.QPointF(column, row) selectionPolygon.push_back(point) pickImage = qt.QImage(threeDWidget.width, threeDWidget.height, qt.QImage().Format_ARGB32) backgroundColor = qt.QColor("#ffffffff") pickImage.fill(backgroundColor) painter = qt.QPainter() painter.begin(pickImage) painterPath = qt.QPainterPath() painterPath.addPolygon(selectionPolygon) brush = qt.QBrush(qt.Qt.SolidPattern) painter.setBrush(brush) painter.drawPath(painterPath) painter.end() debugging = False if debugging: pixmap = qt.QPixmap().fromImage(pickImage) slicer.modules.label = qt.QLabel() slicer.modules.label.setPixmap(pixmap) slicer.modules.label.show() visibleCount = 0 pickedCount = 0 for index in range(fiducialsNode.GetNumberOfControlPoints()): pointVisible = fiducialsRepresentation.GetNthControlPointViewVisibility( index) if pointVisible: visibleCount += 1 ras = [0] * 3 fiducialsNode.GetNthControlPointPositionWorld(index, ras) column, row = rasToColumnRow(ras) if (column >= 0 and column < pickImage.width and row >= 0 and row < pickImage.height): pickColor = pickImage.pixelColor(column, row) picked = (pickColor != backgroundColor) if picked: pickedCount += 1 if selectOption == "set": if pointVisible: fiducialsNode.SetNthControlPointSelected(index, picked) else: fiducialsNode.SetNthControlPointSelected(index, False) elif selectOption == "add": if picked and pointVisible: fiducialsNode.SetNthControlPointSelected(index, True) elif selectOption == "unset": if picked and pointVisible: fiducialsNode.SetNthControlPointSelected(index, False) else: logging.error(f"Unknown selectOption {selectOption}")
def generatePixmapForPrinting(self, filePath): if not self.getOutputFlattenedModelNode(): raise ValueError("Failed to access flattened baffle model") viewOwnerNode = self.getOutputFlattenedModelNode() if not self.printThreeDViewNode: self.printThreeDViewNode = slicer.mrmlScene.CreateNodeByClass( "vtkMRMLViewNode") self.printThreeDViewNode.UnRegister(None) self.printThreeDViewNode.SetSingletonTag("FlattenedBafflePrinter") self.printThreeDViewNode.SetName("FlattenedBafflePrinter") self.printThreeDViewNode.SetLayoutName("FlattenedBafflePrinter") self.printThreeDViewNode.SetLayoutLabel("FlattenedBafflePrinter") self.printThreeDViewNode.SetLayoutColor(1, 1, 0) self.printThreeDViewNode.SetAndObserveParentLayoutNodeID( viewOwnerNode.GetID()) self.printThreeDViewNode.SetRulerType( slicer.vtkMRMLAbstractViewNode.RulerTypeThin) self.printThreeDViewNode.SetRulerColor( slicer.vtkMRMLAbstractViewNode.RulerColorBlack) self.printThreeDViewNode = slicer.mrmlScene.AddNode( self.printThreeDViewNode) if not self.printThreeDWidget: self.printThreeDWidget = slicer.qMRMLThreeDWidget() self.printThreeDWidget.setObjectName( "self.printThreeDWidget" + self.printThreeDViewNode.GetLayoutLabel()) self.printThreeDWidget.viewLabel = self.printThreeDViewNode.GetLayoutLabel( ) self.printThreeDWidget.viewColor = qt.QColor.fromRgbF( *self.printThreeDViewNode.GetLayoutColor()) self.printThreeDWidget.setMRMLScene(slicer.mrmlScene) self.printThreeDWidget.setMRMLViewNode(self.printThreeDViewNode) self.printThreeDViewNode.SetAndObserveParentLayoutNodeID( viewOwnerNode.GetID()) self.printThreeDWidget.setMRMLViewNode(self.printThreeDViewNode) # Configure view and widget self.printThreeDViewNode.SetBoxVisible(0) self.printThreeDViewNode.SetAxisLabelsVisible(0) self.printThreeDViewNode.SetRenderMode( slicer.vtkMRMLViewNode.Orthographic) self.printThreeDViewNode.SetBackgroundColor((1, 1, 1)) self.printThreeDViewNode.SetBackgroundColor2((1, 1, 1)) # Set color and shading of flattened baffle and fixed points flattenedModelDisplayNode = self.getOutputFlattenedModelNode( ).GetDisplayNode() flattenedModelOriginalColor = flattenedModelDisplayNode.GetColor() flattenedModelDisplayNode.SetColor(0.0, 0.0, 0.0) flattenedFixedPointsNode = self.getOutputFlattenedFixedPointsNode() flattenedFixedPointsDisplayNode = flattenedFixedPointsNode.GetDisplayNode( ) flattenedFixedPointsOriginalColor = flattenedFixedPointsDisplayNode.GetColor( ) flattenedFixedPointsDisplayNode.SetColor(1.0, 0.5, 0.5) # Make sure nothing is visible in the print view other than the baffle and the fixed landmarks hiddenDisplayNodes = [] layoutThreeDViewNode = slicer.app.layoutManager().threeDWidget( 0).viewLogic().GetViewNode() allDisplayNodes = slicer.util.getNodesByClass('vtkMRMLDisplayNode') for displayNode in allDisplayNodes: if displayNode is not flattenedModelDisplayNode and displayNode is not flattenedFixedPointsDisplayNode: displayNode.AddViewNodeID(layoutThreeDViewNode.GetID()) hiddenDisplayNodes.append(displayNode) # Show 3D view self.printThreeDWidget.resize(self.printViewWidth, self.printViewHeight) self.printThreeDWidget.show() # Determine ROI for flattened baffle flattenedBaffePolyData = self.getOutputFlattenedModelNode( ).GetPolyData() bounds = [0] * 6 flattenedBaffePolyData.GetBounds(bounds) center = [(bounds[0] + bounds[1]) / 2.0, (bounds[2] + bounds[3]) / 2.0, (bounds[4] + bounds[5]) / 2.0] # Setup camera cameraPositionOffset = 100.0 cameraNode = slicer.modules.cameras.logic().GetViewActiveCameraNode( self.printThreeDViewNode) cameraNode.SetFocalPoint(center) cameraNode.SetPosition( center[0], center[1], center[2] + bounds[5] - bounds[4] + cameraPositionOffset) cameraNode.SetViewUp(0, 1, 0) cameraNode.GetCamera().SetClippingRange(cameraPositionOffset / 2.0, (bounds[5] - bounds[4]) * 2 + cameraPositionOffset * 2.0) windowSizeInPixels = self.printThreeDWidget.threeDView().renderWindow( ).GetSize() pixelSizeInMm = 25.4 / self.printYResolutionDpi printViewHeightOfViewportInMm = windowSizeInPixels[ 1] * pixelSizeInMm / self.printScale cameraNode.SetParallelScale(printViewHeightOfViewportInMm) threeDView = self.printThreeDWidget.threeDView() renderWindow = threeDView.renderWindow() renderer = renderWindow.GetRenderers().GetFirstRenderer() originalCameraUserTransform = cameraNode.GetCamera().GetUserTransform() originalPixelAspect = renderer.GetPixelAspect() cameraUserTransform = vtk.vtkTransform() cameraUserTransform.Scale( self.printXResolutionDpi / self.printYResolutionDpi, 1.0, 1.0) cameraNode.GetCamera().SetUserTransform(cameraUserTransform) if self.printTransparentBackground: originalAlphaBitPlanes = renderWindow.GetAlphaBitPlanes() renderWindow.SetAlphaBitPlanes(1) originalGradientBackground = renderer.GetGradientBackground() renderer.SetGradientBackground(False) # Render threeDView.forceRender() windowToImage = vtk.vtkWindowToImageFilter() if self.printTransparentBackground: windowToImage.SetInputBufferTypeToRGBA() renderWindow.Render() windowToImage.SetInput(renderWindow) # Write to file with custom DPI # (use Qt file writer to allow saving DPI values) windowToImage.Update() vtkImage = windowToImage.GetOutput() qImage = qt.QImage() slicer.qMRMLUtils().vtkImageDataToQImage(vtkImage, qImage) inchesPerMeter = 1000 / 25.4 qImage.setDotsPerMeterX(self.printXResolutionDpi * inchesPerMeter) qImage.setDotsPerMeterY(self.printYResolutionDpi * inchesPerMeter) imagePixmap = qt.QPixmap.fromImage(qImage) imagePixmap.save(filePath) self.printThreeDWidget.hide() # Restore settings cameraNode.GetCamera().SetUserTransform(originalCameraUserTransform) flattenedModelDisplayNode.SetColor(flattenedModelOriginalColor) flattenedFixedPointsDisplayNode.SetColor( flattenedFixedPointsOriginalColor) for displayNode in hiddenDisplayNodes: displayNode.RemoveAllViewNodeIDs() if self.printTransparentBackground: renderWindow.SetAlphaBitPlanes(originalAlphaBitPlanes) renderer.SetGradientBackground(originalGradientBackground)
def revealPixmap(self, xy): """fill a pixmap with an image that has a reveal pattern at xy with the fg drawn over the bg""" # Get QImages for the two layers bgVTKImage = self.layerLogics['B'].GetImageData() fgVTKImage = self.layerLogics['F'].GetImageData() bgQImage = qt.QImage() fgQImage = qt.QImage() slicer.qMRMLUtils().vtkImageDataToQImage(bgVTKImage, bgQImage) slicer.qMRMLUtils().vtkImageDataToQImage(fgVTKImage, fgQImage) # get the geometry of the focal point (xy) and images # noting that vtk has the origin at the bottom left and qt has # it at the top left. yy is the flipped version of y imageWidth = bgQImage.width() imageHeight = bgQImage.height() x, y = xy yy = imageHeight - y # # make a generally transparent image, # then fill quadrants with the fg image # overlayImage = qt.QImage(imageWidth, imageHeight, qt.QImage().Format_ARGB32) overlayImage.fill(0) halfWidth = imageWidth // 2 halfHeight = imageHeight // 2 topLeft = qt.QRect(0, 0, x, yy) bottomRight = qt.QRect(x, yy, imageWidth - x - 1, imageHeight - yy - 1) self.painter.begin(overlayImage) self.painter.drawImage(topLeft, fgQImage, topLeft) self.painter.drawImage(bottomRight, fgQImage, bottomRight) self.painter.end() # draw the bg and fg on top of gray background compositePixmap = qt.QPixmap(self.width, self.height) compositePixmap.fill(self.gray) self.painter.begin(compositePixmap) self.painter.drawImage(-1 * (x - self.width // 2), -1 * (yy - self.height // 2), bgQImage) self.painter.drawImage(-1 * (x - self.width // 2), -1 * (yy - self.height // 2), overlayImage) self.painter.end() if self.scale: compositePixmap = self.scalePixmap(compositePixmap) # draw a border around the pixmap self.painter.begin(compositePixmap) self.pen = qt.QPen() self.color = qt.QColor("#FF0") self.color.setAlphaF(0.3) self.pen.setColor(self.color) self.pen.setWidth(5) self.pen.setStyle(3) # dotted line (Qt::DotLine) self.painter.setPen(self.pen) rect = qt.QRect(1, 1, self.width - 2, self.height - 2) self.painter.drawRect(rect) self.painter.end() return compositePixmap
def processEvent(self,observee,event): # TODO: use a timer to delay calculation and compress events insideView = False ras = [0.0,0.0,0.0] xyz = [0.0,0.0,0.0] sliceNode = None if self.CrosshairNode: insideView = self.CrosshairNode.GetCursorPositionRAS(ras) sliceNode = self.CrosshairNode.GetCursorPositionXYZ(xyz) sliceLogic = None if sliceNode: appLogic = slicer.app.applicationLogic() if appLogic: sliceLogic = appLogic.GetSliceLogic(sliceNode) if not insideView or not sliceNode or not sliceLogic: self.currentLayoutName = None # reset all the readouts self.viewerColor.text = "" self.viewInfo.text = "" layers = ('L', 'F', 'B') for layer in layers: self.layerNames[layer].setText( "" ) self.layerIJKs[layer].setText( "" ) self.layerValues[layer].setText( "" ) self.imageLabel.hide() self.viewerColor.hide() self.viewInfo.hide() self.viewerFrame.hide() self.showImageBox.show() return self.viewerColor.show() self.viewInfo.show() self.viewerFrame.show() self.showImageBox.hide() self.currentLayoutName = sliceNode.GetLayoutName() # populate the widgets self.viewerColor.setText( " " ) rgbColor = sliceNode.GetLayoutColor(); color = qt.QColor.fromRgbF(rgbColor[0], rgbColor[1], rgbColor[2]) if hasattr(color, 'name'): self.viewerColor.setStyleSheet('QLabel {background-color : %s}' % color.name()) # Described below are the details for the ras coordinate width set to 6: # 1: sign # 3: suggested number of digits before decimal point # 1: decimal point: # 1: number of digits after decimal point spacing = "%.1f" % sliceLogic.GetLowestVolumeSliceSpacing()[2] if sliceNode.GetSliceSpacingMode() == slicer.vtkMRMLSliceNode.PrescribedSliceSpacingMode: spacing = "(%s)" % spacing self.viewInfo.text = \ " {layoutName: <8s} RAS: ({ras_x:6.1f}, {ras_y:6.1f}, {ras_z:6.1f}) {orient: >8s} Sp: {spacing:s}" \ .format(layoutName=sliceNode.GetLayoutName(), ras_x=ras[0], ras_y=ras[1], ras_z=ras[2], orient=sliceNode.GetOrientationString(), spacing=spacing ) def _roundInt(value): try: return int(round(value)) except ValueError: return 0 hasVolume = False layerLogicCalls = (('L', sliceLogic.GetLabelLayer), ('F', sliceLogic.GetForegroundLayer), ('B', sliceLogic.GetBackgroundLayer)) for layer,logicCall in layerLogicCalls: layerLogic = logicCall() volumeNode = layerLogic.GetVolumeNode() ijk = [0, 0, 0] if volumeNode: hasVolume = True xyToIJK = layerLogic.GetXYToIJKTransform() ijkFloat = xyToIJK.TransformDoublePoint(xyz) ijk = [_roundInt(value) for value in ijkFloat] self.layerNames[layer].setText( "<b>%s</b>" % (self.fitName(volumeNode.GetName()) if volumeNode else "None")) self.layerIJKs[layer].setText( "({i:4d}, {j:4d}, {k:4d})".format(i=ijk[0], j=ijk[1], k=ijk[2]) if volumeNode else "") self.layerValues[layer].setText( "<b>%s</b>" % self.getPixelString(volumeNode,ijk) if volumeNode else "") # set image if (not slicer.mrmlScene.IsBatchProcessing()) and sliceLogic and hasVolume and self.showImage: self.imageCrop.SetInputConnection(sliceLogic.GetBlend().GetOutputPort()) xyzInt = [0, 0, 0] xyzInt = [_roundInt(value) for value in xyz] dims = sliceLogic.GetBlend().GetOutput().GetDimensions() minDim = min(dims[0],dims[1]) imageSize = _roundInt(minDim/self.imageZoom/2.0) imin = max(0,xyzInt[0]-imageSize) imax = min(dims[0]-1, xyzInt[0]+imageSize) jmin = max(0,xyzInt[1]-imageSize) jmax = min(dims[1]-1, xyzInt[1]+imageSize) if (imin <= imax) and (jmin <= jmax): self.imageCrop.SetVOI(imin, imax, jmin, jmax, 0,0) self.imageCrop.Update() vtkImage = self.imageCrop.GetOutput() if vtkImage: qImage = qt.QImage() slicer.qMRMLUtils().vtkImageDataToQImage(vtkImage, qImage) self.imagePixmap = self.imagePixmap.fromImage(qImage) self.imagePixmap = self.imagePixmap.scaled(self.imageLabel.size, qt.Qt.KeepAspectRatio, qt.Qt.FastTransformation) # draw crosshair self.painter.begin(self.imagePixmap) self.pen.setColor(color) self.painter.setPen(self.pen) self.painter.drawLine(0,self.imagePixmap.height()/2, self.imagePixmap.width(), self.imagePixmap.height()/2) self.painter.drawLine(self.imagePixmap.width()/2,0, self.imagePixmap.width()/2, self.imagePixmap.height()) self.painter.end() self.imageLabel.setPixmap(self.imagePixmap) self.onShowImage(self.showImage) sceneName = slicer.mrmlScene.GetURL() if sceneName != "": self.frame.parent().text = "Data Probe: %s" % self.fitName(sceneName,nameSize=2*self.nameSize) else: self.frame.parent().text = "Data Probe"
def _createMagnifiedPixmap(self, xyz, inputImageDataConnection, outputSize, crosshairColor, imageZoom=10): # Use existing instance of objects to avoid instantiating one at each event. imageCrop = self.imageCrop painter = self.painter pen = self.pen def _roundInt(value): try: return int(round(value)) except ValueError: return 0 imageCrop.SetInputConnection(inputImageDataConnection) xyzInt = [0, 0, 0] xyzInt = [_roundInt(value) for value in xyz] producer = inputImageDataConnection.GetProducer() dims = producer.GetOutput().GetDimensions() minDim = min(dims[0], dims[1]) imageSize = _roundInt(minDim / imageZoom / 2.0) imin = xyzInt[0] - imageSize imax = xyzInt[0] + imageSize jmin = xyzInt[1] - imageSize jmax = xyzInt[1] + imageSize imin_trunc = max(0, imin) imax_trunc = min(dims[0] - 1, imax) jmin_trunc = max(0, jmin) jmax_trunc = min(dims[1] - 1, jmax) # The extra complexity of the canvas is used here to maintain a fixed size # output due to the imageCrop returning a smaller image if the limits are # outside the input image bounds. Specially useful when zooming at the borders. canvas = self.canvas canvas.SetScalarType(producer.GetOutput().GetScalarType()) canvas.SetNumberOfScalarComponents( producer.GetOutput().GetNumberOfScalarComponents()) canvas.SetExtent(imin, imax, jmin, jmax, 0, 0) canvas.FillBox(imin, imax, jmin, jmax) canvas.Update() if (imin_trunc <= imax_trunc) and (jmin_trunc <= jmax_trunc): imageCrop.SetVOI(imin_trunc, imax_trunc, jmin_trunc, jmax_trunc, 0, 0) imageCrop.Update() vtkImageCropped = imageCrop.GetOutput() xyzBounds = [0] * 6 vtkImageCropped.GetBounds(xyzBounds) xyzBounds = [_roundInt(value) for value in xyzBounds] canvas.DrawImage(xyzBounds[0], xyzBounds[2], vtkImageCropped) canvas.Update() vtkImageFromCanvas = canvas.GetOutput() if vtkImageFromCanvas: qImage = qt.QImage() slicer.qMRMLUtils().vtkImageDataToQImage( vtkImageFromCanvas, qImage) imagePixmap = qt.QPixmap.fromImage(qImage) imagePixmap = imagePixmap.scaled(outputSize, qt.Qt.KeepAspectRatio, qt.Qt.FastTransformation) # draw crosshair painter.begin(imagePixmap) pen = qt.QPen() pen.setColor(crosshairColor) painter.setPen(pen) painter.drawLine(0, int(imagePixmap.height() / 2), imagePixmap.width(), int(imagePixmap.height() / 2)) painter.drawLine(int(imagePixmap.width() / 2), 0, int(imagePixmap.width() / 2), imagePixmap.height()) painter.end() return imagePixmap return None