Exemple #1
0
 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.')
Exemple #3
0
    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