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?
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.
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
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