Slicer学习笔记(二十三)slicer调试自带模块

关于slicer的调试设置请参考我的第二十篇博客:Slicer学习笔记(二十)slicer编写自己的扩展模块

1、调试Segment Editor模块下的Grow from seeds

这次笔记是调试 Segment Editor模块下的Grow from seeds 效应。
在这里插入图片描述

执行initialize后的打印信息:

self.extentGrowthRatio = 0.1
masterImageExtent = (0, 127, 0, 127, 0, 255)
labelsEffectiveExtent = (4, 117, 11, 119, 90, 255)
labelsExpandedExtent = [0, 127, 1, 127, 74, 255]

2、调试文件与细节

输入图像信息
在这里插入图片描述

被调试文件

C:\ProgramData\NA-MIC\Slicer 4.11.20210226\lib\Slicer-4.11\qt-scripted-modules\SegmentEditorEffects\AbstractScriptedSegmentEditorAutoCompleteEffect.py

根据调试信息可以确定对象与变量的对应关系:

masterImageData = self.scriptedEffect.masterVolumeImageData()

2.1、masterImageData的调试信息如下,可以确定该变量对应input_volume.

vtkOrientedImageData (000001B79F65CEE0)
  Debug: Off
  Modified Time: 101167526
  Reference Count: 2
  Registered Events: (none)
  Information: 000001B79AE0CE80
  Data Released: False
  Global Release Data: Off
  UpdateTime: 56141501
  Field Data:
    Debug: Off
    Modified Time: 101167524
    Reference Count: 1
    Registered Events: (none)
    Number Of Arrays: 0
    Number Of Components: 0
    Number Of Tuples: 0
  Number Of Points: 4194304
  Number Of Cells: 4112895
  Cell Data:
    Debug: Off
    Modified Time: 101167499
    Reference Count: 1
    Registered Events: 
      Registered Observers:
        vtkObserver (000001B79A31ECE0)
          Event: 36
          EventName: ModifiedEvent
          Command: 000001B79AE0D830
          Priority: 0
          Tag: 1
    Number Of Arrays: 0
    Number Of Components: 0
    Number Of Tuples: 0
    Copy Tuple Flags: ( 1 1 1 1 1 0 1 1 )
    Interpolate Flags: ( 1 1 1 1 1 0 0 1 )
    Pass Through Flags: ( 1 1 1 1 1 1 1 1 )
    Scalars: (none)
    Vectors: (none)
    Normals: (none)
    TCoords: (none)
    Tensors: (none)
    GlobalIds: (none)
    PedigreeIds: (none)
    EdgeFlag: (none)
  Point Data:
    Debug: Off
    Modified Time: 101167523
    Reference Count: 1
    Registered Events: 
      Registered Observers:
        vtkObserver (000001B79A31ECB0)
          Event: 36
          EventName: ModifiedEvent
          Command: 000001B79AE0D830
          Priority: 0
          Tag: 1
    Number Of Arrays: 1
    Array 0 name = ImageScalars
    Number Of Components: 1
    Number Of Tuples: 4194304
    Copy Tuple Flags: ( 1 1 1 1 1 0 1 1 )
    Interpolate Flags: ( 1 1 1 1 1 0 0 1 )
    Pass Through Flags: ( 1 1 1 1 1 1 1 1 )
    Scalars: 
      Debug: Off
      Modified Time: 101167522
      Reference Count: 1
      Registered Events: (none)
      Name: ImageScalars
      Data type: int
      Size: 4194304
      MaxId: 4194303
      NumberOfComponents: 1
      Information: 000001B7CFE24A20
        Debug: Off
        Modified Time: 101167548
        Reference Count: 1
        Registered Events: (none)
        PER_COMPONENT: vtkInformationVector(000001B7CFE22810)
      Name: ImageScalars
      Number Of Components: 1
      Number Of Tuples: 4194304
      Size: 4194304
      MaxId: 4194303
      LookupTable: (none)
    Vectors: (none)
    Normals: (none)
    TCoords: (none)
    Tensors: (none)
    GlobalIds: (none)
    PedigreeIds: (none)
    EdgeFlag: (none)
  Bounds: 
    Xmin,Xmax: (27, 155)
    Ymin,Ymax: (-97, 31)
    Zmin,Zmax: (-732.5, -476.5)
  Compute Time: 137081218
  Spacing: (1, 1, 1)
  Origin: (154.5, 30.5, -732)
  Dimensions: (128, 128, 256)
  Increments: (0, 0, 0)
  Extent: (0, 127, 0, 127, 0, 255)
Directions:
   -1   0   0  
   0   -1   0  
   0   0   1  

2.2、masterImageExtent变量

masterImageExtent = masterImageData.GetExtent()

masterImageExtent变量值:

Extent: (0, 127, 0, 127, 0, 255)

2.3、mergedLabelmapGeometryImage 对应的调试信息

self.mergedLabelmapGeometryImage = slicer.vtkOrientedImageData()

mergedLabelmapGeometryImage 对应的调试信息:

vtkOrientedImageData (000001B7C3AF9DB0)
   Bounds: 
    Xmin,Xmax: (29, 155)
    Ymin,Ymax: (-75, 24)
    Zmin,Zmax: (-640.5, -487.5)
  Compute Time: 137081230
  Spacing: (1, 1, 1)
  Origin: (154.5, 30.5, -732)
  Dimensions: (126, 99, 153)
  Increments: (0, 0, 0)
  Extent: (0, 125, 7, 105, 92, 244)
Directions:
   -1   0   0  
   0   -1   0  
   0   0   1  

2.4、labelsEffectiveExtent调试信息

labelsEffectiveExtent = self.mergedLabelmapGeometryImage.GetExtent()

labelsEffectiveExtent调试信息:

Extent: (0, 125, 7, 105, 92, 244)

2.5、打印输出的变量

masterImageData = self.scriptedEffect.masterVolumeImageData()
      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))

2.6、mergedImage 信息

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

调试信息

 Bounds: 
    Xmin,Xmax: (27, 155)
    Ymin,Ymax: (-97, 31)
    Zmin,Zmax: (-716.5, -476.5)
  Compute Time: 137093904
  Spacing: (1, 1, 1)
  Origin: (154.5, 30.5, -732)
  Dimensions: (128, 128, 240)
  Increments: (0, 0, 0)
  Extent: (0, 127, 0, 127, 16, 255)
Directions:
   -1   0   0  
   0   -1   0  
   0   0   1  

2.7、self.clippedMasterImageData 信息

 if not self.growCutFilter:
      self.growCutFilter = vtkSlicerSegmentationsModuleLogic.vtkImageGrowCutSegment()
      self.growCutFilter.SetIntensityVolume(self.clippedMasterImageData)
      self.growCutFilter.SetMaskVolume(self.clippedMaskImageData)

调试信息

  Bounds: 
    Xmin,Xmax: (27, 155)
    Ymin,Ymax: (-97, 31)
    Zmin,Zmax: (-716.5, -476.5)
  Compute Time: 137088616
  Spacing: (1, 1, 1)
  Origin: (154.5, 30.5, -732)
  Dimensions: (128, 128, 240)
  Increments: (0, 0, 0)
  Extent: (0, 127, 0, 127, 16, 255)
Directions:
   -1   0   0  
   0   -1   0  
   0   0   1  

3、Apply 按钮

在这里插入图片描述

C:\ProgramData\NA-MIC\Slicer 4.11.20210226\lib\Slicer-4.11\qt-scripted-modules\SegmentEditorEffects\AbstractScriptedSegmentEditorAutoCompleteEffect.py

Apply 按钮只是起一个生效的作用,实际操作是在 Initialize这个按钮完成的,也就是第2部分“调试文件与细节”中完成的。
在这里插入图片描述

4、主要计算与显示

4.1、主要计算

 def computePreviewLabelmap(self, mergedImage, outputLabelmap):
    import vtkSlicerSegmentationsModuleLogicPython as vtkSlicerSegmentationsModuleLogic

    if not self.growCutFilter:
      self.growCutFilter = vtkSlicerSegmentationsModuleLogic.vtkImageGrowCutSegment()
      self.growCutFilter.SetIntensityVolume(self.clippedMasterImageData)
      self.growCutFilter.SetMaskVolume(self.clippedMaskImageData)
      maskExtent = self.clippedMaskImageData.GetExtent() if self.clippedMaskImageData else None
      if maskExtent is not None and maskExtent[0] <= maskExtent[1] and maskExtent[2] <= maskExtent[3] and maskExtent[4] <= maskExtent[5]:
        # Mask is used.
        # Grow the extent more, as background segment does not surround region of interest.
        self.extentGrowthRatio = 0.50
      else:
        # No masking is used.
        # Background segment is expected to surround region of interest, so narrower margin is enough.
        self.extentGrowthRatio = 0.20

    if self.scriptedEffect.parameterDefined("SeedLocalityFactor"):
      seedLocalityFactor = self.scriptedEffect.doubleParameter("SeedLocalityFactor")
    else:
      seedLocalityFactor = 0.0
    self.growCutFilter.SetDistancePenalty(seedLocalityFactor)
    self.growCutFilter.SetSeedLabelVolume(mergedImage)
    startTime = time.time()
    self.growCutFilter.Update()
    logging.info('Grow-cut operation on volume of {0}x{1}x{2} voxels was completed in {3:3.1f} seconds.'.format(
      self.clippedMasterImageData.GetDimensions()[0],
      self.clippedMasterImageData.GetDimensions()[1],
      self.clippedMasterImageData.GetDimensions()[2],
      time.time() - startTime))

    outputLabelmap.DeepCopy( self.growCutFilter.GetOutput() )

4.2、Initialize和Applay

4.2.1 Initialize

 def preview(self):
    # Get master volume image data
    import vtkSegmentationCorePython as vtkSegmentationCore

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

    previewNode = self.getPreviewNode()
    previewOpacity = self.getPreviewOpacity()
    previewShow3D = self.getPreviewShow3D()

    # If the selectedSegmentIds have been specified, then they shouldn't be overwritten here
    currentSelectedSegmentIds = self.selectedSegmentIds

    if self.effectiveExtentChanged():
      self.reset()

      # Restore the selectedSegmentIds
      self.selectedSegmentIds = currentSelectedSegmentIds
      if self.selectedSegmentIds is None:
        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))
        self.selectedSegmentIds = None
        return

      # Compute merged labelmap extent (effective extent slightly expanded)
      if not self.mergedLabelmapGeometryImage:
        self.mergedLabelmapGeometryImage = slicer.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)

      masterImageData = self.scriptedEffect.masterVolumeImageData()
      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 = slicer.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 = slicer.vtkOrientedImageData()
        intensityBasedMasking = self.scriptedEffect.parameterSetNode().GetMasterVolumeIntensityMask()
        # add wmz
        mode = self.scriptedEffect.parameterSetNode().GetMaskMode()
        maskSegmentID = self.scriptedEffect.parameterSetNode().GetMaskSegmentID() if self.scriptedEffect.parameterSetNode().GetMaskSegmentID() else ""
        masterVolume = self.clippedMasterImageData if intensityBasedMasking else None
        editableIntensityRange = self.scriptedEffect.parameterSetNode().GetMasterVolumeIntensityMaskRange() if intensityBasedMasking else None
        # add wmz
        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
        maskExtent = self.clippedMaskImageData.GetExtent() if self.clippedMaskImageData else None  # add wmz

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

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

    outputLabelmap = slicer.vtkOrientedImageData()

    self.computePreviewLabelmap(mergedImage, outputLabelmap)

    # Write output segmentation results in segments
    for index in range(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 = slicer.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)
      self.scriptedEffect.modifySegmentByLabelmap(previewNode, segmentID, newSegmentLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet)

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

    # If the preview was reset, we need to restore the visibility options
    self.setPreviewOpacity(previewOpacity)
    self.setPreviewShow3D(previewShow3D)

    self.updateGUIFromMRML()

ResultPreviewNodeReferenceRole = "SegmentationResultPreview"

4.2.2、Apply

 def onApply(self):
    self.delayedAutoUpdateTimer.stop()
    self.observeSegmentation(False)

    import vtkSegmentationCorePython as vtkSegmentationCore
    segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()
    segmentationDisplayNode = segmentationNode.GetDisplayNode()
    previewNode = self.getPreviewNode()

    self.scriptedEffect.saveStateForUndo()

    previewContainsClosedSurfaceRepresentation = previewNode.GetSegmentation().ContainsRepresentation(
      slicer.vtkSegmentationConverter.GetSegmentationClosedSurfaceRepresentationName())

    # Move segments from preview into current segmentation
    segmentIDs = vtk.vtkStringArray()
    previewNode.GetSegmentation().GetSegmentIDs(segmentIDs)
    for index in range(segmentIDs.GetNumberOfValues()):
      segmentID = segmentIDs.GetValue(index)
      previewSegmentLabelmap = slicer.vtkOrientedImageData()
      previewNode.GetBinaryLabelmapRepresentation(segmentID, previewSegmentLabelmap)
      self.scriptedEffect.modifySegmentByLabelmap(segmentationNode, segmentID, previewSegmentLabelmap,
        slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet)
      if segmentationDisplayNode is not None and self.isBackgroundLabelmap(previewSegmentLabelmap):
        # Automatically hide result segments that are background (all eight corners are non-zero)
        segmentationDisplayNode.SetSegmentVisibility(segmentID, False)
      previewNode.GetSegmentation().RemoveSegment(segmentID) # delete now to limit memory usage

    if previewContainsClosedSurfaceRepresentation:
      segmentationNode.CreateClosedSurfaceRepresentation()

    self.reset()

猜你喜欢

转载自blog.csdn.net/juluwangriyue/article/details/120981989
今日推荐