diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkMorphologicalOperationsWidget.cpp b/Modules/SegmentationUI/SegmentationUtilities/QmitkMorphologicalOperationsWidget.cpp index ef4c3bc979..8d9fb53c54 100644 --- a/Modules/SegmentationUI/SegmentationUtilities/QmitkMorphologicalOperationsWidget.cpp +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkMorphologicalOperationsWidget.cpp @@ -1,254 +1,213 @@ /*============================================================================ 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 "QmitkMorphologicalOperationsWidget.h" #include +#include #include -#include - -static const char* const HelpText = "Select a segmentation above"; +#include +#include QmitkMorphologicalOperationsWidget::QmitkMorphologicalOperationsWidget(mitk::DataStorage* dataStorage, QWidget* parent) : QWidget(parent) { m_Controls = new Ui::QmitkMorphologicalOperationsWidgetControls; m_Controls->setupUi(this); - m_Controls->dataSelectionWidget->SetDataStorage(dataStorage); - m_Controls->dataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::SegmentationPredicate); - m_Controls->dataSelectionWidget->SetHelpText(HelpText); + m_Controls->segNodeSelector->SetDataStorage(dataStorage); + m_Controls->segNodeSelector->SetNodePredicate(mitk::GetMultiLabelSegmentationPredicate()); + m_Controls->segNodeSelector->SetSelectionIsOptional(false); + m_Controls->segNodeSelector->SetInvalidInfo(QStringLiteral("Please select segmentation")); + m_Controls->segNodeSelector->SetPopUpTitel(QStringLiteral("Select segmentation")); + m_Controls->segNodeSelector->SetPopUpHint(QStringLiteral("Select the segmentation that should be modified.")); connect(m_Controls->btnClosing, SIGNAL(clicked()), this, SLOT(OnClosingButtonClicked())); connect(m_Controls->btnOpening, SIGNAL(clicked()), this, SLOT(OnOpeningButtonClicked())); connect(m_Controls->btnDilatation, SIGNAL(clicked()), this, SLOT(OnDilatationButtonClicked())); connect(m_Controls->btnErosion, SIGNAL(clicked()), this, SLOT(OnErosionButtonClicked())); connect(m_Controls->btnFillHoles, SIGNAL(clicked()), this, SLOT(OnFillHolesButtonClicked())); connect(m_Controls->radioButtonMorphoCross, SIGNAL(clicked()), this, SLOT(OnRadioButtonsClicked())); connect(m_Controls->radioButtonMorphoBall, SIGNAL(clicked()), this, SLOT(OnRadioButtonsClicked())); - connect(m_Controls->dataSelectionWidget, SIGNAL(SelectionChanged(unsigned int, const mitk::DataNode*)), this, SLOT(OnSelectionChanged(unsigned int, const mitk::DataNode*))); + connect(m_Controls->segNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, + this, &QmitkMorphologicalOperationsWidget::OnSelectionChanged); + + auto widget = this; + connect(m_Controls->labelInspector, &QmitkMultiLabelInspector::CurrentSelectionChanged, + this, [widget](mitk::LabelSetImage::LabelValueVectorType labels) {widget->ConfigureButtons(); }); - if (m_Controls->dataSelectionWidget->GetSelection(0).IsNotNull()) - this->OnSelectionChanged(0, m_Controls->dataSelectionWidget->GetSelection(0)); + + m_Controls->segNodeSelector->SetAutoSelectNewNodes(true); } QmitkMorphologicalOperationsWidget::~QmitkMorphologicalOperationsWidget() { + m_Controls->labelInspector->SetMultiLabelNode(nullptr); } -void QmitkMorphologicalOperationsWidget::OnSelectionChanged(unsigned int, const mitk::DataNode*) +void QmitkMorphologicalOperationsWidget::OnSelectionChanged(QmitkAbstractNodeSelectionWidget::NodeList /*nodes*/) { - QmitkDataSelectionWidget* dataSelectionWidget = m_Controls->dataSelectionWidget; - mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(0); + auto node = m_Controls->segNodeSelector->GetSelectedNode(); + m_Controls->labelInspector->SetMultiLabelNode(node); - if (node.IsNotNull()) - { - m_Controls->dataSelectionWidget->SetHelpText(""); - this->EnableButtons(true); - } - else - { - m_Controls->dataSelectionWidget->SetHelpText(HelpText); - this->EnableButtons(false); - } + this->ConfigureButtons(); } -void QmitkMorphologicalOperationsWidget::EnableButtons(bool enable) +void QmitkMorphologicalOperationsWidget::ConfigureButtons() { + auto node = m_Controls->segNodeSelector->GetSelectedNode(); + + bool enable = node.IsNotNull() && !m_Controls->labelInspector->GetSelectedLabels().empty(); + m_Controls->btnClosing->setEnabled(enable); m_Controls->btnDilatation->setEnabled(enable); m_Controls->btnErosion->setEnabled(enable); m_Controls->btnFillHoles->setEnabled(enable); m_Controls->btnOpening->setEnabled(enable); } void QmitkMorphologicalOperationsWidget::OnRadioButtonsClicked() { bool enable = m_Controls->radioButtonMorphoBall->isChecked(); m_Controls->sliderMorphFactor->setEnabled(enable); m_Controls->spinBoxMorphFactor->setEnabled(enable); } void QmitkMorphologicalOperationsWidget::OnClosingButtonClicked() { - QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - - QmitkDataSelectionWidget* dataSelectionWidget = m_Controls->dataSelectionWidget; - mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(0); - mitk::Image::Pointer image = static_cast(node->GetData()); - mitk::MorphologicalOperations::StructuralElementType structuralElement = CreateStructerElement_UI(); - try - { - int factor = m_Controls->spinBoxMorphFactor->isEnabled() - ? m_Controls->spinBoxMorphFactor->value() - : 1; - - mitk::MorphologicalOperations::Closing(image, factor, structuralElement); - } - catch (const itk::ExceptionObject& exception) - { - MITK_WARN << "Exception caught: " << exception.GetDescription(); - - QApplication::restoreOverrideCursor(); - return; - } - - node->SetData(image); - - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - QApplication::restoreOverrideCursor(); + this->Processing(mitk::MorphologicalOperations::Closing, "Closing"); } void QmitkMorphologicalOperationsWidget::OnOpeningButtonClicked() { - QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - - QmitkDataSelectionWidget* dataSelectionWidget = m_Controls->dataSelectionWidget; - mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(0); - mitk::Image::Pointer image = static_cast(node->GetData()); - - mitk::MorphologicalOperations::StructuralElementType structuralElement = CreateStructerElement_UI(); - - try - { - int factor = m_Controls->spinBoxMorphFactor->isEnabled() - ? m_Controls->spinBoxMorphFactor->value() - : 1; - - mitk::MorphologicalOperations::Opening(image, factor, structuralElement); - } - catch (const itk::ExceptionObject& exception) - { - MITK_WARN << "Exception caught: " << exception.GetDescription(); - - QApplication::restoreOverrideCursor(); - return; - } - - node->SetData(image); - - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - QApplication::restoreOverrideCursor(); + this->Processing(mitk::MorphologicalOperations::Opening, "Open"); } void QmitkMorphologicalOperationsWidget::OnDilatationButtonClicked() { - QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + this->Processing(mitk::MorphologicalOperations::Dilate, "Dilate"); +} - QmitkDataSelectionWidget* dataSelectionWidget = m_Controls->dataSelectionWidget; - mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(0); - mitk::Image::Pointer image = static_cast(node->GetData()); - mitk::MorphologicalOperations::StructuralElementType structuralElement = this->CreateStructerElement_UI(); +void QmitkMorphologicalOperationsWidget::OnErosionButtonClicked() +{ + this->Processing(mitk::MorphologicalOperations::Erode, "Erode"); +} - try - { - int factor = m_Controls->spinBoxMorphFactor->isEnabled() - ? m_Controls->spinBoxMorphFactor->value() - : 1; +void QmitkMorphologicalOperationsWidget::OnFillHolesButtonClicked() +{ + auto wrapper = [](mitk::Image::Pointer& image, int, + mitk::MorphologicalOperations::StructuralElementType) + { + mitk::MorphologicalOperations::FillHoles(image); + }; - mitk::MorphologicalOperations::Dilate(image, factor, structuralElement); - } - catch (const itk::ExceptionObject& exception) - { - MITK_WARN << "Exception caught: " << exception.GetDescription(); + this->Processing(wrapper, "FillHoles"); +} - QApplication::restoreOverrideCursor(); - return; +mitk::MorphologicalOperations::StructuralElementType QmitkMorphologicalOperationsWidget::CreateStructerElement_UI() const +{ + bool ball = m_Controls->radioButtonMorphoBall->isChecked(); + int accum_flag = 0; + if(ball){ + if(m_Controls->planeSelectionComboBox->currentIndex() == 0) accum_flag = mitk::MorphologicalOperations::Ball; // 3D Operation + if(m_Controls->planeSelectionComboBox->currentIndex() == 1) accum_flag = mitk::MorphologicalOperations::Ball_Axial; // 2D Operation - Axial plane + if(m_Controls->planeSelectionComboBox->currentIndex() == 2) accum_flag = mitk::MorphologicalOperations::Ball_Sagittal; // 2D Operation - Sagittal plane + if(m_Controls->planeSelectionComboBox->currentIndex() == 3) accum_flag = mitk::MorphologicalOperations::Ball_Coronal; // 2D Operation - Coronal plane + }else{ + if(m_Controls->planeSelectionComboBox->currentIndex() == 0) accum_flag = mitk::MorphologicalOperations::Cross; + if(m_Controls->planeSelectionComboBox->currentIndex() == 1) accum_flag = mitk::MorphologicalOperations::Cross_Axial; + if(m_Controls->planeSelectionComboBox->currentIndex() == 2) accum_flag = mitk::MorphologicalOperations::Cross_Sagittal; + if(m_Controls->planeSelectionComboBox->currentIndex() == 3) accum_flag = mitk::MorphologicalOperations::Cross_Coronal; } + return (mitk::MorphologicalOperations::StructuralElementType)accum_flag; +} - node->SetData(image); +mitk::Image::Pointer QmitkMorphologicalOperationsWidget::GetSelectedLabelMask() const +{ + auto seg = m_Controls->labelInspector->GetMultiLabelSegmentation(); + if (seg == nullptr) mitkThrow() << "Widget is in invalid state. Processing was triggered with no segmentation selected."; - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - QApplication::restoreOverrideCursor(); + auto labels = m_Controls->labelInspector->GetSelectedLabels(); + if (labels.empty()) mitkThrow() << "Widget is in invalid state. Processing was triggered with no label selected."; + + return mitk::CreateLabelMask(seg, labels.front(), true); } -void QmitkMorphologicalOperationsWidget::OnErosionButtonClicked() +void QmitkMorphologicalOperationsWidget::SaveResultLabelMask(const mitk::Image* resultMask, const std::string& labelName) const { - QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + auto seg = m_Controls->labelInspector->GetMultiLabelSegmentation(); + if (seg == nullptr) mitkThrow() << "Widget is in invalid state. Processing was triggered with no segmentation selected."; - QmitkDataSelectionWidget* dataSelectionWidget = m_Controls->dataSelectionWidget; - mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(0); - mitk::Image::Pointer image = static_cast(node->GetData()); -mitk::MorphologicalOperations::StructuralElementType structuralElement = CreateStructerElement_UI(); + auto labels = m_Controls->labelInspector->GetSelectedLabels(); + if (labels.empty()) mitkThrow() << "Widget is in invalid state. Processing was triggered with no label selected."; - try + if (m_Controls->checkNewLabel->isChecked()) { - int factor = m_Controls->spinBoxMorphFactor->isEnabled() - ? m_Controls->spinBoxMorphFactor->value() - : 1; - - mitk::MorphologicalOperations::Erode(image, factor, structuralElement); + auto groupID = seg->AddLayer(); + auto newLabel = mitk::LabelSetImageHelper::CreateNewLabel(seg, labelName, true); + seg->AddLabelWithContent(newLabel, resultMask, groupID, 1); } - catch (const itk::ExceptionObject& exception) + else { - MITK_WARN << "Exception caught: " << exception.GetDescription(); - - QApplication::restoreOverrideCursor(); - return; - } - - node->SetData(image); + auto groupID = seg->GetGroupIndexOfLabel(labels.front()); + mitk::TransferLabelContent(resultMask, seg->GetGroupImage(groupID), seg->GetConstLabelsByValue(seg->GetLabelValuesByGroup(groupID)), + mitk::LabelSetImage::UNLABELED_VALUE, mitk::LabelSetImage::UNLABELED_VALUE, false, { {1, labels.front()} }, + mitk::MultiLabelSegmentation::MergeStyle::Replace, mitk::MultiLabelSegmentation::OverwriteStyle::RegardLocks); + } + m_Controls->labelInspector->GetMultiLabelSegmentation()->Modified(); + m_Controls->labelInspector->GetMultiLabelNode()->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - QApplication::restoreOverrideCursor(); } -void QmitkMorphologicalOperationsWidget::OnFillHolesButtonClicked() +void QmitkMorphologicalOperationsWidget::Processing(std::function morphFunction, const std::string& opsName) const { QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + mitk::ProgressBar::GetInstance()->Reset(); + mitk::ProgressBar::GetInstance()->AddStepsToDo(3); - QmitkDataSelectionWidget* dataSelectionWidget = m_Controls->dataSelectionWidget; - mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(0); - mitk::Image::Pointer image = static_cast(node->GetData()); + mitk::Image::Pointer image = this->GetSelectedLabelMask(); + mitk::ProgressBar::GetInstance()->Progress(); + + mitk::MorphologicalOperations::StructuralElementType structuralElement = CreateStructerElement_UI(); + + int factor = m_Controls->spinBoxMorphFactor->isEnabled() + ? m_Controls->spinBoxMorphFactor->value() + : 1; try { - mitk::MorphologicalOperations::FillHoles(image); + morphFunction(image, factor, structuralElement); } catch (const itk::ExceptionObject& exception) { MITK_WARN << "Exception caught: " << exception.GetDescription(); QApplication::restoreOverrideCursor(); + mitk::ProgressBar::GetInstance()->Reset(); return; } + mitk::ProgressBar::GetInstance()->Progress(); - node->SetData(image); + auto seg = m_Controls->labelInspector->GetMultiLabelSegmentation(); + auto labels = m_Controls->labelInspector->GetSelectedLabels(); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - QApplication::restoreOverrideCursor(); -} + std::stringstream labelName; + labelName << opsName << " " << seg->GetLabel(labels.front())->GetName() << " (r=" << factor << ")"; + this->SaveResultLabelMask(image, labelName.str()); + mitk::ProgressBar::GetInstance()->Progress(); -mitk::MorphologicalOperations::StructuralElementType QmitkMorphologicalOperationsWidget::CreateStructerElement_UI() -{ - bool ball = m_Controls->radioButtonMorphoBall->isChecked(); - int accum_flag = 0; - if(ball){ - if(m_Controls->planeSelectionComboBox->currentIndex() == 0) accum_flag = mitk::MorphologicalOperations::Ball; // 3D Operation - if(m_Controls->planeSelectionComboBox->currentIndex() == 1) accum_flag = mitk::MorphologicalOperations::Ball_Axial; // 2D Operation - Axial plane - if(m_Controls->planeSelectionComboBox->currentIndex() == 2) accum_flag = mitk::MorphologicalOperations::Ball_Sagittal; // 2D Operation - Sagittal plane - if(m_Controls->planeSelectionComboBox->currentIndex() == 3) accum_flag = mitk::MorphologicalOperations::Ball_Coronal; // 2D Operation - Coronal plane - }else{ - if(m_Controls->planeSelectionComboBox->currentIndex() == 0) accum_flag = mitk::MorphologicalOperations::Cross; - if(m_Controls->planeSelectionComboBox->currentIndex() == 1) accum_flag = mitk::MorphologicalOperations::Cross_Axial; - if(m_Controls->planeSelectionComboBox->currentIndex() == 2) accum_flag = mitk::MorphologicalOperations::Cross_Sagittal; - if(m_Controls->planeSelectionComboBox->currentIndex() == 3) accum_flag = mitk::MorphologicalOperations::Cross_Coronal; - } - return (mitk::MorphologicalOperations::StructuralElementType)accum_flag; -} + QApplication::restoreOverrideCursor(); + mitk::ProgressBar::GetInstance()->Reset(); +} \ No newline at end of file diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkMorphologicalOperationsWidget.h b/Modules/SegmentationUI/SegmentationUtilities/QmitkMorphologicalOperationsWidget.h index 5e3862e85e..38ef3fc755 100644 --- a/Modules/SegmentationUI/SegmentationUtilities/QmitkMorphologicalOperationsWidget.h +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkMorphologicalOperationsWidget.h @@ -1,61 +1,71 @@ /*============================================================================ 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 QmitkMorphologicalOperationsWidget_h #define QmitkMorphologicalOperationsWidget_h #include #include #include +#include + #include namespace Ui { class QmitkMorphologicalOperationsWidgetControls; } namespace mitk { class DataNode; class DataStorage; } /** \brief GUI class for morphological segmentation tools. */ class MITKSEGMENTATIONUI_EXPORT QmitkMorphologicalOperationsWidget : public QWidget { Q_OBJECT public: explicit QmitkMorphologicalOperationsWidget(mitk::DataStorage* dataStorage, QWidget* parent = nullptr); ~QmitkMorphologicalOperationsWidget() override; public slots: void OnClosingButtonClicked(); void OnOpeningButtonClicked(); void OnDilatationButtonClicked(); void OnErosionButtonClicked(); void OnFillHolesButtonClicked(); - void OnSelectionChanged(unsigned int index, const mitk::DataNode* selection); + void OnSelectionChanged(QmitkAbstractNodeSelectionWidget::NodeList nodes); void OnRadioButtonsClicked(); protected: - void EnableButtons(bool enable); + void ConfigureButtons(); + + using MorphFunctionType = void(mitk::Image::Pointer& image, int factor, + mitk::MorphologicalOperations::StructuralElementType structuralElement); + void Processing(std::function morphFunction, const std::string& opsName) const; private: + mitk::Image::Pointer GetSelectedLabelMask() const; + void SaveResultLabelMask(const mitk::Image* resultMask, const std::string& labelName) const; + + mitk::MorphologicalOperations::StructuralElementType CreateStructerElement_UI() const; + Ui::QmitkMorphologicalOperationsWidgetControls* m_Controls; - mitk::MorphologicalOperations::StructuralElementType CreateStructerElement_UI(); }; #endif diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkMorphologicalOperationsWidgetControls.ui b/Modules/SegmentationUI/SegmentationUtilities/QmitkMorphologicalOperationsWidgetControls.ui index bf923876d3..675faf17bd 100644 --- a/Modules/SegmentationUI/SegmentationUtilities/QmitkMorphologicalOperationsWidgetControls.ui +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkMorphologicalOperationsWidgetControls.ui @@ -1,328 +1,338 @@ QmitkMorphologicalOperationsWidgetControls 0 0 - 184 - 377 + 212 + 416 - - - - 0 - 0 - + + + + + + + + + If checked the result of the operation will be added as new label in a new group. Otherwise the selected label will be directly altered (label locks will be regarded). + + + Add result as new label + + + true Structuring Element Ball true Cross 3D Operation 2D Operation - Axial 2D Operation - Sagittal 2D Operation - Coronal Radius 1 20 1 Qt::Horizontal 1 20 false 0 0 Dilation - - :/Qmitk/Dilate_48x48.png:/Qmitk/Dilate_48x48.png - + + :/Qmitk/Dilate_48x48.png:/Qmitk/Dilate_48x48.png 32 32 Qt::ToolButtonTextUnderIcon false 0 0 Erosion - - :/Qmitk/Erode_48x48.png:/Qmitk/Erode_48x48.png - + + :/Qmitk/Erode_48x48.png:/Qmitk/Erode_48x48.png 32 32 Qt::ToolButtonTextUnderIcon false 0 0 Closing - - :/Qmitk/Closing_48x48.png:/Qmitk/Closing_48x48.png - + + :/Qmitk/Closing_48x48.png:/Qmitk/Closing_48x48.png 32 32 Qt::ToolButtonTextUnderIcon false 0 0 Opening - - :/Qmitk/Opening_48x48.png:/Qmitk/Opening_48x48.png - + + :/Qmitk/Opening_48x48.png:/Qmitk/Opening_48x48.png 32 32 Qt::ToolButtonTextUnderIcon false 0 0 Globally fills holes in segmentation (structuring element and radius not required) Fill Holes - - :/Qmitk/FillHoles_48x48.png:/Qmitk/FillHoles_48x48.png - + + :/Qmitk/FillHoles_48x48.png:/Qmitk/FillHoles_48x48.png 32 32 Qt::ToolButtonTextUnderIcon Qt::Vertical 20 40 - QmitkDataSelectionWidget + QmitkSingleNodeSelectionWidget + QWidget +
QmitkSingleNodeSelectionWidget.h
+ 1 +
+ + QmitkMultiLabelInspector QWidget -
QmitkDataSelectionWidget.h
+
QmitkMultiLabelInspector.h
1
sliderMorphFactor valueChanged(int) spinBoxMorphFactor setValue(int) 240 27 766 36 spinBoxMorphFactor valueChanged(int) sliderMorphFactor setValue(int) 784 38 657 38