2 import vtk, qt, ctk, slicer
4 from SegmentEditorEffects
import *
7 """ LogicalEffect is an MorphologyEffect to erode a layer of pixels from a segment 11 scriptedEffect.name =
'Logical operators' 13 AbstractScriptedSegmentEditorEffect.__init__(self, scriptedEffect)
16 import qSlicerSegmentationsEditorEffectsPythonQt
as effects
17 clonedEffect = effects.qSlicerSegmentEditorScriptedEffect(
None)
18 clonedEffect.setPythonSource(__file__.replace(
'\\',
'/'))
22 iconPath = os.path.join(os.path.dirname(__file__),
'Resources/Icons/Logical.png')
23 if os.path.exists(iconPath):
24 return qt.QIcon(iconPath)
28 return """<html>Apply logical operators or combine segments<br>. Available operations:<p> 29 <ul style="margin: 0"> 30 <li><b>Copy:</b> replace the selected segment by the modifier segment.</li> 31 <li><b>Add:</b> add modifier segment to current segment.</li> 32 <li><b>Subtract:</b> subtract region of modifier segment from the selected segment.</li> 33 <li><b>Intersect:</b> only keeps those regions in the select segment that are common with the modifier segment.</li> 34 <li><b>Invert:</b> inverts selected segment.</li> 35 <li><b>Clear:</b> clears selected segment.</li> 36 <li><b>Fill:</b> completely fills selected segment.</li> 38 <b>Selected segment:</b> segment selected in the segment list - above. <b>Modifier segment:</b> segment chosen in segment list in effect options - below. 51 self.
methodSelectorComboBox.setToolTip(
'Click <dfn>Show details</dfn> link above for description of operations.')
54 self.
bypassMaskingCheckBox.setToolTip(
"Ignore all masking options and only modify the selected segment.")
58 self.
applyButton.objectName = self.__class__.__name__ +
'Apply' 60 operationFrame = qt.QHBoxLayout()
64 self.
marginSizeMmLabel = self.scriptedEffect.addLabeledOptionsWidget(
"Operation:", operationFrame)
76 self.
modifierSegmentSelector.setToolTip(
'Contents of this segment will be used for modifying the selected segment. This segment itself will not be changed.')
86 return slicer.util.mainWindow().cursor
89 self.scriptedEffect.setParameterDefault(
"Operation", LOGICAL_COPY)
90 self.scriptedEffect.setParameterDefault(
"ModifierSegmentID",
"")
91 self.scriptedEffect.setParameterDefault(
"BypassMasking", 1)
94 segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()
95 if not segmentationNode:
97 if not self.scriptedEffect.parameterDefined(
"ModifierSegmentID"):
100 modifierSegmentIDs = self.scriptedEffect.parameter(
"ModifierSegmentID").split(
';')
101 if not modifierSegmentIDs:
103 return modifierSegmentIDs[0]
106 operation = self.scriptedEffect.parameter(
"Operation")
113 segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()
123 if operation == LOGICAL_COPY:
125 elif operation == LOGICAL_UNION:
127 elif operation == LOGICAL_SUBTRACT:
129 elif operation == LOGICAL_INTERSECT:
134 if modifierSegmentRequired
and not modifierSegmentID:
135 self.
applyButton.setToolTip(
"Please select a modifier segment in the list below.")
141 bypassMasking = qt.Qt.Unchecked
if self.scriptedEffect.integerParameter(
"BypassMasking") == 0
else qt.Qt.Checked
149 self.scriptedEffect.setParameter(
"Operation", operation)
152 self.scriptedEffect.setParameter(
"BypassMasking", bypassMasking)
155 self.scriptedEffect.setParameter(
"ModifierSegmentID", modifierSegmentIDs)
158 import vtkSegmentationCorePython
as vtkSegmentationCore
162 inverter = vtk.vtkImageThreshold()
163 inverter.SetInputData(modifierLabelmap)
164 inverter.SetInValue(fillValue)
165 inverter.SetOutValue(eraseValue)
166 inverter.ReplaceInOn()
167 inverter.ThresholdByLower(0)
168 inverter.SetOutputScalarType(vtk.VTK_UNSIGNED_CHAR)
171 invertedModifierLabelmap = vtkSegmentationCore.vtkOrientedImageData()
172 invertedModifierLabelmap.ShallowCopy(inverter.GetOutput())
173 imageToWorldMatrix = vtk.vtkMatrix4x4()
174 modifierLabelmap.GetImageToWorldMatrix(imageToWorldMatrix)
175 invertedModifierLabelmap.SetGeometryFromImageToWorldMatrix(imageToWorldMatrix)
176 return invertedModifierLabelmap
180 self.scriptedEffect.saveStateForUndo()
182 import vtkSegmentationCorePython
as vtkSegmentationCore
186 operation = self.scriptedEffect.parameter(
"Operation")
187 bypassMasking = (self.scriptedEffect.integerParameter(
"BypassMasking") != 0)
189 selectedSegmentID = self.scriptedEffect.parameterSetNode().GetSelectedSegmentID()
191 segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode()
192 segmentation = segmentationNode.GetSegmentation()
198 if not modifierSegmentID:
199 logging.error(
"Operation {0} requires a selected modifier segment".format(operation))
201 modifierSegment = segmentation.GetSegment(modifierSegmentID)
202 modifierSegmentLabelmap = modifierSegment.GetRepresentation(vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationBinaryLabelmapRepresentationName())
204 if operation == LOGICAL_COPY:
206 slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(modifierSegmentLabelmap,
207 segmentationNode, selectedSegmentID, slicer.vtkSlicerSegmentationsModuleLogic.MODE_REPLACE, modifierSegmentLabelmap.GetExtent())
209 self.scriptedEffect.modifySelectedSegmentByLabelmap(modifierSegmentLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet)
210 elif operation == LOGICAL_UNION:
212 slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(modifierSegmentLabelmap,
213 segmentationNode, selectedSegmentID, slicer.vtkSlicerSegmentationsModuleLogic.MODE_MERGE_MAX, modifierSegmentLabelmap.GetExtent())
215 self.scriptedEffect.modifySelectedSegmentByLabelmap(modifierSegmentLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeAdd)
216 elif operation == LOGICAL_SUBTRACT:
219 slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(invertedModifierSegmentLabelmap, segmentationNode, selectedSegmentID,
220 slicer.vtkSlicerSegmentationsModuleLogic.MODE_MERGE_MIN, modifierSegmentLabelmap.GetExtent())
222 self.scriptedEffect.modifySelectedSegmentByLabelmap(modifierSegmentLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeRemove)
223 elif operation == LOGICAL_INTERSECT:
224 selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap()
225 intersectionLabelmap = vtkSegmentationCore.vtkOrientedImageData()
226 vtkSegmentationCore.vtkOrientedImageDataResample.MergeImage(selectedSegmentLabelmap, modifierSegmentLabelmap, intersectionLabelmap, vtkSegmentationCore.vtkOrientedImageDataResample.OPERATION_MINIMUM, selectedSegmentLabelmap.GetExtent())
227 selectedSegmentLabelmapExtent = selectedSegmentLabelmap.GetExtent()
228 modifierSegmentLabelmapExtent = modifierSegmentLabelmap.GetExtent()
229 commonExtent = [max(selectedSegmentLabelmapExtent[0], modifierSegmentLabelmapExtent[0]),
230 min(selectedSegmentLabelmapExtent[1], modifierSegmentLabelmapExtent[1]),
231 max(selectedSegmentLabelmapExtent[2], modifierSegmentLabelmapExtent[2]),
232 min(selectedSegmentLabelmapExtent[3], modifierSegmentLabelmapExtent[3]),
233 max(selectedSegmentLabelmapExtent[4], modifierSegmentLabelmapExtent[4]),
234 min(selectedSegmentLabelmapExtent[5], modifierSegmentLabelmapExtent[5])]
236 slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(intersectionLabelmap, segmentationNode, selectedSegmentID,
237 slicer.vtkSlicerSegmentationsModuleLogic.MODE_REPLACE, commonExtent)
239 self.scriptedEffect.modifySelectedSegmentByLabelmap(intersectionLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet, commonExtent)
241 elif operation == LOGICAL_INVERT:
242 selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap()
245 slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(
246 invertedSelectedSegmentLabelmap, segmentationNode, selectedSegmentID, slicer.vtkSlicerSegmentationsModuleLogic.MODE_REPLACE)
248 self.scriptedEffect.modifySelectedSegmentByLabelmap(invertedSelectedSegmentLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet)
250 elif operation == LOGICAL_CLEAR
or operation == LOGICAL_FILL:
251 selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap()
252 vtkSegmentationCore.vtkOrientedImageDataResample.FillImage(selectedSegmentLabelmap, 1
if operation == LOGICAL_FILL
else 0, selectedSegmentLabelmap.GetExtent())
254 slicer.vtkSlicerSegmentationsModuleLogic.SetBinaryLabelmapToSegment(
255 selectedSegmentLabelmap, segmentationNode, selectedSegmentID, slicer.vtkSlicerSegmentationsModuleLogic.MODE_REPLACE)
257 self.scriptedEffect.modifySelectedSegmentByLabelmap(selectedSegmentLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet)
260 logging.error(
"Unknown operation: {0}".format(operation))
262 LOGICAL_COPY =
'COPY' 263 LOGICAL_UNION =
'UNION' 264 LOGICAL_INTERSECT =
'INTERSECT' 265 LOGICAL_SUBTRACT =
'SUBTRACT' 266 LOGICAL_INVERT =
'INVERT' 267 LOGICAL_CLEAR =
'CLEAR' 268 LOGICAL_FILL =
'FILL'
modifierSegmentSelectorLabel
operationsRequireModifierSegment
def modifierSegmentID(self)
def createCursor(self, widget)
def setMRMLDefaults(self)
def updateMRMLFromGUI(self)
def updateGUIFromMRML(self)
def getInvertedBinaryLabelmap(self, modifierLabelmap)
def setupOptionsFrame(self)
def __init__(self, scriptedEffect)