Inaccurate segmentation effect result when run with certain effects together

I am attempting to segment out a pelvis bone model from a volume. I have noticed that the model generated from code is not the same as the one created from the GUI using the same parameters. take a look at the image below, the same parameters and effects in the same order were used to obtain both models, but the green section only shows up when applying the effects from the GUI. the rest of the green overlaps the tan.
image

through testing, it is apparent that the combination of Threshold > Smoothing (with median, opening, either or both) > Islands remove small islands operations cause this issue. I am wondering if this is because the previous operations are not fully complete when the islands operation begins, and since the voxels are still being placed, some are small enough to be removed by the islands operation. However, using self.delayMs does not appear to affect it in any way so i’m not sure about that.

does anyone know if this is the reason, or how to prevent it?

some more info:
i’m calling my operations like the skin surface example here: https://www.slicer.org/wiki/Documentation/Nightly/ScriptRepository#How_to_run_segment_editor_effects_from_a_script

I’ve modified it to be more similar to my calls, i’m going to paste the modified code at the bottom if you want to replicate this.

if you follow the same operations in the gui on the sample data, it is clear that the python script has lost a fair portion of the model, it should look like this image with green being python code and tan being GUI generated:
image

code:

import SampleData
sampleDataLogic = SampleData.SampleDataLogic()
masterVolumeNode = sampleDataLogic.downloadCTChest()

# Create segmentation
segmentationNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSegmentationNode")
segmentationNode.CreateDefaultDisplayNodes() # only needed for display
segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(masterVolumeNode)
addedSegmentID = segmentationNode.GetSegmentation().AddEmptySegment("bone")

# Create segment editor to get access to effects
segmentEditorWidget = slicer.qMRMLSegmentEditorWidget()
segmentEditorWidget.setMRMLScene(slicer.mrmlScene)
segmentEditorNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSegmentEditorNode")
segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode)
segmentEditorWidget.setSegmentationNode(segmentationNode)
segmentEditorWidget.setMasterVolumeNode(masterVolumeNode)

# Thresholding
segmentEditorWidget.setActiveEffectByName("Threshold")
effect = segmentEditorWidget.activeEffect()
effect.setParameter("MinimumThreshold","300")
effect.setParameter("MaximumThreshold","3778")
effect.self().onApply()

# Smoothing
segmentEditorWidget.setActiveEffectByName("Smoothing")
effect = segmentEditorWidget.activeEffect()
effect.setParameter("SmoothingMethod", "MEDIAN")
effect.setParameter("KernelSizeMm", 3)
effect.self().onApply()

# Islands
segmentEditorWidget.setActiveEffectByName("Islands")
effect = segmentEditorWidget.activeEffect()
effect.setParameter("Minimumsize", "1000")
effect.setParameter("EditIslands", "RsEMOVE_SMALL_ISLANDS")
effect.self().onApply()

# Clean up
segmentEditorWidget = None
slicer.mrmlScene.RemoveNode(segmentEditorNode)

# Make segmentation results visible in 3D
segmentationNode.CreateClosedSurfaceRepresentation()

# Make sure surface mesh cells are consistently oriented
surfaceMesh = segmentationNode.GetClosedSurfaceRepresentation(addedSegmentID)
normals = vtk.vtkPolyDataNormals()
normals.AutoOrientNormalsOn()
normals.ConsistencyOn()
normals.SetInputData(surfaceMesh)
normals.Update()
surfaceMesh = normals.GetOutput()

This line was incorrect (non-existing parameter name and typo in parameter value):

effect.setParameter("EditIslands", "RsEMOVE_SMALL_ISLANDS")

Correct command to set operation to remove small islands:

effect.setParameter("Operation", "REMOVE_SMALL_ISLANDS")

While you are working your script, it is useful to make the segment editor widget visible, so that you can verify that effect parameters are set correctly. Run this command right after creating segmentEditorWidget:

segmentEditorWidget.show()

You don’t have to worry about operations running in parallel. onApply() does not return until processing is completed.

that was indeed the issue. I had found the correct variable name and verified it at one point, but it must have been mixed up with a storage variable name when the code was restructured. thanks

1 Like