diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/Common/QmitkDataSelectionWidget.cpp b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/Common/QmitkDataSelectionWidget.cpp index 7bf1533566..04232da4f3 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/Common/QmitkDataSelectionWidget.cpp +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/Common/QmitkDataSelectionWidget.cpp @@ -1,183 +1,224 @@ /*============================================================================ 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 "QmitkDataSelectionWidget.h" #include "internal/mitkPluginActivator.h" #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include #include static mitk::NodePredicateBase::Pointer CreatePredicate(QmitkDataSelectionWidget::PredicateType predicateType) { mitk::NodePredicateAnd::Pointer segmentationPredicate = mitk::NodePredicateAnd::New(); segmentationPredicate->AddPredicate(mitk::TNodePredicateDataType::New()); segmentationPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); mitk::NodePredicateAnd::Pointer maskPredicate = mitk::NodePredicateAnd::New(); maskPredicate->AddPredicate(mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true))); maskPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true)))); mitk::NodePredicateDataType::Pointer isDwi = mitk::NodePredicateDataType::New("DiffusionImage"); mitk::NodePredicateDataType::Pointer isDti = mitk::NodePredicateDataType::New("TensorImage"); mitk::NodePredicateDataType::Pointer isOdf = mitk::NodePredicateDataType::New("OdfImage"); mitk::TNodePredicateDataType::Pointer isImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateOr::Pointer validImages = mitk::NodePredicateOr::New(); validImages->AddPredicate(isImage); validImages->AddPredicate(isDwi); validImages->AddPredicate(isDti); validImages->AddPredicate(isOdf); mitk::NodePredicateAnd::Pointer imagePredicate = mitk::NodePredicateAnd::New(); imagePredicate->AddPredicate(validImages); imagePredicate->AddPredicate(mitk::NodePredicateNot::New(segmentationPredicate)); imagePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)))); imagePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true)))); mitk::NodePredicateAnd::Pointer surfacePredicate = mitk::NodePredicateAnd::New(); surfacePredicate->AddPredicate(mitk::TNodePredicateDataType::New()); surfacePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true)))); switch(predicateType) { case QmitkDataSelectionWidget::ImagePredicate: return imagePredicate.GetPointer(); case QmitkDataSelectionWidget::MaskPredicate: return maskPredicate.GetPointer(); case QmitkDataSelectionWidget::SegmentationPredicate: return segmentationPredicate.GetPointer(); case QmitkDataSelectionWidget::SurfacePredicate: return surfacePredicate.GetPointer(); default: assert(false && "Unknown predefined predicate!"); return nullptr; } } QmitkDataSelectionWidget::QmitkDataSelectionWidget(QWidget* parent) : QWidget(parent) { m_Controls.setupUi(this); m_Controls.helpLabel->hide(); } QmitkDataSelectionWidget::~QmitkDataSelectionWidget() { } unsigned int QmitkDataSelectionWidget::AddDataStorageComboBox(QmitkDataSelectionWidget::PredicateType predicate) { - return this->AddDataStorageComboBox("", predicate); + QString hint = "Select node"; + QString popupTitel = "Select node"; + + switch (predicate) + { + case QmitkDataSelectionWidget::ImagePredicate: + hint = "Select an image"; + popupTitel = "Select an image"; + break; + + case QmitkDataSelectionWidget::MaskPredicate: + hint = "Select a binary mask"; + popupTitel = "Select a binary mask"; + break; + + case QmitkDataSelectionWidget::SegmentationPredicate: + hint = "Select a ML segmentation"; + popupTitel = "Select a ML segmentation"; + break; + + case QmitkDataSelectionWidget::SurfacePredicate: + hint = "Select a surface"; + popupTitel = "Select a surface"; + break; + } + + return this->AddDataStorageComboBox("", hint, popupTitel, "", predicate); } unsigned int QmitkDataSelectionWidget::AddDataStorageComboBox(mitk::NodePredicateBase* predicate) { - return this->AddDataStorageComboBox("", predicate); + return this->AddDataStorageComboBox("", "Select a node", "Select a node", "", predicate); } -unsigned int QmitkDataSelectionWidget::AddDataStorageComboBox(const QString &labelText, QmitkDataSelectionWidget::PredicateType predicate) +unsigned int QmitkDataSelectionWidget::AddDataStorageComboBox(const QString &labelText, const QString &info, const QString &popupTitel, const QString &popupHint, QmitkDataSelectionWidget::PredicateType predicate) { - return this->AddDataStorageComboBox(labelText, CreatePredicate(predicate)); + return this->AddDataStorageComboBox(labelText, info, popupHint, popupTitel, CreatePredicate(predicate)); } -unsigned int QmitkDataSelectionWidget::AddDataStorageComboBox(const QString &labelText, mitk::NodePredicateBase* predicate) +unsigned int QmitkDataSelectionWidget::AddDataStorageComboBox(const QString &labelText, const QString &info, const QString &popupTitel, const QString &popupHint, mitk::NodePredicateBase* predicate) { int row = m_Controls.gridLayout->rowCount(); if (!labelText.isEmpty()) { QLabel* label = new QLabel(labelText, m_Controls.dataSelectionWidget); label->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); m_Controls.gridLayout->addWidget(label, row, 0); } - QmitkDataStorageComboBox* comboBox = new QmitkDataStorageComboBox(this->GetDataStorage(), predicate, m_Controls.dataSelectionWidget); - connect(comboBox, SIGNAL(OnSelectionChanged(const mitk::DataNode *)), this, SLOT(OnSelectionChanged(const mitk::DataNode *))); - comboBox->SetAutoSelectNewItems(true); - m_Controls.gridLayout->addWidget(comboBox, row, 1); + QmitkSingleNodeSelectionWidget* nodeSelection = new QmitkSingleNodeSelectionWidget(m_Controls.dataSelectionWidget); - m_DataStorageComboBoxes.push_back(comboBox); - return static_cast(m_DataStorageComboBoxes.size() - 1); + nodeSelection->SetSelectionIsOptional(false); + nodeSelection->SetAutoSelectNewNodes(false); + nodeSelection->SetInvalidInfo(info); + nodeSelection->SetPopUpTitel(popupTitel); + nodeSelection->SetPopUpHint(popupHint); + nodeSelection->SetDataStorage(this->GetDataStorage()); + nodeSelection->SetNodePredicate(predicate); + nodeSelection->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + nodeSelection->setMinimumSize(0, 40); + + connect(nodeSelection, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(OnSelectionChanged(QList))); + m_Controls.gridLayout->addWidget(nodeSelection, row, 1); + + m_NodeSelectionWidgets.push_back(nodeSelection); + return static_cast(m_NodeSelectionWidgets.size() - 1); } mitk::DataStorage::Pointer QmitkDataSelectionWidget::GetDataStorage() const { ctkServiceReference ref = mitk::PluginActivator::getContext()->getServiceReference(); assert(ref == true); mitk::IDataStorageService* service = mitk::PluginActivator::getContext()->getService(ref); assert(service); return service->GetDefaultDataStorage()->GetDataStorage(); } mitk::DataNode::Pointer QmitkDataSelectionWidget::GetSelection(unsigned int index) { - assert(index < m_DataStorageComboBoxes.size()); - return m_DataStorageComboBoxes[index]->GetSelectedNode(); + assert(index < m_NodeSelectionWidgets.size()); + return m_NodeSelectionWidgets[index]->GetSelectedNode(); } void QmitkDataSelectionWidget::SetPredicate(unsigned int index, PredicateType predicate) { this->SetPredicate(index, CreatePredicate(predicate)); } void QmitkDataSelectionWidget::SetPredicate(unsigned int index, mitk::NodePredicateBase* predicate) { - assert(index < m_DataStorageComboBoxes.size()); - m_DataStorageComboBoxes[index]->SetPredicate(predicate); + assert(index < m_NodeSelectionWidgets.size()); + m_NodeSelectionWidgets[index]->SetNodePredicate(predicate); } void QmitkDataSelectionWidget::SetHelpText(const QString& text) { if (!text.isEmpty()) { m_Controls.helpLabel->setText(text); if (!m_Controls.helpLabel->isVisible()) m_Controls.helpLabel->show(); } else { m_Controls.helpLabel->hide(); } } -void QmitkDataSelectionWidget::OnSelectionChanged(const mitk::DataNode* selection) +void QmitkDataSelectionWidget::OnSelectionChanged(QList selection) { - std::vector::iterator it = std::find(m_DataStorageComboBoxes.begin(), m_DataStorageComboBoxes.end(), sender()); - assert(it != m_DataStorageComboBoxes.end()); + std::vector::iterator it = std::find(m_NodeSelectionWidgets.begin(), m_NodeSelectionWidgets.end(), sender()); + assert(it != m_NodeSelectionWidgets.end()); - emit SelectionChanged(std::distance(m_DataStorageComboBoxes.begin(), it), selection); + const mitk::DataNode* result = nullptr; + if (!selection.empty()) + { + result = selection.front(); + } + emit SelectionChanged(std::distance(m_NodeSelectionWidgets.begin(), it), result); } diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/Common/QmitkDataSelectionWidget.h b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/Common/QmitkDataSelectionWidget.h index 23502425f4..b85f0b59da 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/Common/QmitkDataSelectionWidget.h +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/Common/QmitkDataSelectionWidget.h @@ -1,66 +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. ============================================================================*/ #ifndef QmitkDataSelectionWidget_h #define QmitkDataSelectionWidget_h #include #include #include #include namespace mitk { class NodePredicateBase; } -class QmitkDataStorageComboBox; +class QmitkSingleNodeSelectionWidget; class QmitkDataSelectionWidget : public QWidget { Q_OBJECT public: enum PredicateType { ImagePredicate, MaskPredicate, SegmentationPredicate, SurfacePredicate }; explicit QmitkDataSelectionWidget(QWidget* parent = nullptr); ~QmitkDataSelectionWidget() override; unsigned int AddDataStorageComboBox(PredicateType predicate); unsigned int AddDataStorageComboBox(mitk::NodePredicateBase* predicate = nullptr); - unsigned int AddDataStorageComboBox(const QString &labelText, PredicateType predicate); - unsigned int AddDataStorageComboBox(const QString &labelText, mitk::NodePredicateBase* predicate = nullptr); + unsigned int AddDataStorageComboBox(const QString &labelText, const QString &info, const QString &popupTitel, const QString &popupHint, PredicateType predicate); + unsigned int AddDataStorageComboBox(const QString &labelText, const QString &info, const QString &popupTitel, const QString &popupHint, mitk::NodePredicateBase* predicate = nullptr); mitk::DataStorage::Pointer GetDataStorage() const; mitk::DataNode::Pointer GetSelection(unsigned int index); void SetPredicate(unsigned int index, PredicateType predicate); void SetPredicate(unsigned int index, mitk::NodePredicateBase* predicate); void SetHelpText(const QString& text); signals: void SelectionChanged(unsigned int index, const mitk::DataNode* selection); private slots: - void OnSelectionChanged(const mitk::DataNode* selection); + void OnSelectionChanged(QList selection); private: Ui::QmitkDataSelectionWidgetControls m_Controls; - std::vector m_DataStorageComboBoxes; + std::vector m_NodeSelectionWidgets; }; #endif diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationControls.ui b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationControls.ui index 8f55f99d5d..cfa09e6ac2 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationControls.ui +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationControls.ui @@ -1,760 +1,761 @@ QmitkMultiLabelSegmentationControls 0 0 459 844 0 0 0 0 MS Shell Dlg 2 8 50 false false false false QmitkSegmentation 0 0 Data Selection Patient Image - - - - 0 - 0 - - - + + + + 0 + 40 + + + Create a new segmentation session ... :/multilabelsegmentation/NewSegmentationSession_48x48.png:/multilabelsegmentation/NewSegmentationSession_48x48.png 28 28 N true Segmentation - - - - 0 - 0 - - - + + + + 0 + 40 + + + Layers true false Add a layer to the current segmentation session ... :/Qmitk/AddLayer_48x48.png:/Qmitk/AddLayer_48x48.png 28 28 true Delete the active layer ... :/Qmitk/DeleteLayer_48x48.png:/Qmitk/DeleteLayer_48x48.png 28 28 true Qt::Horizontal 0 20 Change to the previous available layer ... :/Qmitk/PreviousLayer_48x48.png:/Qmitk/PreviousLayer_48x48.png 28 28 true Change to the next available layer ... :/Qmitk/NextLayer_48x48.png:/Qmitk/NextLayer_48x48.png 28 28 true 0 0 50 30 40 30 12 Switch to a layer 0 Labels true Add a new label to the current segmentation session ... :/multilabelsegmentation/NewLabel_48x48.png:/multilabelsegmentation/NewLabel_48x48.png 28 28 N true Lock/Unlock exterior ... :/Qmitk/UnlockExterior_48x48.png :/Qmitk/LockExterior_48x48.png:/Qmitk/UnlockExterior_48x48.png 28 28 true true Qt::Horizontal 0 20 0 34 Show a table with all labels in the current segmentation session >> 28 28 true false Qt::NoArrow 0 0 0 20 0 0 QTabWidget::tab-bar { alignment: middle; } 0 true false 2D Tools 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 0 0 Interpolation 2 QLayout::SetMinimumSize 2 2 2 2 0 0 Disabled 2D Interpolation 3D Interpolation 0 0 1 0 0 QLayout::SetMinimumSize 0 0 0 0 0 0 0 0 50 false 0 0 QLayout::SetMinimumSize 0 0 0 0 0 0 0 50 50 false 0 0 Qt::Vertical 20 40 m_LabelSetWidget groupBox_DataSelection m_tw2DTools m_gbInterpolation groupBox_Layer groupBox_Labels - - QmitkDataStorageComboBox - QComboBox -
QmitkDataStorageComboBox.h
-
- + + QmitkSingleNodeSelectionWidget + QWidget +
QmitkSingleNodeSelectionWidget.h
+ 1 +
+ QmitkToolSelectionBox QWidget
QmitkToolSelectionBox.h
QmitkToolGUIArea QWidget
QmitkToolGUIArea.h
QmitkLabelSetWidget QWidget
Qmitk/QmitkLabelSetWidget.h
1
QmitkSliceBasedInterpolatorWidget QWidget
QmitkSliceBasedInterpolatorWidget.h
1
QmitkSurfaceBasedInterpolatorWidget QWidget
QmitkSurfaceBasedInterpolatorWidget.h
1
QmitkToolReferenceDataSelectionBox.h QmitkToolGUIArea.h QmitkToolSelectionBox.h
diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.cpp b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.cpp index 56f18be8af..cbcd0d9a23 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.cpp +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.cpp @@ -1,1203 +1,1062 @@ /*============================================================================ 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 "QmitkMultiLabelSegmentationView.h" // blueberry #include #include // mitk #include "mitkApplicationCursor.h" #include "mitkLabelSetImage.h" #include "mitkStatusBar.h" #include "mitkToolManagerProvider.h" -//#include "mitkSegmentationObjectFactory.h" #include "mitkInteractionEventObserver.h" #include "mitkPlanePositionManager.h" #include "mitkPluginActivator.h" #include "mitkSegTool2D.h" #include "mitkImageTimeSelector.h" +#include "mitkNodePredicateFunction.h" // Qmitk #include "QmitkNewSegmentationDialog.h" #include "QmitkRenderWindow.h" #include "QmitkSegmentationOrganNamesHandling.cpp" // us #include #include #include #include #include // Qt #include #include #include #include #include #include "tinyxml.h" #include #include const std::string QmitkMultiLabelSegmentationView::VIEW_ID = "org.mitk.views.multilabelsegmentation"; QmitkMultiLabelSegmentationView::QmitkMultiLabelSegmentationView() : m_Parent(nullptr), m_IRenderWindowPart(nullptr), m_ToolManager(nullptr), m_ReferenceNode(nullptr), m_WorkingNode(nullptr), m_AutoSelectionEnabled(false), m_MouseCursorSet(false) { m_SegmentationPredicate = mitk::NodePredicateAnd::New(); m_SegmentationPredicate->AddPredicate(mitk::TNodePredicateDataType::New()); m_SegmentationPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); mitk::TNodePredicateDataType::Pointer isImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isMask = mitk::NodePredicateAnd::New(isBinary, isImage); mitk::NodePredicateDataType::Pointer isDwi = mitk::NodePredicateDataType::New("DiffusionImage"); mitk::NodePredicateDataType::Pointer isDti = mitk::NodePredicateDataType::New("TensorImage"); mitk::NodePredicateDataType::Pointer isOdf = mitk::NodePredicateDataType::New("OdfImage"); auto isSegment = mitk::NodePredicateDataType::New("Segment"); mitk::NodePredicateOr::Pointer validImages = mitk::NodePredicateOr::New(); validImages->AddPredicate(mitk::NodePredicateAnd::New(isImage, mitk::NodePredicateNot::New(isSegment))); validImages->AddPredicate(isDwi); validImages->AddPredicate(isDti); validImages->AddPredicate(isOdf); m_ReferencePredicate = mitk::NodePredicateAnd::New(); m_ReferencePredicate->AddPredicate(validImages); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(m_SegmentationPredicate)); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(isMask)); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); } QmitkMultiLabelSegmentationView::~QmitkMultiLabelSegmentationView() { - // m_ToolManager->ActivateTool(-1); - /* - todo: check this - m_Controls.m_SliceBasedInterpolatorWidget->EnableInterpolation(false); - 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); - - // m_ServiceRegistration.Unregister(); - // Loose LabelSetConnections OnLooseLabelSetConnection(); } void QmitkMultiLabelSegmentationView::CreateQtPartControl(QWidget *parent) { // setup the basic GUI of this view m_Parent = parent; m_Controls.setupUi(parent); // *------------------------ // * Shortcuts // *------------------------ QShortcut* visibilityShortcut = new QShortcut(QKeySequence("CTRL+H"), parent); connect(visibilityShortcut, &QShortcut::activated, this, &QmitkMultiLabelSegmentationView::OnVisibilityShortcutActivated); QShortcut* labelToggleShortcut = new QShortcut(QKeySequence("CTRL+L"), parent); connect(labelToggleShortcut, &QShortcut::activated, this, &QmitkMultiLabelSegmentationView::OnLabelToggleShortcutActivated); // *------------------------ // * DATA SELECTION WIDGETS // *------------------------ - m_Controls.m_cbReferenceNodeSelector->SetAutoSelectNewItems(true); - m_Controls.m_cbReferenceNodeSelector->SetPredicate(m_ReferencePredicate); - m_Controls.m_cbReferenceNodeSelector->SetDataStorage(this->GetDataStorage()); + m_Controls.m_ReferenceNodeSelector->SetNodePredicate(m_ReferencePredicate); + m_Controls.m_ReferenceNodeSelector->SetDataStorage(this->GetDataStorage()); + m_Controls.m_ReferenceNodeSelector->SetInvalidInfo("Select an image"); + m_Controls.m_ReferenceNodeSelector->SetPopUpTitel("Select an image"); + m_Controls.m_ReferenceNodeSelector->SetPopUpHint("Select an image that should be used to define the geometry and bounds of the segmentation."); + - m_Controls.m_cbWorkingNodeSelector->SetAutoSelectNewItems(true); - m_Controls.m_cbWorkingNodeSelector->SetPredicate(m_SegmentationPredicate); - m_Controls.m_cbWorkingNodeSelector->SetDataStorage(this->GetDataStorage()); + m_Controls.m_WorkingNodeSelector->SetNodePredicate(m_SegmentationPredicate); + m_Controls.m_WorkingNodeSelector->SetDataStorage(this->GetDataStorage()); + m_Controls.m_WorkingNodeSelector->SetInvalidInfo("Select a segmentation"); + m_Controls.m_WorkingNodeSelector->SetPopUpTitel("Select a segmentation"); + m_Controls.m_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.m_cbReferenceNodeSelector, - SIGNAL(OnSelectionChanged(const mitk::DataNode *)), + connect(m_Controls.m_ReferenceNodeSelector, + SIGNAL(CurrentSelectionChanged(QList)), this, - SLOT(OnReferenceSelectionChanged(const mitk::DataNode *))); + SLOT(OnReferenceSelectionChanged(QList))); - connect(m_Controls.m_cbWorkingNodeSelector, - SIGNAL(OnSelectionChanged(const mitk::DataNode *)), + connect(m_Controls.m_WorkingNodeSelector, + SIGNAL(CurrentSelectionChanged(QList)), this, - SLOT(OnSegmentationSelectionChanged(const mitk::DataNode *))); + SLOT(OnSegmentationSelectionChanged(QList))); // *------------------------ // * ToolManager // *------------------------ m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); assert(m_ToolManager); m_ToolManager->SetDataStorage(*(this->GetDataStorage())); m_ToolManager->InitializeTools(); // use the same ToolManager instance for our 3D Tools m_Controls.m_ManualToolSelectionBox3D->SetToolManager(*m_ToolManager); // *------------------------ // * LabelSetWidget // *------------------------ m_Controls.m_LabelSetWidget->SetDataStorage(this->GetDataStorage()); m_Controls.m_LabelSetWidget->SetOrganColors(mitk::OrganNamesHandling::GetDefaultOrganColorString()); m_Controls.m_LabelSetWidget->hide(); // *------------------------ // * Interpolation // *------------------------ m_Controls.m_SurfaceBasedInterpolatorWidget->SetDataStorage(*(this->GetDataStorage())); m_Controls.m_SliceBasedInterpolatorWidget->SetDataStorage(*(this->GetDataStorage())); connect(m_Controls.m_cbInterpolation, SIGNAL(activated(int)), this, SLOT(OnInterpolationSelectionChanged(int))); m_Controls.m_cbInterpolation->setCurrentIndex(0); m_Controls.m_swInterpolation->hide(); QString segTools2D = tr("Add Subtract Fill Erase Paint Wipe 'Region Growing' FastMarching2D Correction 'Live Wire'"); QString segTools3D = tr("Threshold 'Two Thresholds' 'Auto Threshold' 'Multiple Otsu'"); 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())); } } // *------------------------ // * ToolSelection 2D // *------------------------ m_Controls.m_ManualToolSelectionBox2D->SetGenerateAccelerators(true); m_Controls.m_ManualToolSelectionBox2D->SetToolGUIArea(m_Controls.m_ManualToolGUIContainer2D); m_Controls.m_ManualToolSelectionBox2D->SetDisplayedToolGroups(segTools2D.toStdString()); // todo: "Correction // 'Live Wire'" m_Controls.m_ManualToolSelectionBox2D->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); connect(m_Controls.m_ManualToolSelectionBox2D, SIGNAL(ToolSelected(int)), this, SLOT(OnManualTool2DSelected(int))); // *------------------------ // * ToolSelection 3D // *------------------------ m_Controls.m_ManualToolSelectionBox3D->SetGenerateAccelerators(true); m_Controls.m_ManualToolSelectionBox3D->SetToolGUIArea(m_Controls.m_ManualToolGUIContainer3D); m_Controls.m_ManualToolSelectionBox3D->SetDisplayedToolGroups(segTools3D.toStdString()); // todo add : FastMarching3D RegionGrowing Watershed m_Controls.m_ManualToolSelectionBox3D->SetLayoutColumns(2); m_Controls.m_ManualToolSelectionBox3D->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); // *------------------------* // * Connect PushButtons (pb) // *------------------------* connect(m_Controls.m_pbNewLabel, SIGNAL(clicked()), this, SLOT(OnNewLabel())); connect(m_Controls.m_pbNewSegmentationSession, SIGNAL(clicked()), this, SLOT(OnNewSegmentationSession())); connect(m_Controls.m_pbShowLabelTable, SIGNAL(toggled(bool)), this, SLOT(OnShowLabelTable(bool))); // *------------------------* // * Connect LabelSetWidget // *------------------------* connect(m_Controls.m_LabelSetWidget, SIGNAL(goToLabel(const mitk::Point3D &)), this, SLOT(OnGoToLabel(const mitk::Point3D &))); connect(m_Controls.m_LabelSetWidget, SIGNAL(resetView()), this, SLOT(OnResetView())); // *------------------------* // * DATA SLECTION WIDGET // *------------------------* m_IRenderWindowPart = this->GetRenderWindowPart(); if (m_IRenderWindowPart) { QList controllers; controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()); controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()); controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()); m_Controls.m_SliceBasedInterpolatorWidget->SetSliceNavigationControllers(controllers); - // m_Controls.m_LabelSetWidget->SetRenderWindowPart(this->m_IRenderWindowPart); } // this->InitializeListeners(); connect(m_Controls.m_btAddLayer, SIGNAL(clicked()), this, SLOT(OnAddLayer())); connect(m_Controls.m_btDeleteLayer, SIGNAL(clicked()), this, SLOT(OnDeleteLayer())); connect(m_Controls.m_btPreviousLayer, SIGNAL(clicked()), this, SLOT(OnPreviousLayer())); connect(m_Controls.m_btNextLayer, SIGNAL(clicked()), this, SLOT(OnNextLayer())); connect(m_Controls.m_btLockExterior, SIGNAL(toggled(bool)), this, SLOT(OnLockExteriorToggled(bool))); connect(m_Controls.m_cbActiveLayer, SIGNAL(currentIndexChanged(int)), this, SLOT(OnChangeLayer(int))); m_Controls.m_btAddLayer->setEnabled(false); m_Controls.m_btDeleteLayer->setEnabled(false); m_Controls.m_btNextLayer->setEnabled(false); m_Controls.m_btPreviousLayer->setEnabled(false); m_Controls.m_cbActiveLayer->setEnabled(false); m_Controls.m_pbNewLabel->setEnabled(false); m_Controls.m_btLockExterior->setEnabled(false); m_Controls.m_pbShowLabelTable->setEnabled(false); // Make sure the GUI notices if appropriate data is already present on creation - this->OnReferenceSelectionChanged(m_Controls.m_cbReferenceNodeSelector->GetSelectedNode()); - this->OnSegmentationSelectionChanged(m_Controls.m_cbWorkingNodeSelector->GetSelectedNode()); + m_Controls.m_ReferenceNodeSelector->SetAutoSelectNewNodes(true); + m_Controls.m_WorkingNodeSelector->SetAutoSelectNewNodes(true); } void QmitkMultiLabelSegmentationView::Activated() { - m_ToolManager->SetReferenceData(m_Controls.m_cbReferenceNodeSelector->GetSelectedNode()); - m_ToolManager->SetWorkingData(m_Controls.m_cbWorkingNodeSelector->GetSelectedNode()); + m_ToolManager->SetReferenceData(m_Controls.m_ReferenceNodeSelector->GetSelectedNode()); + m_ToolManager->SetWorkingData(m_Controls.m_WorkingNodeSelector->GetSelectedNode()); } void QmitkMultiLabelSegmentationView::Deactivated() { // Not yet implemented } void QmitkMultiLabelSegmentationView::Visible() { // Not yet implemented } void QmitkMultiLabelSegmentationView::Hidden() { // Not yet implemented } int QmitkMultiLabelSegmentationView::GetSizeFlags(bool width) { if (!width) { return berry::Constants::MIN | berry::Constants::MAX | berry::Constants::FILL; } else { return 0; } } int QmitkMultiLabelSegmentationView::ComputePreferredSize(bool width, int /*availableParallel*/, int /*availablePerpendicular*/, int preferredResult) { if (width == false) { return 100; } else { return preferredResult; } } /************************************************************************/ /* protected slots */ /************************************************************************/ void QmitkMultiLabelSegmentationView::OnVisibilityShortcutActivated() { mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); bool isVisible = false; workingNode->GetBoolProperty("visible", isVisible); workingNode->SetVisibility(!isVisible); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkMultiLabelSegmentationView::OnLabelToggleShortcutActivated() { mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); WaitCursorOn(); workingImage->GetActiveLabelSet()->SetNextActiveLabel(); workingImage->Modified(); WaitCursorOff(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkMultiLabelSegmentationView::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 QmitkMultiLabelSegmentationView::OnNewLabel() { m_ToolManager->ActivateTool(-1); mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); if (!workingNode) { QMessageBox::information( m_Parent, "New Segmentation Session", "Please load and select a patient image before starting some action."); return; } mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); if (!workingImage) { QMessageBox::information( m_Parent, "New Segmentation Session", "Please load and select a patient image before starting some action."); return; } QmitkNewSegmentationDialog* dialog = new QmitkNewSegmentationDialog(m_Parent); dialog->SetSuggestionList(mitk::OrganNamesHandling::GetDefaultOrganColorString()); dialog->setWindowTitle("New Label"); int dialogReturnValue = dialog->exec(); if (dialogReturnValue == QDialog::Rejected) { return; } QString segName = dialog->GetSegmentationName(); if (segName.isEmpty()) { segName = "Unnamed"; } workingImage->GetActiveLabelSet()->AddLabel(segName.toStdString(), dialog->GetColor()); UpdateControls(); m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); mitk::RenderingManager::GetInstance()->InitializeViews(workingNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); } void QmitkMultiLabelSegmentationView::OnShowLabelTable(bool value) { if (value) m_Controls.m_LabelSetWidget->show(); else m_Controls.m_LabelSetWidget->hide(); } void QmitkMultiLabelSegmentationView::OnNewSegmentationSession() { - mitk::DataNode *referenceNode = m_Controls.m_cbReferenceNodeSelector->GetSelectedNode(); + mitk::DataNode *referenceNode = m_Controls.m_ReferenceNodeSelector->GetSelectedNode(); if (!referenceNode) { QMessageBox::information( m_Parent, "New Segmentation Session", "Please load and select a patient image before starting some action."); return; } m_ToolManager->ActivateTool(-1); mitk::Image::ConstPointer referenceImage = dynamic_cast(referenceNode->GetData()); assert(referenceImage); if (referenceImage->GetDimension() > 3) { auto result = QMessageBox::question(m_Parent, tr("Generate a static mask?"), tr("The selected image has multiple time steps. You can either generate a simple/static masks resembling the geometry of the first timestep of the image. Or you can generate a dynamic mask that equals the selected image in geometry and number of timesteps; thus a dynamic mask can change over time (e.g. according to the image)."), tr("Yes, generate a static mask"), tr("No, generate a dynamic mask"), 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(), 0); newImage->SetTimeGeometry(newTimeGeometry); referenceImage = newImage; } } QString newName = QString::fromStdString(referenceNode->GetName()); newName.append("-labels"); bool ok = false; newName = QInputDialog::getText(m_Parent, "New Segmentation Session", "New name:", QLineEdit::Normal, newName, &ok); if (!ok) { return; } this->WaitCursorOn(); mitk::LabelSetImage::Pointer workingImage = mitk::LabelSetImage::New(); try { workingImage->Initialize(referenceImage); } catch (mitk::Exception& e) { this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(m_Parent, "New Segmentation Session", "Could not create a new segmentation session.\n"); return; } this->WaitCursorOff(); mitk::DataNode::Pointer workingNode = mitk::DataNode::New(); workingNode->SetData(workingImage); workingNode->SetName(newName.toStdString()); workingImage->GetExteriorLabel()->SetProperty("name.parent", mitk::StringProperty::New(referenceNode->GetName().c_str())); workingImage->GetExteriorLabel()->SetProperty("name.image", mitk::StringProperty::New(newName.toStdString().c_str())); if (!GetDataStorage()->Exists(workingNode)) { GetDataStorage()->Add(workingNode, referenceNode); } + m_Controls.m_WorkingNodeSelector->SetCurrentSelectedNode(workingNode); + OnNewLabel(); } void QmitkMultiLabelSegmentationView::OnGoToLabel(const mitk::Point3D& pos) { if (m_IRenderWindowPart) m_IRenderWindowPart->SetSelectedPosition(pos); } void QmitkMultiLabelSegmentationView::OnResetView() { if (m_IRenderWindowPart) m_IRenderWindowPart->ForceImmediateUpdate(); } void QmitkMultiLabelSegmentationView::OnAddLayer() { m_ToolManager->ActivateTool(-1); mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); QString question = "Do you really want to add a layer to the current segmentation session?"; QMessageBox::StandardButton answerButton = QMessageBox::question( m_Controls.m_LabelSetWidget, "Add layer", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton != QMessageBox::Yes) return; try { WaitCursorOn(); workingImage->AddLayer(); WaitCursorOff(); } catch ( mitk::Exception& e ) { WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information( m_Controls.m_LabelSetWidget, "Add Layer", "Could not add a new layer. See error log for details.\n"); return; } OnNewLabel(); } void QmitkMultiLabelSegmentationView::OnDeleteLayer() { m_ToolManager->ActivateTool(-1); mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); if (workingImage->GetNumberOfLayers() < 2) return; QString question = "Do you really want to delete the current layer?"; QMessageBox::StandardButton answerButton = QMessageBox::question( m_Controls.m_LabelSetWidget, "Delete layer", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton != QMessageBox::Yes) { return; } try { this->WaitCursorOn(); workingImage->RemoveLayer(); this->WaitCursorOff(); } catch (mitk::Exception& e) { this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(m_Controls.m_LabelSetWidget, "Delete Layer", "Could not delete the currently active layer. See error log for details.\n"); return; } UpdateControls(); m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); } void QmitkMultiLabelSegmentationView::OnPreviousLayer() { m_ToolManager->ActivateTool(-1); mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage *workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); OnChangeLayer(workingImage->GetActiveLayer() - 1); } void QmitkMultiLabelSegmentationView::OnNextLayer() { m_ToolManager->ActivateTool(-1); mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage *workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); OnChangeLayer(workingImage->GetActiveLayer() + 1); } void QmitkMultiLabelSegmentationView::OnChangeLayer(int layer) { m_ToolManager->ActivateTool(-1); mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage *workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); this->WaitCursorOn(); workingImage->SetActiveLayer(layer); this->WaitCursorOff(); UpdateControls(); m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); } void QmitkMultiLabelSegmentationView::OnDeactivateActiveTool() { m_ToolManager->ActivateTool(-1); } void QmitkMultiLabelSegmentationView::OnLockExteriorToggled(bool checked) { mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); workingImage->GetLabel(0)->SetLocked(checked); } -void QmitkMultiLabelSegmentationView::OnReferenceSelectionChanged(const mitk::DataNode* node) +void QmitkMultiLabelSegmentationView::OnReferenceSelectionChanged(QList nodes) { m_ToolManager->ActivateTool(-1); - m_ReferenceNode = const_cast(node); + auto refNode = m_Controls.m_ReferenceNodeSelector->GetSelectedNode(); + m_ReferenceNode = refNode; m_ToolManager->SetReferenceData(m_ReferenceNode); if (m_ReferenceNode.IsNotNull()) { - if (m_AutoSelectionEnabled) + auto geometryCheck = [refNode](const mitk::DataNode * segNode) { - // if an image is selected find a possible working / segmentation image - mitk::DataStorage::SetOfObjects::ConstPointer derivations = this->GetDataStorage()->GetDerivations(m_ReferenceNode, m_SegmentationPredicate); - if (derivations->Size() != 0) - { - // use the first segmentation child node - m_WorkingNode = derivations->ElementAt(0); - m_ToolManager->SetWorkingData(m_WorkingNode); + return QmitkMultiLabelSegmentationView::CheckForSameGeometry(refNode,segNode); + }; - m_Controls.m_cbWorkingNodeSelector->blockSignals(true); - m_Controls.m_cbWorkingNodeSelector->SetSelectedNode(m_WorkingNode); - m_Controls.m_cbWorkingNodeSelector->blockSignals(false); - } - else if (derivations->size() == 0) - { - m_Controls.m_cbWorkingNodeSelector->setCurrentIndex(-1); - } + mitk::NodePredicateFunction::Pointer hasCorrectGeo = mitk::NodePredicateFunction::New(geometryCheck); + auto segPredicate = mitk::NodePredicateAnd::New(m_SegmentationPredicate.GetPointer(), hasCorrectGeo.GetPointer()); + + m_Controls.m_WorkingNodeSelector->SetNodePredicate(segPredicate); - // hide all image and segmentation nodes to later show only the automatically selected ones + if (m_AutoSelectionEnabled) + { + // hide all image nodes to later show only the automatically selected ones mitk::DataStorage::SetOfObjects::ConstPointer patientNodes = GetDataStorage()->GetSubset(m_ReferencePredicate); for (mitk::DataStorage::SetOfObjects::const_iterator iter = patientNodes->begin(); iter != patientNodes->end(); ++iter) { (*iter)->SetVisibility(false); } - - mitk::DataStorage::SetOfObjects::ConstPointer segmentationNodes = GetDataStorage()->GetSubset(m_SegmentationPredicate); - for (mitk::DataStorage::SetOfObjects::const_iterator iter = segmentationNodes->begin(); iter != segmentationNodes->end(); ++iter) - { - (*iter)->SetVisibility(false); - } } m_ReferenceNode->SetVisibility(true); - - // check match of segmentation and reference image geometries - if (m_WorkingNode.IsNotNull()) - { - mitk::Image* workingImage = dynamic_cast(m_WorkingNode->GetData()); - assert(workingImage); - - mitk::Image* referenceImage = dynamic_cast(node->GetData()); - assert(referenceImage); - - if (!this->CheckForSameGeometry(referenceImage, workingImage)) - { - return; - } - m_WorkingNode->SetVisibility(true); - } } UpdateControls(); - if (m_WorkingNode.IsNotNull()) - { - m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); - mitk::RenderingManager::GetInstance()->InitializeViews(m_WorkingNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); - } } -void QmitkMultiLabelSegmentationView::OnSegmentationSelectionChanged(const mitk::DataNode* node) +void QmitkMultiLabelSegmentationView::OnSegmentationSelectionChanged(QList nodes) { m_ToolManager->ActivateTool(-1); if (m_WorkingNode.IsNotNull()) OnLooseLabelSetConnection(); - m_WorkingNode = const_cast(node); + m_WorkingNode = m_Controls.m_WorkingNodeSelector->GetSelectedNode(); m_ToolManager->SetWorkingData(m_WorkingNode); if (m_WorkingNode.IsNotNull()) { OnEstablishLabelSetConnection(); if (m_AutoSelectionEnabled) { - // if a segmentation is selected find a possible reference image - mitk::DataStorage::SetOfObjects::ConstPointer sources = this->GetDataStorage()->GetSources(m_WorkingNode, m_ReferencePredicate); - if (sources->Size() != 0) - { - m_ReferenceNode = sources->ElementAt(0); - m_ToolManager->SetReferenceData(m_ReferenceNode); - - m_Controls.m_cbReferenceNodeSelector->blockSignals(true); - m_Controls.m_cbReferenceNodeSelector->SetSelectedNode(m_ReferenceNode); - m_Controls.m_cbReferenceNodeSelector->blockSignals(false); - } - else if(sources->size() == 0) - { - m_Controls.m_cbReferenceNodeSelector->setCurrentIndex(-1); - } - - // hide all image and segmentation nodes to later show only the automatically selected ones - mitk::DataStorage::SetOfObjects::ConstPointer patientNodes = GetDataStorage()->GetSubset(m_ReferencePredicate); - for (mitk::DataStorage::SetOfObjects::const_iterator iter = patientNodes->begin(); iter != patientNodes->end(); ++iter) - { - (*iter)->SetVisibility(false); - } - + // hide all segmentation nodes to later show only the automatically selected ones mitk::DataStorage::SetOfObjects::ConstPointer segmentationNodes = GetDataStorage()->GetSubset(m_SegmentationPredicate); for (mitk::DataStorage::SetOfObjects::const_iterator iter = segmentationNodes->begin(); iter != segmentationNodes->end(); ++iter) { (*iter)->SetVisibility(false); } } m_WorkingNode->SetVisibility(true); - - // check match of segmentation and reference image geometries - if (m_ReferenceNode.IsNotNull()) - { - mitk::Image* referenceImage = dynamic_cast(m_ReferenceNode->GetData()); - assert(referenceImage); - - mitk::Image* workingImage = dynamic_cast(m_WorkingNode->GetData()); - assert(workingImage); - - if (!this->CheckForSameGeometry(referenceImage, workingImage)) - { - return; - } - m_ReferenceNode->SetVisibility(true); - } } UpdateControls(); if (m_WorkingNode.IsNotNull()) { m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); mitk::RenderingManager::GetInstance()->InitializeViews(m_WorkingNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); } } void QmitkMultiLabelSegmentationView::OnInterpolationSelectionChanged(int index) { if (index == 1) { m_Controls.m_SurfaceBasedInterpolatorWidget->m_Controls.m_btStart->setChecked(false);//OnToggleWidgetActivation(false); m_Controls.m_swInterpolation->setCurrentIndex(0); m_Controls.m_swInterpolation->show(); } else if (index == 2) { m_Controls.m_SliceBasedInterpolatorWidget->m_Controls.m_btStart->setChecked(false); m_Controls.m_swInterpolation->setCurrentIndex(1); m_Controls.m_swInterpolation->show(); } else { m_Controls.m_SurfaceBasedInterpolatorWidget->m_Controls.m_btStart->setChecked(false); m_Controls.m_SliceBasedInterpolatorWidget->m_Controls.m_btStart->setChecked(false); m_Controls.m_swInterpolation->setCurrentIndex(2); m_Controls.m_swInterpolation->hide(); } } /************************************************************************/ /* protected */ /************************************************************************/ -void QmitkMultiLabelSegmentationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList &nodes) -{ - if (m_AutoSelectionEnabled) - { - // automatically set the reference node and the working node of the multi label plugin - if (1 == nodes.size()) - { - mitk::DataNode::Pointer selectedNode = nodes.at(0); - if (selectedNode.IsNull()) - { - return; - } - - // check selected node - mitk::LabelSetImage::Pointer labelSetImage = dynamic_cast(selectedNode->GetData()); - if (labelSetImage.IsNotNull()) - { - // reset the image / reference node selector in case the current selected segmentation has no image parent - m_Controls.m_cbReferenceNodeSelector->setCurrentIndex(-1); - // selected a label set image (a segmentation ( working node) - m_Controls.m_cbWorkingNodeSelector->SetSelectedNode(selectedNode); - return; - } - - mitk::Image::Pointer selectedImage = dynamic_cast(selectedNode->GetData()); - if (selectedImage.IsNotNull()) - { - // reset the segmentation / working node selector in case the current selected image has no segmentation child - m_Controls.m_cbWorkingNodeSelector->setCurrentIndex(-1); - // selected an image (a reference node) - m_Controls.m_cbReferenceNodeSelector->SetSelectedNode(selectedNode); - return; - } - } - } -} - void QmitkMultiLabelSegmentationView::OnPreferencesChanged(const berry::IBerryPreferences* prefs) { if (m_Parent && m_WorkingNode.IsNotNull()) { m_AutoSelectionEnabled = prefs->GetBool("auto selection", false); mitk::BoolProperty::Pointer drawOutline = mitk::BoolProperty::New(prefs->GetBool("draw outline", true)); mitk::BoolProperty::Pointer volumeRendering = mitk::BoolProperty::New(prefs->GetBool("volume rendering", false)); mitk::LabelSetImage* labelSetImage; mitk::DataNode* segmentation; // iterate all segmentations (binary (single label) and LabelSetImages) mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateOr::Pointer allSegmentationsPredicate = mitk::NodePredicateOr::New(isBinaryPredicate, m_SegmentationPredicate); mitk::DataStorage::SetOfObjects::ConstPointer allSegmentations = GetDataStorage()->GetSubset(allSegmentationsPredicate); for (mitk::DataStorage::SetOfObjects::const_iterator it = allSegmentations->begin(); it != allSegmentations->end(); ++it) { segmentation = *it; labelSetImage = dynamic_cast(segmentation->GetData()); if (nullptr != labelSetImage) { // segmentation node is a multi label segmentation segmentation->SetProperty("labelset.contour.active", drawOutline); //segmentation->SetProperty("opacity", mitk::FloatProperty::New(drawOutline->GetValue() ? 1.0f : 0.3f)); segmentation->SetProperty("volumerendering", volumeRendering); // force render window update to show outline segmentation->GetData()->Modified(); } else if (nullptr != segmentation->GetData()) { // node is actually a 'single label' segmentation, // but its outline property can be set in the 'multi label' segmentation preference page as well bool isBinary = false; segmentation->GetBoolProperty("binary", isBinary); if (isBinary) { segmentation->SetProperty("outline binary", drawOutline); segmentation->SetProperty("outline width", mitk::FloatProperty::New(2.0)); //segmentation->SetProperty("opacity", mitk::FloatProperty::New(drawOutline->GetValue() ? 1.0f : 0.3f)); segmentation->SetProperty("volumerendering", volumeRendering); // force render window update to show outline segmentation->GetData()->Modified(); } } else { // "interpolation feedback" data nodes have binary flag but don't have a data set. So skip them for now. MITK_INFO << "DataNode " << segmentation->GetName() << " doesn't contain a base data."; } } } } -void QmitkMultiLabelSegmentationView::NodeAdded(const mitk::DataNode *) -{ - /* - bool isHelperObject(false); - node->GetBoolProperty("helper object", isHelperObject); - if (isHelperObject) return; - - if (m_ReferenceNode.IsNotNull() && dynamic_cast(node->GetData())) - { - mitk::LabelSetImage* workingImage = dynamic_cast(node->GetData()); - - if (workingImage->GetNumberOfLabels() > 2) - m_Controls.m_LabelSetWidget->show(); - else - m_Controls.m_LabelSetWidget->hide(); - } - */ -} - void QmitkMultiLabelSegmentationView::NodeRemoved(const mitk::DataNode *node) { bool isHelperObject(false); node->GetBoolProperty("helper object", isHelperObject); if (isHelperObject) { return; } if (m_ReferenceNode.IsNotNull() && dynamic_cast(node->GetData())) { // 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; } } void QmitkMultiLabelSegmentationView::OnEstablishLabelSetConnection() { if (m_WorkingNode.IsNull()) { return; } mitk::LabelSetImage *workingImage = dynamic_cast(m_WorkingNode->GetData()); assert(workingImage); workingImage->GetActiveLabelSet()->AddLabelEvent += mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->RemoveLabelEvent += mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->ModifyLabelEvent += mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->AllLabelsModifiedEvent += mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->ActiveLabelEvent += mitk::MessageDelegate1(m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::SelectLabelByPixelValue); workingImage->BeforeChangeLayerEvent += mitk::MessageDelegate( this, &QmitkMultiLabelSegmentationView::OnLooseLabelSetConnection); } void QmitkMultiLabelSegmentationView::OnLooseLabelSetConnection() { if (m_WorkingNode.IsNull()) { return; } mitk::LabelSetImage *workingImage = dynamic_cast(m_WorkingNode->GetData()); assert(workingImage); // Reset LabelSetWidget Events workingImage->GetActiveLabelSet()->AddLabelEvent -= mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->RemoveLabelEvent -= mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->ModifyLabelEvent -= mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->AllLabelsModifiedEvent -= mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->ActiveLabelEvent -= mitk::MessageDelegate1(m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::SelectLabelByPixelValue); workingImage->BeforeChangeLayerEvent -= mitk::MessageDelegate( this, &QmitkMultiLabelSegmentationView::OnLooseLabelSetConnection); } void QmitkMultiLabelSegmentationView::SetFocus() { } void QmitkMultiLabelSegmentationView::UpdateControls() { mitk::DataNode* referenceNode = m_ToolManager->GetReferenceData(0); bool hasReferenceNode = referenceNode != nullptr; mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); bool hasValidWorkingNode = workingNode != nullptr; m_Controls.m_pbNewLabel->setEnabled(false); m_Controls.m_gbInterpolation->setEnabled(false); m_Controls.m_SliceBasedInterpolatorWidget->setEnabled(false); m_Controls.m_SurfaceBasedInterpolatorWidget->setEnabled(false); m_Controls.m_LabelSetWidget->setEnabled(false); m_Controls.m_btAddLayer->setEnabled(false); m_Controls.m_btDeleteLayer->setEnabled(false); m_Controls.m_cbActiveLayer->setEnabled(false); m_Controls.m_btPreviousLayer->setEnabled(false); m_Controls.m_btNextLayer->setEnabled(false); m_Controls.m_btLockExterior->setChecked(false); m_Controls.m_btLockExterior->setEnabled(false); m_Controls.m_pbShowLabelTable->setChecked(false); m_Controls.m_pbShowLabelTable->setEnabled(false); m_Controls.m_ManualToolSelectionBox3D->SetEnabledMode(QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); m_Controls.m_ManualToolSelectionBox2D->SetEnabledMode(QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); if (hasValidWorkingNode) { // TODO adapt tool manager so that this check is done there, e.g. convenience function mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); hasValidWorkingNode = workingImage != nullptr; if (hasValidWorkingNode) { m_Controls.m_pbNewLabel->setEnabled(true); m_Controls.m_btLockExterior->setEnabled(true); m_Controls.m_pbShowLabelTable->setEnabled(true); m_Controls.m_gbInterpolation->setEnabled(true); m_Controls.m_SliceBasedInterpolatorWidget->setEnabled(true); m_Controls.m_SurfaceBasedInterpolatorWidget->setEnabled(true); m_Controls.m_LabelSetWidget->setEnabled(true); m_Controls.m_btAddLayer->setEnabled(true); int activeLayer = workingImage->GetActiveLayer(); int numberOfLayers = workingImage->GetNumberOfLayers(); m_Controls.m_cbActiveLayer->blockSignals(true); m_Controls.m_cbActiveLayer->clear(); for (unsigned int lidx = 0; lidx < workingImage->GetNumberOfLayers(); ++lidx) { m_Controls.m_cbActiveLayer->addItem(QString::number(lidx)); } m_Controls.m_cbActiveLayer->setCurrentIndex(activeLayer); m_Controls.m_cbActiveLayer->blockSignals(false); m_Controls.m_cbActiveLayer->setEnabled(numberOfLayers > 1); m_Controls.m_btDeleteLayer->setEnabled(numberOfLayers > 1); m_Controls.m_btPreviousLayer->setEnabled(activeLayer > 0); m_Controls.m_btNextLayer->setEnabled(activeLayer != numberOfLayers - 1); m_Controls.m_btLockExterior->setChecked(workingImage->GetLabel(0, activeLayer)->GetLocked()); m_Controls.m_pbShowLabelTable->setChecked(workingImage->GetNumberOfLabels() > 1 /*1st is exterior*/); //MLI TODO //m_Controls.m_ManualToolSelectionBox2D->SetEnabledMode(QmitkToolSelectionBox::EnabledWithWorkingDataVisible); } } if (hasValidWorkingNode && hasReferenceNode) { int layer = -1; referenceNode->GetIntProperty("layer", layer); workingNode->SetIntProperty("layer", layer + 1); } this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_ALL); } void QmitkMultiLabelSegmentationView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { if (m_IRenderWindowPart != renderWindowPart) { m_IRenderWindowPart = renderWindowPart; m_Parent->setEnabled(true); QList controllers; controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()); controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()); controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()); m_Controls.m_SliceBasedInterpolatorWidget->SetSliceNavigationControllers(controllers); } } void QmitkMultiLabelSegmentationView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* /*renderWindowPart*/) { m_ToolManager->ActivateTool(-1); m_IRenderWindowPart = nullptr; m_Parent->setEnabled(false); } void QmitkMultiLabelSegmentationView::ResetMouseCursor() { if (m_MouseCursorSet) { mitk::ApplicationCursor::GetInstance()->PopCursor(); m_MouseCursorSet = false; } } void QmitkMultiLabelSegmentationView::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 QmitkMultiLabelSegmentationView::InitializeListeners() { if (m_Interactor.IsNull()) { us::Module* module = us::GetModuleContext()->GetModule(); std::vector resources = module->FindResources("/", "*", true); for (std::vector::iterator iter = resources.begin(); iter != resources.end(); ++iter) { MITK_INFO << iter->GetResourcePath(); } m_Interactor = mitk::SegmentationInteractor::New(); if (!m_Interactor->LoadStateMachine("SegmentationInteraction.xml", module)) { MITK_WARN << "Error loading state machine"; } if (!m_Interactor->SetEventConfig("ConfigSegmentation.xml", module)) { MITK_WARN << "Error loading state machine configuration"; } // Register as listener via micro services us::ServiceProperties props; props["name"] = std::string("SegmentationInteraction"); m_ServiceRegistration = us::GetModuleContext()->RegisterService(m_Interactor.GetPointer(), props); } } -bool QmitkMultiLabelSegmentationView::CheckForSameGeometry(const mitk::Image *image1, const mitk::Image *image2) const +bool QmitkMultiLabelSegmentationView::CheckForSameGeometry(const mitk::DataNode *node1, const mitk::DataNode *node2) { bool isSameGeometry(true); + auto image1 = dynamic_cast(node1->GetData()); + assert(image1); + + auto image2 = dynamic_cast(node2->GetData()); + assert(image2); + if (image1 && image2) { mitk::BaseGeometry::Pointer geo1 = image1->GetGeometry(); mitk::BaseGeometry::Pointer geo2 = image2->GetGeometry(); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetOrigin(), geo2->GetOrigin()); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetExtent(0), geo2->GetExtent(0)); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetExtent(1), geo2->GetExtent(1)); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetExtent(2), geo2->GetExtent(2)); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetSpacing(), geo2->GetSpacing()); isSameGeometry = isSameGeometry && mitk::MatrixEqualElementWise(geo1->GetIndexToWorldTransform()->GetMatrix(), geo2->GetIndexToWorldTransform()->GetMatrix()); return isSameGeometry; } else { return false; } } - -QString QmitkMultiLabelSegmentationView::GetLastFileOpenPath() -{ - return this->GetPreferences()->Get("LastFileOpenPath", ""); -} - -void QmitkMultiLabelSegmentationView::SetLastFileOpenPath(const QString &path) -{ - this->GetPreferences()->Put("LastFileOpenPath", path); - this->GetPreferences()->Flush(); -} diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.h b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.h index ce5f44b385..e8ec36913e 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.h +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.h @@ -1,182 +1,172 @@ /*============================================================================ 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 QmitkMultiLabelSegmentationView_h #define QmitkMultiLabelSegmentationView_h #include #include "mitkSegmentationInteractor.h" #include #include "ui_QmitkMultiLabelSegmentationControls.h" // berry #include class QmitkRenderWindow; /** * \ingroup ToolManagerEtAl * \ingroup org_mitk_gui_qt_multilabelsegmentation_internal */ class QmitkMultiLabelSegmentationView : public QmitkAbstractView, public mitk::ILifecycleAwarePart { Q_OBJECT public: static const std::string VIEW_ID; QmitkMultiLabelSegmentationView(); ~QmitkMultiLabelSegmentationView() override; typedef std::map NodeTagMapType; // GUI setup void CreateQtPartControl(QWidget *parent) override; // ILifecycleAwarePart interface public: void Activated() override; void Deactivated() override; void Visible() override; void Hidden() override; virtual int GetSizeFlags(bool width); virtual int ComputePreferredSize(bool width, int /*availableParallel*/, int /*availablePerpendicular*/, int preferredResult); protected slots: // reaction to the shortcut for toggling the visibility of the working node void OnVisibilityShortcutActivated(); // reaction to the shortcut for iterating over all labels void OnLabelToggleShortcutActivated(); // reaction to the selection of any 2D segmentation tool void OnManualTool2DSelected(int id); // reaction to button "New Label" void OnNewLabel(); // reaction to button "Show Label Table" void OnShowLabelTable(bool value); // reaction to button "New Segmentation Session" void OnNewSegmentationSession(); // reaction to signal "goToLabel" from labelset widget void OnGoToLabel(const mitk::Point3D &pos); void OnResetView(); // reaction to the button "Add Layer" void OnAddLayer(); // reaction to the button "Delete Layer" void OnDeleteLayer(); // reaction to the button "Previous Layer" void OnPreviousLayer(); // reaction to the button "Next Layer" void OnNextLayer(); // reaction to the combobox change "Change Layer" void OnChangeLayer(int); // reaction to the button "Deactive Active Tool" void OnDeactivateActiveTool(); // reaction to the button "Lock exterior" void OnLockExteriorToggled(bool); // reaction to the selection of a new patient (reference) image in the DataStorage combobox - void OnReferenceSelectionChanged(const mitk::DataNode* node); + void OnReferenceSelectionChanged(QList nodes); // reaction to the selection of a new Segmentation (working) image in the DataStorage combobox - void OnSegmentationSelectionChanged(const mitk::DataNode* node); + void OnSegmentationSelectionChanged(QList nodes); // reaction to ... void OnInterpolationSelectionChanged(int); protected: - // reimplemented from QmitkAbstractView - void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList &nodes) override; - // reimplemented from QmitkAbstractView void OnPreferencesChanged(const berry::IBerryPreferences* prefs) override; - // reimplemented from QmitkAbstractView - void NodeAdded(const mitk::DataNode* node) override; - // reimplemented from QmitkAbstractView void NodeRemoved(const mitk::DataNode* node) override; void OnEstablishLabelSetConnection(); void OnLooseLabelSetConnection(); void SetFocus() override; void UpdateControls(); void RenderWindowPartActivated(mitk::IRenderWindowPart *renderWindowPart); void RenderWindowPartDeactivated(mitk::IRenderWindowPart *renderWindowPart); void ResetMouseCursor(); void SetMouseCursor(const us::ModuleResource, int hotspotX, int hotspotY); void InitializeListeners(); /// \brief Checks if two images have the same size and geometry - bool CheckForSameGeometry(const mitk::Image *image1, const mitk::Image *image2) const; - - QString GetLastFileOpenPath(); - - void SetLastFileOpenPath(const QString &path); + static bool CheckForSameGeometry(const mitk::DataNode *node1, const mitk::DataNode *node2); /// \brief the Qt parent of our GUI (NOT of this object) QWidget *m_Parent; /// \brief Qt GUI file Ui::QmitkMultiLabelSegmentationControls m_Controls; mitk::IRenderWindowPart *m_IRenderWindowPart; mitk::ToolManager *m_ToolManager; mitk::DataNode::Pointer m_ReferenceNode; mitk::DataNode::Pointer m_WorkingNode; mitk::NodePredicateAnd::Pointer m_ReferencePredicate; mitk::NodePredicateAnd::Pointer m_SegmentationPredicate; bool m_AutoSelectionEnabled; bool m_MouseCursorSet; mitk::SegmentationInteractor::Pointer m_Interactor; /** * Reference to the service registration of the observer, * it is needed to unregister the observer on unload. */ us::ServiceRegistration m_ServiceRegistration; }; #endif // QmitkMultiLabelSegmentationView_h diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkDataSelectionWidget.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkDataSelectionWidget.cpp index 02cbeede6e..1105c7e56b 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkDataSelectionWidget.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkDataSelectionWidget.cpp @@ -1,181 +1,228 @@ /*============================================================================ 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 "QmitkDataSelectionWidget.h" #include "../mitkPluginActivator.h" #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include static mitk::NodePredicateBase::Pointer CreatePredicate(QmitkDataSelectionWidget::Predicate predicate) { auto imageType = mitk::TNodePredicateDataType::New(); auto labelSetImageType = mitk::TNodePredicateDataType::New(); auto surfaceType = mitk::TNodePredicateDataType::New(); auto contourModelType = mitk::TNodePredicateDataType::New(); auto contourModelSetType = mitk::TNodePredicateDataType::New(); auto nonLabelSetImageType = mitk::NodePredicateAnd::New(imageType, mitk::NodePredicateNot::New(labelSetImageType)); auto nonHelperObject = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object")); auto isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); auto isSegmentation = mitk::NodePredicateProperty::New("segmentation", mitk::BoolProperty::New(true)); auto isBinaryOrSegmentation = mitk::NodePredicateOr::New(isBinary, isSegmentation); mitk::NodePredicateBase::Pointer returnValue; switch(predicate) { case QmitkDataSelectionWidget::ImagePredicate: returnValue = mitk::NodePredicateAnd::New( mitk::NodePredicateNot::New(isBinaryOrSegmentation), nonLabelSetImageType).GetPointer(); break; case QmitkDataSelectionWidget::SegmentationPredicate: returnValue = mitk::NodePredicateOr::New( mitk::NodePredicateAnd::New(imageType, isBinaryOrSegmentation), labelSetImageType).GetPointer(); break; case QmitkDataSelectionWidget::SurfacePredicate: returnValue = surfaceType.GetPointer(); break; case QmitkDataSelectionWidget::ImageAndSegmentationPredicate: returnValue = imageType.GetPointer(); break; case QmitkDataSelectionWidget::ContourModelPredicate: returnValue = mitk::NodePredicateOr::New( contourModelSetType, contourModelSetType).GetPointer(); break; default: assert(false && "Unknown predefined predicate!"); return nullptr; } return mitk::NodePredicateAnd::New(returnValue, nonHelperObject).GetPointer(); } QmitkDataSelectionWidget::QmitkDataSelectionWidget(QWidget* parent) : QWidget(parent) { m_Controls.setupUi(this); m_Controls.helpLabel->hide(); } QmitkDataSelectionWidget::~QmitkDataSelectionWidget() { } unsigned int QmitkDataSelectionWidget::AddDataStorageComboBox(QmitkDataSelectionWidget::Predicate predicate) { - return this->AddDataStorageComboBox("", predicate); + QString hint = "Select node"; + QString popupTitel = "Select node"; + + switch (predicate) + { + case QmitkDataSelectionWidget::ImagePredicate: + hint = "Select an image"; + popupTitel = "Select an image"; + break; + + case QmitkDataSelectionWidget::SegmentationPredicate: + hint = "Select a segmentation"; + popupTitel = "Select a segmentation"; + break; + + case QmitkDataSelectionWidget::SurfacePredicate: + hint = "Select a surface"; + popupTitel = "Select a surface"; + break; + + case QmitkDataSelectionWidget::ImageAndSegmentationPredicate: + hint = "Select an image or segmentation"; + popupTitel = "Select an image or segmentation"; + break; + + case QmitkDataSelectionWidget::ContourModelPredicate: + hint = "Select a contour model"; + popupTitel = "Select a contour model"; + break; + } + + return this->AddDataStorageComboBox("", hint, popupTitel, "", predicate); } unsigned int QmitkDataSelectionWidget::AddDataStorageComboBox(mitk::NodePredicateBase* predicate) { - return this->AddDataStorageComboBox("", predicate); + return this->AddDataStorageComboBox("", "Select a node", "Select a node", "", predicate); } -unsigned int QmitkDataSelectionWidget::AddDataStorageComboBox(const QString &labelText, QmitkDataSelectionWidget::Predicate predicate) +unsigned int QmitkDataSelectionWidget::AddDataStorageComboBox(const QString &labelText, const QString &info, const QString &popupTitel, const QString &popupHint, QmitkDataSelectionWidget::Predicate predicate) { - return this->AddDataStorageComboBox(labelText, CreatePredicate(predicate)); + return this->AddDataStorageComboBox(labelText, info, popupHint, popupTitel, CreatePredicate(predicate)); } -unsigned int QmitkDataSelectionWidget::AddDataStorageComboBox(const QString &labelText, mitk::NodePredicateBase* predicate) +unsigned int QmitkDataSelectionWidget::AddDataStorageComboBox(const QString &labelText, const QString &info, const QString &popupTitel, const QString &popupHint, mitk::NodePredicateBase* predicate) { int row = m_Controls.gridLayout->rowCount(); if (!labelText.isEmpty()) { QLabel* label = new QLabel(labelText, m_Controls.dataSelectionWidget); label->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); m_Controls.gridLayout->addWidget(label, row, 0); } - QmitkDataStorageComboBox* comboBox = new QmitkDataStorageComboBox(this->GetDataStorage(), predicate, m_Controls.dataSelectionWidget); - connect(comboBox, SIGNAL(OnSelectionChanged(const mitk::DataNode *)), this, SLOT(OnSelectionChanged(const mitk::DataNode *))); - m_Controls.gridLayout->addWidget(comboBox, row, 1); - - m_DataStorageComboBoxes.push_back(comboBox); - return static_cast(m_DataStorageComboBoxes.size() - 1); + QmitkSingleNodeSelectionWidget* nodeSelection = new QmitkSingleNodeSelectionWidget(m_Controls.dataSelectionWidget); + + nodeSelection->SetSelectionIsOptional(false); + nodeSelection->SetAutoSelectNewNodes(false); + nodeSelection->SetInvalidInfo(info); + nodeSelection->SetPopUpTitel(popupTitel); + nodeSelection->SetPopUpHint(popupHint); + nodeSelection->SetDataStorage(this->GetDataStorage()); + nodeSelection->SetNodePredicate(predicate); + nodeSelection->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + nodeSelection->setMinimumSize(0, 40); + + connect(nodeSelection, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(OnSelectionChanged(QList))); + m_Controls.gridLayout->addWidget(nodeSelection, row, 1); + + m_NodeSelectionWidgets.push_back(nodeSelection); + return static_cast(m_NodeSelectionWidgets.size() - 1); } mitk::DataStorage::Pointer QmitkDataSelectionWidget::GetDataStorage() const { ctkServiceReference ref = mitk::PluginActivator::getContext()->getServiceReference(); assert(ref == true); mitk::IDataStorageService* service = mitk::PluginActivator::getContext()->getService(ref); assert(service); return service->GetDefaultDataStorage()->GetDataStorage(); } mitk::DataNode::Pointer QmitkDataSelectionWidget::GetSelection(unsigned int index) { - assert(index < m_DataStorageComboBoxes.size()); - return m_DataStorageComboBoxes[index]->GetSelectedNode(); + assert(index < m_NodeSelectionWidgets.size()); + return m_NodeSelectionWidgets[index]->GetSelectedNode(); } void QmitkDataSelectionWidget::SetPredicate(unsigned int index, Predicate predicate) { this->SetPredicate(index, CreatePredicate(predicate)); } void QmitkDataSelectionWidget::SetPredicate(unsigned int index, mitk::NodePredicateBase* predicate) { - assert(index < m_DataStorageComboBoxes.size()); - m_DataStorageComboBoxes[index]->SetPredicate(predicate); + assert(index < m_NodeSelectionWidgets.size()); + m_NodeSelectionWidgets[index]->SetNodePredicate(predicate); } void QmitkDataSelectionWidget::SetHelpText(const QString& text) { if (!text.isEmpty()) { m_Controls.helpLabel->setText(text); if (!m_Controls.helpLabel->isVisible()) m_Controls.helpLabel->show(); } else { m_Controls.helpLabel->hide(); } } -void QmitkDataSelectionWidget::OnSelectionChanged(const mitk::DataNode* selection) +void QmitkDataSelectionWidget::OnSelectionChanged(QList selection) { - std::vector::iterator it = std::find(m_DataStorageComboBoxes.begin(), m_DataStorageComboBoxes.end(), sender()); - assert(it != m_DataStorageComboBoxes.end()); + std::vector::iterator it = std::find(m_NodeSelectionWidgets.begin(), m_NodeSelectionWidgets.end(), sender()); + assert(it != m_NodeSelectionWidgets.end()); - emit SelectionChanged(std::distance(m_DataStorageComboBoxes.begin(), it), selection); + const mitk::DataNode* result = nullptr; + if (!selection.empty()) + { + result = selection.front(); + } + emit SelectionChanged(std::distance(m_NodeSelectionWidgets.begin(), it), result); } diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkDataSelectionWidget.h b/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkDataSelectionWidget.h index 21592bfb24..4b6a210dad 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkDataSelectionWidget.h +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkDataSelectionWidget.h @@ -1,67 +1,67 @@ /*============================================================================ 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 QmitkDataSelectionWidget_h #define QmitkDataSelectionWidget_h #include #include #include #include namespace mitk { class NodePredicateBase; } -class QmitkDataStorageComboBox; +class QmitkSingleNodeSelectionWidget; class QmitkDataSelectionWidget : public QWidget { Q_OBJECT public: enum Predicate { ImagePredicate, SegmentationPredicate, SurfacePredicate, ImageAndSegmentationPredicate, ContourModelPredicate }; explicit QmitkDataSelectionWidget(QWidget* parent = nullptr); ~QmitkDataSelectionWidget() override; unsigned int AddDataStorageComboBox(Predicate predicate); unsigned int AddDataStorageComboBox(mitk::NodePredicateBase* predicate = nullptr); - unsigned int AddDataStorageComboBox(const QString &labelText, Predicate predicate); - unsigned int AddDataStorageComboBox(const QString &labelText, mitk::NodePredicateBase* predicate = nullptr); + unsigned int AddDataStorageComboBox(const QString &labelText, const QString &info, const QString &popupTitel, const QString &popupHint, Predicate predicate); + unsigned int AddDataStorageComboBox(const QString &labelText, const QString &info, const QString &popupTitel, const QString &popupHint, mitk::NodePredicateBase* predicate = nullptr); mitk::DataStorage::Pointer GetDataStorage() const; mitk::DataNode::Pointer GetSelection(unsigned int index); void SetPredicate(unsigned int index, Predicate predicate); void SetPredicate(unsigned int index, mitk::NodePredicateBase* predicate); void SetHelpText(const QString& text); signals: void SelectionChanged(unsigned int index, const mitk::DataNode* selection); private slots: - void OnSelectionChanged(const mitk::DataNode* selection); + void OnSelectionChanged(QList selection); private: Ui::QmitkDataSelectionWidgetControls m_Controls; - std::vector m_DataStorageComboBoxes; + std::vector m_NodeSelectionWidgets; }; #endif diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkDataSelectionWidgetControls.ui b/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkDataSelectionWidgetControls.ui index 1849a496d9..243e1faacd 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkDataSelectionWidgetControls.ui +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkDataSelectionWidgetControls.ui @@ -1,64 +1,94 @@ QmitkDataSelectionWidgetControls 0 0 333 191 - + + 0 + + + 0 + + + 0 + + 0 + + + 0 + 0 + + Data Selection + + + 0 + 0 + + - + + 0 + + + 0 + + + 0 + + 0 0 0 color: red true diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationControls.ui b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationControls.ui index 13c10e8817..2757115a88 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationControls.ui +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationControls.ui @@ -1,496 +1,497 @@ QmitkSegmentationControls 0 0 237 591 0 0 0 0 MS Shell Dlg 2 8 50 false false false false QmitkSegmentation QLayout::SetMinimumSize 6 6 6 6 0 0 Data Selection 6 6 6 6 QLayout::SetMinimumSize 4 0 0 Patient Image 0 0 Segmentation 0 0 Create a new segmentation &New... :/segmentation/btnNew.png:/segmentation/btnNew.png Qt::ToolButtonTextOnly - - - - 0 - 0 - - - + + + + 0 + 40 + + + - - - - 0 - 0 - - - + + + + 0 + 40 + + + 0 0 200 0 0 200 0 0 200 0 0 200 0 0 200 0 0 200 0 0 84 82 78 84 82 78 84 82 78 50 false Please load an image! true 0 0 Qt::LeftToRight QTabWidget::tab-bar { alignment: middle; } QTabWidget::North QTabWidget::Triangular 0 0 0 Qt::LeftToRight false 2D Tools 6 6 6 6 0 0 50 false 0 0 50 false 0 0 50 false Qt::Vertical 20 40 0 0 3D Tools 6 6 6 6 0 0 50 false 0 0 50 false Qt::Vertical 20 40 - - QmitkDataStorageComboBox - QComboBox -
QmitkDataStorageComboBox.h
-
- + + QmitkSingleNodeSelectionWidget + QWidget +
QmitkSingleNodeSelectionWidget.h
+ 1 +
+ QmitkToolSelectionBox QWidget
QmitkToolSelectionBox.h
QmitkSlicesInterpolator QWidget
QmitkSlicesInterpolator.h
QmitkToolGUIArea QWidget
QmitkToolGUIArea.h
QmitkToolReferenceDataSelectionBox.h QmitkToolGUIArea.h QmitkToolSelectionBox.h QmitkSlicesInterpolator.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 29c2fb6189..34b92b3e98 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp @@ -1,1168 +1,986 @@ /*============================================================================ 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 #include "mitkProperties.h" #include "mitkSegTool2D.h" #include "mitkStatusBar.h" #include "QmitkNewSegmentationDialog.h" #include #include #include #include "QmitkSegmentationView.h" #include #include "mitkVtkResliceInterpolationProperty.h" #include "mitkApplicationCursor.h" #include "mitkSegmentationObjectFactory.h" #include "mitkPluginActivator.h" #include "mitkCameraController.h" #include "mitkLabelSetImage.h" #include "mitkImageTimeSelector.h" +#include "mitkNodePredicateFunction.h" #include #include "usModuleResource.h" #include "usModuleResourceStream.h" //micro service to get the ToolManager instance #include "mitkToolManagerProvider.h" #include #include const std::string QmitkSegmentationView::VIEW_ID = "org.mitk.views.segmentation"; QmitkSegmentationView::QmitkSegmentationView() : m_Parent(nullptr) , m_Controls(nullptr) , m_RenderWindowPart(nullptr) , m_MouseCursorSet(false) , m_DataSelectionChanged(false) - , m_AutoSelectionEnabled(false) { mitk::TNodePredicateDataType::Pointer isImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateDataType::Pointer isDwi = mitk::NodePredicateDataType::New("DiffusionImage"); mitk::NodePredicateDataType::Pointer isDti = mitk::NodePredicateDataType::New("TensorImage"); mitk::NodePredicateDataType::Pointer isOdf = mitk::NodePredicateDataType::New("OdfImage"); auto isSegment = mitk::NodePredicateDataType::New("Segment"); mitk::NodePredicateOr::Pointer validImages = mitk::NodePredicateOr::New(); validImages->AddPredicate(mitk::NodePredicateAnd::New(isImage, mitk::NodePredicateNot::New(isSegment))); validImages->AddPredicate(isDwi); validImages->AddPredicate(isDti); validImages->AddPredicate(isOdf); m_IsNotAHelperObject = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true))); m_IsOfTypeImagePredicate = mitk::NodePredicateAnd::New(validImages, m_IsNotAHelperObject); mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateNot::Pointer isNotBinaryPredicate = mitk::NodePredicateNot::New(isBinaryPredicate); mitk::NodePredicateAnd::Pointer isABinaryImagePredicate = mitk::NodePredicateAnd::New(m_IsOfTypeImagePredicate, isBinaryPredicate); mitk::NodePredicateAnd::Pointer isNotABinaryImagePredicate = mitk::NodePredicateAnd::New(m_IsOfTypeImagePredicate, isNotBinaryPredicate); m_IsASegmentationImagePredicate = mitk::NodePredicateOr::New(isABinaryImagePredicate, mitk::TNodePredicateDataType::New()); m_IsAPatientImagePredicate = mitk::NodePredicateAnd::New(isNotABinaryImagePredicate, mitk::NodePredicateNot::New(mitk::TNodePredicateDataType::New())); } QmitkSegmentationView::~QmitkSegmentationView() { if (m_Controls) { SetToolSelectionBoxesEnabled(false); // deactivate all tools mitk::ToolManagerProvider::GetInstance()->GetToolManager()->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(); for (NodeTagMapType::iterator dataIter = m_BinaryPropertyObserverTags.begin(); dataIter != m_BinaryPropertyObserverTags.end(); ++dataIter) { (*dataIter).first->GetProperty("binary")->RemoveObserver((*dataIter).second); } m_BinaryPropertyObserverTags.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); SetToolManagerSelection(nullptr, nullptr); } delete m_Controls; } -void QmitkSegmentationView::NewNodesGenerated() -{ - MITK_WARN << "Use of deprecated function: NewNodesGenerated!! This function is empty and will be removed in the next time!"; -} - void QmitkSegmentationView::NewNodeObjectsGenerated(mitk::ToolManager::DataVectorType* nodes) { if (!nodes) return; mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); if (!toolManager) return; for (mitk::ToolManager::DataVectorType::iterator iter = nodes->begin(); iter != nodes->end(); ++iter) { this->FireNodeSelected( *iter ); // only last iteration meaningful, multiple generated objects are not taken into account here } } void QmitkSegmentationView::Visible() { } void QmitkSegmentationView::Hidden() { } void QmitkSegmentationView::Activated() { } void QmitkSegmentationView::Deactivated() { } void QmitkSegmentationView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { if (m_RenderWindowPart != renderWindowPart) { m_RenderWindowPart = renderWindowPart; } if (m_Parent) { m_Parent->setEnabled(true); } // tell the interpolation about tool manager, data storage and render window part if (m_Controls) { mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); m_Controls->m_SlicesInterpolator->SetDataStorage(this->GetDataStorage()); QList controllers; controllers.push_back(renderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()); controllers.push_back(renderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()); controllers.push_back(renderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()); m_Controls->m_SlicesInterpolator->Initialize(toolManager, controllers); } } void QmitkSegmentationView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* /*renderWindowPart*/) { m_RenderWindowPart = nullptr; if (m_Parent) { m_Parent->setEnabled(false); } } void QmitkSegmentationView::OnPreferencesChanged(const berry::IBerryPreferences* prefs) { if (m_Controls != nullptr) { bool slimView = prefs->GetBool("slim view", false); m_Controls->m_ManualToolSelectionBox2D->SetShowNames(!slimView); m_Controls->m_ManualToolSelectionBox3D->SetShowNames(!slimView); m_Controls->btnNewSegmentation->setToolButtonStyle(slimView ? Qt::ToolButtonIconOnly : Qt::ToolButtonTextOnly); } - m_AutoSelectionEnabled = prefs->GetBool("auto selection", false); + auto autoSelectionEnabled = prefs->GetBool("auto selection", true); + m_Controls->patImageSelector->SetAutoSelectNewNodes(autoSelectionEnabled); + m_Controls->segImageSelector->SetAutoSelectNewNodes(autoSelectionEnabled); this->ForceDisplayPreferencesUponAllImages(); } void QmitkSegmentationView::CreateNewSegmentation() { mitk::DataNode::Pointer node = mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetReferenceData(0); if (node.IsNotNull()) { mitk::Image::ConstPointer image = dynamic_cast(node->GetData()); if (image.IsNotNull()) { if (image->GetDimension() > 1) { // ask about the name and organ type of the new segmentation QmitkNewSegmentationDialog* dialog = new QmitkNewSegmentationDialog(m_Parent); // needs a QWidget as parent, "this" is not QWidget QStringList organColors = mitk::OrganNamesHandling::GetDefaultOrganColorString();; dialog->SetSuggestionList(organColors); int dialogReturnValue = dialog->exec(); if (dialogReturnValue == QDialog::Rejected) { // user clicked cancel or pressed Esc or something similar return; } if (image->GetDimension() > 3) { auto result = QMessageBox::question(m_Parent, tr("Generate a static mask?"),tr("The selected image has multiple time steps. You can either generate a simple/static masks resembling the geometry of the first timestep of the image. Or you can generate a dynamic mask that equals the selected image in geometry and number of timesteps; thus a dynamic mask can change over time (e.g. according to the image)."), tr("Yes, generate a static mask"), tr("No, generate a dynamic mask"), QString(), 0,0); if (result == 0) { auto selector = mitk::ImageTimeSelector::New(); selector->SetInput(image); selector->SetTimeNr(0); selector->Update(); const auto refTimeGeometry = image->GetTimeGeometry(); auto newTimeGeometry = mitk::ProportionalTimeGeometry::New(); newTimeGeometry->SetFirstTimePoint(refTimeGeometry->GetMinimumTimePoint()); newTimeGeometry->SetStepDuration(refTimeGeometry->GetMaximumTimePoint() - refTimeGeometry->GetMinimumTimePoint()); mitk::Image::Pointer newImage = selector->GetOutput(); newTimeGeometry->SetTimeStepGeometry(image->GetGeometry(), 0); newImage->SetTimeGeometry(newTimeGeometry); image = newImage; } } // ask the user about an organ type and name, add this information to the image's (!) propertylist // create a new image of the same dimensions and smallest possible pixel type mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); mitk::Tool* firstTool = toolManager->GetToolById(0); if (firstTool) { try { std::string newNodeName = dialog->GetSegmentationName().toStdString(); if (newNodeName.empty()) { newNodeName = "no_name"; } mitk::DataNode::Pointer emptySegmentation = firstTool->CreateEmptySegmentationNode(image, newNodeName, dialog->GetColor()); // initialize showVolume to false to prevent recalculating the volume while working on the segmentation emptySegmentation->SetProperty("showVolume", mitk::BoolProperty::New(false)); if (!emptySegmentation) { return; // could be aborted by user } mitk::OrganNamesHandling::UpdateOrganList(organColors, dialog->GetSegmentationName(), dialog->GetColor()); // escape ';' here (replace by '\;'), see longer comment above QString stringForStorage = organColors.replaceInStrings(";", "\\;").join(";"); MITK_DEBUG << "Will store: " << stringForStorage; this->GetPreferences()->Put("Organ-Color-List", stringForStorage); this->GetPreferences()->Flush(); if (mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0)) { mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0)->SetSelected(false); } emptySegmentation->SetSelected(true); this->GetDataStorage()->Add(emptySegmentation, node); // add as a child, because the segmentation "derives" from the original - this->FireNodeSelected(emptySegmentation); - this->OnSelectionChanged(emptySegmentation); - - m_Controls->segImageSelector->SetSelectedNode(emptySegmentation); + m_Controls->segImageSelector->SetCurrentSelectedNode(emptySegmentation); mitk::RenderingManager::GetInstance()->InitializeViews(emptySegmentation->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); } catch (const std::bad_alloc&) { QMessageBox::warning(nullptr, tr("Create new segmentation"), tr("Could not allocate memory for new segmentation")); } } } else { QMessageBox::information(nullptr, tr("Segmentation"), tr("Segmentation is currently not supported for 2D images")); } } } else { MITK_ERROR << "'Create new segmentation' button should never be clickable unless a patient image is selected..."; } } void QmitkSegmentationView::OnVisiblePropertyChanged() { - mitk::DataNode* selectedNode = m_Controls->segImageSelector->GetSelectedNode(); - if ( !selectedNode ) + auto selectedNode = m_Controls->segImageSelector->GetSelectedNode(); + if ( selectedNode.IsNull() ) { this->SetToolSelectionBoxesEnabled(false); return; } mitk::IRenderWindowPart* renderWindowPart = this->GetRenderWindowPart(); bool selectedNodeIsVisible = renderWindowPart && selectedNode->IsVisible(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer()); if (!selectedNodeIsVisible) { this->SetToolSelectionBoxesEnabled(false); this->UpdateWarningLabel(tr("The selected segmentation is currently not visible!")); } else { this->SetToolSelectionBoxesEnabled(true); this->UpdateWarningLabel(""); } } void QmitkSegmentationView::OnBinaryPropertyChanged() { - mitk::DataStorage::SetOfObjects::ConstPointer patImages = m_Controls->patImageSelector->GetNodes(); - - for (mitk::DataStorage::SetOfObjects::ConstIterator it = patImages->Begin(); it != patImages->End(); ++it) - { - const mitk::DataNode* node = it->Value(); - if(m_IsASegmentationImagePredicate->CheckNode(node)) - { - m_Controls->patImageSelector->RemoveNode(node); - m_Controls->segImageSelector->AddNode(node); - this->SetToolManagerSelection(nullptr,nullptr); - return; - } - } - - mitk::DataStorage::SetOfObjects::ConstPointer segImages = m_Controls->segImageSelector->GetNodes(); + auto patData = mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetReferenceData(0); + if (patData != nullptr && m_IsASegmentationImagePredicate->CheckNode(patData)) + { + this->SetToolManagerSelection(nullptr, nullptr); + return; + } - for (mitk::DataStorage::SetOfObjects::ConstIterator it = segImages->Begin(); it != segImages->End(); ++it) - { - const mitk::DataNode* node = it->Value(); - if(!m_IsASegmentationImagePredicate->CheckNode(node)) - { - m_Controls->segImageSelector->RemoveNode(node); - m_Controls->patImageSelector->AddNode(node); - if (mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0) == node) - { - mitk::ToolManagerProvider::GetInstance()->GetToolManager()->SetWorkingData(nullptr); - } - return; - } - } + auto segData = mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0); + if (segData != nullptr && !m_IsASegmentationImagePredicate->CheckNode(segData)) + { + mitk::ToolManagerProvider::GetInstance()->GetToolManager()->SetWorkingData(nullptr); + return; + } } void QmitkSegmentationView::NodeAdded(const mitk::DataNode *node) { if (!m_IsOfTypeImagePredicate->CheckNode(node)) { return; } itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::OnVisiblePropertyChanged); m_WorkingDataObserverTags.insert(std::pair(const_cast(node), node->GetProperty("visible")->AddObserver(itk::ModifiedEvent(), command))); itk::SimpleMemberCommand::Pointer command2 = itk::SimpleMemberCommand::New(); command2->SetCallbackFunction(this, &QmitkSegmentationView::OnBinaryPropertyChanged); m_BinaryPropertyObserverTags.insert(std::pair(const_cast(node), node->GetProperty("binary")->AddObserver(itk::ModifiedEvent(), command2))); ApplyDisplayOptions(const_cast(node)); } void QmitkSegmentationView::NodeRemoved(const mitk::DataNode* node) { if (m_IsASegmentationImagePredicate->CheckNode(node)) { //First of all 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; if ((mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0) == node) && m_Controls->patImageSelector->GetSelectedNode().IsNotNull()) { this->SetToolManagerSelection(mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetReferenceData(0), nullptr); this->UpdateWarningLabel(tr("Select or create a segmentation")); } mitk::Image* image = dynamic_cast(node->GetData()); mitk::SurfaceInterpolationController::GetInstance()->RemoveInterpolationSession(image); } mitk::DataNode* tempNode = const_cast(node); - //Since the binary property could be changed during runtime by the user + + //Remove observers for the removed node if it is a image if (m_IsOfTypeImagePredicate->CheckNode(node)) { node->GetProperty("visible")->RemoveObserver(m_WorkingDataObserverTags[tempNode]); m_WorkingDataObserverTags.erase(tempNode); node->GetProperty("binary")->RemoveObserver(m_BinaryPropertyObserverTags[tempNode]); m_BinaryPropertyObserverTags.erase(tempNode); } - if (mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetReferenceData(0) == node) - { - //as we don't know which node was actually removed e.g. our reference node, disable 'New Segmentation' button. - //consider the case that there is no more image in the datastorage - this->SetToolManagerSelection(nullptr, nullptr); - this->SetToolSelectionBoxesEnabled(false); - } } -void QmitkSegmentationView::OnPatientComboBoxSelectionChanged( const mitk::DataNode* node ) +void QmitkSegmentationView::OnPatientComboBoxSelectionChanged(QList nodes) { - //mitk::DataNode* selectedNode = const_cast(node); - if( node != nullptr ) + if(! nodes.empty()) { this->UpdateWarningLabel(""); - mitk::DataNode* segNode = m_Controls->segImageSelector->GetSelectedNode(); - if (segNode) + auto node = nodes.first(); + + auto geometryCheck = [node](const mitk::DataNode * segNode) { - mitk::DataStorage::SetOfObjects::ConstPointer possibleParents = this->GetDataStorage()->GetSources(segNode, m_IsAPatientImagePredicate); - bool isSourceNode(false); + return QmitkSegmentationView::CheckForSameGeometry(segNode, node); + }; + mitk::NodePredicateFunction::Pointer hasCorrectGeo = mitk::NodePredicateFunction::New(geometryCheck); + auto segPredicate = mitk::NodePredicateAnd::New(m_IsASegmentationImagePredicate.GetPointer(), hasCorrectGeo.GetPointer()); - for (mitk::DataStorage::SetOfObjects::ConstIterator it = possibleParents->Begin(); it != possibleParents->End(); it++) - { - if (it.Value() == node) - isSourceNode = true; - } + m_Controls->segImageSelector->SetNodePredicate(segPredicate); - if ( !isSourceNode && (!this->CheckForSameGeometry(segNode, node) || possibleParents->Size() > 0 )) - { - this->SetToolManagerSelection(node, nullptr); - this->SetToolSelectionBoxesEnabled( false ); - this->UpdateWarningLabel(tr("The selected patient image does not match with the selected segmentation!")); - } - else if ((!isSourceNode && this->CheckForSameGeometry(segNode, node)) || isSourceNode ) - { - this->SetToolManagerSelection(node, segNode); - //Doing this we can assure that the segmenation is always visible if the segmentation and the patient image are - //loaded separately - int layer(10); - node->GetIntProperty("layer", layer); - layer++; - segNode->SetProperty("layer", mitk::IntProperty::New(layer)); - //this->UpdateWarningLabel(""); - RenderingManagerReinitialized(); - } + mitk::DataNode* segNode = m_Controls->segImageSelector->GetSelectedNode(); + this->SetToolManagerSelection(node, segNode); + if (segNode) + { + //Doing this we can assure that the segmenation is always visible if the segmentation and the patient image are + //loaded separately + int layer(10); + node->GetIntProperty("layer", layer); + layer++; + segNode->SetProperty("layer", mitk::IntProperty::New(layer)); + RenderingManagerReinitialized(); + + this->SetToolSelectionBoxesEnabled(true); + this->UpdateWarningLabel(""); } else { - this->SetToolManagerSelection(node, nullptr); this->SetToolSelectionBoxesEnabled( false ); this->UpdateWarningLabel(tr("Select or create a segmentation")); } } else { - this->UpdateWarningLabel(tr("Please select an image!")); - this->SetToolSelectionBoxesEnabled( false ); + m_Controls->segImageSelector->SetNodePredicate(m_IsASegmentationImagePredicate); + this->UpdateWarningLabel(tr("Please select an image!")); + this->SetToolSelectionBoxesEnabled( false ); } } -void QmitkSegmentationView::OnSegmentationComboBoxSelectionChanged(const mitk::DataNode *node) +void QmitkSegmentationView::OnSegmentationComboBoxSelectionChanged(QList nodes) { - if (node == nullptr) + if (nodes.empty()) { this->UpdateWarningLabel(tr("Select or create a segmentation")); this->SetToolSelectionBoxesEnabled( false ); return; } - mitk::DataNode* refNode = m_Controls->patImageSelector->GetSelectedNode(); + auto refNode = m_Controls->patImageSelector->GetSelectedNode(); + auto segNode = nodes.front(); + + if (!refNode) + { + this->UpdateWarningLabel(tr("Please select the matching patient image!")); + this->SetToolSelectionBoxesEnabled(false); + this->SetToolManagerSelection(nullptr, segNode); + return; + } RenderingManagerReinitialized(); if ( m_Controls->lblSegmentationWarnings->isVisible()) // "RenderingManagerReinitialized()" caused a warning. we do not need to go any further return; - if (m_AutoSelectionEnabled) + this->SetToolManagerSelection(refNode, segNode); + + if (segNode) { - this->OnSelectionChanged(const_cast(node)); + //Doing this we can assure that the segmenation is always visible if the segmentation and the patient image are + //loaded separately + int layer(10); + refNode->GetIntProperty("layer", layer); + layer++; + segNode->SetProperty("layer", mitk::IntProperty::New(layer)); + RenderingManagerReinitialized(); + + this->SetToolSelectionBoxesEnabled(true); + this->UpdateWarningLabel(""); } else { - mitk::DataStorage::SetOfObjects::ConstPointer possibleParents = this->GetDataStorage()->GetSources(node, m_IsAPatientImagePredicate); - - if ( possibleParents->Size() == 1 ) - { - mitk::DataNode* parentNode = possibleParents->ElementAt(0); - - if (parentNode != refNode) - { - this->UpdateWarningLabel(tr("The selected segmentation does not match with the selected patient image!")); - this->SetToolSelectionBoxesEnabled( false ); - this->SetToolManagerSelection(nullptr, node); - } - else - { - this->UpdateWarningLabel(""); - this->SetToolManagerSelection(refNode, node); - } - } - else if (refNode && this->CheckForSameGeometry(node, refNode)) - { - this->UpdateWarningLabel(""); - this->SetToolManagerSelection(refNode, node); - } - else if (!refNode || !this->CheckForSameGeometry(node, refNode)) - { - this->UpdateWarningLabel(tr("Please select the matching patient image!")); - } + this->SetToolSelectionBoxesEnabled(false); + this->UpdateWarningLabel(tr("Select or create a segmentation")); } mitk::IRenderWindowPart* renderWindowPart = this->GetRenderWindowPart(); - if (!renderWindowPart || !node->IsVisible(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer())) + if (!renderWindowPart || !segNode->IsVisible(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer())) { this->UpdateWarningLabel(tr("The selected segmentation is currently not visible!")); this->SetToolSelectionBoxesEnabled( false ); } } void QmitkSegmentationView::OnShowMarkerNodes (bool state) { mitk::SegTool2D::Pointer manualSegmentationTool; unsigned int numberOfExistingTools = mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetTools().size(); for(unsigned int i = 0; i < numberOfExistingTools; i++) { manualSegmentationTool = dynamic_cast(mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetToolById(i)); if (manualSegmentationTool) { if(state == true) { manualSegmentationTool->SetShowMarkerNodes( true ); } else { manualSegmentationTool->SetShowMarkerNodes( false ); } } } } -void QmitkSegmentationView::OnSelectionChanged(mitk::DataNode* node) -{ - berry::IWorkbenchPart::Pointer nullPart; - QList nodes; - nodes.push_back(node); - this->OnSelectionChanged(nullPart, nodes); -} - -void QmitkSegmentationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) -{ - if (nodes.size() != 0) - { - std::string markerName = "Position"; - unsigned int numberOfNodes = nodes.size(); - std::string nodeName = nodes.at(0)->GetName(); - if ((numberOfNodes == 1) && (nodeName.find(markerName) == 0)) - { - OnContourMarkerSelected(nodes.at(0)); - return; - } - } - - if (m_AutoSelectionEnabled) - { - if (nodes.size() == 0 && m_Controls->patImageSelector->GetSelectedNode().IsNull()) - { - SetToolManagerSelection(nullptr, nullptr); - } - else if (nodes.size() == 1) - { - mitk::DataNode::Pointer selectedNode = nodes.at(0); - if (selectedNode.IsNull()) - { - return; - } - - mitk::Image::Pointer selectedImage = dynamic_cast(selectedNode->GetData()); - if (selectedImage.IsNull()) - { - SetToolManagerSelection(nullptr, nullptr); - return; - } - - if (m_IsASegmentationImagePredicate->CheckNode(selectedNode)) - { - // set all nodes to invisible - mitk::DataStorage::SetOfObjects::ConstPointer allImages = GetDataStorage()->GetSubset(m_IsNotAHelperObject); - for (mitk::DataStorage::SetOfObjects::const_iterator iter = allImages->begin(); iter != allImages->end(); ++iter) - { - (*iter)->SetVisibility(false); - } - - // if a segmentation is selected find a possible patient image (a parent node) - mitk::DataStorage::SetOfObjects::ConstPointer sources = GetDataStorage()->GetSources(selectedNode, m_IsAPatientImagePredicate); - mitk::DataNode::Pointer sourceNode; - if (sources->Size() != 0) - { - // found one or more sources - use the first one - sourceNode = sources->ElementAt(0); - sourceNode->SetVisibility(true); - selectedNode->SetVisibility(true); - SetToolManagerSelection(sourceNode, selectedNode); - - // set all child nodes of the segmentation to visible - mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(selectedNode, m_IsNotAHelperObject, false); - for (mitk::DataStorage::SetOfObjects::const_iterator iter = derivations->begin(); iter != derivations->end(); ++iter) - { - (*iter)->SetVisibility(true); - } - } - else - { - // did not find a source / patient image, check all images and compare geometry - mitk::DataStorage::SetOfObjects::ConstPointer possiblePatientImages = GetDataStorage()->GetSubset(m_IsAPatientImagePredicate); - for (mitk::DataStorage::SetOfObjects::ConstIterator iter = possiblePatientImages->Begin(); iter != possiblePatientImages->End(); ++iter) - { - sourceNode = iter->Value(); - if (CheckForSameGeometry(selectedNode, iter->Value())) - { - sourceNode->SetVisibility(true); - selectedNode->SetVisibility(true); - SetToolManagerSelection(sourceNode, selectedNode); - - // set all child nodes of the segmentation to visible - mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(selectedNode, m_IsNotAHelperObject, false); - for (mitk::DataStorage::SetOfObjects::const_iterator iter = derivations->begin(); iter != derivations->end(); ++iter) - { - (*iter)->SetVisibility(true); - } - - // doing this we can assure that the segmentation is always visible if the segmentation and the patient image are at the - // same level in the data manager - int layer(10); - sourceNode->GetIntProperty("layer", layer); - layer++; - selectedNode->SetProperty("layer", mitk::IntProperty::New(layer)); - return; - } - } - // did not find a source / patient image with the same geometry - SetToolManagerSelection(nullptr, selectedNode); - } - mitk::RenderingManager::GetInstance()->InitializeViews(selectedNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); - } - else - { - if (mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetReferenceData(0) != selectedNode) - { - SetToolManagerSelection(selectedNode, nullptr); - // may be a bug in the selection services. A node which is deselected will be passed as selected node to the OnSelectionChanged function - mitk::IRenderWindowPart* renderWindowPart = GetRenderWindowPart(); - if (renderWindowPart && !selectedNode->IsVisible(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer())) - { - selectedNode->SetVisibility(true); - } - UpdateWarningLabel(tr("The selected patient image does not match with the selected segmentation!")); - SetToolSelectionBoxesEnabled(false); - } - } - } - - if (m_Controls->lblSegmentationWarnings->isVisible()) // "RenderingManagerReinitialized()" caused a warning. we do not need to go any further - { - return; - } - RenderingManagerReinitialized(); - } -} - void QmitkSegmentationView::OnContourMarkerSelected(const mitk::DataNode *node) { QmitkRenderWindow* selectedRenderWindow = nullptr; QmitkRenderWindow* axialRenderWindow = GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)->GetQmitkRenderWindow("axial"); QmitkRenderWindow* sagittalRenderWindow = GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)->GetQmitkRenderWindow("sagittal"); QmitkRenderWindow* coronalRenderWindow = GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)->GetQmitkRenderWindow("coronal"); QmitkRenderWindow* _3DRenderWindow = GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)->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, _3DRenderWindow->GetRenderer())) { selectedRenderWindow = _3DRenderWindow; } // make node visible if (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::OnTabWidgetChanged(int id) { //always disable tools on tab changed mitk::ToolManagerProvider::GetInstance()->GetToolManager()->ActivateTool(-1); //2D Tab ID = 0 //3D Tab ID = 1 if (id == 0) { //Hide 3D selection box, show 2D selection box m_Controls->m_ManualToolSelectionBox3D->hide(); m_Controls->m_ManualToolSelectionBox2D->show(); //Deactivate possible active tool //TODO Remove possible visible interpolations -> Maybe changes in SlicesInterpolator } else { //Hide 3D selection box, show 2D selection box m_Controls->m_ManualToolSelectionBox2D->hide(); m_Controls->m_ManualToolSelectionBox3D->show(); //Deactivate possible active tool } } -void QmitkSegmentationView::InitToolManagerSelection(const mitk::DataNode* referenceData, const mitk::DataNode* workingData) +void QmitkSegmentationView::InitToolManagerSelection(mitk::DataNode* referenceData, mitk::DataNode* workingData) { // initial tool manager selection, called from 'CreateQtPartControl' mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); toolManager->SetReferenceData(const_cast(referenceData)); toolManager->SetWorkingData(const_cast(workingData)); // check original image m_Controls->btnNewSegmentation->setEnabled(referenceData != nullptr); if (referenceData) { UpdateWarningLabel(""); } } -void QmitkSegmentationView::SetToolManagerSelection(const mitk::DataNode* referenceData, const mitk::DataNode* workingData) +void QmitkSegmentationView::SetToolManagerSelection(mitk::DataNode* referenceData, mitk::DataNode* workingData) { // called as a result of new BlueBerry selections // tells the ToolManager for manual segmentation about new selections // updates GUI information about what the user should select mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); toolManager->SetReferenceData(const_cast(referenceData)); toolManager->SetWorkingData(const_cast(workingData)); - // check original image m_Controls->btnNewSegmentation->setEnabled(referenceData != nullptr); - if (referenceData) - { - UpdateWarningLabel(""); - disconnect(m_Controls->patImageSelector, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnPatientComboBoxSelectionChanged(const mitk::DataNode*))); - m_Controls->patImageSelector->setCurrentIndex(m_Controls->patImageSelector->Find(referenceData)); - connect(m_Controls->patImageSelector, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnPatientComboBoxSelectionChanged(const mitk::DataNode*))); - - // check segmentation - if (workingData) - { - //FireNodeSelected(const_cast(workingData)); - - disconnect(m_Controls->segImageSelector, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnSegmentationComboBoxSelectionChanged(const mitk::DataNode*))); - m_Controls->segImageSelector->setCurrentIndex(m_Controls->segImageSelector->Find(workingData)); - connect(m_Controls->segImageSelector, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnSegmentationComboBoxSelectionChanged(const mitk::DataNode*))); - } - } } void QmitkSegmentationView::ForceDisplayPreferencesUponAllImages() { if (!m_Parent) { return; } // check all images and segmentations in DataStorage: // (items in brackets are implicitly done by previous steps) // 1. // if a reference image is selected, // show the reference image // and hide all other images (orignal and segmentation), // (and hide all segmentations of the other original images) // and show all the reference's segmentations // if no reference image is selected, do do nothing // // 2. // if a segmentation is selected, // show it // (and hide all all its siblings (childs of the same parent, incl, nullptr parent)) // if no segmentation is selected, do nothing if (!m_Controls) { return; // might happen on initialization (preferences loaded) } mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); mitk::DataNode::Pointer referenceData = toolManager->GetReferenceData(0); mitk::DataNode::Pointer workingData = toolManager->GetWorkingData(0); // 1. if (referenceData.IsNotNull()) { // iterate all images mitk::DataStorage::SetOfObjects::ConstPointer allImages = this->GetDataStorage()->GetSubset(m_IsASegmentationImagePredicate); for ( mitk::DataStorage::SetOfObjects::const_iterator iter = allImages->begin(); iter != allImages->end(); ++iter) { mitk::DataNode* node = *iter; // apply display preferences ApplyDisplayOptions(node); // set visibility node->SetVisibility(node == referenceData); } } // 2. if (workingData.IsNotNull()) workingData->SetVisibility(true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSegmentationView::ApplyDisplayOptions(mitk::DataNode* node) { if (!node) { return; } mitk::BoolProperty::Pointer drawOutline = mitk::BoolProperty::New(GetPreferences()->GetBool("draw outline", true)); mitk::BoolProperty::Pointer volumeRendering = mitk::BoolProperty::New(GetPreferences()->GetBool("volume rendering", false)); mitk::LabelSetImage* labelSetImage = dynamic_cast(node->GetData()); if (nullptr != labelSetImage) { // node is actually a multi label segmentation, // but its outline property can be set in the 'single label' segmentation preference page as well node->SetProperty("labelset.contour.active", drawOutline); //node->SetProperty("opacity", mitk::FloatProperty::New(drawOutline->GetValue() ? 1.0f : 0.3f)); node->SetProperty("volumerendering", volumeRendering); // force render window update to show outline node->GetData()->Modified(); } else { // node is a 'single label' segmentation bool isBinary = false; node->GetBoolProperty("binary", isBinary); if (isBinary) { node->SetProperty("outline binary", drawOutline); node->SetProperty("outline width", mitk::FloatProperty::New(2.0)); //node->SetProperty("opacity", mitk::FloatProperty::New(drawOutline->GetValue() ? 1.0f : 0.3f)); node->SetProperty("volumerendering", volumeRendering); // force render window update to show outline node->GetData()->Modified(); } } } void QmitkSegmentationView::RenderingManagerReinitialized() { if (!this->GetRenderWindowPart()) { return; } /* * Here we check whether the geometry of the selected segmentation image if 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 */ mitk::DataNode* workingNode = m_Controls->segImageSelector->GetSelectedNode(); const mitk::BaseGeometry* worldGeo = this->GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetSliceNavigationController()->GetCurrentGeometry3D(); if (workingNode && worldGeo) { const mitk::BaseGeometry* workingNodeGeo = workingNode->GetData()->GetGeometry(); const mitk::BaseGeometry* worldGeo = this->GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetSliceNavigationController()->GetCurrentGeometry3D(); if (mitk::Equal(*workingNodeGeo->GetBoundingBox(), *worldGeo->GetBoundingBox(), mitk::eps, true)) { this->SetToolManagerSelection(m_Controls->patImageSelector->GetSelectedNode(), workingNode); this->SetToolSelectionBoxesEnabled(true); this->UpdateWarningLabel(""); } else { this->SetToolManagerSelection(m_Controls->patImageSelector->GetSelectedNode(), nullptr); this->SetToolSelectionBoxesEnabled(false); this->UpdateWarningLabel(tr("Please perform a reinit on the segmentation image!")); } } } -bool QmitkSegmentationView::CheckForSameGeometry(const mitk::DataNode *node1, const mitk::DataNode *node2) const +bool QmitkSegmentationView::CheckForSameGeometry(const mitk::DataNode *node1, const mitk::DataNode *node2) { bool isSameGeometry(true); mitk::Image* image1 = dynamic_cast(node1->GetData()); mitk::Image* image2 = dynamic_cast(node2->GetData()); if (image1 && image2) { mitk::BaseGeometry* geo1 = image1->GetGeometry(); mitk::BaseGeometry* geo2 = image2->GetGeometry(); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetOrigin(), geo2->GetOrigin()); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetExtent(0), geo2->GetExtent(0)); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetExtent(1), geo2->GetExtent(1)); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetExtent(2), geo2->GetExtent(2)); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetSpacing(), geo2->GetSpacing()); isSameGeometry = isSameGeometry && mitk::MatrixEqualElementWise(geo1->GetIndexToWorldTransform()->GetMatrix(), geo2->GetIndexToWorldTransform()->GetMatrix()); return isSameGeometry; } else { return false; } } void QmitkSegmentationView::UpdateWarningLabel(QString text) { if (text.size() == 0) m_Controls->lblSegmentationWarnings->hide(); else m_Controls->lblSegmentationWarnings->show(); m_Controls->lblSegmentationWarnings->setText("" + text + ""); } void QmitkSegmentationView::CreateQtPartControl(QWidget* parent) { // setup the basic GUI of this view m_Parent = parent; m_Controls = new Ui::QmitkSegmentationControls; m_Controls->setupUi(parent); m_Controls->patImageSelector->SetDataStorage(GetDataStorage()); - m_Controls->patImageSelector->SetPredicate(m_IsAPatientImagePredicate); + m_Controls->patImageSelector->SetNodePredicate(m_IsAPatientImagePredicate); + m_Controls->patImageSelector->SetSelectionIsOptional(false); + m_Controls->patImageSelector->SetInvalidInfo("Select an image."); + m_Controls->patImageSelector->SetPopUpTitel("Select an image."); + m_Controls->patImageSelector->SetPopUpHint("Select an image that should be used to define the geometry and bounds of the segmentation."); UpdateWarningLabel(tr("Please select an image")); if (m_Controls->patImageSelector->GetSelectedNode().IsNotNull()) { UpdateWarningLabel(tr("Select or create a new segmentation")); } m_Controls->segImageSelector->SetDataStorage(GetDataStorage()); - m_Controls->segImageSelector->SetPredicate(m_IsASegmentationImagePredicate); + m_Controls->segImageSelector->SetNodePredicate(m_IsASegmentationImagePredicate); + m_Controls->segImageSelector->SetSelectionIsOptional(false); + m_Controls->segImageSelector->SetInvalidInfo("Select a segmentation."); + m_Controls->segImageSelector->SetPopUpTitel("Select a segmentation."); + m_Controls->segImageSelector->SetPopUpHint("Select a segmentation that should be modified. Only segmentation with the same geometry and within the bounds of the reference image are selected."); + if (m_Controls->segImageSelector->GetSelectedNode().IsNotNull()) { UpdateWarningLabel(""); } mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); assert(toolManager); toolManager->SetDataStorage(*(GetDataStorage())); toolManager->InitializeTools(); QString segTools2D = tr("Add Subtract Correction Paint Wipe 'Region Growing' Fill Erase 'Live Wire' '2D Fast Marching'"); QString segTools3D = tr("Threshold 'UL Threshold' Otsu 'Fast Marching 3D' 'Region Growing 3D' Watershed Picking"); std::regex extSegTool2DRegEx("SegTool2D$"); std::regex extSegTool3DRegEx("SegTool3D$"); auto tools = 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())); } } // all part of open source MITK m_Controls->m_ManualToolSelectionBox2D->setEnabled(true); m_Controls->m_ManualToolSelectionBox2D->SetGenerateAccelerators(true); m_Controls->m_ManualToolSelectionBox2D->SetToolGUIArea( m_Controls->m_ManualToolGUIContainer2D ); m_Controls->m_ManualToolSelectionBox2D->SetDisplayedToolGroups(segTools2D.toStdString()); m_Controls->m_ManualToolSelectionBox2D->SetLayoutColumns(3); m_Controls->m_ManualToolSelectionBox2D->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible ); connect( m_Controls->m_ManualToolSelectionBox2D, SIGNAL(ToolSelected(int)), this, SLOT(OnManualTool2DSelected(int)) ); //setup 3D Tools m_Controls->m_ManualToolSelectionBox3D->setEnabled(true); m_Controls->m_ManualToolSelectionBox3D->SetGenerateAccelerators(true); m_Controls->m_ManualToolSelectionBox3D->SetToolGUIArea( m_Controls->m_ManualToolGUIContainer3D ); //specify tools to be added to 3D Tool area m_Controls->m_ManualToolSelectionBox3D->SetDisplayedToolGroups(segTools3D.toStdString()); m_Controls->m_ManualToolSelectionBox3D->SetLayoutColumns(3); m_Controls->m_ManualToolSelectionBox3D->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible ); //Hide 3D selection box, show 2D selection box m_Controls->m_ManualToolSelectionBox3D->hide(); m_Controls->m_ManualToolSelectionBox2D->show(); - // update the list of segmentations - toolManager->NewNodesGenerated += mitk::MessageDelegate(this, &QmitkSegmentationView::NewNodesGenerated); // update the list of segmentations toolManager->NewNodeObjectsGenerated += mitk::MessageDelegate1(this, &QmitkSegmentationView::NewNodeObjectsGenerated); // create signal/slot connections - connect(m_Controls->patImageSelector, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnPatientComboBoxSelectionChanged(const mitk::DataNode*))); - connect(m_Controls->segImageSelector, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnSegmentationComboBoxSelectionChanged(const mitk::DataNode*))); + connect(m_Controls->patImageSelector, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(OnPatientComboBoxSelectionChanged(QList))); + connect(m_Controls->segImageSelector, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(OnSegmentationComboBoxSelectionChanged(QList))); + connect(m_Controls->btnNewSegmentation, SIGNAL(clicked()), this, SLOT(CreateNewSegmentation())); connect(m_Controls->tabWidgetSegmentationTools, SIGNAL(currentChanged(int)), this, SLOT(OnTabWidgetChanged(int))); connect(m_Controls->m_SlicesInterpolator, SIGNAL(SignalShowMarkerNodes(bool)), this, SLOT(OnShowMarkerNodes(bool))); - mitk::DataStorage::SetOfObjects::ConstPointer patientImages = GetDataStorage()->GetSubset(m_IsAPatientImagePredicate); - if (!patientImages->empty()) - { - OnSelectionChanged(*patientImages->begin()); - } + m_Controls->patImageSelector->SetAutoSelectNewNodes(true); + m_Controls->segImageSelector->SetAutoSelectNewNodes(true); // set callback function for already existing nodes (images & segmentations) mitk::DataStorage::SetOfObjects::ConstPointer allImages = GetDataStorage()->GetSubset(m_IsOfTypeImagePredicate); for (mitk::DataStorage::SetOfObjects::const_iterator iter = allImages->begin(); iter != allImages->end(); ++iter) { mitk::DataNode* node = *iter; itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::OnVisiblePropertyChanged); m_WorkingDataObserverTags.insert(std::pair(node, node->GetProperty("visible")->AddObserver(itk::ModifiedEvent(), command))); itk::SimpleMemberCommand::Pointer command2 = itk::SimpleMemberCommand::New(); command2->SetCallbackFunction(this, &QmitkSegmentationView::OnBinaryPropertyChanged); m_BinaryPropertyObserverTags.insert(std::pair(node, node->GetProperty("binary")->AddObserver(itk::ModifiedEvent(), command2))); } itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::RenderingManagerReinitialized); m_RenderingManagerObserverTag = mitk::RenderingManager::GetInstance()->AddObserver(mitk::RenderingManagerViewsInitializedEvent(), command); InitToolManagerSelection(m_Controls->patImageSelector->GetSelectedNode(), m_Controls->segImageSelector->GetSelectedNode()); m_RenderWindowPart = GetRenderWindowPart(); if (m_RenderWindowPart) { RenderWindowPartActivated(m_RenderWindowPart); } } void QmitkSegmentationView::SetFocus() { m_Controls->btnNewSegmentation->setFocus(); } void QmitkSegmentationView::OnManualTool2DSelected(int id) { if (id >= 0) { std::string text = "Active Tool: \""; mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); text += toolManager->GetToolById(id)->GetName(); text += "\""; mitk::StatusBar::GetInstance()->DisplayText(text.c_str()); us::ModuleResource resource = toolManager->GetToolById(id)->GetCursorIconResource(); this->SetMouseCursor(resource, 0, 0); } else { this->ResetMouseCursor(); mitk::StatusBar::GetInstance()->DisplayText(""); } } 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::SetToolSelectionBoxesEnabled(bool status) { if (status) { m_Controls->m_ManualToolSelectionBox2D->RecreateButtons(); m_Controls->m_ManualToolSelectionBox3D->RecreateButtons(); } m_Controls->m_ManualToolSelectionBox2D->setEnabled(status); m_Controls->m_ManualToolSelectionBox3D->setEnabled(status); m_Controls->m_SlicesInterpolator->setEnabled(status); } 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 32e1ccd3e4..3a6607c1d5 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h @@ -1,169 +1,148 @@ /*============================================================================ 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 #include #include #include #include "ui_QmitkSegmentationControls.h" class QmitkRenderWindow; /** * \ingroup ToolManagerEtAl * \ingroup org_mitk_gui_qt_segmentation_internal * \warning Implementation of this class is split up into two .cpp files to make things more compact. Check both this file and QmitkSegmentationOrganNamesHandling.cpp */ class QmitkSegmentationView : public QmitkAbstractView, public mitk::ILifecycleAwarePart, public mitk::IRenderWindowPartListener { Q_OBJECT public: QmitkSegmentationView(); ~QmitkSegmentationView() override; typedef std::map NodeTagMapType; - /*! - \brief Invoked when the DataManager selection changed - */ - virtual void OnSelectionChanged(mitk::DataNode* node); - void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; - - // reaction to new segmentations being created by segmentation tools - void NewNodesGenerated(); void NewNodeObjectsGenerated(mitk::ToolManager::DataVectorType*); void Activated() override; void Deactivated() override; void Visible() override; void Hidden() override; /// /// Sets the focus to an internal widget. /// void SetFocus() override; void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) override; void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) override; // BlueBerry's notification about preference changes (e.g. from a dialog) void OnPreferencesChanged(const berry::IBerryPreferences* prefs) override; // observer to mitk::RenderingManager's RenderingManagerViewsInitializedEvent event void RenderingManagerReinitialized(); - // observer to mitk::SliceController's SliceRotation event - void SliceRotation(const itk::EventObject&); - static const std::string VIEW_ID; protected slots: - void OnPatientComboBoxSelectionChanged(const mitk::DataNode* node); - void OnSegmentationComboBoxSelectionChanged(const mitk::DataNode* node); + void OnPatientComboBoxSelectionChanged(QList nodes); + void OnSegmentationComboBoxSelectionChanged(QList nodes); // reaction to the button "New segmentation" void CreateNewSegmentation(); void OnManualTool2DSelected(int id); void OnVisiblePropertyChanged(); void OnBinaryPropertyChanged(); void OnShowMarkerNodes(bool); void OnTabWidgetChanged(int); protected: // a type for handling lists of DataNodes typedef std::vector NodeList; // GUI setup void CreateQtPartControl(QWidget* parent) override; - // reactions to selection events from data manager (and potential other senders) - //void BlueBerrySelectionChanged(berry::IWorkbenchPart::Pointer sourcepart, berry::ISelection::ConstPointer selection); - mitk::DataNode::Pointer FindFirstRegularImage(std::vector nodes); - mitk::DataNode::Pointer FindFirstSegmentation(std::vector nodes); - // initially set the tool manager selection from the combo boxes - void InitToolManagerSelection(const mitk::DataNode* referenceData, const mitk::DataNode* workingData); + void InitToolManagerSelection(mitk::DataNode* referenceData, mitk::DataNode* workingData); // propagate BlueBerry selection to ToolManager for manual segmentation - void SetToolManagerSelection(const mitk::DataNode* referenceData, const mitk::DataNode* workingData); - - // checks if given render window aligns with the slices of given image - bool IsRenderWindowAligned(QmitkRenderWindow* renderWindow, mitk::Image* image); + void SetToolManagerSelection(mitk::DataNode* referenceData, mitk::DataNode* workingData); // make sure all images/segmentations look as selected by the users in this view's preferences void ForceDisplayPreferencesUponAllImages(); // decorates a DataNode according to the user preference settings void ApplyDisplayOptions(mitk::DataNode* node); void ResetMouseCursor(); void SetMouseCursor(const us::ModuleResource&, int hotspotX, int hotspotY); void SetToolSelectionBoxesEnabled(bool); // 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 NodeRemoved(const mitk::DataNode* node) override; void NodeAdded(const mitk::DataNode *node) override; - bool CheckForSameGeometry(const mitk::DataNode*, const mitk::DataNode*) const; + static bool CheckForSameGeometry(const mitk::DataNode*, const mitk::DataNode*); void UpdateWarningLabel(QString text/*, bool overwriteExistingText = true*/); // the Qt parent of our GUI (NOT of this object) QWidget* m_Parent; // our GUI Ui::QmitkSegmentationControls* m_Controls; mitk::IRenderWindowPart* m_RenderWindowPart; unsigned long m_VisibilityChangedObserverTag; bool m_MouseCursorSet; bool m_DataSelectionChanged; NodeTagMapType m_WorkingDataObserverTags; NodeTagMapType m_BinaryPropertyObserverTags; unsigned int m_RenderingManagerObserverTag; - bool m_AutoSelectionEnabled; - mitk::NodePredicateNot::Pointer m_IsNotAHelperObject; mitk::NodePredicateAnd::Pointer m_IsOfTypeImagePredicate; mitk::NodePredicateOr::Pointer m_IsASegmentationImagePredicate; mitk::NodePredicateAnd::Pointer m_IsAPatientImagePredicate; }; #endif // QMITKSEGMENTATIONVIEW_H diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp index 6888f48345..857ead353c 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp @@ -1,141 +1,141 @@ /*============================================================================ 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 "QmitkBooleanOperationsWidget.h" #include "../../Common/QmitkDataSelectionWidget.h" #include #include #include #include static const char* const HelpText = "Select two different segmentations above"; static std::string GetPrefix(mitk::BooleanOperation::Type type) { switch (type) { case mitk::BooleanOperation::Difference: return "DifferenceFrom_"; case mitk::BooleanOperation::Intersection: return "IntersectionWith_"; case mitk::BooleanOperation::Union: return "UnionWith_"; default: assert(false && "Unknown boolean operation type"); return "UNKNOWN_BOOLEAN_OPERATION_WITH_"; } } static void AddToDataStorage(mitk::DataStorage::Pointer dataStorage, mitk::Image::Pointer segmentation, const std::string& name, mitk::DataNode::Pointer parent = nullptr) { auto dataNode = mitk::DataNode::New(); dataNode->SetName(name); dataNode->SetData(segmentation); dataStorage->Add(dataNode, parent); } QmitkBooleanOperationsWidget::QmitkBooleanOperationsWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent) : QmitkSegmentationUtilityWidget(timeNavigationController, parent) { m_Controls.setupUi(this); - m_Controls.dataSelectionWidget->AddDataStorageComboBox("", QmitkDataSelectionWidget::SegmentationPredicate); - m_Controls.dataSelectionWidget->AddDataStorageComboBox("", QmitkDataSelectionWidget::SegmentationPredicate); + m_Controls.dataSelectionWidget->AddDataStorageComboBox("", "Select 1st segmentation", "Select 1st segmentation", "", QmitkDataSelectionWidget::SegmentationPredicate); + m_Controls.dataSelectionWidget->AddDataStorageComboBox("", "Select 2nd segmentation", "Select 2nd segmentation", "", QmitkDataSelectionWidget::SegmentationPredicate); m_Controls.dataSelectionWidget->SetHelpText(HelpText); connect(m_Controls.dataSelectionWidget, SIGNAL(SelectionChanged(unsigned int, const mitk::DataNode*)), this, SLOT(OnSelectionChanged(unsigned int, const mitk::DataNode*))); connect(m_Controls.differenceButton, SIGNAL(clicked()), this, SLOT(OnDifferenceButtonClicked())); connect(m_Controls.intersectionButton, SIGNAL(clicked()), this, SLOT(OnIntersectionButtonClicked())); connect(m_Controls.unionButton, SIGNAL(clicked()), this, SLOT(OnUnionButtonClicked())); } QmitkBooleanOperationsWidget::~QmitkBooleanOperationsWidget() { } void QmitkBooleanOperationsWidget::OnSelectionChanged(unsigned int, const mitk::DataNode*) { auto dataSelectionWidget = m_Controls.dataSelectionWidget; auto nodeA = dataSelectionWidget->GetSelection(0); auto nodeB = dataSelectionWidget->GetSelection(1); if (nodeA.IsNotNull() && nodeB.IsNotNull() && nodeA != nodeB) { dataSelectionWidget->SetHelpText(""); this->EnableButtons(); } else { dataSelectionWidget->SetHelpText(HelpText); this->EnableButtons(false); } } void QmitkBooleanOperationsWidget::EnableButtons(bool enable) { m_Controls.differenceButton->setEnabled(enable); m_Controls.intersectionButton->setEnabled(enable); m_Controls.unionButton->setEnabled(enable); } void QmitkBooleanOperationsWidget::OnDifferenceButtonClicked() { this->DoBooleanOperation(mitk::BooleanOperation::Difference); } void QmitkBooleanOperationsWidget::OnIntersectionButtonClicked() { this->DoBooleanOperation(mitk::BooleanOperation::Intersection); } void QmitkBooleanOperationsWidget::OnUnionButtonClicked() { this->DoBooleanOperation(mitk::BooleanOperation::Union); } void QmitkBooleanOperationsWidget::DoBooleanOperation(mitk::BooleanOperation::Type type) { auto timeNavigationController = this->GetTimeNavigationController(); assert(timeNavigationController != nullptr); mitk::Image::Pointer segmentationA = dynamic_cast(m_Controls.dataSelectionWidget->GetSelection(0)->GetData()); mitk::Image::Pointer segmentationB = dynamic_cast(m_Controls.dataSelectionWidget->GetSelection(1)->GetData()); mitk::Image::Pointer result; try { mitk::BooleanOperation booleanOperation(type, segmentationA, segmentationB, timeNavigationController->GetTime()->GetPos()); result = booleanOperation.GetResult(); assert(result.IsNotNull()); auto dataSelectionWidget = m_Controls.dataSelectionWidget; AddToDataStorage( dataSelectionWidget->GetDataStorage(), result, GetPrefix(type) + dataSelectionWidget->GetSelection(1)->GetName(), dataSelectionWidget->GetSelection(0)); } catch (const mitk::Exception& exception) { MITK_ERROR << "Boolean operation failed: " << exception.GetDescription(); QMessageBox::information(nullptr, "Boolean operation failed", exception.GetDescription()); } }