Example #1
0
  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
Example #2
0
    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)
Example #4
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
Example #5
0
  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"
Example #6
0
    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