9 from .AbstractScriptedSegmentEditorEffect
import *
11 __all__ = [
'AbstractScriptedSegmentEditorAutoCompleteEffect']
22 """ AutoCompleteEffect is an effect that can create a full segmentation 23 from a partial segmentation (not all slices are segmented or only 24 part of the target structures are painted). 30 scriptedEffect.perSegment =
False 31 AbstractScriptedSegmentEditorEffect.__init__(self, scriptedEffect)
49 autoUpdateDelaySec = 1.0
61 super(SegmentEditorAutoCompleteEffect, self).
__del__()
67 if labelmapOrientedImageData
is None:
70 extent = labelmapOrientedImageData.GetExtent()
71 if extent[0] > extent[1]
or extent[2] > extent[3]
or extent[4] > extent[5]:
73 numberOfFilledCorners = 0
77 voxelValue = labelmapOrientedImageData.GetScalarComponentAsFloat(extent[i], extent[j], extent[k], 0)
80 numberOfFilledCorners += 1
82 if voxelValue == label:
83 numberOfFilledCorners += 1
84 if numberOfFilledCorners > 4:
90 self.
autoUpdateCheckBox.setToolTip(
"Auto-update results preview when input segments change.")
95 self.
previewButton.objectName = self.__class__.__name__ +
'Preview' 96 self.
previewButton.setToolTip(
"Preview complete segmentation")
99 qSize = qt.QSizePolicy()
100 qSize.setHorizontalPolicy(qt.QSizePolicy.Expanding)
103 previewFrame = qt.QHBoxLayout()
106 self.
scriptedEffect.addLabeledOptionsWidget(
"Preview:", previewFrame)
121 displayFrame = qt.QHBoxLayout()
122 displayFrame.addWidget(qt.QLabel(
"inputs"))
124 displayFrame.addWidget(qt.QLabel(
"results"))
126 self.
scriptedEffect.addLabeledOptionsWidget(
"Display:", displayFrame)
129 self.
cancelButton.objectName = self.__class__.__name__ +
'Cancel' 130 self.
cancelButton.setToolTip(
"Clear preview and cancel auto-complete")
133 self.
applyButton.objectName = self.__class__.__name__ +
'Apply' 134 self.
applyButton.setToolTip(
"Replace segments by previewed result")
136 finishFrame = qt.QHBoxLayout()
150 return slicer.util.mainWindow().cursor
160 import vtkSegmentationCorePython
as vtkSegmentationCore
161 segmentationNode = self.
scriptedEffect.parameterSetNode().GetSegmentationNode()
162 segmentation = segmentationNode.GetSegmentation()
167 segment = segmentation.GetSegment(segmentID)
170 logging.debug(
"Segmentation cancelled because an input segment was deleted")
173 segmentLabelmap = segment.GetRepresentation(vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationBinaryLabelmapRepresentationName())
188 logging.debug(
"Segmentation update requested")
195 import vtkSegmentationCorePython
as vtkSegmentationCore
198 segmentationNode =
None 200 segmentationNode = parameterSetNode.GetSegmentationNode()
204 segmentation = segmentationNode.GetSegmentation()
218 if observationEnabled
and segmentation
is not None:
221 vtkSegmentationCore.vtkSegmentation.SegmentAdded,
222 vtkSegmentationCore.vtkSegmentation.SegmentRemoved,
223 vtkSegmentationCore.vtkSegmentation.SegmentModified,
224 vtkSegmentationCore.vtkSegmentation.MasterRepresentationModified]
225 for eventId
in observedEvents:
229 previewNode = self.
scriptedEffect.parameterSetNode().GetNodeReference(ResultPreviewNodeReferenceRole)
240 self.
applyButton.setEnabled(previewNode
is not None)
259 autoUpdate = qt.Qt.Unchecked
if self.
scriptedEffect.integerParameter(
"AutoUpdate") == 0
else qt.Qt.Checked
265 segmentationNode = self.
scriptedEffect.parameterSetNode().GetSegmentationNode()
279 slicer.util.showStatusMessage(f
"Running {self.scriptedEffect.name} auto-complete...", 2000)
282 qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor)
285 qt.QApplication.restoreOverrideCursor()
292 previewNode = self.
scriptedEffect.parameterSetNode().GetNodeReference(ResultPreviewNodeReferenceRole)
294 self.
scriptedEffect.parameterSetNode().SetNodeReferenceID(ResultPreviewNodeReferenceRole,
None)
295 slicer.mrmlScene.RemoveNode(previewNode)
296 self.
scriptedEffect.setCommonParameter(
"SegmentationResultPreviewOwnerEffect",
"")
297 segmentationNode = self.
scriptedEffect.parameterSetNode().GetSegmentationNode()
298 segmentationNode.GetDisplayNode().SetOpacity(1.0)
313 segmentationNode = self.
scriptedEffect.parameterSetNode().GetSegmentationNode()
314 segmentationDisplayNode = segmentationNode.GetDisplayNode()
319 previewContainsClosedSurfaceRepresentation = previewNode.GetSegmentation().ContainsRepresentation(
320 slicer.vtkSegmentationConverter.GetSegmentationClosedSurfaceRepresentationName())
323 segmentIDs = vtk.vtkStringArray()
324 previewNode.GetSegmentation().GetSegmentIDs(segmentIDs)
325 for index
in range(segmentIDs.GetNumberOfValues()):
326 segmentID = segmentIDs.GetValue(index)
327 previewSegmentLabelmap = slicer.vtkOrientedImageData()
328 previewNode.GetBinaryLabelmapRepresentation(segmentID, previewSegmentLabelmap)
329 self.
scriptedEffect.modifySegmentByLabelmap(segmentationNode, segmentID, previewSegmentLabelmap,
330 slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet)
333 segmentationDisplayNode.SetSegmentVisibility(segmentID,
False)
334 previewNode.GetSegmentation().RemoveSegment(segmentID)
336 if previewContainsClosedSurfaceRepresentation:
337 segmentationNode.CreateClosedSurfaceRepresentation()
342 segmentationNode = self.
scriptedEffect.parameterSetNode().GetSegmentationNode()
343 segmentationNode.GetDisplayNode().SetOpacity(1.0 - opacity)
346 previewNode.GetDisplayNode().SetOpacity(opacity)
347 previewNode.GetDisplayNode().SetOpacity3D(opacity)
356 return previewNode.GetDisplayNode().GetOpacity()
if previewNode
else 0.6
362 previewNode.CreateClosedSurfaceRepresentation()
364 previewNode.RemoveClosedSurfaceRepresentation()
375 containsClosedSurfaceRepresentation = previewNode.GetSegmentation().ContainsRepresentation(
376 slicer.vtkSegmentationConverter.GetSegmentationClosedSurfaceRepresentationName())
377 return containsClosedSurfaceRepresentation
387 import vtkSegmentationCorePython
as vtkSegmentationCore
389 segmentationNode = self.
scriptedEffect.parameterSetNode().GetSegmentationNode()
392 effectiveGeometryImage = slicer.vtkOrientedImageData()
393 effectiveGeometryString = segmentationNode.GetSegmentation().DetermineCommonLabelmapGeometry(
394 vtkSegmentationCore.vtkSegmentation.EXTENT_UNION_OF_EFFECTIVE_SEGMENTS, self.
selectedSegmentIds)
395 if effectiveGeometryString
is None:
397 vtkSegmentationCore.vtkSegmentationConverter.DeserializeImageGeometry(effectiveGeometryString, effectiveGeometryImage)
400 masterImageExtent = masterImageData.GetExtent()
403 effectiveLabelExtent = effectiveGeometryImage.GetExtent()
408 return ((masterImageExtent[0] != currentLabelExtent[0]
and currentLabelExtent[0] > effectiveLabelExtent[0] - self.
minimumExtentMargin)
or 409 (masterImageExtent[1] != currentLabelExtent[1]
and currentLabelExtent[1] < effectiveLabelExtent[1] + self.
minimumExtentMargin)
or 410 (masterImageExtent[2] != currentLabelExtent[2]
and currentLabelExtent[2] > effectiveLabelExtent[2] - self.
minimumExtentMargin)
or 411 (masterImageExtent[3] != currentLabelExtent[3]
and currentLabelExtent[3] < effectiveLabelExtent[3] + self.
minimumExtentMargin)
or 412 (masterImageExtent[4] != currentLabelExtent[4]
and currentLabelExtent[4] > effectiveLabelExtent[4] - self.
minimumExtentMargin)
or 413 (masterImageExtent[5] != currentLabelExtent[5]
and currentLabelExtent[5] < effectiveLabelExtent[5] + self.
minimumExtentMargin))
417 import vtkSegmentationCorePython
as vtkSegmentationCore
420 segmentationNode = self.
scriptedEffect.parameterSetNode().GetSegmentationNode()
438 logging.error(f
"Auto-complete operation skipped: at least {self.minimumNumberOfSegments} visible segments are required")
445 commonGeometryString = segmentationNode.GetSegmentation().DetermineCommonLabelmapGeometry(
446 vtkSegmentationCore.vtkSegmentation.EXTENT_UNION_OF_EFFECTIVE_SEGMENTS, self.
selectedSegmentIds)
447 if not commonGeometryString:
448 logging.info(
"Auto-complete operation skipped: all visible segments are empty")
453 masterImageExtent = masterImageData.GetExtent()
456 print(f
"self.extentGrowthRatio = {self.extentGrowthRatio}")
458 int(max(3, self.
extentGrowthRatio * (labelsEffectiveExtent[1] - labelsEffectiveExtent[0]))),
459 int(max(3, self.
extentGrowthRatio * (labelsEffectiveExtent[3] - labelsEffectiveExtent[2]))),
460 int(max(3, self.
extentGrowthRatio * (labelsEffectiveExtent[5] - labelsEffectiveExtent[4])))]
461 labelsExpandedExtent = [
462 max(masterImageExtent[0], labelsEffectiveExtent[0] - margin[0]),
463 min(masterImageExtent[1], labelsEffectiveExtent[1] + margin[0]),
464 max(masterImageExtent[2], labelsEffectiveExtent[2] - margin[1]),
465 min(masterImageExtent[3], labelsEffectiveExtent[3] + margin[1]),
466 max(masterImageExtent[4], labelsEffectiveExtent[4] - margin[2]),
467 min(masterImageExtent[5], labelsEffectiveExtent[5] + margin[2])]
468 print(
"masterImageExtent = " + repr(masterImageExtent))
469 print(
"labelsEffectiveExtent = " + repr(labelsEffectiveExtent))
470 print(
"labelsExpandedExtent = " + repr(labelsExpandedExtent))
474 previewNode = slicer.mrmlScene.AddNewNodeByClass(
"vtkMRMLSegmentationNode")
475 previewNode.CreateDefaultDisplayNodes()
476 previewNode.GetDisplayNode().SetVisibility2DOutline(
False)
477 if segmentationNode.GetParentTransformNode():
478 previewNode.SetAndObserveTransformNodeID(segmentationNode.GetParentTransformNode().GetID())
479 self.
scriptedEffect.parameterSetNode().SetNodeReferenceID(ResultPreviewNodeReferenceRole, previewNode.GetID())
484 previewNode.GetSegmentation().SetConversionParameter(
485 slicer.vtkBinaryLabelmapToClosedSurfaceConversionRule.GetSmoothingFactorParameterName(),
488 inputContainsClosedSurfaceRepresentation = segmentationNode.GetSegmentation().ContainsRepresentation(
489 slicer.vtkSegmentationConverter.GetSegmentationClosedSurfaceRepresentationName())
495 masterImageClipper = vtk.vtkImageConstantPad()
496 masterImageClipper.SetInputData(masterImageData)
498 masterImageClipper.Update()
505 intensityBasedMasking = self.
scriptedEffect.parameterSetNode().GetMasterVolumeIntensityMask()
512 self.
scriptedEffect.parameterSetNode().GetMasterVolumeIntensityMaskRange()
if intensityBasedMasking
else None)
514 logging.error(
"Failed to create edit mask")
517 previewNode.SetName(segmentationNode.GetName() +
" preview")
518 previewNode.RemoveClosedSurfaceRepresentation()
522 mergedImage = slicer.vtkOrientedImageData()
523 segmentationNode.GenerateMergedLabelmapForAllSegments(mergedImage,
526 outputLabelmap = slicer.vtkOrientedImageData()
527 self.computePreviewLabelmap(mergedImage, outputLabelmap)
529 if previewNode.GetSegmentation().GetNumberOfSegments() != self.
selectedSegmentIds.GetNumberOfValues():
531 previewNode.GetSegmentation().RemoveAllSegments()
536 previewSegment = previewNode.GetSegmentation().GetSegment(segmentID)
537 if not previewSegment:
538 inputSegment = segmentationNode.GetSegmentation().GetSegment(segmentID)
540 previewSegment = vtkSegmentationCore.vtkSegment()
541 previewSegment.SetName(inputSegment.GetName())
542 previewSegment.SetColor(inputSegment.GetColor())
543 previewNode.GetSegmentation().AddSegment(previewSegment, segmentID)
545 labelValue = index + 1
546 previewSegment.AddRepresentation(vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationBinaryLabelmapRepresentationName(), outputLabelmap)
547 previewSegment.SetLabelValue(labelValue)
550 previewNode.GetDisplayNode().SetSegmentVisibility3D(segmentID,
not self.
isBackgroundLabelmap(outputLabelmap, labelValue))
559 ResultPreviewNodeReferenceRole =
"SegmentationResultPreview"
clippedMaskImageDataRequired
def effectiveExtentChanged(self)
def getPreviewShow3D(self)
def updateGUIFromMRML(self)
segmentationNodeObserverTags
previewComputationInProgress
def getPreviewOpacity(self)
def updateMRMLFromGUI(self)
def __del__(self, scriptedEffect)
def setMRMLDefaults(self)
selectedSegmentModifiedTimes
def observeSegmentation(self, observationEnabled)
def isBackgroundLabelmap(labelmapOrientedImageData, label=None)
def __init__(self, scriptedEffect)
mergedLabelmapGeometryImage
def setupOptionsFrame(self)
clippedMasterImageDataRequired
def createCursor(self, widget)
def setPreviewShow3D(self, show)
def setPreviewOpacity(self, opacity)
def onSegmentationModified(self, caller, event)