Automate Dental Splint Generation Pt. 2

Hello,

I am following up on my previous post hoping to get some advise on the use of segmentation effects programmatically.

I am currently running a smoothing operation (gaussian), two subtractions, and an additional smoothing (median). This is the section of my code that calls the effects;

# Define master volume using the geometries within the segmentation... This is needed for the implementation of any effect!
masterVolumeNode = segNode.GetNodeReference(segNode.GetReferenceImageGeometryReferenceRole()) #----> if there is a failure point, it is here!
# According to the 3D Slicer documentation, this is the most appropriate way of implementing the effects, using the widget calls
segmentEditorWidget                                         = slicer.qMRMLSegmentEditorWidget()
segmentEditorNode                                           = slicer.vtkMRMLSegmentEditorNode()
slicer.mrmlScene.AddNode(segmentEditorNode)
segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode)
segmentEditorWidget.setSegmentationNode(segNode)
segmentEditorWidget.setMasterVolumeNode(masterVolumeNode)
segmentEditorWidget.setMRMLScene(slicer.mrmlScene)
segmentEditorWidget.setSegmentationNode(segNode)
inputSegmentIDs                                             = vtk.vtkStringArray()
segNode.GetDisplayNode().GetVisibleSegmentIDs(inputSegmentIDs)
segmentEditorNode.SetOverwriteMode( slicer.vtkMRMLSegmentEditorNode.OverwriteNone )
# Essentially, the index for the segments is given by the order in which the segments were created or imported
# Only visible segments are read, but visibility is set to True by default, so all of the segments will be read
#
# Now we apply the effects on each segment...
# ...Firts, we run a median filter operation on the splint!
splintSegmentID = inputSegmentIDs.GetValue(0)
segmentEditorWidget.setCurrentSegmentID(splintSegmentID)
segmentEditorWidget.setActiveEffectByName("Smoothing")
effect = segmentEditorWidget.activeEffect()
effect.setParameter("SmoothingMethod","GAUSSIAN")
effect.setParameter("KernelSizeMm",str(1.0))
effect.setParameter("ApplyToAllVisibleSegments",str(1))
effect.self().onApply()

# ...After applying the filter, we subtract both the maxilla and the mandible sequentially
maxillaSegmentID = inputSegmentIDs.GetValue(1)
mandibleSegmentID = inputSegmentIDs.GetValue(2)
segmentEditorWidget.setCurrentSegmentID(splintSegmentID)
segmentEditorWidget.setActiveEffectByName("Logical operators")
effect = segmentEditorWidget.activeEffect()
effect.setParameter("Operation", "SUBTRACT")
effect.setParameter("ModifierSegmentID", maxillaSegmentID)
effect.self().onApply()

# ...subtract mandible
segmentEditorWidget.setCurrentSegmentID(splintSegmentID)
segmentEditorWidget.setActiveEffectByName("Logical operators")
effect = segmentEditorWidget.activeEffect()
effect.setParameter("Operation", "SUBTRACT")
effect.setParameter("ModifierSegmentID", mandibleSegmentID)
effect.self().onApply()

# ...finally,  one additional smoothing operation
splintSegmentID = inputSegmentIDs.GetValue(0)
segmentEditorWidget.setCurrentSegmentID(splintSegmentID)
segmentEditorWidget.setActiveEffectByName("Smoothing")
effect = segmentEditorWidget.activeEffect()
effect.setParameter("SmoothingMethod","MEDIAN")
effect.setParameter("KernelSizeMm",str(0.5))
effect.setParameter("ApplyToAllVisibleSegments",str(1))
effect.self().onApply()

When I run this sequence, the splint segment (green) seems to converge towards the edges of the volume at the front and the sides. If I am not mistaken, this happens when a gaussian or median filter is applied near the end of the master volume. If this is the case, how do I avoid this?

1 Like

Kernel-based operations, such as Gaussian smoothing, need voxel values around each voxel’s neiguborhood to be able to compute the output. At the image boundary voxel values need to be invented (either some constant value is assumed or the image is wrapped around or mirrored a the boundary). If you don’t like the result of the automatic boundary extension then add blank voxels around your image before applying Gaussian smoothing. For example, you can use Crop volume to enlarge the image extent before you start the segmentation.

1 Like

@lassoan,

What happens when my input is a surface model and not a volume? The only input to my process, not shown in the code above, is an optical scan of the teeth (STLs/OBJs) and a fiducials list. I have no “base” volume to use. Is it possible to generate a blank volume?

That should be no problem. You can just create an empty volume as shown here as use that as reference volume.