24 def __init__(self, scriptedEffect):
25 AbstractScriptedSegmentEditorEffect.__init__(self, scriptedEffect)
26 scriptedEffect.name =
"Threshold"
27 scriptedEffect.title = _(
"Threshold")
47 self.
stencil = vtk.vtkPolyDataToImageStencil()
51 self.
reslice.AutoCropOutputOff()
53 self.
reslice.SetOutputOrigin(0, 0, 0)
54 self.
reslice.SetOutputSpacing(1, 1, 1)
55 self.
reslice.SetOutputDimensionality(3)
56 self.
reslice.GenerateStencilOutputOn()
115 def setupOptionsFrame(self):
117 self.
thresholdSliderLabel.setToolTip(_(
"Set the range of the background values that should be labeled."))
131 " Threshold above/below: sets the range from the computed value to maximum/minimum."
132 " Set as lower/upper value: only modifies one side of the threshold range."))
156 " Useful for iterating through all available methods."))
161 " Useful for iterating through all available methods."))
167 qSize = qt.QSizePolicy()
168 qSize.setHorizontalPolicy(qt.QSizePolicy.Expanding)
171 autoThresholdFrame = qt.QGridLayout()
178 autoThresholdGroupBox = ctk.ctkCollapsibleGroupBox()
179 autoThresholdGroupBox.setTitle(_(
"Automatic threshold"))
180 autoThresholdGroupBox.setLayout(autoThresholdFrame)
181 autoThresholdGroupBox.collapsed =
True
184 histogramFrame = qt.QVBoxLayout()
186 histogramBrushFrame = qt.QHBoxLayout()
187 histogramFrame.addLayout(histogramBrushFrame)
223 histogramBrushFrame.addStretch()
272 histogramItemFrame = qt.QHBoxLayout()
273 histogramFrame.addLayout(histogramItemFrame)
278 lowerGroupBox = qt.QGroupBox(_(
"Lower"))
279 lowerHistogramLayout = qt.QHBoxLayout()
280 lowerHistogramLayout.setContentsMargins(0, 3, 0, 3)
281 lowerGroupBox.setLayout(lowerHistogramLayout)
282 histogramItemFrame.addWidget(lowerGroupBox)
311 upperGroupBox = qt.QGroupBox(_(
"Upper"))
312 upperHistogramLayout = qt.QHBoxLayout()
313 upperHistogramLayout.setContentsMargins(0, 3, 0, 3)
314 upperGroupBox.setLayout(upperHistogramLayout)
315 histogramItemFrame.addWidget(upperGroupBox)
341 histogramGroupBox = ctk.ctkCollapsibleGroupBox()
342 histogramGroupBox.setTitle(_(
"Local histogram"))
343 histogramGroupBox.setLayout(histogramFrame)
344 histogramGroupBox.collapsed =
True
348 self.
useForPaintButton.setToolTip(_(
"Use specified intensity range for masking and switch to Paint effect."))
352 self.
applyButton.objectName = self.__class__.__name__ +
"Apply"
353 self.
applyButton.setToolTip(_(
"Fill selected segment in regions that are in the specified intensity range."))
389 def updateGUIFromMRML(self):
405 histogramBrushType = self.
scriptedEffect.parameter(HISTOGRAM_BRUSH_TYPE_PARAMETER_NAME)
406 self.
boxROIButton.checked = histogramBrushType == HISTOGRAM_BRUSH_TYPE_BOX
407 self.
circleROIButton.checked = histogramBrushType == HISTOGRAM_BRUSH_TYPE_CIRCLE
408 self.
drawROIButton.checked = histogramBrushType == HISTOGRAM_BRUSH_TYPE_DRAW
409 self.
lineROIButton.checked = histogramBrushType == HISTOGRAM_BRUSH_TYPE_LINE
411 histogramSetModeLower = self.
scriptedEffect.parameter(HISTOGRAM_SET_LOWER_PARAMETER_NAME)
416 histogramSetModeUpper = self.
scriptedEffect.parameter(HISTOGRAM_SET_UPPER_PARAMETER_NAME)
423 def updateMRMLFromGUI(self):
424 with slicer.util.NodeModify(self.
scriptedEffect.parameterSetNode()):
430 self.
scriptedEffect.setParameter(
"AutoThresholdMethod", autoThresholdMethod)
434 self.
scriptedEffect.setParameter(
"AutoThresholdMode", autoThresholdMode)
436 histogramParameterChanged =
False
438 histogramBrushType = HISTOGRAM_BRUSH_TYPE_CIRCLE
440 histogramBrushType = HISTOGRAM_BRUSH_TYPE_BOX
442 histogramBrushType = HISTOGRAM_BRUSH_TYPE_CIRCLE
444 histogramBrushType = HISTOGRAM_BRUSH_TYPE_DRAW
446 histogramBrushType = HISTOGRAM_BRUSH_TYPE_LINE
448 if histogramBrushType != self.
scriptedEffect.parameter(HISTOGRAM_BRUSH_TYPE_PARAMETER_NAME):
449 self.
scriptedEffect.setParameter(HISTOGRAM_BRUSH_TYPE_PARAMETER_NAME, histogramBrushType)
450 histogramParameterChanged =
True
452 histogramSetModeLower = HISTOGRAM_SET_LOWER
454 histogramSetModeLower = HISTOGRAM_SET_MINIMUM
456 histogramSetModeLower = HISTOGRAM_SET_LOWER
458 histogramSetModeLower = HISTOGRAM_SET_AVERAGE
459 if histogramSetModeLower != self.
scriptedEffect.parameter(HISTOGRAM_SET_LOWER_PARAMETER_NAME):
460 self.
scriptedEffect.setParameter(HISTOGRAM_SET_LOWER_PARAMETER_NAME, histogramSetModeLower)
461 histogramParameterChanged =
True
463 histogramSetModeUpper = HISTOGRAM_SET_UPPER
465 histogramSetModeUpper = HISTOGRAM_SET_AVERAGE
467 histogramSetModeUpper = HISTOGRAM_SET_UPPER
469 histogramSetModeUpper = HISTOGRAM_SET_MAXIMUM
470 if histogramSetModeUpper != self.
scriptedEffect.parameter(HISTOGRAM_SET_UPPER_PARAMETER_NAME):
471 self.
scriptedEffect.setParameter(HISTOGRAM_SET_UPPER_PARAMETER_NAME, histogramSetModeUpper)
472 histogramParameterChanged =
True
474 if histogramParameterChanged:
510 def autoThreshold(self, autoThresholdMethod, autoThresholdMode):
511 if autoThresholdMethod == METHOD_HUANG:
513 elif autoThresholdMethod == METHOD_INTERMODES:
515 elif autoThresholdMethod == METHOD_ISO_DATA:
517 elif autoThresholdMethod == METHOD_KITTLER_ILLINGWORTH:
519 elif autoThresholdMethod == METHOD_LI:
521 elif autoThresholdMethod == METHOD_MAXIMUM_ENTROPY:
523 elif autoThresholdMethod == METHOD_MOMENTS:
525 elif autoThresholdMethod == METHOD_OTSU:
527 elif autoThresholdMethod == METHOD_RENYI_ENTROPY:
529 elif autoThresholdMethod == METHOD_SHANBHAG:
531 elif autoThresholdMethod == METHOD_TRIANGLE:
533 elif autoThresholdMethod == METHOD_YEN:
536 logging.error(f
"Unknown AutoThresholdMethod {autoThresholdMethod}")
544 sourceVolumeMin, sourceVolumeMax = masterImageData.GetScalarRange()
546 if autoThresholdMode == MODE_SET_UPPER:
547 self.
scriptedEffect.setParameter(
"MaximumThreshold", computedThreshold)
548 elif autoThresholdMode == MODE_SET_LOWER:
549 self.
scriptedEffect.setParameter(
"MinimumThreshold", computedThreshold)
550 elif autoThresholdMode == MODE_SET_MIN_UPPER:
551 self.
scriptedEffect.setParameter(
"MinimumThreshold", sourceVolumeMin)
552 self.
scriptedEffect.setParameter(
"MaximumThreshold", computedThreshold)
553 elif autoThresholdMode == MODE_SET_LOWER_MAX:
554 self.
scriptedEffect.setParameter(
"MinimumThreshold", computedThreshold)
555 self.
scriptedEffect.setParameter(
"MaximumThreshold", sourceVolumeMax)
557 logging.error(f
"Unknown AutoThresholdMode {autoThresholdMode}")
568 originalImageToWorldMatrix = vtk.vtkMatrix4x4()
569 modifierLabelmap.GetImageToWorldMatrix(originalImageToWorldMatrix)
577 thresh = vtk.vtkImageThreshold()
578 thresh.SetInputData(masterImageData)
579 thresh.ThresholdBetween(min, max)
581 thresh.SetOutValue(0)
582 thresh.SetOutputScalarType(modifierLabelmap.GetScalarType())
584 modifierLabelmap.DeepCopy(thresh.GetOutput())
586 logging.error(
"apply: Failed to threshold source volume!")
590 self.
scriptedEffect.modifySelectedSegmentByLabelmap(modifierLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet)
611 def updatePreviewDisplayPipelines(self):
613 layoutManager = slicer.app.layoutManager()
617 sliceWidgetPipelinesToKeep = []
618 for sliceViewName
in sliceViewNames:
620 sliceWidget = layoutManager.sliceWidget(sliceViewName)
621 if not self.
scriptedEffect.segmentationDisplayableInView(sliceWidget.mrmlSliceNode()):
628 segmentationDisplayableManager = sliceWidget.sliceView().displayableManagerByClassName(
"vtkMRMLSegmentationsDisplayableManager2D")
629 existingSegmentRendererTag = segmentationDisplayableManager.GetCustomSegmentRendererTag(
631 if existingSegmentRendererTag != 0:
632 if (
not pipeline)
or (pipeline.customRendererTag != existingSegmentRendererTag):
636 sliceWidgetPipelinesToKeep.append(sliceWidget)
644 logging.error(
"updatePreviewDisplayPipelines: Failed to get renderer!")
649 pipeline.customRendererTag = segmentationDisplayableManager.AddCustomSegmentRenderer(
654 if sliceWidget
in sliceWidgetPipelinesToKeep:
657 segmentationDisplayableManager = sliceWidget.sliceView().displayableManagerByClassName(
"vtkMRMLSegmentationsDisplayableManager2D")
658 segmentationDisplayableManager.RemoveCustomSegmentRenderer(pipeline.customRendererTag)
709 def processInteractionEvents(self, callerInteractor, eventId, viewWidget):
726 if masterImageData
is None:
730 if viewWidget.className() !=
"qMRMLSliceWidget":
733 anyModifierKeyPressed = callerInteractor.GetShiftKey()
or callerInteractor.GetControlKey()
or callerInteractor.GetAltKey()
736 if eventId == vtk.vtkCommand.LeftButtonPressEvent
and not anyModifierKeyPressed:
742 xy = callerInteractor.GetEventPosition()
743 ras = self.
xyToRas(xy, viewWidget)
745 if eventId == vtk.vtkCommand.LeftButtonPressEvent
and not anyModifierKeyPressed:
750 elif eventId == vtk.vtkCommand.LeftButtonReleaseEvent:
754 elif eventId == vtk.vtkCommand.MouseMoveEvent:
797 def getSourceVolumeLayerLogic(self, sliceWidget):
798 sourceVolumeNode = self.
scriptedEffect.parameterSetNode().GetSourceVolumeNode()
799 sliceLogic = sliceWidget.sliceLogic()
801 backgroundLogic = sliceLogic.GetBackgroundLayer()
802 backgroundVolumeNode = backgroundLogic.GetVolumeNode()
803 if sourceVolumeNode == backgroundVolumeNode:
804 return backgroundLogic
806 foregroundLogic = sliceLogic.GetForegroundLayer()
807 foregroundVolumeNode = foregroundLogic.GetVolumeNode()
808 if sourceVolumeNode == foregroundVolumeNode:
809 return foregroundLogic
811 logging.warning(
"Source volume is not set as either the foreground or background")
813 foregroundOpacity = 0.0
814 if foregroundVolumeNode:
815 compositeNode = sliceLogic.GetSliceCompositeNode()
816 foregroundOpacity = compositeNode.GetForegroundOpacity()
818 if foregroundOpacity > 0.5:
819 return foregroundLogic
821 return backgroundLogic
823 def updateHistogram(self):
836 brushBounds = brushPolydata.GetBounds()
837 brushExtent = [0, -1, 0, -1, 0, -1]
839 brushExtent[2 * i] = vtk.vtkMath.Floor(brushBounds[2 * i])
840 brushExtent[2 * i + 1] = vtk.vtkMath.Ceil(brushBounds[2 * i + 1])
841 if brushExtent[0] > brushExtent[1]
or brushExtent[2] > brushExtent[3]
or brushExtent[4] > brushExtent[5]:
846 self.
reslice.SetInputConnection(layerLogic.GetReslice().GetInputConnection(0, 0))
847 self.
reslice.SetResliceTransform(layerLogic.GetReslice().GetResliceTransform())
848 self.
reslice.SetInterpolationMode(layerLogic.GetReslice().GetInterpolationMode())
849 self.
reslice.SetOutputExtent(brushExtent)
851 maxNumberOfBins = 1000
853 scalarRange = masterImageData.GetScalarRange()
854 scalarType = masterImageData.GetScalarType()
855 if scalarType == vtk.VTK_FLOAT
or scalarType == vtk.VTK_DOUBLE:
856 numberOfBins = maxNumberOfBins
858 numberOfBins = int(scalarRange[1] - scalarRange[0]) + 1
859 numberOfBins = min(numberOfBins, maxNumberOfBins)
860 binSpacing = (scalarRange[1] - scalarRange[0] + 1) / numberOfBins
862 self.
imageAccumulate.SetComponentExtent(0, numberOfBins - 1, 0, 0, 0, 0)
863 self.
imageAccumulate.SetComponentSpacing(binSpacing, binSpacing, binSpacing)
864 self.
imageAccumulate.SetComponentOrigin(scalarRange[0], scalarRange[0], scalarRange[0])
869 tableSize = self.
imageAccumulate.GetOutput().GetPointData().GetScalars().GetNumberOfTuples()
870 for i
in range(tableSize):
871 value = self.
imageAccumulate.GetOutput().GetPointData().GetScalars().GetTuple1(i)
885 lower = min(startX, endX)
886 average = (startX + endX) / 2.0
887 upper = max(startX, endX)
905 minimumThreshold = lower
906 maximumThreshold = upper
908 histogramSetModeLower = self.
scriptedEffect.parameter(HISTOGRAM_SET_LOWER_PARAMETER_NAME)
909 if histogramSetModeLower == HISTOGRAM_SET_MINIMUM:
910 minimumThreshold = scalarRange[0]
911 elif histogramSetModeLower == HISTOGRAM_SET_LOWER:
912 minimumThreshold = lower
913 elif histogramSetModeLower == HISTOGRAM_SET_AVERAGE:
914 minimumThreshold = average
916 histogramSetModeUpper = self.
scriptedEffect.parameter(HISTOGRAM_SET_UPPER_PARAMETER_NAME)
917 if histogramSetModeUpper == HISTOGRAM_SET_AVERAGE:
918 maximumThreshold = average
919 elif histogramSetModeUpper == HISTOGRAM_SET_UPPER:
920 maximumThreshold = upper
921 elif histogramSetModeUpper == HISTOGRAM_SET_MAXIMUM:
922 maximumThreshold = scalarRange[1]
924 self.
scriptedEffect.setParameter(
"MinimumThreshold", minimumThreshold)
925 self.
scriptedEffect.setParameter(
"MaximumThreshold", maximumThreshold)
927 def updateHistogramBackground(self):
931 if masterImageData
is None:
934 scalarRange = masterImageData.GetScalarRange()
939 low = max(scalarRange[0] + epsilon, low)
940 upper = min(scalarRange[1] - epsilon, upper)