Slicer  4.10
Slicer is a multi-platform, free and open source software package for visualization and medical image computing
AbstractScriptedSegmentEditorAutoCompleteEffect.py
Go to the documentation of this file.
1 import os
2 import vtk, qt, ctk, slicer, logging
3 from AbstractScriptedSegmentEditorEffect import *
4 
5 __all__ = ['AbstractScriptedSegmentEditorAutoCompleteEffect']
6 
7 #
8 # Abstract class of python scripted segment editor auto-complete effects
9 #
10 # Auto-complete effects are a subtype of general effects that allow preview
11 # and refinement of segmentation results before accepting them.
12 #
13 
15  """ AutoCompleteEffect is an effect that can create a full segmentation
16  from a partial segmentation (not all slices are segmented or only
17  part of the target structures are painted).
18  """
19 
20  def __init__(self, scriptedEffect):
21  # Indicates that effect does not operate on one segment, but the whole segmentation.
22  # This means that while this effect is active, no segment can be selected
23  scriptedEffect.perSegment = False
24  AbstractScriptedSegmentEditorEffect.__init__(self, scriptedEffect)
25 
29 
30  # Stores merged labelmap image geometry (voxel data is not allocated)
32  self.selectedSegmentIds = None
33  self.selectedSegmentModifiedTimes = {} # map from segment ID to ModifiedTime
35 
36  # Observation for auto-update
39 
40  # Wait this much after the last modified event before starting aut-update:
41  autoUpdateDelaySec = 1.0
42  self.delayedAutoUpdateTimer = qt.QTimer()
43  self.delayedAutoUpdateTimer.setSingleShot(True)
44  self.delayedAutoUpdateTimer.interval = autoUpdateDelaySec * 1000
45  self.delayedAutoUpdateTimer.connect('timeout()', self.onPreview)
46 
47  self.extentGrowthRatio = 0.1 # extent of seed region will be grown outside by this much
48 
49 
50  def __del__(self, scriptedEffect):
51  super(SegmentEditorAutoCompleteEffect,self).__del__()
52  self.delayedAutoUpdateTimer.stop()
53  self.observeSegmentation(False)
54 
55  @staticmethod
56  def isBackgroundLabelmap(labelmapOrientedImageData):
57  if labelmapOrientedImageData is None:
58  return False
59  # If five or more corner voxels of the image contain non-zero, then it is background
60  extent = labelmapOrientedImageData.GetExtent()
61  if extent[0] > extent[1] or extent[2] > extent[3] or extent[4] > extent[5]:
62  return False
63  numberOfFilledCorners = 0
64  for i in [0,1]:
65  for j in [2,3]:
66  for k in [4,5]:
67  if labelmapOrientedImageData.GetScalarComponentAsFloat(extent[i],extent[j],extent[k],0) > 0:
68  numberOfFilledCorners += 1
69  if numberOfFilledCorners > 4:
70  return True
71  return False
72 
73  def setupOptionsFrame(self):
74  self.autoUpdateCheckBox = qt.QCheckBox("Auto-update")
75  self.autoUpdateCheckBox.setToolTip("Auto-update results preview when input segments change.")
76  self.autoUpdateCheckBox.setChecked(True)
77  self.autoUpdateCheckBox.setEnabled(False)
78 
79  self.previewButton = qt.QPushButton("Initialize")
80  self.previewButton.objectName = self.__class__.__name__ + 'Preview'
81  self.previewButton.setToolTip("Preview complete segmentation")
82  # qt.QSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Expanding)
83  # fails on some systems, therefore set the policies using separate method calls
84  qSize = qt.QSizePolicy()
85  qSize.setHorizontalPolicy(qt.QSizePolicy.Expanding)
86  self.previewButton.setSizePolicy(qSize)
87 
88  previewFrame = qt.QHBoxLayout()
89  previewFrame.addWidget(self.autoUpdateCheckBox)
90  previewFrame.addWidget(self.previewButton)
91  self.scriptedEffect.addLabeledOptionsWidget("Preview:", previewFrame)
92 
93  self.previewOpacitySlider = ctk.ctkSliderWidget()
94  self.previewOpacitySlider.setToolTip("Adjust visibility of results preview.")
95  self.previewOpacitySlider.minimum = 0
96  self.previewOpacitySlider.maximum = 1.0
97  self.previewOpacitySlider.value = 0.0
98  self.previewOpacitySlider.singleStep = 0.05
99  self.previewOpacitySlider.pageStep = 0.1
100  self.previewOpacitySlider.spinBoxVisible = False
101 
102  self.previewShow3DButton = qt.QPushButton("Show 3D")
103  self.previewShow3DButton.setToolTip("Preview results in 3D.")
104  self.previewShow3DButton.setCheckable(True)
105 
106  displayFrame = qt.QHBoxLayout()
107  displayFrame.addWidget(qt.QLabel("inputs"))
108  displayFrame.addWidget(self.previewOpacitySlider)
109  displayFrame.addWidget(qt.QLabel("results"))
110  displayFrame.addWidget(self.previewShow3DButton)
111  self.scriptedEffect.addLabeledOptionsWidget("Display:", displayFrame)
112 
113  self.cancelButton = qt.QPushButton("Cancel")
114  self.cancelButton.objectName = self.__class__.__name__ + 'Cancel'
115  self.cancelButton.setToolTip("Clear preview and cancel auto-complete")
116 
117  self.applyButton = qt.QPushButton("Apply")
118  self.applyButton.objectName = self.__class__.__name__ + 'Apply'
119  self.applyButton.setToolTip("Replace segments by previewed result")
120 
121  finishFrame = qt.QHBoxLayout()
122  finishFrame.addWidget(self.cancelButton)
123  finishFrame.addWidget(self.applyButton)
124  self.scriptedEffect.addOptionsWidget(finishFrame)
125 
126  self.previewButton.connect('clicked()', self.onPreview)
127  self.cancelButton.connect('clicked()', self.onCancel)
128  self.applyButton.connect('clicked()', self.onApply)
129  self.previewOpacitySlider.connect("valueChanged(double)", self.updateMRMLFromGUI)
130  self.previewShow3DButton.connect("toggled(bool)", self.updateMRMLFromGUI)
131  self.autoUpdateCheckBox.connect("stateChanged(int)", self.updateMRMLFromGUI)
132 
133  def createCursor(self, widget):
134  # Turn off effect-specific cursor for this effect
135  return slicer.util.mainWindow().cursor
136 
137  def setMRMLDefaults(self):
138  self.scriptedEffect.setParameterDefault("AutoUpdate", "1")
139 
140  def onSegmentationModified(self, caller, event):
141  if not self.autoUpdateCheckBox.isChecked():
142  # just in case a queued request comes through
143  return
144 
145  import vtkSegmentationCorePython as vtkSegmentationCore
146  segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()
147  segmentation = segmentationNode.GetSegmentation()
148 
149  updateNeeded = False
150  for segmentIndex in range(self.selectedSegmentIds.GetNumberOfValues()):
151  segmentID = self.selectedSegmentIds.GetValue(segmentIndex)
152  segment = segmentation.GetSegment(segmentID)
153  if not segment:
154  # selected segment was deleted, cancel segmentation
155  logging.debug("Segmentation cancelled because an input segment was deleted")
156  self.onCancel()
157  return
158  segmentLabelmap = segment.GetRepresentation(vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationBinaryLabelmapRepresentationName())
159  if self.selectedSegmentModifiedTimes.has_key(segmentID) \
160  and segmentLabelmap.GetMTime() == self.selectedSegmentModifiedTimes[segmentID]:
161  # this segment has not changed since last update
162  continue
163  self.selectedSegmentModifiedTimes[segmentID] = segmentLabelmap.GetMTime()
164  updateNeeded = True
165  # continue so that all segment modified times are updated
166 
167  if not updateNeeded:
168  return
169 
170  logging.debug("Segmentation update requested")
171  # There could be multiple update events for a single paint operation (e.g., one segment overwrites the other)
172  # therefore don't update directly, just set up/reset a timer that will perform the update when it elapses.
173  self.delayedAutoUpdateTimer.start()
174 
175  def observeSegmentation(self, observationEnabled):
176  import vtkSegmentationCorePython as vtkSegmentationCore
177  segmentation = self.scriptedEffect.parameterSetNode().GetSegmentationNode().GetSegmentation()
178  if observationEnabled and self.observedSegmentation == segmentation:
179  return
180  if not observationEnabled and not self.observedSegmentation:
181  return
182  # Need to update the observer
183  # Remove old observer
184  if self.observedSegmentation:
185  for tag in self.segmentationNodeObserverTags:
186  self.observedSegmentation.RemoveObserver(tag)
188  self.observedSegmentation = None
189  # Add new observer
190  if observationEnabled and segmentation is not None:
191  self.observedSegmentation = segmentation
192  observedEvents = [
193  vtkSegmentationCore.vtkSegmentation.SegmentAdded,
194  vtkSegmentationCore.vtkSegmentation.SegmentRemoved,
195  vtkSegmentationCore.vtkSegmentation.SegmentModified,
196  vtkSegmentationCore.vtkSegmentation.MasterRepresentationModified ]
197  for eventId in observedEvents:
198  self.segmentationNodeObserverTags.append(self.observedSegmentation.AddObserver(eventId, self.onSegmentationModified))
199 
200  def getPreviewNode(self):
201  previewNode = self.scriptedEffect.parameterSetNode().GetNodeReference(ResultPreviewNodeReferenceRole)
202  if previewNode and self.scriptedEffect.parameter("SegmentationResultPreviewOwnerEffect") != self.scriptedEffect.name:
203  # another effect owns this preview node
204  return None
205  return previewNode
206 
207  def updateGUIFromMRML(self):
208 
209  previewNode = self.getPreviewNode()
210 
211  self.cancelButton.setEnabled(previewNode is not None)
212  self.applyButton.setEnabled(previewNode is not None)
213 
214  self.previewOpacitySlider.setEnabled(previewNode is not None)
215  if previewNode:
216  wasBlocked = self.previewOpacitySlider.blockSignals(True)
217  self.previewOpacitySlider.value = self.getPreviewOpacity()
218  self.previewOpacitySlider.blockSignals(wasBlocked)
219  self.previewButton.text = "Update"
220  self.previewShow3DButton.setEnabled(True)
221  self.previewShow3DButton.setChecked(self.getPreviewShow3D())
222  self.autoUpdateCheckBox.setEnabled(True)
223  self.observeSegmentation(self.autoUpdateCheckBox.isChecked())
224  else:
225  self.previewButton.text = "Initialize"
226  self.autoUpdateCheckBox.setEnabled(False)
227  self.previewShow3DButton.setEnabled(False)
228  self.delayedAutoUpdateTimer.stop()
229  self.observeSegmentation(False)
230 
231  autoUpdate = qt.Qt.Unchecked if self.scriptedEffect.integerParameter("AutoUpdate") == 0 else qt.Qt.Checked
232  wasBlocked = self.autoUpdateCheckBox.blockSignals(True)
233  self.autoUpdateCheckBox.setCheckState(autoUpdate)
234  self.autoUpdateCheckBox.blockSignals(wasBlocked)
235 
236  def updateMRMLFromGUI(self):
237  segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()
238  previewNode = self.getPreviewNode()
239  if previewNode:
240  self.setPreviewOpacity(self.previewOpacitySlider.value)
241  self.setPreviewShow3D(self.previewShow3DButton.checked)
242 
243  autoUpdate = 1 if self.autoUpdateCheckBox.isChecked() else 0
244  self.scriptedEffect.setParameter("AutoUpdate", autoUpdate)
245 
246  def onPreview(self):
247  slicer.util.showStatusMessage("Running {0} auto-complete...".format(self.scriptedEffect.name), 2000)
248  try:
249  # This can be a long operation - indicate it to the user
250  qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor)
251  self.preview()
252  finally:
253  qt.QApplication.restoreOverrideCursor()
254 
255  def reset(self):
256  self.delayedAutoUpdateTimer.stop()
257  self.observeSegmentation(False)
258  previewNode = self.scriptedEffect.parameterSetNode().GetNodeReference(ResultPreviewNodeReferenceRole)
259  if previewNode:
260  self.scriptedEffect.parameterSetNode().SetNodeReferenceID(ResultPreviewNodeReferenceRole, None)
261  slicer.mrmlScene.RemoveNode(previewNode)
262  self.scriptedEffect.setCommonParameter("SegmentationResultPreviewOwnerEffect", "")
263  segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()
264  segmentationNode.GetDisplayNode().SetOpacity(1.0)
265  self.mergedLabelmapGeometryImage = None
266  self.selectedSegmentIds = None
268  self.clippedMasterImageData = None
269  self.updateGUIFromMRML()
270 
271  def onCancel(self):
272  self.reset()
273 
274  def onApply(self):
275  self.delayedAutoUpdateTimer.stop()
276  self.observeSegmentation(False)
277 
278  import vtkSegmentationCorePython as vtkSegmentationCore
279  segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()
280  segmentationDisplayNode = segmentationNode.GetDisplayNode()
281  previewNode = self.getPreviewNode()
282 
283  self.scriptedEffect.saveStateForUndo()
284 
285  previewContainsClosedSurfaceRepresentation = previewNode.GetSegmentation().ContainsRepresentation(
286  slicer.vtkSegmentationConverter.GetSegmentationClosedSurfaceRepresentationName())
287 
288  # Move segments from preview into current segmentation
289  segmentIDs = vtk.vtkStringArray()
290  previewNode.GetSegmentation().GetSegmentIDs(segmentIDs)
291  for index in xrange(segmentIDs.GetNumberOfValues()):
292  segmentID = segmentIDs.GetValue(index)
293  previewSegment = previewNode.GetSegmentation().GetSegment(segmentID)
294  previewSegmentLabelmap = previewSegment.GetRepresentation(vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationBinaryLabelmapRepresentationName())
295  slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(previewSegmentLabelmap, segmentationNode, segmentID)
296  if segmentationDisplayNode is not None and self.isBackgroundLabelmap(previewSegmentLabelmap):
297  # Automatically hide result segments that are background (all eight corners are non-zero)
298  segmentationDisplayNode.SetSegmentVisibility(segmentID, False)
299  previewNode.GetSegmentation().RemoveSegment(segmentID) # delete now to limit memory usage
300 
301  if previewContainsClosedSurfaceRepresentation:
302  segmentationNode.CreateClosedSurfaceRepresentation()
303 
304  self.reset()
305 
306  def setPreviewOpacity(self, opacity):
307  segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()
308  segmentationNode.GetDisplayNode().SetOpacity(1.0-opacity)
309  previewNode = self.getPreviewNode()
310  if previewNode:
311  previewNode.GetDisplayNode().SetOpacity(opacity)
312  previewNode.GetDisplayNode().SetOpacity3D(opacity)
313 
314  # Make sure the GUI is up-to-date
315  wasBlocked = self.previewOpacitySlider.blockSignals(True)
316  self.previewOpacitySlider.value = opacity
317  self.previewOpacitySlider.blockSignals(wasBlocked)
318 
319  def getPreviewOpacity(self):
320  previewNode = self.getPreviewNode()
321  return previewNode.GetDisplayNode().GetOpacity() if previewNode else 0.6 # default opacity for preview
322 
323  def setPreviewShow3D(self, show):
324  previewNode = self.getPreviewNode()
325  if previewNode:
326  if show:
327  previewNode.CreateClosedSurfaceRepresentation()
328  else:
329  previewNode.RemoveClosedSurfaceRepresentation()
330 
331  # Make sure the GUI is up-to-date
332  wasBlocked = self.previewShow3DButton.blockSignals(True)
333  self.previewShow3DButton.checked = show
334  self.previewShow3DButton.blockSignals(wasBlocked)
335 
336  def getPreviewShow3D(self):
337  previewNode = self.getPreviewNode()
338  if not previewNode:
339  return False
340  containsClosedSurfaceRepresentation = previewNode.GetSegmentation().ContainsRepresentation(
341  slicer.vtkSegmentationConverter.GetSegmentationClosedSurfaceRepresentationName())
342  return containsClosedSurfaceRepresentation
343 
344  def preview(self):
345  # Get master volume image data
346  import vtkSegmentationCorePython as vtkSegmentationCore
347  masterImageData = self.scriptedEffect.masterVolumeImageData()
348 
349  # Get segmentation
350  segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()
351 
352  previewNode = self.getPreviewNode()
353  if (not previewNode or not self.mergedLabelmapGeometryImage
355 
356  self.reset()
357  # Compute merged labelmap extent (effective extent slightly expanded)
358  self.selectedSegmentIds = vtk.vtkStringArray()
359  segmentationNode.GetDisplayNode().GetVisibleSegmentIDs(self.selectedSegmentIds)
360  if self.selectedSegmentIds.GetNumberOfValues() < self.minimumNumberOfSegments:
361  logging.error("Auto-complete operation skipped: at least {0} visible segments are required".format(self.minimumNumberOfSegments))
362  return
363  if not self.mergedLabelmapGeometryImage:
364  self.mergedLabelmapGeometryImage = vtkSegmentationCore.vtkOrientedImageData()
365  commonGeometryString = segmentationNode.GetSegmentation().DetermineCommonLabelmapGeometry(
366  vtkSegmentationCore.vtkSegmentation.EXTENT_UNION_OF_EFFECTIVE_SEGMENTS, self.selectedSegmentIds)
367  if not commonGeometryString:
368  logging.info("Auto-complete operation skipped: all visible segments are empty")
369  return
370  vtkSegmentationCore.vtkSegmentationConverter.DeserializeImageGeometry(commonGeometryString, self.mergedLabelmapGeometryImage)
371 
372  masterImageExtent = masterImageData.GetExtent()
373  labelsEffectiveExtent = self.mergedLabelmapGeometryImage.GetExtent()
374  # Margin size is relative to combined seed region size, but minimum of 3 voxels
375  print("self.extentGrowthRatio = {0}".format(self.extentGrowthRatio))
376  margin = [
377  int(max(3, self.extentGrowthRatio * (labelsEffectiveExtent[1]-labelsEffectiveExtent[0]))),
378  int(max(3, self.extentGrowthRatio * (labelsEffectiveExtent[3]-labelsEffectiveExtent[2]))),
379  int(max(3, self.extentGrowthRatio * (labelsEffectiveExtent[5]-labelsEffectiveExtent[4]))) ]
380  labelsExpandedExtent = [
381  max(masterImageExtent[0], labelsEffectiveExtent[0]-margin[0]),
382  min(masterImageExtent[1], labelsEffectiveExtent[1]+margin[0]),
383  max(masterImageExtent[2], labelsEffectiveExtent[2]-margin[1]),
384  min(masterImageExtent[3], labelsEffectiveExtent[3]+margin[1]),
385  max(masterImageExtent[4], labelsEffectiveExtent[4]-margin[2]),
386  min(masterImageExtent[5], labelsEffectiveExtent[5]+margin[2]) ]
387  print("masterImageExtent = "+repr(masterImageExtent))
388  print("labelsEffectiveExtent = "+repr(labelsEffectiveExtent))
389  print("labelsExpandedExtent = "+repr(labelsExpandedExtent))
390  self.mergedLabelmapGeometryImage.SetExtent(labelsExpandedExtent)
391 
392  # Create and setup preview node
393  previewNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSegmentationNode")
394  previewNode.CreateDefaultDisplayNodes()
395  previewNode.GetDisplayNode().SetVisibility2DOutline(False)
396  if segmentationNode.GetParentTransformNode():
397  previewNode.SetAndObserveTransformNodeID(segmentationNode.GetParentTransformNode().GetID())
398  self.scriptedEffect.parameterSetNode().SetNodeReferenceID(ResultPreviewNodeReferenceRole, previewNode.GetID())
399  self.scriptedEffect.setCommonParameter("SegmentationResultPreviewOwnerEffect", self.scriptedEffect.name)
400  self.setPreviewOpacity(0.6)
401 
402  # Disable smoothing for closed surface generation to make it fast
403  previewNode.GetSegmentation().SetConversionParameter(
404  slicer.vtkBinaryLabelmapToClosedSurfaceConversionRule.GetSmoothingFactorParameterName(),
405  "-0.5");
406 
407  inputContainsClosedSurfaceRepresentation = segmentationNode.GetSegmentation().ContainsRepresentation(
408  slicer.vtkSegmentationConverter.GetSegmentationClosedSurfaceRepresentationName())
409 
410  self.setPreviewShow3D(inputContainsClosedSurfaceRepresentation)
411 
413  self.clippedMasterImageData = vtkSegmentationCore.vtkOrientedImageData()
414  masterImageClipper = vtk.vtkImageConstantPad()
415  masterImageClipper.SetInputData(masterImageData)
416  masterImageClipper.SetOutputWholeExtent(self.mergedLabelmapGeometryImage.GetExtent())
417  masterImageClipper.Update()
418  self.clippedMasterImageData.ShallowCopy(masterImageClipper.GetOutput())
419  self.clippedMasterImageData.CopyDirections(self.mergedLabelmapGeometryImage)
420 
423  self.clippedMaskImageData = vtkSegmentationCore.vtkOrientedImageData()
424  intensityBasedMasking = self.scriptedEffect.parameterSetNode().GetMasterVolumeIntensityMask()
425  success = segmentationNode.GenerateEditMask(self.clippedMaskImageData,
426  self.scriptedEffect.parameterSetNode().GetMaskMode(),
427  self.clippedMasterImageData, # reference geometry
428  "", # edited segment ID
429  self.scriptedEffect.parameterSetNode().GetMaskSegmentID() if self.scriptedEffect.parameterSetNode().GetMaskSegmentID() else "",
430  self.clippedMasterImageData if intensityBasedMasking else None,
431  self.scriptedEffect.parameterSetNode().GetMasterVolumeIntensityMaskRange() if intensityBasedMasking else None)
432  if not success:
433  logging.error("Failed to create edit mask")
434  self.clippedMaskImageData = None
435 
436  previewNode.SetName(segmentationNode.GetName()+" preview")
437 
438  mergedImage = vtkSegmentationCore.vtkOrientedImageData()
439  segmentationNode.GenerateMergedLabelmapForAllSegments(mergedImage,
440  vtkSegmentationCore.vtkSegmentation.EXTENT_UNION_OF_EFFECTIVE_SEGMENTS, self.mergedLabelmapGeometryImage, self.selectedSegmentIds)
441 
442  outputLabelmap = vtkSegmentationCore.vtkOrientedImageData()
443 
444  self.computePreviewLabelmap(mergedImage, outputLabelmap)
445 
446  # Write output segmentation results in segments
447  for index in xrange(self.selectedSegmentIds.GetNumberOfValues()):
448  segmentID = self.selectedSegmentIds.GetValue(index)
449  segment = segmentationNode.GetSegmentation().GetSegment(segmentID)
450  # Disable save with scene?
451 
452  # Get only the label of the current segment from the output image
453  thresh = vtk.vtkImageThreshold()
454  thresh.ReplaceInOn()
455  thresh.ReplaceOutOn()
456  thresh.SetInValue(1)
457  thresh.SetOutValue(0)
458  labelValue = index + 1 # n-th segment label value = n + 1 (background label value is 0)
459  thresh.ThresholdBetween(labelValue, labelValue);
460  thresh.SetOutputScalarType(vtk.VTK_UNSIGNED_CHAR)
461  thresh.SetInputData(outputLabelmap)
462  thresh.Update()
463 
464  # Write label to segment
465  newSegmentLabelmap = vtkSegmentationCore.vtkOrientedImageData()
466  newSegmentLabelmap.ShallowCopy(thresh.GetOutput())
467  newSegmentLabelmap.CopyDirections(mergedImage)
468  newSegment = previewNode.GetSegmentation().GetSegment(segmentID)
469  if not newSegment:
470  newSegment = vtkSegmentationCore.vtkSegment()
471  newSegment.SetName(segment.GetName())
472  color = segmentationNode.GetSegmentation().GetSegment(segmentID).GetColor()
473  newSegment.SetColor(color)
474  previewNode.GetSegmentation().AddSegment(newSegment, segmentID)
475  slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(newSegmentLabelmap, previewNode, segmentID)
476 
477  # Automatically hide result segments that are background (all eight corners are non-zero)
478  previewNode.GetDisplayNode().SetSegmentVisibility3D(segmentID, not self.isBackgroundLabelmap(newSegmentLabelmap))
479 
480  self.updateGUIFromMRML()
481 
482 ResultPreviewNodeReferenceRole = "SegmentationResultPreview"