def selectParameterNode(self): # Select parameter set node if one is found in the scene, and create one otherwise segmentEditorSingletonTag = "SegmentEditor" segmentEditorNode = slicer.mrmlScene.GetSingletonNode(segmentEditorSingletonTag, "vtkMRMLSegmentEditorNode") if segmentEditorNode is None: segmentEditorNode = slicer.vtkMRMLSegmentEditorNode() segmentEditorNode.SetSingletonTag(segmentEditorSingletonTag) segmentEditorNode = slicer.mrmlScene.AddNode(segmentEditorNode) if self.parameterSetNode == segmentEditorNode: # nothing changed return self.parameterSetNode = segmentEditorNode self.editor.setMRMLSegmentEditorNode(self.parameterSetNode)
def test_ScriptedSegmentEditorEffectModuleTemplate1(self): """ Basic automated test of the segmentation method: - Create segmentation by placing sphere-shaped seeds - Run segmentation - Verify results using segment statistics The test can be executed from SelfTests module (test name: SegmentEditorScriptedSegmentEditorEffectModuleTemplate) """ self.delayDisplay("Starting test_ScriptedSegmentEditorEffectModuleTemplate1") import vtkSegmentationCorePython as vtkSegmentationCore import vtkSlicerSegmentationsModuleLogicPython as vtkSlicerSegmentationsModuleLogic import SampleData from SegmentStatistics import SegmentStatisticsLogic ################################## self.delayDisplay("Load master volume") import SampleData sampleDataLogic = SampleData.SampleDataLogic() masterVolumeNode = sampleDataLogic.downloadMRBrainTumor1() ################################## self.delayDisplay("Create segmentation containing a few spheres") segmentationNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSegmentationNode") segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(masterVolumeNode) # Segments are defined by a list of: name and a list of sphere [radius, posX, posY, posZ] segmentGeometries = [ ['Tumor', [[10, -6,30,28]]], ['Background', [[10, 0,65,22], [15, 1, -14, 30], [12, 0, 28, -7], [5, 0,30,54], [12, 31, 33, 27], [17, -42, 30, 27], [6, -2,-17,71]]], ['Air', [[10, 76,73,0], [15, -70,74,0]]] ] for segmentGeometry in segmentGeometries: segmentName = segmentGeometry[0] appender = vtk.vtkAppendPolyData() for sphere in segmentGeometry[1]: sphereSource = vtk.vtkSphereSource() sphereSource.SetRadius(sphere[0]) sphereSource.SetCenter(sphere[1], sphere[2], sphere[3]) appender.AddInputConnection(sphereSource.GetOutputPort()) segment = vtkSegmentationCore.vtkSegment() segment.SetName(segmentationNode.GetSegmentation().GenerateUniqueSegmentID(segmentName)) appender.Update() segment.AddRepresentation(vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationClosedSurfaceRepresentationName(), appender.GetOutput()) segmentationNode.GetSegmentation().AddSegment(segment) ################################## self.delayDisplay("Create segment editor") segmentEditorWidget = slicer.qMRMLSegmentEditorWidget() segmentEditorWidget.show() segmentEditorWidget.setMRMLScene(slicer.mrmlScene) segmentEditorNode = slicer.vtkMRMLSegmentEditorNode() slicer.mrmlScene.AddNode(segmentEditorNode) segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode) segmentEditorWidget.setSegmentationNode(segmentationNode) segmentEditorWidget.setMasterVolumeNode(masterVolumeNode) ################################## self.delayDisplay("Run segmentation") segmentEditorWidget.setActiveEffectByName("ScriptedSegmentEditorEffectModuleTemplate") effect = segmentEditorWidget.activeEffect() effect.setParameter("ObjectScaleMm", 3.0) effect.self().onApply() ################################## self.delayDisplay("Make segmentation results nicely visible in 3D") segmentationDisplayNode = segmentationNode.GetDisplayNode() segmentationDisplayNode.SetSegmentVisibility("Air", False) segmentationDisplayNode.SetSegmentOpacity3D("Background",0.5) ################################## self.delayDisplay("Compute statistics") segStatLogic = SegmentStatisticsLogic() segStatLogic.computeStatistics(segmentationNode, masterVolumeNode) # Export results to table (just to see all results) resultsTableNode = slicer.vtkMRMLTableNode() slicer.mrmlScene.AddNode(resultsTableNode) segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) self.delayDisplay("Check a few numerical results") self.assertEqual( round(segStatLogic.statistics["Tumor","LM volume cc"]), 16) self.assertEqual( round(segStatLogic.statistics["Background","LM volume cc"]), 3010) self.delayDisplay('test_ScriptedSegmentEditorEffectModuleTemplate1 passed')
def test_SurfaceCut1(self): """ Basic automated test of the segmentation method: - Create segmentation by placing sphere-shaped seeds - Run segmentation - Verify results using segment statistics The test can be executed from SelfTests module (test name: SegmentEditorSurfaceCut) """ self.delayDisplay("Starting test_SurfaceCut1") import vtkSegmentationCorePython as vtkSegmentationCore import vtkSlicerSegmentationsModuleLogicPython as vtkSlicerSegmentationsModuleLogic import SampleData from SegmentStatistics import SegmentStatisticsLogic ################################## self.delayDisplay("Load master volume") import SampleData sampleDataLogic = SampleData.SampleDataLogic() masterVolumeNode = sampleDataLogic.downloadMRBrainTumor1() ################################## self.delayDisplay("Create segmentation containing a few spheres") segmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(segmentationNode) segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode( masterVolumeNode) # Segments are defined by a list of: name and a list of sphere [radius, posX, posY, posZ] segmentGeometries = [['Tumor', [[10, -6, 30, 28]]], [ 'Background', [[10, 0, 65, 22], [15, 1, -14, 30], [12, 0, 28, -7], [5, 0, 30, 54], [12, 31, 33, 27], [17, -42, 30, 27], [6, -2, -17, 71]] ], ['Air', [[10, 76, 73, 0], [15, -70, 74, 0]]]] for segmentGeometry in segmentGeometries: segmentName = segmentGeometry[0] appender = vtk.vtkAppendPolyData() for sphere in segmentGeometry[1]: sphereSource = vtk.vtkSphereSource() sphereSource.SetRadius(sphere[0]) sphereSource.SetCenter(sphere[1], sphere[2], sphere[3]) appender.AddInputConnection(sphereSource.GetOutputPort()) segment = vtkSegmentationCore.vtkSegment() segment.SetName( segmentationNode.GetSegmentation().GenerateUniqueSegmentID( segmentName)) appender.Update() segment.AddRepresentation( vtkSegmentationCore.vtkSegmentationConverter. GetSegmentationClosedSurfaceRepresentationName(), appender.GetOutput()) segmentationNode.GetSegmentation().AddSegment(segment) ################################## self.delayDisplay("Create segment editor") segmentEditorWidget = slicer.qMRMLSegmentEditorWidget() segmentEditorWidget.show() segmentEditorWidget.setMRMLScene(slicer.mrmlScene) segmentEditorNode = slicer.vtkMRMLSegmentEditorNode() slicer.mrmlScene.AddNode(segmentEditorNode) segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode) segmentEditorWidget.setSegmentationNode(segmentationNode) segmentEditorWidget.setMasterVolumeNode(masterVolumeNode) ################################## self.delayDisplay("Run segmentation") segmentEditorWidget.setActiveEffectByName("SurfaceCut") effect = segmentEditorWidget.activeEffect() effect.setParameter("ObjectScaleMm", 3.0) effect.self().onApply() ################################## self.delayDisplay("Make segmentation results nicely visible in 3D") segmentationDisplayNode = segmentationNode.GetDisplayNode() segmentationDisplayNode.SetSegmentVisibility("Air", False) segmentationDisplayNode.SetSegmentOpacity3D("Background", 0.5) ################################## self.delayDisplay("Compute statistics") segStatLogic = SegmentStatisticsLogic() segStatLogic.computeStatistics(segmentationNode, masterVolumeNode) # Export results to table (just to see all results) resultsTableNode = slicer.vtkMRMLTableNode() slicer.mrmlScene.AddNode(resultsTableNode) segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) self.delayDisplay("Check a few numerical results") self.assertEqual( round(segStatLogic.statistics["Tumor", "LM volume cc"]), 16) self.assertEqual( round(segStatLogic.statistics["Background", "LM volume cc"]), 3010) self.delayDisplay('test_SurfaceCut1 passed')
def run(self, inputVolume, outputSegmentation, smoothingKernelSize=3.0): """ Run the processing algorithm. Can be used without GUI widget. :param inputVolume: volume to be segmented :param outputSegmentation: segmentation to sore the result in :param smoothingKernelSize: this is used for closing small holes in the segmentation """ if not inputVolume or not outputSegmentation: raise ValueError("Input volume or output segmentation is invalid") logging.info('Processing started') # Compute bone threshold value automatically import vtkITK thresholdCalculator = vtkITK.vtkITKImageThresholdCalculator() thresholdCalculator.SetInputData(inputVolume.GetImageData()) thresholdCalculator.SetMethodToOtsu() thresholdCalculator.Update() boneThresholdValue = thresholdCalculator.GetThreshold() volumeScalarRange = inputVolume.GetImageData().GetScalarRange() logging.debug( "Volume minimum = {0}, maximum = {1}, bone threshold = {2}".format( volumeScalarRange[0], volumeScalarRange[1], boneThresholdValue)) # Set up segmentation outputSegmentation.CreateDefaultDisplayNodes() outputSegmentation.SetReferenceImageGeometryParameterFromVolumeNode( inputVolume) # Create segment editor to get access to effects segmentEditorWidget = slicer.qMRMLSegmentEditorWidget() # To show segment editor widget (useful for debugging): segmentEditorWidget.show() segmentEditorWidget.setMRMLScene(slicer.mrmlScene) if not segmentEditorWidget.effectByName("Wrap Solidify"): raise NotImplementedError( "SurfaceWrapSolidify extension is required") segmentEditorNode = slicer.vtkMRMLSegmentEditorNode() slicer.mrmlScene.AddNode(segmentEditorNode) segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode) segmentEditorWidget.setSegmentationNode(outputSegmentation) segmentEditorWidget.setMasterVolumeNode(inputVolume) # Create bone segment by thresholding boneSegmentID = outputSegmentation.GetSegmentation().AddEmptySegment( "bone") segmentEditorNode.SetSelectedSegmentID(boneSegmentID) segmentEditorWidget.setActiveEffectByName("Threshold") effect = segmentEditorWidget.activeEffect() effect.setParameter("MinimumThreshold", str(boneThresholdValue)) effect.setParameter("MaximumThreshold", str(volumeScalarRange[1])) effect.self().onApply() # Smooth bone segment (just to reduce solidification computation time) segmentEditorWidget.setActiveEffectByName("Smoothing") effect = segmentEditorWidget.activeEffect() effect.setParameter("SmoothingMethod", "MORPHOLOGICAL_CLOSING") effect.setParameter("KernelSizeMm", str(smoothingKernelSize)) effect.self().onApply() # Solidify bone segmentEditorWidget.setActiveEffectByName("Wrap Solidify") effect = segmentEditorWidget.activeEffect() effect.self().onApply() # Create segment for cavity within bone region using thresholding segmentEditorNode.SetOverwriteMode( slicer.vtkMRMLSegmentEditorNode.OverwriteNone) segmentEditorNode.SetMaskMode( slicer.vtkMRMLSegmentEditorNode.PaintAllowedInsideAllSegments) cavitySegmentID = outputSegmentation.GetSegmentation().AddEmptySegment( "cavity") segmentEditorNode.SetSelectedSegmentID(cavitySegmentID) segmentEditorWidget.setActiveEffectByName("Threshold") effect = segmentEditorWidget.activeEffect() effect.setParameter("MinimumThreshold", str(volumeScalarRange[0])) effect.setParameter("MaximumThreshold", str(boneThresholdValue)) effect.self().onApply() # Cavity shrink segmentEditorWidget.setActiveEffectByName("Margin") effect = segmentEditorWidget.activeEffect() effect.setParameter("MarginSizeMm", str(-smoothingKernelSize)) effect.self().onApply() # Find largest cavity segmentEditorWidget.setActiveEffectByName("Islands") effect = segmentEditorWidget.activeEffect() effect.setParameterDefault("Operation", "KEEP_LARGEST_ISLAND") effect.self().onApply() # Cavity restore segmentEditorNode.SetMaskMode( slicer.vtkMRMLSegmentEditorNode.PaintAllowedInsideAllSegments ) # ensure we don't leak into bone segmentEditorWidget.setActiveEffectByName("Margin") effect = segmentEditorWidget.activeEffect() effect.setParameter("MarginSizeMm", str(smoothingKernelSize)) effect.self().onApply() # Clean up slicer.mrmlScene.RemoveNode(segmentEditorNode) outputSegmentation.RemoveSegment(boneSegmentID) segmentEditorWidget = None logging.info('Processing completed')
def test_WrapSolidify1(self): """ Basic automated test of the segmentation method: - Create segmentation by placing sphere-shaped seeds - Run segmentation - Verify results using segment statistics The test can be executed from SelfTests module (test name: SegmentEditorWrapSolidify) """ self.delayDisplay("Starting test_WrapSolidify1") import vtkSegmentationCorePython as vtkSegmentationCore import vtkSlicerSegmentationsModuleLogicPython as vtkSlicerSegmentationsModuleLogic import SampleData from SegmentStatistics import SegmentStatisticsLogic ################################## self.delayDisplay("Load master volume") masterVolumeNode = SampleData.downloadSample('MRBrainTumor1') ################################## self.delayDisplay("Create segmentation containing a two spheres") segmentationNode = slicer.mrmlScene.AddNewNodeByClass( 'vtkMRMLSegmentationNode') segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode( masterVolumeNode) features = ["none", "carveCavities", "createShell", "both"] spheres = [[20, 5, 5, 5], [20, -5, -5, -5]] appender = vtk.vtkAppendPolyData() for sphere in spheres: sphereSource = vtk.vtkSphereSource() sphereSource.SetRadius(sphere[0]) sphereSource.SetCenter(sphere[1], sphere[2], sphere[3]) appender.AddInputConnection(sphereSource.GetOutputPort()) for m in features: segmentName = str(m) segment = vtkSegmentationCore.vtkSegment() segment.SetName( segmentationNode.GetSegmentation().GenerateUniqueSegmentID( segmentName)) appender.Update() segment.AddRepresentation( vtkSegmentationCore.vtkSegmentationConverter. GetSegmentationClosedSurfaceRepresentationName(), appender.GetOutput()) segmentationNode.GetSegmentation().AddSegment(segment) ################################## self.delayDisplay("Create segment editor") segmentEditorWidget = slicer.qMRMLSegmentEditorWidget() segmentEditorWidget.show() segmentEditorWidget.setMRMLScene(slicer.mrmlScene) segmentEditorNode = slicer.vtkMRMLSegmentEditorNode() slicer.mrmlScene.AddNode(segmentEditorNode) segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode) segmentEditorWidget.setSegmentationNode(segmentationNode) segmentEditorWidget.setMasterVolumeNode(masterVolumeNode) ################################## self.delayDisplay("Run WrapSolidify Effect") segmentEditorWidget.setActiveEffectByName("Wrap Solidify") effect = segmentEditorWidget.activeEffect() for t in ["SEGMENTATION", "MODEL"]: effect.setParameter("outputType", t) self.delayDisplay( "Creating Output Type %s, activated feature none" % (t)) segmentEditorWidget.setCurrentSegmentID( segmentationNode.GetSegmentation().GetSegmentIdBySegmentName( 'none')) effect.setParameter("carveCavities", False) effect.setParameter("createShell", False) effect.self().onApply() self.delayDisplay( "Creating Output Type %s, activated feature carveCavities" % (t)) effect.setParameter("carveCavities", True) effect.setParameter("createShell", False) segmentEditorWidget.setCurrentSegmentID( segmentationNode.GetSegmentation().GetSegmentIdBySegmentName( 'carveCavities')) effect.self().onApply() self.delayDisplay( "Creating Output Type %s, activated feature createShell" % (t)) effect.setParameter("carveCavities", False) effect.setParameter("createShell", True) segmentEditorWidget.setCurrentSegmentID( segmentationNode.GetSegmentation().GetSegmentIdBySegmentName( 'createShell')) effect.self().onApply() self.delayDisplay( "Creating Output Type %s, activated feature both" % (t)) effect.setParameter("carveCavities", True) effect.setParameter("createShell", True) segmentEditorWidget.setCurrentSegmentID( segmentationNode.GetSegmentation().GetSegmentIdBySegmentName( 'both')) effect.self().onApply() ################################## self.delayDisplay("Creating Segments from Models") for m in features: model = slicer.util.getNode(m) segmentName = "MODEL_%s" % m segment = vtkSegmentationCore.vtkSegment() segment.SetName( segmentationNode.GetSegmentation().GenerateUniqueSegmentID( segmentName)) segment.SetColor(model.GetDisplayNode().GetColor()) segment.AddRepresentation( vtkSegmentationCore.vtkSegmentationConverter. GetSegmentationClosedSurfaceRepresentationName(), model.GetPolyData()) segmentationNode.GetSegmentation().AddSegment(segment) ################################## self.delayDisplay("Compute statistics") segStatLogic = SegmentStatisticsLogic() segStatLogic.getParameterNode().SetParameter("Segmentation", segmentationNode.GetID()) segStatLogic.getParameterNode().SetParameter("ScalarVolume", masterVolumeNode.GetID()) segStatLogic.computeStatistics() statistics = segStatLogic.getStatistics() ################################## self.delayDisplay("Check a few numerical results") # logging.info(round(statistics["none",'ScalarVolumeSegmentStatisticsPlugin.volume_mm3'])) # logging.info(round(statistics["MODEL_none",'ScalarVolumeSegmentStatisticsPlugin.volume_mm3'])) # logging.info(round(statistics["carveCavities",'ScalarVolumeSegmentStatisticsPlugin.volume_mm3'])) # logging.info(round(statistics["MODEL_carveCavities",'ScalarVolumeSegmentStatisticsPlugin.volume_mm3'])) # logging.info(round(statistics["createShell",'ScalarVolumeSegmentStatisticsPlugin.volume_mm3'])) # logging.info(round(statistics["MODEL_createShell",'ScalarVolumeSegmentStatisticsPlugin.volume_mm3'])) # logging.info(round(statistics["both",'ScalarVolumeSegmentStatisticsPlugin.volume_mm3'])) # logging.info(round(statistics["MODEL_both",'ScalarVolumeSegmentStatisticsPlugin.volume_mm3'])) self.assertEqual( round( statistics["none", 'ScalarVolumeSegmentStatisticsPlugin.volume_mm3']), 46605) self.assertEqual( round( statistics["MODEL_none", 'ScalarVolumeSegmentStatisticsPlugin.volume_mm3']), 46320) self.assertEqual( round( statistics["carveCavities", 'ScalarVolumeSegmentStatisticsPlugin.volume_mm3']), 46605) self.assertEqual( round( statistics["MODEL_carveCavities", 'ScalarVolumeSegmentStatisticsPlugin.volume_mm3']), 46321) self.assertEqual( round( statistics["createShell", 'ScalarVolumeSegmentStatisticsPlugin.volume_mm3']), 9257) self.assertEqual( round( statistics["MODEL_createShell", 'ScalarVolumeSegmentStatisticsPlugin.volume_mm3']), 9230) self.assertEqual( round( statistics["both", 'ScalarVolumeSegmentStatisticsPlugin.volume_mm3']), 9254) self.assertEqual( round( statistics["MODEL_both", 'ScalarVolumeSegmentStatisticsPlugin.volume_mm3']), 9245) self.delayDisplay('test_WrapSolidify1 passed')
def test_SurfaceCut1(self): """ Basic automated test of the segmentation method: - Create segmentation by placing fiducials around tumor - Apply - Verify results using segment statistics The test can be executed from SelfTests module (test name: SegmentEditorSurfaceCut) """ self.delayDisplay("Starting test_SurfaceCut1") ################################## self.delayDisplay("Load master volume") import SampleData sampleDataLogic = SampleData.SampleDataLogic() masterVolumeNode = sampleDataLogic.downloadMRBrainTumor1() ################################## self.delayDisplay("Create tumor segmentation") segmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(segmentationNode) segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(masterVolumeNode) segmentName = "Tumor" import vtkSegmentationCorePython as vtkSegmentationCore segment = vtkSegmentationCore.vtkSegment() segment.SetName(segmentationNode.GetSegmentation().GenerateUniqueSegmentID(segmentName)) segmentationNode.GetSegmentation().AddSegment(segment) ################################## self.delayDisplay("Create segment editor") segmentEditorWidget = slicer.qMRMLSegmentEditorWidget() segmentEditorWidget.show() segmentEditorWidget.setMRMLScene(slicer.mrmlScene) segmentEditorNode = slicer.vtkMRMLSegmentEditorNode() slicer.mrmlScene.AddNode(segmentEditorNode) segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode) segmentEditorWidget.setSegmentationNode(segmentationNode) segmentEditorWidget.setMasterVolumeNode(masterVolumeNode) ################################## self.delayDisplay("Run segmentation") segmentEditorWidget.setActiveEffectByName("Surface cut") effect = segmentEditorWidget.activeEffect() effect.self().fiducialPlacementToggle.placeButton().click() points =[[2.589283578714074, 44.60536690073953, 27.299999999999997], [8.515228351086698, 35.22262101114956, 27.299999999999997], [13.700430026912741, 25.099132025013006, 27.299999999999997], [5.799170330415919, 19.17318725264039, 27.299999999999997], [2.589283578714074, 9.296612632019361, 27.299999999999997], [-10.250263428093263, 12.25958501820567, 27.299999999999997], [-16.17620820046588, 18.185529790578286, 27.299999999999997], [-20.373752414229813, 27.568275680168263, 27.299999999999997], [-15.929293834950343, 38.679422128366916, 27.299999999999997], [-11.484835255670887, 44.11153816970849, 27.299999999999997], [6.539913426962492, 33.49422045254088, 31.499999999999993], [1.354711751136449, 42.383137611099805, 31.499999999999993], [-8.768777235000101, 44.35845253522401, 31.499999999999993], [-14.200893276341674, 36.70410720424271, 31.499999999999993], [-18.398437490105607, 27.07444694913721, 31.499999999999993], [-12.719407083248512, 16.704043597485132, 31.499999999999993], [-7.534205407422476, 11.765756287174618, 31.499999999999993], [0.12013992355882408, 12.25958501820567, 31.499999999999993], [5.799170330415919, 16.21021486645408, 31.499999999999993], [8.268313985571176, 21.642330907795646, 31.499999999999993], [13.947344392428263, 26.827532583621682, 31.499999999999993], [-3.0897468281430065, 32.50656299047878, 45.49999999999998], [2.589283578714074, 27.32136131465274, 45.49999999999998], [-5.3119761177827485, 21.642330907795646, 45.49999999999998], [-8.02803413845352, 27.32136131465274, 45.49999999999998], [-14.694722007372718, 30.778162431870093, 38.499999999999986], [-8.02803413845352, 12.01267065269014, 38.499999999999986], [-3.583575559174065, 39.66707959042902, 11.900000000000007], [3.576941040776184, 31.765819893932196, 11.900000000000007], [0.12013992355882408, 20.901587811249065, 11.900000000000007], [-9.26260596603116, 28.555933142230366, 11.900000000000007], [6.046084695931441, 38.432507762851394, 17.500000000000007], [-17.163865662527982, 33.7411348180564, 17.500000000000007], [-14.200893276341674, 21.889245273311168, 17.500000000000007]] for p in points: effect.self().segmentMarkupNode.AddFiducialFromArray(p) effect.self().onApply() ################################## self.delayDisplay("Make segmentation results nicely visible in 3D") segmentationDisplayNode = segmentationNode.GetDisplayNode() segmentationDisplayNode.SetSegmentVisibility(segmentName, True) slicer.util.findChild(segmentEditorWidget, "Show3DButton").checked = True segmentationDisplayNode.SetSegmentOpacity3D("Background",0.5) ################################## self.delayDisplay("Compute statistics") from SegmentStatistics import SegmentStatisticsLogic segStatLogic = SegmentStatisticsLogic() segStatLogic.getParameterNode().SetParameter("Segmentation", segmentationNode.GetID()) segStatLogic.getParameterNode().SetParameter("ScalarVolume", masterVolumeNode.GetID()) segStatLogic.getParameterNode().SetParameter("visibleSegmentsOnly", "False") segStatLogic.computeStatistics() # Export results to table (just to see all results) resultsTableNode = slicer.vtkMRMLTableNode() slicer.mrmlScene.AddNode(resultsTableNode) segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) self.delayDisplay("Check a few numerical results") stats = segStatLogic.getStatistics() self.assertEqual( round(stats['Tumor', 'LabelmapSegmentStatisticsPlugin.volume_mm3']), 19498.0) self.delayDisplay('test_SurfaceCut1 passed')
def test_TDIO1(self): """ Basic automated test of the segmentation method: - Create segmentation by placing sphere-shaped seeds - Run segmentation - Verify results using segment statistics The test can be executed from SelfTests module (test name: SegmentEditorTDIO) """ self.delayDisplay('Starting test_TDIO1') import vtkSegmentationCorePython as vtkSegmentationCore, vtkSlicerSegmentationsModuleLogicPython as vtkSlicerSegmentationsModuleLogic, SampleData from SegmentStatistics import SegmentStatisticsLogic self.delayDisplay('Load master volume') masterVolumeNode = SampleData.downloadSample('MRBrainTumor1') self.delayDisplay('Create segmentation containing a few spheres') segmentationNode = slicer.mrmlScene.AddNewNodeByClass( 'vtkMRMLSegmentationNode') segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode( masterVolumeNode) segmentGeometries = [['Tumor', [[10, -6, 30, 28]]], [ 'Background', [[10, 0, 65, 22], [15, 1, -14, 30], [12, 0, 28, -7], [5, 0, 30, 54], [12, 31, 33, 27], [17, -42, 30, 27], [6, -2, -17, 71]] ], ['Air', [[10, 76, 73, 0], [15, -70, 74, 0]]]] for segmentGeometry in segmentGeometries: segmentName = segmentGeometry[0] appender = vtk.vtkAppendPolyData() for sphere in segmentGeometry[1]: sphereSource = vtk.vtkSphereSource() sphereSource.SetRadius(sphere[0]) sphereSource.SetCenter(sphere[1], sphere[2], sphere[3]) appender.AddInputConnection(sphereSource.GetOutputPort()) segment = vtkSegmentationCore.vtkSegment() segment.SetName( segmentationNode.GetSegmentation().GenerateUniqueSegmentID( segmentName)) appender.Update() segment.AddRepresentation( vtkSegmentationCore.vtkSegmentationConverter. GetSegmentationClosedSurfaceRepresentationName(), appender.GetOutput()) segmentationNode.GetSegmentation().AddSegment(segment) self.delayDisplay('Create segment editor') segmentEditorWidget = slicer.qMRMLSegmentEditorWidget() segmentEditorWidget.show() segmentEditorWidget.setMRMLScene(slicer.mrmlScene) segmentEditorNode = slicer.vtkMRMLSegmentEditorNode() slicer.mrmlScene.AddNode(segmentEditorNode) segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode) segmentEditorWidget.setSegmentationNode(segmentationNode) segmentEditorWidget.setMasterVolumeNode(masterVolumeNode) self.delayDisplay('Run segmentation') segmentEditorWidget.setActiveEffectByName('TDIO') effect = segmentEditorWidget.activeEffect() effect.setParameter('ObjectScaleMm', 3.0) effect.self().onApply() self.delayDisplay('Make segmentation results nicely visible in 3D') segmentationDisplayNode = segmentationNode.GetDisplayNode() segmentationDisplayNode.SetSegmentVisibility('Air', False) segmentationDisplayNode.SetSegmentOpacity3D('Background', 0.5) self.delayDisplay('Compute statistics') segStatLogic = SegmentStatisticsLogic() segStatLogic.computeStatistics(segmentationNode, masterVolumeNode) resultsTableNode = slicer.vtkMRMLTableNode() slicer.mrmlScene.AddNode(resultsTableNode) segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) self.delayDisplay('Check a few numerical results') self.assertEqual( round(segStatLogic.statistics[('Tumor', 'LM volume cc')]), 16) self.assertEqual( round(segStatLogic.statistics[('Background', 'LM volume cc')]), 3010) self.delayDisplay('test_TDIO1 passed')
def run(self, inputVolume, outputSegmentation, smoothingKernelSize=3.0, splitCavitiesDiameter=15.0): """ Run the processing algorithm. Can be used without GUI widget. :param inputVolume: volume to be segmented :param outputSegmentation: segmentation to sore the result in :param smoothingKernelSize: this is used for closing small holes in the segmentation :param splitCavitiesDiameter: plugs in holes smaller than splitCavitiesDiamater. """ if not inputVolume or not outputSegmentation: raise ValueError("Input volume or output segmentation is invalid") logging.info('Processing started') # Compute bone threshold value automatically import vtkITK thresholdCalculator = vtkITK.vtkITKImageThresholdCalculator() thresholdCalculator.SetInputData(inputVolume.GetImageData()) # thresholdCalculator.SetMethodToOtsu() - this does not always work (see for example CTHead example data set) thresholdCalculator.SetMethodToMaximumEntropy() thresholdCalculator.Update() boneThresholdValue = thresholdCalculator.GetThreshold() volumeScalarRange = inputVolume.GetImageData().GetScalarRange() logging.debug( f"Volume minimum = {volumeScalarRange[0]}, maximum = {volumeScalarRange[1]}, bone threshold = {boneThresholdValue}" ) # Set up segmentation outputSegmentation.CreateDefaultDisplayNodes() outputSegmentation.SetReferenceImageGeometryParameterFromVolumeNode( inputVolume) # Create segment editor to get access to effects segmentEditorWidget = slicer.qMRMLSegmentEditorWidget() # To show segment editor widget (useful for debugging): segmentEditorWidget.show() segmentEditorWidget.setMRMLScene(slicer.mrmlScene) if not segmentEditorWidget.effectByName("Wrap Solidify"): raise NotImplementedError( "SurfaceWrapSolidify extension is required") segmentEditorNode = slicer.vtkMRMLSegmentEditorNode() slicer.mrmlScene.AddNode(segmentEditorNode) segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode) segmentEditorWidget.setSegmentationNode(outputSegmentation) segmentEditorWidget.setMasterVolumeNode(inputVolume) # Create bone segment by thresholding boneSegmentID = outputSegmentation.GetSegmentation().AddEmptySegment( "bone") segmentEditorNode.SetSelectedSegmentID(boneSegmentID) segmentEditorWidget.setActiveEffectByName("Threshold") effect = segmentEditorWidget.activeEffect() effect.setParameter("MinimumThreshold", str(boneThresholdValue)) effect.setParameter("MaximumThreshold", str(volumeScalarRange[1])) effect.self().onApply() # Smooth bone segment (just to reduce solidification computation time) segmentEditorWidget.setActiveEffectByName("Smoothing") effect = segmentEditorWidget.activeEffect() effect.setParameter("SmoothingMethod", "MORPHOLOGICAL_CLOSING") effect.setParameter("KernelSizeMm", str(smoothingKernelSize)) effect.self().onApply() # Solidify bone segmentEditorWidget.setActiveEffectByName("Wrap Solidify") effect = segmentEditorWidget.activeEffect() effect.setParameter("region", "largestCavity") effect.setParameter("splitCavities", "True" if splitCavitiesDiameter > 0 else "False") effect.setParameter("splitCavitiesDiameter", str(splitCavitiesDiameter)) # in mm effect.setParameter("outputType", "newSegment") # in mm effect.self().onApply() # Clean up #slicer.mrmlScene.RemoveNode(segmentEditorNode) #outputSegmentation.RemoveSegment(boneSegmentID) #segmentEditorWidget = None logging.info('Processing completed')
2 ) # small sphere for small features. Change depending on size of objects in your phantom featSeed.Update() appendFeat.AddInputData(featSeed.GetOutput()) appendFeat.Update() # add feature segmentation seeds to the segmentationNode. Change the name or colour based on preference. segmentationNode.AddSegmentFromClosedSurfaceRepresentation( appendFeat.GetOutput(), "Feature", [0.0, 0.0, 1.0]) # segmentEditorWidget.show() # this is for debugging if you need to! slicer.app.processEvents() segmentEditorWidget.setMRMLScene(slicer.mrmlScene) segmentEditorNode = slicer.vtkMRMLSegmentEditorNode() slicer.mrmlScene.AddNode(segmentEditorNode) segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode) segmentEditorWidget.setSegmentationNode(segmentationNode) segmentEditorWidget.setMasterVolumeNode(masterVolumeNode) # grow from seeds segmentEditorWidget.setActiveEffectByName("Grow from seeds") effect = segmentEditorWidget.activeEffect() effect.self().onPreview() # for troubleshooting / editing the seed growth, stop before the onApply() function effect.self().onApply() # grow the background further into the phantom volume segmentation # i needed this as my images had a noisy edge to the phantom volume, so it picked up to much noise as phantom volume