예제 #1
0
    def onApply(self):
        # This can be a long operation - indicate it to the user
        qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor)

        self.scriptedEffect.saveStateForUndo()

        # Get parameters
        fullyConnected = self.scriptedEffect.integerParameter("FullyConnected")
        minimumSize = self.scriptedEffect.integerParameter("MinimumSize")

        # Get modifier labelmap
        selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap()

        castIn = vtk.vtkImageCast()
        castIn.SetInputData(selectedSegmentLabelmap)
        castIn.SetOutputScalarTypeToUnsignedLong()

        # Identify the islands in the inverted volume and
        # find the pixel that corresponds to the background
        islandMath = vtkITK.vtkITKIslandMath()
        islandMath.SetInputConnection(castIn.GetOutputPort())
        islandMath.SetFullyConnected(fullyConnected)
        islandMath.SetMinimumSize(minimumSize)

        # Note that island operation happens in unsigned long space
        # but the segment editor works in unsigned char
        castOut = vtk.vtkImageCast()
        castOut.SetInputConnection(islandMath.GetOutputPort())
        castOut.SetOutputScalarTypeToUnsignedChar()
        castOut.Update()

        islandCount = islandMath.GetNumberOfIslands()
        islandOrigCount = islandMath.GetOriginalNumberOfIslands()
        ignoredIslands = islandOrigCount - islandCount
        logging.info("%d islands created (%d ignored)" %
                     (islandCount, ignoredIslands))

        # Create oriented image data from output
        import vtkSegmentationCorePython as vtkSegmentationCore
        multiLabelImage = vtkSegmentationCore.vtkOrientedImageData()
        multiLabelImage.DeepCopy(castOut.GetOutput())
        selectedSegmentLabelmapImageToWorldMatrix = vtk.vtkMatrix4x4()
        selectedSegmentLabelmap.GetImageToWorldMatrix(
            selectedSegmentLabelmapImageToWorldMatrix)
        multiLabelImage.SetGeometryFromImageToWorldMatrix(
            selectedSegmentLabelmapImageToWorldMatrix)

        # Import multi-label labelmap to segmentation
        segmentationNode = self.scriptedEffect.parameterSetNode(
        ).GetSegmentationNode()
        selectedSegmentID = self.scriptedEffect.parameterSetNode(
        ).GetSelectedSegmentID()
        selectedSegmentName = segmentationNode.GetSegmentation().GetSegment(
            selectedSegmentID).GetName()
        slicer.vtkSlicerSegmentationsModuleLogic.ImportLabelmapToSegmentationNode( \
          multiLabelImage, segmentationNode, selectedSegmentName )

        segmentationNode.GetSegmentation().RemoveSegment(selectedSegmentID)

        qt.QApplication.restoreOverrideCursor()
예제 #2
0
    def findLargest2DRegion(segmentationNode):
        qrLogic = CustomSegmentEditorLogic
        segmentationsLogic = slicer.modules.segmentations.logic()

        largestLM = None
        largestSize = 0
        for segment in qrLogic.getAllSegments(segmentationNode):
            imageData = vtkSegmentationCore.vtkOrientedImageData()
            segmentID = segmentationNode.GetSegmentation(
            ).GetSegmentIdBySegment(segment)
            segmentationsLogic.GetSegmentBinaryLabelmapRepresentation(
                segmentationNode, segmentID, imageData)
            extent = imageData.GetExtent()

            if extent[1] != -1 and extent[3] != -1 and extent[5] != -1:
                tempLabel = slicer.vtkMRMLLabelMapVolumeNode()
                tempLabel.SetName(segment.GetName() + "CentroidHelper")
                segmentationsLogic.CreateLabelmapVolumeFromOrientedImageData(
                    imageData, tempLabel)

                dims = tempLabel.GetImageData().GetDimensions()
                size = dims[0] * dims[1]
                if size > largestSize:
                    largestSize = size
                    largestLM = tempLabel

        return largestLM
예제 #3
0
  def onApply(self):

    import vtkSegmentationCorePython as vtkSegmentationCore

    # Get modifier labelmap and parameters

    operation = self.scriptedEffect.parameter("Operation")

    if operation in self.operationsRequireModifierSegment:

      # Get modifier segment
      segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()
      segmentation = segmentationNode.GetSegmentation()
      modifierSegmentID = self.modifierSegmentID()
      if not modifierSegmentID:
        logging.error("Operation {0} requires a selected modifier segment".format(operation))
        return
      modifierSegment = segmentation.GetSegment(modifierSegmentID)
      modifierSegmentLabelmap = modifierSegment.GetRepresentation(vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationBinaryLabelmapRepresentationName())

      if operation == LOGICAL_COPY:
        self.scriptedEffect.modifySelectedSegmentByLabelmap(modifierSegmentLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet)
      elif operation == LOGICAL_UNION:
        self.scriptedEffect.modifySelectedSegmentByLabelmap(modifierSegmentLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeAdd)
      elif operation == LOGICAL_SUBTRACT:
        self.scriptedEffect.modifySelectedSegmentByLabelmap(modifierSegmentLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeRemove)
      elif operation == LOGICAL_INTERSECT:
        selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap()
        intersectionLabelmap = vtkSegmentationCore.vtkOrientedImageData()
        vtkSegmentationCore.vtkOrientedImageDataResample.MergeImage(selectedSegmentLabelmap, modifierSegmentLabelmap, intersectionLabelmap, vtkSegmentationCore.vtkOrientedImageDataResample.OPERATION_MINIMUM, selectedSegmentLabelmap.GetExtent())
        selectedSegmentLabelmapExtent = selectedSegmentLabelmap.GetExtent()
        modifierSegmentLabelmapExtent = modifierSegmentLabelmap.GetExtent()
        commonExtent = [max(selectedSegmentLabelmapExtent[0], modifierSegmentLabelmapExtent[0]),
          min(selectedSegmentLabelmapExtent[1], modifierSegmentLabelmapExtent[1]),
          max(selectedSegmentLabelmapExtent[2], modifierSegmentLabelmapExtent[2]),
          min(selectedSegmentLabelmapExtent[3], modifierSegmentLabelmapExtent[3]),
          max(selectedSegmentLabelmapExtent[4], modifierSegmentLabelmapExtent[4]),
          min(selectedSegmentLabelmapExtent[5], modifierSegmentLabelmapExtent[5])]
        self.scriptedEffect.modifySelectedSegmentByLabelmap(intersectionLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet, commonExtent)

    elif operation == LOGICAL_INVERT:
      selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap()
      inverter = vtk.vtkImageThreshold()
      inverter.SetInputData(selectedSegmentLabelmap)
      inverter.SetInValue(1)
      inverter.SetOutValue(0)
      inverter.ReplaceInOn()
      inverter.ThresholdByLower(0)
      inverter.SetOutputScalarType(vtk.VTK_UNSIGNED_CHAR)
      inverter.Update()
      selectedSegmentLabelmap.DeepCopy(inverter.GetOutput())
      self.scriptedEffect.modifySelectedSegmentByLabelmap(selectedSegmentLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet)

    elif operation == LOGICAL_CLEAR or operation == LOGICAL_FILL:
      selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap()
      vtkSegmentationCore.vtkOrientedImageDataResample.FillImage(selectedSegmentLabelmap, 1 if operation == LOGICAL_FILL else 0, selectedSegmentLabelmap.GetExtent())
      self.scriptedEffect.modifySelectedSegmentByLabelmap(selectedSegmentLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet)

    else:
      logging.error("Uknown operation: {0}".format(operation))
    def onApply(self):
        # TODO:
        # self.logic.undoRedo = self.undoRedo

        # Get parameters
        fullyConnected = self.scriptedEffect.integerParameter("FullyConnected")
        minimumSize = self.scriptedEffect.integerParameter("MinimumSize")

        # Get modifier labelmap
        selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap()

        castIn = vtk.vtkImageCast()
        castIn.SetInputData(selectedSegmentLabelmap)
        castIn.SetOutputScalarTypeToUnsignedLong()

        # Identify the islands in the inverted volume and
        # find the pixel that corresponds to the background
        islandMath = vtkITK.vtkITKIslandMath()
        islandMath.SetInputConnection(castIn.GetOutputPort())
        islandMath.SetFullyConnected(fullyConnected)
        islandMath.SetMinimumSize(minimumSize)

        # Note that island operation happens in unsigned long space
        # but the segment editor works in unsigned char
        castOut = vtk.vtkImageCast()
        castOut.SetInputConnection(islandMath.GetOutputPort())
        castOut.SetOutputScalarTypeToUnsignedChar()
        castOut.Update()

        islandCount = islandMath.GetNumberOfIslands()
        islandOrigCount = islandMath.GetOriginalNumberOfIslands()
        ignoredIslands = islandOrigCount - islandCount
        logging.info("%d islands created (%d ignored)" % (islandCount, ignoredIslands))

        # Create oriented image data from output
        import vtkSegmentationCorePython as vtkSegmentationCore

        multiLabelImage = vtkSegmentationCore.vtkOrientedImageData()
        multiLabelImage.DeepCopy(castOut.GetOutput())
        selectedSegmentLabelmapImageToWorldMatrix = vtk.vtkMatrix4x4()
        selectedSegmentLabelmap.GetImageToWorldMatrix(selectedSegmentLabelmapImageToWorldMatrix)
        multiLabelImage.SetGeometryFromImageToWorldMatrix(selectedSegmentLabelmapImageToWorldMatrix)

        # Import multi-label labelmap to segmentation
        segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()
        selectedSegmentID = self.scriptedEffect.parameterSetNode().GetSelectedSegmentID()
        selectedSegmentName = segmentationNode.GetSegmentation().GetSegment(selectedSegmentID).GetName()
        slicer.vtkSlicerSegmentationsModuleLogic.ImportLabelmapToSegmentationNode(
            multiLabelImage, segmentationNode, selectedSegmentName
        )

        # Set labelmap visibility to outline for the new segments
        displayNode = segmentationNode.GetDisplayNode()
        # for index in xrange(1,islandCount+1):
        #  segmentID = selectedSegmentName + "_" + str(index)
        #  displayNode.SetSegmentVisibility2DFill(segmentID, False)
        #  displayNode.SetSegmentVisibility2DOutline(segmentID, True)

        displayNode.SetSegmentVisibility(selectedSegmentID, False)
예제 #5
0
  def onApply(self):
    #TODO:
    #self.logic.undoRedo = self.undoRedo

    # Get parameters
    fullyConnected = self.scriptedEffect.integerParameter("FullyConnected")
    minimumSize = self.scriptedEffect.integerParameter("MinimumSize")

    # Get modifier labelmap
    selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap()

    castIn = vtk.vtkImageCast()
    castIn.SetInputData(selectedSegmentLabelmap)
    castIn.SetOutputScalarTypeToUnsignedLong()

    # Identify the islands in the inverted volume and
    # find the pixel that corresponds to the background
    islandMath = vtkITK.vtkITKIslandMath()
    islandMath.SetInputConnection(castIn.GetOutputPort())
    islandMath.SetFullyConnected(fullyConnected)
    islandMath.SetMinimumSize(minimumSize)

    # Note that island operation happens in unsigned long space
    # but the segment editor works in unsigned char
    castOut = vtk.vtkImageCast()
    castOut.SetInputConnection(islandMath.GetOutputPort())
    castOut.SetOutputScalarTypeToUnsignedChar()
    castOut.Update()

    islandCount = islandMath.GetNumberOfIslands()
    islandOrigCount = islandMath.GetOriginalNumberOfIslands()
    ignoredIslands = islandOrigCount - islandCount
    logging.info( "%d islands created (%d ignored)" % (islandCount, ignoredIslands) )

    # Create oriented image data from output
    import vtkSegmentationCorePython as vtkSegmentationCore
    multiLabelImage = vtkSegmentationCore.vtkOrientedImageData()
    multiLabelImage.DeepCopy(castOut.GetOutput())
    selectedSegmentLabelmapImageToWorldMatrix = vtk.vtkMatrix4x4()
    selectedSegmentLabelmap.GetImageToWorldMatrix(selectedSegmentLabelmapImageToWorldMatrix)
    multiLabelImage.SetGeometryFromImageToWorldMatrix(selectedSegmentLabelmapImageToWorldMatrix)

    # Import multi-label labelmap to segmentation
    segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()
    selectedSegmentID = self.scriptedEffect.parameterSetNode().GetSelectedSegmentID()
    selectedSegmentName = segmentationNode.GetSegmentation().GetSegment(selectedSegmentID).GetName()
    slicer.vtkSlicerSegmentationsModuleLogic.ImportLabelmapToSegmentationNode( \
      multiLabelImage, segmentationNode, selectedSegmentName )

    # Set labelmap visibility to outline for the new segments
    displayNode = segmentationNode.GetDisplayNode()
    #for index in xrange(1,islandCount+1):
    #  segmentID = selectedSegmentName + "_" + str(index)
    #  displayNode.SetSegmentVisibility2DFill(segmentID, False)
    #  displayNode.SetSegmentVisibility2DOutline(segmentID, True)

    displayNode.SetSegmentVisibility(selectedSegmentID, False)
  def TestSection_2_MergeLabelmapWithDifferentGeometries(self):
    # Merge labelmap when segments containing labelmaps with different geometries (both same directions, different directions)
    logging.info('Test section 2: Merge labelmap with different geometries')

    self.assertIsNotNone(self.sphereSegment)
    self.sphereSegment.RemoveRepresentation(self.binaryLabelmapReprName)
    self.assertIsNone(self.sphereSegment.GetRepresentation(self.binaryLabelmapReprName))

    # Create new segmentation with sphere segment
    self.secondSegmentationNode = slicer.vtkMRMLSegmentationNode()
    self.secondSegmentationNode.SetName('Second')
    self.secondSegmentationNode.GetSegmentation().SetMasterRepresentationName(self.binaryLabelmapReprName)
    slicer.mrmlScene.AddNode(self.secondSegmentationNode)

    self.secondSegmentationNode.GetSegmentation().AddSegment(self.sphereSegment)

    # Check automatically converted labelmap. It is supposed to have the default geometry
    # (which is different than the one in the input segmentation)
    sphereLabelmap = self.sphereSegment.GetRepresentation(self.binaryLabelmapReprName)
    self.assertIsNotNone(sphereLabelmap)
    sphereLabelmapSpacing = sphereLabelmap.GetSpacing()
    self.assertTrue(sphereLabelmapSpacing[0] == 1.0 and sphereLabelmapSpacing[1] == 1.0 and sphereLabelmapSpacing[2] == 1.0)

    # Create binary labelmap in segmentation that will create the merged labelmap from
    # different geometries so that labelmap is not removed from sphere segment when adding
    self.inputSegmentationNode.GetSegmentation().CreateRepresentation(self.binaryLabelmapReprName)

    # Copy segment to input segmentation
    self.inputSegmentationNode.GetSegmentation().CopySegmentFromSegmentation(self.secondSegmentationNode.GetSegmentation(), self.sphereSegmentName)
    self.assertEqual(self.inputSegmentationNode.GetSegmentation().GetNumberOfSegments(), 3)

    # Check merged labelmap
    # Reference geometry has the tiny patient spacing, and it is oversampled to have smimilar
    # voxel size as the sphere labelmap with the uniform 1mm spacing
    mergedLabelmap = vtkSegmentationCore.vtkOrientedImageData()
    self.inputSegmentationNode.GenerateMergedLabelmapForAllSegments(mergedLabelmap, 0)
    mergedLabelmapSpacing = mergedLabelmap.GetSpacing()
    self.assertAlmostEqual(mergedLabelmapSpacing[0], 1.2894736842, 8)
    self.assertAlmostEqual(mergedLabelmapSpacing[1], 1.2894736842, 8)
    self.assertAlmostEqual(mergedLabelmapSpacing[2], 0.6052631578, 8)

    imageStat = vtk.vtkImageAccumulate()
    imageStat.SetInputData(mergedLabelmap)
    imageStat.SetComponentExtent(0,5,0,0,0,0)
    imageStat.SetComponentOrigin(0,0,0)
    imageStat.SetComponentSpacing(1,1,1)
    imageStat.Update()
    self.assertEqual(imageStat.GetVoxelCount(), 54872000)
    imageStatResult = imageStat.GetOutput()
    for i in range(5):
      logging.info("Volume {0}: {1}".format(i, imageStatResult.GetScalarComponentAsDouble(i,0,0,0)))
    self.assertEqual(imageStatResult.GetScalarComponentAsDouble(0,0,0,0), 43573723)
    self.assertEqual(imageStatResult.GetScalarComponentAsDouble(1,0,0,0), 10601312)
    self.assertEqual(imageStatResult.GetScalarComponentAsDouble(2,0,0,0), 251476)
    self.assertEqual(imageStatResult.GetScalarComponentAsDouble(3,0,0,0), 445489)
    self.assertEqual(imageStatResult.GetScalarComponentAsDouble(4,0,0,0), 0)  # Built from color table and color four is removed in previous test section
  def onApply(self):
    # This can be a long operation - indicate it to the user
    qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor)

    self.scriptedEffect.saveStateForUndo()

    # Get parameters
    fullyConnected = self.scriptedEffect.integerParameter("FullyConnected")
    minimumSize = self.scriptedEffect.integerParameter("MinimumSize")

    # Get modifier labelmap
    selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap()

    castIn = vtk.vtkImageCast()
    castIn.SetInputData(selectedSegmentLabelmap)
    castIn.SetOutputScalarTypeToUnsignedLong()

    # Identify the islands in the inverted volume and
    # find the pixel that corresponds to the background
    islandMath = vtkITK.vtkITKIslandMath()
    islandMath.SetInputConnection(castIn.GetOutputPort())
    islandMath.SetFullyConnected(fullyConnected)
    islandMath.SetMinimumSize(minimumSize)

    # Note that island operation happens in unsigned long space
    # but the segment editor works in unsigned char
    castOut = vtk.vtkImageCast()
    castOut.SetInputConnection(islandMath.GetOutputPort())
    castOut.SetOutputScalarTypeToUnsignedChar()
    castOut.Update()

    islandCount = islandMath.GetNumberOfIslands()
    islandOrigCount = islandMath.GetOriginalNumberOfIslands()
    ignoredIslands = islandOrigCount - islandCount
    logging.info( "%d islands created (%d ignored)" % (islandCount, ignoredIslands) )

    # Create oriented image data from output
    import vtkSegmentationCorePython as vtkSegmentationCore
    multiLabelImage = vtkSegmentationCore.vtkOrientedImageData()
    multiLabelImage.DeepCopy(castOut.GetOutput())
    selectedSegmentLabelmapImageToWorldMatrix = vtk.vtkMatrix4x4()
    selectedSegmentLabelmap.GetImageToWorldMatrix(selectedSegmentLabelmapImageToWorldMatrix)
    multiLabelImage.SetGeometryFromImageToWorldMatrix(selectedSegmentLabelmapImageToWorldMatrix)

    # Import multi-label labelmap to segmentation
    segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()
    selectedSegmentID = self.scriptedEffect.parameterSetNode().GetSelectedSegmentID()
    selectedSegmentName = segmentationNode.GetSegmentation().GetSegment(selectedSegmentID).GetName()
    slicer.vtkSlicerSegmentationsModuleLogic.ImportLabelmapToSegmentationNode( \
      multiLabelImage, segmentationNode, selectedSegmentName )

    segmentationNode.GetSegmentation().RemoveSegment(selectedSegmentID)

    qt.QApplication.restoreOverrideCursor()
예제 #8
0
  def TestSection_1_AddRemoveSegment(self):
    # Add/remove segment from segmentation (check display properties, color table, etc.)
    logging.info('Test section 1: Add/remove segment')

    # Get baseline values
    displayNode = self.inputSegmentationNode.GetDisplayNode()
    self.assertIsNotNone(displayNode)
    # If segments are not found then the returned color is the pre-defined invalid color
    bodyColor = displayNode.GetSegmentColor('Body_Contour')
    self.assertTrue(int(bodyColor[0]*100) == 33 and int(bodyColor[1]*100) == 66 and bodyColor[2] == 0.0)
    tumorColor = displayNode.GetSegmentColor('Tumor_Contour')
    self.assertTrue(tumorColor[0] == 1.0 and tumorColor[1] == 0.0 and tumorColor[2] == 0.0)

    # Create new segment
    sphere = vtk.vtkSphereSource()
    sphere.SetCenter(0,50,0)
    sphere.SetRadius(50)
    sphere.Update()
    spherePolyData = vtk.vtkPolyData()
    spherePolyData.DeepCopy(sphere.GetOutput())

    self.sphereSegment = vtkSegmentationCore.vtkSegment()
    self.sphereSegment.SetName(self.sphereSegmentName)
    self.sphereSegment.SetDefaultColor(0.0,0.0,1.0)
    self.sphereSegment.AddRepresentation(self.closedSurfaceReprName, spherePolyData)

    # Add segment to segmentation
    self.inputSegmentationNode.GetSegmentation().AddSegment(self.sphereSegment)
    self.assertEqual(self.inputSegmentationNode.GetSegmentation().GetNumberOfSegments(), 3)
    sphereColor = displayNode.GetSegmentColor(self.sphereSegmentName)
    self.assertTrue(sphereColor[0] == 0.0 and sphereColor[1] == 0.0 and sphereColor[2] == 1.0)

    # Check merged labelmap
    mergedLabelmap = vtkSegmentationCore.vtkOrientedImageData()
    self.inputSegmentationNode.GetSegmentation().CreateRepresentation(self.binaryLabelmapReprName)
    self.inputSegmentationNode.GenerateMergedLabelmapForAllSegments(mergedLabelmap, 0)
    imageStat = vtk.vtkImageAccumulate()
    imageStat.SetInputData(mergedLabelmap)
    imageStat.SetComponentExtent(0,4,0,0,0,0)
    imageStat.SetComponentOrigin(0,0,0)
    imageStat.SetComponentSpacing(1,1,1)
    imageStat.Update()
    self.assertEqual(imageStat.GetVoxelCount(), 1000)
    imageStatResult = imageStat.GetOutput()
    self.assertEqual(imageStatResult.GetScalarComponentAsDouble(0,0,0,0), 795)
    self.assertEqual(imageStatResult.GetScalarComponentAsDouble(1,0,0,0), 194)
    self.assertEqual(imageStatResult.GetScalarComponentAsDouble(2,0,0,0), 5)
    self.assertEqual(imageStatResult.GetScalarComponentAsDouble(3,0,0,0), 6)

    # Remove segment from segmentation
    self.inputSegmentationNode.GetSegmentation().RemoveSegment(self.sphereSegmentName)
    self.assertEqual(self.inputSegmentationNode.GetSegmentation().GetNumberOfSegments(), 2)
    sphereColor = displayNode.GetSegmentColor(self.sphereSegmentName)
    self.assertTrue(sphereColor[0] == 0.5 and sphereColor[1] == 0.5 and sphereColor[2] == 0.5)
예제 #9
0
  def jumpToSegmentAndCreateScreenShot(segmentationNode, segment, widgets, center=False, crosshair=False):
    imageData = vtkSegmentationCore.vtkOrientedImageData()
    segmentID = segmentationNode.GetSegmentation().GetSegmentIdBySegment(segment)
    segmentationsLogic = slicer.modules.segmentations.logic()
    segmentationsLogic.GetSegmentBinaryLabelmapRepresentation(segmentationNode, segmentID, imageData)
    extent = imageData.GetExtent()
    if extent[1] != -1 and extent[3] != -1 and extent[5] != -1:
      tempLabel = slicer.vtkMRMLLabelMapVolumeNode()
      slicer.mrmlScene.AddNode(tempLabel)
      tempLabel.SetName(segment.GetName() + "CentroidHelper")
      segmentationsLogic.CreateLabelmapVolumeFromOrientedImageData(imageData, tempLabel)
      CustomSegmentEditorLogic.applyThreshold(tempLabel, 1)
      centroid = ModuleLogicMixin.getCentroidForLabel(tempLabel, 1)
      slicer.mrmlScene.RemoveNode(tempLabel)

      annotationNodes = []

      crosshairButton = None
      if crosshair:
        crosshairButton = CrosshairButton()
        crosshairButton.setSliceIntersectionEnabled(True)
        crosshairButton.checked = True

      for widget in widgets:
        sliceLogic = widget.sliceLogic()
        sliceNode = sliceLogic.GetSliceNode()

        if not center:
          sliceNode.JumpSliceByOffsetting(centroid[0], centroid[1], centroid[2])
        else:
          markupsLogic = slicer.modules.markups.logic()
          markupsLogic.JumpSlicesToLocation(centroid[0], centroid[1], centroid[2], True)

        dNodeProperties = ScreenShotHelper.saveSegmentDisplayProperties(segmentationNode, segment)
        segmentationNode.GetDisplayNode().SetAllSegmentsVisibility(False)
        ScreenShotHelper.setDisplayNodeProperties(segmentationNode, segment,
                                                  properties={'fill': True, 'outline': True, 'visible': True})

        if crosshairButton:
          crosshairButton.crosshairNode.SetCrosshairRAS(centroid)

        annotationNode = ScreenShotHelper.takeScreenShot("{}_Screenshot_{}_{}".format(segment.GetName(),
                                                                                      sliceNode.GetName(),
                                                                                      sliceNode.GetOrientation()),
                                                         "", widget)
        segmentationNode.GetDisplayNode().SetAllSegmentsVisibility(True)
        ScreenShotHelper.setDisplayNodeProperties(segmentationNode, segment, dNodeProperties)
        annotationNodes.append(annotationNode)
        if crosshairButton:
          crosshairButton.checked = False

      return annotationNodes[0] if len(annotationNodes) == 1 else annotationNodes
예제 #10
0
  def createLabelNodeFromSegment(segmentationNode, segmentID):
    labelNode = slicer.vtkMRMLLabelMapVolumeNode()
    slicer.mrmlScene.AddNode(labelNode)
    segmentationsLogic = slicer.modules.segmentations.logic()

    mergedImageData = vtkSegmentationCore.vtkOrientedImageData()
    segmentationNode.GenerateMergedLabelmapForAllSegments(mergedImageData, 0, None,
                                                          DICOMSegmentationExporter.vtkStringArrayFromList([segmentID]))
    if not segmentationsLogic.CreateLabelmapVolumeFromOrientedImageData(mergedImageData, labelNode):
      slicer.mrmlScene.RemoveNode(labelNode)
      return None
    labelNode.SetName("{}_label".format(segmentID))
    return labelNode
  def onApply(self):
    # Apply changes
    import vtkSegmentationCorePython as vtkSegmentationCore
    segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()
    if (slicer.app.majorVersion >= 5) or (slicer.app.majorVersion >= 4 and slicer.app.minorVersion >= 11):
      modifierLabelmap = vtkSegmentationCore.vtkOrientedImageData()
      segmentationNode.GetBinaryLabelmapRepresentation(self.selectedSegmentId, modifierLabelmap)
    else:
      modifierLabelmap = segmentationNode.GetBinaryLabelmapRepresentation(self.selectedSegmentId)
    self.scriptedEffect.modifySelectedSegmentByLabelmap(modifierLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet)
    self.originalSelectedSegmentLabelmap = None

    self.reset()
    self.scriptedEffect.selectEffect("")
  def updateLabel(self,value):
    if not self.fm:
      return
     
    self.fm.show(value)
    self.fm.Modified()
    self.fm.Update()

    import vtkSegmentationCorePython as vtkSegmentationCore
    newSegmentLabelmap = vtkSegmentationCore.vtkOrientedImageData()
    newSegmentLabelmap.ShallowCopy(self.fm.GetOutput())
    newSegmentLabelmap.CopyDirections(self.originalSelectedSegmentLabelmap)
    
    segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()
    slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(newSegmentLabelmap, segmentationNode, self.selectedSegmentId, slicer.vtkSlicerSegmentationsModuleLogic.MODE_REPLACE, newSegmentLabelmap.GetExtent()) 
예제 #13
0
    def createLabelNodeFromSegment(segmentationNode, segmentID):
        labelNode = slicer.vtkMRMLLabelMapVolumeNode()
        slicer.mrmlScene.AddNode(labelNode)
        segmentationsLogic = slicer.modules.segmentations.logic()

        mergedImageData = vtkSegmentationCore.vtkOrientedImageData()
        segmentationNode.GenerateMergedLabelmapForAllSegments(
            mergedImageData, 0, None,
            DICOMSegmentationExporter.vtkStringArrayFromList([segmentID]))
        if not segmentationsLogic.CreateLabelmapVolumeFromOrientedImageData(
                mergedImageData, labelNode):
            slicer.mrmlScene.RemoveNode(labelNode)
            return None
        labelNode.SetName("{}_label".format(segmentID))
        return labelNode
예제 #14
0
 def getSegmentCentroid(segmentationNode, segment):
   imageData = vtkSegmentationCore.vtkOrientedImageData()
   segmentID = segmentationNode.GetSegmentation().GetSegmentIdBySegment(segment)
   segmentationsLogic = slicer.modules.segmentations.logic()
   segmentationsLogic.GetSegmentBinaryLabelmapRepresentation(segmentationNode, segmentID, imageData)
   extent = imageData.GetExtent()
   if extent[1] != -1 and extent[3] != -1 and extent[5] != -1:
     tempLabel = slicer.vtkMRMLLabelMapVolumeNode()
     slicer.mrmlScene.AddNode(tempLabel)
     tempLabel.SetName(segment.GetName() + "CentroidHelper")
     segmentationsLogic.CreateLabelmapVolumeFromOrientedImageData(imageData, tempLabel)
     CustomSegmentEditorLogic.applyThreshold(tempLabel, 1)
     centroid = ModuleLogicMixin.getCentroidForLabel(tempLabel, 1)
     slicer.mrmlScene.RemoveNode(tempLabel)
     return centroid
   return None
예제 #15
0
 def getSegmentCentroid(segmentationNode, segment):
   imageData = vtkSegmentationCore.vtkOrientedImageData()
   segmentID = segmentationNode.GetSegmentation().GetSegmentIdBySegment(segment)
   segmentationsLogic = slicer.modules.segmentations.logic()
   segmentationsLogic.GetSegmentBinaryLabelmapRepresentation(segmentationNode, segmentID, imageData)
   extent = imageData.GetExtent()
   if extent[1] != -1 and extent[3] != -1 and extent[5] != -1:
     tempLabel = slicer.vtkMRMLLabelMapVolumeNode()
     slicer.mrmlScene.AddNode(tempLabel)
     tempLabel.SetName(segment.GetName() + "CentroidHelper")
     segmentationsLogic.CreateLabelmapVolumeFromOrientedImageData(imageData, tempLabel)
     CustomSegmentEditorLogic.applyThreshold(tempLabel, 1)
     centroid = ModuleLogicMixin.getCentroidForLabel(tempLabel, 1)
     slicer.mrmlScene.RemoveNode(tempLabel)
     return centroid
   return None
예제 #16
0
  def getInvertedBinaryLabelmap(self, modifierLabelmap):
    import vtkSegmentationCorePython as vtkSegmentationCore

    fillValue = 1
    eraseValue = 0
    inverter = vtk.vtkImageThreshold()
    inverter.SetInputData(modifierLabelmap)
    inverter.SetInValue(fillValue)
    inverter.SetOutValue(eraseValue)
    inverter.ReplaceInOn()
    inverter.ThresholdByLower(0)
    inverter.SetOutputScalarType(vtk.VTK_UNSIGNED_CHAR)
    inverter.Update()

    invertedModifierLabelmap = vtkSegmentationCore.vtkOrientedImageData()
    invertedModifierLabelmap.ShallowCopy(inverter.GetOutput())
    imageToWorldMatrix = vtk.vtkMatrix4x4()
    modifierLabelmap.GetImageToWorldMatrix(imageToWorldMatrix)
    invertedModifierLabelmap.SetGeometryFromImageToWorldMatrix(imageToWorldMatrix)
    return invertedModifierLabelmap
예제 #17
0
  def getInvertedBinaryLabelmap(self, modifierLabelmap):
    import vtkSegmentationCorePython as vtkSegmentationCore

    fillValue = 1
    eraseValue = 0
    inverter = vtk.vtkImageThreshold()
    inverter.SetInputData(modifierLabelmap)
    inverter.SetInValue(fillValue)
    inverter.SetOutValue(eraseValue)
    inverter.ReplaceInOn()
    inverter.ThresholdByLower(0)
    inverter.SetOutputScalarType(vtk.VTK_UNSIGNED_CHAR)
    inverter.Update()

    invertedModifierLabelmap = vtkSegmentationCore.vtkOrientedImageData()
    invertedModifierLabelmap.ShallowCopy(inverter.GetOutput())
    imageToWorldMatrix = vtk.vtkMatrix4x4()
    modifierLabelmap.GetImageToWorldMatrix(imageToWorldMatrix)
    invertedModifierLabelmap.SetGeometryFromImageToWorldMatrix(imageToWorldMatrix)
    return invertedModifierLabelmap
예제 #18
0
    def clipOrientedImageWithModel(self,
                                   inputOrientedImage,
                                   inputParentTransformNode,
                                   outputOrientedImage,
                                   outputParentTransformNode,
                                   clipOutsideSurface=True,
                                   fillValue=0,
                                   reduceExtent=False):
        """
    Fill voxels of the input volume inside/outside the clipping model with the provided fill value
    """
        import vtkSegmentationCorePython as vtkSegmentationCore
        # Determine the transform between the box and the image IJK coordinate systems

        rasToModel = vtk.vtkMatrix4x4()
        if self.roiModelNode.GetParentTransformNode() is not None:
            self.roiModelNode.GetParentTransformNode(
            ).GetMatrixTransformFromNode(inputParentTransformNode, rasToModel)
        elif inputParentTransformNode is not None:
            inputParentTransformNode.GetMatrixTransformToNode(
                self.roiModelNode.GetParentTransformNode(), rasToModel)

        inputIjkToRas = vtk.vtkMatrix4x4()
        inputOrientedImage.GetImageToWorldMatrix(inputIjkToRas)
        inputImage = vtk.vtkImageData()
        inputImage.ShallowCopy(inputOrientedImage)
        inputImage.SetOrigin(0, 0, 0)
        inputImage.SetSpacing(1, 1, 1)

        clippingPolyData = self.roiModelNode.GetPolyData()

        outputIjkToRas = vtk.vtkMatrix4x4()
        outputImage = vtkSegmentationCore.vtkOrientedImageData()
        self.clipImageWithPolyData(inputImage, outputImage, clippingPolyData,
                                   rasToModel, inputIjkToRas, outputIjkToRas,
                                   clipOutsideSurface, fillValue, reduceExtent)

        outputOrientedImage.DeepCopy(outputImage)
        outputOrientedImage.SetGeometryFromImageToWorldMatrix(outputIjkToRas)
예제 #19
0
  def findLargest2DRegion(segmentationNode):
    qrLogic = CustomSegmentEditorLogic
    segmentationsLogic = slicer.modules.segmentations.logic()

    largestLM = None
    largestSize = 0
    for segment in qrLogic.getAllSegments(segmentationNode):
      imageData = vtkSegmentationCore.vtkOrientedImageData()
      segmentID = segmentationNode.GetSegmentation().GetSegmentIdBySegment(segment)
      segmentationsLogic.GetSegmentBinaryLabelmapRepresentation(segmentationNode, segmentID, imageData)
      extent = imageData.GetExtent()

      if extent[1] != -1 and extent[3] != -1 and extent[5] != -1:
        tempLabel = slicer.vtkMRMLLabelMapVolumeNode()
        tempLabel.SetName(segment.GetName() + "CentroidHelper")
        segmentationsLogic.CreateLabelmapVolumeFromOrientedImageData(imageData, tempLabel)

        dims = tempLabel.GetImageData().GetDimensions()
        size = dims[0]*dims[1]
        if size > largestSize:
          largestSize = size
          largestLM = tempLabel

    return largestLM
예제 #20
0
    def convertSegmentsToSegment(self, probeNode, nodeIds):
        thisScene = probeNode.GetScene()

        #probeNode.GetSegmentation().CreateRepresentation("Binary labelmap") #added 2/22
        #probeNode.GetSegmentation().SetMasterRepresentationName("Binary labelmap") #added 2/22

        probeName = "ablation zone"
        if len(nodeIds) > 1:
            print(
                "Found multiple probe nodes, combining them into a single segment!: ",
                nodeIds)
            probeName = "combined ablation zone"

        segmentationNode = slicer.vtkMRMLSegmentationNode()
        slicer.mrmlScene.AddNode(segmentationNode)
        segmentationNode.CreateDefaultDisplayNodes()  # only needed for display

        slicer.app.processEvents()

        for probeNodeID in nodeIds:
            duplicateProbeNode = thisScene.GetNodeByID(probeNodeID)
            #duplicateProbeNode.GetSegmentation().SetMasterRepresentationName("Binary labelmap") #ADDED 2/22
            segmentType = duplicateProbeNode.GetSegmentation(
            ).GetMasterRepresentationName()
            slicer.app.processEvents()
            if (segmentType == "Closed surface"):
                mergedImage = vtk.vtkPolyData()
                duplicateProbeNode.GetClosedSurfaceRepresentation(
                    duplicateProbeNode.GetSegmentation().GetNthSegmentID(0),
                    mergedImage)
                newSegmentID = segmentationNode.AddSegmentFromClosedSurfaceRepresentation(
                    mergedImage, probeNodeID, [0, 1, 0])
                newSegment = segmentationNode.GetSegmentation().GetSegment(
                    newSegmentID)
                newSegment.SetName(probeName)
            else:
                labelmapImage = vtkSegmentationCore.vtkOrientedImageData()
                duplicateProbeNode.GetBinaryLabelmapRepresentation(
                    duplicateProbeNode.GetSegmentation().GetNthSegmentID(0),
                    labelmapImage)
                newSegmentID = segmentationNode.AddSegmentFromBinaryLabelmapRepresentation(
                    labelmapImage, probeNodeID, [1, 0, 0])
                newSegment = segmentationNode.GetSegmentation().GetSegment(
                    newSegmentID)
                newSegment.SetName(probeName)
                duplicateProbeNode.GetSegmentation().CreateRepresentation(
                    "Closed Surface")
                #segmentationNode.GetSegmentation().CreateRepresentation("Closed surface")
                #segmentationNode.GetSegmentation().SetMasterRepresentationName("Closed surface")
            #slicer.mrmlScene.RemoveNode(duplicateProbeNode)
            duplicateProbeNode.SetDisplayVisibility(0)

        segmentEditorWidget = slicer.qMRMLSegmentEditorWidget()
        segmentEditorWidget.setMRMLScene(slicer.mrmlScene)
        segmentEditorNode = slicer.mrmlScene.AddNewNodeByClass(
            "vtkMRMLSegmentEditorNode")
        segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode)
        segmentEditorWidget.setSegmentationNode(segmentationNode)

        for i in range(
                1,
                segmentationNode.GetSegmentation().GetNumberOfSegments() +
                1):  #TWO ADDITIONAL PROBES
            segmentEditorWidget.setActiveEffectByName("Logical operators")
            effect = segmentEditorWidget.activeEffect()
            effect.self().scriptedEffect.setParameter("Operation", "UNION")
            effect.self().scriptedEffect.setParameter(
                "ModifierSegmentID",
                segmentationNode.GetSegmentation().GetNthSegmentID(i))
            effect.self().onApply()
            #segmentationNode.GetSegmentation().RemoveSegment(segmentationNode.GetSegmentation().GetNthSegmentID(i))

        #for i in range(1, segmentationNode.GetSegmentation().GetNumberOfSegments()):  #TWO ADDITIONAL PROBES
        #    segmentationNode.GetSegmentation().RemoveSegment(segmentationNode.GetSegmentation().GetNthSegmentID(i))

        segDisplayNode = segmentationNode.GetDisplayNode()
        segDisplayNode.SetOpacity(0.3)

        segmentationNode.GetSegmentation().CreateRepresentation(
            "Closed surface")
        segmentationNode.GetSegmentation().SetMasterRepresentationName(
            "Closed surface")

        segNum = segmentationNode.GetSegmentation().GetNumberOfSegments()
        for i in range(0, segNum):
            segmentationNode.GetSegmentation().RemoveSegment(
                segmentationNode.GetSegmentation().GetNthSegmentID(1))

        segmentationNode.SetName("translated probe")
        #segmentationNode.GetSegmentation().GetNthSegment(0).SetName(probeName)
        return segmentationNode
  def preview(self):
    # Get master volume image data
    import vtkSegmentationCorePython as vtkSegmentationCore
    masterImageData = self.scriptedEffect.masterVolumeImageData()

    # Get segmentation
    segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()

    previewNode = self.getPreviewNode()
    if not previewNode or not self.mergedLabelmapGeometryImage \
      or (self.clippedMasterImageDataRequired and not self.clippedMasterImageData):
      self.reset()
      # Compute merged labelmap extent (effective extent slightly expanded)
      self.selectedSegmentIds = vtk.vtkStringArray()
      segmentationNode.GetDisplayNode().GetVisibleSegmentIDs(self.selectedSegmentIds)
      if self.selectedSegmentIds.GetNumberOfValues() < self.minimumNumberOfSegments:
        logging.error("Auto-complete operation skipped: at least {0} visible segments are required".format(self.minimumNumberOfSegments))
        return
      if not self.mergedLabelmapGeometryImage:
        self.mergedLabelmapGeometryImage = vtkSegmentationCore.vtkOrientedImageData()
      commonGeometryString = segmentationNode.GetSegmentation().DetermineCommonLabelmapGeometry(
        vtkSegmentationCore.vtkSegmentation.EXTENT_UNION_OF_EFFECTIVE_SEGMENTS, self.selectedSegmentIds)
      if not commonGeometryString:
        logging.info("Auto-complete operation skipped: all visible segments are empty")
        return
      vtkSegmentationCore.vtkSegmentationConverter.DeserializeImageGeometry(commonGeometryString, self.mergedLabelmapGeometryImage)

      masterImageExtent = masterImageData.GetExtent()
      labelsEffectiveExtent = self.mergedLabelmapGeometryImage.GetExtent()
      margin = [17, 17, 17]
      labelsExpandedExtent = [
        max(masterImageExtent[0], labelsEffectiveExtent[0]-margin[0]),
        min(masterImageExtent[1], labelsEffectiveExtent[1]+margin[0]),
        max(masterImageExtent[2], labelsEffectiveExtent[2]-margin[1]),
        min(masterImageExtent[3], labelsEffectiveExtent[3]+margin[1]),
        max(masterImageExtent[4], labelsEffectiveExtent[4]-margin[2]),
        min(masterImageExtent[5], labelsEffectiveExtent[5]+margin[2]) ]
      self.mergedLabelmapGeometryImage.SetExtent(labelsExpandedExtent)

      previewNode = slicer.mrmlScene.CreateNodeByClass('vtkMRMLSegmentationNode')
      previewNode.UnRegister(None)
      previewNode = slicer.mrmlScene.AddNode(previewNode)
      previewNode.CreateDefaultDisplayNodes()
      previewNode.GetDisplayNode().SetVisibility2DOutline(False)
      if segmentationNode.GetParentTransformNode():
        previewNode.SetAndObserveTransformNodeID(segmentationNode.GetParentTransformNode().GetID())
      self.scriptedEffect.parameterSetNode().SetNodeReferenceID(ResultPreviewNodeReferenceRole, previewNode.GetID())
      self.scriptedEffect.setCommonParameter("SegmentationResultPreviewOwnerEffect", self.scriptedEffect.name)
      self.setPreviewOpacity(0.6)

      if self.clippedMasterImageDataRequired:
        self.clippedMasterImageData = vtkSegmentationCore.vtkOrientedImageData()
        masterImageClipper = vtk.vtkImageConstantPad()
        masterImageClipper.SetInputData(masterImageData)
        masterImageClipper.SetOutputWholeExtent(self.mergedLabelmapGeometryImage.GetExtent())
        masterImageClipper.Update()
        self.clippedMasterImageData.ShallowCopy(masterImageClipper.GetOutput())
        self.clippedMasterImageData.CopyDirections(self.mergedLabelmapGeometryImage)

    previewNode.SetName(segmentationNode.GetName()+" preview")

    mergedImage = vtkSegmentationCore.vtkOrientedImageData()
    segmentationNode.GenerateMergedLabelmapForAllSegments(mergedImage,
      vtkSegmentationCore.vtkSegmentation.EXTENT_UNION_OF_EFFECTIVE_SEGMENTS, self.mergedLabelmapGeometryImage, self.selectedSegmentIds)

    outputLabelmap = vtkSegmentationCore.vtkOrientedImageData()

    self.computePreviewLabelmap(mergedImage, outputLabelmap)

    # Write output segmentation results in segments
    for index in xrange(self.selectedSegmentIds.GetNumberOfValues()):
      segmentID = self.selectedSegmentIds.GetValue(index)
      segment = segmentationNode.GetSegmentation().GetSegment(segmentID)
      # Disable save with scene?

      # Get only the label of the current segment from the output image
      thresh = vtk.vtkImageThreshold()
      thresh.ReplaceInOn()
      thresh.ReplaceOutOn()
      thresh.SetInValue(1)
      thresh.SetOutValue(0)
      labelValue = index + 1 # n-th segment label value = n + 1 (background label value is 0)
      thresh.ThresholdBetween(labelValue, labelValue);
      thresh.SetOutputScalarType(vtk.VTK_UNSIGNED_CHAR)
      thresh.SetInputData(outputLabelmap)
      thresh.Update()

      # Write label to segment
      newSegmentLabelmap = vtkSegmentationCore.vtkOrientedImageData()
      newSegmentLabelmap.ShallowCopy(thresh.GetOutput())
      newSegmentLabelmap.CopyDirections(mergedImage)
      newSegment = previewNode.GetSegmentation().GetSegment(segmentID)
      if not newSegment:
        newSegment = vtkSegmentationCore.vtkSegment()
        newSegment.SetName(segment.GetName())
        color = segmentationNode.GetSegmentation().GetSegment(segmentID).GetColor()
        newSegment.SetColor(color)
        previewNode.GetSegmentation().AddSegment(newSegment, segmentID)
      slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(newSegmentLabelmap, previewNode, segmentID)

    self.updateGUIFromMRML()
예제 #22
0
    def onApply(self):

        self.scriptedEffect.saveStateForUndo()

        import vtkSegmentationCorePython as vtkSegmentationCore

        # Get modifier labelmap and parameters

        operation = self.scriptedEffect.parameter("Operation")
        bypassMasking = (self.scriptedEffect.integerParameter("BypassMasking")
                         != 0)

        selectedSegmentID = self.scriptedEffect.parameterSetNode(
        ).GetSelectedSegmentID()

        segmentationNode = self.scriptedEffect.parameterSetNode(
        ).GetSegmentationNode()
        segmentation = segmentationNode.GetSegmentation()

        if operation in self.operationsRequireModifierSegment:

            # Get modifier segment
            modifierSegmentID = self.modifierSegmentID()
            if not modifierSegmentID:
                logging.error(
                    "Operation {0} requires a selected modifier segment".
                    format(operation))
                return
            modifierSegment = segmentation.GetSegment(modifierSegmentID)
            modifierSegmentLabelmap = modifierSegment.GetRepresentation(
                vtkSegmentationCore.vtkSegmentationConverter.
                GetSegmentationBinaryLabelmapRepresentationName())

            if operation == LOGICAL_COPY:
                if bypassMasking:
                    slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(
                        modifierSegmentLabelmap, segmentationNode,
                        selectedSegmentID,
                        slicer.vtkSlicerSegmentationsModuleLogic.MODE_REPLACE,
                        modifierSegmentLabelmap.GetExtent())
                else:
                    self.scriptedEffect.modifySelectedSegmentByLabelmap(
                        modifierSegmentLabelmap, slicer.
                        qSlicerSegmentEditorAbstractEffect.ModificationModeSet)
            elif operation == LOGICAL_UNION:
                if bypassMasking:
                    slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(
                        modifierSegmentLabelmap, segmentationNode,
                        selectedSegmentID, slicer.
                        vtkSlicerSegmentationsModuleLogic.MODE_MERGE_MAX,
                        modifierSegmentLabelmap.GetExtent())
                else:
                    self.scriptedEffect.modifySelectedSegmentByLabelmap(
                        modifierSegmentLabelmap, slicer.
                        qSlicerSegmentEditorAbstractEffect.ModificationModeAdd)
            elif operation == LOGICAL_SUBTRACT:
                if bypassMasking:
                    invertedModifierSegmentLabelmap = self.getInvertedBinaryLabelmap(
                        modifierSegmentLabelmap)
                    slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(
                        invertedModifierSegmentLabelmap, segmentationNode,
                        selectedSegmentID, slicer.
                        vtkSlicerSegmentationsModuleLogic.MODE_MERGE_MIN,
                        modifierSegmentLabelmap.GetExtent())
                else:
                    self.scriptedEffect.modifySelectedSegmentByLabelmap(
                        modifierSegmentLabelmap,
                        slicer.qSlicerSegmentEditorAbstractEffect.
                        ModificationModeRemove)
            elif operation == LOGICAL_INTERSECT:
                selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap(
                )
                intersectionLabelmap = vtkSegmentationCore.vtkOrientedImageData(
                )
                vtkSegmentationCore.vtkOrientedImageDataResample.MergeImage(
                    selectedSegmentLabelmap, modifierSegmentLabelmap,
                    intersectionLabelmap, vtkSegmentationCore.
                    vtkOrientedImageDataResample.OPERATION_MINIMUM,
                    selectedSegmentLabelmap.GetExtent())
                selectedSegmentLabelmapExtent = selectedSegmentLabelmap.GetExtent(
                )
                modifierSegmentLabelmapExtent = modifierSegmentLabelmap.GetExtent(
                )
                commonExtent = [
                    max(selectedSegmentLabelmapExtent[0],
                        modifierSegmentLabelmapExtent[0]),
                    min(selectedSegmentLabelmapExtent[1],
                        modifierSegmentLabelmapExtent[1]),
                    max(selectedSegmentLabelmapExtent[2],
                        modifierSegmentLabelmapExtent[2]),
                    min(selectedSegmentLabelmapExtent[3],
                        modifierSegmentLabelmapExtent[3]),
                    max(selectedSegmentLabelmapExtent[4],
                        modifierSegmentLabelmapExtent[4]),
                    min(selectedSegmentLabelmapExtent[5],
                        modifierSegmentLabelmapExtent[5])
                ]
                if bypassMasking:
                    slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(
                        intersectionLabelmap, segmentationNode,
                        selectedSegmentID,
                        slicer.vtkSlicerSegmentationsModuleLogic.MODE_REPLACE,
                        commonExtent)
                else:
                    self.scriptedEffect.modifySelectedSegmentByLabelmap(
                        intersectionLabelmap, slicer.
                        qSlicerSegmentEditorAbstractEffect.ModificationModeSet,
                        commonExtent)

        elif operation == LOGICAL_INVERT:
            selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap(
            )
            invertedSelectedSegmentLabelmap = self.getInvertedBinaryLabelmap(
                selectedSegmentLabelmap)
            if bypassMasking:
                slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(
                    invertedSelectedSegmentLabelmap, segmentationNode,
                    selectedSegmentID,
                    slicer.vtkSlicerSegmentationsModuleLogic.MODE_REPLACE)
            else:
                self.scriptedEffect.modifySelectedSegmentByLabelmap(
                    invertedSelectedSegmentLabelmap, slicer.
                    qSlicerSegmentEditorAbstractEffect.ModificationModeSet)

        elif operation == LOGICAL_CLEAR or operation == LOGICAL_FILL:
            selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap(
            )
            vtkSegmentationCore.vtkOrientedImageDataResample.FillImage(
                selectedSegmentLabelmap, 1 if operation == LOGICAL_FILL else 0,
                selectedSegmentLabelmap.GetExtent())
            if bypassMasking:
                slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(
                    selectedSegmentLabelmap, segmentationNode,
                    selectedSegmentID,
                    slicer.vtkSlicerSegmentationsModuleLogic.MODE_REPLACE)
            else:
                self.scriptedEffect.modifySelectedSegmentByLabelmap(
                    selectedSegmentLabelmap, slicer.
                    qSlicerSegmentEditorAbstractEffect.ModificationModeSet)

        else:
            logging.error("Unknown operation: {0}".format(operation))
예제 #23
0
  def processInteractionEvents(self, callerInteractor, eventId, viewWidget):
    import vtkSegmentationCorePython as vtkSegmentationCore

    abortEvent = False

    # Only allow in modes where segment selection is needed
    if not self.currentOperationRequiresSegmentSelection():
      return False

    # Only allow for slice views
    if viewWidget.className() != "qMRMLSliceWidget":
      return abortEvent

    if eventId != vtk.vtkCommand.LeftButtonPressEvent:
      return abortEvent

    abortEvent = True

    # Generate merged labelmap of all visible segments
    segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()
    visibleSegmentIds = vtk.vtkStringArray()
    segmentationNode.GetDisplayNode().GetVisibleSegmentIDs(visibleSegmentIds)
    if visibleSegmentIds.GetNumberOfValues() == 0:
      logging.info("Smoothing operation skipped: there are no visible segments")
      return abortEvent

    self.scriptedEffect.saveStateForUndo()

    # This can be a long operation - indicate it to the user
    qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor)

    operationName = self.scriptedEffect.parameter("Operation")

    if operationName == ADD_SELECTED_ISLAND:
      inputLabelImage = vtkSegmentationCore.vtkOrientedImageData()
      if not segmentationNode.GenerateMergedLabelmapForAllSegments(inputLabelImage,
                                                                   vtkSegmentationCore.vtkSegmentation.EXTENT_UNION_OF_SEGMENTS_PADDED,
                                                                   None, visibleSegmentIds):
        logging.error('Failed to apply smoothing: cannot get list of visible segments')
        qt.QApplication.restoreOverrideCursor()
        return abortEvent
    else:
      selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap()
      # We need to know exactly the value of the segment voxels, apply threshold to make force the selected label value
      labelValue = 1
      backgroundValue = 0
      thresh = vtk.vtkImageThreshold()
      thresh.SetInputData(selectedSegmentLabelmap)
      thresh.ThresholdByLower(0)
      thresh.SetInValue(backgroundValue)
      thresh.SetOutValue(labelValue)
      thresh.SetOutputScalarType(selectedSegmentLabelmap.GetScalarType())
      thresh.Update()
      # Create oriented image data from output
      import vtkSegmentationCorePython as vtkSegmentationCore
      inputLabelImage = vtkSegmentationCore.vtkOrientedImageData()
      inputLabelImage.ShallowCopy(thresh.GetOutput())
      selectedSegmentLabelmapImageToWorldMatrix = vtk.vtkMatrix4x4()
      selectedSegmentLabelmap.GetImageToWorldMatrix(selectedSegmentLabelmapImageToWorldMatrix)
      inputLabelImage.SetImageToWorldMatrix(selectedSegmentLabelmapImageToWorldMatrix)

    xy = callerInteractor.GetEventPosition()
    ijk = self.xyToIjk(xy, viewWidget, inputLabelImage)
    pixelValue = inputLabelImage.GetScalarComponentAsFloat(ijk[0], ijk[1], ijk[2], 0)

    try:

      floodFillingFilter = vtk.vtkImageThresholdConnectivity()
      floodFillingFilter.SetInputData(inputLabelImage)
      seedPoints = vtk.vtkPoints()
      origin = inputLabelImage.GetOrigin()
      spacing = inputLabelImage.GetSpacing()
      seedPoints.InsertNextPoint(origin[0]+ijk[0]*spacing[0], origin[1]+ijk[1]*spacing[1], origin[2]+ijk[2]*spacing[2])
      floodFillingFilter.SetSeedPoints(seedPoints)
      floodFillingFilter.ThresholdBetween(pixelValue, pixelValue)

      if operationName == ADD_SELECTED_ISLAND:
        floodFillingFilter.SetInValue(1)
        floodFillingFilter.SetOutValue(0)
        floodFillingFilter.Update()
        modifierLabelmap = self.scriptedEffect.defaultModifierLabelmap()
        modifierLabelmap.DeepCopy(floodFillingFilter.GetOutput())
        self.scriptedEffect.modifySelectedSegmentByLabelmap(modifierLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeAdd)

      elif pixelValue != 0: # if clicked on empty part then there is nothing to remove or keep

        if operationName == KEEP_SELECTED_ISLAND:
          floodFillingFilter.SetInValue(1)
          floodFillingFilter.SetOutValue(0)
        else: # operationName == REMOVE_SELECTED_ISLAND:
          floodFillingFilter.SetInValue(1)
          floodFillingFilter.SetOutValue(0)

        floodFillingFilter.Update()
        modifierLabelmap = self.scriptedEffect.defaultModifierLabelmap()
        modifierLabelmap.DeepCopy(floodFillingFilter.GetOutput())

        if operationName == KEEP_SELECTED_ISLAND:
          self.scriptedEffect.modifySelectedSegmentByLabelmap(modifierLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet)
        else: # operationName == REMOVE_SELECTED_ISLAND:
          self.scriptedEffect.modifySelectedSegmentByLabelmap(modifierLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeRemove)

    except IndexError:
      logging.error('apply: Failed to threshold master volume!')
    finally:
      qt.QApplication.restoreOverrideCursor()

    return abortEvent
예제 #24
0
  def growCut(self):
    # Get master volume image data
    import vtkSegmentationCorePython as vtkSegmentationCore
    masterImageData = self.scriptedEffect.masterVolumeImageData()
    # Get segmentation
    segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()

    # Cast master image if not short
    if masterImageData.GetScalarType() != vtk.VTK_SHORT:
      imageCast = vtk.vtkImageCast()
      imageCast.SetInputData(masterImageData)
      imageCast.SetOutputScalarTypeToShort()
      imageCast.ClampOverflowOn()
      imageCast.Update()
      masterImageDataShort = vtkSegmentationCore.vtkOrientedImageData()
      masterImageDataShort.DeepCopy(imageCast.GetOutput()) # Copy image data
      masterImageDataShort.CopyDirections(masterImageData) # Copy geometry
      masterImageData = masterImageDataShort

    # Generate merged labelmap as input to GrowCut
    mergedImage = vtkSegmentationCore.vtkOrientedImageData()
    segmentationNode.GenerateMergedLabelmapForAllSegments(mergedImage, vtkSegmentationCore.vtkSegmentation.EXTENT_UNION_OF_SEGMENTS, masterImageData)

    # Make a zero-valued volume for the output
    outputLabelmap = vtkSegmentationCore.vtkOrientedImageData()
    thresh = vtk.vtkImageThreshold()
    thresh.ReplaceInOn()
    thresh.ReplaceOutOn()
    thresh.SetInValue(0)
    thresh.SetOutValue(0)
    thresh.SetOutputScalarType( vtk.VTK_SHORT )
    thresh.SetInputData( mergedImage )
    thresh.SetOutput( outputLabelmap )
    thresh.Update()
    outputLabelmap.DeepCopy( mergedImage ) #TODO: It was thresholded just above, why deep copy now?

    # Perform grow cut
    import vtkITK
    growCutFilter = vtkITK.vtkITKGrowCutSegmentationImageFilter()
    growCutFilter.SetInputData( 0, masterImageData )
    growCutFilter.SetInputData( 1, mergedImage )
    #TODO: This call sets an empty image for the optional "previous segmentation", and
    #      is apparently needed for the first segmentation too. Why?
    growCutFilter.SetInputConnection( 2, thresh.GetOutputPort() )

    #TODO: These are magic numbers inherited from EditorLib/GrowCut.py
    objectSize = 5.
    contrastNoiseRatio = 0.8
    priorStrength = 0.003
    segmented = 2
    conversion = 1000

    spacing = mergedImage.GetSpacing()
    voxelVolume = reduce(lambda x,y: x*y, spacing)
    voxelAmount = objectSize / voxelVolume
    voxelNumber = round(voxelAmount) * conversion

    cubeRoot = 1./3.
    oSize = int(round(pow(voxelNumber,cubeRoot)))

    growCutFilter.SetObjectSize( oSize )
    growCutFilter.SetContrastNoiseRatio( contrastNoiseRatio )
    growCutFilter.SetPriorSegmentConfidence( priorStrength )
    growCutFilter.Update()

    outputLabelmap.DeepCopy( growCutFilter.GetOutput() )

    # Write output segmentation results in segments
    segmentIDs = vtk.vtkStringArray()
    segmentationNode.GetSegmentation().GetSegmentIDs(segmentIDs)
    for index in xrange(segmentIDs.GetNumberOfValues()):
      segmentID = segmentIDs.GetValue(index)
      segment = segmentationNode.GetSegmentation().GetSegment(segmentID)

      # Get label corresponding to segment in merged labelmap (and so GrowCut output)
      colorIndexStr = vtk.mutable("")
      tagFound = segment.GetTag(slicer.vtkMRMLSegmentationDisplayNode.GetColorIndexTag(), colorIndexStr);
      if not tagFound:
        logging.error('Failed to apply GrowCut result on segment ' + segmentID)
        continue
      colorIndex = int(colorIndexStr.get())

      # Get only the label of the current segment from the output image
      thresh = vtk.vtkImageThreshold()
      thresh.ReplaceInOn()
      thresh.ReplaceOutOn()
      thresh.SetInValue(1)
      thresh.SetOutValue(0)
      thresh.ThresholdBetween(colorIndex, colorIndex);
      thresh.SetOutputScalarType(vtk.VTK_UNSIGNED_CHAR)
      thresh.SetInputData(outputLabelmap)
      thresh.Update()

      # Write label to segment
      newSegmentLabelmap = vtkSegmentationCore.vtkOrientedImageData()
      newSegmentLabelmap.ShallowCopy(thresh.GetOutput())
      newSegmentLabelmap.CopyDirections(mergedImage)
      slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(newSegmentLabelmap, segmentationNode, segmentID, slicer.vtkSlicerSegmentationsModuleLogic.MODE_REPLACE, newSegmentLabelmap.GetExtent())
예제 #25
0
    def growCut(self):
        # Get master volume image data
        import vtkSegmentationCorePython as vtkSegmentationCore
        masterImageData = self.scriptedEffect.masterVolumeImageData()
        # Get segmentation
        segmentationNode = self.scriptedEffect.parameterSetNode(
        ).GetSegmentationNode()

        # Cast master image if not short
        if masterImageData.GetScalarType() != vtk.VTK_SHORT:
            imageCast = vtk.vtkImageCast()
            imageCast.SetInputData(masterImageData)
            imageCast.SetOutputScalarTypeToShort()
            imageCast.ClampOverflowOn()
            imageCast.Update()
            masterImageDataShort = vtkSegmentationCore.vtkOrientedImageData()
            masterImageDataShort.DeepCopy(
                imageCast.GetOutput())  # Copy image data
            masterImageDataShort.CopyDirections(
                masterImageData)  # Copy geometry
            masterImageData = masterImageDataShort

        # Generate merged labelmap as input to GrowCut
        mergedImage = vtkSegmentationCore.vtkOrientedImageData()
        segmentationNode.GenerateMergedLabelmapForAllSegments(
            mergedImage,
            vtkSegmentationCore.vtkSegmentation.EXTENT_UNION_OF_SEGMENTS,
            masterImageData)

        # Make a zero-valued volume for the output
        outputLabelmap = vtkSegmentationCore.vtkOrientedImageData()
        thresh = vtk.vtkImageThreshold()
        thresh.ReplaceInOn()
        thresh.ReplaceOutOn()
        thresh.SetInValue(0)
        thresh.SetOutValue(0)
        thresh.SetOutputScalarType(vtk.VTK_SHORT)
        thresh.SetInputData(mergedImage)
        thresh.SetOutput(outputLabelmap)
        thresh.Update()
        outputLabelmap.DeepCopy(
            mergedImage
        )  #TODO: It was thresholded just above, why deep copy now?

        # Perform grow cut
        import vtkITK
        growCutFilter = vtkITK.vtkITKGrowCutSegmentationImageFilter()
        growCutFilter.SetInputData(0, masterImageData)
        growCutFilter.SetInputData(1, mergedImage)
        #TODO: This call sets an empty image for the optional "previous segmentation", and
        #      is apparently needed for the first segmentation too. Why?
        growCutFilter.SetInputConnection(2, thresh.GetOutputPort())

        #TODO: These are magic numbers inherited from EditorLib/GrowCut.py
        objectSize = 5.
        contrastNoiseRatio = 0.8
        priorStrength = 0.003
        segmented = 2
        conversion = 1000

        spacing = mergedImage.GetSpacing()
        voxelVolume = reduce(lambda x, y: x * y, spacing)
        voxelAmount = objectSize / voxelVolume
        voxelNumber = round(voxelAmount) * conversion

        cubeRoot = 1. / 3.
        oSize = int(round(pow(voxelNumber, cubeRoot)))

        growCutFilter.SetObjectSize(oSize)
        growCutFilter.SetContrastNoiseRatio(contrastNoiseRatio)
        growCutFilter.SetPriorSegmentConfidence(priorStrength)
        growCutFilter.Update()

        outputLabelmap.DeepCopy(growCutFilter.GetOutput())

        # Write output segmentation results in segments
        segmentIDs = vtk.vtkStringArray()
        segmentationNode.GetSegmentation().GetSegmentIDs(segmentIDs)
        for index in xrange(segmentIDs.GetNumberOfValues()):
            segmentID = segmentIDs.GetValue(index)
            segment = segmentationNode.GetSegmentation().GetSegment(segmentID)

            # Get label corresponding to segment in merged labelmap (and so GrowCut output)
            colorIndexStr = vtk.mutable("")
            tagFound = segment.GetTag(
                slicer.vtkMRMLSegmentationDisplayNode.GetColorIndexTag(),
                colorIndexStr)
            if not tagFound:
                logging.error('Failed to apply GrowCut result on segment ' +
                              segmentID)
                continue
            colorIndex = int(colorIndexStr.get())

            # Get only the label of the current segment from the output image
            thresh = vtk.vtkImageThreshold()
            thresh.ReplaceInOn()
            thresh.ReplaceOutOn()
            thresh.SetInValue(1)
            thresh.SetOutValue(0)
            thresh.ThresholdBetween(colorIndex, colorIndex)
            thresh.SetOutputScalarType(vtk.VTK_UNSIGNED_CHAR)
            thresh.SetInputData(outputLabelmap)
            thresh.Update()

            # Write label to segment
            newSegmentLabelmap = vtkSegmentationCore.vtkOrientedImageData()
            newSegmentLabelmap.ShallowCopy(thresh.GetOutput())
            newSegmentLabelmap.CopyDirections(mergedImage)
            slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(
                newSegmentLabelmap, segmentationNode, segmentID,
                slicer.vtkSlicerSegmentationsModuleLogic.MODE_REPLACE,
                newSegmentLabelmap.GetExtent())
예제 #26
0
  def TestSection_2_qMRMLSegmentationGeometryWidget(self):
    logging.info('Test section 2: qMRMLSegmentationGeometryWidget')

    import vtkSegmentationCore
    binaryLabelmapReprName = vtkSegmentationCore.vtkSegmentationConverter.GetBinaryLabelmapRepresentationName()
    closedSurfaceReprName = vtkSegmentationCore.vtkSegmentationConverter.GetClosedSurfaceRepresentationName()

    # Use MRHead and Tinypatient for testing
    import SampleData
    sampleDataLogic = SampleData.SampleDataLogic()
    mrVolumeNode = sampleDataLogic.downloadMRHead()
    [tinyVolumeNode, tinySegmentationNode] = sampleDataLogic.downloadSample('TinyPatient')

    # Convert MRHead to oriented image data
    import vtkSlicerSegmentationsModuleLogicPython as vtkSlicerSegmentationsModuleLogic
    mrOrientedImageData = vtkSlicerSegmentationsModuleLogic.vtkSlicerSegmentationsModuleLogic.CreateOrientedImageDataFromVolumeNode(mrVolumeNode)
    mrOrientedImageData.UnRegister(None)

    # Create segmentation node with binary labelmap master and one segment with MRHead geometry
    segmentationNode = slicer.vtkMRMLSegmentationNode()
    segmentationNode.GetSegmentation().SetMasterRepresentationName(binaryLabelmapReprName)
    geometryStr = vtkSegmentationCore.vtkSegmentationConverter.SerializeImageGeometry(mrOrientedImageData)
    segmentationNode.GetSegmentation().SetConversionParameter(
      vtkSegmentationCore.vtkSegmentationConverter.GetReferenceImageGeometryParameterName(), geometryStr)
    slicer.mrmlScene.AddNode(segmentationNode)
    threshold = vtk.vtkImageThreshold()
    threshold.SetInputData(mrOrientedImageData)
    threshold.ThresholdByUpper(16.0)
    threshold.SetInValue(1)
    threshold.SetOutValue(0)
    threshold.SetOutputScalarType(vtk.VTK_UNSIGNED_CHAR)
    threshold.Update()
    segmentOrientedImageData = vtkSegmentationCore.vtkOrientedImageData()
    segmentOrientedImageData.DeepCopy(threshold.GetOutput())
    mrImageToWorldMatrix = vtk.vtkMatrix4x4()
    mrOrientedImageData.GetImageToWorldMatrix(mrImageToWorldMatrix)
    segmentOrientedImageData.SetImageToWorldMatrix(mrImageToWorldMatrix)
    segment = vtkSegmentationCore.vtkSegment()
    segment.SetName('Brain')
    segment.SetColor(0.0,0.0,1.0)
    segment.AddRepresentation(binaryLabelmapReprName, segmentOrientedImageData)
    segmentationNode.GetSegmentation().AddSegment(segment)

    # Create geometry widget
    geometryWidget = slicer.qMRMLSegmentationGeometryWidget()
    geometryWidget.setSegmentationNode(segmentationNode)
    geometryWidget.editEnabled = True
    geometryImageData = vtkSegmentationCore.vtkOrientedImageData() # To contain the output later

    # Volume source with no transforms
    geometryWidget.setSourceNode(tinyVolumeNode)
    geometryWidget.geometryImageData(geometryImageData)
    self.assertTrue(self.compareOutputGeometry(geometryImageData,
        (49,49,23), (248.8439, 248.2890, -123.75),
        [[-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]]))
    vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
      segmentOrientedImageData, geometryImageData, geometryImageData, False, True)
    self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 92)

    # Transformed volume source
    translationTransformMatrix = vtk.vtkMatrix4x4()
    translationTransformMatrix.SetElement(0,3,24.5)
    translationTransformMatrix.SetElement(1,3,24.5)
    translationTransformMatrix.SetElement(2,3,11.5)
    translationTransformNode = slicer.vtkMRMLLinearTransformNode()
    translationTransformNode.SetName('TestTranslation')
    slicer.mrmlScene.AddNode(translationTransformNode)
    translationTransformNode.SetMatrixTransformToParent(translationTransformMatrix)

    tinyVolumeNode.SetAndObserveTransformNodeID(translationTransformNode.GetID())
    geometryWidget.geometryImageData(geometryImageData)
    self.assertTrue(self.compareOutputGeometry(geometryImageData,
        (49,49,23), (224.3439, 223.7890, -135.25),
        [[-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]]))
    vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
      segmentOrientedImageData, geometryImageData, geometryImageData, False, True)
    self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 94)

    # Volume source with isotropic spacing
    tinyVolumeNode.SetAndObserveTransformNodeID(None)
    geometryWidget.setIsotropicSpacing(True)
    geometryWidget.geometryImageData(geometryImageData)
    self.assertTrue(self.compareOutputGeometry(geometryImageData,
        (23,23,23), (248.8439, 248.2890, -123.75),
        [[-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]]))
    vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
      segmentOrientedImageData, geometryImageData, geometryImageData, False, True)
    self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 414)

    # Volume source with oversampling
    geometryWidget.setIsotropicSpacing(False)
    geometryWidget.setOversamplingFactor(2.0)
    geometryWidget.geometryImageData(geometryImageData)
    self.assertTrue(self.compareOutputGeometry(geometryImageData,
        (24.5, 24.5, 11.5), (261.0939, 260.5390, -129.5),
        [[-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]]))
    vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
      segmentOrientedImageData, geometryImageData, geometryImageData, False, True)
    self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 751)
    slicer.util.delayDisplay('Volume source cases - OK')

    # Segmentation source with binary labelmap master
    geometryWidget.setOversamplingFactor(1.0)
    geometryWidget.setSourceNode(tinySegmentationNode)
    geometryWidget.geometryImageData(geometryImageData)
    self.assertTrue(self.compareOutputGeometry(geometryImageData,
        (49,49,23), (248.8439, 248.2890, -123.75),
        [[-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]]))
    vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
      segmentOrientedImageData, geometryImageData, geometryImageData, False, True)
    self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 92)

    # Segmentation source with closed surface master
    tinySegmentationNode.GetSegmentation().SetConversionParameter('Smoothing factor', '0.0')
    self.assertTrue(tinySegmentationNode.GetSegmentation().CreateRepresentation(closedSurfaceReprName))
    tinySegmentationNode.GetSegmentation().SetMasterRepresentationName(closedSurfaceReprName)
    tinySegmentationNode.Modified() # Trigger re-calculation of geometry (only generic Modified event is observed)
    geometryWidget.geometryImageData(geometryImageData)
    self.assertTrue(self.compareOutputGeometry(geometryImageData,
        (1,1,1), (-167.156, -217.711, -135.75),
        [[0.0, 0.0, 1.0], [-1.0, 0.0, 0.0], [0.0, -1.0, 0.0]]))
    vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
      segmentOrientedImageData, geometryImageData, geometryImageData, False, True)
    self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 5223846)
    slicer.util.delayDisplay('Segmentation source cases - OK')

    # Model source with no transform
    outputModelHierarchy = slicer.vtkMRMLModelHierarchyNode()
    slicer.mrmlScene.AddNode(outputModelHierarchy)
    success = vtkSlicerSegmentationsModuleLogic.vtkSlicerSegmentationsModuleLogic.ExportVisibleSegmentsToModelHierarchy(
      tinySegmentationNode, outputModelHierarchy )
    self.assertTrue(success)
    modelNode = slicer.util.getNode('Body_Contour')
    geometryWidget.setSourceNode(modelNode)
    geometryWidget.geometryImageData(geometryImageData)
    self.assertTrue(self.compareOutputGeometry(geometryImageData,
        (1,1,1), (-167.156, -217.711, -135.75),
        [[0.0, 0.0, 1.0], [-1.0, 0.0, 0.0], [0.0, -1.0, 0.0]]))
    vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
      segmentOrientedImageData, geometryImageData, geometryImageData, False, True)
    self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 5223846)

    # Transformed model source
    rotationTransform = vtk.vtkTransform()
    rotationTransform.RotateX(45)
    rotationTransformMatrix = vtk.vtkMatrix4x4()
    rotationTransform.GetMatrix(rotationTransformMatrix)
    rotationTransformNode = slicer.vtkMRMLLinearTransformNode()
    rotationTransformNode.SetName('TestRotation')
    slicer.mrmlScene.AddNode(rotationTransformNode)
    rotationTransformNode.SetMatrixTransformToParent(rotationTransformMatrix)

    modelNode.SetAndObserveTransformNodeID(rotationTransformNode.GetID())
    modelNode.Modified()
    geometryWidget.geometryImageData(geometryImageData)
    self.assertTrue(self.compareOutputGeometry(geometryImageData,
        (1,1,1), (-167.156, -58.6623, -249.228),
        [[0.0, 0.0, 1.0], [-0.7071, -0.7071, 0.0], [0.7071, -0.7071, 0.0]]))
    vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
      segmentOrientedImageData, geometryImageData, geometryImageData, False, True)
    self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 5221241)

    # ROI source
    roiNode = slicer.vtkMRMLAnnotationROINode()
    roiNode.SetName('SourceROI')
    slicer.mrmlScene.AddNode(roiNode)
    roiNode.UnRegister(None)
    xyz = [0]*3
    center = [0]*3
    slicer.vtkMRMLSliceLogic.GetVolumeRASBox(tinyVolumeNode, xyz, center)
    radius = map(lambda x: x/2.0, xyz)
    roiNode.SetXYZ(center)
    roiNode.SetRadiusXYZ(radius)
    geometryWidget.setSourceNode(roiNode)
    geometryWidget.geometryImageData(geometryImageData)
    self.assertTrue(self.compareOutputGeometry(geometryImageData,
        (1,1,1), (-216.156, -217.711, -135.75),
        [[0.0, 0.0, 1.0], [-1.0, 0.0, 0.0], [0.0, -1.0, 0.0]]))
    vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
      segmentOrientedImageData, geometryImageData, geometryImageData, False, True)
    self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 5223846)
    slicer.util.delayDisplay('Model and ROI source cases - OK')

    slicer.util.delayDisplay('Segmentation geometry widget test passed')
예제 #27
0
    def processInteractionEvents(self, callerInteractor, eventId, viewWidget):
        import vtkSegmentationCorePython as vtkSegmentationCore

        abortEvent = False

        # Only allow in modes where segment selection is needed
        if not self.currentOperationRequiresSegmentSelection():
            return False

        # Only allow for slice views
        if viewWidget.className() != "qMRMLSliceWidget":
            return abortEvent

        if eventId != vtk.vtkCommand.LeftButtonPressEvent:
            return abortEvent

        abortEvent = True

        # Generate merged labelmap of all visible segments
        segmentationNode = self.scriptedEffect.parameterSetNode(
        ).GetSegmentationNode()
        visibleSegmentIds = vtk.vtkStringArray()
        segmentationNode.GetDisplayNode().GetVisibleSegmentIDs(
            visibleSegmentIds)
        if visibleSegmentIds.GetNumberOfValues() == 0:
            logging.info(
                "Smoothing operation skipped: there are no visible segments")
            return abortEvent

        self.scriptedEffect.saveStateForUndo()

        # This can be a long operation - indicate it to the user
        qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor)

        operationName = self.scriptedEffect.parameter("Operation")

        if operationName == ADD_SELECTED_ISLAND:
            inputLabelImage = vtkSegmentationCore.vtkOrientedImageData()
            if not segmentationNode.GenerateMergedLabelmapForAllSegments(
                    inputLabelImage, vtkSegmentationCore.vtkSegmentation.
                    EXTENT_UNION_OF_SEGMENTS_PADDED, None, visibleSegmentIds):
                logging.error(
                    'Failed to apply smoothing: cannot get list of visible segments'
                )
                qt.QApplication.restoreOverrideCursor()
                return abortEvent
        else:
            selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap(
            )
            # We need to know exactly the value of the segment voxels, apply threshold to make force the selected label value
            labelValue = 1
            backgroundValue = 0
            thresh = vtk.vtkImageThreshold()
            thresh.SetInputData(selectedSegmentLabelmap)
            thresh.ThresholdByLower(0)
            thresh.SetInValue(backgroundValue)
            thresh.SetOutValue(labelValue)
            thresh.SetOutputScalarType(selectedSegmentLabelmap.GetScalarType())
            thresh.Update()
            # Create oriented image data from output
            import vtkSegmentationCorePython as vtkSegmentationCore
            inputLabelImage = vtkSegmentationCore.vtkOrientedImageData()
            inputLabelImage.ShallowCopy(thresh.GetOutput())
            selectedSegmentLabelmapImageToWorldMatrix = vtk.vtkMatrix4x4()
            selectedSegmentLabelmap.GetImageToWorldMatrix(
                selectedSegmentLabelmapImageToWorldMatrix)
            inputLabelImage.SetImageToWorldMatrix(
                selectedSegmentLabelmapImageToWorldMatrix)

        xy = callerInteractor.GetEventPosition()
        ijk = self.xyToIjk(xy, viewWidget, inputLabelImage)
        pixelValue = inputLabelImage.GetScalarComponentAsFloat(
            ijk[0], ijk[1], ijk[2], 0)

        try:

            floodFillingFilter = vtk.vtkImageThresholdConnectivity()
            floodFillingFilter.SetInputData(inputLabelImage)
            seedPoints = vtk.vtkPoints()
            origin = inputLabelImage.GetOrigin()
            spacing = inputLabelImage.GetSpacing()
            seedPoints.InsertNextPoint(origin[0] + ijk[0] * spacing[0],
                                       origin[1] + ijk[1] * spacing[1],
                                       origin[2] + ijk[2] * spacing[2])
            floodFillingFilter.SetSeedPoints(seedPoints)
            floodFillingFilter.ThresholdBetween(pixelValue, pixelValue)

            if operationName == ADD_SELECTED_ISLAND:
                floodFillingFilter.SetInValue(1)
                floodFillingFilter.SetOutValue(0)
                floodFillingFilter.Update()
                modifierLabelmap = self.scriptedEffect.defaultModifierLabelmap(
                )
                modifierLabelmap.DeepCopy(floodFillingFilter.GetOutput())
                self.scriptedEffect.modifySelectedSegmentByLabelmap(
                    modifierLabelmap, slicer.
                    qSlicerSegmentEditorAbstractEffect.ModificationModeAdd)

            elif pixelValue != 0:  # if clicked on empty part then there is nothing to remove or keep

                if operationName == KEEP_SELECTED_ISLAND:
                    floodFillingFilter.SetInValue(1)
                    floodFillingFilter.SetOutValue(0)
                else:  # operationName == REMOVE_SELECTED_ISLAND:
                    floodFillingFilter.SetInValue(1)
                    floodFillingFilter.SetOutValue(0)

                floodFillingFilter.Update()
                modifierLabelmap = self.scriptedEffect.defaultModifierLabelmap(
                )
                modifierLabelmap.DeepCopy(floodFillingFilter.GetOutput())

                if operationName == KEEP_SELECTED_ISLAND:
                    self.scriptedEffect.modifySelectedSegmentByLabelmap(
                        modifierLabelmap, slicer.
                        qSlicerSegmentEditorAbstractEffect.ModificationModeSet)
                else:  # operationName == REMOVE_SELECTED_ISLAND:
                    self.scriptedEffect.modifySelectedSegmentByLabelmap(
                        modifierLabelmap,
                        slicer.qSlicerSegmentEditorAbstractEffect.
                        ModificationModeRemove)

        except IndexError:
            logging.error('apply: Failed to threshold master volume!')
        finally:
            qt.QApplication.restoreOverrideCursor()

        return abortEvent
예제 #28
0
  def onApply(self):

    import vtkSegmentationCorePython as vtkSegmentationCore

    # Get modifier labelmap and parameters

    operation = self.scriptedEffect.parameter("Operation")
    bypassMasking =  (self.scriptedEffect.integerParameter("BypassMasking") != 0)

    selectedSegmentID = self.scriptedEffect.parameterSetNode().GetSelectedSegmentID()

    segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()
    segmentation = segmentationNode.GetSegmentation()

    if operation in self.operationsRequireModifierSegment:

      # Get modifier segment
      modifierSegmentID = self.modifierSegmentID()
      if not modifierSegmentID:
        logging.error("Operation {0} requires a selected modifier segment".format(operation))
        return
      modifierSegment = segmentation.GetSegment(modifierSegmentID)
      modifierSegmentLabelmap = modifierSegment.GetRepresentation(vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationBinaryLabelmapRepresentationName())

      if operation == LOGICAL_COPY:
        if bypassMasking:
          slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(modifierSegmentLabelmap,
            segmentationNode, selectedSegmentID, slicer.vtkSlicerSegmentationsModuleLogic.MODE_REPLACE, modifierSegmentLabelmap.GetExtent())
        else:
          self.scriptedEffect.modifySelectedSegmentByLabelmap(modifierSegmentLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet)
      elif operation == LOGICAL_UNION:
        if bypassMasking:
          slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(modifierSegmentLabelmap,
            segmentationNode, selectedSegmentID, slicer.vtkSlicerSegmentationsModuleLogic.MODE_MERGE_MAX, modifierSegmentLabelmap.GetExtent())
        else:
          self.scriptedEffect.modifySelectedSegmentByLabelmap(modifierSegmentLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeAdd)
      elif operation == LOGICAL_SUBTRACT:
        if bypassMasking:
          invertedModifierSegmentLabelmap = self.getInvertedBinaryLabelmap(modifierSegmentLabelmap)
          slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(invertedModifierSegmentLabelmap, segmentationNode, selectedSegmentID,
            slicer.vtkSlicerSegmentationsModuleLogic.MODE_MERGE_MIN, modifierSegmentLabelmap.GetExtent())
        else:
          self.scriptedEffect.modifySelectedSegmentByLabelmap(modifierSegmentLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeRemove)
      elif operation == LOGICAL_INTERSECT:
        selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap()
        intersectionLabelmap = vtkSegmentationCore.vtkOrientedImageData()
        vtkSegmentationCore.vtkOrientedImageDataResample.MergeImage(selectedSegmentLabelmap, modifierSegmentLabelmap, intersectionLabelmap, vtkSegmentationCore.vtkOrientedImageDataResample.OPERATION_MINIMUM, selectedSegmentLabelmap.GetExtent())
        selectedSegmentLabelmapExtent = selectedSegmentLabelmap.GetExtent()
        modifierSegmentLabelmapExtent = modifierSegmentLabelmap.GetExtent()
        commonExtent = [max(selectedSegmentLabelmapExtent[0], modifierSegmentLabelmapExtent[0]),
          min(selectedSegmentLabelmapExtent[1], modifierSegmentLabelmapExtent[1]),
          max(selectedSegmentLabelmapExtent[2], modifierSegmentLabelmapExtent[2]),
          min(selectedSegmentLabelmapExtent[3], modifierSegmentLabelmapExtent[3]),
          max(selectedSegmentLabelmapExtent[4], modifierSegmentLabelmapExtent[4]),
          min(selectedSegmentLabelmapExtent[5], modifierSegmentLabelmapExtent[5])]
        if bypassMasking:
          slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(intersectionLabelmap, segmentationNode, selectedSegmentID,
            slicer.vtkSlicerSegmentationsModuleLogic.MODE_REPLACE, commonExtent)
        else:
          self.scriptedEffect.modifySelectedSegmentByLabelmap(intersectionLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet, commonExtent)

    elif operation == LOGICAL_INVERT:
      selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap()
      invertedSelectedSegmentLabelmap = self.getInvertedBinaryLabelmap(selectedSegmentLabelmap)
      if bypassMasking:
        slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(
          invertedSelectedSegmentLabelmap, segmentationNode, selectedSegmentID, slicer.vtkSlicerSegmentationsModuleLogic.MODE_REPLACE)
      else:
        self.scriptedEffect.modifySelectedSegmentByLabelmap(invertedSelectedSegmentLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet)

    elif operation == LOGICAL_CLEAR or operation == LOGICAL_FILL:
      selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap()
      vtkSegmentationCore.vtkOrientedImageDataResample.FillImage(selectedSegmentLabelmap, 1 if operation == LOGICAL_FILL else 0, selectedSegmentLabelmap.GetExtent())
      if bypassMasking:
        slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(
          selectedSegmentLabelmap, segmentationNode, selectedSegmentID, slicer.vtkSlicerSegmentationsModuleLogic.MODE_REPLACE)
      else:
        self.scriptedEffect.modifySelectedSegmentByLabelmap(selectedSegmentLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet)

    else:
      logging.error("Uknown operation: {0}".format(operation))
예제 #29
0
  def addGrayscaleVolumeStatistics(self):
    import vtkSegmentationCorePython as vtkSegmentationCore

    containsLabelmapRepresentation = self.segmentationNode.GetSegmentation().ContainsRepresentation(
      vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationBinaryLabelmapRepresentationName())
    if not containsLabelmapRepresentation:
      return

    if self.grayscaleNode is None or self.grayscaleNode.GetImageData() is None:
      return

    # Get geometry of grayscale volume node as oriented image data
    referenceGeometry_Reference = vtkSegmentationCore.vtkOrientedImageData() # reference geometry in reference node coordinate system
    referenceGeometry_Reference.SetExtent(self.grayscaleNode.GetImageData().GetExtent())
    ijkToRasMatrix = vtk.vtkMatrix4x4()
    self.grayscaleNode.GetIJKToRASMatrix(ijkToRasMatrix)
    referenceGeometry_Reference.SetGeometryFromImageToWorldMatrix(ijkToRasMatrix)

    # Get transform between grayscale volume and segmentation
    segmentationToReferenceGeometryTransform = vtk.vtkGeneralTransform()
    slicer.vtkMRMLTransformNode.GetTransformBetweenNodes(self.segmentationNode.GetParentTransformNode(),
      self.grayscaleNode.GetParentTransformNode(), segmentationToReferenceGeometryTransform)

    cubicMMPerVoxel = reduce(lambda x,y: x*y, referenceGeometry_Reference.GetSpacing())
    ccPerCubicMM = 0.001

    for segmentID in self.statistics["SegmentIDs"]:
      segment = self.segmentationNode.GetSegmentation().GetSegment(segmentID)
      segmentLabelmap = segment.GetRepresentation(vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationBinaryLabelmapRepresentationName())

      segmentLabelmap_Reference = vtkSegmentationCore.vtkOrientedImageData()
      vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
        segmentLabelmap, referenceGeometry_Reference, segmentLabelmap_Reference,
        False, # nearest neighbor interpolation
        False, # no padding
        segmentationToReferenceGeometryTransform)

      # We need to know exactly the value of the segment voxels, apply threshold to make force the selected label value
      labelValue = 1
      backgroundValue = 0
      thresh = vtk.vtkImageThreshold()
      thresh.SetInputData(segmentLabelmap_Reference)
      thresh.ThresholdByLower(0)
      thresh.SetInValue(backgroundValue)
      thresh.SetOutValue(labelValue)
      thresh.SetOutputScalarType(vtk.VTK_UNSIGNED_CHAR)
      thresh.Update()

      #  Use binary labelmap as a stencil
      stencil = vtk.vtkImageToImageStencil()
      stencil.SetInputData(thresh.GetOutput())
      stencil.ThresholdByUpper(labelValue)
      stencil.Update()

      stat = vtk.vtkImageAccumulate()
      stat.SetInputData(self.grayscaleNode.GetImageData())
      stat.SetStencilData(stencil.GetOutput())
      stat.Update()

      # Add data to statistics list
      self.statistics[segmentID,"GS voxel count"] = stat.GetVoxelCount()
      self.statistics[segmentID,"GS volume mm3"] = stat.GetVoxelCount() * cubicMMPerVoxel
      self.statistics[segmentID,"GS volume cc"] = stat.GetVoxelCount() * cubicMMPerVoxel * ccPerCubicMM
      if stat.GetVoxelCount()>0:
        self.statistics[segmentID,"GS min"] = stat.GetMin()[0]
        self.statistics[segmentID,"GS max"] = stat.GetMax()[0]
        self.statistics[segmentID,"GS mean"] = stat.GetMean()[0]
        self.statistics[segmentID,"GS stdev"] = stat.GetStandardDeviation()[0]
예제 #30
0
  def TestSection_1_AddRemoveSegment(self):
    # Add/remove segment from segmentation (check display properties, color table, etc.)
    logging.info('Test section 1: Add/remove segment')

    # Get baseline values
    displayNode = self.inputSegmentationNode.GetDisplayNode()
    self.assertIsNotNone(displayNode)
    # If segments are not found then the returned color is the pre-defined invalid color
    bodyColor = self.inputSegmentationNode.GetSegmentation().GetSegment('Body_Contour').GetColor()
    logging.info("bodyColor: {0}".format(bodyColor))
    self.assertEqual(int(bodyColor[0]*100), 33)
    self.assertEqual(int(bodyColor[1]*100), 66)
    self.assertEqual(int(bodyColor[2]*100), 0)
    tumorColor = self.inputSegmentationNode.GetSegmentation().GetSegment('Tumor_Contour').GetColor()
    logging.info("tumorColor: {0}".format(tumorColor))
    self.assertEqual(int(tumorColor[0]*100), 100)
    self.assertEqual(int(tumorColor[1]*100), 0)
    self.assertEqual(int(tumorColor[2]*100), 0)

    # Create new segment
    sphere = vtk.vtkSphereSource()
    sphere.SetCenter(0,50,0)
    sphere.SetRadius(50)
    sphere.Update()
    spherePolyData = vtk.vtkPolyData()
    spherePolyData.DeepCopy(sphere.GetOutput())

    self.sphereSegment = vtkSegmentationCore.vtkSegment()
    self.sphereSegment.SetName(self.sphereSegmentName)
    self.sphereSegment.SetColor(0.0,0.0,1.0)
    self.sphereSegment.AddRepresentation(self.closedSurfaceReprName, spherePolyData)

    # Add segment to segmentation
    self.inputSegmentationNode.GetSegmentation().AddSegment(self.sphereSegment)
    self.assertEqual(self.inputSegmentationNode.GetSegmentation().GetNumberOfSegments(), 3)

    # Check merged labelmap
    mergedLabelmap = vtkSegmentationCore.vtkOrientedImageData()
    self.inputSegmentationNode.GetSegmentation().CreateRepresentation(self.binaryLabelmapReprName)
    self.inputSegmentationNode.GenerateMergedLabelmapForAllSegments(mergedLabelmap, 0)
    imageStat = vtk.vtkImageAccumulate()
    imageStat.SetInputData(mergedLabelmap)
    imageStat.SetComponentExtent(0,4,0,0,0,0)
    imageStat.SetComponentOrigin(0,0,0)
    imageStat.SetComponentSpacing(1,1,1)
    imageStat.Update()
    self.assertEqual(imageStat.GetVoxelCount(), 1000)
    imageStatResult = imageStat.GetOutput()
    for i in range(4):
      logging.info("Volume {0}: {1}".format(i, imageStatResult.GetScalarComponentAsDouble(i,0,0,0)))
    self.assertEqual(imageStatResult.GetScalarComponentAsDouble(0,0,0,0), 795)
    self.assertEqual(imageStatResult.GetScalarComponentAsDouble(1,0,0,0), 194)
    self.assertEqual(imageStatResult.GetScalarComponentAsDouble(2,0,0,0), 4)
    self.assertEqual(imageStatResult.GetScalarComponentAsDouble(3,0,0,0), 7)

    # Check if segment reorder is taken into account in merged labelmap generation
    # Change segment order
    sphereSegmentId = self.inputSegmentationNode.GetSegmentation().GetSegmentIdBySegment(self.sphereSegment)
    self.inputSegmentationNode.GetSegmentation().SetSegmentIndex(sphereSegmentId, 1)
    # Re-generate merged labelmap
    self.inputSegmentationNode.GenerateMergedLabelmapForAllSegments(mergedLabelmap, 0)
    imageStat.SetInputData(mergedLabelmap)
    imageStat.Update()
    self.assertEqual(imageStat.GetVoxelCount(), 1000)
    imageStatResult = imageStat.GetOutput()
    for i in range(4):
      logging.info("Volume {0}: {1}".format(i, imageStatResult.GetScalarComponentAsDouble(i,0,0,0)))
    self.assertEqual(imageStatResult.GetScalarComponentAsDouble(0,0,0,0), 795)
    self.assertEqual(imageStatResult.GetScalarComponentAsDouble(1,0,0,0), 194)
    self.assertEqual(imageStatResult.GetScalarComponentAsDouble(2,0,0,0), 6)
    self.assertEqual(imageStatResult.GetScalarComponentAsDouble(3,0,0,0), 5)

    # Remove segment from segmentation
    self.inputSegmentationNode.GetSegmentation().RemoveSegment(self.sphereSegmentName)
    self.assertEqual(self.inputSegmentationNode.GetSegmentation().GetNumberOfSegments(), 2)
예제 #31
0
    def onApply(self):

        import vtkSegmentationCorePython as vtkSegmentationCore

        # Allow users revert to this state by clicking Undo
        self.scriptedEffect.saveStateForUndo()

        # This can be a long operation - indicate it to the user
        qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor)

        if self.segmentMarkupNode and (
                self.segmentModel.GetPolyData().GetNumberOfPolys() > 0):
            self.observeSegmentation(False)
            operationName = self.scriptedEffect.parameter("Operation")
            modifierLabelmap = self.scriptedEffect.defaultModifierLabelmap()
            segmentationNode = self.scriptedEffect.parameterSetNode(
            ).GetSegmentationNode()
            WorldToModifierLabelmapIjkTransform = vtk.vtkTransform()

            WorldToModifierLabelmapIjkTransformer = vtk.vtkTransformPolyDataFilter(
            )
            WorldToModifierLabelmapIjkTransformer.SetTransform(
                WorldToModifierLabelmapIjkTransform)
            WorldToModifierLabelmapIjkTransformer.SetInputConnection(
                self.segmentModel.GetPolyDataConnection())

            segmentationToSegmentationIjkTransformMatrix = vtk.vtkMatrix4x4()
            modifierLabelmap.GetImageToWorldMatrix(
                segmentationToSegmentationIjkTransformMatrix)
            segmentationToSegmentationIjkTransformMatrix.Invert()
            WorldToModifierLabelmapIjkTransform.Concatenate(
                segmentationToSegmentationIjkTransformMatrix)

            worldToSegmentationTransformMatrix = vtk.vtkMatrix4x4()
            slicer.vtkMRMLTransformNode.GetMatrixTransformBetweenNodes(
                None, segmentationNode.GetParentTransformNode(),
                worldToSegmentationTransformMatrix)
            WorldToModifierLabelmapIjkTransform.Concatenate(
                worldToSegmentationTransformMatrix)
            WorldToModifierLabelmapIjkTransformer.Update()

            polyToStencil = vtk.vtkPolyDataToImageStencil()
            polyToStencil.SetOutputSpacing(1.0, 1.0, 1.0)
            polyToStencil.SetInputConnection(
                WorldToModifierLabelmapIjkTransformer.GetOutputPort())
            boundsIjk = WorldToModifierLabelmapIjkTransformer.GetOutput(
            ).GetBounds()
            modifierLabelmapExtent = self.scriptedEffect.modifierLabelmap(
            ).GetExtent()
            polyToStencil.SetOutputWholeExtent(modifierLabelmapExtent[0],
                                               modifierLabelmapExtent[1],
                                               modifierLabelmapExtent[2],
                                               modifierLabelmapExtent[3],
                                               int(round(boundsIjk[4])),
                                               int(round(boundsIjk[5])))
            polyToStencil.Update()

            stencilData = polyToStencil.GetOutput()
            stencilExtent = [0, -1, 0, -1, 0, -1]
            stencilData.SetExtent(stencilExtent)

            stencilToImage = vtk.vtkImageStencilToImage()
            stencilToImage.SetInputConnection(polyToStencil.GetOutputPort())
            if operationName in ("FILL_INSIDE", "ERASE_INSIDE", "SET"):
                stencilToImage.SetInsideValue(1.0)
                stencilToImage.SetOutsideValue(0.0)
            else:
                stencilToImage.SetInsideValue(0.0)
                stencilToImage.SetOutsideValue(1.0)
            stencilToImage.SetOutputScalarType(
                modifierLabelmap.GetScalarType())

            stencilPositioner = vtk.vtkImageChangeInformation()
            stencilPositioner.SetInputConnection(
                stencilToImage.GetOutputPort())
            stencilPositioner.SetOutputSpacing(modifierLabelmap.GetSpacing())
            stencilPositioner.SetOutputOrigin(modifierLabelmap.GetOrigin())

            stencilPositioner.Update()
            orientedStencilPositionerOuput = vtkSegmentationCore.vtkOrientedImageData(
            )
            orientedStencilPositionerOuput.ShallowCopy(
                stencilToImage.GetOutput())
            imageToWorld = vtk.vtkMatrix4x4()
            modifierLabelmap.GetImageToWorldMatrix(imageToWorld)
            orientedStencilPositionerOuput.SetImageToWorldMatrix(imageToWorld)

            vtkSegmentationCore.vtkOrientedImageDataResample.ModifyImage(
                modifierLabelmap, orientedStencilPositionerOuput,
                vtkSegmentationCore.vtkOrientedImageDataResample.
                OPERATION_MAXIMUM)

            modMode = slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeAdd
            if operationName == "ERASE_INSIDE" or operationName == "ERASE_OUTSIDE":
                modMode = slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeRemove
            elif operationName == "SET":
                modMode = slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet

            self.scriptedEffect.modifySelectedSegmentByLabelmap(
                modifierLabelmap, modMode)

            import numpy
            n = self.segmentMarkupNode.GetNumberOfFiducials()
            # get fiducial positions
            fPos = numpy.zeros((n, 3))
            for i in xrange(n):
                coord = [0.0, 0.0, 0.0]
                self.segmentMarkupNode.GetNthFiducialPosition(i, coord)
                fPos[i] = coord
            segmentID = self.scriptedEffect.parameterSetNode(
            ).GetSelectedSegmentID()
            segment = segmentationNode.GetSegmentation().GetSegment(segmentID)
            segment.SetTag("fP", fPos.tostring())
            segment.SetTag("fN", n)

        self.reset()
        self.createNewMarkupNode()
        self.fiducialPlacementToggle.setCurrentNode(self.segmentMarkupNode)
        self.observeSegmentation(True)
        qt.QApplication.restoreOverrideCursor()
예제 #32
0
  def smoothMultipleSegments(self):
    import vtkSegmentationCorePython as vtkSegmentationCore

    # Generate merged labelmap of all visible segments
    segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()
    visibleSegmentIds = vtk.vtkStringArray()
    segmentationNode.GetDisplayNode().GetVisibleSegmentIDs(visibleSegmentIds)
    if visibleSegmentIds.GetNumberOfValues() == 0:
      logging.info("Smoothing operation skipped: there are no visible segments")
      return

    mergedImage = vtkSegmentationCore.vtkOrientedImageData()
    if not segmentationNode.GenerateMergedLabelmapForAllSegments(mergedImage,
                                                                 vtkSegmentationCore.vtkSegmentation.EXTENT_UNION_OF_SEGMENTS_PADDED,
                                                                 None, visibleSegmentIds):
      logging.error('Failed to apply smoothing: cannot get list of visible segments')
      return

    segmentLabelValues = [] # list of [segmentId, labelValue]
    for i in range(visibleSegmentIds.GetNumberOfValues()):
      segmentId = visibleSegmentIds.GetValue(i)
      segmentLabelValues.append([segmentId, i+1])

    # Perform smoothing in voxel space
    ici = vtk.vtkImageChangeInformation()
    ici.SetInputData(mergedImage)
    ici.SetOutputSpacing(1, 1, 1)
    ici.SetOutputOrigin(0, 0, 0)

    # Convert labelmap to combined polydata
    # vtkDiscreteFlyingEdges3D cannot be used here, as in the output of that filter,
    # each labeled region is completely disconnected from neighboring regions, and
    # for joint smoothing it is essential for the points to move together.
    convertToPolyData = vtk.vtkDiscreteMarchingCubes()
    convertToPolyData.SetInputConnection(ici.GetOutputPort())
    convertToPolyData.SetNumberOfContours(len(segmentLabelValues))

    contourIndex = 0
    for segmentId, labelValue in segmentLabelValues:
      convertToPolyData.SetValue(contourIndex, labelValue)
      contourIndex += 1

    # Low-pass filtering using Taubin's method
    smoothingFactor = self.scriptedEffect.doubleParameter("JointTaubinSmoothingFactor")
    smoothingIterations = 100 #  according to VTK documentation 10-20 iterations could be enough but we use a higher value to reduce chance of shrinking
    passBand = pow(10.0, -4.0*smoothingFactor) # gives a nice range of 1-0.0001 from a user input of 0-1
    smoother = vtk.vtkWindowedSincPolyDataFilter()
    smoother.SetInputConnection(convertToPolyData.GetOutputPort())
    smoother.SetNumberOfIterations(smoothingIterations)
    smoother.BoundarySmoothingOff()
    smoother.FeatureEdgeSmoothingOff()
    smoother.SetFeatureAngle(90.0)
    smoother.SetPassBand(passBand)
    smoother.NonManifoldSmoothingOn()
    smoother.NormalizeCoordinatesOn()

    # Extract a label
    threshold = vtk.vtkThreshold()
    threshold.SetInputConnection(smoother.GetOutputPort())

    # Convert to polydata
    geometryFilter = vtk.vtkGeometryFilter()
    geometryFilter.SetInputConnection(threshold.GetOutputPort())

    # Convert polydata to stencil
    polyDataToImageStencil = vtk.vtkPolyDataToImageStencil()
    polyDataToImageStencil.SetInputConnection(geometryFilter.GetOutputPort())
    polyDataToImageStencil.SetOutputSpacing(1,1,1)
    polyDataToImageStencil.SetOutputOrigin(0,0,0)
    polyDataToImageStencil.SetOutputWholeExtent(mergedImage.GetExtent())

    # Convert stencil to image
    stencil = vtk.vtkImageStencil()
    emptyBinaryLabelMap = vtk.vtkImageData()
    emptyBinaryLabelMap.SetExtent(mergedImage.GetExtent())
    emptyBinaryLabelMap.AllocateScalars(vtk.VTK_UNSIGNED_CHAR, 1)
    vtkSegmentationCore.vtkOrientedImageDataResample.FillImage(emptyBinaryLabelMap, 0)
    stencil.SetInputData(emptyBinaryLabelMap)
    stencil.SetStencilConnection(polyDataToImageStencil.GetOutputPort())
    stencil.ReverseStencilOn()
    stencil.SetBackgroundValue(1) # General foreground value is 1 (background value because of reverse stencil)

    imageToWorldMatrix = vtk.vtkMatrix4x4()
    mergedImage.GetImageToWorldMatrix(imageToWorldMatrix)

    for segmentId, labelValue in segmentLabelValues:
      threshold.ThresholdBetween(labelValue, labelValue)
      stencil.Update()
      smoothedBinaryLabelMap = vtkSegmentationCore.vtkOrientedImageData()
      smoothedBinaryLabelMap.ShallowCopy(stencil.GetOutput())
      smoothedBinaryLabelMap.SetImageToWorldMatrix(imageToWorldMatrix)
      # Write results to segments directly, bypassing masking
      slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(smoothedBinaryLabelMap,
        segmentationNode, segmentId, slicer.vtkSlicerSegmentationsModuleLogic.MODE_REPLACE, smoothedBinaryLabelMap.GetExtent())
예제 #33
0
    def jumpToSegmentAndCreateScreenShot(segmentationNode,
                                         segment,
                                         widgets,
                                         center=False,
                                         crosshair=False):
        imageData = vtkSegmentationCore.vtkOrientedImageData()
        segmentID = segmentationNode.GetSegmentation().GetSegmentIdBySegment(
            segment)
        segmentationsLogic = slicer.modules.segmentations.logic()
        segmentationsLogic.GetSegmentBinaryLabelmapRepresentation(
            segmentationNode, segmentID, imageData)
        extent = imageData.GetExtent()
        if extent[1] != -1 and extent[3] != -1 and extent[5] != -1:
            tempLabel = slicer.vtkMRMLLabelMapVolumeNode()
            slicer.mrmlScene.AddNode(tempLabel)
            tempLabel.SetName(segment.GetName() + "CentroidHelper")
            segmentationsLogic.CreateLabelmapVolumeFromOrientedImageData(
                imageData, tempLabel)
            CustomSegmentEditorLogic.applyThreshold(tempLabel, 1)
            centroid = ModuleLogicMixin.getCentroidForLabel(tempLabel, 1)
            slicer.mrmlScene.RemoveNode(tempLabel)

            annotationNodes = []

            crosshairButton = None
            if crosshair:
                crosshairButton = CrosshairButton()
                crosshairButton.setSliceIntersectionEnabled(True)
                crosshairButton.checked = True

            for widget in widgets:
                sliceLogic = widget.sliceLogic()
                sliceNode = sliceLogic.GetSliceNode()

                if not center:
                    sliceNode.JumpSliceByOffsetting(centroid[0], centroid[1],
                                                    centroid[2])
                else:
                    markupsLogic = slicer.modules.markups.logic()
                    markupsLogic.JumpSlicesToLocation(centroid[0], centroid[1],
                                                      centroid[2], True)

                dNodeProperties = ScreenShotHelper.saveSegmentDisplayProperties(
                    segmentationNode, segment)
                segmentationNode.GetDisplayNode().SetAllSegmentsVisibility(
                    False)
                ScreenShotHelper.setDisplayNodeProperties(segmentationNode,
                                                          segment,
                                                          properties={
                                                              'fill': True,
                                                              'outline': True,
                                                              'visible': True
                                                          })

                if crosshairButton:
                    crosshairButton.crosshairNode.SetCrosshairRAS(centroid)

                annotationNode = ScreenShotHelper.takeScreenShot(
                    "{}_Screenshot_{}_{}".format(segment.GetName(),
                                                 sliceNode.GetName(),
                                                 sliceNode.GetOrientation()),
                    "", widget)
                segmentationNode.GetDisplayNode().SetAllSegmentsVisibility(
                    True)
                ScreenShotHelper.setDisplayNodeProperties(
                    segmentationNode, segment, dNodeProperties)
                annotationNodes.append(annotationNode)
                if crosshairButton:
                    crosshairButton.checked = False

            return annotationNodes[0] if len(
                annotationNodes) == 1 else annotationNodes
예제 #34
0
    def exportAsDICOMSEG(self, exportablesCollection):
        """Export the given node to a segmentation object and load it in the
    DICOM database

    This function was copied and modified from the EditUtil.py function of the same name in Slicer.
    """

        if hasattr(slicer.modules, 'segmentations'):

            exportable = exportablesCollection.GetItemAsObject(0)
            subjectHierarchyNode = slicer.mrmlScene.GetNodeByID(
                exportable.GetNodeID())

            instanceUIDs = subjectHierarchyNode.GetAttribute(
                "DICOM.ReferencedInstanceUIDs").split()

            if instanceUIDs == "":
                raise Exception(
                    "Editor master node does not have DICOM information")

            # get the list of source DICOM files
            inputDICOMImageFileNames = ""
            for instanceUID in instanceUIDs:
                inputDICOMImageFileNames += slicer.dicomDatabase.fileForInstance(
                    instanceUID) + ","
            inputDICOMImageFileNames = inputDICOMImageFileNames[:
                                                                -1]  # strip last comma

            # save the per-structure volumes in the temp directory
            inputSegmentationsFileNames = ""

            import random  # TODO: better way to generate temp file names?
            import vtkITK
            writer = vtkITK.vtkITKImageWriter()
            rasToIJKMatrix = vtk.vtkMatrix4x4()

            import vtkSegmentationCore
            import vtkSlicerSegmentationsModuleLogic
            logic = vtkSlicerSegmentationsModuleLogic.vtkSlicerSegmentationsModuleLogic(
            )

            segmentationNode = subjectHierarchyNode.GetAssociatedNode()

            mergedSegmentationImageData = segmentationNode.GetImageData()
            mergedSegmentationLabelmapNode = slicer.vtkMRMLLabelMapVolumeNode()

            segmentationNode.GetRASToIJKMatrix(rasToIJKMatrix)
            mergedSegmentationLabelmapNode.SetRASToIJKMatrix(rasToIJKMatrix)
            mergedSegmentationLabelmapNode.SetAndObserveImageData(
                mergedSegmentationImageData)
            mergedSegmentationOrientedImageData = logic.CreateOrientedImageDataFromVolumeNode(
                mergedSegmentationLabelmapNode)

            segmentation = segmentationNode.GetSegmentation()

            segmentIDs = vtk.vtkStringArray()
            segmentation.GetSegmentIDs(segmentIDs)
            segmentationName = segmentationNode.GetName()

            for i in range(0, segmentIDs.GetNumberOfValues()):
                segmentID = segmentIDs.GetValue(i)
                segment = segmentation.GetSegment(segmentID)

                segmentName = segment.GetName()
                structureName = segmentName[len(segmentationName) + 1:-1 *
                                            len('-label')]

                structureFileName = structureName + str(
                    random.randint(0, vtk.VTK_INT_MAX)) + ".nrrd"
                filePath = os.path.join(slicer.app.temporaryPath,
                                        structureFileName)
                writer.SetFileName(filePath)

                segmentImageData = segment.GetRepresentation(
                    vtkSegmentationCore.vtkSegmentationConverter.
                    GetSegmentationBinaryLabelmapRepresentationName())
                paddedImageData = vtkSegmentationCore.vtkOrientedImageData()
                vtkSegmentationCore.vtkOrientedImageDataResample.PadImageToContainImage(
                    segmentImageData, mergedSegmentationOrientedImageData,
                    paddedImageData)

                labelmapImageData = slicer.vtkMRMLLabelMapVolumeNode()
                logic.CreateLabelmapVolumeFromOrientedImageData(
                    paddedImageData, labelmapImageData)

                writer.SetInputDataObject(labelmapImageData.GetImageData())

                labelmapImageData.GetRASToIJKMatrix(rasToIJKMatrix)
                writer.SetRasToIJKMatrix(rasToIJKMatrix)
                logging.debug("Saving to %s..." % filePath)
                writer.Write()
                inputSegmentationsFileNames += filePath + ","
            inputSegmentationsFileNames = inputSegmentationsFileNames[:
                                                                      -1]  # strip last comma

            # save the per-structure volumes label attributes
            colorNode = segmentationNode.GetNodeReference('colorNodeID')

            terminologyName = colorNode.GetAttribute("TerminologyName")
            colorLogic = slicer.modules.colors.logic()
            if not terminologyName or not colorLogic:
                raise Exception(
                    "No terminology or color logic - cannot export")

            inputLabelAttributesFileNames = ""

            for i in range(0, segmentIDs.GetNumberOfValues()):
                segmentID = segmentIDs.GetValue(i)
                segment = segmentation.GetSegment(segmentID)

                segmentName = segment.GetName()
                structureName = segmentName[len(segmentationName) + 1:-1 *
                                            len('-label')]
                labelIndex = colorNode.GetColorIndexByName(structureName)

                rgbColor = [
                    0,
                ] * 4
                colorNode.GetColor(labelIndex, rgbColor)
                rgbColor = map(lambda e: e * 255., rgbColor)

                # get the attributes and convert to format CodeValue,CodeMeaning,CodingSchemeDesignator
                # or empty strings if not defined
                propertyCategoryWithColons = colorLogic.GetSegmentedPropertyCategory(
                    labelIndex, terminologyName)
                if propertyCategoryWithColons == '':
                    logging.debug(
                        'ERROR: no segmented property category found for label ',
                        str(labelIndex))
                    # Try setting a default as this section is required
                    propertyCategory = "C94970,NCIt,Reference Region"
                else:
                    propertyCategory = propertyCategoryWithColons.replace(
                        ':', ',')

                propertyTypeWithColons = colorLogic.GetSegmentedPropertyType(
                    labelIndex, terminologyName)
                propertyType = propertyTypeWithColons.replace(':', ',')

                propertyTypeModifierWithColons = colorLogic.GetSegmentedPropertyTypeModifier(
                    labelIndex, terminologyName)
                propertyTypeModifier = propertyTypeModifierWithColons.replace(
                    ':', ',')

                anatomicRegionWithColons = colorLogic.GetAnatomicRegion(
                    labelIndex, terminologyName)
                anatomicRegion = anatomicRegionWithColons.replace(':', ',')

                anatomicRegionModifierWithColons = colorLogic.GetAnatomicRegionModifier(
                    labelIndex, terminologyName)
                anatomicRegionModifier = anatomicRegionModifierWithColons.replace(
                    ':', ',')

                structureFileName = structureName + str(
                    random.randint(0, vtk.VTK_INT_MAX)) + ".info"
                filePath = os.path.join(slicer.app.temporaryPath,
                                        structureFileName)

                # EncodeSEG is expecting a file of format:
                # labelNum;SegmentedPropertyCategory:codeValue,codeScheme,codeMeaning;SegmentedPropertyType:v,m,s etc
                attributes = "%d" % labelIndex
                attributes += ";SegmentedPropertyCategory:" + propertyCategory
                if propertyType != "":
                    attributes += ";SegmentedPropertyType:" + propertyType
                if propertyTypeModifier != "":
                    attributes += ";SegmentedPropertyTypeModifier:" + propertyTypeModifier
                if anatomicRegion != "":
                    attributes += ";AnatomicRegion:" + anatomicRegion
                if anatomicRegionModifier != "":
                    attributes += ";AnatomicRegionModifier:" + anatomicRegionModifier
                attributes += ";SegmentAlgorithmType:AUTOMATIC"
                attributes += ";SegmentAlgorithmName:SlicerSelfTest"
                attributes += ";RecommendedDisplayRGBValue:%g,%g,%g" % tuple(
                    rgbColor[:-1])
                fp = open(filePath, "w")
                fp.write(attributes)
                fp.close()
                logging.debug("filePath: %s", filePath)
                logging.debug("attributes: %s", attributes)
                inputLabelAttributesFileNames += filePath + ","
            inputLabelAttributesFileNames = inputLabelAttributesFileNames[:
                                                                          -1]  # strip last comma'''

            try:
                user = os.environ['USER']
            except KeyError:
                user = "******"
            segFileName = "editor_export.SEG" + str(
                random.randint(0, vtk.VTK_INT_MAX)) + ".dcm"
            segFilePath = os.path.join(slicer.app.temporaryPath, segFileName)
            # TODO: define a way to set parameters like description
            # TODO: determine a good series number automatically by looking in the database
            parameters = {
                "inputDICOMImageFileNames": inputDICOMImageFileNames,
                "inputSegmentationsFileNames": inputSegmentationsFileNames,
                "inputLabelAttributesFileNames": inputLabelAttributesFileNames,
                "readerId": user,
                "sessionId": "1",
                "timePointId": "1",
                "seriesDescription": "SlicerEditorSEGExport",
                "seriesNumber": "100",
                "instanceNumber": "1",
                "bodyPart": "HEAD",
                "algorithmDescriptionFileName": "Editor",
                "outputSEGFileName": segFilePath,
                "skipEmptySlices": False,
                "compress": False,
            }

            encodeSEG = slicer.modules.encodeseg
            cliNode = None

            cliNode = slicer.cli.run(encodeSEG,
                                     cliNode,
                                     parameters,
                                     delete_temporary_files=False)
            waitCount = 0
            while cliNode.IsBusy() and waitCount < 20:
                slicer.util.delayDisplay(
                    "Running SEG Encoding... %d" % waitCount, 1000)
                waitCount += 1

            if cliNode.GetStatusString() != 'Completed':
                raise Exception("encodeSEG CLI did not complete cleanly")

            logging.info("Added segmentation to DICOM database (%s)",
                         segFilePath)
            slicer.dicomDatabase.insert(segFilePath)
  def processInteractionEvents(self, callerInteractor, eventId, viewWidget):
    abortEvent = False

    # Only allow for slice views
    if viewWidget.className() != "qMRMLSliceWidget":
      return abortEvent

    if eventId == vtk.vtkCommand.LeftButtonPressEvent:
      self.scriptedEffect.saveStateForUndo()

      # Get master volume image data
      import vtkSegmentationCorePython as vtkSegmentationCore
      masterImageData = self.scriptedEffect.masterVolumeImageData()
      selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap()

      # Get modifier labelmap
      modifierLabelmap = self.scriptedEffect.defaultModifierLabelmap()

      xy = callerInteractor.GetEventPosition()
      ijk = self.xyToIjk(xy, viewWidget, masterImageData)

      pixelValue = masterImageData.GetScalarComponentAsFloat(ijk[0], ijk[1], ijk[2], 0)      
      
      useSegmentationAsStencil = False
      
      try:

        # This can be a long operation - indicate it to the user
        qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor)

        # Perform thresholding
        floodFillingFilter = vtk.vtkImageThresholdConnectivity()
        floodFillingFilter.SetInputData(masterImageData)
        seedPoints = vtk.vtkPoints()
        origin = masterImageData.GetOrigin()
        spacing = masterImageData.GetSpacing()
        seedPoints.InsertNextPoint(origin[0]+ijk[0]*spacing[0], origin[1]+ijk[1]*spacing[1], origin[2]+ijk[2]*spacing[2])
        floodFillingFilter.SetSeedPoints(seedPoints)

        maskImageData = vtkSegmentationCore.vtkOrientedImageData()
        intensityBasedMasking = self.scriptedEffect.parameterSetNode().GetMasterVolumeIntensityMask()
        segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()
        success = segmentationNode.GenerateEditMask(maskImageData,
          self.scriptedEffect.parameterSetNode().GetMaskMode(),
          masterImageData, # reference geometry
          self.scriptedEffect.parameterSetNode().GetSelectedSegmentID(),
          self.scriptedEffect.parameterSetNode().GetMaskSegmentID() if self.scriptedEffect.parameterSetNode().GetMaskSegmentID() else "",
          masterImageData if intensityBasedMasking else None,
          self.scriptedEffect.parameterSetNode().GetMasterVolumeIntensityMaskRange() if intensityBasedMasking else None)
        if success:
          stencil = vtk.vtkImageToImageStencil()
          stencil.SetInputData(maskImageData)
          stencil.ThresholdByLower(0)
          stencil.Update()
          floodFillingFilter.SetStencilData(stencil.GetOutput())
        else:
          logging.error("Failed to create edit mask")
        
        neighborhoodSizeMm = self.neighborhoodSizeMmSlider.value
        floodFillingFilter.SetNeighborhoodRadius(neighborhoodSizeMm,neighborhoodSizeMm,neighborhoodSizeMm)
        floodFillingFilter.SetNeighborhoodFraction(0.5)
        
        if useSegmentationAsStencil:
          stencilFilter = vtk.vtkImageToImageStencil()
          stencilFilter.SetInputData(selectedSegmentLabelmap)
          stencilFilter.ThresholdByLower(0)
          stencilFilter.Update()          
          floodFillingFilter.SetStencilData(stencilFilter.GetOutput())

        pixelValueTolerance = float(self.intensityToleranceSlider.value)
        floodFillingFilter.ThresholdBetween(pixelValue-pixelValueTolerance, pixelValue+pixelValueTolerance)
        
        floodFillingFilter.SetInValue(1)
        floodFillingFilter.SetOutValue(0)
        floodFillingFilter.Update()
        modifierLabelmap.DeepCopy(floodFillingFilter.GetOutput())
      except IndexError:
        logging.error('apply: Failed to threshold master volume!')
      finally:
        qt.QApplication.restoreOverrideCursor() 

      # Apply changes
      self.scriptedEffect.modifySelectedSegmentByLabelmap(modifierLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeAdd)
      abortEvent = True
        
    return abortEvent
      
예제 #36
0
  def computeStatistics(self, segmentID):
    import vtkSegmentationCorePython as vtkSegmentationCore
    requestedKeys = self.getRequestedKeys()

    segmentationNode = slicer.mrmlScene.GetNodeByID(self.getParameterNode().GetParameter("Segmentation"))
    grayscaleNode = slicer.mrmlScene.GetNodeByID(self.getParameterNode().GetParameter("ScalarVolume"))

    if len(requestedKeys)==0:
      return {}

    containsLabelmapRepresentation = segmentationNode.GetSegmentation().ContainsRepresentation(
      vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationBinaryLabelmapRepresentationName())
    if not containsLabelmapRepresentation:
      return {}

    if grayscaleNode is None or grayscaleNode.GetImageData() is None:
      return {}

    # Get geometry of grayscale volume node as oriented image data
    # reference geometry in reference node coordinate system
    referenceGeometry_Reference = vtkSegmentationCore.vtkOrientedImageData()
    referenceGeometry_Reference.SetExtent(grayscaleNode.GetImageData().GetExtent())
    ijkToRasMatrix = vtk.vtkMatrix4x4()
    grayscaleNode.GetIJKToRASMatrix(ijkToRasMatrix)
    referenceGeometry_Reference.SetGeometryFromImageToWorldMatrix(ijkToRasMatrix)

    # Get transform between grayscale volume and segmentation
    segmentationToReferenceGeometryTransform = vtk.vtkGeneralTransform()
    slicer.vtkMRMLTransformNode.GetTransformBetweenNodes(segmentationNode.GetParentTransformNode(),
      grayscaleNode.GetParentTransformNode(), segmentationToReferenceGeometryTransform)

    cubicMMPerVoxel = reduce(lambda x,y: x*y, referenceGeometry_Reference.GetSpacing())
    ccPerCubicMM = 0.001

    segment = segmentationNode.GetSegmentation().GetSegment(segmentID)
    segBinaryLabelName = vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationBinaryLabelmapRepresentationName()
    segmentLabelmap = segment.GetRepresentation(segBinaryLabelName)

    segmentLabelmap_Reference = vtkSegmentationCore.vtkOrientedImageData()
    vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
      segmentLabelmap, referenceGeometry_Reference, segmentLabelmap_Reference,
      False, # nearest neighbor interpolation
      False, # no padding
      segmentationToReferenceGeometryTransform)

    # We need to know exactly the value of the segment voxels, apply threshold to make force the selected label value
    labelValue = 1
    backgroundValue = 0
    thresh = vtk.vtkImageThreshold()
    thresh.SetInputData(segmentLabelmap_Reference)
    thresh.ThresholdByLower(0)
    thresh.SetInValue(backgroundValue)
    thresh.SetOutValue(labelValue)
    thresh.SetOutputScalarType(vtk.VTK_UNSIGNED_CHAR)
    thresh.Update()

    #  Use binary labelmap as a stencil
    stencil = vtk.vtkImageToImageStencil()
    stencil.SetInputData(thresh.GetOutput())
    stencil.ThresholdByUpper(labelValue)
    stencil.Update()

    stat = vtk.vtkImageAccumulate()
    stat.SetInputData(grayscaleNode.GetImageData())
    stat.SetStencilData(stencil.GetOutput())
    stat.Update()

    # create statistics list
    stats = {}
    if "voxel_count" in requestedKeys:
      stats["voxel_count"] = stat.GetVoxelCount()
    if "volume_mm3" in requestedKeys:
      stats["volume_mm3"] = stat.GetVoxelCount() * cubicMMPerVoxel
    if "volume_cm3" in requestedKeys:
      stats["volume_cm3"] = stat.GetVoxelCount() * cubicMMPerVoxel * ccPerCubicMM
    if stat.GetVoxelCount()>0:
      if "min" in requestedKeys:
        stats["min"] = stat.GetMin()[0]
      if "max" in requestedKeys:
        stats["max"] = stat.GetMax()[0]
      if "mean" in requestedKeys:
        stats["mean"] = stat.GetMean()[0]
      if "stdev" in requestedKeys:
        stats["stdev"] = stat.GetStandardDeviation()[0]
    return stats
    def TestSection_03_qMRMLSegmentationGeometryWidget(self):
        logging.info('Test section 2: qMRMLSegmentationGeometryWidget')

        import vtkSegmentationCore
        binaryLabelmapReprName = vtkSegmentationCore.vtkSegmentationConverter.GetBinaryLabelmapRepresentationName(
        )
        closedSurfaceReprName = vtkSegmentationCore.vtkSegmentationConverter.GetClosedSurfaceRepresentationName(
        )

        # Use MRHead and Tinypatient for testing
        import SampleData
        mrVolumeNode = SampleData.downloadSample("MRHead")
        [tinyVolumeNode,
         tinySegmentationNode] = SampleData.downloadSamples('TinyPatient')

        # Convert MRHead to oriented image data
        import vtkSlicerSegmentationsModuleLogicPython as vtkSlicerSegmentationsModuleLogic
        mrOrientedImageData = vtkSlicerSegmentationsModuleLogic.vtkSlicerSegmentationsModuleLogic.CreateOrientedImageDataFromVolumeNode(
            mrVolumeNode)
        mrOrientedImageData.UnRegister(None)

        # Create segmentation node with binary labelmap master and one segment with MRHead geometry
        segmentationNode = slicer.mrmlScene.AddNewNodeByClass(
            'vtkMRMLSegmentationNode')
        segmentationNode.GetSegmentation().SetMasterRepresentationName(
            binaryLabelmapReprName)
        geometryStr = vtkSegmentationCore.vtkSegmentationConverter.SerializeImageGeometry(
            mrOrientedImageData)
        segmentationNode.GetSegmentation().SetConversionParameter(
            vtkSegmentationCore.vtkSegmentationConverter.
            GetReferenceImageGeometryParameterName(), geometryStr)

        threshold = vtk.vtkImageThreshold()
        threshold.SetInputData(mrOrientedImageData)
        threshold.ThresholdByUpper(16.0)
        threshold.SetInValue(1)
        threshold.SetOutValue(0)
        threshold.SetOutputScalarType(vtk.VTK_UNSIGNED_CHAR)
        threshold.Update()
        segmentOrientedImageData = vtkSegmentationCore.vtkOrientedImageData()
        segmentOrientedImageData.DeepCopy(threshold.GetOutput())
        mrImageToWorldMatrix = vtk.vtkMatrix4x4()
        mrOrientedImageData.GetImageToWorldMatrix(mrImageToWorldMatrix)
        segmentOrientedImageData.SetImageToWorldMatrix(mrImageToWorldMatrix)
        segment = vtkSegmentationCore.vtkSegment()
        segment.SetName('Brain')
        segment.SetColor(0.0, 0.0, 1.0)
        segment.AddRepresentation(binaryLabelmapReprName,
                                  segmentOrientedImageData)
        segmentationNode.GetSegmentation().AddSegment(segment)

        # Create geometry widget
        geometryWidget = slicer.qMRMLSegmentationGeometryWidget()
        geometryWidget.setSegmentationNode(segmentationNode)
        geometryWidget.editEnabled = True
        geometryImageData = vtkSegmentationCore.vtkOrientedImageData(
        )  # To contain the output later

        # Volume source with no transforms
        geometryWidget.setSourceNode(tinyVolumeNode)
        geometryWidget.geometryImageData(geometryImageData)
        self.assertTrue(
            self.compareOutputGeometry(
                geometryImageData, (49, 49, 23), (248.8439, 248.2890, -123.75),
                [[-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]]))
        vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
            segmentOrientedImageData, geometryImageData, geometryImageData,
            False, True)
        self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 92)

        # Transformed volume source
        translationTransformMatrix = vtk.vtkMatrix4x4()
        translationTransformMatrix.SetElement(0, 3, 24.5)
        translationTransformMatrix.SetElement(1, 3, 24.5)
        translationTransformMatrix.SetElement(2, 3, 11.5)
        translationTransformNode = slicer.vtkMRMLLinearTransformNode()
        translationTransformNode.SetName('TestTranslation')
        slicer.mrmlScene.AddNode(translationTransformNode)
        translationTransformNode.SetMatrixTransformToParent(
            translationTransformMatrix)

        tinyVolumeNode.SetAndObserveTransformNodeID(
            translationTransformNode.GetID())
        geometryWidget.geometryImageData(geometryImageData)
        self.assertTrue(
            self.compareOutputGeometry(
                geometryImageData, (49, 49, 23), (224.3439, 223.7890, -135.25),
                [[-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]]))
        vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
            segmentOrientedImageData, geometryImageData, geometryImageData,
            False, True)
        self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 94)

        # Volume source with isotropic spacing
        tinyVolumeNode.SetAndObserveTransformNodeID(None)
        geometryWidget.setIsotropicSpacing(True)
        geometryWidget.geometryImageData(geometryImageData)
        self.assertTrue(
            self.compareOutputGeometry(
                geometryImageData, (23, 23, 23), (248.8439, 248.2890, -123.75),
                [[-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]]))
        vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
            segmentOrientedImageData, geometryImageData, geometryImageData,
            False, True)
        self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 414)

        # Volume source with oversampling
        geometryWidget.setIsotropicSpacing(False)
        geometryWidget.setOversamplingFactor(2.0)
        geometryWidget.geometryImageData(geometryImageData)
        self.assertTrue(
            self.compareOutputGeometry(
                geometryImageData, (24.5, 24.5, 11.5),
                (261.0939, 260.5390, -129.5),
                [[-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]]))
        vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
            segmentOrientedImageData, geometryImageData, geometryImageData,
            False, True)
        self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 751)
        slicer.util.delayDisplay('Volume source cases - OK')

        # Segmentation source with binary labelmap master
        geometryWidget.setOversamplingFactor(1.0)
        geometryWidget.setSourceNode(tinySegmentationNode)
        geometryWidget.geometryImageData(geometryImageData)
        self.assertTrue(
            self.compareOutputGeometry(
                geometryImageData, (49, 49, 23), (248.8439, 248.2890, -123.75),
                [[-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]]))
        vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
            segmentOrientedImageData, geometryImageData, geometryImageData,
            False, True)
        self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 92)

        # Segmentation source with closed surface master
        tinySegmentationNode.GetSegmentation().SetConversionParameter(
            'Smoothing factor', '0.0')
        self.assertTrue(
            tinySegmentationNode.GetSegmentation().CreateRepresentation(
                closedSurfaceReprName))
        tinySegmentationNode.GetSegmentation().SetMasterRepresentationName(
            closedSurfaceReprName)
        tinySegmentationNode.Modified(
        )  # Trigger re-calculation of geometry (only generic Modified event is observed)
        geometryWidget.geometryImageData(geometryImageData)
        self.assertTrue(
            self.compareOutputGeometry(
                geometryImageData, (1, 1, 1), (-167.156, -217.711, -135.75),
                [[0.0, 0.0, 1.0], [-1.0, 0.0, 0.0], [0.0, -1.0, 0.0]]))
        vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
            segmentOrientedImageData, geometryImageData, geometryImageData,
            False, True)
        self.assertEqual(self.getForegroundVoxelCount(geometryImageData),
                         5223846)
        slicer.util.delayDisplay('Segmentation source cases - OK')

        # Model source with no transform
        shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(
            slicer.mrmlScene)
        outputFolderId = shNode.CreateFolderItem(shNode.GetSceneItemID(),
                                                 'ModelsFolder')
        success = vtkSlicerSegmentationsModuleLogic.vtkSlicerSegmentationsModuleLogic.ExportVisibleSegmentsToModels(
            tinySegmentationNode, outputFolderId)
        self.assertTrue(success)
        modelNode = slicer.util.getNode('Body_Contour')
        geometryWidget.setSourceNode(modelNode)
        geometryWidget.geometryImageData(geometryImageData)
        self.assertTrue(
            self.compareOutputGeometry(
                geometryImageData, (1, 1, 1), (-167.156, -217.711, -135.75),
                [[0.0, 0.0, 1.0], [-1.0, 0.0, 0.0], [0.0, -1.0, 0.0]]))
        vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
            segmentOrientedImageData, geometryImageData, geometryImageData,
            False, True)
        self.assertEqual(self.getForegroundVoxelCount(geometryImageData),
                         5223846)

        # Transformed model source
        rotationTransform = vtk.vtkTransform()
        rotationTransform.RotateX(45)
        rotationTransformMatrix = vtk.vtkMatrix4x4()
        rotationTransform.GetMatrix(rotationTransformMatrix)
        rotationTransformNode = slicer.vtkMRMLLinearTransformNode()
        rotationTransformNode.SetName('TestRotation')
        slicer.mrmlScene.AddNode(rotationTransformNode)
        rotationTransformNode.SetMatrixTransformToParent(
            rotationTransformMatrix)

        modelNode.SetAndObserveTransformNodeID(rotationTransformNode.GetID())
        modelNode.Modified()
        geometryWidget.geometryImageData(geometryImageData)
        self.assertTrue(
            self.compareOutputGeometry(
                geometryImageData, (1, 1, 1), (-167.156, -58.6623, -249.228),
                [[0.0, 0.0, 1.0], [-0.7071, -0.7071, 0.0],
                 [0.7071, -0.7071, 0.0]]))
        vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
            segmentOrientedImageData, geometryImageData, geometryImageData,
            False, True)
        self.assertEqual(self.getForegroundVoxelCount(geometryImageData),
                         5221241)

        # ROI source
        roiNode = slicer.vtkMRMLAnnotationROINode()
        roiNode.SetName('SourceROI')
        slicer.mrmlScene.AddNode(roiNode)
        roiNode.UnRegister(None)
        xyz = [0] * 3
        center = [0] * 3
        slicer.vtkMRMLSliceLogic.GetVolumeRASBox(tinyVolumeNode, xyz, center)
        radius = [x / 2.0 for x in xyz]
        roiNode.SetXYZ(center)
        roiNode.SetRadiusXYZ(radius)
        geometryWidget.setSourceNode(roiNode)
        geometryWidget.geometryImageData(geometryImageData)
        self.assertTrue(
            self.compareOutputGeometry(
                geometryImageData, (1, 1, 1), (-216.156, -217.711, -135.75),
                [[0.0, 0.0, 1.0], [-1.0, 0.0, 0.0], [0.0, -1.0, 0.0]]))
        vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
            segmentOrientedImageData, geometryImageData, geometryImageData,
            False, True)
        self.assertEqual(self.getForegroundVoxelCount(geometryImageData),
                         5223846)
        slicer.util.delayDisplay('Model and ROI source cases - OK')

        slicer.util.delayDisplay('Segmentation geometry widget test passed')
예제 #38
0
  def splitSegments(self, minimumSize = 0, maxNumberOfSegments = 0, split = True):
    """
    minimumSize: if 0 then it means that all islands are kept, regardless of size
    maxNumberOfSegments: if 0 then it means that all islands are kept, regardless of how many
    """
    # This can be a long operation - indicate it to the user
    qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor)

    self.scriptedEffect.saveStateForUndo()

    # Get modifier labelmap
    selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap()

    castIn = vtk.vtkImageCast()
    castIn.SetInputData(selectedSegmentLabelmap)
    castIn.SetOutputScalarTypeToUnsignedInt()

    # Identify the islands in the inverted volume and
    # find the pixel that corresponds to the background
    islandMath = vtkITK.vtkITKIslandMath()
    islandMath.SetInputConnection(castIn.GetOutputPort())
    islandMath.SetFullyConnected(False)
    islandMath.SetMinimumSize(minimumSize)
    islandMath.Update()

    # Create a separate image for the first (largest) island
    labelValue = 1
    backgroundValue = 0
    thresh = vtk.vtkImageThreshold()
    if split:
      thresh.ThresholdBetween(1, 1)
    else:
      if maxNumberOfSegments != 0:
        thresh.ThresholdBetween(1, maxNumberOfSegments)
      else:
        thresh.ThresholdByUpper(1)

    thresh.SetInputData(islandMath.GetOutput())
    thresh.SetOutValue(backgroundValue)
    thresh.SetInValue(labelValue)
    thresh.SetOutputScalarType(selectedSegmentLabelmap.GetScalarType())
    thresh.Update()
    # Create oriented image data from output
    import vtkSegmentationCorePython as vtkSegmentationCore
    largestIslandImage = vtkSegmentationCore.vtkOrientedImageData()
    largestIslandImage.ShallowCopy(thresh.GetOutput())
    selectedSegmentLabelmapImageToWorldMatrix = vtk.vtkMatrix4x4()
    selectedSegmentLabelmap.GetImageToWorldMatrix(selectedSegmentLabelmapImageToWorldMatrix)
    largestIslandImage.SetImageToWorldMatrix(selectedSegmentLabelmapImageToWorldMatrix)

    if split and (maxNumberOfSegments != 1):

      thresh2 = vtk.vtkImageThreshold()
      # 0 is background, 1 is largest island; we need label 2 and higher
      if maxNumberOfSegments != 0:
        thresh2.ThresholdBetween(2, maxNumberOfSegments)
      else:
        thresh2.ThresholdByUpper(2)
      thresh2.SetInputData(islandMath.GetOutput())
      thresh2.SetOutValue(backgroundValue)
      thresh2.ReplaceInOff()
      thresh2.Update()

      islandCount = islandMath.GetNumberOfIslands()
      islandOrigCount = islandMath.GetOriginalNumberOfIslands()
      ignoredIslands = islandOrigCount - islandCount
      logging.info( "%d islands created (%d ignored)" % (islandCount, ignoredIslands) )

      # Create oriented image data from output
      import vtkSegmentationCorePython as vtkSegmentationCore
      multiLabelImage = vtkSegmentationCore.vtkOrientedImageData()
      multiLabelImage.DeepCopy(thresh2.GetOutput())
      selectedSegmentLabelmapImageToWorldMatrix = vtk.vtkMatrix4x4()
      selectedSegmentLabelmap.GetImageToWorldMatrix(selectedSegmentLabelmapImageToWorldMatrix)
      multiLabelImage.SetGeometryFromImageToWorldMatrix(selectedSegmentLabelmapImageToWorldMatrix)

      # Import multi-label labelmap to segmentation
      segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()
      selectedSegmentID = self.scriptedEffect.parameterSetNode().GetSelectedSegmentID()
      selectedSegmentIndex = segmentationNode.GetSegmentation().GetSegmentIndex(selectedSegmentID)
      insertBeforeSegmentID = segmentationNode.GetSegmentation().GetNthSegmentID(selectedSegmentIndex + 1)
      selectedSegmentName = segmentationNode.GetSegmentation().GetSegment(selectedSegmentID).GetName()
      slicer.vtkSlicerSegmentationsModuleLogic.ImportLabelmapToSegmentationNode( \
        multiLabelImage, segmentationNode, selectedSegmentName+" -", insertBeforeSegmentID )

    self.scriptedEffect.modifySelectedSegmentByLabelmap(largestIslandImage, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet)

    qt.QApplication.restoreOverrideCursor()
예제 #39
0
    def TestSection_1_AddRemoveSegment(self):
        # Add/remove segment from segmentation (check display properties, color table, etc.)
        logging.info('Test section 1: Add/remove segment')

        # Get baseline values
        displayNode = self.inputSegmentationNode.GetDisplayNode()
        self.assertIsNotNone(displayNode)
        # If segments are not found then the returned color is the pre-defined invalid color
        bodyColor = self.inputSegmentationNode.GetSegmentation().GetSegment(
            'Body_Contour').GetColor()
        logging.info("bodyColor: {0}".format(bodyColor))
        self.assertEqual(int(bodyColor[0] * 100), 33)
        self.assertEqual(int(bodyColor[1] * 100), 66)
        self.assertEqual(int(bodyColor[2] * 100), 0)
        tumorColor = self.inputSegmentationNode.GetSegmentation().GetSegment(
            'Tumor_Contour').GetColor()
        logging.info("tumorColor: {0}".format(tumorColor))
        self.assertEqual(int(tumorColor[0] * 100), 100)
        self.assertEqual(int(tumorColor[1] * 100), 0)
        self.assertEqual(int(tumorColor[2] * 100), 0)

        # Create new segment
        sphere = vtk.vtkSphereSource()
        sphere.SetCenter(0, 50, 0)
        sphere.SetRadius(50)
        sphere.Update()
        spherePolyData = vtk.vtkPolyData()
        spherePolyData.DeepCopy(sphere.GetOutput())

        self.sphereSegment = vtkSegmentationCore.vtkSegment()
        self.sphereSegment.SetName(self.sphereSegmentName)
        self.sphereSegment.SetColor(0.0, 0.0, 1.0)
        self.sphereSegment.AddRepresentation(self.closedSurfaceReprName,
                                             spherePolyData)

        # Add segment to segmentation
        self.inputSegmentationNode.GetSegmentation().AddSegment(
            self.sphereSegment)
        self.assertEqual(
            self.inputSegmentationNode.GetSegmentation().GetNumberOfSegments(),
            3)

        # Check merged labelmap
        mergedLabelmap = vtkSegmentationCore.vtkOrientedImageData()
        self.inputSegmentationNode.GetSegmentation().CreateRepresentation(
            self.binaryLabelmapReprName)
        self.inputSegmentationNode.GenerateMergedLabelmapForAllSegments(
            mergedLabelmap, 0)
        imageStat = vtk.vtkImageAccumulate()
        imageStat.SetInputData(mergedLabelmap)
        imageStat.SetComponentExtent(0, 4, 0, 0, 0, 0)
        imageStat.SetComponentOrigin(0, 0, 0)
        imageStat.SetComponentSpacing(1, 1, 1)
        imageStat.Update()
        self.assertEqual(imageStat.GetVoxelCount(), 1000)
        imageStatResult = imageStat.GetOutput()
        for i in range(4):
            logging.info("Volume {0}: {1}".format(
                i, imageStatResult.GetScalarComponentAsDouble(i, 0, 0, 0)))
        self.assertEqual(
            imageStatResult.GetScalarComponentAsDouble(0, 0, 0, 0), 795)
        self.assertEqual(
            imageStatResult.GetScalarComponentAsDouble(1, 0, 0, 0), 194)
        self.assertEqual(
            imageStatResult.GetScalarComponentAsDouble(2, 0, 0, 0), 4)
        self.assertEqual(
            imageStatResult.GetScalarComponentAsDouble(3, 0, 0, 0), 7)

        # Check if segment reorder is taken into account in merged labelmap generation
        # Change segment order
        sphereSegmentId = self.inputSegmentationNode.GetSegmentation(
        ).GetSegmentIdBySegment(self.sphereSegment)
        self.inputSegmentationNode.GetSegmentation().SetSegmentIndex(
            sphereSegmentId, 1)
        # Re-generate merged labelmap
        self.inputSegmentationNode.GenerateMergedLabelmapForAllSegments(
            mergedLabelmap, 0)
        imageStat.SetInputData(mergedLabelmap)
        imageStat.Update()
        self.assertEqual(imageStat.GetVoxelCount(), 1000)
        imageStatResult = imageStat.GetOutput()
        for i in range(4):
            logging.info("Volume {0}: {1}".format(
                i, imageStatResult.GetScalarComponentAsDouble(i, 0, 0, 0)))
        self.assertEqual(
            imageStatResult.GetScalarComponentAsDouble(0, 0, 0, 0), 795)
        self.assertEqual(
            imageStatResult.GetScalarComponentAsDouble(1, 0, 0, 0), 194)
        self.assertEqual(
            imageStatResult.GetScalarComponentAsDouble(2, 0, 0, 0), 6)
        self.assertEqual(
            imageStatResult.GetScalarComponentAsDouble(3, 0, 0, 0), 5)

        # Remove segment from segmentation
        self.inputSegmentationNode.GetSegmentation().RemoveSegment(
            self.sphereSegmentName)
        self.assertEqual(
            self.inputSegmentationNode.GetSegmentation().GetNumberOfSegments(),
            2)
예제 #40
0
    def TestSection_2_MergeLabelmapWithDifferentGeometries(self):
        # Merge labelmap when segments containing labelmaps with different geometries (both same directions, different directions)
        logging.info(
            'Test section 2: Merge labelmap with different geometries')

        self.assertIsNotNone(self.sphereSegment)
        self.sphereSegment.RemoveRepresentation(self.binaryLabelmapReprName)
        self.assertIsNone(
            self.sphereSegment.GetRepresentation(self.binaryLabelmapReprName))

        # Create new segmentation with sphere segment
        self.secondSegmentationNode = slicer.vtkMRMLSegmentationNode()
        self.secondSegmentationNode.SetName('Second')
        self.secondSegmentationNode.GetSegmentation(
        ).SetMasterRepresentationName(self.binaryLabelmapReprName)
        slicer.mrmlScene.AddNode(self.secondSegmentationNode)

        self.secondSegmentationNode.GetSegmentation().AddSegment(
            self.sphereSegment)

        # Check automatically converted labelmap. It is supposed to have the default geometry
        # (which is different than the one in the input segmentation)
        sphereLabelmap = self.sphereSegment.GetRepresentation(
            self.binaryLabelmapReprName)
        self.assertIsNotNone(sphereLabelmap)
        sphereLabelmapSpacing = sphereLabelmap.GetSpacing()
        self.assertTrue(sphereLabelmapSpacing[0] == 1.0
                        and sphereLabelmapSpacing[1] == 1.0
                        and sphereLabelmapSpacing[2] == 1.0)

        # Create binary labelmap in segmentation that will create the merged labelmap from
        # different geometries so that labelmap is not removed from sphere segment when adding
        self.inputSegmentationNode.GetSegmentation().CreateRepresentation(
            self.binaryLabelmapReprName)

        # Copy segment to input segmentation
        self.inputSegmentationNode.GetSegmentation(
        ).CopySegmentFromSegmentation(
            self.secondSegmentationNode.GetSegmentation(),
            self.sphereSegmentName)
        self.assertEqual(
            self.inputSegmentationNode.GetSegmentation().GetNumberOfSegments(),
            3)

        # Check merged labelmap
        # Reference geometry has the tiny patient spacing, and it is oversampled to have smimilar
        # voxel size as the sphere labelmap with the uniform 1mm spacing
        mergedLabelmap = vtkSegmentationCore.vtkOrientedImageData()
        self.inputSegmentationNode.GenerateMergedLabelmapForAllSegments(
            mergedLabelmap, 0)
        mergedLabelmapSpacing = mergedLabelmap.GetSpacing()
        self.assertAlmostEqual(mergedLabelmapSpacing[0], 1.2894736842, 8)
        self.assertAlmostEqual(mergedLabelmapSpacing[1], 1.2894736842, 8)
        self.assertAlmostEqual(mergedLabelmapSpacing[2], 0.6052631578, 8)

        imageStat = vtk.vtkImageAccumulate()
        imageStat.SetInputData(mergedLabelmap)
        imageStat.SetComponentExtent(0, 5, 0, 0, 0, 0)
        imageStat.SetComponentOrigin(0, 0, 0)
        imageStat.SetComponentSpacing(1, 1, 1)
        imageStat.Update()
        self.assertEqual(imageStat.GetVoxelCount(), 54872000)
        imageStatResult = imageStat.GetOutput()
        for i in range(5):
            logging.info("Volume {0}: {1}".format(
                i, imageStatResult.GetScalarComponentAsDouble(i, 0, 0, 0)))
        self.assertEqual(
            imageStatResult.GetScalarComponentAsDouble(0, 0, 0, 0), 43573723)
        self.assertEqual(
            imageStatResult.GetScalarComponentAsDouble(1, 0, 0, 0), 10601312)
        self.assertEqual(
            imageStatResult.GetScalarComponentAsDouble(2, 0, 0, 0), 251476)
        self.assertEqual(
            imageStatResult.GetScalarComponentAsDouble(3, 0, 0, 0), 445489)
        self.assertEqual(
            imageStatResult.GetScalarComponentAsDouble(4, 0, 0, 0), 0
        )  # Built from color table and color four is removed in previous test section
예제 #41
0
    def addGrayscaleVolumeStatistics(self):
        import vtkSegmentationCorePython as vtkSegmentationCore

        containsLabelmapRepresentation = self.segmentationNode.GetSegmentation(
        ).ContainsRepresentation(
            vtkSegmentationCore.vtkSegmentationConverter.
            GetSegmentationBinaryLabelmapRepresentationName())
        if not containsLabelmapRepresentation:
            return

        if self.grayscaleNode is None or self.grayscaleNode.GetImageData(
        ) is None:
            return

        # Get geometry of grayscale volume node as oriented image data
        referenceGeometry_Reference = vtkSegmentationCore.vtkOrientedImageData(
        )  # reference geometry in reference node coordinate system
        referenceGeometry_Reference.SetExtent(
            self.grayscaleNode.GetImageData().GetExtent())
        ijkToRasMatrix = vtk.vtkMatrix4x4()
        self.grayscaleNode.GetIJKToRASMatrix(ijkToRasMatrix)
        referenceGeometry_Reference.SetGeometryFromImageToWorldMatrix(
            ijkToRasMatrix)

        # Get transform between grayscale volume and segmentation
        segmentationToReferenceGeometryTransform = vtk.vtkGeneralTransform()
        slicer.vtkMRMLTransformNode.GetTransformBetweenNodes(
            self.segmentationNode.GetParentTransformNode(),
            self.grayscaleNode.GetParentTransformNode(),
            segmentationToReferenceGeometryTransform)

        cubicMMPerVoxel = reduce(lambda x, y: x * y,
                                 referenceGeometry_Reference.GetSpacing())
        ccPerCubicMM = 0.001

        for segmentID in self.statistics["SegmentIDs"]:
            segment = self.segmentationNode.GetSegmentation().GetSegment(
                segmentID)
            segmentLabelmap = segment.GetRepresentation(
                vtkSegmentationCore.vtkSegmentationConverter.
                GetSegmentationBinaryLabelmapRepresentationName())

            segmentLabelmap_Reference = vtkSegmentationCore.vtkOrientedImageData(
            )
            vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
                segmentLabelmap,
                referenceGeometry_Reference,
                segmentLabelmap_Reference,
                False,  # nearest neighbor interpolation
                False,  # no padding
                segmentationToReferenceGeometryTransform)

            # We need to know exactly the value of the segment voxels, apply threshold to make force the selected label value
            labelValue = 1
            backgroundValue = 0
            thresh = vtk.vtkImageThreshold()
            thresh.SetInputData(segmentLabelmap_Reference)
            thresh.ThresholdByLower(0)
            thresh.SetInValue(backgroundValue)
            thresh.SetOutValue(labelValue)
            thresh.SetOutputScalarType(vtk.VTK_UNSIGNED_CHAR)
            thresh.Update()

            #  Use binary labelmap as a stencil
            stencil = vtk.vtkImageToImageStencil()
            stencil.SetInputData(thresh.GetOutput())
            stencil.ThresholdByUpper(labelValue)
            stencil.Update()

            stat = vtk.vtkImageAccumulate()
            stat.SetInputData(self.grayscaleNode.GetImageData())
            stat.SetStencilData(stencil.GetOutput())
            stat.Update()

            # Add data to statistics list
            self.statistics[segmentID, "GS voxel count"] = stat.GetVoxelCount()
            self.statistics[
                segmentID,
                "GS volume mm3"] = stat.GetVoxelCount() * cubicMMPerVoxel
            self.statistics[segmentID, "GS volume cc"] = stat.GetVoxelCount(
            ) * cubicMMPerVoxel * ccPerCubicMM
            if stat.GetVoxelCount() > 0:
                self.statistics[segmentID, "GS min"] = stat.GetMin()[0]
                self.statistics[segmentID, "GS max"] = stat.GetMax()[0]
                self.statistics[segmentID, "GS mean"] = stat.GetMean()[0]
                self.statistics[segmentID,
                                "GS stdev"] = stat.GetStandardDeviation()[0]
예제 #42
0
    def cutSurfaceWithModel(self, segmentMarkupNode, segmentModel):

        import vtkSegmentationCorePython as vtkSegmentationCore

        if not segmentMarkupNode:
            raise AttributeError("{}: segment markup node not set.".format(
                self.__class__.__name__))
        if not segmentModel:
            raise AttributeError("{}: segment model not set.".format(
                self.__class__.__name__))

        if segmentMarkupNode and segmentModel.GetPolyData().GetNumberOfPolys(
        ) > 0:
            operationName = self.scriptedEffect.parameter("Operation")

            segmentationNode = self.scriptedEffect.parameterSetNode(
            ).GetSegmentationNode()
            if not segmentationNode:
                raise AttributeError("{}: Segmentation node not set.".format(
                    self.__class__.__name__))

            modifierLabelmap = self.scriptedEffect.defaultModifierLabelmap()
            if not modifierLabelmap:
                raise AttributeError(
                    "{}: ModifierLabelmap not set. This can happen for various reasons:\n"
                    "No master volume set for segmentation,\n"
                    "No existing segments for segmentation, or\n"
                    "No referenceImageGeometry is specified in the segmentation"
                    .format(self.__class__.__name__))

            WorldToModifierLabelmapIjkTransform = vtk.vtkTransform()

            WorldToModifierLabelmapIjkTransformer = vtk.vtkTransformPolyDataFilter(
            )
            WorldToModifierLabelmapIjkTransformer.SetTransform(
                WorldToModifierLabelmapIjkTransform)
            WorldToModifierLabelmapIjkTransformer.SetInputConnection(
                segmentModel.GetPolyDataConnection())

            segmentationToSegmentationIjkTransformMatrix = vtk.vtkMatrix4x4()
            modifierLabelmap.GetImageToWorldMatrix(
                segmentationToSegmentationIjkTransformMatrix)
            segmentationToSegmentationIjkTransformMatrix.Invert()
            WorldToModifierLabelmapIjkTransform.Concatenate(
                segmentationToSegmentationIjkTransformMatrix)

            worldToSegmentationTransformMatrix = vtk.vtkMatrix4x4()
            slicer.vtkMRMLTransformNode.GetMatrixTransformBetweenNodes(
                None, segmentationNode.GetParentTransformNode(),
                worldToSegmentationTransformMatrix)
            WorldToModifierLabelmapIjkTransform.Concatenate(
                worldToSegmentationTransformMatrix)
            WorldToModifierLabelmapIjkTransformer.Update()

            polyToStencil = vtk.vtkPolyDataToImageStencil()
            polyToStencil.SetOutputSpacing(1.0, 1.0, 1.0)
            polyToStencil.SetInputConnection(
                WorldToModifierLabelmapIjkTransformer.GetOutputPort())
            boundsIjk = WorldToModifierLabelmapIjkTransformer.GetOutput(
            ).GetBounds()
            modifierLabelmapExtent = self.scriptedEffect.modifierLabelmap(
            ).GetExtent()
            polyToStencil.SetOutputWholeExtent(modifierLabelmapExtent[0],
                                               modifierLabelmapExtent[1],
                                               modifierLabelmapExtent[2],
                                               modifierLabelmapExtent[3],
                                               int(round(boundsIjk[4])),
                                               int(round(boundsIjk[5])))
            polyToStencil.Update()

            stencilData = polyToStencil.GetOutput()
            stencilExtent = [0, -1, 0, -1, 0, -1]
            stencilData.SetExtent(stencilExtent)

            stencilToImage = vtk.vtkImageStencilToImage()
            stencilToImage.SetInputConnection(polyToStencil.GetOutputPort())
            if operationName in ("FILL_INSIDE", "ERASE_INSIDE", "SET"):
                stencilToImage.SetInsideValue(1.0)
                stencilToImage.SetOutsideValue(0.0)
            else:
                stencilToImage.SetInsideValue(0.0)
                stencilToImage.SetOutsideValue(1.0)
            stencilToImage.SetOutputScalarType(
                modifierLabelmap.GetScalarType())

            stencilPositioner = vtk.vtkImageChangeInformation()
            stencilPositioner.SetInputConnection(
                stencilToImage.GetOutputPort())
            stencilPositioner.SetOutputSpacing(modifierLabelmap.GetSpacing())
            stencilPositioner.SetOutputOrigin(modifierLabelmap.GetOrigin())

            stencilPositioner.Update()
            orientedStencilPositionerOutput = vtkSegmentationCore.vtkOrientedImageData(
            )
            orientedStencilPositionerOutput.ShallowCopy(
                stencilToImage.GetOutput())
            imageToWorld = vtk.vtkMatrix4x4()
            modifierLabelmap.GetImageToWorldMatrix(imageToWorld)
            orientedStencilPositionerOutput.SetImageToWorldMatrix(imageToWorld)

            vtkSegmentationCore.vtkOrientedImageDataResample.ModifyImage(
                modifierLabelmap, orientedStencilPositionerOutput,
                vtkSegmentationCore.vtkOrientedImageDataResample.
                OPERATION_MAXIMUM)

            modMode = slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeAdd
            if operationName == "ERASE_INSIDE" or operationName == "ERASE_OUTSIDE":
                modMode = slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeRemove
            elif operationName == "SET":
                modMode = slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet

            self.scriptedEffect.modifySelectedSegmentByLabelmap(
                modifierLabelmap, modMode)

            # get fiducial positions as space-separated list
            import numpy
            n = segmentMarkupNode.GetNumberOfFiducials()
            fPos = []
            for i in range(n):
                coord = [0.0, 0.0, 0.0]
                segmentMarkupNode.GetNthFiducialPosition(i, coord)
                fPos.extend(coord)
            fPosString = ' '.join(map(str, fPos))

            segmentID = self.scriptedEffect.parameterSetNode(
            ).GetSelectedSegmentID()
            segment = segmentationNode.GetSegmentation().GetSegment(segmentID)
            segment.SetTag("SurfaceCutEffectMarkupPositions", fPosString)
    def getStencilForVolume(self, segmentationNode, segmentID, grayscaleNode):
        import vtkSegmentationCorePython as vtkSegmentationCore

        containsLabelmapRepresentation = segmentationNode.GetSegmentation(
        ).ContainsRepresentation(
            vtkSegmentationCore.vtkSegmentationConverter.
            GetSegmentationBinaryLabelmapRepresentationName())
        if not containsLabelmapRepresentation:
            return None

        if (not grayscaleNode or not grayscaleNode.GetImageData()
                or not grayscaleNode.GetImageData().GetPointData() or
                not grayscaleNode.GetImageData().GetPointData().GetScalars()):
            # Input grayscale node does not contain valid image data
            return None

        # Get geometry of grayscale volume node as oriented image data
        # reference geometry in reference node coordinate system
        referenceGeometry_Reference = vtkSegmentationCore.vtkOrientedImageData(
        )
        referenceGeometry_Reference.SetExtent(
            grayscaleNode.GetImageData().GetExtent())
        ijkToRasMatrix = vtk.vtkMatrix4x4()
        grayscaleNode.GetIJKToRASMatrix(ijkToRasMatrix)
        referenceGeometry_Reference.SetGeometryFromImageToWorldMatrix(
            ijkToRasMatrix)

        # Get transform between grayscale volume and segmentation
        segmentationToReferenceGeometryTransform = vtk.vtkGeneralTransform()
        slicer.vtkMRMLTransformNode.GetTransformBetweenNodes(
            segmentationNode.GetParentTransformNode(),
            grayscaleNode.GetParentTransformNode(),
            segmentationToReferenceGeometryTransform)

        segmentLabelmap = vtkSegmentationCore.vtkOrientedImageData()
        segmentationNode.GetBinaryLabelmapRepresentation(
            segmentID, segmentLabelmap)
        if (not segmentLabelmap or not segmentLabelmap.GetPointData()
                or not segmentLabelmap.GetPointData().GetScalars()):
            # No input label data
            return None

        segmentLabelmap_Reference = vtkSegmentationCore.vtkOrientedImageData()
        vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
            segmentLabelmap,
            referenceGeometry_Reference,
            segmentLabelmap_Reference,
            False,  # nearest neighbor interpolation
            False,  # no padding
            segmentationToReferenceGeometryTransform)

        # We need to know exactly the value of the segment voxels, apply threshold to make force the selected label value
        labelValue = 1
        backgroundValue = 0
        thresh = vtk.vtkImageThreshold()
        thresh.SetInputData(segmentLabelmap_Reference)
        thresh.ThresholdByLower(0)
        thresh.SetInValue(backgroundValue)
        thresh.SetOutValue(labelValue)
        thresh.SetOutputScalarType(vtk.VTK_UNSIGNED_CHAR)
        thresh.Update()

        #  Use binary labelmap as a stencil
        stencil = vtk.vtkImageToImageStencil()
        stencil.SetInputData(thresh.GetOutput())
        stencil.ThresholdByUpper(labelValue)
        stencil.Update()

        return stencil
  def TestSection_2_qMRMLSegmentationGeometryWidget(self):
    logging.info('Test section 2: qMRMLSegmentationGeometryWidget')

    import vtkSegmentationCore
    binaryLabelmapReprName = vtkSegmentationCore.vtkSegmentationConverter.GetBinaryLabelmapRepresentationName()
    closedSurfaceReprName = vtkSegmentationCore.vtkSegmentationConverter.GetClosedSurfaceRepresentationName()

    # Use MRHead and Tinypatient for testing
    import SampleData
    sampleDataLogic = SampleData.SampleDataLogic()
    mrVolumeNode = sampleDataLogic.downloadMRHead()
    [tinyVolumeNode, tinySegmentationNode] = sampleDataLogic.downloadSample('TinyPatient')

    # Convert MRHead to oriented image data
    import vtkSlicerSegmentationsModuleLogicPython as vtkSlicerSegmentationsModuleLogic
    mrOrientedImageData = vtkSlicerSegmentationsModuleLogic.vtkSlicerSegmentationsModuleLogic.CreateOrientedImageDataFromVolumeNode(mrVolumeNode)
    mrOrientedImageData.UnRegister(None)

    # Create segmentation node with binary labelmap master and one segment with MRHead geometry
    segmentationNode = slicer.vtkMRMLSegmentationNode()
    segmentationNode.GetSegmentation().SetMasterRepresentationName(binaryLabelmapReprName)
    geometryStr = vtkSegmentationCore.vtkSegmentationConverter.SerializeImageGeometry(mrOrientedImageData)
    segmentationNode.GetSegmentation().SetConversionParameter(
      vtkSegmentationCore.vtkSegmentationConverter.GetReferenceImageGeometryParameterName(), geometryStr)
    slicer.mrmlScene.AddNode(segmentationNode)
    threshold = vtk.vtkImageThreshold()
    threshold.SetInputData(mrOrientedImageData)
    threshold.ThresholdByUpper(16.0)
    threshold.SetInValue(1)
    threshold.SetOutValue(0)
    threshold.SetOutputScalarType(vtk.VTK_UNSIGNED_CHAR)
    threshold.Update()
    segmentOrientedImageData = vtkSegmentationCore.vtkOrientedImageData()
    segmentOrientedImageData.DeepCopy(threshold.GetOutput())
    mrImageToWorldMatrix = vtk.vtkMatrix4x4()
    mrOrientedImageData.GetImageToWorldMatrix(mrImageToWorldMatrix)
    segmentOrientedImageData.SetImageToWorldMatrix(mrImageToWorldMatrix)
    segment = vtkSegmentationCore.vtkSegment()
    segment.SetName('Brain')
    segment.SetColor(0.0,0.0,1.0)
    segment.AddRepresentation(binaryLabelmapReprName, segmentOrientedImageData)
    segmentationNode.GetSegmentation().AddSegment(segment)

    # Create geometry widget
    geometryWidget = slicer.qMRMLSegmentationGeometryWidget()
    geometryWidget.setSegmentationNode(segmentationNode)
    geometryWidget.editEnabled = True
    geometryImageData = vtkSegmentationCore.vtkOrientedImageData() # To contain the output later

    # Volume source with no transforms
    geometryWidget.setSourceNode(tinyVolumeNode)
    geometryWidget.geometryImageData(geometryImageData)
    self.assertTrue(self.compareOutputGeometry(geometryImageData,
        (49,49,23), (248.8439, 248.2890, -123.75),
        [[0.0, 0.0, 1.0], [0.0, 0.0, 1.0], [0.0, 0.0, 1.0]]))
    slicer.util.delayDisplay('Volume source with no transforms - OK')

    # Transformed volume source
    translationTransformMatrix = vtk.vtkMatrix4x4()
    translationTransformMatrix.SetElement(0,3,24.5)
    translationTransformMatrix.SetElement(1,3,24.5)
    translationTransformMatrix.SetElement(2,3,11.5)
    translationTransformNode = slicer.vtkMRMLLinearTransformNode()
    translationTransformNode.SetName('TestTranslation')
    slicer.mrmlScene.AddNode(translationTransformNode)
    translationTransformNode.SetMatrixTransformToParent(translationTransformMatrix)

    tinyVolumeNode.SetAndObserveTransformNodeID(translationTransformNode.GetID())
    geometryWidget.geometryImageData(geometryImageData)
    self.assertTrue(self.compareOutputGeometry(geometryImageData,
        (49,49,23), (224.3439, 223.7890, -135.25),
        [[0.0, 0.0, 1.0], [0.0, 0.0, 1.0], [0.0, 0.0, 1.0]]))
    slicer.util.delayDisplay('Transformed volume source - OK')

    # Volume source with isotropic spacing
    tinyVolumeNode.SetAndObserveTransformNodeID(None)
    geometryWidget.setIsotropicSpacing(True)
    geometryWidget.geometryImageData(geometryImageData)
    self.assertTrue(self.compareOutputGeometry(geometryImageData,
        (23,23,23), (248.8439, 248.2890, -123.75),
        [[0.0, 0.0, 1.0], [0.0, 0.0, 1.0], [0.0, 0.0, 1.0]]))
    slicer.util.delayDisplay('Volume source with isotropic spacing - OK')

    # Volume source with oversampling
    geometryWidget.setIsotropicSpacing(False)
    geometryWidget.setOversamplingFactor(2.0)
    geometryWidget.geometryImageData(geometryImageData)
    self.assertTrue(self.compareOutputGeometry(geometryImageData,
        (24.5, 24.5, 11.5), (261.0939, 260.5390, -129.5),
        [[0.0, 0.0, 1.0], [0.0, 0.0, 1.0], [0.0, 0.0, 1.0]]))
    slicer.util.delayDisplay('Volume source with oversampling - OK')

    # Segmentation source with binary labelmap master
    geometryWidget.setOversamplingFactor(1.0)
    geometryWidget.setSourceNode(tinySegmentationNode)
    geometryWidget.geometryImageData(geometryImageData)
    self.assertTrue(self.compareOutputGeometry(geometryImageData,
        (49,49,23), (248.8439, 248.2890, -123.75),
        [[0.0, 0.0, 1.0], [0.0, 0.0, 1.0], [0.0, 0.0, 1.0]]))
    slicer.util.delayDisplay('Segmentation source with binary labelmap master - OK')

    # Segmentation source with closed surface master
    tinySegmentationNode.GetSegmentation().SetConversionParameter('Smoothing factor', '0.0')
    self.assertTrue(tinySegmentationNode.GetSegmentation().CreateRepresentation(closedSurfaceReprName))
    tinySegmentationNode.GetSegmentation().SetMasterRepresentationName(closedSurfaceReprName)
    tinySegmentationNode.Modified() # Trigger re-calculation of geometry (only generic Modified event is observed)
    geometryWidget.geometryImageData(geometryImageData)
    # Manually resample and check if the output is non-empty
    # Note: This is done for all poly data based geometry calculations below
    #TODO: Come up with proper geometry baselines for these too
    vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
      segmentOrientedImageData, geometryImageData, geometryImageData, False, True)
    self.assertTrue(self.imageDataContainsData(geometryImageData))
    slicer.util.delayDisplay('Segmentation source with closed surface master - OK')

    # Model source with no transform
    outputModelHierarchy = slicer.vtkMRMLModelHierarchyNode()
    slicer.mrmlScene.AddNode(outputModelHierarchy)
    success = vtkSlicerSegmentationsModuleLogic.vtkSlicerSegmentationsModuleLogic.ExportVisibleSegmentsToModelHierarchy(
      tinySegmentationNode, outputModelHierarchy )
    self.assertTrue(success)
    modelNode = slicer.util.getNode('Body_Contour')
    geometryWidget.setSourceNode(modelNode)
    geometryWidget.geometryImageData(geometryImageData)
    vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
      segmentOrientedImageData, geometryImageData, geometryImageData, False, True)
    self.assertTrue(self.imageDataContainsData(geometryImageData))
    slicer.util.delayDisplay('Model source with no transform - OK')

    # Transformed model source
    rotationTransform = vtk.vtkTransform()
    rotationTransform.RotateX(45)
    rotationTransformMatrix = vtk.vtkMatrix4x4()
    rotationTransform.GetMatrix(rotationTransformMatrix)
    rotationTransformNode = slicer.vtkMRMLLinearTransformNode()
    rotationTransformNode.SetName('TestRotation')
    slicer.mrmlScene.AddNode(rotationTransformNode)
    rotationTransformNode.SetMatrixTransformToParent(rotationTransformMatrix)

    modelNode.SetAndObserveTransformNodeID(rotationTransformNode.GetID())
    modelNode.Modified()
    geometryWidget.geometryImageData(geometryImageData)
    vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
      segmentOrientedImageData, geometryImageData, geometryImageData, False, True)
    self.assertTrue(self.imageDataContainsData(geometryImageData))
    slicer.util.delayDisplay('Transformed model source - OK')

    # ROI source
    roiNode = slicer.vtkMRMLAnnotationROINode()
    roiNode.SetName('SourceROI')
    slicer.mrmlScene.AddNode(roiNode)
    roiNode.UnRegister(None)
    xyz = [0]*3
    center = [0]*3
    slicer.vtkMRMLSliceLogic.GetVolumeRASBox(tinyVolumeNode, xyz, center)
    radius = map(lambda x: x/2.0, xyz)
    roiNode.SetXYZ(center)
    roiNode.SetRadiusXYZ(radius)
    geometryWidget.setSourceNode(roiNode)
    geometryWidget.geometryImageData(geometryImageData)
    vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
      segmentOrientedImageData, geometryImageData, geometryImageData, False, True)
    self.assertTrue(self.imageDataContainsData(geometryImageData))
    slicer.util.delayDisplay('ROI source - OK')

    slicer.util.delayDisplay('Segmentation geometry widget test passed')
    def fastMarching(self, percentMax):

        self.fm = None

        # Get master volume image data
        import vtkSegmentationCorePython as vtkSegmentationCore
        masterImageData = self.scriptedEffect.masterVolumeImageData()
        # Get segmentation
        segmentationNode = self.scriptedEffect.parameterSetNode(
        ).GetSegmentationNode()

        # Cast master image if not short
        if masterImageData.GetScalarType() != vtk.VTK_SHORT:
            imageCast = vtk.vtkImageCast()
            imageCast.SetInputData(masterImageData)
            imageCast.SetOutputScalarTypeToShort()
            imageCast.ClampOverflowOn()
            imageCast.Update()
            masterImageDataShort = vtkSegmentationCore.vtkOrientedImageData()
            masterImageDataShort.ShallowCopy(
                imageCast.GetOutput())  # Copy image data
            masterImageDataShort.CopyDirections(
                masterImageData)  # Copy geometry
            masterImageData = masterImageDataShort

        if not self.originalSelectedSegmentLabelmap:
            segmentationNode = self.scriptedEffect.parameterSetNode(
            ).GetSegmentationNode()
            segmentationNode.GetSegmentation().SeparateSegmentLabelmap(
                self.scriptedEffect.parameterSetNode().GetSelectedSegmentID())

        selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap()

        if not self.originalSelectedSegmentLabelmap:
            self.originalSelectedSegmentLabelmap = vtkSegmentationCore.vtkOrientedImageData(
            )
            self.originalSelectedSegmentLabelmap.DeepCopy(
                selectedSegmentLabelmap)
            self.selectedSegmentId = self.scriptedEffect.parameterSetNode(
            ).GetSelectedSegmentID()

        # We need to know exactly the value of the segment voxels, apply threshold to make force the selected label value
        labelValue = 1
        backgroundValue = 0
        thresh = vtk.vtkImageThreshold()
        thresh.SetInputData(selectedSegmentLabelmap)
        thresh.ThresholdByLower(0)
        thresh.SetInValue(backgroundValue)
        thresh.SetOutValue(labelValue)
        thresh.SetOutputScalarType(vtk.VTK_UNSIGNED_SHORT)
        thresh.Update()
        labelImage = thresh.GetOutput()

        # collect seeds
        dim = masterImageData.GetDimensions()
        # initialize the filter
        import vtkSlicerSegmentEditorFastMarchingModuleLogicPython
        self.fm = vtkSlicerSegmentEditorFastMarchingModuleLogicPython.vtkPichonFastMarching(
        )
        scalarRange = masterImageData.GetScalarRange()
        depth = scalarRange[1] - scalarRange[0]

        # this is more or less arbitrary; large depth values will bring the
        # algorithm to the knees
        scaleValue = 0
        shiftValue = 0

        if depth > 300:
            scaleValue = 300. / depth
        if scalarRange[0] < 0:
            shiftValue = scalarRange[0] * -1

        if scaleValue or shiftValue:
            rescale = vtk.vtkImageShiftScale()
            rescale.SetInputData(masterImageData)
            rescale.SetScale(scaleValue)
            rescale.SetShift(shiftValue)
            rescale.Update()
            masterImageData = rescale.GetOutput()
            scalarRange = masterImageData.GetScalarRange()
            depth = scalarRange[1] - scalarRange[0]

        self.fm.init(dim[0], dim[1], dim[2], depth, 1, 1, 1)

        caster = vtk.vtkImageCast()
        caster.SetOutputScalarTypeToShort()
        caster.SetInputData(masterImageData)
        self.fm.SetInputConnection(caster.GetOutputPort())

        # self.fm.SetOutput(labelImage)

        npoints = int(dim[0] * dim[1] * dim[2] * percentMax / 100.)

        self.fm.setNPointsEvolution(npoints)
        self.fm.setActiveLabel(labelValue)

        spacing = self.originalSelectedSegmentLabelmap.GetSpacing()
        self.voxelVolume = spacing[0] * spacing[1] * spacing[2]
        self.totalNumberOfVoxels = npoints

        nSeeds = self.fm.addSeedsFromImage(labelImage)
        if nSeeds == 0:
            self.totalNumberOfVoxels = 0
            return

        self.fm.Modified()
        self.fm.Update()

        # Need to call show() twice for data to be updated.
        # There are many other issues with the vtkPichonFastMarching filter
        # (expects extents to start at 0, crashes in debug mode, etc).
        self.fm.show(1)
        self.fm.Modified()
        self.fm.Update()

        self.updateLabel(self.marcher.value / self.marcher.maximum)

        logging.info('FastMarching march update completed')
예제 #46
0
    def splitSegments(self, minimumSize=0, maxNumberOfSegments=0, split=True):
        """
    minimumSize: if 0 then it means that all islands are kept, regardless of size
    maxNumberOfSegments: if 0 then it means that all islands are kept, regardless of how many
    """
        # This can be a long operation - indicate it to the user
        qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor)

        self.scriptedEffect.saveStateForUndo()

        # Get modifier labelmap
        selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap()

        castIn = vtk.vtkImageCast()
        castIn.SetInputData(selectedSegmentLabelmap)
        castIn.SetOutputScalarTypeToUnsignedInt()

        # Identify the islands in the inverted volume and
        # find the pixel that corresponds to the background
        islandMath = vtkITK.vtkITKIslandMath()
        islandMath.SetInputConnection(castIn.GetOutputPort())
        islandMath.SetFullyConnected(False)
        islandMath.SetMinimumSize(minimumSize)
        islandMath.Update()

        # Create a separate image for the first (largest) island
        labelValue = 1
        backgroundValue = 0
        thresh = vtk.vtkImageThreshold()
        if split:
            thresh.ThresholdBetween(1, 1)
        else:
            if maxNumberOfSegments != 0:
                thresh.ThresholdBetween(1, maxNumberOfSegments)
            else:
                thresh.ThresholdByUpper(1)

        thresh.SetInputData(islandMath.GetOutput())
        thresh.SetOutValue(backgroundValue)
        thresh.SetInValue(labelValue)
        thresh.SetOutputScalarType(selectedSegmentLabelmap.GetScalarType())
        thresh.Update()
        # Create oriented image data from output
        import vtkSegmentationCorePython as vtkSegmentationCore
        largestIslandImage = vtkSegmentationCore.vtkOrientedImageData()
        largestIslandImage.ShallowCopy(thresh.GetOutput())
        selectedSegmentLabelmapImageToWorldMatrix = vtk.vtkMatrix4x4()
        selectedSegmentLabelmap.GetImageToWorldMatrix(
            selectedSegmentLabelmapImageToWorldMatrix)
        largestIslandImage.SetImageToWorldMatrix(
            selectedSegmentLabelmapImageToWorldMatrix)

        if split and (maxNumberOfSegments != 1):

            thresh2 = vtk.vtkImageThreshold()
            # 0 is background, 1 is largest island; we need label 2 and higher
            if maxNumberOfSegments != 0:
                thresh2.ThresholdBetween(2, maxNumberOfSegments)
            else:
                thresh2.ThresholdByUpper(2)
            thresh2.SetInputData(islandMath.GetOutput())
            thresh2.SetOutValue(backgroundValue)
            thresh2.ReplaceInOff()
            thresh2.Update()

            islandCount = islandMath.GetNumberOfIslands()
            islandOrigCount = islandMath.GetOriginalNumberOfIslands()
            ignoredIslands = islandOrigCount - islandCount
            logging.info("%d islands created (%d ignored)" %
                         (islandCount, ignoredIslands))

            # Create oriented image data from output
            import vtkSegmentationCorePython as vtkSegmentationCore
            multiLabelImage = vtkSegmentationCore.vtkOrientedImageData()
            multiLabelImage.DeepCopy(thresh2.GetOutput())
            selectedSegmentLabelmapImageToWorldMatrix = vtk.vtkMatrix4x4()
            selectedSegmentLabelmap.GetImageToWorldMatrix(
                selectedSegmentLabelmapImageToWorldMatrix)
            multiLabelImage.SetGeometryFromImageToWorldMatrix(
                selectedSegmentLabelmapImageToWorldMatrix)

            # Import multi-label labelmap to segmentation
            segmentationNode = self.scriptedEffect.parameterSetNode(
            ).GetSegmentationNode()
            selectedSegmentID = self.scriptedEffect.parameterSetNode(
            ).GetSelectedSegmentID()
            selectedSegmentIndex = segmentationNode.GetSegmentation(
            ).GetSegmentIndex(selectedSegmentID)
            insertBeforeSegmentID = segmentationNode.GetSegmentation(
            ).GetNthSegmentID(selectedSegmentIndex + 1)
            selectedSegmentName = segmentationNode.GetSegmentation(
            ).GetSegment(selectedSegmentID).GetName()
            slicer.vtkSlicerSegmentationsModuleLogic.ImportLabelmapToSegmentationNode( \
              multiLabelImage, segmentationNode, selectedSegmentName+" -", insertBeforeSegmentID )

        self.scriptedEffect.modifySelectedSegmentByLabelmap(
            largestIslandImage,
            slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet)

        qt.QApplication.restoreOverrideCursor()
예제 #47
0
    def onApply(self):

        self.scriptedEffect.saveStateForUndo()

        import vtkSegmentationCorePython as vtkSegmentationCore

        # Get modifier labelmap and parameters

        operation = self.scriptedEffect.parameter("Operation")
        bypassMasking = (self.scriptedEffect.integerParameter("BypassMasking")
                         != 0)

        selectedSegmentID = self.scriptedEffect.parameterSetNode(
        ).GetSelectedSegmentID()

        segmentationNode = self.scriptedEffect.parameterSetNode(
        ).GetSegmentationNode()
        segmentation = segmentationNode.GetSegmentation()

        if operation in self.operationsRequireModifierSegment:

            # Get modifier segment
            modifierSegmentID = self.modifierSegmentID()
            if not modifierSegmentID:
                logging.error(
                    "Operation {0} requires a selected modifier segment".
                    format(operation))
                return
            modifierSegment = segmentation.GetSegment(modifierSegmentID)
            modifierSegmentLabelmap = modifierSegment.GetRepresentation(
                vtkSegmentationCore.vtkSegmentationConverter.
                GetSegmentationBinaryLabelmapRepresentationName())

            # Get common geometry
            commonGeometryString = segmentationNode.GetSegmentation(
            ).DetermineCommonLabelmapGeometry(
                vtkSegmentationCore.vtkSegmentation.EXTENT_UNION_OF_SEGMENTS,
                None)
            if not commonGeometryString:
                logging.info(
                    "Logical operation skipped: all segments are empty")
                return
            commonGeometryImage = vtkSegmentationCore.vtkOrientedImageData()
            vtkSegmentationCore.vtkSegmentationConverter.DeserializeImageGeometry(
                commonGeometryString, commonGeometryImage, False)

            # Make sure modifier segment has correct geometry
            # (if modifier segment has been just copied over from another segment then its geometry may be different)
            if not vtkSegmentationCore.vtkOrientedImageDataResample.DoGeometriesMatch(
                    commonGeometryImage, modifierSegmentLabelmap):
                modifierSegmentLabelmap_CommonGeometry = vtkSegmentationCore.vtkOrientedImageData(
                )
                vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage(
                    modifierSegmentLabelmap,
                    commonGeometryImage,
                    modifierSegmentLabelmap_CommonGeometry,
                    False,  # nearest neighbor interpolation,
                    True  # make sure resampled modifier segment is not cropped
                )
                modifierSegmentLabelmap = modifierSegmentLabelmap_CommonGeometry

            if operation == LOGICAL_COPY:
                if bypassMasking:
                    slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(
                        modifierSegmentLabelmap, segmentationNode,
                        selectedSegmentID,
                        slicer.vtkSlicerSegmentationsModuleLogic.MODE_REPLACE,
                        modifierSegmentLabelmap.GetExtent())
                else:
                    self.scriptedEffect.modifySelectedSegmentByLabelmap(
                        modifierSegmentLabelmap, slicer.
                        qSlicerSegmentEditorAbstractEffect.ModificationModeSet)
            elif operation == LOGICAL_UNION:
                if bypassMasking:
                    slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(
                        modifierSegmentLabelmap, segmentationNode,
                        selectedSegmentID, slicer.
                        vtkSlicerSegmentationsModuleLogic.MODE_MERGE_MAX,
                        modifierSegmentLabelmap.GetExtent())
                else:
                    self.scriptedEffect.modifySelectedSegmentByLabelmap(
                        modifierSegmentLabelmap, slicer.
                        qSlicerSegmentEditorAbstractEffect.ModificationModeAdd)
            elif operation == LOGICAL_SUBTRACT:
                if bypassMasking:
                    invertedModifierSegmentLabelmap = self.getInvertedBinaryLabelmap(
                        modifierSegmentLabelmap)
                    slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(
                        invertedModifierSegmentLabelmap, segmentationNode,
                        selectedSegmentID, slicer.
                        vtkSlicerSegmentationsModuleLogic.MODE_MERGE_MIN,
                        modifierSegmentLabelmap.GetExtent())
                else:
                    self.scriptedEffect.modifySelectedSegmentByLabelmap(
                        modifierSegmentLabelmap,
                        slicer.qSlicerSegmentEditorAbstractEffect.
                        ModificationModeRemove)
            elif operation == LOGICAL_INTERSECT:
                selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap(
                )
                intersectionLabelmap = vtkSegmentationCore.vtkOrientedImageData(
                )
                vtkSegmentationCore.vtkOrientedImageDataResample.MergeImage(
                    selectedSegmentLabelmap, modifierSegmentLabelmap,
                    intersectionLabelmap, vtkSegmentationCore.
                    vtkOrientedImageDataResample.OPERATION_MINIMUM,
                    selectedSegmentLabelmap.GetExtent())
                selectedSegmentLabelmapExtent = selectedSegmentLabelmap.GetExtent(
                )
                modifierSegmentLabelmapExtent = modifierSegmentLabelmap.GetExtent(
                )
                commonExtent = [
                    max(selectedSegmentLabelmapExtent[0],
                        modifierSegmentLabelmapExtent[0]),
                    min(selectedSegmentLabelmapExtent[1],
                        modifierSegmentLabelmapExtent[1]),
                    max(selectedSegmentLabelmapExtent[2],
                        modifierSegmentLabelmapExtent[2]),
                    min(selectedSegmentLabelmapExtent[3],
                        modifierSegmentLabelmapExtent[3]),
                    max(selectedSegmentLabelmapExtent[4],
                        modifierSegmentLabelmapExtent[4]),
                    min(selectedSegmentLabelmapExtent[5],
                        modifierSegmentLabelmapExtent[5])
                ]
                if bypassMasking:
                    slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(
                        intersectionLabelmap, segmentationNode,
                        selectedSegmentID,
                        slicer.vtkSlicerSegmentationsModuleLogic.MODE_REPLACE,
                        commonExtent)
                else:
                    self.scriptedEffect.modifySelectedSegmentByLabelmap(
                        intersectionLabelmap, slicer.
                        qSlicerSegmentEditorAbstractEffect.ModificationModeSet,
                        commonExtent)

        elif operation == LOGICAL_INVERT:
            selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap(
            )
            invertedSelectedSegmentLabelmap = self.getInvertedBinaryLabelmap(
                selectedSegmentLabelmap)
            if bypassMasking:
                slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(
                    invertedSelectedSegmentLabelmap, segmentationNode,
                    selectedSegmentID,
                    slicer.vtkSlicerSegmentationsModuleLogic.MODE_REPLACE)
            else:
                self.scriptedEffect.modifySelectedSegmentByLabelmap(
                    invertedSelectedSegmentLabelmap, slicer.
                    qSlicerSegmentEditorAbstractEffect.ModificationModeSet)

        elif operation == LOGICAL_CLEAR or operation == LOGICAL_FILL:
            selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap(
            )
            vtkSegmentationCore.vtkOrientedImageDataResample.FillImage(
                selectedSegmentLabelmap, 1 if operation == LOGICAL_FILL else 0,
                selectedSegmentLabelmap.GetExtent())
            if bypassMasking:
                slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(
                    selectedSegmentLabelmap, segmentationNode,
                    selectedSegmentID,
                    slicer.vtkSlicerSegmentationsModuleLogic.MODE_REPLACE)
            else:
                self.scriptedEffect.modifySelectedSegmentByLabelmap(
                    selectedSegmentLabelmap, slicer.
                    qSlicerSegmentEditorAbstractEffect.ModificationModeSet)

        else:
            logging.error("Unknown operation: {0}".format(operation))
예제 #48
0
    def preview(self):
        # Get master volume image data
        import vtkSegmentationCorePython as vtkSegmentationCore
        masterImageData = self.scriptedEffect.masterVolumeImageData()

        # Get segmentation
        segmentationNode = self.scriptedEffect.parameterSetNode(
        ).GetSegmentationNode()

        previewNode = self.getPreviewNode()
        if not previewNode or not self.mergedLabelmapGeometryImage \
          or (self.clippedMasterImageDataRequired and not self.clippedMasterImageData):
            self.reset()
            # Compute merged labelmap extent (effective extent slightly expanded)
            self.selectedSegmentIds = vtk.vtkStringArray()
            segmentationNode.GetDisplayNode().GetVisibleSegmentIDs(
                self.selectedSegmentIds)
            if self.selectedSegmentIds.GetNumberOfValues(
            ) < self.minimumNumberOfSegments:
                logging.error(
                    "Auto-complete operation skipped: at least {0} visible segments are required"
                    .format(self.minimumNumberOfSegments))
                return
            if not self.mergedLabelmapGeometryImage:
                self.mergedLabelmapGeometryImage = vtkSegmentationCore.vtkOrientedImageData(
                )
            commonGeometryString = segmentationNode.GetSegmentation(
            ).DetermineCommonLabelmapGeometry(
                vtkSegmentationCore.vtkSegmentation.
                EXTENT_UNION_OF_EFFECTIVE_SEGMENTS, self.selectedSegmentIds)
            if not commonGeometryString:
                logging.info(
                    "Auto-complete operation skipped: all visible segments are empty"
                )
                return
            vtkSegmentationCore.vtkSegmentationConverter.DeserializeImageGeometry(
                commonGeometryString, self.mergedLabelmapGeometryImage)

            masterImageExtent = masterImageData.GetExtent()
            labelsEffectiveExtent = self.mergedLabelmapGeometryImage.GetExtent(
            )
            margin = [17, 17, 17]
            labelsExpandedExtent = [
                max(masterImageExtent[0],
                    labelsEffectiveExtent[0] - margin[0]),
                min(masterImageExtent[1],
                    labelsEffectiveExtent[1] + margin[0]),
                max(masterImageExtent[2],
                    labelsEffectiveExtent[2] - margin[1]),
                min(masterImageExtent[3],
                    labelsEffectiveExtent[3] + margin[1]),
                max(masterImageExtent[4],
                    labelsEffectiveExtent[4] - margin[2]),
                min(masterImageExtent[5], labelsEffectiveExtent[5] + margin[2])
            ]
            self.mergedLabelmapGeometryImage.SetExtent(labelsExpandedExtent)

            previewNode = slicer.mrmlScene.CreateNodeByClass(
                'vtkMRMLSegmentationNode')
            previewNode.UnRegister(None)
            previewNode = slicer.mrmlScene.AddNode(previewNode)
            previewNode.CreateDefaultDisplayNodes()
            previewNode.GetDisplayNode().SetVisibility2DOutline(False)
            if segmentationNode.GetParentTransformNode():
                previewNode.SetAndObserveTransformNodeID(
                    segmentationNode.GetParentTransformNode().GetID())
            self.scriptedEffect.parameterSetNode().SetNodeReferenceID(
                ResultPreviewNodeReferenceRole, previewNode.GetID())
            self.scriptedEffect.setCommonParameter(
                "SegmentationResultPreviewOwnerEffect",
                self.scriptedEffect.name)
            self.setPreviewOpacity(0.6)

            if self.clippedMasterImageDataRequired:
                self.clippedMasterImageData = vtkSegmentationCore.vtkOrientedImageData(
                )
                masterImageClipper = vtk.vtkImageConstantPad()
                masterImageClipper.SetInputData(masterImageData)
                masterImageClipper.SetOutputWholeExtent(
                    self.mergedLabelmapGeometryImage.GetExtent())
                masterImageClipper.Update()
                self.clippedMasterImageData.ShallowCopy(
                    masterImageClipper.GetOutput())
                self.clippedMasterImageData.CopyDirections(
                    self.mergedLabelmapGeometryImage)

        previewNode.SetName(segmentationNode.GetName() + " preview")

        mergedImage = vtkSegmentationCore.vtkOrientedImageData()
        segmentationNode.GenerateMergedLabelmapForAllSegments(
            mergedImage, vtkSegmentationCore.vtkSegmentation.
            EXTENT_UNION_OF_EFFECTIVE_SEGMENTS,
            self.mergedLabelmapGeometryImage, self.selectedSegmentIds)

        outputLabelmap = vtkSegmentationCore.vtkOrientedImageData()

        self.computePreviewLabelmap(mergedImage, outputLabelmap)

        # Write output segmentation results in segments
        for index in xrange(self.selectedSegmentIds.GetNumberOfValues()):
            segmentID = self.selectedSegmentIds.GetValue(index)
            segment = segmentationNode.GetSegmentation().GetSegment(segmentID)
            # Disable save with scene?

            # Get only the label of the current segment from the output image
            thresh = vtk.vtkImageThreshold()
            thresh.ReplaceInOn()
            thresh.ReplaceOutOn()
            thresh.SetInValue(1)
            thresh.SetOutValue(0)
            labelValue = index + 1  # n-th segment label value = n + 1 (background label value is 0)
            thresh.ThresholdBetween(labelValue, labelValue)
            thresh.SetOutputScalarType(vtk.VTK_UNSIGNED_CHAR)
            thresh.SetInputData(outputLabelmap)
            thresh.Update()

            # Write label to segment
            newSegmentLabelmap = vtkSegmentationCore.vtkOrientedImageData()
            newSegmentLabelmap.ShallowCopy(thresh.GetOutput())
            newSegmentLabelmap.CopyDirections(mergedImage)
            newSegment = previewNode.GetSegmentation().GetSegment(segmentID)
            if not newSegment:
                newSegment = vtkSegmentationCore.vtkSegment()
                newSegment.SetName(segment.GetName())
                color = segmentationNode.GetSegmentation().GetSegment(
                    segmentID).GetColor()
                newSegment.SetColor(color)
                previewNode.GetSegmentation().AddSegment(newSegment, segmentID)
            slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(
                newSegmentLabelmap, previewNode, segmentID)

        self.updateGUIFromMRML()
  def preview(self):
    # Get master volume image data
    import vtkSegmentationCorePython as vtkSegmentationCore
    masterImageData = self.scriptedEffect.masterVolumeImageData()

    # Get segmentation
    segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()

    previewNode = self.getPreviewNode()
    if (not previewNode or not self.mergedLabelmapGeometryImage
      or (self.clippedMasterImageDataRequired and not self.clippedMasterImageData)):

      self.reset()
      # Compute merged labelmap extent (effective extent slightly expanded)
      self.selectedSegmentIds = vtk.vtkStringArray()
      segmentationNode.GetDisplayNode().GetVisibleSegmentIDs(self.selectedSegmentIds)
      if self.selectedSegmentIds.GetNumberOfValues() < self.minimumNumberOfSegments:
        logging.error("Auto-complete operation skipped: at least {0} visible segments are required".format(self.minimumNumberOfSegments))
        return
      if not self.mergedLabelmapGeometryImage:
        self.mergedLabelmapGeometryImage = vtkSegmentationCore.vtkOrientedImageData()
      commonGeometryString = segmentationNode.GetSegmentation().DetermineCommonLabelmapGeometry(
        vtkSegmentationCore.vtkSegmentation.EXTENT_UNION_OF_EFFECTIVE_SEGMENTS, self.selectedSegmentIds)
      if not commonGeometryString:
        logging.info("Auto-complete operation skipped: all visible segments are empty")
        return
      vtkSegmentationCore.vtkSegmentationConverter.DeserializeImageGeometry(commonGeometryString, self.mergedLabelmapGeometryImage)

      masterImageExtent = masterImageData.GetExtent()
      labelsEffectiveExtent = self.mergedLabelmapGeometryImage.GetExtent()
      # Margin size is relative to combined seed region size, but minimum of 3 voxels
      print("self.extentGrowthRatio = {0}".format(self.extentGrowthRatio))
      margin = [
        int(max(3, self.extentGrowthRatio * (labelsEffectiveExtent[1]-labelsEffectiveExtent[0]))),
        int(max(3, self.extentGrowthRatio * (labelsEffectiveExtent[3]-labelsEffectiveExtent[2]))),
        int(max(3, self.extentGrowthRatio * (labelsEffectiveExtent[5]-labelsEffectiveExtent[4]))) ]
      labelsExpandedExtent = [
        max(masterImageExtent[0], labelsEffectiveExtent[0]-margin[0]),
        min(masterImageExtent[1], labelsEffectiveExtent[1]+margin[0]),
        max(masterImageExtent[2], labelsEffectiveExtent[2]-margin[1]),
        min(masterImageExtent[3], labelsEffectiveExtent[3]+margin[1]),
        max(masterImageExtent[4], labelsEffectiveExtent[4]-margin[2]),
        min(masterImageExtent[5], labelsEffectiveExtent[5]+margin[2]) ]
      print("masterImageExtent = "+repr(masterImageExtent))
      print("labelsEffectiveExtent = "+repr(labelsEffectiveExtent))
      print("labelsExpandedExtent = "+repr(labelsExpandedExtent))
      self.mergedLabelmapGeometryImage.SetExtent(labelsExpandedExtent)

      # Create and setup preview node
      previewNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSegmentationNode")
      previewNode.CreateDefaultDisplayNodes()
      previewNode.GetDisplayNode().SetVisibility2DOutline(False)
      if segmentationNode.GetParentTransformNode():
        previewNode.SetAndObserveTransformNodeID(segmentationNode.GetParentTransformNode().GetID())
      self.scriptedEffect.parameterSetNode().SetNodeReferenceID(ResultPreviewNodeReferenceRole, previewNode.GetID())
      self.scriptedEffect.setCommonParameter("SegmentationResultPreviewOwnerEffect", self.scriptedEffect.name)
      self.setPreviewOpacity(0.6)

      # Disable smoothing for closed surface generation to make it fast
      previewNode.GetSegmentation().SetConversionParameter(
        slicer.vtkBinaryLabelmapToClosedSurfaceConversionRule.GetSmoothingFactorParameterName(),
        "-0.5");

      inputContainsClosedSurfaceRepresentation = segmentationNode.GetSegmentation().ContainsRepresentation(
        slicer.vtkSegmentationConverter.GetSegmentationClosedSurfaceRepresentationName())

      self.setPreviewShow3D(inputContainsClosedSurfaceRepresentation)

      if self.clippedMasterImageDataRequired:
        self.clippedMasterImageData = vtkSegmentationCore.vtkOrientedImageData()
        masterImageClipper = vtk.vtkImageConstantPad()
        masterImageClipper.SetInputData(masterImageData)
        masterImageClipper.SetOutputWholeExtent(self.mergedLabelmapGeometryImage.GetExtent())
        masterImageClipper.Update()
        self.clippedMasterImageData.ShallowCopy(masterImageClipper.GetOutput())
        self.clippedMasterImageData.CopyDirections(self.mergedLabelmapGeometryImage)

      self.clippedMaskImageData = None
      if self.clippedMaskImageDataRequired:
        self.clippedMaskImageData = vtkSegmentationCore.vtkOrientedImageData()
        intensityBasedMasking = self.scriptedEffect.parameterSetNode().GetMasterVolumeIntensityMask()
        success = segmentationNode.GenerateEditMask(self.clippedMaskImageData,
          self.scriptedEffect.parameterSetNode().GetMaskMode(),
          self.clippedMasterImageData, # reference geometry
          "", # edited segment ID
          self.scriptedEffect.parameterSetNode().GetMaskSegmentID() if self.scriptedEffect.parameterSetNode().GetMaskSegmentID() else "",
          self.clippedMasterImageData if intensityBasedMasking else None,
          self.scriptedEffect.parameterSetNode().GetMasterVolumeIntensityMaskRange() if intensityBasedMasking else None)
        if not success:
          logging.error("Failed to create edit mask")
          self.clippedMaskImageData = None

    previewNode.SetName(segmentationNode.GetName()+" preview")

    mergedImage = vtkSegmentationCore.vtkOrientedImageData()
    segmentationNode.GenerateMergedLabelmapForAllSegments(mergedImage,
      vtkSegmentationCore.vtkSegmentation.EXTENT_UNION_OF_EFFECTIVE_SEGMENTS, self.mergedLabelmapGeometryImage, self.selectedSegmentIds)

    outputLabelmap = vtkSegmentationCore.vtkOrientedImageData()

    self.computePreviewLabelmap(mergedImage, outputLabelmap)

    # Write output segmentation results in segments
    for index in xrange(self.selectedSegmentIds.GetNumberOfValues()):
      segmentID = self.selectedSegmentIds.GetValue(index)
      segment = segmentationNode.GetSegmentation().GetSegment(segmentID)
      # Disable save with scene?

      # Get only the label of the current segment from the output image
      thresh = vtk.vtkImageThreshold()
      thresh.ReplaceInOn()
      thresh.ReplaceOutOn()
      thresh.SetInValue(1)
      thresh.SetOutValue(0)
      labelValue = index + 1 # n-th segment label value = n + 1 (background label value is 0)
      thresh.ThresholdBetween(labelValue, labelValue);
      thresh.SetOutputScalarType(vtk.VTK_UNSIGNED_CHAR)
      thresh.SetInputData(outputLabelmap)
      thresh.Update()

      # Write label to segment
      newSegmentLabelmap = vtkSegmentationCore.vtkOrientedImageData()
      newSegmentLabelmap.ShallowCopy(thresh.GetOutput())
      newSegmentLabelmap.CopyDirections(mergedImage)
      newSegment = previewNode.GetSegmentation().GetSegment(segmentID)
      if not newSegment:
        newSegment = vtkSegmentationCore.vtkSegment()
        newSegment.SetName(segment.GetName())
        color = segmentationNode.GetSegmentation().GetSegment(segmentID).GetColor()
        newSegment.SetColor(color)
        previewNode.GetSegmentation().AddSegment(newSegment, segmentID)
      slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(newSegmentLabelmap, previewNode, segmentID)

      # Automatically hide result segments that are background (all eight corners are non-zero)
      previewNode.GetDisplayNode().SetSegmentVisibility3D(segmentID, not self.isBackgroundLabelmap(newSegmentLabelmap))

    self.updateGUIFromMRML()