示例#1
0
  def changeLabel(self):
    #
    # change the label values based on the parameter node
    #
    if not self.sliceLogic:
      self.sliceLogic = EditUtil.getSliceLogic()
    parameterNode = EditUtil.getParameterNode()
    parameterNode = EditUtil.getParameterNode()
    inputColor = int(parameterNode.GetParameter("ChangeLabelEffect,inputColor"))
    outputColor = int(parameterNode.GetParameter("ChangeLabelEffect,outputColor"))

    change = slicer.vtkImageLabelChange()
    if vtk.VTK_MAJOR_VERSION <= 5:
      change.SetInput( self.getScopedLabelInput() )
    else:
      change.SetInputData( self.getScopedLabelInput() )
    change.SetOutput( self.getScopedLabelOutput() )
    change.SetInputLabel( inputColor )
    change.SetOutputLabel( outputColor )

    # TODO
    #$this setProgressFilter $change "Change Label"
    change.Update()

    self.applyScopedLabel()
    change.SetOutput( None )
示例#2
0
    def changeLabel(self):
        #
        # change the label values based on the parameter node
        #
        if not self.sliceLogic:
            self.sliceLogic = EditUtil.getSliceLogic()
        parameterNode = EditUtil.getParameterNode()
        parameterNode = EditUtil.getParameterNode()
        inputColor = int(
            parameterNode.GetParameter("ChangeLabelEffect,inputColor"))
        outputColor = int(
            parameterNode.GetParameter("ChangeLabelEffect,outputColor"))

        change = slicer.vtkImageLabelChange()
        if vtk.VTK_MAJOR_VERSION <= 5:
            change.SetInput(self.getScopedLabelInput())
        else:
            change.SetInputData(self.getScopedLabelInput())
        change.SetOutput(self.getScopedLabelOutput())
        change.SetInputLabel(inputColor)
        change.SetOutputLabel(outputColor)

        # TODO
        #$this setProgressFilter $change "Change Label"
        change.Update()

        self.applyScopedLabel()
        change.SetOutput(None)
示例#3
0
  def paintPixel(self, x, y):
    """
    paint with a single pixel (in label space)
    """
    sliceLogic = self.sliceWidget.sliceLogic()
    labelLogic = sliceLogic.GetLabelLayer()
    labelNode = labelLogic.GetVolumeNode()
    labelImage = labelNode.GetImageData()

    if not labelNode:
      # if there's no label, we can't paint
      return

    xyToIJK = labelLogic.GetXYToIJKTransform()
    ijkFloat = xyToIJK.TransformDoublePoint( (x, y, 0) )
    ijk = []
    for e in ijkFloat:
      try:
        index = int(round(e))
      except ValueError:
        return
      ijk.append(index)
    dims = labelImage.GetDimensions()
    for e,d in zip(ijk,dims): # clamp to volume extent
      if e < 0 or e >= d:
        return

    parameterNode = EditUtil.getParameterNode()
    paintLabel = int(parameterNode.GetParameter("label"))
    labelImage.SetScalarComponentFromFloat(ijk[0],ijk[1],ijk[2],0, paintLabel)
    EditUtil.markVolumeNodeAsModified(labelNode)
示例#4
0
 def updateParameterNode(self, caller, event):
   node = EditUtil.getParameterNode()
   if node != self.parameterNode:
     if self.parameterNode:
       node.RemoveObserver(self.parameterNodeTag)
     self.parameterNode = node
     self.parameterNodeTag = node.AddObserver(vtk.vtkCommand.ModifiedEvent, self.updateGUIFromMRML)
示例#5
0
 def updateParameterNode(self, caller, event):
   node = EditUtil.getParameterNode()
   if node != self.parameterNode:
     if self.parameterNode:
       node.RemoveObserver(self.parameterNodeTag)
     self.parameterNode = node
     self.parameterNodeTag = node.AddObserver(vtk.vtkCommand.ModifiedEvent, self.updateGUIFromMRML)
示例#6
0
    def create(self):

        self.findEffects()

        self.mainFrame = qt.QFrame(self.parent)
        self.mainFrame.objectName = 'MainFrame'
        vbox = qt.QVBoxLayout()
        self.mainFrame.setLayout(vbox)
        self.parent.layout().addWidget(self.mainFrame)

        #
        # the buttons
        #
        self.rowFrames = []
        self.actions = {}
        self.buttons = {}
        self.icons = {}
        self.callbacks = {}

        # create all of the buttons
        # createButtonRow() ensures that only effects in self.effects are exposed,
        self.createButtonRow(
            ("DefaultTool", "EraseLabel", "PaintEffect", "DrawEffect",
             "WandEffect", "LevelTracingEffect", "RectangleEffect",
             "IdentifyIslandsEffect", "ChangeIslandEffect",
             "RemoveIslandsEffect", "SaveIslandEffect"))
        self.createButtonRow(
            ("ErodeEffect", "DilateEffect", "GrowCutEffect",
             "WatershedFromMarkerEffect", "ThresholdEffect",
             "ChangeLabelEffect", "MakeModelEffect", "FastMarchingEffect"))

        extensions = []
        for k in slicer.modules.editorExtensions:
            extensions.append(k)
        self.createButtonRow(extensions)

        self.createButtonRow(("PreviousCheckPoint", "NextCheckPoint"),
                             rowLabel="Undo/Redo: ")

        #
        # the labels
        #
        self.toolsActiveToolFrame = qt.QFrame(self.parent)
        self.toolsActiveToolFrame.setLayout(qt.QHBoxLayout())
        self.parent.layout().addWidget(self.toolsActiveToolFrame)
        self.toolsActiveTool = qt.QLabel(self.toolsActiveToolFrame)
        self.toolsActiveTool.setText('Active Tool:')
        self.toolsActiveTool.setStyleSheet(
            "background-color: rgb(232,230,235)")
        self.toolsActiveToolFrame.layout().addWidget(self.toolsActiveTool)
        self.toolsActiveToolName = qt.QLabel(self.toolsActiveToolFrame)
        self.toolsActiveToolName.setText('')
        self.toolsActiveToolName.setStyleSheet(
            "background-color: rgb(232,230,235)")
        self.toolsActiveToolFrame.layout().addWidget(self.toolsActiveToolName)

        vbox.addStretch(1)

        self.updateUndoRedoButtons()
        self._onParameterNodeModified(EditUtil.getParameterNode())
示例#7
0
  def __init__(self, sliceWidget):
    super(PaintEffectTool,self).__init__(sliceWidget)
    # create a logic instance to do the non-gui work
    self.logic = PaintEffectLogic(self.sliceWidget.sliceLogic())

    # configuration variables
    self.delayedPaint = True
    self.parameterNode = EditUtil.getParameterNode()
    self.sphere = not (0 == int(self.parameterNode.GetParameter("PaintEffect,sphere")))
    self.smudge = not (0 == int(self.parameterNode.GetParameter("PaintEffect,smudge")))
    self.pixelMode = not (0 == int(self.parameterNode.GetParameter("PaintEffect,pixelMode")))
    self.radius = float(self.parameterNode.GetParameter("PaintEffect,radius"))

    # interaction state variables
    self.position = [0, 0, 0]
    self.paintCoordinates = []
    self.feedbackActors = []
    self.lastRadius = 0

    # scratch variables
    self.rasToXY = vtk.vtkMatrix4x4()

    # initialization
    self.brush = vtk.vtkPolyData()
    self.createGlyph(self.brush)
    self.mapper = vtk.vtkPolyDataMapper2D()
    self.actor = vtk.vtkActor2D()
    self.mapper.SetInputData(self.brush)
    self.actor.SetMapper(self.mapper)
    self.actor.VisibilityOff()

    self.renderer.AddActor2D(self.actor)
    self.actors.append(self.actor)

    self.processEvent()
示例#8
0
    def paintPixel(self, x, y):
        """
    paint with a single pixel (in label space)
    """
        sliceLogic = self.sliceWidget.sliceLogic()
        labelLogic = sliceLogic.GetLabelLayer()
        labelNode = labelLogic.GetVolumeNode()
        labelImage = labelNode.GetImageData()

        if not labelNode:
            # if there's no label, we can't paint
            return

        xyToIJK = labelLogic.GetXYToIJKTransform()
        ijkFloat = xyToIJK.TransformDoublePoint((x, y, 0))
        ijk = []
        for e in ijkFloat:
            try:
                index = int(round(e))
            except ValueError:
                return
            ijk.append(index)
        dims = labelImage.GetDimensions()
        for e, d in zip(ijk, dims):  # clamp to volume extent
            if e < 0 or e >= d:
                return

        parameterNode = EditUtil.getParameterNode()
        paintLabel = int(parameterNode.GetParameter("label"))
        labelImage.SetScalarComponentFromFloat(ijk[0], ijk[1], ijk[2], 0,
                                               paintLabel)
        EditUtil.markVolumeNodeAsModified(labelNode)
示例#9
0
    def select(self, masterVolume=None, mergeVolume=None):
        """select master volume - load merge volume if one with the correct name exists"""

        if masterVolume == None:
            masterVolume = self.masterSelector.currentNode()
        self.master = masterVolume

        self.masterSelector.blockSignals(True)
        self.masterSelector.setCurrentNode(self.master)
        self.masterSelector.blockSignals(False)

        self.mergeSelector.setCurrentNode(mergeVolume)

        if self.master and not self.mergeVolume():
            # the master exists, but there is no merge volume yet
            # bring up dialog to create a merge with a user-selected color node
            self.labelCreateDialog()

        merge = self.mergeVolume()
        if merge:
            if not merge.IsA("vtkMRMLLabelMapVolumeNode"):
                slicer.util.errorDisplay(
                    "Error: selected merge label volume is not a label volume")
            else:
                EditUtil.setActiveVolumes(self.master, merge)
                self.mergeSelector.setCurrentNode(merge)

        self.structureListWidget.master = self.master
        self.structureListWidget.merge = merge
        self.structureListWidget.updateStructures()

        if self.master and merge:
            warnings = self.volumesLogic.CheckForLabelVolumeValidity(
                self.master, merge)
            if warnings != "":
                warnings = "Geometry of master and merge volumes do not match.\n\n" + warnings
                slicer.util.errorDisplay("Warning: %s" % warnings)

        # trigger a modified event on the parameter node so that other parts of the GUI
        # (such as the EditColor) will know to update and enable themselves
        EditUtil.getParameterNode().Modified()

        if self.selectCommand:
            self.selectCommand()
示例#10
0
 def updateParameterNode(self, caller, event):
   #
   # observe the scene to know when to get the parameter node
   #
   parameterNode = EditUtil.getParameterNode()
   if parameterNode != self.parameterNode:
     if self.parameterNode:
       self.parameterNode.RemoveObserver(self.parameterNodeTag)
     self.parameterNode = parameterNode
     self.parameterNodeTag = self.parameterNode.AddObserver(vtk.vtkCommand.ModifiedEvent, self.updateGUIFromMRML)
示例#11
0
 def updateParameterNode(self, caller, event):
   #
   # observe the scene to know when to get the parameter node
   #
   parameterNode = EditUtil.getParameterNode()
   if parameterNode != self.parameterNode:
     if self.parameterNode:
       self.parameterNode.RemoveObserver(self.parameterNodeTag)
     self.parameterNode = parameterNode
     self.parameterNodeTag = self.parameterNode.AddObserver(vtk.vtkCommand.ModifiedEvent, self.updateGUIFromMRML)
示例#12
0
  def select(self, masterVolume=None, mergeVolume=None):
    """select master volume - load merge volume if one with the correct name exists"""

    if masterVolume is None:
        masterVolume = self.masterSelector.currentNode()
    self.master = masterVolume

    self.masterSelector.blockSignals(True)
    self.masterSelector.setCurrentNode(self.master)
    self.masterSelector.blockSignals(False)

    self.mergeSelector.setCurrentNode(mergeVolume)

    if self.master and not self.mergeVolume():
      # the master exists, but there is no merge volume yet
      # bring up dialog to create a merge with a user-selected color node
      self.labelCreateDialog()

    merge = self.mergeVolume()
    if merge:
      if not merge.IsA("vtkMRMLLabelMapVolumeNode"):
        slicer.util.errorDisplay( "Error: selected merge label volume is not a label volume" )
      else:
        EditUtil.setActiveVolumes(self.master, merge)
        self.mergeSelector.setCurrentNode(merge)

    self.structureListWidget.master = self.master
    self.structureListWidget.merge = merge
    self.structureListWidget.updateStructures()

    if self.master and merge:
      warnings = self.volumesLogic.CheckForLabelVolumeValidity(self.master,merge)
      if warnings != "":
        warnings = "Geometry of master and merge volumes do not match.\n\n" + warnings
        slicer.util.errorDisplay( "Warning: %s" % warnings )

    # trigger a modified event on the parameter node so that other parts of the GUI
    # (such as the EditColor) will know to update and enable themselves
    EditUtil.getParameterNode().Modified()

    if self.selectCommand:
      self.selectCommand()
示例#13
0
 def updateParameterNode(self, caller, event):
   """
   note: this method needs to be implemented exactly as
   defined in the leaf classes in EditOptions.py
   in each leaf subclass so that "self" in the observer
   is of the correct type """
   node = EditUtil.getParameterNode()
   if node != self.parameterNode:
     if self.parameterNode:
       node.RemoveObserver(self.parameterNodeTag)
     self.parameterNode = node
     self.parameterNodeTag = node.AddObserver(vtk.vtkCommand.ModifiedEvent, self.updateGUIFromMRML)
示例#14
0
 def updateParameterNode(self, caller, event):
     """
 note: this method needs to be implemented exactly as
 defined in the leaf classes in EditOptions.py
 in each leaf subclass so that "self" in the observer
 is of the correct type """
     node = EditUtil.getParameterNode()
     if node != self.parameterNode:
         if self.parameterNode:
             node.RemoveObserver(self.parameterNodeTag)
         self.parameterNode = node
         self.parameterNodeTag = node.AddObserver(
             vtk.vtkCommand.ModifiedEvent, self.updateGUIFromMRML)
示例#15
0
  def create(self):

    self.findEffects()

    self.mainFrame = qt.QFrame(self.parent)
    self.mainFrame.objectName = 'MainFrame'
    vbox = qt.QVBoxLayout()
    self.mainFrame.setLayout(vbox)
    self.parent.layout().addWidget(self.mainFrame)

    #
    # the buttons
    #
    self.rowFrames = []
    self.actions = {}
    self.buttons = {}
    self.icons = {}
    self.callbacks = {}

    # create all of the buttons
    # createButtonRow() ensures that only effects in self.effects are exposed,
    self.createButtonRow( ("DefaultTool", "EraseLabel", "PaintEffect", "DrawEffect", "WandEffect", "LevelTracingEffect", "RectangleEffect", "IdentifyIslandsEffect", "ChangeIslandEffect", "RemoveIslandsEffect", "SaveIslandEffect") )
    self.createButtonRow( ("ErodeEffect", "DilateEffect", "GrowCutEffect", "WatershedFromMarkerEffect", "ThresholdEffect", "ChangeLabelEffect", "MakeModelEffect", "FastMarchingEffect") )

    extensions = []
    for k in slicer.modules.editorExtensions:
      extensions.append(k)
    self.createButtonRow( extensions )

    self.createButtonRow( ("PreviousCheckPoint", "NextCheckPoint"), rowLabel="Undo/Redo: " )

    #
    # the labels
    #
    self.toolsActiveToolFrame = qt.QFrame(self.parent)
    self.toolsActiveToolFrame.setLayout(qt.QHBoxLayout())
    self.parent.layout().addWidget(self.toolsActiveToolFrame)
    self.toolsActiveTool = qt.QLabel(self.toolsActiveToolFrame)
    self.toolsActiveTool.setText( 'Active Tool:' )
    self.toolsActiveTool.setStyleSheet("background-color: rgb(232,230,235)")
    self.toolsActiveToolFrame.layout().addWidget(self.toolsActiveTool)
    self.toolsActiveToolName = qt.QLabel(self.toolsActiveToolFrame)
    self.toolsActiveToolName.setText( '' )
    self.toolsActiveToolName.setStyleSheet("background-color: rgb(232,230,235)")
    self.toolsActiveToolFrame.layout().addWidget(self.toolsActiveToolName)

    vbox.addStretch(1)

    self.updateUndoRedoButtons()
    self._onParameterNodeModified(EditUtil.getParameterNode())
示例#16
0
    def __init__(self, sliceWidget):
        super(PaintEffectTool, self).__init__(sliceWidget)
        # create a logic instance to do the non-gui work
        self.logic = PaintEffectLogic(self.sliceWidget.sliceLogic())

        # configuration variables
        self.delayedPaint = True
        self.parameterNode = EditUtil.getParameterNode()
        self.sphere = not (0 == int(
            self.parameterNode.GetParameter("PaintEffect,sphere")))
        self.smudge = not (0 == int(
            self.parameterNode.GetParameter("PaintEffect,smudge")))
        self.pixelMode = not (0 == int(
            self.parameterNode.GetParameter("PaintEffect,pixelMode")))
        self.radius = float(
            self.parameterNode.GetParameter("PaintEffect,radius"))

        # interaction state variables
        self.position = [0, 0, 0]
        self.paintCoordinates = []
        self.feedbackActors = []
        self.lastRadius = 0

        # scratch variables
        self.rasToXY = vtk.vtkMatrix4x4()

        # initialization
        self.brush = vtk.vtkPolyData()
        self.createGlyph(self.brush)
        self.mapper = vtk.vtkPolyDataMapper2D()
        self.actor = vtk.vtkActor2D()
        if vtk.VTK_MAJOR_VERSION <= 5:
            self.mapper.SetInput(self.brush)
        else:
            self.mapper.SetInputData(self.brush)
        self.actor.SetMapper(self.mapper)
        self.actor.VisibilityOff()

        self.renderer.AddActor2D(self.actor)
        self.actors.append(self.actor)

        self.processEvent()
示例#17
0
    def paintBrush(self, x, y):
        """
    paint with a brush that is circular (or optionally spherical) in XY space
     (could be stretched or rotate when transformed to IJK)
     - make sure to hit every pixel in IJK space
     - apply the threshold if selected
    """

        sliceLogic = self.sliceWidget.sliceLogic()
        sliceNode = sliceLogic.GetSliceNode()
        labelLogic = sliceLogic.GetLabelLayer()
        labelNode = labelLogic.GetVolumeNode()
        labelImage = labelNode.GetImageData()
        backgroundLogic = sliceLogic.GetBackgroundLayer()
        backgroundNode = backgroundLogic.GetVolumeNode()
        backgroundImage = backgroundNode.GetImageData()

        if not labelNode:
            # if there's no label, we can't paint
            return

        #
        # get the brush bounding box in ijk coordinates
        # - get the xy bounds
        # - transform to ijk
        # - clamp the bounds to the dimensions of the label image
        #
        bounds = self.brush.GetPoints().GetBounds()
        left = x + bounds[0]
        right = x + bounds[1]
        bottom = y + bounds[2]
        top = y + bounds[3]

        xyToIJK = labelLogic.GetXYToIJKTransform()
        tlIJK = xyToIJK.TransformDoublePoint((left, top, 0))
        trIJK = xyToIJK.TransformDoublePoint((right, top, 0))
        blIJK = xyToIJK.TransformDoublePoint((left, bottom, 0))
        brIJK = xyToIJK.TransformDoublePoint((right, bottom, 0))

        dims = labelImage.GetDimensions()

        # clamp the top, bottom, left, right to the
        # valid dimensions of the label image
        tl = [0, 0, 0]
        tr = [0, 0, 0]
        bl = [0, 0, 0]
        br = [0, 0, 0]
        for i in xrange(3):
            tl[i] = int(round(tlIJK[i]))
            if tl[i] < 0:
                tl[i] = 0
            if tl[i] >= dims[i]:
                tl[i] = dims[i] - 1
            tr[i] = int(round(trIJK[i]))
            if tr[i] < 0:
                tr[i] = 0
            if tr[i] >= dims[i]:
                tr[i] = dims[i] - 1
            bl[i] = int(round(blIJK[i]))
            if bl[i] < 0:
                bl[i] = 0
            if bl[i] >= dims[i]:
                bl[i] = dims[i] - 1
            br[i] = int(round(brIJK[i]))
            if br[i] < 0:
                br[i] = 0
            if br[i] >= dims[i]:
                br[i] = dims[i] - 1

        # If the region is smaller than a pixel then paint it using paintPixel mode,
        # to make sure at least one pixel is filled on each click
        maxRowDelta = 0
        maxColumnDelta = 0
        for i in xrange(3):
            d = abs(tr[i] - tl[i])
            if d > maxColumnDelta:
                maxColumnDelta = d
            d = abs(br[i] - bl[i])
            if d > maxColumnDelta:
                maxColumnDelta = d
            d = abs(bl[i] - tl[i])
            if d > maxRowDelta:
                maxRowDelta = d
            d = abs(br[i] - tr[i])
            if d > maxRowDelta:
                maxRowDelta = d
        if maxRowDelta <= 1 or maxColumnDelta <= 1:
            self.paintPixel(x, y)
            return

        #
        # get the layers and nodes
        # and ijk to ras matrices including transforms
        #
        backgroundIJKToRAS = self.logic.getIJKToRASMatrix(backgroundNode)
        labelIJKToRAS = self.logic.getIJKToRASMatrix(labelNode)

        xyToRAS = sliceNode.GetXYToRAS()
        brushCenter = xyToRAS.MultiplyPoint((x, y, 0, 1))[:3]

        brushRadius = self.radius
        bSphere = self.sphere

        parameterNode = EditUtil.getParameterNode()
        paintLabel = int(parameterNode.GetParameter("label"))
        paintOver = int(parameterNode.GetParameter("LabelEffect,paintOver"))
        paintThreshold = int(
            parameterNode.GetParameter("LabelEffect,paintThreshold"))
        paintThresholdMin = float(
            parameterNode.GetParameter("LabelEffect,paintThresholdMin"))
        paintThresholdMax = float(
            parameterNode.GetParameter("LabelEffect,paintThresholdMax"))

        #
        # set up the painter class and let 'r rip!
        #
        if not hasattr(self, "painter"):
            self.painter = slicer.vtkImageSlicePaint()

        self.painter.SetBackgroundImage(backgroundImage)
        self.painter.SetBackgroundIJKToWorld(backgroundIJKToRAS)
        self.painter.SetWorkingImage(labelImage)
        self.painter.SetWorkingIJKToWorld(labelIJKToRAS)
        self.painter.SetTopLeft(tl[0], tl[1], tl[2])
        self.painter.SetTopRight(tr[0], tr[1], tr[2])
        self.painter.SetBottomLeft(bl[0], bl[1], bl[2])
        self.painter.SetBottomRight(br[0], br[1], br[2])
        self.painter.SetBrushCenter(brushCenter[0], brushCenter[1],
                                    brushCenter[2])
        self.painter.SetBrushRadius(brushRadius)
        self.painter.SetPaintLabel(paintLabel)
        self.painter.SetPaintOver(paintOver)
        self.painter.SetThresholdPaint(paintThreshold)
        self.painter.SetThresholdPaintRange(paintThresholdMin,
                                            paintThresholdMax)

        if bSphere:  # fill volume of a sphere rather than a circle on the currently displayed image slice
            # Algorithm:
            ###########################
            # Assume brushRadius is in mm
            # Estimate zVoxelSize
            # Compute number of slices spanned by sphere, that are still within the volume
            # For each spanned slice
            #    reposition the brushCenter using xy(z)ToRAS transform: i.e. canvas to patient world coordinates
            #    resize the radius: brushRadiusOffset=sqrt(brushRadius*brushRadius - zOffset_mm*zOffset_mm)
            #    invoke Paint()
            # Finally paint on the center slice, leaving the gui on the center slice being most visibly edited
            #------------------
            # Estimate zVoxelSize_mm
            brushCenter1 = xyToRAS.MultiplyPoint((x, y, 0, 1))[:3]
            brushCenter2 = xyToRAS.MultiplyPoint((x, y, 100, 1))[:3]
            dx1 = brushCenter1[0] - brushCenter2[0]
            dx2 = brushCenter1[1] - brushCenter2[1]
            dx3 = brushCenter1[2] - brushCenter2[2]
            distanceSpannedBy100Slices = sqrt(dx1 * dx1 + dx2 * dx2 +
                                              dx3 * dx3)  # compute L2 norm
            if distanceSpannedBy100Slices == 0:
                zVoxelSize_mm = 1
            else:
                zVoxelSize_mm = distanceSpannedBy100Slices / 100
            # --
            # Compute number of slices spanned by sphere
            nNumSlicesInEachDirection = brushRadius / zVoxelSize_mm
            nNumSlicesInEachDirection = nNumSlicesInEachDirection - 1
            sliceOffsetArray = numpy.concatenate((-1 * numpy.arange(
                1,
                nNumSlicesInEachDirection + 1,
            ), numpy.arange(1, nNumSlicesInEachDirection + 1)))
            for iSliceOffset in sliceOffsetArray:
                # x,y uses slice (canvas) coordinate system and actually has a 3rd z component (index into the slice you're looking at)
                # hence xyToRAS is really performing xyzToRAS.   RAS is patient world coordinate system. Note the 1 is because the trasform uses homogeneous coordinates
                iBrushCenter = xyToRAS.MultiplyPoint(
                    (x, y, iSliceOffset, 1))[:3]
                self.painter.SetBrushCenter(iBrushCenter[0], iBrushCenter[1],
                                            iBrushCenter[2])
                # [ ] Need to just continue (pass this loop iteration if the brush center is not within the volume
                zOffset_mm = zVoxelSize_mm * iSliceOffset
                brushRadiusOffset = sqrt(brushRadius * brushRadius -
                                         zOffset_mm * zOffset_mm)
                self.painter.SetBrushRadius(brushRadiusOffset)

                # --
                tlIJKtemp = xyToIJK.TransformDoublePoint(
                    (left, top, iSliceOffset))
                trIJKtemp = xyToIJK.TransformDoublePoint(
                    (right, top, iSliceOffset))
                blIJKtemp = xyToIJK.TransformDoublePoint(
                    (left, bottom, iSliceOffset))
                brIJKtemp = xyToIJK.TransformDoublePoint(
                    (right, bottom, iSliceOffset))
                # clamp the top, bottom, left, right to the
                # valid dimensions of the label image
                tltemp = [0, 0, 0]
                trtemp = [0, 0, 0]
                bltemp = [0, 0, 0]
                brtemp = [0, 0, 0]
                for i in xrange(3):
                    tltemp[i] = int(round(tlIJKtemp[i]))
                    if tltemp[i] < 0:
                        tltemp[i] = 0
                    if tltemp[i] >= dims[i]:
                        tltemp[i] = dims[i] - 1
                    trtemp[i] = int(round(trIJKtemp[i]))
                    if trtemp[i] < 0:
                        trtemp[i] = 0
                    if trtemp[i] > dims[i]:
                        trtemp[i] = dims[i] - 1
                    bltemp[i] = int(round(blIJKtemp[i]))
                    if bltemp[i] < 0:
                        bltemp[i] = 0
                    if bltemp[i] > dims[i]:
                        bltemp[i] = dims[i] - 1
                    brtemp[i] = int(round(brIJKtemp[i]))
                    if brtemp[i] < 0:
                        brtemp[i] = 0
                    if brtemp[i] > dims[i]:
                        brtemp[i] = dims[i] - 1
                self.painter.SetTopLeft(tltemp[0], tltemp[1], tltemp[2])
                self.painter.SetTopRight(trtemp[0], trtemp[1], trtemp[2])
                self.painter.SetBottomLeft(bltemp[0], bltemp[1], bltemp[2])
                self.painter.SetBottomRight(brtemp[0], brtemp[1], brtemp[2])

                self.painter.Paint()

        # paint the slice: same for circular and spherical brush modes
        self.painter.SetTopLeft(tl[0], tl[1], tl[2])
        self.painter.SetTopRight(tr[0], tr[1], tr[2])
        self.painter.SetBottomLeft(bl[0], bl[1], bl[2])
        self.painter.SetBottomRight(br[0], br[1], br[2])
        self.painter.SetBrushCenter(brushCenter[0], brushCenter[1],
                                    brushCenter[2])
        self.painter.SetBrushRadius(brushRadius)
        self.painter.Paint()
示例#18
0
    def applyImageMask(self, maskIJKToRAS, mask, bounds):
        """
    apply a pre-rasterized image to the current label layer
    - maskIJKToRAS tells the mapping from image pixels to RAS
    - mask is a vtkImageData
    - bounds are the xy extents of the mask (zlo and zhi ignored)
    """
        backgroundLogic = self.sliceLogic.GetBackgroundLayer()
        backgroundNode = backgroundLogic.GetVolumeNode()
        if not backgroundNode: return
        backgroundImage = backgroundNode.GetImageData()
        if not backgroundImage: return
        labelLogic = self.sliceLogic.GetLabelLayer()
        labelNode = labelLogic.GetVolumeNode()
        if not labelNode: return
        labelImage = labelNode.GetImageData()
        if not labelImage: return

        #
        # at this point, the mask vtkImageData contains a rasterized
        # version of the polygon and now needs to be added to the label
        # image
        #

        # store a backup copy of the label map for undo
        # (this happens in it's own thread, so it is cheap)
        if self.undoRedo:
            self.undoRedo.saveState()

        #
        # get the mask bounding box in ijk coordinates
        # - get the xy bounds
        # - transform to ijk
        # - clamp the bounds to the dimensions of the label image
        #

        xlo, xhi, ylo, yhi, zlo, zhi = bounds
        labelLogic = self.sliceLogic.GetLabelLayer()
        xyToIJK = labelLogic.GetXYToIJKTransform()
        tlIJK = xyToIJK.TransformDoublePoint((xlo, yhi, 0))
        trIJK = xyToIJK.TransformDoublePoint((xhi, yhi, 0))
        blIJK = xyToIJK.TransformDoublePoint((xlo, ylo, 0))
        brIJK = xyToIJK.TransformDoublePoint((xhi, ylo, 0))

        # do the clamping of the four corners
        dims = labelImage.GetDimensions()
        tl = [
            0,
        ] * 3
        tr = [
            0,
        ] * 3
        bl = [
            0,
        ] * 3
        br = [
            0,
        ] * 3
        corners = ((tlIJK, tl), (trIJK, tr), (blIJK, bl), (brIJK, br))
        for corner, clampedCorner in corners:
            for d in xrange(3):
                clamped = int(round(corner[d]))
                if clamped < 0: clamped = 0
                if clamped >= dims[d]: clamped = dims[d] - 1
                clampedCorner[d] = clamped

        #
        # get the ijk to ras matrices including transforms
        # (use the maskToRAS calculated above)
        #

        labelLogic = self.sliceLogic.GetLabelLayer()
        labelNode = labelLogic.GetVolumeNode()
        backgroundLogic = self.sliceLogic.GetLabelLayer()
        backgroundNode = backgroundLogic.GetVolumeNode()

        backgroundIJKToRAS = self.getIJKToRASMatrix(backgroundNode)
        labelIJKToRAS = self.getIJKToRASMatrix(labelNode)

        #
        # create an extract image for undo if it doesn't exist yet.
        #

        if not self.extractImage:
            self.extractImage = vtk.vtkImageData()

        parameterNode = EditUtil.getParameterNode()
        paintLabel = int(parameterNode.GetParameter("label"))
        paintOver = int(parameterNode.GetParameter("LabelEffect,paintOver"))
        paintThreshold = int(
            parameterNode.GetParameter("LabelEffect,paintThreshold"))
        paintThresholdMin = float(
            parameterNode.GetParameter("LabelEffect,paintThresholdMin"))
        paintThresholdMax = float(
            parameterNode.GetParameter("LabelEffect,paintThresholdMax"))

        #
        # set up the painter class and let 'r rip!
        #
        self.painter.SetBackgroundImage(backgroundImage)
        self.painter.SetBackgroundIJKToWorld(backgroundIJKToRAS)
        self.painter.SetWorkingImage(labelImage)
        self.painter.SetWorkingIJKToWorld(labelIJKToRAS)
        self.painter.SetMaskImage(mask)
        self.painter.SetExtractImage(self.extractImage)
        self.painter.SetReplaceImage(None)
        self.painter.SetMaskIJKToWorld(maskIJKToRAS)
        self.painter.SetTopLeft(tl)
        self.painter.SetTopRight(tr)
        self.painter.SetBottomLeft(bl)
        self.painter.SetBottomRight(br)

        self.painter.SetPaintLabel(paintLabel)
        self.painter.SetPaintOver(paintOver)
        self.painter.SetThresholdPaint(paintThreshold)
        self.painter.SetThresholdPaintRange(paintThresholdMin,
                                            paintThresholdMax)

        self.painter.Paint()

        EditUtil.markVolumeNodeAsModified(labelNode)
示例#19
0
    def __init__(self, parent=None, optionsFrame=None):
        VTKObservationMixin.__init__(self)
        self.effects = []
        self.effectButtons = {}
        self.effectCursors = {}
        self.effectActionGroup = qt.QActionGroup(parent)
        self.effectActionGroup.connect('triggered(QAction*)',
                                       self._onEffectActionTriggered)
        self.effectActionGroup.exclusive = True
        self.currentEffect = None
        self.undoRedo = UndoRedo()
        self.undoRedo.stateChangedCallback = self.updateUndoRedoButtons
        self.toggleShortcut = None

        # check for extensions - if none have been registered, just create the empty dictionary
        try:
            slicer.modules.editorExtensions
        except AttributeError:
            slicer.modules.editorExtensions = {}

        # register the builtin extensions
        self.editorBuiltins = {}
        self.editorBuiltins["PaintEffect"] = EditorLib.PaintEffect
        self.editorBuiltins["DrawEffect"] = EditorLib.DrawEffect
        self.editorBuiltins["ThresholdEffect"] = EditorLib.ThresholdEffect
        self.editorBuiltins["RectangleEffect"] = EditorLib.RectangleEffect
        self.editorBuiltins[
            "LevelTracingEffect"] = EditorLib.LevelTracingEffect
        self.editorBuiltins["MakeModelEffect"] = EditorLib.MakeModelEffect
        self.editorBuiltins["ErodeEffect"] = EditorLib.ErodeEffect
        self.editorBuiltins["DilateEffect"] = EditorLib.DilateEffect
        self.editorBuiltins["ChangeLabelEffect"] = EditorLib.ChangeLabelEffect
        self.editorBuiltins[
            "RemoveIslandsEffect"] = EditorLib.RemoveIslandsEffect
        self.editorBuiltins[
            "IdentifyIslandsEffect"] = EditorLib.IdentifyIslandsEffect
        self.editorBuiltins["SaveIslandEffect"] = EditorLib.SaveIslandEffect
        self.editorBuiltins[
            "ChangeIslandEffect"] = EditorLib.ChangeIslandEffect
        self.editorBuiltins["GrowCutEffect"] = EditorLib.GrowCutEffect
        self.editorBuiltins[
            "WatershedFromMarkerEffect"] = EditorLib.WatershedFromMarkerEffect
        self.editorBuiltins[
            "FastMarchingEffect"] = EditorLib.FastMarchingEffect
        self.editorBuiltins["WandEffect"] = EditorLib.WandEffect

        # frame that holds widgets specific for each effect
        if not optionsFrame:
            self.optionsFrame = qt.QFrame(self.parent)
            self.optionsFrame.objectName = 'OptionsFrame'
        else:
            self.optionsFrame = optionsFrame

        # state variables for selected effect in the box
        # - currentOption is an instance of an option GUI
        # - currentTools is a list of EffectTool instances
        self.currentOption = None
        self.currentTools = []

        # listen for changes in the Interaction Mode
        interactionNode = slicer.app.applicationLogic().GetInteractionNode()
        self.addObserver(interactionNode,
                         interactionNode.InteractionModeChangedEvent,
                         self.onInteractionModeChanged)

        # Listen for changed on the Parameter node
        self.addObserver(EditUtil.getParameterNode(),
                         vtk.vtkCommand.ModifiedEvent,
                         self._onParameterNodeModified)

        if not parent:
            self.parent = qt.QFrame()
            self.parent.setLayout(qt.QVBoxLayout())
            self.create()
            self.parent.show()
        else:
            self.parent = parent
            self.create()
示例#20
0
  def __init__(self, parent=None, optionsFrame=None):
    VTKObservationMixin.__init__(self)
    self.effects = []
    self.effectButtons = {}
    self.effectCursors = {}
    self.effectActionGroup = qt.QActionGroup(parent)
    self.effectActionGroup.connect('triggered(QAction*)', self._onEffectActionTriggered)
    self.effectActionGroup.exclusive = True
    self.currentEffect = None
    self.undoRedo = UndoRedo()
    self.undoRedo.stateChangedCallback = self.updateUndoRedoButtons
    self.toggleShortcut = None

    # check for extensions - if none have been registered, just create the empty dictionary
    try:
      slicer.modules.editorExtensions
    except AttributeError:
      slicer.modules.editorExtensions = {}

    # register the builtin extensions
    self.editorBuiltins = {}
    self.editorBuiltins["PaintEffect"] = EditorLib.PaintEffect
    self.editorBuiltins["DrawEffect"] = EditorLib.DrawEffect
    self.editorBuiltins["ThresholdEffect"] = EditorLib.ThresholdEffect
    self.editorBuiltins["RectangleEffect"] = EditorLib.RectangleEffect
    self.editorBuiltins["LevelTracingEffect"] = EditorLib.LevelTracingEffect
    self.editorBuiltins["MakeModelEffect"] = EditorLib.MakeModelEffect
    self.editorBuiltins["ErodeEffect"] = EditorLib.ErodeEffect
    self.editorBuiltins["DilateEffect"] = EditorLib.DilateEffect
    self.editorBuiltins["ChangeLabelEffect"] = EditorLib.ChangeLabelEffect
    self.editorBuiltins["RemoveIslandsEffect"] = EditorLib.RemoveIslandsEffect
    self.editorBuiltins["IdentifyIslandsEffect"] = EditorLib.IdentifyIslandsEffect
    self.editorBuiltins["SaveIslandEffect"] = EditorLib.SaveIslandEffect
    self.editorBuiltins["ChangeIslandEffect"] = EditorLib.ChangeIslandEffect
    self.editorBuiltins["GrowCutEffect"] = EditorLib.GrowCutEffect
    self.editorBuiltins["WatershedFromMarkerEffect"] = EditorLib.WatershedFromMarkerEffect
    self.editorBuiltins["FastMarchingEffect"] = EditorLib.FastMarchingEffect
    self.editorBuiltins["WandEffect"] = EditorLib.WandEffect

    # frame that holds widgets specific for each effect
    if not optionsFrame:
      self.optionsFrame = qt.QFrame(self.parent)
      self.optionsFrame.objectName = 'OptionsFrame'
    else:
      self.optionsFrame = optionsFrame

    # state variables for selected effect in the box
    # - currentOption is an instance of an option GUI
    # - currentTools is a list of EffectTool instances
    self.currentOption = None
    self.currentTools = []

    # listen for changes in the Interaction Mode
    interactionNode = slicer.app.applicationLogic().GetInteractionNode()
    self.addObserver(interactionNode, interactionNode.InteractionModeChangedEvent, self.onInteractionModeChanged)

    # Listen for changed on the Parameter node
    self.addObserver(EditUtil.getParameterNode(), vtk.vtkCommand.ModifiedEvent, self._onParameterNodeModified)

    if not parent:
      self.parent = qt.QFrame()
      self.parent.setLayout( qt.QVBoxLayout() )
      self.create()
      self.parent.show()
    else:
      self.parent = parent
      self.create()
示例#21
0
  def paintBrush(self, x, y):
    """
    paint with a brush that is circular (or optionally spherical) in XY space
     (could be streched or rotate when transformed to IJK)
     - make sure to hit every pixel in IJK space
     - apply the threshold if selected
    """

    sliceLogic = self.sliceWidget.sliceLogic()
    sliceNode = sliceLogic.GetSliceNode()
    labelLogic = sliceLogic.GetLabelLayer()
    labelNode = labelLogic.GetVolumeNode()
    labelImage = labelNode.GetImageData()
    backgroundLogic = sliceLogic.GetBackgroundLayer()
    backgroundNode = backgroundLogic.GetVolumeNode()
    backgroundImage = backgroundNode.GetImageData()

    if not labelNode:
      # if there's no label, we can't paint
      return

    #
    # get the brush bounding box in ijk coordinates
    # - get the xy bounds
    # - transform to ijk
    # - clamp the bounds to the dimensions of the label image
    #
    bounds = self.brush.GetPoints().GetBounds()
    left = x + bounds[0]
    right = x + bounds[1]
    bottom = y + bounds[2]
    top = y + bounds[3]

    xyToIJK = labelLogic.GetXYToIJKTransform()
    tlIJK = xyToIJK.TransformDoublePoint( (left, top, 0) )
    trIJK = xyToIJK.TransformDoublePoint( (right, top, 0) )
    blIJK = xyToIJK.TransformDoublePoint( (left, bottom, 0) )
    brIJK = xyToIJK.TransformDoublePoint( (right, bottom, 0) )

    dims = labelImage.GetDimensions()

    # clamp the top, bottom, left, right to the
    # valid dimensions of the label image
    tl = [0,0,0]
    tr = [0,0,0]
    bl = [0,0,0]
    br = [0,0,0]
    for i in xrange(3):
      tl[i] = int(round(tlIJK[i]))
      if tl[i] < 0:
        tl[i] = 0
      if tl[i] >= dims[i]:
        tl[i] = dims[i] - 1
      tr[i] = int(round(trIJK[i]))
      if tr[i] < 0:
        tr[i] = 0
      if tr[i] > dims[i]:
        tr[i] = dims[i] - 1
      bl[i] = int(round(blIJK[i]))
      if bl[i] < 0:
        bl[i] = 0
      if bl[i] > dims[i]:
        bl[i] = dims[i] - 1
      br[i] = int(round(brIJK[i]))
      if br[i] < 0:
        br[i] = 0
      if br[i] > dims[i]:
        br[i] = dims[i] - 1

    # If the region is smaller than a pixel then paint it using paintPixel mode,
    # to make sure at least one pixel is filled on each click
    maxRowDelta = 0
    maxColumnDelta = 0
    for i in xrange(3):
      d = abs(tr[i] - tl[i])
      if d > maxColumnDelta:
        maxColumnDelta = d
      d = abs(br[i] - bl[i])
      if d > maxColumnDelta:
        maxColumnDelta = d
      d = abs(bl[i] - tl[i])
      if d > maxRowDelta:
        maxRowDelta = d
      d = abs(br[i] - tr[i])
      if d > maxRowDelta:
        maxRowDelta = d
    if maxRowDelta<=1 or maxColumnDelta<=1 :
      self.paintPixel(x,y)
      return

    #
    # get the layers and nodes
    # and ijk to ras matrices including transforms
    #
    labelLogic = self.sliceLogic.GetLabelLayer()
    labelNode = labelLogic.GetVolumeNode()
    backgroundLogic = self.sliceLogic.GetLabelLayer()
    backgroundNode = backgroundLogic.GetVolumeNode()
    backgroundIJKToRAS = self.logic.getIJKToRASMatrix(backgroundNode)
    labelIJKToRAS = self.logic.getIJKToRASMatrix(labelNode)


    xyToRAS = sliceNode.GetXYToRAS()
    brushCenter = xyToRAS.MultiplyPoint( (x, y, 0, 1) )[:3]


    brushRadius = self.radius
    bSphere = self.sphere

    parameterNode = EditUtil.getParameterNode()
    paintLabel = int(parameterNode.GetParameter("label"))
    paintOver = int(parameterNode.GetParameter("LabelEffect,paintOver"))
    paintThreshold = int(parameterNode.GetParameter("LabelEffect,paintThreshold"))
    paintThresholdMin = float(
        parameterNode.GetParameter("LabelEffect,paintThresholdMin"))
    paintThresholdMax = float(
        parameterNode.GetParameter("LabelEffect,paintThresholdMax"))

    #
    # set up the painter class and let 'r rip!
    #
    if not hasattr(self,"painter"):
      self.painter = slicer.vtkImageSlicePaint()

    self.painter.SetBackgroundImage(backgroundImage)
    self.painter.SetBackgroundIJKToWorld(backgroundIJKToRAS)
    self.painter.SetWorkingImage(labelImage)
    self.painter.SetWorkingIJKToWorld(labelIJKToRAS)
    self.painter.SetTopLeft( tl[0], tl[1], tl[2] )
    self.painter.SetTopRight( tr[0], tr[1], tr[2] )
    self.painter.SetBottomLeft( bl[0], bl[1], bl[2] )
    self.painter.SetBottomRight( br[0], br[1], br[2] )
    self.painter.SetBrushCenter( brushCenter[0], brushCenter[1], brushCenter[2] )
    self.painter.SetBrushRadius( brushRadius )
    self.painter.SetPaintLabel(paintLabel)
    self.painter.SetPaintOver(paintOver)
    self.painter.SetThresholdPaint(paintThreshold)
    self.painter.SetThresholdPaintRange(paintThresholdMin, paintThresholdMax)

    if bSphere:  # fill volume of a sphere rather than a circle on the currently displayed image slice
        # Algorithm:
        ###########################
        # Assume brushRadius is in mm
        # Estimate zVoxelSize
        # Compute number of slices spanned by sphere, that are still within the volume
        # For each spanned slice
        #    reposition the brushCenter using xy(z)ToRAS transform: i.e. canvas to patient world coordinates
        #    resize the radius: brushRadiusOffset=sqrt(brushRadius*brushRadius - zOffset_mm*zOffset_mm)
        #    invoke Paint()
        # Finally paint on the center slice, leaving the gui on the center slice being most visibly edited
        #------------------
        # Estimate zVoxelSize_mm
        brushCenter1 = xyToRAS.MultiplyPoint( (x, y, 0, 1) )[:3]
        brushCenter2 = xyToRAS.MultiplyPoint( (x, y, 100, 1) )[:3]
        dx1=brushCenter1[0]-brushCenter2[0]
        dx2=brushCenter1[1]-brushCenter2[1]
        dx3=brushCenter1[2]-brushCenter2[2]
        distanceSpannedBy100Slices = sqrt(dx1*dx1+dx2*dx2+dx3*dx3)  # compute L2 norm
        if distanceSpannedBy100Slices==0:
            zVoxelSize_mm=1
        else:
            zVoxelSize_mm = distanceSpannedBy100Slices/100
        # --
        # Compute number of slices spanned by sphere
        nNumSlicesInEachDirection=brushRadius / zVoxelSize_mm;
        nNumSlicesInEachDirection=nNumSlicesInEachDirection-1
        sliceOffsetArray=numpy.concatenate((-1*numpy.arange(1,nNumSlicesInEachDirection+1,),  numpy.arange(1,nNumSlicesInEachDirection+1)))
        for iSliceOffset in sliceOffsetArray:
            # x,y uses slice (canvas) coordinate system and actually has a 3rd z component (index into the slice you're looking at)
            # hence xyToRAS is really performing xyzToRAS.   RAS is patient world coordinate system. Note the 1 is because the trasform uses homogeneous coordinates
            iBrushCenter = xyToRAS.MultiplyPoint( (x, y, iSliceOffset, 1) )[:3]
            self.painter.SetBrushCenter( iBrushCenter[0], iBrushCenter[1], iBrushCenter[2] )
            # [ ] Need to just continue (pass this loop iteration if the brush center is not within the volume
            zOffset_mm=zVoxelSize_mm*iSliceOffset;
            brushRadiusOffset=sqrt(brushRadius*brushRadius - zOffset_mm*zOffset_mm)
            self.painter.SetBrushRadius( brushRadiusOffset )

            # --
            tlIJKtemp = xyToIJK.TransformDoublePoint( (left, top, iSliceOffset) )
            trIJKtemp = xyToIJK.TransformDoublePoint( (right, top, iSliceOffset) )
            blIJKtemp = xyToIJK.TransformDoublePoint( (left, bottom, iSliceOffset) )
            brIJKtemp = xyToIJK.TransformDoublePoint( (right, bottom, iSliceOffset) )
            # clamp the top, bottom, left, right to the
            # valid dimensions of the label image
            tltemp = [0,0,0]
            trtemp = [0,0,0]
            bltemp = [0,0,0]
            brtemp = [0,0,0]
            for i in xrange(3):
              tltemp[i] = int(round(tlIJKtemp[i]))
              if tltemp[i] < 0:
                tltemp[i] = 0
              if tltemp[i] >= dims[i]:
                tltemp[i] = dims[i] - 1
              trtemp[i] = int(round(trIJKtemp[i]))
              if trtemp[i] < 0:
                trtemp[i] = 0
              if trtemp[i] > dims[i]:
                trtemp[i] = dims[i] - 1
              bltemp[i] = int(round(blIJKtemp[i]))
              if bltemp[i] < 0:
                bltemp[i] = 0
              if bltemp[i] > dims[i]:
                bltemp[i] = dims[i] - 1
              brtemp[i] = int(round(brIJKtemp[i]))
              if brtemp[i] < 0:
                brtemp[i] = 0
              if brtemp[i] > dims[i]:
                brtemp[i] = dims[i] - 1
            self.painter.SetTopLeft( tltemp[0], tltemp[1], tltemp[2] )
            self.painter.SetTopRight( trtemp[0], trtemp[1], trtemp[2] )
            self.painter.SetBottomLeft( bltemp[0], bltemp[1], bltemp[2] )
            self.painter.SetBottomRight( brtemp[0], brtemp[1], brtemp[2] )


            self.painter.Paint()


    # paint the slice: same for circular and spherical brush modes
    self.painter.SetTopLeft( tl[0], tl[1], tl[2] )
    self.painter.SetTopRight( tr[0], tr[1], tr[2] )
    self.painter.SetBottomLeft( bl[0], bl[1], bl[2] )
    self.painter.SetBottomRight( br[0], br[1], br[2] )
    self.painter.SetBrushCenter( brushCenter[0], brushCenter[1], brushCenter[2] )
    self.painter.SetBrushRadius( brushRadius )
    self.painter.Paint()
示例#22
0
  def applyImageMask(self, maskIJKToRAS, mask, bounds):
    """
    apply a pre-rasterized image to the current label layer
    - maskIJKToRAS tells the mapping from image pixels to RAS
    - mask is a vtkImageData
    - bounds are the xy extents of the mask (zlo and zhi ignored)
    """
    backgroundLogic = self.sliceLogic.GetBackgroundLayer()
    backgroundNode = backgroundLogic.GetVolumeNode()
    if not backgroundNode: return
    backgroundImage = backgroundNode.GetImageData()
    if not backgroundImage: return
    labelLogic = self.sliceLogic.GetLabelLayer()
    labelNode = labelLogic.GetVolumeNode()
    if not labelNode: return
    labelImage = labelNode.GetImageData()
    if not labelImage: return

    #
    # at this point, the mask vtkImageData contains a rasterized
    # version of the polygon and now needs to be added to the label
    # image
    #

    # store a backup copy of the label map for undo
    # (this happens in it's own thread, so it is cheap)
    if self.undoRedo:
      self.undoRedo.saveState()

    #
    # get the mask bounding box in ijk coordinates
    # - get the xy bounds
    # - transform to ijk
    # - clamp the bounds to the dimensions of the label image
    #

    xlo, xhi, ylo, yhi, zlo, zhi = bounds
    labelLogic = self.sliceLogic.GetLabelLayer()
    xyToIJK = labelLogic.GetXYToIJKTransform()
    tlIJK = xyToIJK.TransformDoublePoint( (xlo, yhi, 0) )
    trIJK = xyToIJK.TransformDoublePoint( (xhi, yhi, 0) )
    blIJK = xyToIJK.TransformDoublePoint( (xlo, ylo, 0) )
    brIJK = xyToIJK.TransformDoublePoint( (xhi, ylo, 0) )

    # do the clamping of the four corners
    dims = labelImage.GetDimensions()
    tl = [0,] * 3
    tr = [0,] * 3
    bl = [0,] * 3
    br = [0,] * 3
    corners = ((tlIJK, tl),(trIJK, tr),(blIJK, bl),(brIJK, br))
    for corner,clampedCorner in corners:
      for d in xrange(3):
        clamped = int(round(corner[d]))
        if clamped < 0: clamped = 0
        if clamped >= dims[d]: clamped = dims[d]-1
        clampedCorner[d] = clamped

    #
    # get the ijk to ras matrices including transforms
    # (use the maskToRAS calculated above)
    #

    labelLogic = self.sliceLogic.GetLabelLayer()
    labelNode = labelLogic.GetVolumeNode()
    backgroundLogic = self.sliceLogic.GetLabelLayer()
    backgroundNode = backgroundLogic.GetVolumeNode()

    backgroundIJKToRAS = self.getIJKToRASMatrix(backgroundNode)
    labelIJKToRAS = self.getIJKToRASMatrix(labelNode)

    #
    # create an exract image for undo if it doesn't exist yet.
    #

    if not self.extractImage:
      self.extractImage = vtk.vtkImageData()

    parameterNode = EditUtil.getParameterNode()
    paintLabel = int(parameterNode.GetParameter("label"))
    paintOver = int(parameterNode.GetParameter("LabelEffect,paintOver"))
    paintThreshold = int(parameterNode.GetParameter("LabelEffect,paintThreshold"))
    paintThresholdMin = float(
        parameterNode.GetParameter("LabelEffect,paintThresholdMin"))
    paintThresholdMax = float(
        parameterNode.GetParameter("LabelEffect,paintThresholdMax"))

    #
    # set up the painter class and let 'r rip!
    #
    self.painter.SetBackgroundImage( backgroundImage )
    self.painter.SetBackgroundIJKToWorld( backgroundIJKToRAS )
    self.painter.SetWorkingImage( labelImage )
    self.painter.SetWorkingIJKToWorld( labelIJKToRAS )
    self.painter.SetMaskImage( mask )
    self.painter.SetExtractImage( self.extractImage )
    self.painter.SetReplaceImage(None)
    self.painter.SetMaskIJKToWorld( maskIJKToRAS )
    self.painter.SetTopLeft(tl)
    self.painter.SetTopRight(tr)
    self.painter.SetBottomLeft(bl)
    self.painter.SetBottomRight(br)

    self.painter.SetPaintLabel( paintLabel )
    self.painter.SetPaintOver( paintOver )
    self.painter.SetThresholdPaint( paintThreshold )
    self.painter.SetThresholdPaintRange( paintThresholdMin, paintThresholdMax )

    self.painter.Paint()

    EditUtil.markVolumeNodeAsModified(labelNode)