@@ -206,7 +206,6 @@ def __init__(self, parent=None):
206206 self ._scribblesROINode = None
207207 self ._volumeNodes = []
208208 self ._updatingGUIFromParameterNode = False
209- self ._scribblesEditorWidget = None
210209
211210 self .info = {}
212211 self .models = OrderedDict ()
@@ -345,6 +344,7 @@ def setup(self):
345344 self .ui .embeddedSegmentEditorWidget .setMRMLScene (slicer .mrmlScene )
346345 self .ui .embeddedSegmentEditorWidget .setSegmentationNodeSelectorVisible (False )
347346 self .ui .embeddedSegmentEditorWidget .setMasterVolumeNodeSelectorVisible (False )
347+ self .ui .embeddedSegmentEditorWidget .setMRMLSegmentEditorNode (self .logic .get_segment_editor_node ())
348348
349349 self .initializeParameterNode ()
350350 self .updateServerUrlGUIFromSettings ()
@@ -651,10 +651,6 @@ def updateGUIFromParameterNode(self, caller=None, event=None):
651651 self .ui .dgUpdateCheckBox .setEnabled (self .ui .deepgrowModelSelector .currentText and self ._segmentNode )
652652 self .ui .dgUpdateButton .setEnabled (self .ui .deepgrowModelSelector .currentText and self ._segmentNode )
653653
654- self .ui .embeddedSegmentEditorWidget .setMRMLSegmentEditorNode (
655- slicer .mrmlScene .GetFirstNodeByClass ("vtkMRMLSegmentEditorNode" )
656- )
657-
658654 # All the GUI updates are done
659655 self ._updatingGUIFromParameterNode = False
660656
@@ -1275,17 +1271,16 @@ def initSample(self, sample, autosegment=True):
12751271
12761272 # Create Empty Segments for all labels for this node
12771273 self .createSegmentNode ()
1278- segmentEditorWidget = slicer .modules .segmenteditor .widgetRepresentation ().self ().editor
1279- segmentEditorWidget .setSegmentationNode (self ._segmentNode )
1280- segmentEditorWidget .setMasterVolumeNode (self ._volumeNode )
1274+ self .ui .embeddedSegmentEditorWidget .setSegmentationNode (self ._segmentNode )
1275+ self .ui .embeddedSegmentEditorWidget .setMasterVolumeNode (self ._volumeNode )
12811276
12821277 self .createScribblesROINode ()
12831278 self .ui .scribblesPlaceWidget .setCurrentNode (self ._scribblesROINode )
12841279
12851280 # check if user allows overlapping segments
12861281 if slicer .util .settingsValue ("MONAILabel/allowOverlappingSegments" , False , converter = slicer .util .toBool ):
12871282 # set segment editor to allow overlaps
1288- slicer . util . getNodesByClass ( "vtkMRMLSegmentEditorNode" )[ 0 ] .SetOverwriteMode (2 )
1283+ self . logic . get_segment_editor_node () .SetOverwriteMode (slicer . vtkMRMLSegmentEditorNode . OverwriteNone )
12891284
12901285 if self .info .get ("labels" ):
12911286 self .updateSegmentationMask (None , self .info .get ("labels" ))
@@ -1693,12 +1688,11 @@ def updateSegmentationMask(self, in_file, labels, sliceIndex=None, freeze=None):
16931688 if freeze and label not in freeze :
16941689 print (f"Discard label update for: { label } " )
16951690 elif label in existing_label_ids :
1696- segmentEditorWidget = slicer .modules .segmenteditor .widgetRepresentation ().self ().editor
1697- segmentEditorWidget .setSegmentationNode (segmentationNode )
1698- segmentEditorWidget .setMasterVolumeNode (self ._volumeNode )
1699- segmentEditorWidget .setCurrentSegmentID (existing_label_ids [label ])
1691+ self .ui .embeddedSegmentEditorWidget .setSegmentationNode (segmentationNode )
1692+ self .ui .embeddedSegmentEditorWidget .setMasterVolumeNode (self ._volumeNode )
1693+ self .ui .embeddedSegmentEditorWidget .setCurrentSegmentID (existing_label_ids [label ])
17001694
1701- effect = segmentEditorWidget .effectByName ("Logical operators" )
1695+ effect = self . ui . embeddedSegmentEditorWidget .effectByName ("Logical operators" )
17021696 labelmap = slicer .vtkOrientedImageData ()
17031697 segmentationNode .GetBinaryLabelmapRepresentation (segmentId , labelmap )
17041698
@@ -1795,53 +1789,33 @@ def scribblesLayersPresent(self):
17951789 scribbles_exist = sum (int ("scribbles" in sid ) for sid in segmentIds ) > 0
17961790 return scribbles_exist
17971791
1798- def onStartScribbling (self ):
1799- if not self ._segmentNode :
1792+ def ensureScribblesLayersPresent (self ):
1793+ if ( not self ._segmentNode ) or self . scribblesLayersPresent () :
18001794 return
18011795
1802- logging .debug ("Scribbles start event" )
1803- if (not self .scribblesLayersPresent ()) and (self ._scribblesEditorWidget is None ):
1804- # add background, layer index = -2 [2], color = red
1805- self ._segmentNode .GetSegmentation ().AddEmptySegment (
1806- "background_scribbles" , "background_scribbles" , [1.0 , 0.0 , 0.0 ]
1807- )
1808-
1809- # add foreground, layer index = -1 [3], color = green
1810- self ._segmentNode .GetSegmentation ().AddEmptySegment (
1811- "foreground_scribbles" , "foreground_scribbles" , [0.0 , 1.0 , 0.0 ]
1812- )
1813-
1814- # change segmentation display properties to "see through" the scribbles
1815- # further explanation at:
1816- # https://apidocs.slicer.org/master/classvtkMRMLSegmentationDisplayNode.html
1817- segmentationDisplayNode = self ._segmentNode .GetDisplayNode ()
1818-
1819- # background
1820- opacity = 0.2
1821- segmentationDisplayNode .SetSegmentOpacity2DFill ("background_scribbles" , opacity )
1822- segmentationDisplayNode .SetSegmentOpacity2DOutline ("background_scribbles" , opacity )
1796+ # add background, layer index = -2 [2], color = red
1797+ self ._segmentNode .GetSegmentation ().AddEmptySegment (
1798+ "background_scribbles" , "background_scribbles" , [1.0 , 0.0 , 0.0 ]
1799+ )
18231800
1824- # foreground
1825- segmentationDisplayNode .SetSegmentOpacity2DFill ("foreground_scribbles" , opacity )
1826- segmentationDisplayNode .SetSegmentOpacity2DOutline ("foreground_scribbles" , opacity )
1801+ # add foreground, layer index = -1 [3], color = green
1802+ self ._segmentNode .GetSegmentation ().AddEmptySegment (
1803+ "foreground_scribbles" , "foreground_scribbles" , [0.0 , 1.0 , 0.0 ]
1804+ )
18271805
1828- # create segmentEditorWidget to access "Paint" and "Erase" segmentation tools
1829- # these will be used to draw scribbles
1830- self ._scribblesEditorWidget = slicer .qMRMLSegmentEditorWidget ()
1831- self ._scribblesEditorWidget .setMRMLScene (slicer .mrmlScene )
1832- segmentEditorNode = slicer .vtkMRMLSegmentEditorNode ()
1806+ # change segmentation display properties to "see through" the scribbles
1807+ # further explanation at:
1808+ # https://apidocs.slicer.org/master/classvtkMRMLSegmentationDisplayNode.html
1809+ segmentationDisplayNode = self ._segmentNode .GetDisplayNode ()
18331810
1834- # adding new scribbles can overwrite a new one-hot vector, hence erase any existing
1835- # labels - this is not a desired behaviour hence we swith to overlay mode that enables drawing
1836- # scribbles without changing existing labels. Further explanation at:
1837- # https://discourse.slicer.org/t/how-can-i-set-masking-settings-on-a-segment-editor-effect-in-python/4406/7
1838- segmentEditorNode .SetOverwriteMode (slicer .vtkMRMLSegmentEditorNode .OverwriteNone )
1811+ # background
1812+ opacity = 0.2
1813+ segmentationDisplayNode .SetSegmentOpacity2DFill ("background_scribbles" , opacity )
1814+ segmentationDisplayNode .SetSegmentOpacity2DOutline ("background_scribbles" , opacity )
18391815
1840- # add all nodes to the widget
1841- slicer .mrmlScene .AddNode (segmentEditorNode )
1842- self ._scribblesEditorWidget .setMRMLSegmentEditorNode (segmentEditorNode )
1843- self ._scribblesEditorWidget .setSegmentationNode (self ._segmentNode )
1844- self ._scribblesEditorWidget .setMasterVolumeNode (self ._volumeNode )
1816+ # foreground
1817+ segmentationDisplayNode .SetSegmentOpacity2DFill ("foreground_scribbles" , opacity )
1818+ segmentationDisplayNode .SetSegmentOpacity2DOutline ("foreground_scribbles" , opacity )
18451819
18461820 def onUpdateScribbles (self ):
18471821 logging .info ("Scribbles update event" )
@@ -1992,9 +1966,6 @@ def onResetScribbles(self):
19921966 # reset scribbles mode
19931967 self .scribblesMode = None
19941968
1995- # clear scribbles editor widget
1996- self ._scribblesEditorWidget = None
1997-
19981969 # remove "scribbles" segments from label
19991970 self .onClearScribblesSegmentNodes ()
20001971
@@ -2006,29 +1977,29 @@ def onResetScribbles(self):
20061977 self .ui .scribLabelComboBox .setCurrentIndex (0 )
20071978 self .ignoreScribblesLabelChangeEvent = False
20081979
2009- def checkAndInitialiseScribbles (self ):
1980+ def updateScribToolLayerFromMode (self ):
20101981 if not self ._segmentNode :
20111982 return
20121983
2013- if self ._scribblesEditorWidget is None :
2014- self .onStartScribbling ()
1984+ logging .info (f"Scribbles mode { self .scribblesMode } " )
20151985
20161986 if self .scribblesMode is None :
20171987 self .changeScribblesMode (tool = "Paint" , layer = "foreground_scribbles" )
20181988 self .updateScribToolLayerFromMode ()
20191989
2020- def updateScribToolLayerFromMode (self ):
2021- if not self ._segmentNode :
2022- return
2023-
2024- logging .info (f"Scribbles mode { self .scribblesMode } " )
2025- self .checkAndInitialiseScribbles ()
2026-
20271990 # update tool/layer select for scribblesEditorWidget
20281991 tool , layer = self .getToolAndLayerFromScribblesMode ()
2029- if self ._scribblesEditorWidget :
2030- self ._scribblesEditorWidget .setActiveEffectByName (tool )
2031- self ._scribblesEditorWidget .setCurrentSegmentID (layer )
1992+ if self .scribblesMode is not None :
1993+ self .ensureScribblesLayersPresent ()
1994+
1995+ # adding new scribbles can overwrite a new one-hot vector, hence erase any existing
1996+ # labels - this is not a desired behaviour hence we swith to overlay mode that enables drawing
1997+ # scribbles without changing existing labels. Further explanation at:
1998+ # https://discourse.slicer.org/t/how-can-i-set-masking-settings-on-a-segment-editor-effect-in-python/4406/7
1999+ self .logic .get_segment_editor_node ().SetOverwriteMode (slicer .vtkMRMLSegmentEditorNode .OverwriteNone )
2000+
2001+ self .ui .embeddedSegmentEditorWidget .setActiveEffectByName (tool )
2002+ self .ui .embeddedSegmentEditorWidget .setCurrentSegmentID (layer )
20322003
20332004 # update brush type from checkbox
20342005 if tool in ("Paint" , "Erase" ):
@@ -2088,18 +2059,14 @@ def onSelectScribblesLabel(self):
20882059
20892060 def on3dBrushCheckbox (self , state ):
20902061 logging .info (f"3D brush update { state } " )
2091- self .checkAndInitialiseScribbles ()
2092- effect = self ._scribblesEditorWidget .activeEffect ()
2093-
20942062 # enable scribbles in 3d using a sphere brush
2063+ effect = self .ui .embeddedSegmentEditorWidget .effectByName ("Paint" )
20952064 effect .setParameter ("BrushSphere" , state )
20962065
20972066 def updateBrushSize (self , value ):
20982067 logging .info (f"brush size update { value } " )
2099- if self .ui .paintScribblesButton .checked or self .ui .eraseScribblesButton .checked :
2100- self .checkAndInitialiseScribbles ()
2101- effect = self ._scribblesEditorWidget .activeEffect ()
2102- effect .setParameter ("BrushAbsoluteDiameter" , value )
2068+ effect = self .ui .embeddedSegmentEditorWidget .effectByName ("Paint" )
2069+ effect .setParameter ("BrushAbsoluteDiameter" , value )
21032070
21042071
21052072class MONAILabelLogic (ScriptedLoadableModuleLogic ):
@@ -2137,6 +2104,19 @@ def reportProgress(self, progress):
21372104 if self .progress_callback :
21382105 self .progress_callback (progress )
21392106
2107+ def get_segment_editor_node (self ):
2108+ # Use the Segment Editor module's parameter node for the embedded segment editor widget.
2109+ # This ensures that if the user switches to the Segment Editor then the selected
2110+ # segmentation node, volume node, etc. are the same.
2111+ segmentEditorSingletonTag = "SegmentEditor"
2112+ segmentEditorNode = slicer .mrmlScene .GetSingletonNode (segmentEditorSingletonTag , "vtkMRMLSegmentEditorNode" )
2113+ if segmentEditorNode is None :
2114+ segmentEditorNode = slicer .mrmlScene .CreateNodeByClass ("vtkMRMLSegmentEditorNode" )
2115+ segmentEditorNode .UnRegister (None )
2116+ segmentEditorNode .SetSingletonTag (segmentEditorSingletonTag )
2117+ segmentEditorNode = slicer .mrmlScene .AddNode (segmentEditorNode )
2118+ return segmentEditorNode
2119+
21402120 def info (self ):
21412121 return MONAILabelClient (self .server_url , self .tmpdir , self .client_id ).info ()
21422122
0 commit comments