diff --git a/Modules/Segmentation/Interactions/mitkBinaryThresholdBaseTool.cpp b/Modules/Segmentation/Interactions/mitkBinaryThresholdBaseTool.cpp index f48232e055..a8ee655db0 100644 --- a/Modules/Segmentation/Interactions/mitkBinaryThresholdBaseTool.cpp +++ b/Modules/Segmentation/Interactions/mitkBinaryThresholdBaseTool.cpp @@ -1,466 +1,126 @@ /*============================================================================ 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 "mitkBinaryThresholdBaseTool.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 mitk::BinaryThresholdBaseTool::BinaryThresholdBaseTool() : m_SensibleMinimumThresholdValue(-100), m_SensibleMaximumThresholdValue(+100), 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::BinaryThresholdBaseTool::~BinaryThresholdBaseTool() { } -void mitk::BinaryThresholdBaseTool::Activated() -{ - Superclass::Activated(); - - m_ToolManager->RoiDataChanged += - mitk::MessageDelegate(this, &mitk::BinaryThresholdBaseTool::OnRoiDataChanged); - - m_ToolManager->SelectedTimePointChanged += - 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::BinaryThresholdBaseTool::Deactivated() -{ - m_ToolManager->RoiDataChanged -= - mitk::MessageDelegate(this, &mitk::BinaryThresholdBaseTool::OnRoiDataChanged); - - m_ToolManager->SelectedTimePointChanged -= - 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::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 (nullptr != this->GetPreviewSegmentation()) { - UpdatePreview(); } } -void mitk::BinaryThresholdBaseTool::AcceptCurrentThresholdValue() -{ - CreateNewSegmentationFromThreshold(); - - RenderingManager::GetInstance()->RequestUpdateAll(); - m_ToolManager->ActivateTool(-1); -} - -void mitk::BinaryThresholdBaseTool::CancelThresholding() +void mitk::BinaryThresholdBaseTool::InitiateToolByInput() { - m_ToolManager->ActivateTool(-1); -} - -void mitk::BinaryThresholdBaseTool::SetupPreviewNode() -{ - itk::RGBPixel pixel; - pixel[0] = 0.0f; - pixel[1] = 1.0f; - pixel[2] = 0.0f; - - if (m_NodeForThresholding.IsNotNull()) + const auto referenceImage = this->GetReferenceData(); + if (nullptr != referenceImage) { - Image::Pointer image = dynamic_cast(m_NodeForThresholding->GetData()); - Image::Pointer originalImage = dynamic_cast(m_OriginalImageNode->GetData()); - - if (image.IsNotNull()) + m_SensibleMinimumThresholdValue = std::numeric_limits::max(); + m_SensibleMaximumThresholdValue = std::numeric_limits::lowest(); + Image::StatisticsHolderPointer statistics = referenceImage->GetStatistics(); + for (unsigned int ts = 0; ts < referenceImage->GetTimeSteps(); ++ts) { - 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)) - { - isFloatImage = true; - } - - IntervalBordersChanged.Send(m_SensibleMinimumThresholdValue, m_SensibleMaximumThresholdValue, isFloatImage); - ThresholdingValuesChanged.Send(m_CurrentLowerThresholdValue, m_CurrentUpperThresholdValue); + m_SensibleMinimumThresholdValue = std::min(m_SensibleMinimumThresholdValue, static_cast(statistics->GetScalarValueMin())); + m_SensibleMaximumThresholdValue = std::max(m_SensibleMaximumThresholdValue, static_cast(statistics->GetScalarValueMax())); } - } -} -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::BinaryThresholdBaseTool::TransferImageAtTimeStep(const Image* sourceImage, Image* destinationImage, const TimeStepType timeStep) -{ - try - { - Image::ConstPointer image3D = this->Get3DImage(sourceImage, timeStep); - - if (image3D->GetDimension() == 2) + if (m_LockedUpperThreshold) { - AccessFixedDimensionByItk_2( - image3D, ITKSetVolume, 2, destinationImage, timeStep); + m_CurrentLowerThresholdValue = (m_SensibleMaximumThresholdValue + m_SensibleMinimumThresholdValue) / 2.0; + m_CurrentUpperThresholdValue = m_SensibleMaximumThresholdValue; } else { - AccessFixedDimensionByItk_2( - image3D, ITKSetVolume, 3, destinationImage, timeStep); + double range = m_SensibleMaximumThresholdValue - m_SensibleMinimumThresholdValue; + m_CurrentLowerThresholdValue = m_SensibleMinimumThresholdValue + range / 3.0; + m_CurrentUpperThresholdValue = m_SensibleMinimumThresholdValue + 2 * range / 3.0; } - } - catch (...) - { - Tool::ErrorMessage("Error accessing single time steps of the original image. Cannot create segmentation."); - } -} -void mitk::BinaryThresholdBaseTool::CreateNewSegmentationFromThreshold() -{ - if (m_NodeForThresholding.IsNotNull() && m_ThresholdFeedbackNode.IsNotNull()) - { - Image::Pointer feedBackImage = dynamic_cast(m_ThresholdFeedbackNode->GetData()); - if (feedBackImage.IsNotNull()) + bool isFloatImage = false; + if ((referenceImage->GetPixelType().GetPixelType() == itk::ImageIOBase::SCALAR) && + (referenceImage->GetPixelType().GetComponentType() == itk::ImageIOBase::FLOAT || + referenceImage->GetPixelType().GetComponentType() == itk::ImageIOBase::DOUBLE)) { - // 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->SetBinaryFilter(true); - padFilter->SetUpperThreshold(1); - padFilter->SetLowerThreshold(1); - padFilter->Update(); - - emptySegmentationNode->SetData(padFilter->GetOutput()); - } - - m_ToolManager->SetWorkingData(emptySegmentationNode); - m_ToolManager->GetWorkingData(0)->Modified(); - } + isFloatImage = true; } - } -} - -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_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::BinaryThresholdBaseTool::OnTimePointChanged() -{ - if (m_ThresholdFeedbackNode.IsNotNull() && m_NodeForThresholding.IsNotNull()) - { - if (m_ThresholdFeedbackNode->GetData()->GetTimeSteps() == 1) - { - this->UpdatePreview(); - } + IntervalBordersChanged.Send(m_SensibleMinimumThresholdValue, m_SensibleMaximumThresholdValue, isFloatImage); + ThresholdingValuesChanged.Send(m_CurrentLowerThresholdValue, m_CurrentUpperThresholdValue); } } template 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(lower); filter->SetUpperThreshold(upper); filter->SetInsideValue(1); filter->SetOutsideValue(0); filter->Update(); segmentation->SetVolume((void *)(filter->GetOutput()->GetPixelContainer()->GetBufferPointer()), timeStep); } -template -static void ITKThresholdingOldBinary(const itk::Image *originalImage, - mitk::Image *segmentation, - double lower, - double upper, - unsigned int timeStep) +void mitk::BinaryThresholdBaseTool::DoUpdatePreview(const Image* inputAtTimeStep, Image* previewImage, TimeStepType 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::BinaryThresholdBaseTool::UpdatePreview() -{ - mitk::Image::Pointer thresholdImage = dynamic_cast(m_NodeForThresholding->GetData()); - mitk::Image::Pointer previewImage = dynamic_cast(m_ThresholdFeedbackNode->GetData()); - if (thresholdImage && previewImage) + if (nullptr != inputAtTimeStep && nullptr != 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_CurrentLowerThresholdValue, m_CurrentUpperThresholdValue, timeStep)); - } - else - { - 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 timeStep = previewImage->GetTimeGeometry()->TimePointToTimeStep(timePoint); - - 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(); + AccessByItk_n(inputAtTimeStep, + ITKThresholding, + (previewImage, m_CurrentLowerThresholdValue, m_CurrentUpperThresholdValue, timeStep)); } } diff --git a/Modules/Segmentation/Interactions/mitkBinaryThresholdBaseTool.h b/Modules/Segmentation/Interactions/mitkBinaryThresholdBaseTool.h index dece9ae498..cdc15f18be 100644 --- a/Modules/Segmentation/Interactions/mitkBinaryThresholdBaseTool.h +++ b/Modules/Segmentation/Interactions/mitkBinaryThresholdBaseTool.h @@ -1,98 +1,70 @@ /*============================================================================ 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 mitkBinaryThresholdBaseTool_h_Included #define mitkBinaryThresholdBaseTool_h_Included -#include "mitkAutoSegmentationTool.h" +#include "mitkAutoSegmentationWithPreviewTool.h" #include "mitkCommon.h" #include "mitkDataNode.h" #include #include #include namespace mitk { /** \brief Base class for binary threshold tools. \ingroup ToolManagerEtAl \sa mitk::Tool \sa QmitkInteractiveSegmentation */ - class MITKSEGMENTATION_EXPORT BinaryThresholdBaseTool : public AutoSegmentationTool + class MITKSEGMENTATION_EXPORT BinaryThresholdBaseTool : public AutoSegmentationWithPreviewTool { public: Message3 IntervalBordersChanged; Message2 ThresholdingValuesChanged; - mitkClassMacro(BinaryThresholdBaseTool, AutoSegmentationTool); - - void Activated() override; - void Deactivated() override; + mitkClassMacro(BinaryThresholdBaseTool, AutoSegmentationWithPreviewTool); virtual void SetThresholdValues(double lower, double upper); - virtual void AcceptCurrentThresholdValue(); - virtual void CancelThresholding(); - - itkSetMacro(CreateAllTimeSteps, bool); - itkGetMacro(CreateAllTimeSteps, bool); - itkBooleanMacro(CreateAllTimeSteps); - protected: BinaryThresholdBaseTool(); // purposely hidden ~BinaryThresholdBaseTool() override; itkSetMacro(LockedUpperThreshold, bool); itkGetMacro(LockedUpperThreshold, bool); itkBooleanMacro(LockedUpperThreshold); itkGetMacro(SensibleMinimumThresholdValue, ScalarType); itkGetMacro(SensibleMaximumThresholdValue, ScalarType); - private: - void SetupPreviewNode(); - - 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; + void InitiateToolByInput() override; + void DoUpdatePreview(const Image* inputAtTimeStep, Image* previewImage, TimeStepType timeStep) override; + private: ScalarType m_SensibleMinimumThresholdValue; ScalarType m_SensibleMaximumThresholdValue; ScalarType m_CurrentLowerThresholdValue; ScalarType m_CurrentUpperThresholdValue; - bool m_IsOldBinary = false; - - /** Indicates if Accepting the threshold should transfer/create the segmentations - of all time steps (true) or only of the currently selected timepoint (false).*/ - bool m_CreateAllTimeSteps = false; - /** Indicates if the tool should behave like a single threshold tool (true) or like a upper/lower threshold tool (false)*/ bool m_LockedUpperThreshold = false; }; } // namespace #endif diff --git a/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdToolGUI.cpp b/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdToolGUI.cpp index d26c729fa2..7c720d4a58 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdToolGUI.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdToolGUI.cpp @@ -1,144 +1,168 @@ /*============================================================================ 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 #include #include #include +#include MITK_TOOL_GUI_MACRO(MITKSEGMENTATIONUI_EXPORT, QmitkBinaryThresholdToolGUI, "") QmitkBinaryThresholdToolGUI::QmitkBinaryThresholdToolGUI() : 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_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); m_CheckProcessAll = new QCheckBox("Process all time steps", this); m_CheckProcessAll->setChecked(false); + m_CheckProcessAll->setToolTip("Process/overwrite all time steps of the dynamic segmentation and not just the currently visible time step."); + mainLayout->addWidget(m_CheckProcessAll); m_CheckCreateNew = new QCheckBox("Create as new segmentation", this); m_CheckCreateNew->setChecked(false); + m_CheckCreateNew->setToolTip("Add the confirmed segmentation as a new segmentation instead of overwriting the currently selected."); mainLayout->addWidget(m_CheckCreateNew); connect(this, SIGNAL(NewToolAssociated(mitk::Tool *)), this, SLOT(OnNewToolAssociated(mitk::Tool *))); } QmitkBinaryThresholdToolGUI::~QmitkBinaryThresholdToolGUI() { if (m_BinaryThresholdTool.IsNotNull()) { + m_BinaryThresholdTool->CurrentlyBusy -= + mitk::MessageDelegate1(this, &QmitkBinaryThresholdToolGUI::BusyStateChanged); m_BinaryThresholdTool->IntervalBordersChanged -= mitk::MessageDelegate3( this, &QmitkBinaryThresholdToolGUI::OnThresholdingIntervalBordersChanged); m_BinaryThresholdTool->ThresholdingValuesChanged -= mitk::MessageDelegate2( this, &QmitkBinaryThresholdToolGUI::OnThresholdingValuesChanged); } } void QmitkBinaryThresholdToolGUI::OnNewToolAssociated(mitk::Tool *tool) { if (m_BinaryThresholdTool.IsNotNull()) { + m_BinaryThresholdTool->CurrentlyBusy -= + mitk::MessageDelegate1(this, &QmitkBinaryThresholdToolGUI::BusyStateChanged); m_BinaryThresholdTool->IntervalBordersChanged -= mitk::MessageDelegate3( this, &QmitkBinaryThresholdToolGUI::OnThresholdingIntervalBordersChanged); m_BinaryThresholdTool->ThresholdingValuesChanged -= mitk::MessageDelegate2( this, &QmitkBinaryThresholdToolGUI::OnThresholdingValuesChanged); } m_BinaryThresholdTool = dynamic_cast(tool); if (m_BinaryThresholdTool.IsNotNull()) { + m_BinaryThresholdTool->CurrentlyBusy += + mitk::MessageDelegate1(this, &QmitkBinaryThresholdToolGUI::BusyStateChanged); m_BinaryThresholdTool->IntervalBordersChanged += mitk::MessageDelegate3( this, &QmitkBinaryThresholdToolGUI::OnThresholdingIntervalBordersChanged); m_BinaryThresholdTool->ThresholdingValuesChanged += mitk::MessageDelegate2( this, &QmitkBinaryThresholdToolGUI::OnThresholdingValuesChanged); m_BinaryThresholdTool->SetOverwriteExistingSegmentation(true); m_CheckProcessAll->setVisible(m_BinaryThresholdTool->GetTargetSegmentationNode()->GetData()->GetTimeSteps()>1); } } void QmitkBinaryThresholdToolGUI::OnAcceptThresholdPreview() { if (m_BinaryThresholdTool.IsNotNull()) { if (m_CheckCreateNew->isChecked()) { m_BinaryThresholdTool->SetOverwriteExistingSegmentation(false); } else { m_BinaryThresholdTool->SetOverwriteExistingSegmentation(true); } m_BinaryThresholdTool->SetCreateAllTimeSteps(m_CheckProcessAll->isChecked()); this->thresholdAccepted(); - m_BinaryThresholdTool->AcceptCurrentThresholdValue(); + m_BinaryThresholdTool->ConfirmSegmentation(); } } void QmitkBinaryThresholdToolGUI::OnThresholdingIntervalBordersChanged(double lower, double upper, bool isFloat) { m_InternalUpdate = true; if (!isFloat) { m_ThresholdSlider->setRange(int(lower), int(upper)); m_ThresholdSlider->setSingleStep(1); m_ThresholdSlider->setDecimals(0); } else { m_ThresholdSlider->setRange(lower, upper); } m_InternalUpdate = false; } void QmitkBinaryThresholdToolGUI::OnThresholdingValuesChanged(mitk::ScalarType lower, mitk::ScalarType /*upper*/) { m_ThresholdSlider->setValue(lower); } void QmitkBinaryThresholdToolGUI::OnSliderValueChanged(double value) { if (m_BinaryThresholdTool.IsNotNull() && !m_InternalUpdate) { m_BinaryThresholdTool->SetThresholdValue(value); } } + +void QmitkBinaryThresholdToolGUI::BusyStateChanged(bool value) +{ + if (value) + { + QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); + } + else + { + QApplication::restoreOverrideCursor(); + } + + m_ThresholdSlider->setEnabled(!value); +} diff --git a/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdToolGUI.h b/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdToolGUI.h index 3d1e396cd2..5696c1ff98 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdToolGUI.h +++ b/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdToolGUI.h @@ -1,78 +1,80 @@ /*============================================================================ 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 "ctkSliderWidget.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. 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 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(); void OnSliderValueChanged(double value); protected: QmitkBinaryThresholdToolGUI(); ~QmitkBinaryThresholdToolGUI() override; + void BusyStateChanged(bool) override; + ctkSliderWidget* m_ThresholdSlider = nullptr; QCheckBox* m_CheckProcessAll = nullptr; QCheckBox* m_CheckCreateNew = nullptr; bool m_InternalUpdate = false; mitk::BinaryThresholdTool::Pointer m_BinaryThresholdTool; }; #endif diff --git a/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdULToolGUI.cpp b/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdULToolGUI.cpp index 8f283ae403..5954acff4c 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdULToolGUI.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdULToolGUI.cpp @@ -1,141 +1,163 @@ /*============================================================================ 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 "QmitkBinaryThresholdULToolGUI.h" #include #include #include #include +#include MITK_TOOL_GUI_MACRO(MITKSEGMENTATIONUI_EXPORT, QmitkBinaryThresholdULToolGUI, "") QmitkBinaryThresholdULToolGUI::QmitkBinaryThresholdULToolGUI() : 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_DoubleThresholdSlider = new ctkRangeWidget(); connect( m_DoubleThresholdSlider, SIGNAL(valuesChanged(double, double)), this, SLOT(OnThresholdsChanged(double, double))); layout->addWidget(m_DoubleThresholdSlider); mainLayout->addLayout(layout); m_DoubleThresholdSlider->setSingleStep(0.01); QPushButton *okButton = new QPushButton("Confirm Segmentation", this); connect(okButton, SIGNAL(clicked()), this, SLOT(OnAcceptThresholdPreview())); okButton->setFont(f); mainLayout->addWidget(okButton); m_CheckProcessAll = new QCheckBox("Process all time steps", this); m_CheckProcessAll->setChecked(false); + m_CheckProcessAll->setToolTip("Process/overwrite all time steps of the dynamic segmentation and not just the currently visible time step."); mainLayout->addWidget(m_CheckProcessAll); m_CheckCreateNew = new QCheckBox("Create as new segmentation", this); m_CheckCreateNew->setChecked(false); + m_CheckCreateNew->setToolTip("Add the confirmed segmentation as a new segmentation instead of overwriting the currently selected."); mainLayout->addWidget(m_CheckCreateNew); connect(this, SIGNAL(NewToolAssociated(mitk::Tool *)), this, SLOT(OnNewToolAssociated(mitk::Tool *))); } QmitkBinaryThresholdULToolGUI::~QmitkBinaryThresholdULToolGUI() { - // !!! if (m_BinaryThresholdULTool.IsNotNull()) { + m_BinaryThresholdULTool->CurrentlyBusy -= + mitk::MessageDelegate1(this, &QmitkBinaryThresholdULToolGUI::BusyStateChanged); m_BinaryThresholdULTool->IntervalBordersChanged -= mitk::MessageDelegate3( this, &QmitkBinaryThresholdULToolGUI::OnThresholdingIntervalBordersChanged); m_BinaryThresholdULTool->ThresholdingValuesChanged -= mitk::MessageDelegate2( this, &QmitkBinaryThresholdULToolGUI::OnThresholdingValuesChanged); } } void QmitkBinaryThresholdULToolGUI::OnNewToolAssociated(mitk::Tool *tool) { if (m_BinaryThresholdULTool.IsNotNull()) { + m_BinaryThresholdULTool->CurrentlyBusy -= + mitk::MessageDelegate1(this, &QmitkBinaryThresholdULToolGUI::BusyStateChanged); m_BinaryThresholdULTool->IntervalBordersChanged -= mitk::MessageDelegate3( this, &QmitkBinaryThresholdULToolGUI::OnThresholdingIntervalBordersChanged); m_BinaryThresholdULTool->ThresholdingValuesChanged -= mitk::MessageDelegate2( this, &QmitkBinaryThresholdULToolGUI::OnThresholdingValuesChanged); } m_BinaryThresholdULTool = dynamic_cast(tool); if (m_BinaryThresholdULTool.IsNotNull()) { + m_BinaryThresholdULTool->CurrentlyBusy += + mitk::MessageDelegate1(this, &QmitkBinaryThresholdULToolGUI::BusyStateChanged); m_BinaryThresholdULTool->IntervalBordersChanged += mitk::MessageDelegate3( this, &QmitkBinaryThresholdULToolGUI::OnThresholdingIntervalBordersChanged); m_BinaryThresholdULTool->ThresholdingValuesChanged += mitk::MessageDelegate2( this, &QmitkBinaryThresholdULToolGUI::OnThresholdingValuesChanged); m_BinaryThresholdULTool->SetOverwriteExistingSegmentation(true); m_CheckProcessAll->setVisible(m_BinaryThresholdULTool->GetTargetSegmentationNode()->GetData()->GetTimeSteps() > 1); } } void QmitkBinaryThresholdULToolGUI::OnAcceptThresholdPreview() { if (m_BinaryThresholdULTool.IsNotNull()) { if (m_CheckCreateNew->isChecked()) { m_BinaryThresholdULTool->SetOverwriteExistingSegmentation(false); } else { m_BinaryThresholdULTool->SetOverwriteExistingSegmentation(true); } m_BinaryThresholdULTool->SetCreateAllTimeSteps(m_CheckProcessAll->isChecked()); - m_BinaryThresholdULTool->AcceptCurrentThresholdValue(); + m_BinaryThresholdULTool->ConfirmSegmentation(); } } void QmitkBinaryThresholdULToolGUI::OnThresholdingIntervalBordersChanged(double lower, double upper, bool isFloat) { if (!isFloat) { m_DoubleThresholdSlider->setRange(int(lower), int(upper)); m_DoubleThresholdSlider->setSingleStep(1); m_DoubleThresholdSlider->setDecimals(0); } else { m_DoubleThresholdSlider->setRange(lower, upper); } } void QmitkBinaryThresholdULToolGUI::OnThresholdingValuesChanged(mitk::ScalarType lower, mitk::ScalarType upper) { m_DoubleThresholdSlider->setValues(lower, upper); } void QmitkBinaryThresholdULToolGUI::OnThresholdsChanged(double min, double max) { m_BinaryThresholdULTool->SetThresholdValues(min, max); } + +void QmitkBinaryThresholdULToolGUI::BusyStateChanged(bool value) +{ + if (value) + { + QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); + } + else + { + QApplication::restoreOverrideCursor(); + } + + m_DoubleThresholdSlider->setEnabled(!value); +} diff --git a/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdULToolGUI.h b/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdULToolGUI.h index 3e178be366..ec0c130821 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdULToolGUI.h +++ b/Modules/SegmentationUI/Qmitk/QmitkBinaryThresholdULToolGUI.h @@ -1,66 +1,68 @@ /*============================================================================ 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 #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 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; + void BusyStateChanged(bool) override; + ctkRangeWidget *m_DoubleThresholdSlider; QCheckBox* m_CheckProcessAll = nullptr; QCheckBox* m_CheckCreateNew = nullptr; mitk::BinaryThresholdULTool::Pointer m_BinaryThresholdULTool; }; #endif