diff --git a/Modules/Segmentation/Interactions/mitkBinaryThresholdTool.cpp b/Modules/Segmentation/Interactions/mitkBinaryThresholdBaseTool.cpp similarity index 70% copy from Modules/Segmentation/Interactions/mitkBinaryThresholdTool.cpp copy to Modules/Segmentation/Interactions/mitkBinaryThresholdBaseTool.cpp index 0dc58b626e..f48232e055 100644 --- a/Modules/Segmentation/Interactions/mitkBinaryThresholdTool.cpp +++ b/Modules/Segmentation/Interactions/mitkBinaryThresholdBaseTool.cpp @@ -1,480 +1,466 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ -#include "mitkBinaryThresholdTool.h" +#include "mitkBinaryThresholdBaseTool.h" -#include "mitkBoundingObjectToSegmentationFilter.h" #include "mitkToolManager.h" #include "mitkColorProperty.h" -#include "mitkDataStorage.h" #include "mitkLevelWindowProperty.h" #include "mitkProperties.h" + +#include "mitkDataStorage.h" #include "mitkRenderingManager.h" -#include "mitkVtkResliceInterpolationProperty.h" -#include +#include #include "mitkImageAccessByItk.h" #include "mitkImageCast.h" #include "mitkImageStatisticsHolder.h" #include "mitkImageTimeSelector.h" #include "mitkLabelSetImage.h" #include "mitkMaskAndCutRoiImageFilter.h" #include "mitkPadImageFilter.h" #include #include -// us -#include "usGetModuleContext.h" -#include "usModule.h" -#include "usModuleResource.h" - -namespace mitk -{ - MITK_TOOL_MACRO(MITKSEGMENTATION_EXPORT, BinaryThresholdTool, "Thresholding tool"); -} - -mitk::BinaryThresholdTool::BinaryThresholdTool() +mitk::BinaryThresholdBaseTool::BinaryThresholdBaseTool() : m_SensibleMinimumThresholdValue(-100), m_SensibleMaximumThresholdValue(+100), - m_CurrentThresholdValue(0.0), - m_IsFloatImage(false) + m_CurrentLowerThresholdValue(1), + m_CurrentUpperThresholdValue(1) { m_ThresholdFeedbackNode = DataNode::New(); m_ThresholdFeedbackNode->SetProperty("color", ColorProperty::New(0.0, 1.0, 0.0)); m_ThresholdFeedbackNode->SetProperty("name", StringProperty::New("Thresholding feedback")); m_ThresholdFeedbackNode->SetProperty("opacity", FloatProperty::New(0.3)); m_ThresholdFeedbackNode->SetProperty("binary", BoolProperty::New(true)); m_ThresholdFeedbackNode->SetProperty("helper object", BoolProperty::New(true)); } -mitk::BinaryThresholdTool::~BinaryThresholdTool() -{ -} - -const char **mitk::BinaryThresholdTool::GetXPM() const +mitk::BinaryThresholdBaseTool::~BinaryThresholdBaseTool() { - return nullptr; } -us::ModuleResource mitk::BinaryThresholdTool::GetIconResource() const -{ - us::Module *module = us::GetModuleContext()->GetModule(); - us::ModuleResource resource = module->GetResource("Threshold_48x48.png"); - return resource; -} - -const char *mitk::BinaryThresholdTool::GetName() const -{ - return "Threshold"; -} - -void mitk::BinaryThresholdTool::Activated() +void mitk::BinaryThresholdBaseTool::Activated() { Superclass::Activated(); m_ToolManager->RoiDataChanged += - mitk::MessageDelegate(this, &mitk::BinaryThresholdTool::OnRoiDataChanged); + mitk::MessageDelegate(this, &mitk::BinaryThresholdBaseTool::OnRoiDataChanged); m_ToolManager->SelectedTimePointChanged += - mitk::MessageDelegate(this, &mitk::BinaryThresholdTool::OnTimePointChanged); + mitk::MessageDelegate(this, &mitk::BinaryThresholdBaseTool::OnTimePointChanged); m_OriginalImageNode = m_ToolManager->GetReferenceData(0); m_NodeForThresholding = m_OriginalImageNode; if (m_NodeForThresholding.IsNotNull()) { SetupPreviewNode(); } else { m_ToolManager->ActivateTool(-1); } } -void mitk::BinaryThresholdTool::Deactivated() +void mitk::BinaryThresholdBaseTool::Deactivated() { m_ToolManager->RoiDataChanged -= - mitk::MessageDelegate(this, &mitk::BinaryThresholdTool::OnRoiDataChanged); + mitk::MessageDelegate(this, &mitk::BinaryThresholdBaseTool::OnRoiDataChanged); m_ToolManager->SelectedTimePointChanged -= - mitk::MessageDelegate(this, &mitk::BinaryThresholdTool::OnTimePointChanged); + mitk::MessageDelegate(this, &mitk::BinaryThresholdBaseTool::OnTimePointChanged); m_NodeForThresholding = nullptr; m_OriginalImageNode = nullptr; try { if (DataStorage *storage = m_ToolManager->GetDataStorage()) { storage->Remove(m_ThresholdFeedbackNode); RenderingManager::GetInstance()->RequestUpdateAll(); } } catch (...) { // don't care } m_ThresholdFeedbackNode->SetData(nullptr); Superclass::Deactivated(); } -void mitk::BinaryThresholdTool::SetThresholdValue(double value) +void mitk::BinaryThresholdBaseTool::SetThresholdValues(double lower, double upper) { + /* If value is not in the min/max range, do nothing. In that case, this + method will be called again with a proper value right after. The only + known case where this happens is with an [0.0, 1.0[ image, where value + could be an epsilon greater than the max. */ + if (lower < m_SensibleMinimumThresholdValue + || lower > m_SensibleMaximumThresholdValue + || upper < m_SensibleMinimumThresholdValue + || upper > m_SensibleMaximumThresholdValue) + { + return; + } + + m_CurrentLowerThresholdValue = lower; + m_CurrentUpperThresholdValue = upper; + if (m_ThresholdFeedbackNode.IsNotNull()) { - /* If value is not in the min/max range, do nothing. In that case, this - method will be called again with a proper value right after. The only - known case where this happens is with an [0.0, 1.0[ image, where value - could be an epsilon greater than the max. */ - if (value < m_SensibleMinimumThresholdValue - || value > m_SensibleMaximumThresholdValue) - { - return; - } - m_CurrentThresholdValue = value; - // Bug 19250: The range of 0.01 is rather random. It was 0.001 before and probably due to rounding error propagation - // in VTK code - // it leads to strange banding effects on floating point images with a huge range (like -40000 - 40000). 0.01 lowers - // this effect - // enough to work with our images. Might not work on images with really huge ranges, though. Anyways, still seems to - // be low enough - // to work for floating point images with a range between 0 and 1. A better solution might be to dynamically - // calculate the value - // based on the value range of the current image (as big as possible, as small as necessary). - // m_ThresholdFeedbackNode->SetProperty( "levelwindow", LevelWindowProperty::New( - // LevelWindow(m_CurrentThresholdValue, 0.01) ) ); UpdatePreview(); } } -void mitk::BinaryThresholdTool::AcceptCurrentThresholdValue() +void mitk::BinaryThresholdBaseTool::AcceptCurrentThresholdValue() { CreateNewSegmentationFromThreshold(); RenderingManager::GetInstance()->RequestUpdateAll(); m_ToolManager->ActivateTool(-1); } -void mitk::BinaryThresholdTool::CancelThresholding() +void mitk::BinaryThresholdBaseTool::CancelThresholding() { m_ToolManager->ActivateTool(-1); } -void mitk::BinaryThresholdTool::SetupPreviewNode() +void mitk::BinaryThresholdBaseTool::SetupPreviewNode() { itk::RGBPixel pixel; pixel[0] = 0.0f; pixel[1] = 1.0f; pixel[2] = 0.0f; if (m_NodeForThresholding.IsNotNull()) { Image::Pointer image = dynamic_cast(m_NodeForThresholding->GetData()); Image::Pointer originalImage = dynamic_cast(m_OriginalImageNode->GetData()); if (image.IsNotNull()) { mitk::LabelSetImage::Pointer workingImage = dynamic_cast(m_ToolManager->GetWorkingData(0)->GetData()); if (workingImage.IsNotNull()) { m_ThresholdFeedbackNode->SetData(workingImage->Clone()); m_IsOldBinary = false; // Let's paint the feedback node green... mitk::LabelSetImage::Pointer previewImage = dynamic_cast(m_ThresholdFeedbackNode->GetData()); if (previewImage.IsNull()) { MITK_ERROR << "Cannot create helper objects."; return; } previewImage->GetActiveLabel()->SetColor(pixel); previewImage->GetActiveLabelSet()->UpdateLookupTable(previewImage->GetActiveLabel()->GetValue()); } else { mitk::Image::Pointer workingImageBin = dynamic_cast(m_ToolManager->GetWorkingData(0)->GetData()); if (workingImageBin) { m_ThresholdFeedbackNode->SetData(workingImageBin->Clone()); m_IsOldBinary = true; } else m_ThresholdFeedbackNode->SetData(mitk::Image::New()); } m_ThresholdFeedbackNode->SetColor(pixel); m_ThresholdFeedbackNode->SetOpacity(0.5); int layer(50); m_NodeForThresholding->GetIntProperty("layer", layer); m_ThresholdFeedbackNode->SetIntProperty("layer", layer + 1); if (DataStorage *ds = m_ToolManager->GetDataStorage()) { if (!ds->Exists(m_ThresholdFeedbackNode)) ds->Add(m_ThresholdFeedbackNode, m_OriginalImageNode); } if (image.GetPointer() == originalImage.GetPointer()) { m_SensibleMinimumThresholdValue = std::numeric_limits::max(); m_SensibleMaximumThresholdValue = std::numeric_limits::lowest(); Image::StatisticsHolderPointer statistics = originalImage->GetStatistics(); for (unsigned int ts = 0; ts < originalImage->GetTimeSteps(); ++ts) { m_SensibleMinimumThresholdValue = std::min(m_SensibleMinimumThresholdValue, static_cast(statistics->GetScalarValueMin())); m_SensibleMaximumThresholdValue = std::max(m_SensibleMaximumThresholdValue, static_cast(statistics->GetScalarValueMax())); } } + if (m_LockedUpperThreshold) + { + m_CurrentLowerThresholdValue = (m_SensibleMaximumThresholdValue + m_SensibleMinimumThresholdValue) / 2.0; + m_CurrentUpperThresholdValue = m_SensibleMaximumThresholdValue; + } + else + { + double range = m_SensibleMaximumThresholdValue - m_SensibleMinimumThresholdValue; + m_CurrentLowerThresholdValue = m_SensibleMinimumThresholdValue + range / 3.0; + m_CurrentUpperThresholdValue = m_SensibleMinimumThresholdValue + 2 * range / 3.0; + } + + bool isFloatImage = false; if ((originalImage->GetPixelType().GetPixelType() == itk::ImageIOBase::SCALAR) && (originalImage->GetPixelType().GetComponentType() == itk::ImageIOBase::FLOAT || originalImage->GetPixelType().GetComponentType() == itk::ImageIOBase::DOUBLE)) - m_IsFloatImage = true; - else - m_IsFloatImage = false; - - m_CurrentThresholdValue = (m_SensibleMaximumThresholdValue + m_SensibleMinimumThresholdValue) / 2.0; + { + isFloatImage = true; + } - IntervalBordersChanged.Send(m_SensibleMinimumThresholdValue, m_SensibleMaximumThresholdValue, m_IsFloatImage); - ThresholdingValueChanged.Send(m_CurrentThresholdValue); + IntervalBordersChanged.Send(m_SensibleMinimumThresholdValue, m_SensibleMaximumThresholdValue, isFloatImage); + ThresholdingValuesChanged.Send(m_CurrentLowerThresholdValue, m_CurrentUpperThresholdValue); } } } template static void ITKSetVolume(const itk::Image *originalImage, mitk::Image *segmentation, unsigned int timeStep) { auto constPixelContainer = originalImage->GetPixelContainer(); //have to make a const cast because itk::PixelContainer does not provide a const correct access :( auto pixelContainer = const_cast::PixelContainer*>(constPixelContainer); + segmentation->SetVolume((void *)pixelContainer->GetBufferPointer(), timeStep); } -void mitk::BinaryThresholdTool::TransferImageAtTimeStep(const Image* sourceImage, Image* destinationImage, const TimeStepType timeStep) +void mitk::BinaryThresholdBaseTool::TransferImageAtTimeStep(const Image* sourceImage, Image* destinationImage, const TimeStepType timeStep) { try { Image::ConstPointer image3D = this->Get3DImage(sourceImage, timeStep); if (image3D->GetDimension() == 2) { AccessFixedDimensionByItk_2( image3D, ITKSetVolume, 2, destinationImage, timeStep); } else { AccessFixedDimensionByItk_2( image3D, ITKSetVolume, 3, destinationImage, timeStep); } } catch (...) { Tool::ErrorMessage("Error accessing single time steps of the original image. Cannot create segmentation."); } } -void mitk::BinaryThresholdTool::CreateNewSegmentationFromThreshold() +void mitk::BinaryThresholdBaseTool::CreateNewSegmentationFromThreshold() { if (m_NodeForThresholding.IsNotNull() && m_ThresholdFeedbackNode.IsNotNull()) { Image::Pointer feedBackImage = dynamic_cast(m_ThresholdFeedbackNode->GetData()); if (feedBackImage.IsNotNull()) { + // create a new image of the same dimensions and smallest possible pixel type DataNode::Pointer emptySegmentationNode = GetTargetSegmentationNode(); if (emptySegmentationNode) { const auto timePoint = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint(); auto emptySegmentation = dynamic_cast(emptySegmentationNode->GetData()); // actually perform a thresholding // REMARK: the following code in this scope assumes that feedBackImage and emptySegmentationImage // are clones of the working image (segmentation provided to the tool). Therefor the have the same // time geometry. if (feedBackImage->GetTimeSteps() != emptySegmentation->GetTimeSteps()) { mitkThrow() << "Cannot performe threshold. Internal tool state is invalid." << " Preview segmentation and segmentation result image have different time geometries."; } if (m_CreateAllTimeSteps) { for (unsigned int timeStep = 0; timeStep < feedBackImage->GetTimeSteps(); ++timeStep) { TransferImageAtTimeStep(feedBackImage, emptySegmentation, timeStep); } } else { const auto timeStep = emptySegmentation->GetTimeGeometry()->TimePointToTimeStep(timePoint); TransferImageAtTimeStep(feedBackImage, emptySegmentation, timeStep); } + // since we are maybe working on a smaller image, pad it to the size of the original image if (m_OriginalImageNode.GetPointer() != m_NodeForThresholding.GetPointer()) { mitk::PadImageFilter::Pointer padFilter = mitk::PadImageFilter::New(); padFilter->SetInput(0, emptySegmentation); - padFilter->SetInput(1, dynamic_cast(m_OriginalImageNode->GetData())); + padFilter->SetInput(1, dynamic_cast(m_OriginalImageNode->GetData())); padFilter->SetBinaryFilter(true); padFilter->SetUpperThreshold(1); padFilter->SetLowerThreshold(1); padFilter->Update(); emptySegmentationNode->SetData(padFilter->GetOutput()); } m_ToolManager->SetWorkingData(emptySegmentationNode); m_ToolManager->GetWorkingData(0)->Modified(); } } } } -void mitk::BinaryThresholdTool::OnRoiDataChanged() +void mitk::BinaryThresholdBaseTool::OnRoiDataChanged() { mitk::DataNode::Pointer node = m_ToolManager->GetRoiData(0); if (node.IsNotNull()) { mitk::MaskAndCutRoiImageFilter::Pointer roiFilter = mitk::MaskAndCutRoiImageFilter::New(); mitk::Image::Pointer image = dynamic_cast(m_NodeForThresholding->GetData()); if (image.IsNull()) return; roiFilter->SetInput(image); roiFilter->SetRegionOfInterest(node->GetData()); roiFilter->Update(); mitk::DataNode::Pointer tmpNode = mitk::DataNode::New(); tmpNode->SetData(roiFilter->GetOutput()); - m_SensibleMaximumThresholdValue = static_cast(roiFilter->GetMaxValue()); m_SensibleMinimumThresholdValue = static_cast(roiFilter->GetMinValue()); + m_SensibleMaximumThresholdValue = static_cast(roiFilter->GetMaxValue()); m_NodeForThresholding = tmpNode; } else - { m_NodeForThresholding = m_OriginalImageNode; - } this->SetupPreviewNode(); this->UpdatePreview(); } -void mitk::BinaryThresholdTool::OnTimePointChanged() +void mitk::BinaryThresholdBaseTool::OnTimePointChanged() { if (m_ThresholdFeedbackNode.IsNotNull() && m_NodeForThresholding.IsNotNull()) { if (m_ThresholdFeedbackNode->GetData()->GetTimeSteps() == 1) { this->UpdatePreview(); } } } template -void mitk::BinaryThresholdTool::ITKThresholding(const itk::Image *originalImage, - Image *segmentation, - double thresholdValue, - unsigned int timeStep) const +static void ITKThresholding(const itk::Image *originalImage, + mitk::Image *segmentation, + double lower, + double upper, + unsigned int timeStep) { typedef itk::Image ImageType; typedef itk::Image SegmentationType; typedef itk::BinaryThresholdImageFilter ThresholdFilterType; typename ThresholdFilterType::Pointer filter = ThresholdFilterType::New(); filter->SetInput(originalImage); - filter->SetLowerThreshold(thresholdValue); - filter->SetUpperThreshold(m_SensibleMaximumThresholdValue); + filter->SetLowerThreshold(lower); + filter->SetUpperThreshold(upper); filter->SetInsideValue(1); filter->SetOutsideValue(0); filter->Update(); segmentation->SetVolume((void *)(filter->GetOutput()->GetPixelContainer()->GetBufferPointer()), timeStep); } template -void mitk::BinaryThresholdTool::ITKThresholdingOldBinary(const itk::Image *originalImage, - Image *segmentation, - double thresholdValue, - unsigned int timeStep) const +static void ITKThresholdingOldBinary(const itk::Image *originalImage, + mitk::Image *segmentation, + double lower, + double upper, + unsigned int timeStep) { typedef itk::Image ImageType; typedef itk::Image SegmentationType; typedef itk::BinaryThresholdImageFilter ThresholdFilterType; typename ThresholdFilterType::Pointer filter = ThresholdFilterType::New(); filter->SetInput(originalImage); - filter->SetLowerThreshold(thresholdValue); - filter->SetUpperThreshold(m_SensibleMaximumThresholdValue); + filter->SetLowerThreshold(lower); + filter->SetUpperThreshold(upper); filter->SetInsideValue(1); filter->SetOutsideValue(0); filter->Update(); segmentation->SetVolume((void *)(filter->GetOutput()->GetPixelContainer()->GetBufferPointer()), timeStep); } -void mitk::BinaryThresholdTool::UpdatePreview() +void mitk::BinaryThresholdBaseTool::UpdatePreview() { mitk::Image::Pointer thresholdImage = dynamic_cast(m_NodeForThresholding->GetData()); mitk::Image::Pointer previewImage = dynamic_cast(m_ThresholdFeedbackNode->GetData()); if (thresholdImage && previewImage) { if (previewImage->GetTimeSteps() > 1) { for (unsigned int timeStep = 0; timeStep < thresholdImage->GetTimeSteps(); ++timeStep) { auto feedBackImage3D = this->Get3DImage(thresholdImage, timeStep); if (m_IsOldBinary) { - AccessByItk_n(feedBackImage3D, ITKThresholdingOldBinary, (previewImage, m_CurrentThresholdValue, timeStep)); + AccessByItk_n(feedBackImage3D, + ITKThresholdingOldBinary, + (previewImage, m_CurrentLowerThresholdValue, m_CurrentUpperThresholdValue, timeStep)); } else { - AccessByItk_n(feedBackImage3D, ITKThresholding, (previewImage, m_CurrentThresholdValue, timeStep)); + AccessByItk_n(feedBackImage3D, + ITKThresholding, + (previewImage, m_CurrentLowerThresholdValue, m_CurrentUpperThresholdValue, timeStep)); } } } else { const auto timePoint = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint(); auto feedBackImage3D = this->Get3DImageByTimePoint(thresholdImage, timePoint); - auto segTimeStep = previewImage->GetTimeGeometry()->TimePointToTimeStep(timePoint); + auto timeStep = previewImage->GetTimeGeometry()->TimePointToTimeStep(timePoint); if (m_IsOldBinary) { - AccessByItk_n(feedBackImage3D, ITKThresholdingOldBinary, (previewImage, m_CurrentThresholdValue, segTimeStep)); + AccessByItk_n(feedBackImage3D, + ITKThresholdingOldBinary, + (previewImage, m_CurrentLowerThresholdValue, m_CurrentUpperThresholdValue, timeStep)); } else { - AccessByItk_n(feedBackImage3D, ITKThresholding, (previewImage, m_CurrentThresholdValue, segTimeStep)); + AccessByItk_n(feedBackImage3D, + ITKThresholding, + (previewImage, m_CurrentLowerThresholdValue, m_CurrentUpperThresholdValue, timeStep)); } } - - RenderingManager::GetInstance()->RequestUpdateAll(); } } diff --git a/Modules/Segmentation/Interactions/mitkBinaryThresholdULTool.h b/Modules/Segmentation/Interactions/mitkBinaryThresholdBaseTool.h similarity index 52% copy from Modules/Segmentation/Interactions/mitkBinaryThresholdULTool.h copy to Modules/Segmentation/Interactions/mitkBinaryThresholdBaseTool.h index a29b5f3f7d..da610d25f9 100644 --- a/Modules/Segmentation/Interactions/mitkBinaryThresholdULTool.h +++ b/Modules/Segmentation/Interactions/mitkBinaryThresholdBaseTool.h @@ -1,91 +1,88 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ -#ifndef mitkBinaryThresholdULTool_h_Included -#define mitkBinaryThresholdULTool_h_Included +#ifndef mitkBinaryThresholdBaseTool_h_Included +#define mitkBinaryThresholdBaseTool_h_Included #include "mitkAutoSegmentationTool.h" #include "mitkCommon.h" #include "mitkDataNode.h" #include #include #include -namespace us -{ - class ModuleResource; -} - namespace mitk { /** - \brief Calculates the segmented volumes for binary images. + \brief Base class for binary threshold tools. \ingroup ToolManagerEtAl \sa mitk::Tool \sa QmitkInteractiveSegmentation - - Last contributor: $Author$ */ - class MITKSEGMENTATION_EXPORT BinaryThresholdULTool : public AutoSegmentationTool + class MITKSEGMENTATION_EXPORT BinaryThresholdBaseTool : public AutoSegmentationTool { public: Message3 IntervalBordersChanged; Message2 ThresholdingValuesChanged; - mitkClassMacro(BinaryThresholdULTool, AutoSegmentationTool); - itkFactorylessNewMacro(Self); - itkCloneMacro(Self); - - const char **GetXPM() const override; - us::ModuleResource GetIconResource() const override; - const char *GetName() const override; + mitkClassMacro(BinaryThresholdBaseTool, AutoSegmentationTool); void Activated() override; void Deactivated() override; virtual void SetThresholdValues(double lower, double upper); + virtual void AcceptCurrentThresholdValue(); virtual void CancelThresholding(); protected: - BinaryThresholdULTool(); // purposely hidden - ~BinaryThresholdULTool() override; + BinaryThresholdBaseTool(); // purposely hidden + ~BinaryThresholdBaseTool() override; + itkSetMacro(LockedUpperThreshold, bool); + itkGetMacro(LockedUpperThreshold, bool); + itkBooleanMacro(LockedUpperThreshold); + + itkGetMacro(SensibleMinimumThresholdValue, ScalarType); + itkGetMacro(SensibleMaximumThresholdValue, ScalarType); + + private: void SetupPreviewNode(); - void CreateNewSegmentationFromThreshold(DataNode *node); + void TransferImageAtTimeStep(const Image* sourceImage, Image* destinationImage, const TimeStepType timeStep); + + void CreateNewSegmentationFromThreshold(); void OnRoiDataChanged(); + void OnTimePointChanged(); + void UpdatePreview(); DataNode::Pointer m_ThresholdFeedbackNode; DataNode::Pointer m_OriginalImageNode; DataNode::Pointer m_NodeForThresholding; - mitk::ScalarType m_SensibleMinimumThresholdValue; - mitk::ScalarType m_SensibleMaximumThresholdValue; - mitk::ScalarType m_CurrentLowerThresholdValue; - mitk::ScalarType m_CurrentUpperThresholdValue; + ScalarType m_SensibleMinimumThresholdValue; + ScalarType m_SensibleMaximumThresholdValue; + ScalarType m_CurrentLowerThresholdValue; + ScalarType m_CurrentUpperThresholdValue; bool m_IsOldBinary = false; - - typedef itk::Image ImageType; - typedef itk::Image SegmentationType; // this is sure for new segmentations - typedef itk::BinaryThresholdImageFilter ThresholdFilterType; - ThresholdFilterType::Pointer m_ThresholdFilter; + bool m_CreateAllTimeSteps = false; + bool m_LockedUpperThreshold = false; }; } // namespace #endif diff --git a/Modules/Segmentation/Interactions/mitkBinaryThresholdTool.cpp b/Modules/Segmentation/Interactions/mitkBinaryThresholdTool.cpp index 0dc58b626e..332383f5e6 100644 --- a/Modules/Segmentation/Interactions/mitkBinaryThresholdTool.cpp +++ b/Modules/Segmentation/Interactions/mitkBinaryThresholdTool.cpp @@ -1,480 +1,55 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkBinaryThresholdTool.h" -#include "mitkBoundingObjectToSegmentationFilter.h" -#include "mitkToolManager.h" - -#include "mitkColorProperty.h" -#include "mitkDataStorage.h" -#include "mitkLevelWindowProperty.h" -#include "mitkProperties.h" -#include "mitkRenderingManager.h" -#include "mitkVtkResliceInterpolationProperty.h" -#include - -#include "mitkImageAccessByItk.h" -#include "mitkImageCast.h" -#include "mitkImageStatisticsHolder.h" -#include "mitkImageTimeSelector.h" -#include "mitkLabelSetImage.h" -#include "mitkMaskAndCutRoiImageFilter.h" -#include "mitkPadImageFilter.h" -#include -#include - // us #include "usGetModuleContext.h" #include "usModule.h" #include "usModuleResource.h" namespace mitk { MITK_TOOL_MACRO(MITKSEGMENTATION_EXPORT, BinaryThresholdTool, "Thresholding tool"); } -mitk::BinaryThresholdTool::BinaryThresholdTool() - : m_SensibleMinimumThresholdValue(-100), - m_SensibleMaximumThresholdValue(+100), - m_CurrentThresholdValue(0.0), - m_IsFloatImage(false) +mitk::BinaryThresholdTool::BinaryThresholdTool() : BinaryThresholdBaseTool() { - m_ThresholdFeedbackNode = DataNode::New(); - m_ThresholdFeedbackNode->SetProperty("color", ColorProperty::New(0.0, 1.0, 0.0)); - m_ThresholdFeedbackNode->SetProperty("name", StringProperty::New("Thresholding feedback")); - m_ThresholdFeedbackNode->SetProperty("opacity", FloatProperty::New(0.3)); - m_ThresholdFeedbackNode->SetProperty("binary", BoolProperty::New(true)); - m_ThresholdFeedbackNode->SetProperty("helper object", BoolProperty::New(true)); + LockedUpperThresholdOn(); } mitk::BinaryThresholdTool::~BinaryThresholdTool() { } const char **mitk::BinaryThresholdTool::GetXPM() const { return nullptr; } us::ModuleResource mitk::BinaryThresholdTool::GetIconResource() const { us::Module *module = us::GetModuleContext()->GetModule(); us::ModuleResource resource = module->GetResource("Threshold_48x48.png"); return resource; } const char *mitk::BinaryThresholdTool::GetName() const { return "Threshold"; } -void mitk::BinaryThresholdTool::Activated() -{ - Superclass::Activated(); - - m_ToolManager->RoiDataChanged += - mitk::MessageDelegate(this, &mitk::BinaryThresholdTool::OnRoiDataChanged); - - m_ToolManager->SelectedTimePointChanged += - mitk::MessageDelegate(this, &mitk::BinaryThresholdTool::OnTimePointChanged); - - m_OriginalImageNode = m_ToolManager->GetReferenceData(0); - m_NodeForThresholding = m_OriginalImageNode; - - if (m_NodeForThresholding.IsNotNull()) - { - SetupPreviewNode(); - } - else - { - m_ToolManager->ActivateTool(-1); - } -} - -void mitk::BinaryThresholdTool::Deactivated() -{ - m_ToolManager->RoiDataChanged -= - mitk::MessageDelegate(this, &mitk::BinaryThresholdTool::OnRoiDataChanged); - - m_ToolManager->SelectedTimePointChanged -= - mitk::MessageDelegate(this, &mitk::BinaryThresholdTool::OnTimePointChanged); - - m_NodeForThresholding = nullptr; - m_OriginalImageNode = nullptr; - try - { - if (DataStorage *storage = m_ToolManager->GetDataStorage()) - { - storage->Remove(m_ThresholdFeedbackNode); - RenderingManager::GetInstance()->RequestUpdateAll(); - } - } - catch (...) - { - // don't care - } - m_ThresholdFeedbackNode->SetData(nullptr); - - Superclass::Deactivated(); -} void mitk::BinaryThresholdTool::SetThresholdValue(double value) { - if (m_ThresholdFeedbackNode.IsNotNull()) - { - /* If value is not in the min/max range, do nothing. In that case, this - method will be called again with a proper value right after. The only - known case where this happens is with an [0.0, 1.0[ image, where value - could be an epsilon greater than the max. */ - if (value < m_SensibleMinimumThresholdValue - || value > m_SensibleMaximumThresholdValue) - { - return; - } - - m_CurrentThresholdValue = value; - // Bug 19250: The range of 0.01 is rather random. It was 0.001 before and probably due to rounding error propagation - // in VTK code - // it leads to strange banding effects on floating point images with a huge range (like -40000 - 40000). 0.01 lowers - // this effect - // enough to work with our images. Might not work on images with really huge ranges, though. Anyways, still seems to - // be low enough - // to work for floating point images with a range between 0 and 1. A better solution might be to dynamically - // calculate the value - // based on the value range of the current image (as big as possible, as small as necessary). - // m_ThresholdFeedbackNode->SetProperty( "levelwindow", LevelWindowProperty::New( - // LevelWindow(m_CurrentThresholdValue, 0.01) ) ); - UpdatePreview(); - } -} - -void mitk::BinaryThresholdTool::AcceptCurrentThresholdValue() -{ - CreateNewSegmentationFromThreshold(); - - RenderingManager::GetInstance()->RequestUpdateAll(); - m_ToolManager->ActivateTool(-1); -} - -void mitk::BinaryThresholdTool::CancelThresholding() -{ - m_ToolManager->ActivateTool(-1); -} - -void mitk::BinaryThresholdTool::SetupPreviewNode() -{ - itk::RGBPixel pixel; - pixel[0] = 0.0f; - pixel[1] = 1.0f; - pixel[2] = 0.0f; - - if (m_NodeForThresholding.IsNotNull()) - { - Image::Pointer image = dynamic_cast(m_NodeForThresholding->GetData()); - Image::Pointer originalImage = dynamic_cast(m_OriginalImageNode->GetData()); - - if (image.IsNotNull()) - { - mitk::LabelSetImage::Pointer workingImage = - dynamic_cast(m_ToolManager->GetWorkingData(0)->GetData()); - - if (workingImage.IsNotNull()) - { - m_ThresholdFeedbackNode->SetData(workingImage->Clone()); - m_IsOldBinary = false; - - // Let's paint the feedback node green... - mitk::LabelSetImage::Pointer previewImage = - dynamic_cast(m_ThresholdFeedbackNode->GetData()); - - if (previewImage.IsNull()) - { - MITK_ERROR << "Cannot create helper objects."; - return; - } - - previewImage->GetActiveLabel()->SetColor(pixel); - previewImage->GetActiveLabelSet()->UpdateLookupTable(previewImage->GetActiveLabel()->GetValue()); - } - else - { - mitk::Image::Pointer workingImageBin = dynamic_cast(m_ToolManager->GetWorkingData(0)->GetData()); - if (workingImageBin) - { - m_ThresholdFeedbackNode->SetData(workingImageBin->Clone()); - m_IsOldBinary = true; - } - else - m_ThresholdFeedbackNode->SetData(mitk::Image::New()); - } - - m_ThresholdFeedbackNode->SetColor(pixel); - m_ThresholdFeedbackNode->SetOpacity(0.5); - - int layer(50); - m_NodeForThresholding->GetIntProperty("layer", layer); - m_ThresholdFeedbackNode->SetIntProperty("layer", layer + 1); - - if (DataStorage *ds = m_ToolManager->GetDataStorage()) - { - if (!ds->Exists(m_ThresholdFeedbackNode)) - ds->Add(m_ThresholdFeedbackNode, m_OriginalImageNode); - } - - if (image.GetPointer() == originalImage.GetPointer()) - { - m_SensibleMinimumThresholdValue = std::numeric_limits::max(); - m_SensibleMaximumThresholdValue = std::numeric_limits::lowest(); - Image::StatisticsHolderPointer statistics = originalImage->GetStatistics(); - for (unsigned int ts = 0; ts < originalImage->GetTimeSteps(); ++ts) - { - m_SensibleMinimumThresholdValue = std::min(m_SensibleMinimumThresholdValue, static_cast(statistics->GetScalarValueMin())); - m_SensibleMaximumThresholdValue = std::max(m_SensibleMaximumThresholdValue, static_cast(statistics->GetScalarValueMax())); - } - } - - if ((originalImage->GetPixelType().GetPixelType() == itk::ImageIOBase::SCALAR) && - (originalImage->GetPixelType().GetComponentType() == itk::ImageIOBase::FLOAT || - originalImage->GetPixelType().GetComponentType() == itk::ImageIOBase::DOUBLE)) - m_IsFloatImage = true; - else - m_IsFloatImage = false; - - m_CurrentThresholdValue = (m_SensibleMaximumThresholdValue + m_SensibleMinimumThresholdValue) / 2.0; - - IntervalBordersChanged.Send(m_SensibleMinimumThresholdValue, m_SensibleMaximumThresholdValue, m_IsFloatImage); - ThresholdingValueChanged.Send(m_CurrentThresholdValue); - } - } -} - -template -static void ITKSetVolume(const itk::Image *originalImage, - mitk::Image *segmentation, - unsigned int timeStep) -{ - auto constPixelContainer = originalImage->GetPixelContainer(); - //have to make a const cast because itk::PixelContainer does not provide a const correct access :( - auto pixelContainer = const_cast::PixelContainer*>(constPixelContainer); - segmentation->SetVolume((void *)pixelContainer->GetBufferPointer(), timeStep); -} - -void mitk::BinaryThresholdTool::TransferImageAtTimeStep(const Image* sourceImage, Image* destinationImage, const TimeStepType timeStep) -{ - try - { - Image::ConstPointer image3D = this->Get3DImage(sourceImage, timeStep); - - if (image3D->GetDimension() == 2) - { - AccessFixedDimensionByItk_2( - image3D, ITKSetVolume, 2, destinationImage, timeStep); - } - else - { - AccessFixedDimensionByItk_2( - image3D, ITKSetVolume, 3, destinationImage, timeStep); - } - } - catch (...) - { - Tool::ErrorMessage("Error accessing single time steps of the original image. Cannot create segmentation."); - } -} - -void mitk::BinaryThresholdTool::CreateNewSegmentationFromThreshold() -{ - if (m_NodeForThresholding.IsNotNull() && m_ThresholdFeedbackNode.IsNotNull()) - { - Image::Pointer feedBackImage = dynamic_cast(m_ThresholdFeedbackNode->GetData()); - if (feedBackImage.IsNotNull()) - { - DataNode::Pointer emptySegmentationNode = GetTargetSegmentationNode(); - - if (emptySegmentationNode) - { - const auto timePoint = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint(); - auto emptySegmentation = dynamic_cast(emptySegmentationNode->GetData()); - - // actually perform a thresholding - // REMARK: the following code in this scope assumes that feedBackImage and emptySegmentationImage - // are clones of the working image (segmentation provided to the tool). Therefor the have the same - // time geometry. - if (feedBackImage->GetTimeSteps() != emptySegmentation->GetTimeSteps()) - { - mitkThrow() << "Cannot performe threshold. Internal tool state is invalid." - << " Preview segmentation and segmentation result image have different time geometries."; - } - - if (m_CreateAllTimeSteps) - { - for (unsigned int timeStep = 0; timeStep < feedBackImage->GetTimeSteps(); ++timeStep) - { - TransferImageAtTimeStep(feedBackImage, emptySegmentation, timeStep); - } - } - else - { - const auto timeStep = emptySegmentation->GetTimeGeometry()->TimePointToTimeStep(timePoint); - TransferImageAtTimeStep(feedBackImage, emptySegmentation, timeStep); - } - - if (m_OriginalImageNode.GetPointer() != m_NodeForThresholding.GetPointer()) - { - mitk::PadImageFilter::Pointer padFilter = mitk::PadImageFilter::New(); - - padFilter->SetInput(0, emptySegmentation); - padFilter->SetInput(1, dynamic_cast(m_OriginalImageNode->GetData())); - padFilter->SetBinaryFilter(true); - padFilter->SetUpperThreshold(1); - padFilter->SetLowerThreshold(1); - padFilter->Update(); - - emptySegmentationNode->SetData(padFilter->GetOutput()); - } - - m_ToolManager->SetWorkingData(emptySegmentationNode); - m_ToolManager->GetWorkingData(0)->Modified(); - } - } - } -} - -void mitk::BinaryThresholdTool::OnRoiDataChanged() -{ - mitk::DataNode::Pointer node = m_ToolManager->GetRoiData(0); - - if (node.IsNotNull()) - { - mitk::MaskAndCutRoiImageFilter::Pointer roiFilter = mitk::MaskAndCutRoiImageFilter::New(); - mitk::Image::Pointer image = dynamic_cast(m_NodeForThresholding->GetData()); - - if (image.IsNull()) - return; - - roiFilter->SetInput(image); - roiFilter->SetRegionOfInterest(node->GetData()); - roiFilter->Update(); - - mitk::DataNode::Pointer tmpNode = mitk::DataNode::New(); - tmpNode->SetData(roiFilter->GetOutput()); - - m_SensibleMaximumThresholdValue = static_cast(roiFilter->GetMaxValue()); - m_SensibleMinimumThresholdValue = static_cast(roiFilter->GetMinValue()); - - m_NodeForThresholding = tmpNode; - } - else - { - m_NodeForThresholding = m_OriginalImageNode; - } - - this->SetupPreviewNode(); - this->UpdatePreview(); -} - -void mitk::BinaryThresholdTool::OnTimePointChanged() -{ - if (m_ThresholdFeedbackNode.IsNotNull() && m_NodeForThresholding.IsNotNull()) - { - if (m_ThresholdFeedbackNode->GetData()->GetTimeSteps() == 1) - { - this->UpdatePreview(); - } - } -} - -template -void mitk::BinaryThresholdTool::ITKThresholding(const itk::Image *originalImage, - Image *segmentation, - double thresholdValue, - unsigned int timeStep) const -{ - typedef itk::Image ImageType; - typedef itk::Image SegmentationType; - typedef itk::BinaryThresholdImageFilter ThresholdFilterType; - - typename ThresholdFilterType::Pointer filter = ThresholdFilterType::New(); - filter->SetInput(originalImage); - filter->SetLowerThreshold(thresholdValue); - filter->SetUpperThreshold(m_SensibleMaximumThresholdValue); - filter->SetInsideValue(1); - filter->SetOutsideValue(0); - filter->Update(); - - segmentation->SetVolume((void *)(filter->GetOutput()->GetPixelContainer()->GetBufferPointer()), timeStep); -} - -template -void mitk::BinaryThresholdTool::ITKThresholdingOldBinary(const itk::Image *originalImage, - Image *segmentation, - double thresholdValue, - unsigned int timeStep) const -{ - typedef itk::Image ImageType; - typedef itk::Image SegmentationType; - typedef itk::BinaryThresholdImageFilter ThresholdFilterType; - - typename ThresholdFilterType::Pointer filter = ThresholdFilterType::New(); - filter->SetInput(originalImage); - filter->SetLowerThreshold(thresholdValue); - filter->SetUpperThreshold(m_SensibleMaximumThresholdValue); - filter->SetInsideValue(1); - filter->SetOutsideValue(0); - filter->Update(); - - segmentation->SetVolume((void *)(filter->GetOutput()->GetPixelContainer()->GetBufferPointer()), timeStep); -} - -void mitk::BinaryThresholdTool::UpdatePreview() -{ - mitk::Image::Pointer thresholdImage = dynamic_cast(m_NodeForThresholding->GetData()); - mitk::Image::Pointer previewImage = dynamic_cast(m_ThresholdFeedbackNode->GetData()); - if (thresholdImage && previewImage) - { - if (previewImage->GetTimeSteps() > 1) - { - for (unsigned int timeStep = 0; timeStep < thresholdImage->GetTimeSteps(); ++timeStep) - { - auto feedBackImage3D = this->Get3DImage(thresholdImage, timeStep); - - if (m_IsOldBinary) - { - AccessByItk_n(feedBackImage3D, ITKThresholdingOldBinary, (previewImage, m_CurrentThresholdValue, timeStep)); - } - else - { - AccessByItk_n(feedBackImage3D, ITKThresholding, (previewImage, m_CurrentThresholdValue, timeStep)); - } - } - } - else - { - const auto timePoint = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint(); - auto feedBackImage3D = this->Get3DImageByTimePoint(thresholdImage, timePoint); - auto segTimeStep = previewImage->GetTimeGeometry()->TimePointToTimeStep(timePoint); - - if (m_IsOldBinary) - { - AccessByItk_n(feedBackImage3D, ITKThresholdingOldBinary, (previewImage, m_CurrentThresholdValue, segTimeStep)); - } - else - { - AccessByItk_n(feedBackImage3D, ITKThresholding, (previewImage, m_CurrentThresholdValue, segTimeStep)); - } - } - - - RenderingManager::GetInstance()->RequestUpdateAll(); - } + this->SetThresholdValues(value, this->GetSensibleMaximumThresholdValue()); } diff --git a/Modules/Segmentation/Interactions/mitkBinaryThresholdTool.h b/Modules/Segmentation/Interactions/mitkBinaryThresholdTool.h index e0cd558f3e..aed3e99328 100644 --- a/Modules/Segmentation/Interactions/mitkBinaryThresholdTool.h +++ b/Modules/Segmentation/Interactions/mitkBinaryThresholdTool.h @@ -1,101 +1,56 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkBinaryThresholdTool_h_Included #define mitkBinaryThresholdTool_h_Included -#include "mitkAutoSegmentationTool.h" -#include "mitkCommon.h" -#include "mitkDataNode.h" +#include "mitkBinaryThresholdBaseTool.h" #include -#include - namespace us { class ModuleResource; } namespace mitk { /** \brief Calculates the segmented volumes for binary images. \ingroup ToolManagerEtAl \sa mitk::Tool \sa QmitkInteractiveSegmentation Last contributor: $Author$ */ - class MITKSEGMENTATION_EXPORT BinaryThresholdTool : public AutoSegmentationTool + class MITKSEGMENTATION_EXPORT BinaryThresholdTool : public BinaryThresholdBaseTool { public: - Message3 IntervalBordersChanged; - Message1 ThresholdingValueChanged; - mitkClassMacro(BinaryThresholdTool, AutoSegmentationTool); + mitkClassMacro(BinaryThresholdTool, BinaryThresholdBaseTool); itkFactorylessNewMacro(Self); itkCloneMacro(Self); - const char **GetXPM() const override; + const char **GetXPM() const override; us::ModuleResource GetIconResource() const override; const char *GetName() const override; - void Activated() override; - void Deactivated() override; - virtual void SetThresholdValue(double value); - virtual void AcceptCurrentThresholdValue(); - virtual void CancelThresholding(); protected: BinaryThresholdTool(); // purposely hidden ~BinaryThresholdTool() override; - - void SetupPreviewNode(); - - void TransferImageAtTimeStep(const Image* sourceImage, Image* destinationImage, const TimeStepType timeStep); - - void CreateNewSegmentationFromThreshold(); - - void OnRoiDataChanged(); - void OnTimePointChanged(); - - void UpdatePreview(); - - template - void ITKThresholding(const itk::Image *originalImage, - mitk::Image *segmentation, - double thresholdValue, - unsigned int timeStep) const; - template - void ITKThresholdingOldBinary(const itk::Image *originalImage, - mitk::Image *segmentation, - double thresholdValue, - unsigned int timeStep) const; - - DataNode::Pointer m_ThresholdFeedbackNode; - DataNode::Pointer m_OriginalImageNode; - DataNode::Pointer m_NodeForThresholding; - - double m_SensibleMinimumThresholdValue; - double m_SensibleMaximumThresholdValue; - double m_CurrentThresholdValue; - bool m_IsFloatImage; - - bool m_IsOldBinary = false; - bool m_CreateAllTimeSteps = false; }; } // namespace #endif diff --git a/Modules/Segmentation/Interactions/mitkBinaryThresholdULTool.cpp b/Modules/Segmentation/Interactions/mitkBinaryThresholdULTool.cpp index ab917f34fe..7e729be00e 100644 --- a/Modules/Segmentation/Interactions/mitkBinaryThresholdULTool.cpp +++ b/Modules/Segmentation/Interactions/mitkBinaryThresholdULTool.cpp @@ -1,406 +1,50 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkBinaryThresholdULTool.h" -#include "mitkToolManager.h" - -#include "mitkColorProperty.h" -#include "mitkLevelWindowProperty.h" -#include "mitkProperties.h" - -#include "mitkDataStorage.h" -#include "mitkRenderingManager.h" -#include - -#include "mitkImageAccessByItk.h" -#include "mitkImageCast.h" -#include "mitkImageStatisticsHolder.h" -#include "mitkImageTimeSelector.h" -#include "mitkLabelSetImage.h" -#include "mitkMaskAndCutRoiImageFilter.h" -#include "mitkPadImageFilter.h" -#include -#include - // us #include "usGetModuleContext.h" #include "usModule.h" #include "usModuleContext.h" #include "usModuleResource.h" namespace mitk { MITK_TOOL_MACRO(MITKSEGMENTATION_EXPORT, BinaryThresholdULTool, "ThresholdingUL tool"); } -mitk::BinaryThresholdULTool::BinaryThresholdULTool() - : m_SensibleMinimumThresholdValue(-100), - m_SensibleMaximumThresholdValue(+100), - m_CurrentLowerThresholdValue(1), - m_CurrentUpperThresholdValue(1) +mitk::BinaryThresholdULTool::BinaryThresholdULTool() : BinaryThresholdBaseTool() { - m_ThresholdFeedbackNode = DataNode::New(); - m_ThresholdFeedbackNode->SetProperty("color", ColorProperty::New(0.0, 1.0, 0.0)); - m_ThresholdFeedbackNode->SetProperty("name", StringProperty::New("Thresholding feedback")); - m_ThresholdFeedbackNode->SetProperty("opacity", FloatProperty::New(0.3)); - m_ThresholdFeedbackNode->SetProperty("binary", BoolProperty::New(true)); - m_ThresholdFeedbackNode->SetProperty("helper object", BoolProperty::New(true)); } mitk::BinaryThresholdULTool::~BinaryThresholdULTool() { } const char **mitk::BinaryThresholdULTool::GetXPM() const { return nullptr; } us::ModuleResource mitk::BinaryThresholdULTool::GetIconResource() const { us::Module *module = us::GetModuleContext()->GetModule(); us::ModuleResource resource = module->GetResource("TwoThresholds_48x48.png"); return resource; } const char *mitk::BinaryThresholdULTool::GetName() const { return "UL Threshold"; } -void mitk::BinaryThresholdULTool::Activated() -{ - Superclass::Activated(); - - m_ToolManager->RoiDataChanged += - mitk::MessageDelegate(this, &mitk::BinaryThresholdULTool::OnRoiDataChanged); - - m_OriginalImageNode = m_ToolManager->GetReferenceData(0); - m_NodeForThresholding = m_OriginalImageNode; - - if (m_NodeForThresholding.IsNotNull()) - { - SetupPreviewNode(); - } - else - { - m_ToolManager->ActivateTool(-1); - } -} - -void mitk::BinaryThresholdULTool::Deactivated() -{ - m_ToolManager->RoiDataChanged -= - mitk::MessageDelegate(this, &mitk::BinaryThresholdULTool::OnRoiDataChanged); - m_NodeForThresholding = nullptr; - m_OriginalImageNode = nullptr; - try - { - if (DataStorage *storage = m_ToolManager->GetDataStorage()) - { - storage->Remove(m_ThresholdFeedbackNode); - RenderingManager::GetInstance()->RequestUpdateAll(); - } - } - catch (...) - { - // don't care - } - m_ThresholdFeedbackNode->SetData(nullptr); - - Superclass::Deactivated(); -} - -void mitk::BinaryThresholdULTool::SetThresholdValues(double lower, double upper) -{ - if (m_ThresholdFeedbackNode.IsNotNull()) - { - m_CurrentLowerThresholdValue = lower; - m_CurrentUpperThresholdValue = upper; - UpdatePreview(); - } -} - -void mitk::BinaryThresholdULTool::AcceptCurrentThresholdValue() -{ - CreateNewSegmentationFromThreshold(m_NodeForThresholding); - - RenderingManager::GetInstance()->RequestUpdateAll(); - m_ToolManager->ActivateTool(-1); -} - -void mitk::BinaryThresholdULTool::CancelThresholding() -{ - m_ToolManager->ActivateTool(-1); -} - -void mitk::BinaryThresholdULTool::SetupPreviewNode() -{ - itk::RGBPixel pixel; - pixel[0] = 0.0f; - pixel[1] = 1.0f; - pixel[2] = 0.0f; - - if (m_NodeForThresholding.IsNotNull()) - { - Image::Pointer image = dynamic_cast(m_NodeForThresholding->GetData()); - Image::Pointer originalImage = dynamic_cast(m_OriginalImageNode->GetData()); - - if (image.IsNotNull()) - { - mitk::LabelSetImage::Pointer workingImage = - dynamic_cast(m_ToolManager->GetWorkingData(0)->GetData()); - - if (workingImage.IsNotNull()) - { - m_ThresholdFeedbackNode->SetData(workingImage->Clone()); - m_IsOldBinary = false; - - // Let's paint the feedback node green... - mitk::LabelSetImage::Pointer previewImage = - dynamic_cast(m_ThresholdFeedbackNode->GetData()); - - if (previewImage.IsNull()) - { - MITK_ERROR << "Cannot create helper objects."; - return; - } - - previewImage->GetActiveLabel()->SetColor(pixel); - previewImage->GetActiveLabelSet()->UpdateLookupTable(previewImage->GetActiveLabel()->GetValue()); - } - else - { - mitk::Image::Pointer workingImageBin = dynamic_cast(m_ToolManager->GetWorkingData(0)->GetData()); - if (workingImageBin) - { - m_ThresholdFeedbackNode->SetData(workingImageBin->Clone()); - m_IsOldBinary = true; - } - else - m_ThresholdFeedbackNode->SetData(mitk::Image::New()); - } - - m_ThresholdFeedbackNode->SetColor(pixel); - m_ThresholdFeedbackNode->SetOpacity(0.5); - - int layer(50); - m_NodeForThresholding->GetIntProperty("layer", layer); - m_ThresholdFeedbackNode->SetIntProperty("layer", layer + 1); - - if (DataStorage *ds = m_ToolManager->GetDataStorage()) - { - if (!ds->Exists(m_ThresholdFeedbackNode)) - ds->Add(m_ThresholdFeedbackNode, m_OriginalImageNode); - } - - if (image.GetPointer() == originalImage.GetPointer()) - { - Image::StatisticsHolderPointer statistics = originalImage->GetStatistics(); - m_SensibleMinimumThresholdValue = static_cast(statistics->GetScalarValueMin()); - m_SensibleMaximumThresholdValue = static_cast(statistics->GetScalarValueMax()); - } - - double range = m_SensibleMaximumThresholdValue - m_SensibleMinimumThresholdValue; - m_CurrentLowerThresholdValue = m_SensibleMinimumThresholdValue + range / 3.0; - m_CurrentUpperThresholdValue = m_SensibleMinimumThresholdValue + 2 * range / 3.0; - - bool isFloatImage = false; - if ((originalImage->GetPixelType().GetPixelType() == itk::ImageIOBase::SCALAR) && - (originalImage->GetPixelType().GetComponentType() == itk::ImageIOBase::FLOAT || - originalImage->GetPixelType().GetComponentType() == itk::ImageIOBase::DOUBLE)) - { - isFloatImage = true; - } - - IntervalBordersChanged.Send(m_SensibleMinimumThresholdValue, m_SensibleMaximumThresholdValue, isFloatImage); - ThresholdingValuesChanged.Send(m_CurrentLowerThresholdValue, m_CurrentUpperThresholdValue); - } - } -} - -template -static void ITKSetVolume(itk::Image *originalImage, - mitk::Image *segmentation, - unsigned int timeStep) -{ - segmentation->SetVolume((void *)originalImage->GetPixelContainer()->GetBufferPointer(), timeStep); -} - -void mitk::BinaryThresholdULTool::CreateNewSegmentationFromThreshold(DataNode *node) -{ - if (node) - { - Image::Pointer feedBackImage = dynamic_cast(m_ThresholdFeedbackNode->GetData()); - if (feedBackImage.IsNotNull()) - { - // create a new image of the same dimensions and smallest possible pixel type - DataNode::Pointer emptySegmentation = GetTargetSegmentationNode(); - - if (emptySegmentation) - { - // actually perform a thresholding and ask for an organ type - for (unsigned int timeStep = 0; timeStep < feedBackImage->GetTimeSteps(); ++timeStep) - { - try - { - ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New(); - timeSelector->SetInput(feedBackImage); - timeSelector->SetTimeNr(timeStep); - timeSelector->UpdateLargestPossibleRegion(); - Image::Pointer feedBackImage3D = timeSelector->GetOutput(); - - if (feedBackImage3D->GetDimension() == 2) - { - AccessFixedDimensionByItk_2( - feedBackImage3D, ITKSetVolume, 2, dynamic_cast(emptySegmentation->GetData()), timeStep); - } - else - { - AccessFixedDimensionByItk_2( - feedBackImage3D, ITKSetVolume, 3, dynamic_cast(emptySegmentation->GetData()), timeStep); - } - } - catch (...) - { - Tool::ErrorMessage("Error accessing single time steps of the original image. Cannot create segmentation."); - } - } - - // since we are maybe working on a smaller image, pad it to the size of the original image - if (m_OriginalImageNode.GetPointer() != m_NodeForThresholding.GetPointer()) - { - mitk::PadImageFilter::Pointer padFilter = mitk::PadImageFilter::New(); - - padFilter->SetInput(0, dynamic_cast(emptySegmentation->GetData())); - padFilter->SetInput(1, dynamic_cast(m_OriginalImageNode->GetData())); - padFilter->SetBinaryFilter(true); - padFilter->SetUpperThreshold(1); - padFilter->SetLowerThreshold(1); - padFilter->Update(); - - emptySegmentation->SetData(padFilter->GetOutput()); - } - - m_ToolManager->SetWorkingData(emptySegmentation); - m_ToolManager->GetWorkingData(0)->Modified(); - } - } - } -} - -void mitk::BinaryThresholdULTool::OnRoiDataChanged() -{ - mitk::DataNode::Pointer node = m_ToolManager->GetRoiData(0); - - if (node.IsNotNull()) - { - mitk::MaskAndCutRoiImageFilter::Pointer roiFilter = mitk::MaskAndCutRoiImageFilter::New(); - mitk::Image::Pointer image = dynamic_cast(m_NodeForThresholding->GetData()); - - if (image.IsNull()) - return; - - roiFilter->SetInput(image); - roiFilter->SetRegionOfInterest(node->GetData()); - roiFilter->Update(); - - mitk::DataNode::Pointer tmpNode = mitk::DataNode::New(); - tmpNode->SetData(roiFilter->GetOutput()); - - m_SensibleMinimumThresholdValue = static_cast(roiFilter->GetMinValue()); - m_SensibleMaximumThresholdValue = static_cast(roiFilter->GetMaxValue()); - - m_NodeForThresholding = tmpNode; - } - else - m_NodeForThresholding = m_OriginalImageNode; - - this->SetupPreviewNode(); - this->UpdatePreview(); -} - -template -static void ITKThresholding(itk::Image *originalImage, - mitk::Image *segmentation, - double lower, - double upper, - unsigned int timeStep) -{ - typedef itk::Image ImageType; - typedef itk::Image SegmentationType; - typedef itk::BinaryThresholdImageFilter ThresholdFilterType; - - typename ThresholdFilterType::Pointer filter = ThresholdFilterType::New(); - filter->SetInput(originalImage); - filter->SetLowerThreshold(lower); - filter->SetUpperThreshold(upper); - filter->SetInsideValue(1); - filter->SetOutsideValue(0); - filter->Update(); - - segmentation->SetVolume((void *)(filter->GetOutput()->GetPixelContainer()->GetBufferPointer()), timeStep); -} - -template -static void ITKThresholdingOldBinary(itk::Image *originalImage, - mitk::Image *segmentation, - double lower, - double upper, - unsigned int timeStep) -{ - typedef itk::Image ImageType; - typedef itk::Image SegmentationType; - typedef itk::BinaryThresholdImageFilter ThresholdFilterType; - - typename ThresholdFilterType::Pointer filter = ThresholdFilterType::New(); - filter->SetInput(originalImage); - filter->SetLowerThreshold(lower); - filter->SetUpperThreshold(upper); - filter->SetInsideValue(1); - filter->SetOutsideValue(0); - filter->Update(); - - segmentation->SetVolume((void *)(filter->GetOutput()->GetPixelContainer()->GetBufferPointer()), timeStep); -} - -void mitk::BinaryThresholdULTool::UpdatePreview() -{ - mitk::Image::Pointer thresholdImage = dynamic_cast(m_NodeForThresholding->GetData()); - mitk::Image::Pointer previewImage = dynamic_cast(m_ThresholdFeedbackNode->GetData()); - if (thresholdImage && previewImage) - { - for (unsigned int timeStep = 0; timeStep < thresholdImage->GetTimeSteps(); ++timeStep) - { - ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New(); - timeSelector->SetInput(thresholdImage); - timeSelector->SetTimeNr(timeStep); - timeSelector->UpdateLargestPossibleRegion(); - Image::Pointer feedBackImage3D = timeSelector->GetOutput(); - - if (m_IsOldBinary) - { - AccessByItk_n(feedBackImage3D, - ITKThresholdingOldBinary, - (previewImage, m_CurrentLowerThresholdValue, m_CurrentUpperThresholdValue, timeStep)); - } - else - { - AccessByItk_n(feedBackImage3D, - ITKThresholding, - (previewImage, m_CurrentLowerThresholdValue, m_CurrentUpperThresholdValue, timeStep)); - } - } - RenderingManager::GetInstance()->RequestUpdateAll(); - } -} diff --git a/Modules/Segmentation/Interactions/mitkBinaryThresholdULTool.h b/Modules/Segmentation/Interactions/mitkBinaryThresholdULTool.h index a29b5f3f7d..b6f15824a2 100644 --- a/Modules/Segmentation/Interactions/mitkBinaryThresholdULTool.h +++ b/Modules/Segmentation/Interactions/mitkBinaryThresholdULTool.h @@ -1,91 +1,54 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkBinaryThresholdULTool_h_Included #define mitkBinaryThresholdULTool_h_Included -#include "mitkAutoSegmentationTool.h" -#include "mitkCommon.h" -#include "mitkDataNode.h" +#include "mitkBinaryThresholdBaseTool.h" #include -#include -#include namespace us { class ModuleResource; } namespace mitk { /** \brief Calculates the segmented volumes for binary images. \ingroup ToolManagerEtAl \sa mitk::Tool \sa QmitkInteractiveSegmentation Last contributor: $Author$ */ - class MITKSEGMENTATION_EXPORT BinaryThresholdULTool : public AutoSegmentationTool + class MITKSEGMENTATION_EXPORT BinaryThresholdULTool : public BinaryThresholdBaseTool { public: - Message3 IntervalBordersChanged; - Message2 ThresholdingValuesChanged; - - mitkClassMacro(BinaryThresholdULTool, AutoSegmentationTool); + mitkClassMacro(BinaryThresholdULTool, BinaryThresholdBaseTool); itkFactorylessNewMacro(Self); itkCloneMacro(Self); - const char **GetXPM() const override; + const char **GetXPM() const override; us::ModuleResource GetIconResource() const override; const char *GetName() const override; - void Activated() override; - void Deactivated() override; - - virtual void SetThresholdValues(double lower, double upper); - virtual void AcceptCurrentThresholdValue(); - virtual void CancelThresholding(); - protected: BinaryThresholdULTool(); // purposely hidden ~BinaryThresholdULTool() override; - - void SetupPreviewNode(); - - void CreateNewSegmentationFromThreshold(DataNode *node); - - void OnRoiDataChanged(); - void UpdatePreview(); - - DataNode::Pointer m_ThresholdFeedbackNode; - DataNode::Pointer m_OriginalImageNode; - DataNode::Pointer m_NodeForThresholding; - - mitk::ScalarType m_SensibleMinimumThresholdValue; - mitk::ScalarType m_SensibleMaximumThresholdValue; - mitk::ScalarType m_CurrentLowerThresholdValue; - mitk::ScalarType m_CurrentUpperThresholdValue; - - bool m_IsOldBinary = false; - - typedef itk::Image ImageType; - typedef itk::Image SegmentationType; // this is sure for new segmentations - typedef itk::BinaryThresholdImageFilter ThresholdFilterType; - ThresholdFilterType::Pointer m_ThresholdFilter; }; } // namespace #endif diff --git a/Modules/Segmentation/files.cmake b/Modules/Segmentation/files.cmake index 071e038786..676362200a 100644 --- a/Modules/Segmentation/files.cmake +++ b/Modules/Segmentation/files.cmake @@ -1,124 +1,116 @@ set(CPP_FILES Algorithms/mitkCalculateSegmentationVolume.cpp Algorithms/mitkContourModelSetToImageFilter.cpp Algorithms/mitkContourSetToPointSetFilter.cpp Algorithms/mitkContourUtils.cpp Algorithms/mitkCorrectorAlgorithm.cpp Algorithms/mitkDiffImageApplier.cpp Algorithms/mitkDiffSliceOperation.cpp Algorithms/mitkDiffSliceOperationApplier.cpp Algorithms/mitkFeatureBasedEdgeDetectionFilter.cpp Algorithms/mitkImageLiveWireContourModelFilter.cpp Algorithms/mitkImageToContourFilter.cpp #Algorithms/mitkImageToContourModelFilter.cpp Algorithms/mitkImageToLiveWireContourFilter.cpp Algorithms/mitkManualSegmentationToSurfaceFilter.cpp Algorithms/mitkOtsuSegmentationFilter.cpp Algorithms/mitkOverwriteDirectedPlaneImageFilter.cpp Algorithms/mitkOverwriteSliceImageFilter.cpp Algorithms/mitkSegmentationObjectFactory.cpp Algorithms/mitkShapeBasedInterpolationAlgorithm.cpp Algorithms/mitkShowSegmentationAsSmoothedSurface.cpp Algorithms/mitkShowSegmentationAsSurface.cpp Algorithms/mitkVtkImageOverwrite.cpp Controllers/mitkSegmentationInterpolationController.cpp Controllers/mitkToolManager.cpp Controllers/mitkSegmentationModuleActivator.cpp Controllers/mitkToolManagerProvider.cpp DataManagement/mitkContour.cpp - #DataManagement/mitkContourElement.cpp - #DataManagement/mitkContourModel.cpp DataManagement/mitkContourSet.cpp DataManagement/mitkExtrudedContour.cpp Interactions/mitkAdaptiveRegionGrowingTool.cpp Interactions/mitkAddContourTool.cpp Interactions/mitkAutoCropTool.cpp Interactions/mitkAutoSegmentationTool.cpp + Interactions/mitkBinaryThresholdBaseTool.cpp Interactions/mitkBinaryThresholdTool.cpp Interactions/mitkBinaryThresholdULTool.cpp Interactions/mitkCalculateGrayValueStatisticsTool.cpp Interactions/mitkCalculateVolumetryTool.cpp Interactions/mitkContourModelInteractor.cpp Interactions/mitkContourModelLiveWireInteractor.cpp Interactions/mitkLiveWireTool2D.cpp Interactions/mitkContourTool.cpp Interactions/mitkCorrectorTool2D.cpp Interactions/mitkCreateSurfaceTool.cpp Interactions/mitkDrawPaintbrushTool.cpp Interactions/mitkErasePaintbrushTool.cpp Interactions/mitkEraseRegionTool.cpp Interactions/mitkFastMarchingTool.cpp Interactions/mitkFastMarchingTool3D.cpp Interactions/mitkFeedbackContourTool.cpp Interactions/mitkFillRegionTool.cpp Interactions/mitkOtsuTool3D.cpp Interactions/mitkPaintbrushTool.cpp Interactions/mitkPixelManipulationTool.cpp Interactions/mitkRegionGrowingTool.cpp Interactions/mitkSegmentationsProcessingTool.cpp Interactions/mitkSetRegionTool.cpp Interactions/mitkSegTool2D.cpp Interactions/mitkSubtractContourTool.cpp Interactions/mitkTool.cpp Interactions/mitkToolCommand.cpp Interactions/mitkWatershedTool.cpp Interactions/mitkPickingTool.cpp Interactions/mitkSegmentationInteractor.cpp #SO - #IO/mitkContourModelIOFactory.cpp - #IO/mitkContourModelReader.cpp - #IO/mitkContourModelWriter.cpp - #IO/mitkContourModelWriterFactory.cpp Rendering/mitkContourMapper2D.cpp - #Rendering/mitkContourModelGLMapper2D.cpp - #Rendering/mitkContourModelMapper2D.cpp - #Rendering/mitkContourModelMapper3D.cpp Rendering/mitkContourSetMapper2D.cpp Rendering/mitkContourSetVtkMapper3D.cpp Rendering/mitkContourVtkMapper3D.cpp SegmentationUtilities/BooleanOperations/mitkBooleanOperation.cpp SegmentationUtilities/MorphologicalOperations/mitkMorphologicalOperations.cpp #Added from ML Controllers/mitkSliceBasedInterpolationController.cpp Algorithms/mitkSurfaceStampImageFilter.cpp ) set(RESOURCE_FILES Add_48x48.png Add_Cursor_32x32.png Correction_48x48.png Correction_Cursor_32x32.png Erase_48x48.png Erase_Cursor_32x32.png FastMarching_48x48.png FastMarching_Cursor_32x32.png Fill_48x48.png Fill_Cursor_32x32.png LiveWire_48x48.png LiveWire_Cursor_32x32.png Otsu_48x48.png Paint_48x48.png Paint_Cursor_32x32.png Pick_48x48.png RegionGrowing_48x48.png RegionGrowing_Cursor_32x32.png Subtract_48x48.png Subtract_Cursor_32x32.png Threshold_48x48.png TwoThresholds_48x48.png Watershed_48x48.png Watershed_Cursor_32x32.png Wipe_48x48.png Wipe_Cursor_32x32.png Interactions/dummy.xml Interactions/LiveWireTool.xml Interactions/FastMarchingTool.xml Interactions/PressMoveRelease.xml Interactions/PressMoveReleaseAndPointSetting.xml Interactions/PressMoveReleaseWithCTRLInversion.xml Interactions/PressMoveReleaseWithCTRLInversionAllMouseMoves.xml Interactions/SegmentationToolsConfig.xml Interactions/ContourModelModificationConfig.xml Interactions/ContourModelModificationInteractor.xml ) diff --git a/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdToolGUI.cpp b/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdToolGUI.cpp index b950c20c1c..8984c1a21c 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdToolGUI.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdToolGUI.cpp @@ -1,212 +1,143 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkBinaryThresholdToolGUI.h" #include "QmitkConfirmSegmentationDialog.h" #include "QmitkNewSegmentationDialog.h" #include #include #include #include MITK_TOOL_GUI_MACRO(MITKSEGMENTATIONUI_EXPORT, QmitkBinaryThresholdToolGUI, "") QmitkBinaryThresholdToolGUI::QmitkBinaryThresholdToolGUI() - : QmitkToolGUI(), - m_Slider(nullptr), - m_Spinner(nullptr), - m_isFloat(false), - m_RangeMin(0), - m_RangeMax(0), - m_ChangingSlider(false), - m_ChangingSpinner(false) + : QmitkToolGUI() { // create the visible widgets QBoxLayout *mainLayout = new QVBoxLayout(this); QLabel *label = new QLabel("Threshold :", this); QFont f = label->font(); f.setBold(false); label->setFont(f); mainLayout->addWidget(label); QBoxLayout *layout = new QHBoxLayout(); - m_Spinner = new QDoubleSpinBox(); - m_Spinner->setMaximum(20); - m_Spinner->setMinimum(5); - m_Spinner->setValue(1); - - connect(m_Spinner, SIGNAL(valueChanged(double)), this, SLOT(OnSpinnerValueChanged())); - layout->addWidget(m_Spinner); - - // m_Slider = new QSlider( 5, 20, 1, 1, Qt::Horizontal, this ); - m_Slider = new QSlider(Qt::Horizontal, this); - m_Slider->setMinimum(5); - m_Slider->setMaximum(20); - m_Slider->setPageStep(1); - m_Slider->setValue(1); - connect(m_Slider, SIGNAL(valueChanged(int)), this, SLOT(OnSliderValueChanged(int))); - layout->addWidget(m_Slider); - + m_ThresholdSlider = new ctkSliderWidget(); + connect( + m_ThresholdSlider, SIGNAL(valueChanged(double)), this, SLOT(OnSliderValueChanged(double))); + layout->addWidget(m_ThresholdSlider); mainLayout->addLayout(layout); + m_ThresholdSlider->setSingleStep(0.01); QPushButton *okButton = new QPushButton("Confirm Segmentation", this); connect(okButton, SIGNAL(clicked()), this, SLOT(OnAcceptThresholdPreview())); okButton->setFont(f); mainLayout->addWidget(okButton); connect(this, SIGNAL(NewToolAssociated(mitk::Tool *)), this, SLOT(OnNewToolAssociated(mitk::Tool *))); } QmitkBinaryThresholdToolGUI::~QmitkBinaryThresholdToolGUI() { // !!! if (m_BinaryThresholdTool.IsNotNull()) { m_BinaryThresholdTool->IntervalBordersChanged -= mitk::MessageDelegate3( this, &QmitkBinaryThresholdToolGUI::OnThresholdingIntervalBordersChanged); - m_BinaryThresholdTool->ThresholdingValueChanged -= mitk::MessageDelegate1( - this, &QmitkBinaryThresholdToolGUI::OnThresholdingValueChanged); + m_BinaryThresholdTool->ThresholdingValuesChanged -= mitk::MessageDelegate2( + this, &QmitkBinaryThresholdToolGUI::OnThresholdingValuesChanged); } } void QmitkBinaryThresholdToolGUI::OnNewToolAssociated(mitk::Tool *tool) { if (m_BinaryThresholdTool.IsNotNull()) { m_BinaryThresholdTool->IntervalBordersChanged -= mitk::MessageDelegate3( this, &QmitkBinaryThresholdToolGUI::OnThresholdingIntervalBordersChanged); - m_BinaryThresholdTool->ThresholdingValueChanged -= mitk::MessageDelegate1( - this, &QmitkBinaryThresholdToolGUI::OnThresholdingValueChanged); + m_BinaryThresholdTool->ThresholdingValuesChanged -= mitk::MessageDelegate2( + this, &QmitkBinaryThresholdToolGUI::OnThresholdingValuesChanged); } m_BinaryThresholdTool = dynamic_cast(tool); if (m_BinaryThresholdTool.IsNotNull()) { m_BinaryThresholdTool->IntervalBordersChanged += mitk::MessageDelegate3( this, &QmitkBinaryThresholdToolGUI::OnThresholdingIntervalBordersChanged); - m_BinaryThresholdTool->ThresholdingValueChanged += mitk::MessageDelegate1( - this, &QmitkBinaryThresholdToolGUI::OnThresholdingValueChanged); - } -} - -void QmitkBinaryThresholdToolGUI::OnSpinnerValueChanged() -{ - if (m_BinaryThresholdTool.IsNotNull()) - { - m_ChangingSpinner = true; - double doubleVal = m_Spinner->value(); - int intVal = this->DoubleToSliderInt(doubleVal); - m_BinaryThresholdTool->SetThresholdValue(doubleVal); - if (m_ChangingSlider == false) - m_Slider->setValue(intVal); - m_ChangingSpinner = false; - } -} - -void QmitkBinaryThresholdToolGUI::OnSliderValueChanged(int value) -{ - if (m_BinaryThresholdTool.IsNotNull()) - { - m_ChangingSlider = true; - double doubleVal = SliderIntToDouble(value); - if (m_ChangingSpinner == false) - m_Spinner->setValue(doubleVal); - m_ChangingSlider = false; + m_BinaryThresholdTool->ThresholdingValuesChanged += mitk::MessageDelegate2( + this, &QmitkBinaryThresholdToolGUI::OnThresholdingValuesChanged); } } void QmitkBinaryThresholdToolGUI::OnAcceptThresholdPreview() { QmitkConfirmSegmentationDialog dialog; QString segName = QString::fromStdString(m_BinaryThresholdTool->GetCurrentSegmentationName()); dialog.SetSegmentationName(segName); int result = dialog.exec(); switch (result) { case QmitkConfirmSegmentationDialog::CREATE_NEW_SEGMENTATION: m_BinaryThresholdTool->SetOverwriteExistingSegmentation(false); break; case QmitkConfirmSegmentationDialog::OVERWRITE_SEGMENTATION: m_BinaryThresholdTool->SetOverwriteExistingSegmentation(true); break; case QmitkConfirmSegmentationDialog::CANCEL_SEGMENTATION: return; } if (m_BinaryThresholdTool.IsNotNull()) { this->thresholdAccepted(); m_BinaryThresholdTool->AcceptCurrentThresholdValue(); } } void QmitkBinaryThresholdToolGUI::OnThresholdingIntervalBordersChanged(double lower, double upper, bool isFloat) { - m_isFloat = isFloat; - m_RangeMin = lower; - m_RangeMax = upper; - - m_Spinner->setRange(lower, upper); - if (!m_isFloat) + m_InternalUpdate = true; + if (!isFloat) { - m_Slider->setRange(int(lower), int(upper)); - m_Spinner->setDecimals(0); - m_Spinner->setSingleStep(1); + m_ThresholdSlider->setRange(int(lower), int(upper)); + m_ThresholdSlider->setSingleStep(1); + m_ThresholdSlider->setDecimals(0); } else { - m_Slider->setRange(0, 99); - m_Spinner->setDecimals(2); - m_Range = upper - lower; - m_Spinner->setSingleStep(m_Range / 100); + m_ThresholdSlider->setRange(lower, upper); } + m_InternalUpdate = false; } -void QmitkBinaryThresholdToolGUI::OnThresholdingValueChanged(double current) +void QmitkBinaryThresholdToolGUI::OnThresholdingValuesChanged(mitk::ScalarType lower, mitk::ScalarType upper) { - m_Slider->setValue(DoubleToSliderInt(current)); - m_Spinner->setValue(current); + m_ThresholdSlider->setValue(lower); } -double QmitkBinaryThresholdToolGUI::SliderIntToDouble(int val) +void QmitkBinaryThresholdToolGUI::OnSliderValueChanged(double value) { - if (!m_isFloat) - { - return double(val); - } - else - { - return double(val * (m_Range) / 100 + m_RangeMin); - } -} - -int QmitkBinaryThresholdToolGUI::DoubleToSliderInt(double val) -{ - if (!m_isFloat) - { - return int(val); - } - else + if (m_BinaryThresholdTool.IsNotNull() && !m_InternalUpdate) { - int intVal = int(((val - m_RangeMin) / m_Range) * 100); - return intVal; + m_BinaryThresholdTool->SetThresholdValue(value); } } diff --git a/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdToolGUI.h b/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdToolGUI.h index bab07a7824..3698ba2457 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdToolGUI.h +++ b/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdToolGUI.h @@ -1,95 +1,74 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QmitkBinaryThresholdToolGUI_h_Included #define QmitkBinaryThresholdToolGUI_h_Included #include "QmitkToolGUI.h" #include "mitkBinaryThresholdTool.h" #include -#include +#include "ctkSliderWidget.h" -class QSlider; /** \ingroup org_mitk_gui_qt_interactivesegmentation_internal \brief GUI for mitk::BinaryThresholdTool. This GUI shows a slider to change the tool's threshold and an OK button to accept a preview for actual thresholding. There is only a slider for INT values in QT. So, if the working image has a float/double pixeltype, we need to convert the original float intensity into a respective int value for the slider. The slider range is then between 0 and 99. If the pixeltype is INT, then we do not need any conversion. Last contributor: $Author$ */ class MITKSEGMENTATIONUI_EXPORT QmitkBinaryThresholdToolGUI : public QmitkToolGUI { Q_OBJECT public: mitkClassMacro(QmitkBinaryThresholdToolGUI, QmitkToolGUI); itkFactorylessNewMacro(Self); itkCloneMacro(Self); - void OnThresholdingIntervalBordersChanged(double lower, double upper, bool isFloat); - void OnThresholdingValueChanged(double current); + void OnThresholdingIntervalBordersChanged(double lower, double upper, bool isFloat); + void OnThresholdingValuesChanged(mitk::ScalarType lower, mitk::ScalarType upper); signals: /// \brief Emitted when threshold Accepted void thresholdAccepted(); /// \brief Emitted when threshold Canceled void thresholdCanceled(); public slots: protected slots: void OnNewToolAssociated(mitk::Tool *); void OnAcceptThresholdPreview(); - /// \brief Called when Spinner value has changed. Consider: Spinner contains DOUBLE values - void OnSpinnerValueChanged(); - - /// \brief Called when Slider value has changed. Consider: Slider contains INT values - void OnSliderValueChanged(int value); + void OnSliderValueChanged(double value); protected: QmitkBinaryThresholdToolGUI(); ~QmitkBinaryThresholdToolGUI() override; - /// \brief When Slider (int value) has changed, we need to convert it to a respective double value for the spinner - double SliderIntToDouble(int val); - - /// \brief When Spinner (double value) has changed, we need to convert it to a respective int value for the slider - int DoubleToSliderInt(double val); - - QSlider *m_Slider; - QDoubleSpinBox *m_Spinner; - - /// \brief is image float or int? - bool m_isFloat; - - double m_RangeMin; - double m_RangeMax; - double m_Range; - - /// \brief helper bool values to find out, which of the GUI elements has been touched by the user. - bool m_ChangingSlider, m_ChangingSpinner; + ctkSliderWidget* m_ThresholdSlider; + bool m_InternalUpdate = false; mitk::BinaryThresholdTool::Pointer m_BinaryThresholdTool; }; #endif diff --git a/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdULToolGUI.h b/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdULToolGUI.h index 67965c9ef2..7e895adc8f 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdULToolGUI.h +++ b/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdULToolGUI.h @@ -1,62 +1,62 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QmitkBinaryThresholdULToolGUI_h_Included #define QmitkBinaryThresholdULToolGUI_h_Included #include "QmitkToolGUI.h" #include "ctkRangeWidget.h" #include "mitkBinaryThresholdULTool.h" #include /** \ingroup org_mitk_gui_qt_interactivesegmentation_internal \brief GUI for mitk::BinaryThresholdTool. This GUI shows a slider to change the tool's threshold and an OK button to accept a preview for actual thresholding. Last contributor: $Author$ */ class MITKSEGMENTATIONUI_EXPORT QmitkBinaryThresholdULToolGUI : public QmitkToolGUI { Q_OBJECT public: mitkClassMacro(QmitkBinaryThresholdULToolGUI, QmitkToolGUI); itkFactorylessNewMacro(Self); itkCloneMacro(Self); - void OnThresholdingIntervalBordersChanged(double lower, double upper, bool isFloat); + void OnThresholdingIntervalBordersChanged(double lower, double upper, bool isFloat); void OnThresholdingValuesChanged(mitk::ScalarType lower, mitk::ScalarType upper); signals: public slots: protected slots: void OnNewToolAssociated(mitk::Tool *); void OnAcceptThresholdPreview(); void OnThresholdsChanged(double min, double max); protected: QmitkBinaryThresholdULToolGUI(); ~QmitkBinaryThresholdULToolGUI() override; ctkRangeWidget *m_DoubleThresholdSlider; mitk::BinaryThresholdULTool::Pointer m_BinaryThresholdULTool; }; #endif