Exemple #1
0
 def __init__(self, sliceLogic):
     super().__init__(sliceLogic)
     self.paintThreshold = 0
     self.paintThresholdMin = 1
     self.paintThresholdMax = 1
     self.paintOver = 1
     self.extractImage = None
     self.painter = slicer.vtkImageSlicePaint()
Exemple #2
0
 def __init__(self,sliceLogic):
   super(LabelEffectLogic,self).__init__(sliceLogic)
   self.paintThreshold = 0
   self.paintThresholdMin = 1
   self.paintThresholdMax = 1
   self.paintOver = 1
   self.extractImage = None
   self.painter = slicer.vtkImageSlicePaint()
Exemple #3
0
  def __init__(self,sliceLogic):
    self.sliceLogic = sliceLogic
    self.editUtil = EditUtil.EditUtil()
    # optionally set by users of the class
    self.undoRedo = None
    self.scope = 'All'

    #
    # instance variables used internally
    # - buffer for result of scoped editing
    self.scopedImageBuffer = vtk.vtkImageData()
    # - slice paint is used to extract/replace scoped regions
    self.scopedSlicePaint = slicer.vtkImageSlicePaint()
Exemple #4
0
    def __init__(self, sliceLogic):
        self.sliceLogic = sliceLogic
        self.editUtil = EditUtil()  # Kept for backward compatibility
        # optionally set by users of the class
        self.undoRedo = None
        self.scope = 'All'

        #
        # instance variables used internally
        # - buffer for result of scoped editing
        self.scopedImageBuffer = vtk.vtkImageData()
        # - slice paint is used to extract/replace scoped regions
        self.scopedSlicePaint = slicer.vtkImageSlicePaint()
Exemple #5
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()
Exemple #6
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 range(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 range(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 = int(distanceSpannedBy100Slices / 100)
        # --
        # Compute number of slices spanned by sphere
        nNumSlicesInEachDirection=int(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 range(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()