Automatize model generation from segmentation

Hi,

I would like to automatically generate 3D-models from segmented 3D-data. The
segmented data is stored as *.nrrd, and the segmentation was performed with
an external program.

The idea is to store the segmented data in a folder and use “slicerpipelines” to
automatize the task. But I am not exactly sure how to set up the pipeline.

The following steps need to be covered:

  • load the data as “segmentation”
  • select only segment1 and segment2
  • keep largest element of segment1, keep largest element of segment2
  • generate model of segment1 and of segment2
  • store model_segment1 and model_segment2 → file names should be derived from
    the loaded segmentation-data

Any hint / tutorial how to set-up the “SlicerPipeline” for this workflow?

Thanks!

Any help is greatly appreciated!

Best,
Markus

I am not sure if all of this is possible through SlicerPipelines, but it is definitely possible via python scripting. See the script repository, specifically segmentations section for examples.

https://slicer.readthedocs.io/en/latest/developer_guide/script_repository.html#segmentations

Thanks for the hint!

Looks promising.

Best,
Markus

There’s a functiun that should be very useful for you in the ablation planner module line 793

convertSegmentToModel(segmentNode, folderName="Folder")

Hi,

once again thanks for the link.

I tried to find & use the code snippets which looked promising to me.
And it worked out, starting from the segmentation models were generated and
also filtered using the “Islands” - Operation.

An nice example of how to apply the filter-effects is given here:

BUT. While testing I found out that the model generation / exporting is
introducing a “transformation” / or change of the coordinate system.

→ in comparison to the position of the segmentation is the position of the
model now changed.

Any idea how this is caused and how it could be solved?

I am using:

Export model to Blender, including color by scalar

https://slicer.readthedocs.io/en/latest/developer_guide/script_repository.html#export-model-to-blender-including-color-by-scalar

Maybe there is a better way how to export “Segment” → “Model” ?

Thanks!
Best,
Markus

Hi again,

meanwhile I discoverd similar topics, e.g.

and an example how to export the Model to disk:

https://github.com/SlicerMorph/Scripts#2-run-an-image-processing-pipeline-on-a-folder-of-volumes

One question remains on how is the order in setting up the segmentEditorWidget.
Not sure if the code is “fine” like it is applied, because after all files in the folder
are processed the “KEEP_LARGEST_ISLAND” filter is still “active” → the mouse pointer has this typical “icon”…

# Load CurrentSegmentation
    CurrentSegmentation = os.path.join(ProjectFolder, FilesInFolder[sampleIndex])
    slicer.util.loadSegmentation(CurrentSegmentation)
    segmentationNode = slicer.mrmlScene.GetFirstNodeByClass("vtkMRMLSegmentationNode")
    
    sampleID = segmentationNode.GetName()
    
    # storage of the segment volume 
    volumeSegment[sampleIndex][0] = sampleID 
    
    # masterVolume for segmentation
    masterVolumeNode = segmentationNode.GetNodeReference(segmentationNode.GetReferenceImageGeometryReferenceRole())
    
    # 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)
    segmentEditorNode = slicer.vtkMRMLSegmentEditorNode()
    slicer.mrmlScene.AddNode(segmentEditorNode)
    segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode)
    
    # actual segmentation
    segmentEditorWidget.setSegmentationNode(segmentationNode)
    segmentEditorWidget.setSourceVolumeNode(masterVolumeNode)
    
    # Visible segments will be processed
    inputSegmentIDs = vtk.vtkStringArray()
    segmentationNode.GetDisplayNode().GetVisibleSegmentIDs(inputSegmentIDs)
    
    segmentationNode.GetDisplayNode().SetSegmentVisibility(inputSegmentIDs.GetValue(2), False)
    
    # apply filter: Keep_Largest_Island / get rid of "particles"
    for index in range(inputSegmentIDs.GetNumberOfValues()-1):
        segmentID = inputSegmentIDs.GetValue(index)
        segmentEditorWidget.setCurrentSegmentID(segmentID)
        
        # Remove islands in inverted segment (these are the holes inside the segment)
        segmentEditorWidget.setActiveEffectByName("Islands")
        effect = segmentEditorWidget.activeEffect()
        effect.setParameter("Operation", "KEEP_LARGEST_ISLAND")
        effect.self().onApply()

    # prepare: Export segment -> to model
    shNode = slicer.mrmlScene.GetSubjectHierarchyNode()
    exportFolderItemId = shNode.CreateFolderItem(shNode.GetSceneItemID(), sampleID)
    slicer.modules.segmentations.logic().ExportAllSegmentsToModels(segmentationNode, exportFolderItemId)
itemList=[]
    shNode.GetItemChildren(exportFolderItemId,itemList)
    if itemList is []:
      print("Error: no model node exported for ", volumeNode.GetName())
      continue
    
    # export skull = Segment_1
    modelNode = shNode.GetItemDataNode(itemList[0])
    # Decimate the model 80%
    slicer.modules.SurfaceToolboxWidget.logic.decimate(modelNode, modelNode, 0.8)
    slicer.util.saveNode(modelNode, plyFilePathSkull)

  # Delete temporary segment editor
    slicer.mrmlScene.RemoveNode(segmentEditorNode)
    del segmentEditorWidget

  slicer.mrmlScene.Clear(0)  # EMPTY scene

Maybe one could comment on the lines above.

THANKS!

Best,
Markus