def cursorForEffect(self, effectName): """Return an instance of QCursor customized for the given effectName. TODO: this could be moved to the EffectTool class so that effects can manage per-widget cursors, possibly turning them off or making them dynamic """ if not effectName in self.effectCursors: baseImage = qt.QImage(":/Icons/AnnotationPointWithArrow.png") effectImage = qt.QImage(self.effectIconFiles[effectName]) width = max(baseImage.width(), effectImage.width()) pad = -9 height = pad + baseImage.height() + effectImage.height() width = height = max(width, height) center = int(width / 2) cursorImage = qt.QImage(width, height, qt.QImage().Format_ARGB32) painter = qt.QPainter() cursorImage.fill(0) painter.begin(cursorImage) point = qt.QPoint(center - (baseImage.width() / 2), 0) painter.drawImage(point, baseImage) point.setX(center - (effectImage.width() / 2)) point.setY(cursorImage.height() - effectImage.height()) painter.drawImage(point, effectImage) painter.end() cursorPixmap = qt.QPixmap() cursorPixmap = cursorPixmap.fromImage(cursorImage) self.effectCursors[effectName] = qt.QCursor( cursorPixmap, center, 0) return self.effectCursors[effectName]
def generate(self, volumeRenderingNode, filePattern="/tmp/slice_%04d.png"): # underscore not dash self.cancelRequested = False # Ensure view node and widget exists and cross-references are up-to-date self.create3dView(volumeRenderingNode) self.threeDViewNode.SetAndObserveParentLayoutNodeID( volumeRenderingNode.GetID()) self.threeDWidget.setMRMLViewNode(self.threeDViewNode) # Make sure the selected volume rendering node is visible in the capture view if not volumeRenderingNode.IsDisplayableInView( self.threeDViewNode.GetID()): volumeRenderingNode.AddViewNodeID(self.threeDViewNode.GetID()) # Configure view and widget self.threeDViewNode.SetBoxVisible(0) self.threeDViewNode.SetAxisLabelsVisible(0) self.threeDViewNode.SetVolumeRenderingQuality( slicer.vtkMRMLViewNode.Normal ) # viewNode.Maximum could provide better quality but slower self.threeDViewNode.SetRenderMode(slicer.vtkMRMLViewNode.Orthographic) self.threeDViewNode.SetBackgroundColor((1, 1, 1)) self.threeDViewNode.SetBackgroundColor2((1, 1, 1)) # Turn off shading. We do not want any lighting effect (specular reflections, etc.) to be baked into the image. originalShade = volumeRenderingNode.GetVolumePropertyNode( ).GetVolumeProperty().GetShade() volumeRenderingNode.GetVolumePropertyNode().GetVolumeProperty( ).SetShade(False) self.threeDWidget.resize(self.width, self.height) self.threeDWidget.show() # Save original ROI volumeRenderingNode.SetCroppingEnabled(True) roi = volumeRenderingNode.GetROINode() roiCenter = [0] * 3 roiRadius = [0] * 3 roi.GetXYZ(roiCenter) roi.GetRadiusXYZ(roiRadius) originalRoiVisibility = roi.GetDisplayVisibility() roi.SetDisplayVisibility(False) cameraPositionOffset = 100.0 cameraNode = slicer.modules.cameras.logic().GetViewActiveCameraNode( self.threeDViewNode) cameraNode.SetFocalPoint(roiCenter) cameraNode.SetPosition( roiCenter[0], roiCenter[1], roiCenter[2] + roiRadius[2] + cameraPositionOffset) cameraNode.SetViewUp((0, 1, 0)) cameraNode.GetCamera().SetClippingRange( cameraPositionOffset / 2.0, roiRadius[2] * 2 + cameraPositionOffset * 2.0) windowSizeInPixels = self.threeDWidget.threeDView().renderWindow( ).GetSize() pixelSizeInMm = 25.4 / self.yResolutionDpi heightOfViewportInMm = windowSizeInPixels[ 1] * pixelSizeInMm / self.printScale cameraNode.SetParallelScale(heightOfViewportInMm) # cycle through the slabs slabRadius = list(roiRadius) slabRadius[2] = self.slabThickness roi.SetRadiusXYZ(slabRadius) slabCounter = 0 slabCenter = [roiCenter[0], roiCenter[1], roiCenter[2] - roiRadius[2]] slabTop = roiCenter[2] + roiRadius[2] scaledSlabSpacingMm = self.slabSpacingMm / self.printScale numberOfSlabs = int(roiRadius[2] * 2.0 / scaledSlabSpacingMm) + 1 threeDView = self.threeDWidget.threeDView() renderWindow = threeDView.renderWindow() renderer = renderWindow.GetRenderers().GetFirstRenderer() originalCameraUserTransform = cameraNode.GetCamera().GetUserTransform() originalPixelAspect = renderer.GetPixelAspect() cameraUserTransform = vtk.vtkTransform() cameraUserTransform.Scale(self.xResolutionDpi / self.yResolutionDpi, 1.0, 1.0) cameraNode.GetCamera().SetUserTransform(cameraUserTransform) if self.transparentBackground: originalAlphaBitPlanes = renderWindow.GetAlphaBitPlanes() renderWindow.SetAlphaBitPlanes(1) originalGradientBackground = renderer.GetGradientBackground() renderer.SetGradientBackground(False) logging.info("Starting render...") while slabCenter[2] <= slabTop: slicer.app.processEvents() if self.cancelRequested: break roi.SetXYZ(slabCenter) threeDView.forceRender() windowToImage = vtk.vtkWindowToImageFilter() if self.transparentBackground: windowToImage.SetInputBufferTypeToRGBA() renderWindow.Render() windowToImage.SetInput(renderWindow) # Write to file with custom DPI # (use Qt file writer to allow saving DPI values) filename = "c:/tmp/test.png" windowToImage.Update() vtkImage = windowToImage.GetOutput() qImage = qt.QImage() slicer.qMRMLUtils().vtkImageDataToQImage(vtkImage, qImage) inchesPerMeter = 1000 / 25.4 qImage.setDotsPerMeterX(self.xResolutionDpi * inchesPerMeter) qImage.setDotsPerMeterY(self.yResolutionDpi * inchesPerMeter) imagePixmap = qt.QPixmap.fromImage(qImage) filePath = filePattern % slabCounter imagePixmap.save(filePath) slabCounter += 1 slabCenter[2] = slabCenter[2] + scaledSlabSpacingMm logging.info("Slab {0}/{1} saved to {2}".format( slabCounter, numberOfSlabs, filePath)) self.threeDWidget.hide() # reset ROI roi.SetXYZ(roiCenter) roi.SetRadiusXYZ(roiRadius) roi.SetDisplayVisibility(originalRoiVisibility) cameraNode.GetCamera().SetUserTransform(originalCameraUserTransform) if self.transparentBackground: renderWindow.SetAlphaBitPlanes(originalAlphaBitPlanes) renderer.SetGradientBackground(originalGradientBackground) volumeRenderingNode.GetVolumePropertyNode().GetVolumeProperty( ).SetShade(originalShade) # for debugging convenience slicer.modules.BitmapGeneratorWidget.threeDWidget = self.threeDWidget slicer.modules.BitmapGeneratorWidget.threeDViewNode = self.threeDViewNode slicer.modules.BitmapGeneratorWidget.volumeRenderingNode = volumeRenderingNode if self.cancelRequested: raise ValueError('User requested cancel.')
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