Margin effect altering multiple segments at once

Hi everyone,

I’m running into a problem while trying to use the margin effect in the segment editor. My goal is to create a shrunken copy of a Brain segment for CSF segmentation without altering the original Brain segment.

For some reason, the moment effect.self().onApply() is executed, the original Brain segment is altered in a way I don’t expect. Instead of leaving the original segment untouched, it appears to contain only the voxels that were removed from the shrunken segment.

Here’s the relevant code snippet:

# Create Brain Shrunk Segment as a copy of original Brain
existingIds = set(segmentation.GetSegmentIDs())
segmentation.CopySegmentFromSegmentation(segmentation, segmentId)
newIds = set(segmentation.GetSegmentIDs())
shrunkSegmentId = list(newIds - existingIds)[0]  # The new segment ID
shrunkSegment = segmentation.GetSegment(shrunkSegmentId)
shrunkSegment.SetName(shrunkSegmentName)

# Set up Segment Editor to subtract shrunk Brain from CSF shell
slicer.app.processEvents()
segmentEditorWidget = slicer.qMRMLSegmentEditorWidget()
segmentEditorWidget.setMRMLScene(slicer.mrmlScene)
segmentEditorNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSegmentEditorNode")
segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode)
segmentEditorWidget.setSegmentationNode(segNode)

# Shrink Brain Segment
segmentEditorWidget.setActiveEffectByName("Margin")
effect = segmentEditorWidget.activeEffect()
segmentEditorNode.SetSelectedSegmentID(shrunkSegmentId)
effect.setParameter("ApplyToAllVisibleSegments", 0)
effect.setParameter("MarginSizeMm", marginMm)  # Amount to shrink
effect.self().onApply()

Theoretically, CopySegmentFromSegmentation should create a deep copy, and I don’t experience the same issue later on when applying the logical operators effect on another copy of the Brain Segment. I’ve also verified that the selected segment ID is correctly set before calling the effect.

Any guidance on how to ensure that only the selected segment is affected would be greatly appreciated. Thanks in advance.

I haven’t done this through scripting, but normally on the Editor, if you want only modify the existing segment, and you have more than one segment, you need to set the Masking correctly. For example you can set the Modify other segments to “Overwrite visible” and set the visibility of all other segments to hidden.

Yes, this is your masking settings interfering. It must be set to Overwrite All or Overwrite Visible, so when the shrunken version is written, it deletes those voxels from the original brain segment, leaving only the original voxels which are not present in the shrunken version. Below is a code snippet which uses the margin effect and handles masking settings. It isn’t stand-alone, but you can see how masking settings are applied…

    def grow_segment(
        self,
        segmentID,
        segmentationNode,
        growMarginMm,
        overwriteOtherSegments=False,
        useIntensityMask=False,
    ):
        """Uses Margin segment editor effect to grow given segment by given amount in mm. By default
        this growth does not overwrite any other segments or use the intensity mask settings, but these
        can be overridden by flags.
        """
        segmentEditorWidget, segmentEditorNode, segmentationNode = setup_segment_editor(
            segmentationNode, None
        )
        segmentEditorNode.SetSelectedSegmentID(segmentID)
        segmentEditorWidget.setActiveEffectByName("Margin")
        effect = segmentEditorWidget.activeEffect()
        effect.setParameter(
            "MarginSizeMm", growMarginMm
        )  # negative values would shrink
        # Handle masking
        if overwriteOtherSegments:
            segmentEditorNode.OverwriteMode(segmentEditorNode.OverwriteAll)
            # OverwriteVisible is also an option
        else:
            segmentEditorNode.SetOverwriteMode(
                segmentEditorNode.OverwriteNone
            )  # allow overlap
        segmentEditorNode.SetMasterVolumeIntensityMask(useIntensityMask)
        # segmentEditorNode.setMasterVolumeIntensityMaskRange(minVal, maxVal) # if needed, this is how to set
        # Apply margin growth
        effect.self().onApply()
        # Clean up
        slicer.mrmlScene.RemoveNode(segmentEditorNode)
        return  # no need to return anything, segment is just modified...
```

Thank you both so much for the help - that did the trick! Really appreciate it.