2 import vtk, qt, ctk, slicer
4 from SegmentEditorEffects
import *
7 """This effect makes a segment hollow by replacing it with a shell at the segment boundary""" 10 scriptedEffect.name =
'Hollow' 11 AbstractScriptedSegmentEditorEffect.__init__(self, scriptedEffect)
14 import qSlicerSegmentationsEditorEffectsPythonQt
as effects
15 clonedEffect = effects.qSlicerSegmentEditorScriptedEffect(
None)
16 clonedEffect.setPythonSource(__file__.replace(
'\\',
'/'))
20 iconPath = os.path.join(os.path.dirname(__file__),
'Resources/Icons/Hollow.png')
21 if os.path.exists(iconPath):
22 return qt.QIcon(iconPath)
26 return """Make the selected segment hollow by replacing the segment with a uniform-thickness shell defined by the segment boundary.""" 30 operationLayout = qt.QVBoxLayout()
40 self.scriptedEffect.addLabeledOptionsWidget(
"Use current segment as:", operationLayout)
51 self.
kernelSizePixel.setToolTip(
"Thickness in pixels. Computed from the segment's spacing and the specified margin size.")
53 shellThicknessFrame = qt.QHBoxLayout()
56 self.
shellThicknessMmLabel = self.scriptedEffect.addLabeledOptionsWidget(
"Shell thickness:", shellThicknessFrame)
59 self.
applyButton.objectName = self.__class__.__name__ +
'Apply' 60 self.
applyButton.setToolTip(
"Makes the segment hollow by replacing it with a thick shell at the segment boundary.")
61 self.scriptedEffect.addOptionsWidget(self.
applyButton)
71 return slicer.util.mainWindow().cursor
74 self.scriptedEffect.setParameterDefault(
"ShellMode", INSIDE_SURFACE)
75 self.scriptedEffect.setParameterDefault(
"ShellThicknessMm", 3.0)
78 selectedSegmentLabelmapSpacing = [1.0, 1.0, 1.0]
79 selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap()
80 if selectedSegmentLabelmap:
81 selectedSegmentLabelmapSpacing = selectedSegmentLabelmap.GetSpacing()
83 if self.scriptedEffect.parameter(
"ShellMode") == MEDIAL_SURFACE:
85 shellThicknessMm = abs(self.scriptedEffect.doubleParameter(
"ShellThicknessMm"))
86 kernelSizePixel = [int(round((shellThicknessMm / selectedSegmentLabelmapSpacing[componentIndex]+2)/4)*4)
for componentIndex
in range(3)]
89 shellThicknessMm = abs(self.scriptedEffect.doubleParameter(
"ShellThicknessMm"))
90 kernelSizePixel = [int(round((shellThicknessMm / selectedSegmentLabelmapSpacing[componentIndex]+1)/2)*2-1)
for componentIndex
in range(3)]
91 return kernelSizePixel
94 shellThicknessMm = self.scriptedEffect.doubleParameter(
"ShellThicknessMm")
96 self.setWidgetMinMaxStepFromImageSpacing(self.
shellThicknessMmSpinBox, self.scriptedEffect.selectedSegmentLabelmap())
114 if self.scriptedEffect.parameter(
"ShellMode") == MEDIAL_SURFACE:
115 minimumKernelSize = 2
117 minimumKernelSize = 1
118 if kernelSizePixel[0]<=1
and kernelSizePixel[1]<=1
and kernelSizePixel[2]<=1:
122 self.
kernelSizePixel.text =
"{0}x{1}x{2} pixels".format(abs(kernelSizePixel[0]), abs(kernelSizePixel[1]), abs(kernelSizePixel[2]))
125 self.setWidgetMinMaxStepFromImageSpacing(self.
shellThicknessMmSpinBox, self.scriptedEffect.selectedSegmentLabelmap())
133 self.scriptedEffect.setParameter(
"ShellMode", INSIDE_SURFACE)
137 self.scriptedEffect.setParameter(
"ShellMode", MEDIAL_SURFACE)
141 self.scriptedEffect.setParameter(
"ShellMode", OUTSIDE_SURFACE)
145 self.scriptedEffect.saveStateForUndo()
148 modifierLabelmap = self.scriptedEffect.defaultModifierLabelmap()
149 selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap()
151 shellMode = self.scriptedEffect.parameter(
"ShellMode")
153 marginSizeMm = self.scriptedEffect.doubleParameter(
"MarginSizeMm")
155 if shellMode == MEDIAL_SURFACE:
157 kernelSizePixel = [kernelSizePixel[0]/2, kernelSizePixel[1]/2, kernelSizePixel[2]/2]
162 thresh = vtk.vtkImageThreshold()
163 thresh.SetInputData(selectedSegmentLabelmap)
164 thresh.ThresholdByLower(0)
165 thresh.SetInValue(backgroundValue)
166 thresh.SetOutValue(labelValue)
167 thresh.SetOutputScalarType(selectedSegmentLabelmap.GetScalarType())
170 subtract = vtk.vtkImageMathematics()
171 subtract.SetOperationToSubtract()
173 if shellMode == INSIDE_SURFACE
or shellMode == MEDIAL_SURFACE:
174 dilate = vtk.vtkImageDilateErode3D()
175 dilate.SetInputConnection(thresh.GetOutputPort())
176 dilate.SetDilateValue(labelValue)
177 dilate.SetErodeValue(backgroundValue)
178 dilate.SetKernelSize(kernelSizePixel[0],kernelSizePixel[1],kernelSizePixel[2])
180 subtract.SetInput1Data(dilate.GetOutput())
182 subtract.SetInput1Data(thresh.GetOutput())
184 if shellMode == OUTSIDE_SURFACE
or shellMode == MEDIAL_SURFACE:
185 erode = vtk.vtkImageDilateErode3D()
186 erode.SetInputConnection(thresh.GetOutputPort())
187 erode.SetDilateValue(backgroundValue)
188 erode.SetErodeValue(labelValue)
189 erode.SetKernelSize(kernelSizePixel[0],kernelSizePixel[1],kernelSizePixel[2])
191 subtract.SetInput2Data(erode.GetOutput())
193 subtract.SetInput2Data(thresh.GetOutput())
196 qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor)
199 modifierLabelmap.DeepCopy(subtract.GetOutput())
202 self.scriptedEffect.modifySelectedSegmentByLabelmap(modifierLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet)
204 qt.QApplication.restoreOverrideCursor()
206 INSIDE_SURFACE =
'INSIDE_SURFACE' 207 MEDIAL_SURFACE =
'MEDIAL_SURFACE' 208 OUTSIDE_SURFACE =
'OUTSIDE_SURFACE' def __init__(self, scriptedEffect)
def insideSurfaceModeToggled(self, toggled)
outsideSurfaceOptionRadioButton
def setupOptionsFrame(self)
def setMRMLDefaults(self)
def createCursor(self, widget)
def getKernelSizePixel(self)
def outsideSurfaceModeToggled(self, toggled)
def medialSurfaceModeToggled(self, toggled)
insideSurfaceOptionRadioButton
medialSurfaceOptionRadioButton
def updateMRMLFromGUI(self)
def updateGUIFromMRML(self)