23 def __init__(self, scriptedEffect):
24 AbstractScriptedSegmentEditorEffect.__init__(self, scriptedEffect)
25 scriptedEffect.name =
"Threshold"
26 scriptedEffect.title = _(
"Threshold")
46 self.
stencil = vtk.vtkPolyDataToImageStencil()
50 self.
reslice.AutoCropOutputOff()
52 self.
reslice.SetOutputOrigin(0, 0, 0)
53 self.
reslice.SetOutputSpacing(1, 1, 1)
54 self.
reslice.SetOutputDimensionality(3)
55 self.
reslice.GenerateStencilOutputOn()
105 def setupOptionsFrame(self):
107 self.
thresholdSliderLabel.setToolTip(_(
"Set the range of the background values that should be labeled."))
121 " Threshold above/below: sets the range from the computed value to maximum/minimum."
122 " Set as lower/upper value: only modifies one side of the threshold range."))
146 " Useful for iterating through all available methods."))
151 " Useful for iterating through all available methods."))
157 qSize = qt.QSizePolicy()
158 qSize.setHorizontalPolicy(qt.QSizePolicy.Expanding)
161 autoThresholdFrame = qt.QGridLayout()
168 autoThresholdGroupBox = ctk.ctkCollapsibleGroupBox()
169 autoThresholdGroupBox.setTitle(_(
"Automatic threshold"))
170 autoThresholdGroupBox.setLayout(autoThresholdFrame)
171 autoThresholdGroupBox.collapsed =
True
174 histogramFrame = qt.QVBoxLayout()
176 histogramBrushFrame = qt.QHBoxLayout()
177 histogramFrame.addLayout(histogramBrushFrame)
213 histogramBrushFrame.addStretch()
262 histogramItemFrame = qt.QHBoxLayout()
263 histogramFrame.addLayout(histogramItemFrame)
268 lowerGroupBox = qt.QGroupBox(_(
"Lower"))
269 lowerHistogramLayout = qt.QHBoxLayout()
270 lowerHistogramLayout.setContentsMargins(0, 3, 0, 3)
271 lowerGroupBox.setLayout(lowerHistogramLayout)
272 histogramItemFrame.addWidget(lowerGroupBox)
301 upperGroupBox = qt.QGroupBox(_(
"Upper"))
302 upperHistogramLayout = qt.QHBoxLayout()
303 upperHistogramLayout.setContentsMargins(0, 3, 0, 3)
304 upperGroupBox.setLayout(upperHistogramLayout)
305 histogramItemFrame.addWidget(upperGroupBox)
331 histogramGroupBox = ctk.ctkCollapsibleGroupBox()
332 histogramGroupBox.setTitle(_(
"Local histogram"))
333 histogramGroupBox.setLayout(histogramFrame)
334 histogramGroupBox.collapsed =
True
338 self.
useForPaintButton.setToolTip(_(
"Use specified intensity range for masking and switch to Paint effect."))
342 self.
applyButton.objectName = self.__class__.__name__ +
"Apply"
343 self.
applyButton.setToolTip(_(
"Fill selected segment in regions that are in the specified intensity range."))
379 def updateGUIFromMRML(self):
395 histogramBrushType = self.
scriptedEffect.parameter(HISTOGRAM_BRUSH_TYPE_PARAMETER_NAME)
396 self.
boxROIButton.checked = histogramBrushType == HISTOGRAM_BRUSH_TYPE_BOX
397 self.
circleROIButton.checked = histogramBrushType == HISTOGRAM_BRUSH_TYPE_CIRCLE
398 self.
drawROIButton.checked = histogramBrushType == HISTOGRAM_BRUSH_TYPE_DRAW
399 self.
lineROIButton.checked = histogramBrushType == HISTOGRAM_BRUSH_TYPE_LINE
401 histogramSetModeLower = self.
scriptedEffect.parameter(HISTOGRAM_SET_LOWER_PARAMETER_NAME)
406 histogramSetModeUpper = self.
scriptedEffect.parameter(HISTOGRAM_SET_UPPER_PARAMETER_NAME)
413 def updateMRMLFromGUI(self):
414 with slicer.util.NodeModify(self.
scriptedEffect.parameterSetNode()):
420 self.
scriptedEffect.setParameter(
"AutoThresholdMethod", autoThresholdMethod)
424 self.
scriptedEffect.setParameter(
"AutoThresholdMode", autoThresholdMode)
426 histogramParameterChanged =
False
428 histogramBrushType = HISTOGRAM_BRUSH_TYPE_CIRCLE
430 histogramBrushType = HISTOGRAM_BRUSH_TYPE_BOX
432 histogramBrushType = HISTOGRAM_BRUSH_TYPE_CIRCLE
434 histogramBrushType = HISTOGRAM_BRUSH_TYPE_DRAW
436 histogramBrushType = HISTOGRAM_BRUSH_TYPE_LINE
438 if histogramBrushType != self.
scriptedEffect.parameter(HISTOGRAM_BRUSH_TYPE_PARAMETER_NAME):
439 self.
scriptedEffect.setParameter(HISTOGRAM_BRUSH_TYPE_PARAMETER_NAME, histogramBrushType)
440 histogramParameterChanged =
True
442 histogramSetModeLower = HISTOGRAM_SET_LOWER
444 histogramSetModeLower = HISTOGRAM_SET_MINIMUM
446 histogramSetModeLower = HISTOGRAM_SET_LOWER
448 histogramSetModeLower = HISTOGRAM_SET_AVERAGE
449 if histogramSetModeLower != self.
scriptedEffect.parameter(HISTOGRAM_SET_LOWER_PARAMETER_NAME):
450 self.
scriptedEffect.setParameter(HISTOGRAM_SET_LOWER_PARAMETER_NAME, histogramSetModeLower)
451 histogramParameterChanged =
True
453 histogramSetModeUpper = HISTOGRAM_SET_UPPER
455 histogramSetModeUpper = HISTOGRAM_SET_AVERAGE
457 histogramSetModeUpper = HISTOGRAM_SET_UPPER
459 histogramSetModeUpper = HISTOGRAM_SET_MAXIMUM
460 if histogramSetModeUpper != self.
scriptedEffect.parameter(HISTOGRAM_SET_UPPER_PARAMETER_NAME):
461 self.
scriptedEffect.setParameter(HISTOGRAM_SET_UPPER_PARAMETER_NAME, histogramSetModeUpper)
462 histogramParameterChanged =
True
464 if histogramParameterChanged:
500 def autoThreshold(self, autoThresholdMethod, autoThresholdMode):
501 if autoThresholdMethod == METHOD_HUANG:
503 elif autoThresholdMethod == METHOD_INTERMODES:
505 elif autoThresholdMethod == METHOD_ISO_DATA:
507 elif autoThresholdMethod == METHOD_KITTLER_ILLINGWORTH:
509 elif autoThresholdMethod == METHOD_LI:
511 elif autoThresholdMethod == METHOD_MAXIMUM_ENTROPY:
513 elif autoThresholdMethod == METHOD_MOMENTS:
515 elif autoThresholdMethod == METHOD_OTSU:
517 elif autoThresholdMethod == METHOD_RENYI_ENTROPY:
519 elif autoThresholdMethod == METHOD_SHANBHAG:
521 elif autoThresholdMethod == METHOD_TRIANGLE:
523 elif autoThresholdMethod == METHOD_YEN:
526 logging.error(f
"Unknown AutoThresholdMethod {autoThresholdMethod}")
534 sourceVolumeMin, sourceVolumeMax = masterImageData.GetScalarRange()
536 if autoThresholdMode == MODE_SET_UPPER:
537 self.
scriptedEffect.setParameter(
"MaximumThreshold", computedThreshold)
538 elif autoThresholdMode == MODE_SET_LOWER:
539 self.
scriptedEffect.setParameter(
"MinimumThreshold", computedThreshold)
540 elif autoThresholdMode == MODE_SET_MIN_UPPER:
541 self.
scriptedEffect.setParameter(
"MinimumThreshold", sourceVolumeMin)
542 self.
scriptedEffect.setParameter(
"MaximumThreshold", computedThreshold)
543 elif autoThresholdMode == MODE_SET_LOWER_MAX:
544 self.
scriptedEffect.setParameter(
"MinimumThreshold", computedThreshold)
545 self.
scriptedEffect.setParameter(
"MaximumThreshold", sourceVolumeMax)
547 logging.error(f
"Unknown AutoThresholdMode {autoThresholdMode}")
558 originalImageToWorldMatrix = vtk.vtkMatrix4x4()
559 modifierLabelmap.GetImageToWorldMatrix(originalImageToWorldMatrix)
567 thresh = vtk.vtkImageThreshold()
568 thresh.SetInputData(masterImageData)
569 thresh.ThresholdBetween(min, max)
571 thresh.SetOutValue(0)
572 thresh.SetOutputScalarType(modifierLabelmap.GetScalarType())
574 modifierLabelmap.DeepCopy(thresh.GetOutput())
576 logging.error(
"apply: Failed to threshold source volume!")
580 self.
scriptedEffect.modifySelectedSegmentByLabelmap(modifierLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet)
601 def updatePreviewDisplayPipelines(self):
603 layoutManager = slicer.app.layoutManager()
607 sliceWidgetPipelinesToKeep = []
608 for sliceViewName
in sliceViewNames:
610 sliceWidget = layoutManager.sliceWidget(sliceViewName)
611 if not self.
scriptedEffect.segmentationDisplayableInView(sliceWidget.mrmlSliceNode()):
618 segmentationDisplayableManager = sliceWidget.sliceView().displayableManagerByClassName(
"vtkMRMLSegmentationsDisplayableManager2D")
619 existingSegmentRendererTag = segmentationDisplayableManager.GetCustomSegmentRendererTag(
621 if existingSegmentRendererTag != 0:
622 if (
not pipeline)
or (pipeline.customRendererTag != existingSegmentRendererTag):
626 sliceWidgetPipelinesToKeep.append(sliceWidget)
634 logging.error(
"updatePreviewDisplayPipelines: Failed to get renderer!")
639 pipeline.customRendererTag = segmentationDisplayableManager.AddCustomSegmentRenderer(
644 if sliceWidget
in sliceWidgetPipelinesToKeep:
647 segmentationDisplayableManager = sliceWidget.sliceView().displayableManagerByClassName(
"vtkMRMLSegmentationsDisplayableManager2D")
648 segmentationDisplayableManager.RemoveCustomSegmentRenderer(pipeline.customRendererTag)
699 def processInteractionEvents(self, callerInteractor, eventId, viewWidget):
716 if masterImageData
is None:
720 if viewWidget.className() !=
"qMRMLSliceWidget":
723 anyModifierKeyPressed = callerInteractor.GetShiftKey()
or callerInteractor.GetControlKey()
or callerInteractor.GetAltKey()
726 if eventId == vtk.vtkCommand.LeftButtonPressEvent
and not anyModifierKeyPressed:
732 xy = callerInteractor.GetEventPosition()
733 ras = self.
xyToRas(xy, viewWidget)
735 if eventId == vtk.vtkCommand.LeftButtonPressEvent
and not anyModifierKeyPressed:
740 elif eventId == vtk.vtkCommand.LeftButtonReleaseEvent:
744 elif eventId == vtk.vtkCommand.MouseMoveEvent:
787 def getSourceVolumeLayerLogic(self, sliceWidget):
788 sourceVolumeNode = self.
scriptedEffect.parameterSetNode().GetSourceVolumeNode()
789 sliceLogic = sliceWidget.sliceLogic()
791 backgroundLogic = sliceLogic.GetBackgroundLayer()
792 backgroundVolumeNode = backgroundLogic.GetVolumeNode()
793 if sourceVolumeNode == backgroundVolumeNode:
794 return backgroundLogic
796 foregroundLogic = sliceLogic.GetForegroundLayer()
797 foregroundVolumeNode = foregroundLogic.GetVolumeNode()
798 if sourceVolumeNode == foregroundVolumeNode:
799 return foregroundLogic
801 logging.warning(
"Source volume is not set as either the foreground or background")
803 foregroundOpacity = 0.0
804 if foregroundVolumeNode:
805 compositeNode = sliceLogic.GetSliceCompositeNode()
806 foregroundOpacity = compositeNode.GetForegroundOpacity()
808 if foregroundOpacity > 0.5:
809 return foregroundLogic
811 return backgroundLogic
813 def updateHistogram(self):
826 brushBounds = brushPolydata.GetBounds()
827 brushExtent = [0, -1, 0, -1, 0, -1]
829 brushExtent[2 * i] = vtk.vtkMath.Floor(brushBounds[2 * i])
830 brushExtent[2 * i + 1] = vtk.vtkMath.Ceil(brushBounds[2 * i + 1])
831 if brushExtent[0] > brushExtent[1]
or brushExtent[2] > brushExtent[3]
or brushExtent[4] > brushExtent[5]:
836 self.
reslice.SetInputConnection(layerLogic.GetReslice().GetInputConnection(0, 0))
837 self.
reslice.SetResliceTransform(layerLogic.GetReslice().GetResliceTransform())
838 self.
reslice.SetInterpolationMode(layerLogic.GetReslice().GetInterpolationMode())
839 self.
reslice.SetOutputExtent(brushExtent)
841 maxNumberOfBins = 1000
843 scalarRange = masterImageData.GetScalarRange()
844 scalarType = masterImageData.GetScalarType()
845 if scalarType == vtk.VTK_FLOAT
or scalarType == vtk.VTK_DOUBLE:
846 numberOfBins = maxNumberOfBins
848 numberOfBins = int(scalarRange[1] - scalarRange[0]) + 1
849 numberOfBins = min(numberOfBins, maxNumberOfBins)
850 binSpacing = (scalarRange[1] - scalarRange[0] + 1) / numberOfBins
852 self.
imageAccumulate.SetComponentExtent(0, numberOfBins - 1, 0, 0, 0, 0)
853 self.
imageAccumulate.SetComponentSpacing(binSpacing, binSpacing, binSpacing)
854 self.
imageAccumulate.SetComponentOrigin(scalarRange[0], scalarRange[0], scalarRange[0])
859 tableSize = self.
imageAccumulate.GetOutput().GetPointData().GetScalars().GetNumberOfTuples()
860 for i
in range(tableSize):
861 value = self.
imageAccumulate.GetOutput().GetPointData().GetScalars().GetTuple1(i)
875 lower = min(startX, endX)
876 average = (startX + endX) / 2.0
877 upper = max(startX, endX)
895 minimumThreshold = lower
896 maximumThreshold = upper
898 histogramSetModeLower = self.
scriptedEffect.parameter(HISTOGRAM_SET_LOWER_PARAMETER_NAME)
899 if histogramSetModeLower == HISTOGRAM_SET_MINIMUM:
900 minimumThreshold = scalarRange[0]
901 elif histogramSetModeLower == HISTOGRAM_SET_LOWER:
902 minimumThreshold = lower
903 elif histogramSetModeLower == HISTOGRAM_SET_AVERAGE:
904 minimumThreshold = average
906 histogramSetModeUpper = self.
scriptedEffect.parameter(HISTOGRAM_SET_UPPER_PARAMETER_NAME)
907 if histogramSetModeUpper == HISTOGRAM_SET_AVERAGE:
908 maximumThreshold = average
909 elif histogramSetModeUpper == HISTOGRAM_SET_UPPER:
910 maximumThreshold = upper
911 elif histogramSetModeUpper == HISTOGRAM_SET_MAXIMUM:
912 maximumThreshold = scalarRange[1]
914 self.
scriptedEffect.setParameter(
"MinimumThreshold", minimumThreshold)
915 self.
scriptedEffect.setParameter(
"MaximumThreshold", maximumThreshold)
917 def updateHistogramBackground(self):
921 if masterImageData
is None:
924 scalarRange = masterImageData.GetScalarRange()
929 low = max(scalarRange[0] + epsilon, low)
930 upper = min(scalarRange[1] - epsilon, upper)