Automating "Flood Fill" segmentation with seeds from previous marker locations

Sorry if this is a basic question but I’m currently trying to automate a segmentation tool for my project needs. I basically want to segment a preprocessed image volume in which I previously collected fiducial marker locations. To segment, I want to use the “flood filling” - which I can do manually. However, I want to automate the segmentation process. Is there a way for me seed the “flood filling” with a control point that I previously collected with a marker and then turn off ‘flood filling’ - using python scripting and not manually clicking as my code below requires? This is what I have so far from online resources - I think I would need to add something between the “flood filling” and “none” active effect by name settings. Any advice would be appreciated:

masterVolumeNode = slicer.util.getNode(‘Preproccessed Image’)

segmentEditorWidget = slicer.qMRMLSegmentEditorWidget()
segmentEditorWidget.show()
segmentEditorWidget.setMRMLScene(slicer.mrmlScene)
segmentEditorNode = slicer.vtkMRMLSegmentEditorNode()
slicer.mrmlScene.AddNode(segmentEditorNode)
segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode)

segmentationNode = slicer.vtkMRMLSegmentationNode()
segmentationNode.GetSegmentation().AddEmptySegment(“skin”)
slicer.mrmlScene.AddNode(segmentationNode)
segmentationNode.CreateDefaultDisplayNodes()
segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(masterVolumeNode)

segmentEditorWidget.setSegmentationNode(segmentationNode)
segmentEditorWidget.setMasterVolumeNode(masterVolumeNode)

segmentEditorWidget.setActiveEffectByName(‘Flood filling’)
segmentEditorWidget.setActiveEffectByName(‘None’)

I’ve split out the logic that performs the actual processing in Flood Fill effect into a new method: floodFillFromPoint.

You can call this method (after you activated the effect) like this:

floodFillEffect=slicer.modules.segmenteditor.widgetRepresentation().self().editor.activeEffect().self()
floodFillEffect.floodFillFromPoint([130,65,28])

The coordinates are IJK voxel coordinates of the master volume. You can find here how to get IJK coordinates from RAS coordinates (such as physical position of a markups fiducial point).

Thank you very much for building that method for me, Iassoan!

For those who are interested I have provided my rough, sample code that I was able to pull together from online resources. One needs to make sure the new function that Lassoan created is added to the segmentation editor module - I did this manually. The following code takes an image volume and fiducial marker node called “Right Vertebral Artery” and flood fills, i.e., segments, the image based on the marker’s first control point. The code then converts the segmentation to a surface mesh model.

masterVolumeNode = slicer.util.getNode('Preproccessed Image')

segmentEditorWidget = slicer.qMRMLSegmentEditorWidget() 
segmentEditorWidget.show() 
segmentEditorWidget.setMRMLScene(slicer.mrmlScene) 
segmentEditorNode = slicer.vtkMRMLSegmentEditorNode() 
slicer.mrmlScene.AddNode(segmentEditorNode) 
segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode) 


segmentationNode = slicer.vtkMRMLSegmentationNode() 
segmentationNode.GetSegmentation().AddEmptySegment("skin")
slicer.mrmlScene.AddNode(segmentationNode) 
segmentationNode.CreateDefaultDisplayNodes() 
segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(masterVolumeNode) 


segmentEditorWidget.setSegmentationNode(segmentationNode) 
segmentEditorWidget.setMasterVolumeNode(masterVolumeNode) 


segmentEditorWidget.setActiveEffectByName('Flood filling')

R0 = slicer.util.getNode('Right Vertebral Artery').GetNthControlPointPositionVector(0)[0]
R1 = slicer.util.getNode('Right Vertebral Artery').GetNthControlPointPositionVector(0)[1]
R2 = slicer.util.getNode('Right Vertebral Artery').GetNthControlPointPositionVector(0)[2]

# Get point coordinate in RAS
point_Ras = [R0, R1, R2, 1]
markupsNode.GetNthFiducialWorldCoordinates(markupsIndex, point_Ras)

# If volume node is transformed, apply that transform to get volume's RAS coordinates
transformRasToVolumeRas = vtk.vtkGeneralTransform()
slicer.vtkMRMLTransformNode.GetTransformBetweenNodes(None, volumeNode.GetParentTransformNode(), transformRasToVolumeRas)
point_VolumeRas = transformRasToVolumeRas.TransformPoint(point_Ras[0:3])

# Get voxel coordinates from physical coordinates
volumeRasToIjk = vtk.vtkMatrix4x4()
masterVolumeNode.GetRASToIJKMatrix(volumeRasToIjk)
point_Ijk = [0, 0, 0, 1]
volumeRasToIjk.MultiplyPoint(numpy.append(point_VolumeRas,1.0), point_Ijk)
point_Ijk = [ int(round(c)) for c in point_Ijk[0:3] ]

# Print output
print(point_Ijk)

a = segmentEditorWidget.activeEffect().self()
a.floodFillFromPoint(point_Ijk)

segmentEditorWidget.setActiveEffectByName('None')


segmentationNode = getNode("Segmentation")
shNode = slicer.mrmlScene.GetSubjectHierarchyNode()
exportFolderItemId = shNode.CreateFolderItem(shNode.GetSceneItemID(), "Segments")
slicer.modules.segmentations.logic().ExportAllSegmentsToModels(segmentationNode, exportFolderItemId)
2 Likes