Slicer  4.10
Slicer is a multi-platform, free and open source software package for visualization and medical image computing
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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"