Segment editor effect sourceVolumeImageData not updated

Hello I am writing a SegmentEditorEffect based on AbstractScriptedSegmentEditorEffect.

When I call self.scriptedEffect.sourceVolumeImageData() everything works fine. However if I change the selected source volume in the segment editor the change will not be recognized and once I call self.scriptedEffect.sourceVolumeImageData() again, I get the old image data.

If I change the segmentation this is reset and I will get the first selected volume but cannot get any follow up selection

Is there a way to force an update of this?

It all works well for me. For example, load two volumes, use threshold effect, select another source volume, use threshold effect.

Please provide full script that I can simply copy-paste into the Python console and reproduces the behavior you reported.

Thanks for your quick reply, Andras.

I tried ThresholdEffect’s and it works fine here. I don’t know why though. When I copy code and add a check to see if the sourceVolume has changed it has the same behavior.

I am pretty new to slicer and python so I might be making obvious mistakes.

I’ve tried to create a minimal version:

  1. Save this to MySegmentEditorEffect.py
  2. Run the lines below after fixing the path.
  3. Drag and drop at least 2 images
  4. Switch the images in Segment Editor’s ComboBox.
  5. In my opinion you shoulg get the “sourceImageData changed”-Message every time you change the image
from SegmentEditorEffects import *
class MySegmentEditorEffect(AbstractScriptedSegmentEditorEffect):
    def __init__(self, scriptedEffect):
        AbstractScriptedSegmentEditorEffect.__init__(self, scriptedEffect)
        scriptedEffect.name = "MySegmentEditorEffect"
        self.sourceImageData = None

    def clone(self):
        # It should not be necessary to modify this method
        import qSlicerSegmentationsEditorEffectsPythonQt as effects
        clonedEffect = effects.qSlicerSegmentEditorScriptedEffect(None)
        clonedEffect.setPythonSource(__file__.replace('\\','/'))
        return clonedEffect
    
    def sourceVolumeNodeChanged(self):
        sourceImageData = self.scriptedEffect.sourceVolumeImageData()

        if(self.sourceImageData != sourceImageData):
            if( sourceImageData is None):
                print(f"sourceImageData changed: None")
            else:
                print(f"sourceImageData changed: {sourceImageData.GetExtent()}")
            self.sourceImageData = sourceImageData
import qSlicerSegmentationsEditorEffectsPythonQt as effects
scriptedEffect = effects.qSlicerSegmentEditorScriptedEffect(None)
scriptedEffect.setPythonSource(r"Your_Location\MySegmentEditorEffect.py")
scriptedEffect.self().register()

I’ve investigated further and while the SegmentEditorThresholdEffect works as it should it has the same issue. If i change up the sourceVolumeNodeChanged method as below, I get the same behavior.
Maybe I will find out where it get’s the correct data but this seems like a genuine bug to me.
Have you found anything @lassoan ?

    def sourceVolumeNodeChanged(self):
        # Set scalar range of source volume image data to threshold slider
        masterImageData = self.scriptedEffect.sourceVolumeImageData()
        if masterImageData:
            print(f"this should change: {masterImageData.GetDimensions()}")
            lo, hi = masterImageData.GetScalarRange()
            self.thresholdSlider.setRange(lo, hi)
            self.thresholdSlider.singleStep = (hi - lo) / 1000.
            if (self.scriptedEffect.doubleParameter("MinimumThreshold") == self.scriptedEffect.doubleParameter("MaximumThreshold")):
                # has not been initialized yet
                self.scriptedEffect.setParameter("MinimumThreshold", lo + (hi - lo) * 0.25)
                self.scriptedEffect.setParameter("MaximumThreshold", hi)

Okay I found a solution. I can get the Node instead and then the image data. The node is updated.

sourceImageData = self.scriptedEffect.parameterSetNode().GetSourceVolumeNode().GetImageData()

This code gives you the source volume’s image data as is:

self.scriptedEffect.parameterSetNode().GetSourceVolumeNode().GetImageData()

This is usually not what you need, because the source volume’s geometry (origin, spacing, axis directions, extents) may differ from the segmentation’s.

This gives you the image data resampled to the segmentation’s geometry (taking into account all parent transforms, including warping transforms):

masterImageData = self.scriptedEffect.sourceVolumeImageData()

What you observed (image data is resampled to the segmentation’s geometry, therefore dimension does not change) maybe unexpected, but it is the correct, intended behavior.

1 Like