1 from __future__
import print_function
3 import vtk, qt, ctk, slicer, logging
4 from .AbstractScriptedSegmentEditorEffect
import *
6 __all__ = [
'AbstractScriptedSegmentEditorAutoCompleteEffect']
16 """ AutoCompleteEffect is an effect that can create a full segmentation 17 from a partial segmentation (not all slices are segmented or only 18 part of the target structures are painted). 24 scriptedEffect.perSegment =
False 25 AbstractScriptedSegmentEditorEffect.__init__(self, scriptedEffect)
43 autoUpdateDelaySec = 1.0
54 super(SegmentEditorAutoCompleteEffect,self).
__del__()
60 if labelmapOrientedImageData
is None:
63 extent = labelmapOrientedImageData.GetExtent()
64 if extent[0] > extent[1]
or extent[2] > extent[3]
or extent[4] > extent[5]:
66 numberOfFilledCorners = 0
70 if labelmapOrientedImageData.GetScalarComponentAsFloat(extent[i],extent[j],extent[k],0) > 0:
71 numberOfFilledCorners += 1
72 if numberOfFilledCorners > 4:
78 self.
autoUpdateCheckBox.setToolTip(
"Auto-update results preview when input segments change.")
83 self.
previewButton.objectName = self.__class__.__name__ +
'Preview' 84 self.
previewButton.setToolTip(
"Preview complete segmentation")
87 qSize = qt.QSizePolicy()
88 qSize.setHorizontalPolicy(qt.QSizePolicy.Expanding)
91 previewFrame = qt.QHBoxLayout()
94 self.
scriptedEffect.addLabeledOptionsWidget(
"Preview:", previewFrame)
109 displayFrame = qt.QHBoxLayout()
110 displayFrame.addWidget(qt.QLabel(
"inputs"))
112 displayFrame.addWidget(qt.QLabel(
"results"))
114 self.
scriptedEffect.addLabeledOptionsWidget(
"Display:", displayFrame)
117 self.
cancelButton.objectName = self.__class__.__name__ +
'Cancel' 118 self.
cancelButton.setToolTip(
"Clear preview and cancel auto-complete")
121 self.
applyButton.objectName = self.__class__.__name__ +
'Apply' 122 self.
applyButton.setToolTip(
"Replace segments by previewed result")
124 finishFrame = qt.QHBoxLayout()
138 return slicer.util.mainWindow().cursor
148 import vtkSegmentationCorePython
as vtkSegmentationCore
149 segmentationNode = self.
scriptedEffect.parameterSetNode().GetSegmentationNode()
150 segmentation = segmentationNode.GetSegmentation()
155 segment = segmentation.GetSegment(segmentID)
158 logging.debug(
"Segmentation cancelled because an input segment was deleted")
161 segmentLabelmap = segment.GetRepresentation(vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationBinaryLabelmapRepresentationName())
176 logging.debug(
"Segmentation update requested")
182 import vtkSegmentationCorePython
as vtkSegmentationCore
185 segmentationNode =
None 187 segmentationNode = parameterSetNode.GetSegmentationNode()
191 segmentation = segmentationNode.GetSegmentation()
205 if observationEnabled
and segmentation
is not None:
208 vtkSegmentationCore.vtkSegmentation.SegmentAdded,
209 vtkSegmentationCore.vtkSegmentation.SegmentRemoved,
210 vtkSegmentationCore.vtkSegmentation.SegmentModified,
211 vtkSegmentationCore.vtkSegmentation.MasterRepresentationModified ]
212 for eventId
in observedEvents:
216 previewNode = self.
scriptedEffect.parameterSetNode().GetNodeReference(ResultPreviewNodeReferenceRole)
227 self.
applyButton.setEnabled(previewNode
is not None)
246 autoUpdate = qt.Qt.Unchecked
if self.
scriptedEffect.integerParameter(
"AutoUpdate") == 0
else qt.Qt.Checked
252 segmentationNode = self.
scriptedEffect.parameterSetNode().GetSegmentationNode()
262 slicer.util.showStatusMessage(
"Running {0} auto-complete...".format(self.
scriptedEffect.name), 2000)
265 qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor)
268 qt.QApplication.restoreOverrideCursor()
273 previewNode = self.
scriptedEffect.parameterSetNode().GetNodeReference(ResultPreviewNodeReferenceRole)
275 self.
scriptedEffect.parameterSetNode().SetNodeReferenceID(ResultPreviewNodeReferenceRole,
None)
276 slicer.mrmlScene.RemoveNode(previewNode)
277 self.
scriptedEffect.setCommonParameter(
"SegmentationResultPreviewOwnerEffect",
"")
278 segmentationNode = self.
scriptedEffect.parameterSetNode().GetSegmentationNode()
279 segmentationNode.GetDisplayNode().SetOpacity(1.0)
294 import vtkSegmentationCorePython
as vtkSegmentationCore
295 segmentationNode = self.
scriptedEffect.parameterSetNode().GetSegmentationNode()
296 segmentationDisplayNode = segmentationNode.GetDisplayNode()
301 previewContainsClosedSurfaceRepresentation = previewNode.GetSegmentation().ContainsRepresentation(
302 slicer.vtkSegmentationConverter.GetSegmentationClosedSurfaceRepresentationName())
305 segmentIDs = vtk.vtkStringArray()
306 previewNode.GetSegmentation().GetSegmentIDs(segmentIDs)
307 for index
in range(segmentIDs.GetNumberOfValues()):
308 segmentID = segmentIDs.GetValue(index)
309 previewSegmentLabelmap = slicer.vtkOrientedImageData()
310 previewNode.GetBinaryLabelmapRepresentation(segmentID, previewSegmentLabelmap)
311 self.
scriptedEffect.modifySegmentByLabelmap(segmentationNode, segmentID, previewSegmentLabelmap,
312 slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet)
315 segmentationDisplayNode.SetSegmentVisibility(segmentID,
False)
316 previewNode.GetSegmentation().RemoveSegment(segmentID)
318 if previewContainsClosedSurfaceRepresentation:
319 segmentationNode.CreateClosedSurfaceRepresentation()
324 segmentationNode = self.
scriptedEffect.parameterSetNode().GetSegmentationNode()
325 segmentationNode.GetDisplayNode().SetOpacity(1.0-opacity)
328 previewNode.GetDisplayNode().SetOpacity(opacity)
329 previewNode.GetDisplayNode().SetOpacity3D(opacity)
338 return previewNode.GetDisplayNode().GetOpacity()
if previewNode
else 0.6
344 previewNode.CreateClosedSurfaceRepresentation()
346 previewNode.RemoveClosedSurfaceRepresentation()
357 containsClosedSurfaceRepresentation = previewNode.GetSegmentation().ContainsRepresentation(
358 slicer.vtkSegmentationConverter.GetSegmentationClosedSurfaceRepresentationName())
359 return containsClosedSurfaceRepresentation
369 import vtkSegmentationCorePython
as vtkSegmentationCore
371 segmentationNode = self.
scriptedEffect.parameterSetNode().GetSegmentationNode()
374 effectiveGeometryImage = slicer.vtkOrientedImageData()
375 effectiveGeometryString = segmentationNode.GetSegmentation().DetermineCommonLabelmapGeometry(
376 vtkSegmentationCore.vtkSegmentation.EXTENT_UNION_OF_EFFECTIVE_SEGMENTS, self.
selectedSegmentIds)
377 if effectiveGeometryString
is None:
379 vtkSegmentationCore.vtkSegmentationConverter.DeserializeImageGeometry(effectiveGeometryString, effectiveGeometryImage)
382 masterImageExtent = masterImageData.GetExtent()
385 effectiveLabelExtent = effectiveGeometryImage.GetExtent()
390 return ((masterImageExtent[0] != currentLabelExtent[0]
and currentLabelExtent[0] > effectiveLabelExtent[0] - self.
minimumExtentMargin)
or 391 (masterImageExtent[1] != currentLabelExtent[1]
and currentLabelExtent[1] < effectiveLabelExtent[1] + self.
minimumExtentMargin)
or 392 (masterImageExtent[2] != currentLabelExtent[2]
and currentLabelExtent[2] > effectiveLabelExtent[2] - self.
minimumExtentMargin)
or 393 (masterImageExtent[3] != currentLabelExtent[3]
and currentLabelExtent[3] < effectiveLabelExtent[3] + self.
minimumExtentMargin)
or 394 (masterImageExtent[4] != currentLabelExtent[4]
and currentLabelExtent[4] > effectiveLabelExtent[4] - self.
minimumExtentMargin)
or 395 (masterImageExtent[5] != currentLabelExtent[5]
and currentLabelExtent[5] < effectiveLabelExtent[5] + self.
minimumExtentMargin))
399 import vtkSegmentationCorePython
as vtkSegmentationCore
402 segmentationNode = self.
scriptedEffect.parameterSetNode().GetSegmentationNode()
420 logging.error(
"Auto-complete operation skipped: at least {0} visible segments are required".format(self.
minimumNumberOfSegments))
427 commonGeometryString = segmentationNode.GetSegmentation().DetermineCommonLabelmapGeometry(
428 vtkSegmentationCore.vtkSegmentation.EXTENT_UNION_OF_EFFECTIVE_SEGMENTS, self.
selectedSegmentIds)
429 if not commonGeometryString:
430 logging.info(
"Auto-complete operation skipped: all visible segments are empty")
435 masterImageExtent = masterImageData.GetExtent()
440 int(max(3, self.
extentGrowthRatio * (labelsEffectiveExtent[1]-labelsEffectiveExtent[0]))),
441 int(max(3, self.
extentGrowthRatio * (labelsEffectiveExtent[3]-labelsEffectiveExtent[2]))),
442 int(max(3, self.
extentGrowthRatio * (labelsEffectiveExtent[5]-labelsEffectiveExtent[4]))) ]
443 labelsExpandedExtent = [
444 max(masterImageExtent[0], labelsEffectiveExtent[0]-margin[0]),
445 min(masterImageExtent[1], labelsEffectiveExtent[1]+margin[0]),
446 max(masterImageExtent[2], labelsEffectiveExtent[2]-margin[1]),
447 min(masterImageExtent[3], labelsEffectiveExtent[3]+margin[1]),
448 max(masterImageExtent[4], labelsEffectiveExtent[4]-margin[2]),
449 min(masterImageExtent[5], labelsEffectiveExtent[5]+margin[2]) ]
450 print(
"masterImageExtent = "+repr(masterImageExtent))
451 print(
"labelsEffectiveExtent = "+repr(labelsEffectiveExtent))
452 print(
"labelsExpandedExtent = "+repr(labelsExpandedExtent))
456 previewNode = slicer.mrmlScene.AddNewNodeByClass(
"vtkMRMLSegmentationNode")
457 previewNode.CreateDefaultDisplayNodes()
458 previewNode.GetDisplayNode().SetVisibility2DOutline(
False)
459 if segmentationNode.GetParentTransformNode():
460 previewNode.SetAndObserveTransformNodeID(segmentationNode.GetParentTransformNode().GetID())
461 self.
scriptedEffect.parameterSetNode().SetNodeReferenceID(ResultPreviewNodeReferenceRole, previewNode.GetID())
466 previewNode.GetSegmentation().SetConversionParameter(
467 slicer.vtkBinaryLabelmapToClosedSurfaceConversionRule.GetSmoothingFactorParameterName(),
470 inputContainsClosedSurfaceRepresentation = segmentationNode.GetSegmentation().ContainsRepresentation(
471 slicer.vtkSegmentationConverter.GetSegmentationClosedSurfaceRepresentationName())
477 masterImageClipper = vtk.vtkImageConstantPad()
478 masterImageClipper.SetInputData(masterImageData)
480 masterImageClipper.Update()
487 intensityBasedMasking = self.
scriptedEffect.parameterSetNode().GetMasterVolumeIntensityMask()
494 self.
scriptedEffect.parameterSetNode().GetMasterVolumeIntensityMaskRange()
if intensityBasedMasking
else None)
496 logging.error(
"Failed to create edit mask")
499 previewNode.SetName(segmentationNode.GetName()+
" preview")
501 mergedImage = slicer.vtkOrientedImageData()
502 segmentationNode.GenerateMergedLabelmapForAllSegments(mergedImage,
505 outputLabelmap = slicer.vtkOrientedImageData()
507 self.computePreviewLabelmap(mergedImage, outputLabelmap)
512 segment = segmentationNode.GetSegmentation().GetSegment(segmentID)
516 thresh = vtk.vtkImageThreshold()
518 thresh.ReplaceOutOn()
520 thresh.SetOutValue(0)
521 labelValue = index + 1
522 thresh.ThresholdBetween(labelValue, labelValue);
523 thresh.SetOutputScalarType(vtk.VTK_UNSIGNED_CHAR)
524 thresh.SetInputData(outputLabelmap)
528 newSegmentLabelmap = slicer.vtkOrientedImageData()
529 newSegmentLabelmap.ShallowCopy(thresh.GetOutput())
530 newSegmentLabelmap.CopyDirections(mergedImage)
531 newSegment = previewNode.GetSegmentation().GetSegment(segmentID)
533 newSegment = vtkSegmentationCore.vtkSegment()
534 newSegment.SetName(segment.GetName())
535 color = segmentationNode.GetSegmentation().GetSegment(segmentID).GetColor()
536 newSegment.SetColor(color)
537 previewNode.GetSegmentation().AddSegment(newSegment, segmentID)
538 self.
scriptedEffect.modifySegmentByLabelmap(previewNode, segmentID, newSegmentLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet)
541 previewNode.GetDisplayNode().SetSegmentVisibility3D(segmentID,
not self.
isBackgroundLabelmap(newSegmentLabelmap))
549 ResultPreviewNodeReferenceRole =
"SegmentationResultPreview"
clippedMaskImageDataRequired
def effectiveExtentChanged(self)
def getPreviewShow3D(self)
def updateGUIFromMRML(self)
segmentationNodeObserverTags
def getPreviewOpacity(self)
def updateMRMLFromGUI(self)
def __del__(self, scriptedEffect)
def setMRMLDefaults(self)
selectedSegmentModifiedTimes
def observeSegmentation(self, observationEnabled)
def __init__(self, scriptedEffect)
mergedLabelmapGeometryImage
def setupOptionsFrame(self)
clippedMasterImageDataRequired
def createCursor(self, widget)
def isBackgroundLabelmap(labelmapOrientedImageData)
def setPreviewShow3D(self, show)
def setPreviewOpacity(self, opacity)
def onSegmentationModified(self, caller, event)