diff --git a/Modules/SegmentationUI/resources/NewLabel_48x48.png b/Modules/SegmentationUI/resources/NewLabel_48x48.png index c11110bda6..defcc15ebc 100644 Binary files a/Modules/SegmentationUI/resources/NewLabel_48x48.png and b/Modules/SegmentationUI/resources/NewLabel_48x48.png differ diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/files.cmake b/Plugins/org.mitk.gui.qt.multilabelsegmentation/files.cmake index 7906c490d9..92c311902c 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/files.cmake +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/files.cmake @@ -1,106 +1,101 @@ set(SRC_CPP_FILES QmitkMultiLabelSegmentationPreferencePage.cpp ) set(INTERNAL_CPP_FILES mitkPluginActivator.cpp QmitkMultiLabelSegmentationView.cpp QmitkThresholdAction.cpp QmitkConvertSurfaceToLabelAction.cpp QmitkConvertMaskToLabelAction.cpp QmitkConvertToMultiLabelSegmentationAction.cpp QmitkCreateMultiLabelSegmentationAction.cpp - QmitkLoadMultiLabelPresetAction.cpp - QmitkCreateMultiLabelPresetAction.cpp Common/QmitkDataSelectionWidget.cpp SegmentationUtilities/QmitkMultiLabelSegmentationUtilitiesView.cpp SegmentationUtilities/QmitkSegmentationUtilityWidget.cpp SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp SegmentationUtilities/ContourModelToImage/QmitkContourModelToImageWidget.cpp SegmentationUtilities/MorphologicalOperations/QmitkMorphologicalOperationsWidget.cpp SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.cpp SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.cpp SegmentationUtilities/ConvertToMl/QmitkConvertToMlWidget.cpp ) set(UI_FILES src/internal/QmitkMultiLabelSegmentationControls.ui src/internal/Common/QmitkDataSelectionWidgetControls.ui src/internal/SegmentationUtilities/QmitkMultiLabelSegmentationUtilitiesViewControls.ui src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidgetControls.ui src/internal/SegmentationUtilities/ContourModelToImage/QmitkContourModelToImageWidgetControls.ui src/internal/SegmentationUtilities/MorphologicalOperations/QmitkMorphologicalOperationsWidgetControls.ui src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidgetControls.ui src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidgetControls.ui src/internal/SegmentationUtilities/ConvertToMl/QmitkConvertToMlWidgetControls.ui ) set(MOC_H_FILES src/QmitkMultiLabelSegmentationPreferencePage.h src/internal/mitkPluginActivator.h src/internal/QmitkMultiLabelSegmentationView.h src/internal/QmitkThresholdAction.h src/internal/QmitkConvertSurfaceToLabelAction.h - src/internal/QmitkLoadMultiLabelPresetAction.h - src/internal/QmitkCreateMultiLabelPresetAction.h src/internal/QmitkConvertMaskToLabelAction.h src/internal/QmitkConvertToMultiLabelSegmentationAction.h src/internal/QmitkCreateMultiLabelSegmentationAction.h src/internal/Common/QmitkDataSelectionWidget.h src/internal/SegmentationUtilities/QmitkMultiLabelSegmentationUtilitiesView.h src/internal/SegmentationUtilities/QmitkSegmentationUtilityWidget.h src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.h src/internal/SegmentationUtilities/ContourModelToImage/QmitkContourModelToImageWidget.h src/internal/SegmentationUtilities/MorphologicalOperations/QmitkMorphologicalOperationsWidget.h src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.h src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.h src/internal/SegmentationUtilities/ConvertToMl/QmitkConvertToMlWidget.h ) set(CACHED_RESOURCE_FILES resources/BooleanDifference_48x48.png resources/BooleanIntersection_48x48.png resources/BooleanOperations_48x48.png resources/BooleanUnion_48x48.png resources/Closing_48x48.png resources/CTKWidgets_48x48.png resources/deformablePlane.png resources/Dilate_48x48.png resources/Erode_48x48.png resources/FillHoles_48x48.png resources/Icons.svg resources/ImageMasking_48x48.png resources/MorphologicalOperations_48x48.png resources/multilabelsegmentation.svg resources/multilabelsegmentation_utilities.svg - resources/NewLabel_48x48.png resources/NewSegmentationSession_48x48.png resources/Opening_48x48.png resources/SurfaceToImage_48x48.png plugin.xml ) set(QRC_FILES resources/multilabelsegmentation.qrc resources/MultiLabelSegmentationUtilities.qrc resources/MorphologicalOperationsWidget.qrc resources/BooleanOperationsWidget.qrc ) set(CPP_FILES) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) #usFunctionEmbedResources( #CPP_FILES # LIBRARY_NAME "liborg_mitk_gui_qt_multilabelsegmentation" #ROOT_DIR resources #FILES Interactions/SegmentationInteraction.xml # Interactions/ConfigSegmentation.xml #) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/plugin.xml b/Plugins/org.mitk.gui.qt.multilabelsegmentation/plugin.xml index 7f3d3a7c9a..b0c2b62a22 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/plugin.xml +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/plugin.xml @@ -1,39 +1,38 @@ - - + diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/resources/NewLabel_48x48.png b/Plugins/org.mitk.gui.qt.multilabelsegmentation/resources/NewLabel_48x48.png deleted file mode 100644 index defcc15ebc..0000000000 Binary files a/Plugins/org.mitk.gui.qt.multilabelsegmentation/resources/NewLabel_48x48.png and /dev/null differ diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/resources/multilabelsegmentation.qrc b/Plugins/org.mitk.gui.qt.multilabelsegmentation/resources/multilabelsegmentation.qrc index bc38736d14..b8493eaab3 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/resources/multilabelsegmentation.qrc +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/resources/multilabelsegmentation.qrc @@ -1,7 +1,6 @@ multilabelsegmentation.svg - NewLabel_48x48.png NewSegmentationSession_48x48.png diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/mitkPluginActivator.cpp b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/mitkPluginActivator.cpp index ac1102b2a0..f38f072b70 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/mitkPluginActivator.cpp +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/mitkPluginActivator.cpp @@ -1,56 +1,52 @@ /*============================================================================ 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 "mitkPluginActivator.h" #include "QmitkMultiLabelSegmentationView.h" #include "QmitkThresholdAction.h" #include "QmitkConvertSurfaceToLabelAction.h" #include "QmitkConvertMaskToLabelAction.h" #include "QmitkConvertToMultiLabelSegmentationAction.h" #include "QmitkCreateMultiLabelSegmentationAction.h" #include "QmitkMultiLabelSegmentationPreferencePage.h" -#include "QmitkLoadMultiLabelPresetAction.h" -#include "QmitkCreateMultiLabelPresetAction.h" #include "SegmentationUtilities/QmitkMultiLabelSegmentationUtilitiesView.h" #include ctkPluginContext* mitk::PluginActivator::m_Context = nullptr; //MLI TODO US_INITIALIZE_MODULE //("MultiLabelSegmentation", "liborg_mitk_gui_qt_multilabelsegmentation") void mitk::PluginActivator::start(ctkPluginContext *context) { BERRY_REGISTER_EXTENSION_CLASS(QmitkMultiLabelSegmentationView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkThresholdAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkConvertSurfaceToLabelAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkConvertMaskToLabelAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkConvertToMultiLabelSegmentationAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkCreateMultiLabelSegmentationAction, context) - BERRY_REGISTER_EXTENSION_CLASS(QmitkCreateMultiLabelPresetAction, context) - BERRY_REGISTER_EXTENSION_CLASS(QmitkLoadMultiLabelPresetAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkMultiLabelSegmentationPreferencePage, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkMultiLabelSegmentationUtilitiesView, context) m_Context = context; } void mitk::PluginActivator::stop(ctkPluginContext*) { } ctkPluginContext* mitk::PluginActivator::getContext() { return m_Context; } diff --git a/Plugins/org.mitk.gui.qt.segmentation/files.cmake b/Plugins/org.mitk.gui.qt.segmentation/files.cmake index 99032b0f3d..f63907b3ae 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/files.cmake +++ b/Plugins/org.mitk.gui.qt.segmentation/files.cmake @@ -1,73 +1,80 @@ set(SRC_CPP_FILES QmitkSegmentationPreferencePage.cpp ) set(INTERNAL_CPP_FILES mitkPluginActivator.cpp QmitkSegmentationView.cpp - QmitkCreatePolygonModelAction.cpp QmitkAutocropAction.cpp QmitkAutocropLabelSetImageAction.cpp + QmitkCreatePolygonModelAction.cpp + QmitkLoadMultiLabelPresetAction.cpp + QmitkSaveMultiLabelPresetAction.cpp Common/QmitkDataSelectionWidget.cpp + Common/QmitkLabelsWidget.cpp Common/QmitkLayersWidget.cpp SegmentationUtilities/QmitkSegmentationUtilitiesView.cpp SegmentationUtilities/QmitkSegmentationUtilityWidget.cpp SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.cpp SegmentationUtilities/ContourModelToImage/QmitkContourModelToImageWidget.cpp SegmentationUtilities/MorphologicalOperations/QmitkMorphologicalOperationsWidget.cpp SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.cpp ) set(UI_FILES src/internal/QmitkSegmentationViewControls.ui src/internal/Common/QmitkDataSelectionWidgetControls.ui + src/internal/Common/QmitkLabelsWidgetControls.ui src/internal/Common/QmitkLayersWidgetControls.ui src/internal/SegmentationUtilities/QmitkSegmentationUtilitiesViewControls.ui src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidgetControls.ui src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidgetControls.ui src/internal/SegmentationUtilities/ContourModelToImage/QmitkContourModelToImageWidgetControls.ui src/internal/SegmentationUtilities/MorphologicalOperations/QmitkMorphologicalOperationsWidgetControls.ui src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidgetControls.ui ) set(MOC_H_FILES src/QmitkSegmentationPreferencePage.h src/internal/mitkPluginActivator.h src/internal/QmitkSegmentationView.h - src/internal/QmitkCreatePolygonModelAction.h src/internal/QmitkAutocropAction.h src/internal/QmitkAutocropLabelSetImageAction.h + src/internal/QmitkCreatePolygonModelAction.h + src/internal/QmitkLoadMultiLabelPresetAction.h + src/internal/QmitkSaveMultiLabelPresetAction.h src/internal/Common/QmitkDataSelectionWidget.h + src/internal/Common/QmitkLabelsWidget.h src/internal/Common/QmitkLayersWidget.h src/internal/SegmentationUtilities/QmitkSegmentationUtilitiesView.h src/internal/SegmentationUtilities/QmitkSegmentationUtilityWidget.h src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.h src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.h src/internal/SegmentationUtilities/ContourModelToImage/QmitkContourModelToImageWidget.h src/internal/SegmentationUtilities/MorphologicalOperations/QmitkMorphologicalOperationsWidget.h src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.h ) set(CACHED_RESOURCE_FILES resources/segmentation.svg resources/segmentation_utilities.svg plugin.xml ) set(QRC_FILES resources/segmentation.qrc resources/SegmentationUtilities.qrc resources/BooleanOperationsWidget.qrc resources/MorphologicalOperationsWidget.qrc ) set(CPP_FILES) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.segmentation/plugin.xml b/Plugins/org.mitk.gui.qt.segmentation/plugin.xml index a628b56818..b0753685a8 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/plugin.xml +++ b/Plugins/org.mitk.gui.qt.segmentation/plugin.xml @@ -1,81 +1,82 @@ Allows the segmentation of images using different tools. Edit segmentations using standard operations. + + - diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkLabelsWidget.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkLabelsWidget.cpp new file mode 100644 index 0000000000..bd9e0955e5 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkLabelsWidget.cpp @@ -0,0 +1,183 @@ +/*============================================================================ + +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 "QmitkLabelsWidget.h" +#include + +// mitk +#include +#include +#include +#include + +// Qmitk +#include +#include + +#include "../QmitkSaveMultiLabelPresetAction.h" +#include "../QmitkLoadMultiLabelPresetAction.h" + +// Qt +#include + +QmitkLabelsWidget::QmitkLabelsWidget(QWidget *parent) + : QWidget(parent) + , m_Controls(new Ui::QmitkLabelsWidgetControls) + , m_ToolManager(nullptr) +{ + m_Controls->setupUi(this); + + m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); + + m_Controls->savePresetButton->setIcon(QmitkStyleManager::ThemeIcon(QStringLiteral(":/org_mitk_icons/icons/awesome/scalable/actions/document-save.svg"))); + m_Controls->loadPresetButton->setIcon(QmitkStyleManager::ThemeIcon(QStringLiteral(":/org_mitk_icons/icons/awesome/scalable/actions/document-open.svg"))); + + connect(m_Controls->newLabelButton, &QToolButton::clicked, this, &QmitkLabelsWidget::OnNewLabel); + connect(m_Controls->lockExteriorButton, &QToolButton::toggled, this, &QmitkLabelsWidget::OnLockExterior); + connect(m_Controls->savePresetButton, &QToolButton::clicked, this, &QmitkLabelsWidget::OnSavePreset); + connect(m_Controls->loadPresetButton, &QToolButton::clicked, this, &QmitkLabelsWidget::OnLoadPreset); + connect(m_Controls->showLabelTableButton, &QToolButton::toggled, this, &QmitkLabelsWidget::ShowLabelTable); + + this->UpdateGUI(); +} + +QmitkLabelsWidget::~QmitkLabelsWidget() +{ + delete m_Controls; +} + +void QmitkLabelsWidget::UpdateGUI() +{ + m_Controls->newLabelButton->setEnabled(false); + m_Controls->lockExteriorButton->setEnabled(false); + m_Controls->lockExteriorButton->setChecked(false); + m_Controls->savePresetButton->setEnabled(false); + m_Controls->loadPresetButton->setEnabled(false); + m_Controls->showLabelTableButton->setEnabled(false); + m_Controls->showLabelTableButton->setChecked(false); + + mitk::LabelSetImage* workingImage = this->GetWorkingImage(); + if (nullptr == workingImage) + { + return; + } + + int activeLayer = workingImage->GetActiveLayer(); + m_Controls->lockExteriorButton->setEnabled(true); + m_Controls->lockExteriorButton->setChecked(workingImage->GetLabel(0, activeLayer)->GetLocked()); + m_Controls->showLabelTableButton->setEnabled(true); + m_Controls->showLabelTableButton->setChecked(true); + m_Controls->newLabelButton->setEnabled(true); + m_Controls->savePresetButton->setEnabled(true); + m_Controls->loadPresetButton->setEnabled(true); +} + +mitk::LabelSetImage* QmitkLabelsWidget::GetWorkingImage() +{ + mitk::DataNode* workingNode = this->GetWorkingNode(); + if (nullptr == workingNode) + { + return nullptr; + } + + auto workingImage = dynamic_cast(workingNode->GetData()); + return workingImage; +} + +mitk::DataNode* QmitkLabelsWidget::GetWorkingNode() +{ + mitk::DataNode* referenceNode = m_ToolManager->GetWorkingData(0); + return referenceNode; +} + +void QmitkLabelsWidget::OnNewLabel() +{ + m_ToolManager->ActivateTool(-1); + + mitk::DataNode* workingNode = this->GetWorkingNode(); + if (nullptr == workingNode) + { + return; + } + + auto workingImage = dynamic_cast(workingNode->GetData()); + if (nullptr == workingImage) + { + return; + } + + + int numberOfLabels = workingImage->GetActiveLabelSet()->GetNumberOfLabels(); + + mitk::LookupTable::Pointer lookupTable = mitk::LookupTable::New(); + lookupTable->SetType(mitk::LookupTable::LookupTableType::MULTILABEL); + double rgb[3]; + lookupTable->GetColor(numberOfLabels, rgb); + mitk::Color labelColor; + labelColor.Set(static_cast(rgb[0]), static_cast(rgb[1]), static_cast(rgb[2])); + + std::string labelName = "New label " + std::to_string(numberOfLabels); + + this->WaitCursorOn(); + workingImage->GetActiveLabelSet()->AddLabel(labelName, labelColor); + this->WaitCursorOff(); + + this->UpdateGUI(); + emit LabelsChanged(); +} + +void QmitkLabelsWidget::OnLockExterior(bool checked) +{ + auto workingImage = this->GetWorkingImage(); + if (nullptr == workingImage) + { + return; + } + + workingImage->GetLabel(0)->SetLocked(checked); +} + +void QmitkLabelsWidget::OnSavePreset() +{ + auto workingNode = this->GetWorkingNode(); + QmitkAbstractNodeSelectionWidget::NodeList nodes; + nodes.append(workingNode); + + QmitkSaveMultiLabelPresetAction action; + action.Run(nodes); +} + +void QmitkLabelsWidget::OnLoadPreset() +{ + auto workingNode = this->GetWorkingNode(); + QmitkAbstractNodeSelectionWidget::NodeList nodes; + nodes.append(workingNode); + + QmitkLoadMultiLabelPresetAction action; + action.Run(nodes); +} + +void QmitkLabelsWidget::WaitCursorOn() +{ + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); +} + +void QmitkLabelsWidget::WaitCursorOff() +{ + this->RestoreOverrideCursor(); +} + +void QmitkLabelsWidget::RestoreOverrideCursor() +{ + QApplication::restoreOverrideCursor(); +} + diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkLabelsWidget.h b/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkLabelsWidget.h new file mode 100644 index 0000000000..bd74ae2ead --- /dev/null +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkLabelsWidget.h @@ -0,0 +1,82 @@ +/*============================================================================ + +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 QMITKLABELSWIDGET_H +#define QMITKLABELSWIDGET_H + +// mitk core +#include + +// Qt +#include + +namespace Ui +{ + class QmitkLabelsWidgetControls; +} + +namespace mitk +{ + class DataNode; + class Image; + class LabelSetImage; + class ToolManager; +} + +class QmitkLabelsWidget : public QWidget +{ + Q_OBJECT + +public: + + explicit QmitkLabelsWidget(QWidget* parent = nullptr); + ~QmitkLabelsWidget() override; + + void UpdateGUI(); + +Q_SIGNALS: + + void LabelsChanged(); + + void ShowLabelTable(bool); + +private: + + mitk::LabelSetImage* GetWorkingImage(); + + mitk::DataNode* GetWorkingNode(); + + // reaction to button "New Label" + void OnNewLabel(); + + // reaction to the button "Lock exterior" + void OnLockExterior(bool); + + // reaction to button "Save Preset" + void OnSavePreset(); + + // reaction to button "Load Preset" + void OnLoadPreset(); + + void WaitCursorOn(); + + void WaitCursorOff(); + + void RestoreOverrideCursor(); + + Ui::QmitkLabelsWidgetControls* m_Controls; + + mitk::ToolManager* m_ToolManager; + +}; + +#endif diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkLabelsWidgetControls.ui b/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkLabelsWidgetControls.ui new file mode 100644 index 0000000000..35fb68f86b --- /dev/null +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkLabelsWidgetControls.ui @@ -0,0 +1,188 @@ + + + QmitkLabelsWidgetControls + + + + 0 + 0 + 300 + 75 + + + + + 0 + 0 + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Labels + + + + + + Add a label to the current segmentation session + + + ... + + + + :/Qmitk/NewLabel_48x48.png:/Qmitk/NewLabel_48x48.png + + + + 28 + 28 + + + + true + + + + + + + Lock / unlock exterior + + + ... + + + + :/Qmitk/UnlockExterior_48x48.png + :/Qmitk/LockExterior_48x48.png:/Qmitk/UnlockExterior_48x48.png + + + + 28 + 28 + + + + true + + + true + + + + + + + Save labelset preset + + + ... + + + + :/org_mitk_icons/icons/awesome/scalable/actions/document-save.svg:/org_mitk_icons/icons/awesome/scalable/actions/document-save.svg + + + + 28 + 28 + + + + true + + + + + + + Load LabelSet Preset + + + ... + + + + :/org_mitk_icons/icons/awesome/scalable/actions/document-open.svg:/org_mitk_icons/icons/awesome/scalable/actions/document-open.svg + + + + 28 + 28 + + + + true + + + + + + + Qt::Horizontal + + + + 0 + 20 + + + + + + + + + 0 + 34 + + + + Show a table with all labels in the current segmentation session + + + >> + + + + 28 + 28 + + + + true + + + false + + + Qt::NoArrow + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkLoadMultiLabelPresetAction.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkLoadMultiLabelPresetAction.cpp similarity index 100% rename from Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkLoadMultiLabelPresetAction.cpp rename to Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkLoadMultiLabelPresetAction.cpp diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkLoadMultiLabelPresetAction.h b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkLoadMultiLabelPresetAction.h similarity index 100% rename from Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkLoadMultiLabelPresetAction.h rename to Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkLoadMultiLabelPresetAction.h diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkCreateMultiLabelPresetAction.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSaveMultiLabelPresetAction.cpp similarity index 75% rename from Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkCreateMultiLabelPresetAction.cpp rename to Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSaveMultiLabelPresetAction.cpp index 5c245ed824..b813c809e8 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkCreateMultiLabelPresetAction.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSaveMultiLabelPresetAction.cpp @@ -1,63 +1,63 @@ /*============================================================================ 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 "QmitkCreateMultiLabelPresetAction.h" +#include "QmitkSaveMultiLabelPresetAction.h" #include #include #include #include -void QmitkCreateMultiLabelPresetAction::Run(const QList &selectedNodes) +void QmitkSaveMultiLabelPresetAction::Run(const QList &selectedNodes) { for (const auto &node : selectedNodes) { if (node.IsNull()) continue; mitk::LabelSetImage::Pointer image = dynamic_cast(node->GetData()); if (image.IsNull()) continue; const auto filename = QFileDialog::getSaveFileName(nullptr, QStringLiteral("Save LabelSet Preset"), QString(), QStringLiteral("LabelSet Preset (*.lsetp)")).toStdString(); if (filename.empty()) continue; if(!mitk::LabelSetIOHelper::SaveLabelSetImagePreset(filename, image)) { QMessageBox::critical(nullptr, QStringLiteral("Save LabelSetImage Preset"), QString("Could not save \"%1\" as preset.").arg(QString::fromStdString(node->GetName()))); continue; } } } -void QmitkCreateMultiLabelPresetAction::SetDataStorage(mitk::DataStorage*) +void QmitkSaveMultiLabelPresetAction::SetDataStorage(mitk::DataStorage*) { } -void QmitkCreateMultiLabelPresetAction::SetFunctionality(berry::QtViewPart*) +void QmitkSaveMultiLabelPresetAction::SetFunctionality(berry::QtViewPart*) { } -void QmitkCreateMultiLabelPresetAction::SetSmoothed(bool) +void QmitkSaveMultiLabelPresetAction::SetSmoothed(bool) { } -void QmitkCreateMultiLabelPresetAction::SetDecimated(bool) +void QmitkSaveMultiLabelPresetAction::SetDecimated(bool) { } diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkCreateMultiLabelPresetAction.h b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSaveMultiLabelPresetAction.h similarity index 69% rename from Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkCreateMultiLabelPresetAction.h rename to Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSaveMultiLabelPresetAction.h index 2406a22bd8..0b948cc46e 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkCreateMultiLabelPresetAction.h +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSaveMultiLabelPresetAction.h @@ -1,34 +1,34 @@ /*============================================================================ 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 QmitkCreateMultiLabelPresetAction_h -#define QmitkCreateMultiLabelPresetAction_h +#ifndef QMITKSAVEMULTILABELPRESETACTION_H +#define QMITKSAVEMULTILABELPRESETACTION_H #include -class QmitkCreateMultiLabelPresetAction : public QObject, public mitk::IContextMenuAction +class QmitkSaveMultiLabelPresetAction : public QObject, public mitk::IContextMenuAction { Q_OBJECT Q_INTERFACES(mitk::IContextMenuAction) public: - QmitkCreateMultiLabelPresetAction() = default; - ~QmitkCreateMultiLabelPresetAction() override = default; + QmitkSaveMultiLabelPresetAction() = default; + ~QmitkSaveMultiLabelPresetAction() override = default; void Run(const QList& selectedNodes) override; void SetDataStorage(mitk::DataStorage*) override; void SetFunctionality(berry::QtViewPart*) override; void SetSmoothed(bool) override; void SetDecimated(bool) override; }; -#endif +#endif // QMITKSAVEMULTILABELPRESETACTION_H diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp index 087fe8aeb8..754b367f47 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp @@ -1,820 +1,829 @@ /*============================================================================ 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 "QmitkSegmentationView.h" #include "mitkPluginActivator.h" // blueberry #include // mitk #include #include #include #include #include #include #include #include #include #include #include // Qmitk #include #include #include // us #include #include // Qt #include #include const std::string QmitkSegmentationView::VIEW_ID = "org.mitk.views.segmentation"; QmitkSegmentationView::QmitkSegmentationView() : m_Parent(nullptr) , m_Controls(nullptr) , m_RenderWindowPart(nullptr) , m_ToolManager(nullptr) , m_ReferenceNode(nullptr) , m_WorkingNode(nullptr) , m_AutoSelectionEnabled(false) , m_MouseCursorSet(false) { auto isImage = mitk::TNodePredicateDataType::New(); auto isDwi = mitk::NodePredicateDataType::New("DiffusionImage"); auto isDti = mitk::NodePredicateDataType::New("TensorImage"); auto isOdf = mitk::NodePredicateDataType::New("OdfImage"); auto isSegment = mitk::NodePredicateDataType::New("Segment"); auto validImages = mitk::NodePredicateOr::New(); validImages->AddPredicate(mitk::NodePredicateAnd::New(isImage, mitk::NodePredicateNot::New(isSegment))); validImages->AddPredicate(isDwi); validImages->AddPredicate(isDti); validImages->AddPredicate(isOdf); auto isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); auto isMask = mitk::NodePredicateAnd::New(isBinary, isImage); auto validSegmentations = mitk::NodePredicateOr::New(); validSegmentations->AddPredicate(mitk::TNodePredicateDataType::New()); validSegmentations->AddPredicate(isMask); m_SegmentationPredicate = mitk::NodePredicateAnd::New(); m_SegmentationPredicate->AddPredicate(validSegmentations); m_SegmentationPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); m_SegmentationPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("hidden object"))); m_ReferencePredicate = mitk::NodePredicateAnd::New(); m_ReferencePredicate->AddPredicate(validImages); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(m_SegmentationPredicate)); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("hidden object"))); } QmitkSegmentationView::~QmitkSegmentationView() { if (nullptr != m_Controls) { // deactivate all tools m_ToolManager->ActivateTool(-1); // removing all observers for (NodeTagMapType::iterator dataIter = m_WorkingDataObserverTags.begin(); dataIter != m_WorkingDataObserverTags.end(); ++dataIter) { (*dataIter).first->GetProperty("visible")->RemoveObserver((*dataIter).second); } m_WorkingDataObserverTags.clear(); mitk::RenderingManager::GetInstance()->RemoveObserver(m_RenderingManagerObserverTag); ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); service->RemoveAllPlanePositions(); context->ungetService(ppmRef); m_ToolManager->SetReferenceData(nullptr); m_ToolManager->SetWorkingData(nullptr); } delete m_Controls; } /**********************************************************************/ /* private Q_SLOTS */ /**********************************************************************/ void QmitkSegmentationView::OnReferenceSelectionChanged(QList nodes) { m_ToolManager->ActivateTool(-1); if (nodes.empty()) { m_Controls->workingNodeSelector->SetNodePredicate(m_SegmentationPredicate); m_ReferenceNode = nullptr; m_ToolManager->SetReferenceData(m_ReferenceNode); this->UpdateGUI(); return; } m_ReferenceNode = nodes.first(); m_ToolManager->SetReferenceData(m_ReferenceNode); if (m_ReferenceNode.IsNotNull()) { // set a predicate such that a segmentation fits the selected reference image geometry auto segPredicate = mitk::NodePredicateAnd::New(m_SegmentationPredicate.GetPointer(), mitk::NodePredicateSubGeometry::New(m_ReferenceNode->GetData()->GetGeometry())); m_Controls->workingNodeSelector->SetNodePredicate(segPredicate); if (m_AutoSelectionEnabled) { // hide all image nodes to later show only the automatically selected ones mitk::DataStorage::SetOfObjects::ConstPointer imageNodes = this->GetDataStorage()->GetSubset(m_ReferencePredicate); for (mitk::DataStorage::SetOfObjects::const_iterator iter = imageNodes->begin(); iter != imageNodes->end(); ++iter) { (*iter)->SetVisibility(false); } } m_ReferenceNode->SetVisibility(true); } this->UpdateGUI(); } void QmitkSegmentationView::OnSegmentationSelectionChanged(QList nodes) { m_ToolManager->ActivateTool(-1); // Remove observer if one was registered auto finding = m_WorkingDataObserverTags.find(m_WorkingNode); if (finding != m_WorkingDataObserverTags.end()) { m_WorkingNode->GetProperty("visible")->RemoveObserver(m_WorkingDataObserverTags[m_WorkingNode]); m_WorkingDataObserverTags.erase(m_WorkingNode); } if (nodes.empty()) { m_WorkingNode = nullptr; m_ToolManager->SetWorkingData(m_WorkingNode); this->UpdateGUI(); return; } if (m_ReferenceNode.IsNull()) { this->UpdateGUI(); return; } mitk::Image::ConstPointer referenceImage = dynamic_cast(m_ReferenceNode->GetData()); if (referenceImage.IsNull()) { this->UpdateGUI(); return; } m_WorkingNode = nodes.first(); m_ToolManager->SetWorkingData(m_WorkingNode); if (m_WorkingNode.IsNotNull()) { if (m_AutoSelectionEnabled) { // hide all segmentation nodes to later show only the automatically selected ones mitk::DataStorage::SetOfObjects::ConstPointer segmentationNodes = this->GetDataStorage()->GetSubset(m_SegmentationPredicate); for (mitk::DataStorage::SetOfObjects::const_iterator iter = segmentationNodes->begin(); iter != segmentationNodes->end(); ++iter) { (*iter)->SetVisibility(false); } } m_WorkingNode->SetVisibility(true); auto command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::ValidateSelectionInput); m_WorkingDataObserverTags.insert(std::pair(m_WorkingNode, m_WorkingNode->GetProperty("visible")->AddObserver(itk::ModifiedEvent(), command))); this->InitializeRenderWindows(referenceImage->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, false); } this->UpdateGUI(); } void QmitkSegmentationView::OnNewSegmentation() { m_ToolManager->ActivateTool(-1); mitk::DataNode::Pointer referenceNode = m_ToolManager->GetReferenceData(0); if (referenceNode.IsNull()) { MITK_ERROR << "'Create new segmentation' button should never be clickable unless a reference image is selected."; return; } mitk::Image::ConstPointer referenceImage = dynamic_cast(referenceNode->GetData()); if (referenceImage.IsNull()) { QMessageBox::information( m_Parent, "New segmentation", "Please load and select an image before starting some action."); return; } if (referenceImage->GetDimension() <= 1) { QMessageBox::information( m_Parent, "New segmentation", "Segmentation is currently not supported for 2D images"); return; } const auto currentTimePoint = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint(); unsigned int imageTimeStep = 0; if (referenceImage->GetTimeGeometry()->IsValidTimePoint(currentTimePoint)) { imageTimeStep = referenceImage->GetTimeGeometry()->TimePointToTimeStep(currentTimePoint); } auto segTemplateImage = referenceImage; if (referenceImage->GetDimension() > 3) { auto result = QMessageBox::question(m_Parent, tr("Create a static or dynamic segmentation?"), tr("The selected image has multiple time steps.\n\nDo you want to create a static " "segmentation that is identical for all time steps or do you want to create a " "dynamic segmentation to segment individual time steps?"), tr("Create static segmentation"), tr("Create dynamic segmentation"), QString(), 0, 0); if (result == 0) { auto selector = mitk::ImageTimeSelector::New(); selector->SetInput(referenceImage); selector->SetTimeNr(0); selector->Update(); const auto refTimeGeometry = referenceImage->GetTimeGeometry(); auto newTimeGeometry = mitk::ProportionalTimeGeometry::New(); newTimeGeometry->SetFirstTimePoint(refTimeGeometry->GetMinimumTimePoint()); newTimeGeometry->SetStepDuration(refTimeGeometry->GetMaximumTimePoint() - refTimeGeometry->GetMinimumTimePoint()); mitk::Image::Pointer newImage = selector->GetOutput(); newTimeGeometry->SetTimeStepGeometry(referenceImage->GetGeometry(imageTimeStep), 0); newImage->SetTimeGeometry(newTimeGeometry); segTemplateImage = newImage; } } QString newName = QString::fromStdString(referenceNode->GetName()); newName.append("-labels"); // ask about the name and organ type of the new segmentation auto dialog = new QmitkNewSegmentationDialog(m_Parent); QStringList organColors = mitk::OrganNamesHandling::GetDefaultOrganColorString(); dialog->SetSuggestionList(organColors); dialog->SetSegmentationName(newName); int dialogReturnValue = dialog->exec(); if (dialogReturnValue == QDialog::Rejected) { return; } std::string newNodeName = dialog->GetSegmentationName().toStdString(); if (newNodeName.empty()) { newNodeName = "Unnamed"; } // create a new image of the same dimensions and smallest possible pixel type auto firstTool = m_ToolManager->GetToolById(0); if (nullptr == firstTool) { return; } mitk::DataNode::Pointer emptySegmentation = nullptr; try { emptySegmentation = firstTool->CreateEmptySegmentationNode(segTemplateImage, newNodeName, dialog->GetColor()); } catch (const std::bad_alloc &) { QMessageBox::warning(m_Parent, tr("New segmentation"), tr("Could not allocate memory for new segmentation")); } if (nullptr == emptySegmentation) { return; // could have been aborted by user } // initialize "showVolume"-property to false to prevent recalculating the volume while working on the segmentation emptySegmentation->SetProperty("showVolume", mitk::BoolProperty::New(false)); mitk::OrganNamesHandling::UpdateOrganList(organColors, dialog->GetSegmentationName(), dialog->GetColor()); // escape ';' here (replace by '\;') QString stringForStorage = organColors.replaceInStrings(";", "\\;").join(";"); MITK_DEBUG << "Will store: " << stringForStorage; this->GetPreferences()->Put("Organ-Color-List", stringForStorage); this->GetPreferences()->Flush(); this->GetDataStorage()->Add(emptySegmentation, referenceNode); if (m_ToolManager->GetWorkingData(0)) { m_ToolManager->GetWorkingData(0)->SetSelected(false); } emptySegmentation->SetSelected(true); m_Controls->workingNodeSelector->SetCurrentSelectedNode(emptySegmentation); } void QmitkSegmentationView::OnManualTool2DSelected(int id) { this->ResetMouseCursor(); mitk::StatusBar::GetInstance()->DisplayText(""); if (id >= 0) { std::string text = "Active Tool: \""; text += m_ToolManager->GetToolById(id)->GetName(); text += "\""; mitk::StatusBar::GetInstance()->DisplayText(text.c_str()); us::ModuleResource resource = m_ToolManager->GetToolById(id)->GetCursorIconResource(); this->SetMouseCursor(resource, 0, 0); } } void QmitkSegmentationView::OnShowMarkerNodes(bool state) { mitk::SegTool2D::Pointer manualSegmentationTool; unsigned int numberOfExistingTools = m_ToolManager->GetTools().size(); for (unsigned int i = 0; i < numberOfExistingTools; i++) { manualSegmentationTool = dynamic_cast(m_ToolManager->GetToolById(i)); if (nullptr == manualSegmentationTool) { continue; } manualSegmentationTool->SetShowMarkerNodes(state); } } void QmitkSegmentationView::OnLayersChanged() { m_Controls->labelSetWidget->ResetAllTableWidgetItems(); } +void QmitkSegmentationView::OnLabelsChanged() +{ + m_Controls->labelSetWidget->ResetAllTableWidgetItems(); +} + /**********************************************************************/ /* private */ /**********************************************************************/ void QmitkSegmentationView::CreateQtPartControl(QWidget* parent) { m_Parent = parent; m_Controls = new Ui::QmitkSegmentationViewControls; m_Controls->setupUi(parent); // *------------------------ // * DATA SELECTION WIDGETS // *------------------------ m_Controls->referenceNodeSelector->SetDataStorage(GetDataStorage()); m_Controls->referenceNodeSelector->SetNodePredicate(m_ReferencePredicate); m_Controls->referenceNodeSelector->SetInvalidInfo("Select an image"); m_Controls->referenceNodeSelector->SetPopUpTitel("Select an image"); m_Controls->referenceNodeSelector->SetPopUpHint("Select an image that should be used to define the geometry and bounds of the segmentation."); m_Controls->workingNodeSelector->SetDataStorage(GetDataStorage()); m_Controls->workingNodeSelector->SetNodePredicate(m_SegmentationPredicate); m_Controls->workingNodeSelector->SetInvalidInfo("Select a segmentation"); m_Controls->workingNodeSelector->SetPopUpTitel("Select a segmentation"); m_Controls->workingNodeSelector->SetPopUpHint("Select a segmentation that should be modified. Only segmentation with the same geometry and within the bounds of the reference image are selected."); connect(m_Controls->referenceNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkSegmentationView::OnReferenceSelectionChanged); connect(m_Controls->workingNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkSegmentationView::OnSegmentationSelectionChanged); // *------------------------ // * TOOLMANAGER // *------------------------ m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); m_ToolManager->SetDataStorage(*(this->GetDataStorage())); m_ToolManager->InitializeTools(); QString segTools2D = tr("Add Subtract Fill Erase Paint Wipe 'Region Growing' 'Live Wire' '2D Fast Marching'"); QString segTools3D = tr("Threshold 'UL Threshold' Otsu 'Fast Marching 3D' 'Region Growing 3D' Watershed Picking"); #ifdef __linux__ segTools3D.append(" nnUNet"); // plugin not enabled for MacOS / Windows #endif std::regex extSegTool2DRegEx("SegTool2D$"); std::regex extSegTool3DRegEx("SegTool3D$"); auto tools = m_ToolManager->GetTools(); for (const auto &tool : tools) { if (std::regex_search(tool->GetNameOfClass(), extSegTool2DRegEx)) { segTools2D.append(QString(" '%1'").arg(tool->GetName())); } else if (std::regex_search(tool->GetNameOfClass(), extSegTool3DRegEx)) { segTools3D.append(QString(" '%1'").arg(tool->GetName())); } } // setup 2D tools m_Controls->toolSelectionBox2D->SetToolManager(*m_ToolManager); m_Controls->toolSelectionBox2D->SetGenerateAccelerators(true); m_Controls->toolSelectionBox2D->SetToolGUIArea(m_Controls->toolGUIArea2D); m_Controls->toolSelectionBox2D->SetDisplayedToolGroups(segTools2D.toStdString()); m_Controls->toolSelectionBox2D->SetLayoutColumns(3); m_Controls->toolSelectionBox2D->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); connect(m_Controls->toolSelectionBox2D, &QmitkToolSelectionBox::ToolSelected, this, &QmitkSegmentationView::OnManualTool2DSelected); // setup 3D Tools m_Controls->toolSelectionBox3D->SetToolManager(*m_ToolManager); m_Controls->toolSelectionBox3D->SetGenerateAccelerators(true); m_Controls->toolSelectionBox3D->SetToolGUIArea(m_Controls->toolGUIArea3D); m_Controls->toolSelectionBox3D->SetDisplayedToolGroups(segTools3D.toStdString()); m_Controls->toolSelectionBox3D->SetLayoutColumns(3); m_Controls->toolSelectionBox3D->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); - // create signal/slot connections + // create general signal / slot connections connect(m_Controls->newSegmentationButton, &QToolButton::clicked, this, &QmitkSegmentationView::OnNewSegmentation); connect(m_Controls->slicesInterpolator, &QmitkSlicesInterpolator::SignalShowMarkerNodes, this, &QmitkSegmentationView::OnShowMarkerNodes); connect(m_Controls->layersWidget, &QmitkLayersWidget::LayersChanged, this, &QmitkSegmentationView::OnLayersChanged); + connect(m_Controls->labelsWidget, &QmitkLabelsWidget::LabelsChanged, this, &QmitkSegmentationView::OnLabelsChanged); auto command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::ValidateSelectionInput); m_RenderingManagerObserverTag = mitk::RenderingManager::GetInstance()->AddObserver(mitk::RenderingManagerViewsInitializedEvent(), command); m_RenderWindowPart = this->GetRenderWindowPart(); if (nullptr != m_RenderWindowPart) { this->RenderWindowPartActivated(m_RenderWindowPart); } // Make sure the GUI notices if appropriate data is already present on creation. // Should be done last, if everything else is configured because it triggers the autoselection of data. m_Controls->referenceNodeSelector->SetAutoSelectNewNodes(true); m_Controls->workingNodeSelector->SetAutoSelectNewNodes(true); this->UpdateGUI(); } void QmitkSegmentationView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { if (m_RenderWindowPart != renderWindowPart) { m_RenderWindowPart = renderWindowPart; } if (nullptr != m_Parent) { m_Parent->setEnabled(true); } // tell the interpolation about tool manager, data storage and render window part if (nullptr != m_Controls && nullptr != m_RenderWindowPart) { m_Controls->slicesInterpolator->SetDataStorage(this->GetDataStorage()); QList controllers; controllers.push_back(m_RenderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()); controllers.push_back(m_RenderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()); controllers.push_back(m_RenderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()); m_Controls->slicesInterpolator->Initialize(m_ToolManager, controllers); } } void QmitkSegmentationView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* /*renderWindowPart*/) { m_RenderWindowPart = nullptr; if (nullptr != m_Parent) { m_Parent->setEnabled(false); } } void QmitkSegmentationView::OnPreferencesChanged(const berry::IBerryPreferences* prefs) { if (nullptr != m_Controls) { bool slimView = prefs->GetBool("slim view", false); m_Controls->toolSelectionBox2D->SetShowNames(!slimView); m_Controls->toolSelectionBox3D->SetShowNames(!slimView); } m_AutoSelectionEnabled = prefs->GetBool("auto selection", false); this->ApplyDisplayOptions(); } void QmitkSegmentationView::NodeAdded(const mitk::DataNode* node) { if (m_SegmentationPredicate->CheckNode(node)) { this->ApplyDisplayOptions(const_cast(node)); } } void QmitkSegmentationView::NodeRemoved(const mitk::DataNode* node) { if (!m_SegmentationPredicate->CheckNode(node)) { return; } // remove all possible contour markers of the segmentation mitk::DataStorage::SetOfObjects::ConstPointer allContourMarkers = this->GetDataStorage()->GetDerivations( node, mitk::NodePredicateProperty::New("isContourMarker", mitk::BoolProperty::New(true))); ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); for (mitk::DataStorage::SetOfObjects::ConstIterator it = allContourMarkers->Begin(); it != allContourMarkers->End(); ++it) { std::string nodeName = node->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int id = atof(nodeName.substr(t + 1).c_str()) - 1; service->RemovePlanePosition(id); this->GetDataStorage()->Remove(it->Value()); } context->ungetService(ppmRef); service = nullptr; mitk::Image* image = dynamic_cast(node->GetData()); mitk::SurfaceInterpolationController::GetInstance()->RemoveInterpolationSession(image); } void QmitkSegmentationView::ApplyDisplayOptions() { if (nullptr == m_Parent) { return; } if (nullptr == m_Controls) { return; // might happen on initialization (preferences loaded) } mitk::DataStorage::SetOfObjects::ConstPointer allImages = this->GetDataStorage()->GetSubset(m_SegmentationPredicate); for (mitk::DataStorage::SetOfObjects::const_iterator iter = allImages->begin(); iter != allImages->end(); ++iter) { this->ApplyDisplayOptions(*iter); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSegmentationView::ApplyDisplayOptions(mitk::DataNode* node) { if (nullptr == node) { return; } auto drawOutline = mitk::BoolProperty::New(GetPreferences()->GetBool("draw outline", true)); auto labelSetImage = dynamic_cast(node->GetData()); if (nullptr != labelSetImage) { // node is a multi label segmentation, // its outline property can be set in the segmentation preference page node->SetProperty("labelset.contour.active", drawOutline); // force render window update to show outline node->GetData()->Modified(); } else if (nullptr != node->GetData()) { // node is a legacy binary segmentation bool isBinary = false; node->GetBoolProperty("binary", isBinary); if (isBinary) { node->SetProperty("outline binary", drawOutline); node->SetProperty("outline width", mitk::FloatProperty::New(2.0)); // force render window update to show outline node->GetData()->Modified(); } } } void QmitkSegmentationView::OnContourMarkerSelected(const mitk::DataNode* node) { QmitkRenderWindow* selectedRenderWindow = nullptr; auto* renderWindowPart = this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN); auto* axialRenderWindow = renderWindowPart->GetQmitkRenderWindow("axial"); auto* sagittalRenderWindow = renderWindowPart->GetQmitkRenderWindow("sagittal"); auto* coronalRenderWindow = renderWindowPart->GetQmitkRenderWindow("coronal"); auto* threeDRenderWindow = renderWindowPart->GetQmitkRenderWindow("3d"); bool PlanarFigureInitializedWindow = false; // find initialized renderwindow if (node->GetBoolProperty("PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, axialRenderWindow->GetRenderer())) { selectedRenderWindow = axialRenderWindow; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, sagittalRenderWindow->GetRenderer())) { selectedRenderWindow = sagittalRenderWindow; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, coronalRenderWindow->GetRenderer())) { selectedRenderWindow = coronalRenderWindow; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, threeDRenderWindow->GetRenderer())) { selectedRenderWindow = threeDRenderWindow; } // make node visible if (nullptr != selectedRenderWindow) { std::string nodeName = node->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int id = atof(nodeName.substr(t + 1).c_str()) - 1; ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); selectedRenderWindow->GetSliceNavigationController()->ExecuteOperation(service->GetPlanePosition(id)); context->ungetService(ppmRef); selectedRenderWindow->GetRenderer()->GetCameraController()->Fit(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkSegmentationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) { if (0 == nodes.size()) { return; } std::string markerName = "Position"; unsigned int numberOfNodes = nodes.size(); std::string nodeName = nodes.at(0)->GetName(); if ((numberOfNodes == 1) && (nodeName.find(markerName) == 0)) { this->OnContourMarkerSelected(nodes.at(0)); return; } } void QmitkSegmentationView::ResetMouseCursor() { if (m_MouseCursorSet) { mitk::ApplicationCursor::GetInstance()->PopCursor(); m_MouseCursorSet = false; } } void QmitkSegmentationView::SetMouseCursor(const us::ModuleResource& resource, int hotspotX, int hotspotY) { // Remove previously set mouse cursor if (m_MouseCursorSet) { this->ResetMouseCursor(); } if (resource) { us::ModuleResourceStream cursor(resource, std::ios::binary); mitk::ApplicationCursor::GetInstance()->PushCursor(cursor, hotspotX, hotspotY); m_MouseCursorSet = true; } } void QmitkSegmentationView::UpdateGUI() { mitk::DataNode* referenceNode = m_ToolManager->GetReferenceData(0); bool hasReferenceNode = referenceNode != nullptr; mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); bool hasWorkingNode = workingNode != nullptr; m_Controls->newSegmentationButton->setEnabled(false); m_Controls->slicesInterpolator->setEnabled(false); if (hasReferenceNode) { m_Controls->newSegmentationButton->setEnabled(true); } if (hasWorkingNode && hasReferenceNode) { m_Controls->slicesInterpolator->setEnabled(true); int layer = -1; referenceNode->GetIntProperty("layer", layer); workingNode->SetIntProperty("layer", layer + 1); } + m_Controls->layersWidget->UpdateGUI(); + m_Controls->labelsWidget->UpdateGUI(); + this->ValidateSelectionInput(); } void QmitkSegmentationView::ValidateSelectionInput() { this->UpdateWarningLabel(""); // the argument is actually not used // enable status depends on the tool manager selection m_Controls->toolSelectionBox2D->setEnabled(false); m_Controls->toolSelectionBox3D->setEnabled(false); mitk::DataNode* referenceNode = m_Controls->referenceNodeSelector->GetSelectedNode(); mitk::DataNode* workingNode = m_Controls->workingNodeSelector->GetSelectedNode(); if (nullptr == referenceNode) { return; } if (nullptr == workingNode) { return; } mitk::IRenderWindowPart* renderWindowPart = this->GetRenderWindowPart(); auto workingNodeIsVisible = renderWindowPart && workingNode->IsVisible(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer()); if (!workingNodeIsVisible) { this->UpdateWarningLabel(tr("The selected segmentation is currently not visible!")); return; } /* * Here we check whether the geometry of the selected segmentation image is aligned with the worldgeometry. * At the moment it is not supported to use a geometry different from the selected image for reslicing. * For further information see Bug 16063 */ const mitk::BaseGeometry* workingNodeGeo = workingNode->GetData()->GetGeometry(); const mitk::BaseGeometry* worldGeo = renderWindowPart->GetQmitkRenderWindow("3d")->GetSliceNavigationController()->GetCurrentGeometry3D(); if (nullptr != workingNodeGeo && nullptr != worldGeo) { if (mitk::Equal(*workingNodeGeo->GetBoundingBox(), *worldGeo->GetBoundingBox(), mitk::eps, true)) { m_ToolManager->SetReferenceData(referenceNode); m_ToolManager->SetWorkingData(workingNode); m_Controls->toolSelectionBox2D->setEnabled(true); m_Controls->toolSelectionBox3D->setEnabled(true); return; } } m_ToolManager->SetReferenceData(referenceNode); m_ToolManager->SetWorkingData(nullptr); this->UpdateWarningLabel(tr("Please perform a reinit on the segmentation image!")); } void QmitkSegmentationView::UpdateWarningLabel(QString text) { if (text.size() == 0) { m_Controls->selectionWarningLabel->hide(); } else { m_Controls->selectionWarningLabel->show(); m_Controls->selectionWarningLabel->setText("" + text + ""); } } diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h index f417676bff..ae08604655 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h @@ -1,131 +1,133 @@ /*============================================================================ 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 QMITKSEGMENTATIONVIEW_H #define QMITKSEGMENTATIONVIEW_H #include "ui_QmitkSegmentationViewControls.h" #include #include #include /** * @brief The segmentation view provides a set of tool to use different segmentation algorithms. * It provides two selection widgets to load an image node and a segmentation node * on which to perform the segmentation. Creating new segmentation nodes is also possible. * The available segmentation tools are grouped into "2D"- and "3D"-tools. * * Most segmentation tools / algorithms need some kind of user interaction, where the * user is asked to draw something in the image display or set some seed points / start values. * The tools also often provide additional propeties so that a user can modify the * algorithm's behavior. * * This class additionally provides options to work with different layers (create new layers, * switch between layers). * Moreover, a multilabel widget displays all the existing labels of a multilabel segmentation * for the currently active layer. * The multilabel widget allows to control the labels by creatin new one, removing existing ones, * showing / hiding single labels, merging labels, (re-)naming them etc. * * Additionally the view provides an option to create "2D"- and "3D"-interpolations between * neighboring segmentation masks on unsegmented slices. */ class QmitkSegmentationView : public QmitkAbstractView, public mitk::IRenderWindowPartListener { Q_OBJECT public: static const std::string VIEW_ID; QmitkSegmentationView(); ~QmitkSegmentationView() override; private Q_SLOTS: // reaction to the selection of a new reference image in the selection widget void OnReferenceSelectionChanged(QList nodes); // reaction to the selection of a new segmentation image in the selection widget void OnSegmentationSelectionChanged(QList nodes); // reaction to the button "New segmentation" void OnNewSegmentation(); void OnManualTool2DSelected(int id); void OnShowMarkerNodes(bool); void OnLayersChanged(); + void OnLabelsChanged(); + private: void CreateQtPartControl(QWidget* parent) override; void SetFocus() override {} void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) override; void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) override; void OnPreferencesChanged(const berry::IBerryPreferences* prefs) override; void NodeAdded(const mitk::DataNode* node) override; void NodeRemoved(const mitk::DataNode* node) override; // make sure all images / segmentations look according to the user preference settings void ApplyDisplayOptions(); // decorates a DataNode according to the user preference settings void ApplyDisplayOptions(mitk::DataNode* node); // If a contourmarker is selected, the plane in the related widget will be reoriented according to the marker`s geometry void OnContourMarkerSelected(const mitk::DataNode* node); void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList &nodes) override; void ResetMouseCursor(); void SetMouseCursor(const us::ModuleResource&, int hotspotX, int hotspotY); void UpdateGUI(); void ValidateSelectionInput(); void UpdateWarningLabel(QString text); QWidget* m_Parent; Ui::QmitkSegmentationViewControls* m_Controls; mitk::IRenderWindowPart* m_RenderWindowPart; mitk::ToolManager* m_ToolManager; mitk::DataNode::Pointer m_ReferenceNode; mitk::DataNode::Pointer m_WorkingNode; typedef std::map NodeTagMapType; NodeTagMapType m_WorkingDataObserverTags; unsigned int m_RenderingManagerObserverTag; mitk::NodePredicateAnd::Pointer m_ReferencePredicate; mitk::NodePredicateAnd::Pointer m_SegmentationPredicate; bool m_AutoSelectionEnabled; bool m_MouseCursorSet; }; #endif // QMITKSEGMENTATIONVIEW_H diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationViewControls.ui b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationViewControls.ui index a9d41d9142..595e2dbba9 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationViewControls.ui @@ -1,289 +1,306 @@ QmitkSegmentationViewControls 0 0 300 600 0 0 0 0 Data selection Selected image 0 40 Selected segmentation 0 40 Create a new segmentation New... Qt::ToolButtonTextOnly 0 0 true 0 0 + + + + + 0 + 0 + + + + + 0 0 QTabWidget::tab-bar { alignment: middle; } 0 2D tools 0 0 50 false 0 0 50 false 0 0 50 false Qt::Vertical 20 40 3D tools 0 0 50 false 0 0 50 false Qt::Vertical 20 40 Qt::Vertical 20 40 QmitkSingleNodeSelectionWidget QWidget
QmitkSingleNodeSelectionWidget.h
1
QmitkLayersWidget QWidget
internal/Common/QmitkLayersWidget.h
1
+ + QmitkLabelsWidget + QWidget +
internal/Common/QmitkLabelsWidget.h
+ 1 +
QmitkToolSelectionBox QWidget
QmitkToolSelectionBox.h
QmitkToolGUIArea QWidget
QmitkToolGUIArea.h
QmitkSlicesInterpolator QWidget
QmitkSlicesInterpolator.h
diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/mitkPluginActivator.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/mitkPluginActivator.cpp index 6d27f32fde..2e080b5c7e 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/mitkPluginActivator.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/mitkPluginActivator.cpp @@ -1,61 +1,66 @@ /*============================================================================ 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 "mitkPluginActivator.h" #include "QmitkSegmentationView.h" -#include "QmitkCreatePolygonModelAction.h" -#include "QmitkAutocropAction.h" -#include "QmitkAutocropLabelSetImageAction.h" #include "QmitkSegmentationPreferencePage.h" #include "SegmentationUtilities/QmitkSegmentationUtilitiesView.h" +#include "QmitkAutocropAction.h" +#include "QmitkAutocropLabelSetImageAction.h" +#include "QmitkCreatePolygonModelAction.h" +#include "QmitkLoadMultiLabelPresetAction.h" +#include "QmitkSaveMultiLabelPresetAction.h" + using namespace mitk; ctkPluginContext* PluginActivator::m_context = nullptr; PluginActivator* PluginActivator::m_Instance = nullptr; PluginActivator::PluginActivator() { m_Instance = this; } PluginActivator::~PluginActivator() { m_Instance = nullptr; } void PluginActivator::start(ctkPluginContext *context) { BERRY_REGISTER_EXTENSION_CLASS(QmitkSegmentationView, context) - BERRY_REGISTER_EXTENSION_CLASS(QmitkCreatePolygonModelAction, context) - BERRY_REGISTER_EXTENSION_CLASS(QmitkAutocropAction, context) - BERRY_REGISTER_EXTENSION_CLASS(QmitkAutocropLabelSetImageAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkSegmentationPreferencePage, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkSegmentationUtilitiesView, context) + BERRY_REGISTER_EXTENSION_CLASS(QmitkAutocropAction, context) + BERRY_REGISTER_EXTENSION_CLASS(QmitkAutocropLabelSetImageAction, context) + BERRY_REGISTER_EXTENSION_CLASS(QmitkCreatePolygonModelAction, context) + BERRY_REGISTER_EXTENSION_CLASS(QmitkLoadMultiLabelPresetAction, context) + BERRY_REGISTER_EXTENSION_CLASS(QmitkSaveMultiLabelPresetAction, context) this->m_context = context; } void PluginActivator::stop(ctkPluginContext *) { this->m_context = nullptr; } PluginActivator* PluginActivator::getDefault() { return m_Instance; } ctkPluginContext*PluginActivator::getContext() { return m_context; }