diff --git a/Modules/SegmentationUI/Qmitk/QmitkLabelSetWidget.cpp b/Modules/SegmentationUI/Qmitk/QmitkLabelSetWidget.cpp index 72f745d546..22a29d589a 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkLabelSetWidget.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitkLabelSetWidget.cpp @@ -1,1336 +1,1339 @@ /*============================================================================ 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 "QmitkLabelSetWidget.h" // mitk #include #include #include #include #include #include #include #include #include #include #include // Qmitk #include #include #include #include // Qt #include #include #include #include #include #include #include #include #include // itk #include // todo: // berry //#include QmitkLabelSetWidget::QmitkLabelSetWidget(QWidget *parent) : QWidget(parent), m_DataStorage(nullptr), m_Completer(nullptr), m_ToolManager(nullptr) { m_Controls.setupUi(this); m_ColorSequenceRainbow.GoToBegin(); m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(mitk::ToolManagerProvider::MULTILABEL_SEGMENTATION); m_Controls.m_LabelSearchBox->setAlwaysShowClearIcon(true); m_Controls.m_LabelSearchBox->setShowSearchIcon(true); QStringList completionList; completionList << ""; m_Completer = new QCompleter(completionList, this); m_Completer->setCaseSensitivity(Qt::CaseInsensitive); m_Controls.m_LabelSearchBox->setCompleter(m_Completer); connect(m_Controls.m_LabelSearchBox, SIGNAL(returnPressed()), this, SLOT(OnSearchLabel())); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(labelListModified(const QStringList&)), this, SLOT( // OnLabelListModified(const QStringList&)) ); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(mergeLabel(int)), this, SLOT( OnMergeLabel(int)) ); QStringListModel *completeModel = static_cast(m_Completer->model()); completeModel->setStringList(GetLabelStringList()); m_Controls.m_LabelSearchBox->setEnabled(false); m_Controls.m_lblCaption->setText(""); InitializeTableWidget(); } QmitkLabelSetWidget::~QmitkLabelSetWidget() {} void QmitkLabelSetWidget::OnTableViewContextMenuRequested(const QPoint & /*pos*/) { int pixelValue = GetPixelValueOfSelectedItem(); if (-1 == pixelValue) return; QMenu *menu = new QMenu(m_Controls.m_LabelSetTableWidget); if (m_Controls.m_LabelSetTableWidget->selectedItems().size() > 1) { QAction *mergeAction = new QAction(QIcon(":/Qmitk/MergeLabels.png"), "Merge selection on current label", this); mergeAction->setEnabled(true); QObject::connect(mergeAction, SIGNAL(triggered(bool)), this, SLOT(OnMergeLabels(bool))); menu->addAction(mergeAction); QAction *removeLabelsAction = new QAction(QIcon(":/Qmitk/RemoveLabel.png"), "Remove selected labels", this); removeLabelsAction->setEnabled(true); QObject::connect(removeLabelsAction, SIGNAL(triggered(bool)), this, SLOT(OnRemoveLabels(bool))); menu->addAction(removeLabelsAction); QAction *eraseLabelsAction = new QAction(QIcon(":/Qmitk/EraseLabel.png"), "Erase selected labels", this); eraseLabelsAction->setEnabled(true); QObject::connect(eraseLabelsAction, SIGNAL(triggered(bool)), this, SLOT(OnEraseLabels(bool))); menu->addAction(eraseLabelsAction); QAction *combineAndCreateSurfaceAction = new QAction(QIcon(":/Qmitk/CreateSurface.png"), "Combine and create a surface", this); combineAndCreateSurfaceAction->setEnabled(true); QObject::connect( combineAndCreateSurfaceAction, SIGNAL(triggered(bool)), this, SLOT(OnCombineAndCreateSurface(bool))); // menu->addAction(combineAndCreateSurfaceAction); Not implemented QAction *createMasksAction = new QAction(QIcon(":/Qmitk/CreateMask.png"), "Create a mask for each selected label", this); createMasksAction->setEnabled(true); QObject::connect(createMasksAction, SIGNAL(triggered(bool)), this, SLOT(OnCreateMasks(bool))); // menu->addAction(createMasksAction); Not implemented QAction *combineAndCreateMaskAction = new QAction(QIcon(":/Qmitk/CreateMask.png"), "Combine and create a mask", this); combineAndCreateMaskAction->setEnabled(true); QObject::connect(combineAndCreateMaskAction, SIGNAL(triggered(bool)), this, SLOT(OnCombineAndCreateMask(bool))); // menu->addAction(combineAndCreateMaskAction); Not implemented } else { QAction *renameAction = new QAction(QIcon(":/Qmitk/RenameLabel.png"), "Rename...", this); renameAction->setEnabled(true); QObject::connect(renameAction, SIGNAL(triggered(bool)), this, SLOT(OnRenameLabel(bool))); menu->addAction(renameAction); QAction *removeAction = new QAction(QIcon(":/Qmitk/RemoveLabel.png"), "Remove...", this); removeAction->setEnabled(true); QObject::connect(removeAction, SIGNAL(triggered(bool)), this, SLOT(OnRemoveLabel(bool))); menu->addAction(removeAction); QAction *eraseAction = new QAction(QIcon(":/Qmitk/EraseLabel.png"), "Erase...", this); eraseAction->setEnabled(true); QObject::connect(eraseAction, SIGNAL(triggered(bool)), this, SLOT(OnEraseLabel(bool))); menu->addAction(eraseAction); QAction *mergeAction = new QAction(QIcon(":/Qmitk/MergeLabels.png"), "Merge...", this); mergeAction->setEnabled(true); QObject::connect(mergeAction, SIGNAL(triggered(bool)), this, SLOT(OnMergeLabel(bool))); menu->addAction(mergeAction); QAction *randomColorAction = new QAction(QIcon(":/Qmitk/RandomColor.png"), "Random color", this); randomColorAction->setEnabled(true); QObject::connect(randomColorAction, SIGNAL(triggered(bool)), this, SLOT(OnRandomColor(bool))); menu->addAction(randomColorAction); QAction *viewOnlyAction = new QAction(QIcon(":/Qmitk/visible.png"), "View only", this); viewOnlyAction->setEnabled(true); QObject::connect(viewOnlyAction, SIGNAL(triggered(bool)), this, SLOT(OnSetOnlyActiveLabelVisible(bool))); menu->addAction(viewOnlyAction); QAction *viewAllAction = new QAction(QIcon(":/Qmitk/visible.png"), "View all", this); viewAllAction->setEnabled(true); QObject::connect(viewAllAction, SIGNAL(triggered(bool)), this, SLOT(OnSetAllLabelsVisible(bool))); menu->addAction(viewAllAction); QAction *hideAllAction = new QAction(QIcon(":/Qmitk/invisible.png"), "Hide all", this); hideAllAction->setEnabled(true); QObject::connect(hideAllAction, SIGNAL(triggered(bool)), this, SLOT(OnSetAllLabelsInvisible(bool))); menu->addAction(hideAllAction); QAction *lockAllAction = new QAction(QIcon(":/Qmitk/lock.png"), "Lock all", this); lockAllAction->setEnabled(true); QObject::connect(lockAllAction, SIGNAL(triggered(bool)), this, SLOT(OnLockAllLabels(bool))); menu->addAction(lockAllAction); QAction *unlockAllAction = new QAction(QIcon(":/Qmitk/unlock.png"), "Unlock all", this); unlockAllAction->setEnabled(true); QObject::connect(unlockAllAction, SIGNAL(triggered(bool)), this, SLOT(OnUnlockAllLabels(bool))); menu->addAction(unlockAllAction); QAction *createSurfaceAction = new QAction(QIcon(":/Qmitk/CreateSurface.png"), "Create surface", this); createSurfaceAction->setEnabled(true); createSurfaceAction->setMenu(new QMenu()); QAction *tmp1 = createSurfaceAction->menu()->addAction(QString("Detailed")); QAction *tmp2 = createSurfaceAction->menu()->addAction(QString("Smoothed")); QObject::connect(tmp1, SIGNAL(triggered(bool)), this, SLOT(OnCreateDetailedSurface(bool))); QObject::connect(tmp2, SIGNAL(triggered(bool)), this, SLOT(OnCreateSmoothedSurface(bool))); menu->addAction(createSurfaceAction); QAction *createMaskAction = new QAction(QIcon(":/Qmitk/CreateMask.png"), "Create mask", this); createMaskAction->setEnabled(true); QObject::connect(createMaskAction, SIGNAL(triggered(bool)), this, SLOT(OnCreateMask(bool))); menu->addAction(createMaskAction); QAction *createCroppedMaskAction = new QAction(QIcon(":/Qmitk/CreateMask.png"), "Create cropped mask", this); createCroppedMaskAction->setEnabled(true); QObject::connect(createCroppedMaskAction, SIGNAL(triggered(bool)), this, SLOT(OnCreateCroppedMask(bool))); // QAction* importAction = new QAction(QIcon(":/Qmitk/RenameLabel.png"), "Import...", this ); // importAction->setEnabled(true); // QObject::connect( importAction, SIGNAL( triggered(bool) ), this, SLOT( OnImportSegmentationSession(bool) ) ); // menu->addAction(importAction); menu->addAction(createCroppedMaskAction); QSlider *opacitySlider = new QSlider; opacitySlider->setMinimum(0); opacitySlider->setMaximum(100); opacitySlider->setOrientation(Qt::Horizontal); QObject::connect(opacitySlider, SIGNAL(valueChanged(int)), this, SLOT(OnOpacityChanged(int))); QLabel *_OpacityLabel = new QLabel("Opacity: "); QVBoxLayout *_OpacityWidgetLayout = new QVBoxLayout; _OpacityWidgetLayout->setContentsMargins(4, 4, 4, 4); _OpacityWidgetLayout->addWidget(_OpacityLabel); _OpacityWidgetLayout->addWidget(opacitySlider); QWidget *_OpacityWidget = new QWidget; _OpacityWidget->setLayout(_OpacityWidgetLayout); QWidgetAction *OpacityAction = new QWidgetAction(this); OpacityAction->setDefaultWidget(_OpacityWidget); // QObject::connect( m_OpacityAction, SIGNAL( changed() ), this, SLOT( OpacityActionChanged() ) ); auto workingImage = this->GetWorkingImage(); auto activeLayer = workingImage->GetActiveLayer(); auto label = workingImage->GetLabel(pixelValue, activeLayer); if (nullptr != label) { auto opacity = label->GetOpacity(); opacitySlider->setValue(static_cast(opacity * 100)); } menu->addAction(OpacityAction); } menu->popup(QCursor::pos()); } void QmitkLabelSetWidget::OnUnlockAllLabels(bool /*value*/) { GetWorkingImage()->GetActiveLabelSet()->SetAllLabelsLocked(false); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLabelSetWidget::OnLockAllLabels(bool /*value*/) { GetWorkingImage()->GetActiveLabelSet()->SetAllLabelsLocked(true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLabelSetWidget::OnSetAllLabelsVisible(bool /*value*/) { GetWorkingImage()->GetActiveLabelSet()->SetAllLabelsVisible(true); UpdateAllTableWidgetItems(); } void QmitkLabelSetWidget::OnSetAllLabelsInvisible(bool /*value*/) { GetWorkingImage()->GetActiveLabelSet()->SetAllLabelsVisible(false); UpdateAllTableWidgetItems(); } void QmitkLabelSetWidget::OnSetOnlyActiveLabelVisible(bool /*value*/) { mitk::LabelSetImage *workingImage = GetWorkingImage(); int pixelValue = GetPixelValueOfSelectedItem(); workingImage->GetActiveLabelSet()->SetAllLabelsVisible(false); workingImage->GetLabel(pixelValue, workingImage->GetActiveLayer())->SetVisible(true); workingImage->GetActiveLabelSet()->UpdateLookupTable(pixelValue); this->WaitCursorOn(); const mitk::Point3D &pos = workingImage->GetLabel(pixelValue, workingImage->GetActiveLayer())->GetCenterOfMassCoordinates(); this->WaitCursorOff(); if (pos.GetVnlVector().max_value() > 0.0) { emit goToLabel(pos); } UpdateAllTableWidgetItems(); } void QmitkLabelSetWidget::OnMergeLabel(bool /*value*/) { QmitkSearchLabelDialog dialog(this); dialog.setWindowTitle("Select a second label.."); dialog.SetLabelSuggestionList(GetLabelStringList()); int dialogReturnValue = dialog.exec(); if (dialogReturnValue == QDialog::Rejected) return; int sourcePixelValue = -1; for (int i = 0; i < m_Controls.m_LabelSetTableWidget->rowCount(); i++) { if (dialog.GetLabelSetWidgetTableCompleteWord() == QString(m_Controls.m_LabelSetTableWidget->item(i, 0)->text())) sourcePixelValue = m_Controls.m_LabelSetTableWidget->item(i, 0)->data(Qt::UserRole).toInt(); } if (sourcePixelValue == -1) { MITK_INFO << "unknown label"; return; } int pixelValue = GetPixelValueOfSelectedItem(); GetWorkingImage()->MergeLabel(pixelValue, sourcePixelValue, GetWorkingImage()->GetActiveLayer()); UpdateAllTableWidgetItems(); } void QmitkLabelSetWidget::OnEraseLabel(bool /*value*/) { int pixelValue = GetPixelValueOfSelectedItem(); QString question = "Do you really want to erase the contents of label \""; question.append( QString::fromStdString(GetWorkingImage()->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer())->GetName())); question.append("\"?"); QMessageBox::StandardButton answerButton = QMessageBox::question(this, "Erase label", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton == QMessageBox::Yes) { this->WaitCursorOn(); GetWorkingImage()->EraseLabel(pixelValue); this->WaitCursorOff(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkLabelSetWidget::OnRemoveLabel(bool /*value*/) { int pixelValue = GetPixelValueOfSelectedItem(); QString question = "Do you really want to remove label \""; question.append( QString::fromStdString(GetWorkingImage()->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer())->GetName())); question.append("\"?"); QMessageBox::StandardButton answerButton = QMessageBox::question(this, "Remove label", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton == QMessageBox::Yes) { this->WaitCursorOn(); GetWorkingImage()->GetActiveLabelSet()->RemoveLabel(pixelValue); GetWorkingImage()->EraseLabel(pixelValue); this->WaitCursorOff(); } ResetAllTableWidgetItems(); } void QmitkLabelSetWidget::OnRenameLabel(bool /*value*/) { int pixelValue = GetPixelValueOfSelectedItem(); QmitkNewSegmentationDialog dialog(this); dialog.setWindowTitle("Rename Label"); dialog.SetSuggestionList(m_OrganColors); dialog.SetColor(GetWorkingImage()->GetActiveLabelSet()->GetLabel(pixelValue)->GetColor()); dialog.SetSegmentationName( QString::fromStdString(GetWorkingImage()->GetActiveLabelSet()->GetLabel(pixelValue)->GetName())); if (dialog.exec() == QDialog::Rejected) { return; } QString segmentationName = dialog.GetSegmentationName(); if (segmentationName.isEmpty()) { segmentationName = "Unnamed"; } GetWorkingImage()->GetActiveLabelSet()->RenameLabel(pixelValue, segmentationName.toStdString(), dialog.GetColor()); GetWorkingImage()->GetActiveLabelSet()->UpdateLookupTable(pixelValue); UpdateAllTableWidgetItems(); } void QmitkLabelSetWidget::OnCombineAndCreateMask(bool /*value*/) { m_Controls.m_LabelSetTableWidget->selectedRanges(); // ...to do... // } void QmitkLabelSetWidget::OnCreateMasks(bool /*value*/) { m_Controls.m_LabelSetTableWidget->selectedRanges(); // ..to do.. // } void QmitkLabelSetWidget::OnCombineAndCreateSurface(bool /*value*/) { m_Controls.m_LabelSetTableWidget->selectedRanges(); // ..to do.. // } void QmitkLabelSetWidget::OnEraseLabels(bool /*value*/) { QString question = "Do you really want to erase the selected labels?"; QMessageBox::StandardButton answerButton = QMessageBox::question( this, "Erase selected labels", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton == QMessageBox::Yes) { QList ranges = m_Controls.m_LabelSetTableWidget->selectedRanges(); if (ranges.isEmpty()) return; std::vector VectorOfLablePixelValues; foreach (QTableWidgetSelectionRange a, ranges) for (int i = a.topRow(); i <= a.bottomRow(); i++) VectorOfLablePixelValues.push_back(m_Controls.m_LabelSetTableWidget->item(i, 0)->data(Qt::UserRole).toInt()); this->WaitCursorOn(); GetWorkingImage()->EraseLabels(VectorOfLablePixelValues, GetWorkingImage()->GetActiveLayer()); this->WaitCursorOff(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkLabelSetWidget::OnRemoveLabels(bool /*value*/) { QString question = "Do you really want to remove selected labels?"; QMessageBox::StandardButton answerButton = QMessageBox::question( this, "Remove selected labels", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton == QMessageBox::Yes) { QList ranges = m_Controls.m_LabelSetTableWidget->selectedRanges(); if (ranges.isEmpty()) { return; } std::vector VectorOfLablePixelValues; foreach (QTableWidgetSelectionRange a, ranges) { for (int i = a.topRow(); i <= a.bottomRow(); ++i) { VectorOfLablePixelValues.push_back(m_Controls.m_LabelSetTableWidget->item(i, 0)->data(Qt::UserRole).toInt()); } } this->WaitCursorOn(); GetWorkingImage()->RemoveLabels(VectorOfLablePixelValues, GetWorkingImage()->GetActiveLayer()); this->WaitCursorOff(); } ResetAllTableWidgetItems(); } void QmitkLabelSetWidget::OnMergeLabels(bool /*value*/) { int pixelValue = GetPixelValueOfSelectedItem(); QString question = "Do you really want to merge selected labels into \""; question.append( QString::fromStdString(GetWorkingImage()->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer())->GetName())); question.append("\"?"); QMessageBox::StandardButton answerButton = QMessageBox::question( this, "Merge selected label", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton == QMessageBox::Yes) { QList ranges = m_Controls.m_LabelSetTableWidget->selectedRanges(); if (ranges.isEmpty()) { return; } std::vector vectorOfSourcePixelValues; foreach (QTableWidgetSelectionRange a, ranges) { for (int i = a.topRow(); i <= a.bottomRow(); ++i) { vectorOfSourcePixelValues.push_back(m_Controls.m_LabelSetTableWidget->item(i, 0)->data(Qt::UserRole).toInt()); } } this->WaitCursorOn(); GetWorkingImage()->MergeLabels(pixelValue, vectorOfSourcePixelValues, GetWorkingImage()->GetActiveLayer()); this->WaitCursorOff(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkLabelSetWidget::OnLockedButtonClicked() { int row = -1; for (int i = 0; i < m_Controls.m_LabelSetTableWidget->rowCount(); ++i) { if (sender() == m_Controls.m_LabelSetTableWidget->cellWidget(i, LOCKED_COL)) { row = i; } } if (row >= 0 && row < m_Controls.m_LabelSetTableWidget->rowCount()) { int pixelValue = m_Controls.m_LabelSetTableWidget->item(row, 0)->data(Qt::UserRole).toInt(); GetWorkingImage() ->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer()) ->SetLocked(!GetWorkingImage()->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer())->GetLocked()); } } void QmitkLabelSetWidget::OnVisibleButtonClicked() { int row = -1; for (int i = 0; i < m_Controls.m_LabelSetTableWidget->rowCount(); ++i) { if (sender() == m_Controls.m_LabelSetTableWidget->cellWidget(i, VISIBLE_COL)) { row = i; break; } } if (row >= 0 && row < m_Controls.m_LabelSetTableWidget->rowCount()) { QTableWidgetItem *item = m_Controls.m_LabelSetTableWidget->item(row, 0); int pixelValue = item->data(Qt::UserRole).toInt(); GetWorkingImage() ->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer()) ->SetVisible(!GetWorkingImage()->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer())->GetVisible()); GetWorkingImage()->GetActiveLabelSet()->UpdateLookupTable(pixelValue); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLabelSetWidget::OnColorButtonClicked() { int row = -1; for (int i = 0; i < m_Controls.m_LabelSetTableWidget->rowCount(); ++i) { if (sender() == m_Controls.m_LabelSetTableWidget->cellWidget(i, COLOR_COL)) { row = i; } } if (row >= 0 && row < m_Controls.m_LabelSetTableWidget->rowCount()) { int pixelValue = m_Controls.m_LabelSetTableWidget->item(row, 0)->data(Qt::UserRole).toInt(); const mitk::Color &color = GetWorkingImage()->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer())->GetColor(); QColor initial(color.GetRed() * 255, color.GetGreen() * 255, color.GetBlue() * 255); QColor qcolor = QColorDialog::getColor(initial, nullptr, QString("Change color")); if (!qcolor.isValid()) { return; } QPushButton *button = static_cast(m_Controls.m_LabelSetTableWidget->cellWidget(row, COLOR_COL)); if (!button) { return; } button->setAutoFillBackground(true); QString styleSheet = "background-color:rgb("; styleSheet.append(QString::number(qcolor.red())); styleSheet.append(","); styleSheet.append(QString::number(qcolor.green())); styleSheet.append(","); styleSheet.append(QString::number(qcolor.blue())); styleSheet.append("); border: 0;"); button->setStyleSheet(styleSheet); mitk::Color newColor; newColor.SetRed(qcolor.red() / 255.0); newColor.SetGreen(qcolor.green() / 255.0); newColor.SetBlue(qcolor.blue() / 255.0); GetWorkingImage()->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer())->SetColor(newColor); GetWorkingImage()->GetActiveLabelSet()->UpdateLookupTable(pixelValue); } } void QmitkLabelSetWidget::OnRandomColor(bool /*value*/) { int pixelValue = GetPixelValueOfSelectedItem(); GetWorkingImage() ->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer()) ->SetColor(m_ColorSequenceRainbow.GetNextColor()); GetWorkingImage()->GetActiveLabelSet()->UpdateLookupTable(pixelValue); UpdateAllTableWidgetItems(); } void QmitkLabelSetWidget::SetOrganColors(const QStringList &organColors) { m_OrganColors = organColors; } void QmitkLabelSetWidget::OnActiveLabelChanged(int pixelValue) { mitk::LabelSetImage *workingImage = GetWorkingImage(); assert(workingImage); workingImage->GetActiveLabelSet()->SetActiveLabel(pixelValue); // MITK_INFO << "Active Label set to << " << pixelValue; mitk::SurfaceBasedInterpolationController *interpolator = mitk::SurfaceBasedInterpolationController::GetInstance(); if (interpolator) { interpolator->SetActiveLabel(pixelValue); } workingImage->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLabelSetWidget::OnItemClicked(QTableWidgetItem *item) { if (!item) return; int pixelValue = item->data(Qt::UserRole).toInt(); QList ranges = m_Controls.m_LabelSetTableWidget->selectedRanges(); if (!ranges.empty() && ranges.back().rowCount() == 1) { SelectLabelByPixelValue(pixelValue); OnActiveLabelChanged(pixelValue); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkLabelSetWidget::OnItemDoubleClicked(QTableWidgetItem *item) { if (!item) return; int pixelValue = item->data(Qt::UserRole).toInt(); // OnItemClicked(item); <<-- Double click first call OnItemClicked WaitCursorOn(); mitk::LabelSetImage *workingImage = GetWorkingImage(); workingImage->UpdateCenterOfMass(pixelValue, workingImage->GetActiveLayer()); const mitk::Point3D &pos = workingImage->GetLabel(pixelValue, workingImage->GetActiveLayer())->GetCenterOfMassCoordinates(); WaitCursorOff(); if (pos.GetVnlVector().max_value() > 0.0) { emit goToLabel(pos); } workingImage->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLabelSetWidget::SelectLabelByPixelValue(mitk::Label::PixelType pixelValue) { // MITK_INFO << "QmitkLabelSetWidget::SelectLabelByPixelValue " << pixelValue; if (!GetWorkingImage()->ExistLabel(pixelValue)) return; for (int row = 0; row < m_Controls.m_LabelSetTableWidget->rowCount(); row++) { if (m_Controls.m_LabelSetTableWidget->item(row, 0)->data(Qt::UserRole).toInt() == pixelValue) { m_Controls.m_LabelSetTableWidget->clearSelection(); m_Controls.m_LabelSetTableWidget->setSelectionMode(QAbstractItemView::SingleSelection); m_Controls.m_LabelSetTableWidget->selectRow(row); m_Controls.m_LabelSetTableWidget->scrollToItem(m_Controls.m_LabelSetTableWidget->item(row, 0)); m_Controls.m_LabelSetTableWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); // SelectTableWidgetItem(m_Controls.m_LabelSetTableWidget->item(i,0)); // emit resetView(); // GetWorkingImage()->Modified(); return; } } } void QmitkLabelSetWidget::InsertTableWidgetItem(mitk::Label *label) { const mitk::Color &color = label->GetColor(); QString styleSheet = "background-color:rgb("; styleSheet.append(QString::number(color[0] * 255)); styleSheet.append(","); styleSheet.append(QString::number(color[1] * 255)); styleSheet.append(","); styleSheet.append(QString::number(color[2] * 255)); styleSheet.append("); border: 0;"); QTableWidget *tableWidget = m_Controls.m_LabelSetTableWidget; int colWidth = (tableWidget->columnWidth(NAME_COL) < 180) ? 180 : tableWidget->columnWidth(NAME_COL) - 2; QString text = fontMetrics().elidedText(label->GetName().c_str(), Qt::ElideMiddle, colWidth); QTableWidgetItem *nameItem = new QTableWidgetItem(text); nameItem->setTextAlignment(Qt::AlignCenter | Qt::AlignLeft); // ---!--- // IMPORTANT: ADD PIXELVALUE TO TABLEWIDGETITEM.DATA nameItem->setData(Qt::UserRole, QVariant(label->GetValue())); // ---!--- QPushButton *pbColor = new QPushButton(tableWidget); pbColor->setFixedSize(24, 24); pbColor->setCheckable(false); pbColor->setAutoFillBackground(true); pbColor->setToolTip("Change label color"); pbColor->setStyleSheet(styleSheet); connect(pbColor, SIGNAL(clicked()), this, SLOT(OnColorButtonClicked())); QString transparentStyleSheet = QLatin1String("background-color: transparent; border: 0;"); QPushButton *pbLocked = new QPushButton(tableWidget); pbLocked->setFixedSize(24, 24); QIcon *iconLocked = new QIcon(); auto lockIcon = QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/lock.svg")); auto unlockIcon = QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/unlock.svg")); iconLocked->addPixmap(lockIcon.pixmap(64), QIcon::Normal, QIcon::Off); iconLocked->addPixmap(unlockIcon.pixmap(64), QIcon::Normal, QIcon::On); pbLocked->setIcon(*iconLocked); pbLocked->setIconSize(QSize(24, 24)); pbLocked->setCheckable(true); pbLocked->setToolTip("Lock/unlock label"); pbLocked->setChecked(!label->GetLocked()); pbLocked->setStyleSheet(transparentStyleSheet); connect(pbLocked, SIGNAL(clicked()), this, SLOT(OnLockedButtonClicked())); QPushButton *pbVisible = new QPushButton(tableWidget); pbVisible->setFixedSize(24, 24); pbVisible->setAutoRepeat(false); QIcon *iconVisible = new QIcon(); auto visibleIcon = QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/visible.svg")); auto invisibleIcon = QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/invisible.svg")); iconVisible->addPixmap(visibleIcon.pixmap(64), QIcon::Normal, QIcon::Off); iconVisible->addPixmap(invisibleIcon.pixmap(64), QIcon::Normal, QIcon::On); pbVisible->setIcon(*iconVisible); pbVisible->setIconSize(QSize(24, 24)); pbVisible->setCheckable(true); pbVisible->setToolTip("Show/hide label"); pbVisible->setChecked(!label->GetVisible()); pbVisible->setStyleSheet(transparentStyleSheet); connect(pbVisible, SIGNAL(clicked()), this, SLOT(OnVisibleButtonClicked())); int row = tableWidget->rowCount(); tableWidget->insertRow(row); tableWidget->setRowHeight(row, 24); tableWidget->setItem(row, 0, nameItem); tableWidget->setCellWidget(row, 1, pbLocked); tableWidget->setCellWidget(row, 2, pbColor); tableWidget->setCellWidget(row, 3, pbVisible); tableWidget->selectRow(row); // m_LabelSetImage->SetActiveLabel(label->GetPixelValue()); // m_ToolManager->WorkingDataModified.Send(); // emit activeLabelChanged(label->GetPixelValue()); if (row == 0) { tableWidget->hideRow(row); // hide exterior label } } void QmitkLabelSetWidget::UpdateAllTableWidgetItems() { mitk::LabelSetImage *workingImage = GetWorkingImage(); if (!workingImage) return; // add all labels QTableWidget *tableWidget = m_Controls.m_LabelSetTableWidget; m_LabelStringList.clear(); for (int i = 0; i < tableWidget->rowCount(); ++i) { UpdateTableWidgetItem(tableWidget->item(i, 0)); m_LabelStringList.append(tableWidget->item(i, 0)->text()); } OnLabelListModified(m_LabelStringList); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLabelSetWidget::UpdateTableWidgetItem(QTableWidgetItem *item) { mitk::LabelSetImage *workingImage = GetWorkingImage(); mitk::Label *label = workingImage->GetLabel(item->data(Qt::UserRole).toInt(), workingImage->GetActiveLayer()); const mitk::Color &color = label->GetColor(); QString styleSheet = "background-color:rgb("; styleSheet.append(QString::number(color[0] * 255)); styleSheet.append(","); styleSheet.append(QString::number(color[1] * 255)); styleSheet.append(","); styleSheet.append(QString::number(color[2] * 255)); styleSheet.append("); border: 0;"); QTableWidget *tableWidget = m_Controls.m_LabelSetTableWidget; int colWidth = (tableWidget->columnWidth(NAME_COL) < 180) ? 180 : tableWidget->columnWidth(NAME_COL) - 2; QString text = fontMetrics().elidedText(label->GetName().c_str(), Qt::ElideMiddle, colWidth); item->setText(text); QPushButton *pbLocked = dynamic_cast(tableWidget->cellWidget(item->row(), 1)); pbLocked->setChecked(!label->GetLocked()); QPushButton *pbColor = dynamic_cast(tableWidget->cellWidget(item->row(), 2)); pbColor->setStyleSheet(styleSheet); QPushButton *pbVisible = dynamic_cast(tableWidget->cellWidget(item->row(), 3)); pbVisible->setChecked(!label->GetVisible()); if (item->row() == 0) { tableWidget->hideRow(item->row()); // hide exterior label } } void QmitkLabelSetWidget::ResetAllTableWidgetItems() { QTableWidget *tableWidget = m_Controls.m_LabelSetTableWidget; // remove all rows while (tableWidget->rowCount()) { tableWidget->removeRow(0); } - mitk::LabelSetImage *workingImage = GetWorkingImage(); - if (!workingImage) + mitk::DataNode * workingNode = GetWorkingNode(); + auto workingImage = dynamic_cast(workingNode->GetData()); + if (nullptr == workingImage) + { return; + } // add all labels m_LabelStringList.clear(); mitk::LabelSet::LabelContainerConstIteratorType it = workingImage->GetActiveLabelSet()->IteratorConstBegin(); mitk::LabelSet::LabelContainerConstIteratorType end = workingImage->GetActiveLabelSet()->IteratorConstEnd(); int pixelValue = -1; while (it != end) { InsertTableWidgetItem(it->second); if (workingImage->GetActiveLabel() == it->second) // get active pixelValue = it->first; m_LabelStringList.append(QString(it->second->GetName().c_str())); it++; } SelectLabelByPixelValue(pixelValue); OnLabelListModified(m_LabelStringList); std::stringstream captionText; captionText << "Number of labels: " << workingImage->GetNumberOfLabels(workingImage->GetActiveLayer()) - 1; m_Controls.m_lblCaption->setText(captionText.str().c_str()); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } int QmitkLabelSetWidget::GetPixelValueOfSelectedItem() { if (m_Controls.m_LabelSetTableWidget->currentItem()) { return m_Controls.m_LabelSetTableWidget->currentItem()->data(Qt::UserRole).toInt(); } return -1; } QStringList &QmitkLabelSetWidget::GetLabelStringList() { return m_LabelStringList; } void QmitkLabelSetWidget::InitializeTableWidget() { QTableWidget *tableWidged = m_Controls.m_LabelSetTableWidget; tableWidged->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); tableWidged->setTabKeyNavigation(false); tableWidged->setAlternatingRowColors(false); tableWidged->setFocusPolicy(Qt::NoFocus); tableWidged->setColumnCount(4); tableWidged->resizeColumnToContents(NAME_COL); tableWidged->setColumnWidth(LOCKED_COL, 25); tableWidged->setColumnWidth(COLOR_COL, 25); tableWidged->setColumnWidth(VISIBLE_COL, 25); tableWidged->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); tableWidged->setContextMenuPolicy(Qt::CustomContextMenu); tableWidged->horizontalHeader()->hide(); tableWidged->setSortingEnabled(false); tableWidged->verticalHeader()->hide(); tableWidged->setEditTriggers(QAbstractItemView::NoEditTriggers); tableWidged->setSelectionMode(QAbstractItemView::ExtendedSelection); tableWidged->setSelectionBehavior(QAbstractItemView::SelectRows); connect(tableWidged, SIGNAL(itemClicked(QTableWidgetItem *)), this, SLOT(OnItemClicked(QTableWidgetItem *))); connect( tableWidged, SIGNAL(itemDoubleClicked(QTableWidgetItem *)), this, SLOT(OnItemDoubleClicked(QTableWidgetItem *))); connect(tableWidged, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(OnTableViewContextMenuRequested(const QPoint &))); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(activeLabelChanged(int)), this, SLOT(OnActiveLabelChanged(int)) // ); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(importSegmentation()), this, SLOT( OnImportSegmentation()) ); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(importLabeledImage()), this, SLOT( OnImportLabeledImage()) ); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(renameLabel(int, const mitk::Color&, const std::string&)), this, // SLOT(OnRenameLabel(int, const mitk::Color&, const std::string&)) ); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(createSurface(int, bool)), this, SLOT(OnCreateSurface(int, bool)) // ); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(toggleOutline(bool)), this, SLOT(OnToggleOutline(bool)) ); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(goToLabel(const mitk::Point3D&)), this, SIGNAL(goToLabel(const // mitk::Point3D&)) ); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(combineAndCreateSurface( const QList& // )), // this, SLOT(OnCombineAndCreateSurface( const QList&)) ); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(createMask(int)), this, SLOT(OnCreateMask(int)) ); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(createCroppedMask(int)), this, SLOT(OnCreateCroppedMask(int)) ); // connect( m_Controls.m_LabelSetTableWidget, SIGNAL(combineAndCreateMask( const QList& // )), // this, SLOT(OnCombineAndCreateMask( const QList&)) ); } void QmitkLabelSetWidget::OnOpacityChanged(int value) { int pixelValue = GetPixelValueOfSelectedItem(); float opacity = static_cast(value) / 100.0f; GetWorkingImage()->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer())->SetOpacity(opacity); GetWorkingImage()->GetActiveLabelSet()->UpdateLookupTable(pixelValue); } void QmitkLabelSetWidget::setEnabled(bool enabled) { QWidget::setEnabled(enabled); UpdateControls(); } void QmitkLabelSetWidget::SetDataStorage(mitk::DataStorage *storage) { m_DataStorage = storage; } void QmitkLabelSetWidget::OnSearchLabel() { std::string text = m_Controls.m_LabelSearchBox->text().toStdString(); int pixelValue = -1; int row = -1; for (int i = 0; i < m_Controls.m_LabelSetTableWidget->rowCount(); ++i) { if (m_Controls.m_LabelSetTableWidget->item(i, 0)->text().toStdString().compare(text) == 0) { pixelValue = m_Controls.m_LabelSetTableWidget->item(i, 0)->data(Qt::UserRole).toInt(); row = i; break; } } if (pixelValue == -1) { return; } GetWorkingImage()->GetActiveLabelSet()->SetActiveLabel(pixelValue); QTableWidgetItem *nameItem = m_Controls.m_LabelSetTableWidget->item(row, NAME_COL); if (!nameItem) { return; } m_Controls.m_LabelSetTableWidget->clearSelection(); m_Controls.m_LabelSetTableWidget->setSelectionMode(QAbstractItemView::SingleSelection); m_Controls.m_LabelSetTableWidget->selectRow(row); m_Controls.m_LabelSetTableWidget->scrollToItem(nameItem); m_Controls.m_LabelSetTableWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); GetWorkingImage()->GetActiveLabelSet()->SetActiveLabel(pixelValue); this->WaitCursorOn(); mitk::Point3D pos = GetWorkingImage()->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer())->GetCenterOfMassCoordinates(); m_ToolManager->WorkingDataChanged(); if (pos.GetVnlVector().max_value() > 0.0) { emit goToLabel(pos); } else { GetWorkingImage()->UpdateCenterOfMass(pixelValue, GetWorkingImage()->GetActiveLayer()); mitk::Point3D pos = GetWorkingImage()->GetLabel(pixelValue, GetWorkingImage()->GetActiveLayer())->GetCenterOfMassCoordinates(); emit goToLabel(pos); } this->WaitCursorOff(); } void QmitkLabelSetWidget::OnLabelListModified(const QStringList &list) { QStringListModel *completeModel = static_cast(m_Completer->model()); completeModel->setStringList(list); } mitk::LabelSetImage *QmitkLabelSetWidget::GetWorkingImage() { mitk::DataNode *workingNode = GetWorkingNode(); mitk::LabelSetImage *workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); return workingImage; } mitk::DataNode *QmitkLabelSetWidget::GetWorkingNode() { mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); return workingNode; } void QmitkLabelSetWidget::UpdateControls() { mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); bool hasWorkingData = (workingNode != nullptr); m_Controls.m_LabelSetTableWidget->setEnabled(hasWorkingData); m_Controls.m_LabelSearchBox->setEnabled(hasWorkingData); if (!hasWorkingData) return; QStringListModel *completeModel = static_cast(m_Completer->model()); completeModel->setStringList(GetLabelStringList()); } void QmitkLabelSetWidget::OnCreateCroppedMask(bool) { m_ToolManager->ActivateTool(-1); mitk::LabelSetImage *workingImage = GetWorkingImage(); mitk::Image::Pointer maskImage; int pixelValue = GetPixelValueOfSelectedItem(); try { this->WaitCursorOn(); mitk::AutoCropImageFilter::Pointer cropFilter = mitk::AutoCropImageFilter::New(); cropFilter->SetInput(workingImage->CreateLabelMask(pixelValue)); cropFilter->SetBackgroundValue(0); cropFilter->SetMarginFactor(1.15); cropFilter->Update(); maskImage = cropFilter->GetOutput(); this->WaitCursorOff(); } catch (mitk::Exception &e) { this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(this, "Create Mask", "Could not create a mask out of the selected label.\n"); return; } if (maskImage.IsNull()) { QMessageBox::information(this, "Create Mask", "Could not create a mask out of the selected label.\n"); return; } mitk::DataNode::Pointer maskNode = mitk::DataNode::New(); std::string name = workingImage->GetLabel(pixelValue, workingImage->GetActiveLayer())->GetName(); name += "-mask"; maskNode->SetName(name); maskNode->SetData(maskImage); maskNode->SetBoolProperty("binary", true); maskNode->SetBoolProperty("outline binary", true); maskNode->SetBoolProperty("outline binary shadow", true); maskNode->SetFloatProperty("outline width", 2.0); maskNode->SetColor(workingImage->GetLabel(pixelValue, workingImage->GetActiveLayer())->GetColor()); maskNode->SetOpacity(1.0); m_DataStorage->Add(maskNode, GetWorkingNode()); } void QmitkLabelSetWidget::OnCreateMask(bool /*triggered*/) { m_ToolManager->ActivateTool(-1); mitk::LabelSetImage *workingImage = GetWorkingImage(); mitk::Image::Pointer maskImage; int pixelValue = GetPixelValueOfSelectedItem(); try { this->WaitCursorOn(); maskImage = workingImage->CreateLabelMask(pixelValue); this->WaitCursorOff(); } catch (mitk::Exception &e) { this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(this, "Create Mask", "Could not create a mask out of the selected label.\n"); return; } if (maskImage.IsNull()) { QMessageBox::information(this, "Create Mask", "Could not create a mask out of the selected label.\n"); return; } mitk::DataNode::Pointer maskNode = mitk::DataNode::New(); std::string name = workingImage->GetLabel(pixelValue, workingImage->GetActiveLayer())->GetName(); name += "-mask"; maskNode->SetName(name); maskNode->SetData(maskImage); maskNode->SetBoolProperty("binary", true); maskNode->SetBoolProperty("outline binary", true); maskNode->SetBoolProperty("outline binary shadow", true); maskNode->SetFloatProperty("outline width", 2.0); maskNode->SetColor(workingImage->GetLabel(pixelValue, workingImage->GetActiveLayer())->GetColor()); maskNode->SetOpacity(1.0); m_DataStorage->Add(maskNode, GetWorkingNode()); } void QmitkLabelSetWidget::OnToggleOutline(bool value) { mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); workingNode->SetBoolProperty("labelset.contour.active", value); workingNode->GetData()->Modified(); // fixme: workaround to force data-type rendering (and not only property-type) mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLabelSetWidget::OnCreateSmoothedSurface(bool /*triggered*/) { m_ToolManager->ActivateTool(-1); mitk::DataNode::Pointer workingNode = GetWorkingNode(); mitk::LabelSetImage *workingImage = GetWorkingImage(); int pixelValue = GetPixelValueOfSelectedItem(); mitk::LabelSetImageToSurfaceThreadedFilter::Pointer surfaceFilter = mitk::LabelSetImageToSurfaceThreadedFilter::New(); itk::SimpleMemberCommand::Pointer successCommand = itk::SimpleMemberCommand::New(); successCommand->SetCallbackFunction(this, &QmitkLabelSetWidget::OnThreadedCalculationDone); surfaceFilter->AddObserver(mitk::ResultAvailable(), successCommand); itk::SimpleMemberCommand::Pointer errorCommand = itk::SimpleMemberCommand::New(); errorCommand->SetCallbackFunction(this, &QmitkLabelSetWidget::OnThreadedCalculationDone); surfaceFilter->AddObserver(mitk::ProcessingError(), errorCommand); mitk::DataNode::Pointer groupNode = workingNode; surfaceFilter->SetPointerParameter("Group node", groupNode); surfaceFilter->SetPointerParameter("Input", workingImage); surfaceFilter->SetParameter("RequestedLabel", pixelValue); surfaceFilter->SetParameter("Smooth", true); surfaceFilter->SetDataStorage(*m_DataStorage); mitk::StatusBar::GetInstance()->DisplayText("Surface creation is running in background..."); try { surfaceFilter->StartAlgorithm(); } catch (mitk::Exception &e) { MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(this, "Create Surface", "Could not create a surface mesh out of the selected label. See error log for details.\n"); } } void QmitkLabelSetWidget::OnCreateDetailedSurface(bool /*triggered*/) { m_ToolManager->ActivateTool(-1); mitk::DataNode::Pointer workingNode = GetWorkingNode(); mitk::LabelSetImage *workingImage = GetWorkingImage(); int pixelValue = GetPixelValueOfSelectedItem(); mitk::LabelSetImageToSurfaceThreadedFilter::Pointer surfaceFilter = mitk::LabelSetImageToSurfaceThreadedFilter::New(); itk::SimpleMemberCommand::Pointer successCommand = itk::SimpleMemberCommand::New(); successCommand->SetCallbackFunction(this, &QmitkLabelSetWidget::OnThreadedCalculationDone); surfaceFilter->AddObserver(mitk::ResultAvailable(), successCommand); itk::SimpleMemberCommand::Pointer errorCommand = itk::SimpleMemberCommand::New(); errorCommand->SetCallbackFunction(this, &QmitkLabelSetWidget::OnThreadedCalculationDone); surfaceFilter->AddObserver(mitk::ProcessingError(), errorCommand); mitk::DataNode::Pointer groupNode = workingNode; surfaceFilter->SetPointerParameter("Group node", groupNode); surfaceFilter->SetPointerParameter("Input", workingImage); surfaceFilter->SetParameter("RequestedLabel", pixelValue); surfaceFilter->SetParameter("Smooth", false); surfaceFilter->SetDataStorage(*m_DataStorage); mitk::StatusBar::GetInstance()->DisplayText("Surface creation is running in background..."); try { surfaceFilter->StartAlgorithm(); } catch (mitk::Exception &e) { MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(this, "Create Surface", "Could not create a surface mesh out of the selected label. See error log for details.\n"); } } void QmitkLabelSetWidget::OnImportLabeledImage() { /* m_ToolManager->ActivateTool(-1); mitk::DataNode* referenceNode = m_ToolManager->GetReferenceData(0); assert(referenceNode); // Ask the user for a list of files to open QStringList fileNames = QFileDialog::getOpenFileNames( this, "Open Image", m_LastFileOpenPath, mitk::CoreObjectFactory::GetInstance()->GetFileExtensions()); if (fileNames.empty()) return; try { this->WaitCursorOn(); mitk::Image::Pointer image = mitk::IOUtil::Load( fileNames.front().toStdString() ); if (image.IsNull()) { this->WaitCursorOff(); QMessageBox::information(this, "Import Labeled Image", "Could not load the selected segmentation.\n"); return; } mitk::LabelSetImage::Pointer newImage = mitk::LabelSetImage::New(); newImage->InitializeByLabeledImage(image); this->WaitCursorOff(); mitk::DataNode::Pointer newNode = mitk::DataNode::New(); std::string newName = referenceNode->GetName(); newName += "-labels"; newNode->SetName(newName); newNode->SetData(newImage); m_DataStorage->Add(newNode, referenceNode); } catch (mitk::Exception & e) { this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(this, "Import Labeled Image", "Could not load the selected segmentation. See error log for details.\n"); return; } this->UpdateControls(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); */ } void QmitkLabelSetWidget::OnImportSegmentation() { /* m_ToolManager->ActivateTool(-1); mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage* workingImage = dynamic_cast( workingNode->GetData() ); assert(workingImage); std::string fileExtensions("Segmentation files (*.lset);;"); QString qfileName = QFileDialog::getOpenFileName(this, "Import Segmentation", m_LastFileOpenPath, fileExtensions.c_str() ); if (qfileName.isEmpty() ) return; mitk::NrrdLabelSetImageReader::Pointer reader = mitk::NrrdLabelSetImageReader::New(); reader->SetFileName(qfileName.toLatin1()); try { this->WaitCursorOn(); reader->Update(); mitk::LabelSetImage::Pointer newImage = reader->GetOutput(); workingImage->Concatenate(newImage); this->WaitCursorOff(); } catch ( mitk::Exception& e ) { this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(this, "Import Segmentation", "Could not import the selected segmentation session.\n See error log for details.\n"); } */ mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkLabelSetWidget::WaitCursorOn() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); } void QmitkLabelSetWidget::WaitCursorOff() { this->RestoreOverrideCursor(); } void QmitkLabelSetWidget::RestoreOverrideCursor() { QApplication::restoreOverrideCursor(); } void QmitkLabelSetWidget::OnThreadedCalculationDone() { mitk::StatusBar::GetInstance()->Clear(); } diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/QmitkMultiLabelSegmentationPreferencePage.cpp b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/QmitkMultiLabelSegmentationPreferencePage.cpp index ae6433cdce..e384407c7c 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/QmitkMultiLabelSegmentationPreferencePage.cpp +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/QmitkMultiLabelSegmentationPreferencePage.cpp @@ -1,151 +1,156 @@ /*============================================================================ 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 "QmitkMultiLabelSegmentationPreferencePage.h" #include #include #include #include #include #include #include #include #include #include QmitkMultiLabelSegmentationPreferencePage::QmitkMultiLabelSegmentationPreferencePage() : m_MainControl(nullptr), + m_SlimViewCheckBox(nullptr), m_RadioOutline(nullptr), m_RadioOverlay(nullptr), + m_SelectionModeCheckBox(nullptr), m_SmoothingSpinBox(nullptr), m_DecimationSpinBox(nullptr), - m_SelectionModeCheckBox(nullptr), m_Initializing(false) { } QmitkMultiLabelSegmentationPreferencePage::~QmitkMultiLabelSegmentationPreferencePage() { } void QmitkMultiLabelSegmentationPreferencePage::Init(berry::IWorkbench::Pointer ) { } void QmitkMultiLabelSegmentationPreferencePage::CreateQtControl(QWidget* parent) { m_Initializing = true; - berry::IPreferencesService* prefService - = berry::Platform::GetPreferencesService(); + berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); m_SegmentationPreferencesNode = prefService->GetSystemPreferences()->Node("/org.mitk.views.multilabelsegmentation"); m_MainControl = new QWidget(parent); + QFormLayout *formLayout = new QFormLayout; + formLayout->setHorizontalSpacing(8); + formLayout->setVerticalSpacing(24); + + m_SlimViewCheckBox = new QCheckBox("Hide tool button texts and increase icon size", m_MainControl); + formLayout->addRow("Slim view", m_SlimViewCheckBox); + QVBoxLayout* displayOptionsLayout = new QVBoxLayout; m_RadioOutline = new QRadioButton( "Draw as outline", m_MainControl); displayOptionsLayout->addWidget( m_RadioOutline ); m_RadioOverlay = new QRadioButton( "Draw as transparent overlay", m_MainControl); displayOptionsLayout->addWidget( m_RadioOverlay ); - - QFormLayout *formLayout = new QFormLayout; - formLayout->setHorizontalSpacing(8); - formLayout->setVerticalSpacing(24); formLayout->addRow( "2D display", displayOptionsLayout ); + m_SelectionModeCheckBox = new QCheckBox("Enable auto-selection mode", m_MainControl); + m_SelectionModeCheckBox->setToolTip("If checked the segmentation plugin ensures that only one segmentation and the according greyvalue image are visible at one time."); + formLayout->addRow("Data node selection mode", m_SelectionModeCheckBox); + QFormLayout* surfaceLayout = new QFormLayout; surfaceLayout->setSpacing(8); m_SmoothingSpinBox = new QDoubleSpinBox(m_MainControl); m_SmoothingSpinBox->setMinimum(0.0); m_SmoothingSpinBox->setSingleStep(0.5); m_SmoothingSpinBox->setValue(0.1); m_SmoothingSpinBox->setToolTip("The Smoothing value is used as Sigma for a gaussian blur."); surfaceLayout->addRow("Smoothing value (mm)", m_SmoothingSpinBox); m_DecimationSpinBox = new QDoubleSpinBox(m_MainControl); m_DecimationSpinBox->setMinimum(0.0); m_DecimationSpinBox->setMaximum(0.99); m_DecimationSpinBox->setSingleStep(0.1); m_DecimationSpinBox->setValue(0.5); m_DecimationSpinBox->setToolTip("Valid range is [0, 1). High values increase decimation, especially when very close to 1. A value of 0 disables decimation."); surfaceLayout->addRow("Decimation rate", m_DecimationSpinBox); - m_SelectionModeCheckBox = new QCheckBox("Enable auto-selection mode", m_MainControl); - m_SelectionModeCheckBox->setToolTip("If checked the segmentation plugin ensures that only one segmentation and the according greyvalue image are visible at one time."); - formLayout->addRow("Data node selection mode",m_SelectionModeCheckBox); - formLayout->addRow("Smoothed surface creation", surfaceLayout); m_MainControl->setLayout(formLayout); this->Update(); m_Initializing = false; } QWidget* QmitkMultiLabelSegmentationPreferencePage::GetQtControl() const { return m_MainControl; } bool QmitkMultiLabelSegmentationPreferencePage::PerformOk() { + m_SegmentationPreferencesNode->PutBool("slim view", m_SlimViewCheckBox->isChecked()); m_SegmentationPreferencesNode->PutBool("draw outline", m_RadioOutline->isChecked()); m_SegmentationPreferencesNode->PutDouble("smoothing value", m_SmoothingSpinBox->value()); m_SegmentationPreferencesNode->PutDouble("decimation rate", m_DecimationSpinBox->value()); m_SegmentationPreferencesNode->PutBool("auto selection", m_SelectionModeCheckBox->isChecked()); return true; } void QmitkMultiLabelSegmentationPreferencePage::PerformCancel() { } void QmitkMultiLabelSegmentationPreferencePage::Update() { - //m_EnableSingleEditing->setChecked(m_SegmentationPreferencesNode->GetBool("Single click property editing", true)); + m_SlimViewCheckBox->setChecked(m_SegmentationPreferencesNode->GetBool("slim view", false)); + if (m_SegmentationPreferencesNode->GetBool("draw outline", true) ) { - m_RadioOutline->setChecked( true ); + m_RadioOutline->setChecked(true); } else { - m_RadioOverlay->setChecked( true ); + m_RadioOverlay->setChecked(true); } + m_SelectionModeCheckBox->setChecked(m_SegmentationPreferencesNode->GetBool("auto selection", false)); + if (m_SegmentationPreferencesNode->GetBool("smoothing hint", true)) { m_SmoothingSpinBox->setDisabled(true); } else { m_SmoothingSpinBox->setEnabled(true); } - m_SelectionModeCheckBox->setChecked( m_SegmentationPreferencesNode->GetBool("auto selection", false) ); - m_SmoothingSpinBox->setValue(m_SegmentationPreferencesNode->GetDouble("smoothing value", 0.1)); m_DecimationSpinBox->setValue(m_SegmentationPreferencesNode->GetDouble("decimation rate", 0.5)); } void QmitkMultiLabelSegmentationPreferencePage::OnSmoothingCheckboxChecked(int state) { if (state != Qt::Unchecked) m_SmoothingSpinBox->setDisabled(true); else m_SmoothingSpinBox->setEnabled(true); } diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/QmitkMultiLabelSegmentationPreferencePage.h b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/QmitkMultiLabelSegmentationPreferencePage.h index 6eb6075a4e..ef52b83c76 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/QmitkMultiLabelSegmentationPreferencePage.h +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/QmitkMultiLabelSegmentationPreferencePage.h @@ -1,75 +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 QmitkMultiLabelSegmentationPreferencePage_h_included #define QmitkMultiLabelSegmentationPreferencePage_h_included #include "berryIQtPreferencePage.h" #include "org_mitk_gui_qt_multilabelsegmentation_Export.h" #include class QWidget; class QCheckBox; class QRadioButton; class QDoubleSpinBox; class MITK_QT_SEGMENTATION QmitkMultiLabelSegmentationPreferencePage : public QObject, public berry::IQtPreferencePage { Q_OBJECT Q_INTERFACES(berry::IPreferencePage) public: QmitkMultiLabelSegmentationPreferencePage(); ~QmitkMultiLabelSegmentationPreferencePage() override; void Init(berry::IWorkbench::Pointer workbench) override; void CreateQtControl(QWidget* widget) override; QWidget* GetQtControl() const override; - /// - /// \see IPreferencePage::PerformOk() - /// bool PerformOk() override; - /// - /// \see IPreferencePage::PerformCancel() - /// void PerformCancel() override; - /// - /// \see IPreferencePage::Update() - /// void Update() override; protected slots: void OnSmoothingCheckboxChecked(int); protected: QWidget* m_MainControl; + QCheckBox* m_SlimViewCheckBox; QRadioButton* m_RadioOutline; QRadioButton* m_RadioOverlay; + QCheckBox* m_SelectionModeCheckBox; QDoubleSpinBox* m_SmoothingSpinBox; QDoubleSpinBox* m_DecimationSpinBox; - QCheckBox* m_SelectionModeCheckBox; bool m_Initializing; berry::IPreferences::Pointer m_SegmentationPreferencesNode; }; #endif /* QMITKDATAMANAGERPREFERENCEPAGE_H_ */ 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 7bffe9ff5f..1b1ea78f8e 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationControls.ui +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationControls.ui @@ -1,827 +1,786 @@ QmitkMultiLabelSegmentationControls 0 0 459 844 0 0 0 0 - - - MS Shell Dlg 2 - 8 - 50 - false - false - false - false - - - QmitkSegmentation + QmitkMultiLabelSegmentation 0 0 Data Selection Selected Image 0 40 Create a new segmentation session ... :/multilabelsegmentation/NewSegmentationSession_48x48.png:/multilabelsegmentation/NewSegmentationSession_48x48.png 28 28 N true Segmentation 0 40 + + + + + + 0 + 0 + + + + true + + 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 MS Shell Dlg 2 12 50 false false false false 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 Save LabelSet Preset ... :/org_mitk_icons/icons/awesome/scalable/actions/document-save.svg:/org_mitk_icons/icons/awesome/scalable/actions/document-save.svg 28 28 true Load LabelSet Preset ... :/org_mitk_icons/icons/awesome/scalable/actions/document-open.svg:/org_mitk_icons/icons/awesome/scalable/actions/document-open.svg 28 28 true Qt::Horizontal 0 20 0 34 Show a table with all labels in the current segmentation session >> 28 28 true false Qt::NoArrow 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 - - - MS Shell Dlg 2 - 8 - 50 - false - false - false - false - - 0 0 - - QLayout::SetMinimumSize - - - 0 - - - 0 - - - 0 - - - 0 - 0 0 0 50 - - - MS Shell Dlg 2 - 8 - 50 - false - false - false - false - - 0 0 Qt::Vertical 20 40 m_LabelSetWidget groupBox_DataSelection m_tw2DTools m_gbInterpolation groupBox_Layer groupBox_Labels 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
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 7287bb2cef..0d02206bb5 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.cpp +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.cpp @@ -1,1093 +1,1213 @@ /*============================================================================ 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" +#include "mitkPluginActivator.h" // blueberry -#include #include // mitk -#include "mitkApplicationCursor.h" -#include "mitkLabelSetImage.h" -#include "mitkStatusBar.h" -#include "mitkToolManagerProvider.h" -#include "mitkInteractionEventObserver.h" -#include "mitkPlanePositionManager.h" -#include "mitkPluginActivator.h" -#include "mitkSegTool2D.h" -#include "mitkImageTimeSelector.h" -#include "mitkNodePredicateSubGeometry.h" +#include +#include +#include +#include +#include +#include +#include +#include // Qmitk -#include -#include "QmitkNewSegmentationDialog.h" -#include "QmitkRenderWindow.h" -#include "QmitkSegmentationOrganNamesHandling.cpp" #include "QmitkCreateMultiLabelPresetAction.h" #include "QmitkLoadMultiLabelPresetAction.h" +#include +#include +#include +#include // us #include #include #include #include #include // Qt -#include -#include #include #include #include #include #include const std::string QmitkMultiLabelSegmentationView::VIEW_ID = "org.mitk.views.multilabelsegmentation"; QmitkMultiLabelSegmentationView::QmitkMultiLabelSegmentationView() : m_Parent(nullptr), - m_IRenderWindowPart(nullptr), + m_RenderWindowPart(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"))); - m_SegmentationPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("hidden 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 isImage = mitk::TNodePredicateDataType::New(); + auto isDwi = mitk::NodePredicateDataType::New("DiffusionImage"); + auto isDti = mitk::NodePredicateDataType::New("TensorImage"); + auto isOdf = mitk::NodePredicateDataType::New("OdfImage"); auto isSegment = mitk::NodePredicateDataType::New("Segment"); - mitk::NodePredicateOr::Pointer validImages = mitk::NodePredicateOr::New(); + auto validImages = mitk::NodePredicateOr::New(); validImages->AddPredicate(mitk::NodePredicateAnd::New(isImage, mitk::NodePredicateNot::New(isSegment))); validImages->AddPredicate(isDwi); validImages->AddPredicate(isDti); validImages->AddPredicate(isOdf); + auto isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); + auto isMask = mitk::NodePredicateAnd::New(isBinary, isImage); + + auto validSegmentations = mitk::NodePredicateOr::New(); + validSegmentations->AddPredicate(mitk::TNodePredicateDataType::New()); + validSegmentations->AddPredicate(isMask); + + m_SegmentationPredicate = mitk::NodePredicateAnd::New(); + m_SegmentationPredicate->AddPredicate(validSegmentations); + m_SegmentationPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); + m_SegmentationPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("hidden object"))); + m_ReferencePredicate = mitk::NodePredicateAnd::New(); m_ReferencePredicate->AddPredicate(validImages); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(m_SegmentationPredicate)); - m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(isMask)); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("hidden object"))); } QmitkMultiLabelSegmentationView::~QmitkMultiLabelSegmentationView() { - // Loose LabelSetConnections OnLooseLabelSetConnection(); -} - -void QmitkMultiLabelSegmentationView::CreateQtPartControl(QWidget *parent) -{ - // setup the basic GUI of this view - m_Parent = parent; - - m_Controls.setupUi(parent); - - m_Controls.m_tbSavePreset->setIcon(QmitkStyleManager::ThemeIcon(QStringLiteral(":/org_mitk_icons/icons/awesome/scalable/actions/document-save.svg"))); - m_Controls.m_tbLoadPreset->setIcon(QmitkStyleManager::ThemeIcon(QStringLiteral(":/org_mitk_icons/icons/awesome/scalable/actions/document-open.svg"))); - - // *------------------------ - // * 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_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_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_ReferenceNodeSelector, - &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, - this,&QmitkMultiLabelSegmentationView::OnReferenceSelectionChanged); - connect(m_Controls.m_WorkingNodeSelector, - &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, - this,&QmitkMultiLabelSegmentationView::OnSegmentationSelectionChanged); - - // *------------------------ - // * ToolManager - // *------------------------ - - m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(mitk::ToolManagerProvider::MULTILABEL_SEGMENTATION); - m_ToolManager->SetDataStorage(*(this->GetDataStorage())); - m_ToolManager->InitializeTools(); - m_Controls.m_ManualToolSelectionBox2D->SetToolManager(*m_ToolManager); - 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(); - m_Controls.m_gbInterpolation->hide(); // See T27436 - - QString segTools2D = tr("Add Subtract Fill Erase Paint Wipe 'Region Growing' FastMarching2D '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) + // removing all observers + for (NodeTagMapType::iterator dataIter = m_WorkingDataObserverTags.begin(); dataIter != m_WorkingDataObserverTags.end(); ++dataIter) { - 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())); - } + (*dataIter).first->GetProperty("visible")->RemoveObserver((*dataIter).second); } + m_WorkingDataObserverTags.clear(); - // *------------------------ - // * 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) - // *------------------------* + mitk::RenderingManager::GetInstance()->RemoveObserver(m_RenderingManagerObserverTag); - connect(m_Controls.m_pbNewLabel, SIGNAL(clicked()), this, SLOT(OnNewLabel())); - connect(m_Controls.m_tbSavePreset, SIGNAL(clicked()), this, SLOT(OnSavePreset())); - connect(m_Controls.m_tbLoadPreset, SIGNAL(clicked()), this, SLOT(OnLoadPreset())); - connect(m_Controls.m_pbNewSegmentationSession, SIGNAL(clicked()), this, SLOT(OnNewSegmentationSession())); - connect(m_Controls.m_pbShowLabelTable, SIGNAL(toggled(bool)), this, SLOT(OnShowLabelTable(bool))); - - // *------------------------* - // * Connect LabelSetWidget - // *------------------------* + m_ToolManager->SetReferenceData(nullptr); + m_ToolManager->SetWorkingData(nullptr); +} - 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())); +/**********************************************************************/ +/* private Q_SLOTS */ +/**********************************************************************/ +void QmitkMultiLabelSegmentationView::OnReferenceSelectionChanged(QList nodes) +{ + m_ToolManager->ActivateTool(-1); - // *------------------------* - // * DATA SLECTION WIDGET - // *------------------------* - m_IRenderWindowPart = this->GetRenderWindowPart(); - if (m_IRenderWindowPart) + if (nodes.empty()) { - 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_WorkingNodeSelector->SetNodePredicate(m_SegmentationPredicate); + m_ReferenceNode = nullptr; + m_ToolManager->SetReferenceData(m_ReferenceNode); + this->UpdateGUI(); + return; } - // 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_ReferenceNode = nodes.first(); + m_ToolManager->SetReferenceData(m_ReferenceNode); - m_Controls.m_pbNewLabel->setEnabled(false); - m_Controls.m_btLockExterior->setEnabled(false); - m_Controls.m_tbSavePreset->setEnabled(false); - m_Controls.m_tbLoadPreset->setEnabled(false); - m_Controls.m_pbShowLabelTable->setEnabled(false); + if (m_ReferenceNode.IsNotNull()) + { + // set a predicate such that a segmentation fits the selected reference image geometry + auto segPredicate = mitk::NodePredicateAnd::New(m_SegmentationPredicate.GetPointer(), + mitk::NodePredicateSubGeometry::New(m_ReferenceNode->GetData()->GetGeometry())); - // Make sure the GUI notices if appropriate data is already present on creation - m_Controls.m_ReferenceNodeSelector->SetAutoSelectNewNodes(true); - m_Controls.m_WorkingNodeSelector->SetAutoSelectNewNodes(true); -} + m_Controls.m_WorkingNodeSelector->SetNodePredicate(segPredicate); -void QmitkMultiLabelSegmentationView::Activated() -{ - m_ToolManager->SetReferenceData(m_Controls.m_ReferenceNodeSelector->GetSelectedNode()); - m_ToolManager->SetWorkingData(m_Controls.m_WorkingNodeSelector->GetSelectedNode()); -} + if (m_AutoSelectionEnabled) + { + // hide all image nodes to later show only the automatically selected ones + mitk::DataStorage::SetOfObjects::ConstPointer imageNodes = + this->GetDataStorage()->GetSubset(m_ReferencePredicate); + for (mitk::DataStorage::SetOfObjects::const_iterator iter = imageNodes->begin(); iter != imageNodes->end(); ++iter) + { + (*iter)->SetVisibility(false); + } + } + m_ReferenceNode->SetVisibility(true); + } -void QmitkMultiLabelSegmentationView::Deactivated() -{ - // Not yet implemented + this->UpdateGUI(); } -void QmitkMultiLabelSegmentationView::Visible() +void QmitkMultiLabelSegmentationView::OnSegmentationSelectionChanged(QList nodes) { - // Not yet implemented -} + m_ToolManager->ActivateTool(-1); -void QmitkMultiLabelSegmentationView::Hidden() -{ - // Not yet implemented -} + if (nodes.empty()) + { + m_WorkingNode = nullptr; + m_ToolManager->SetWorkingData(m_WorkingNode); + this->UpdateGUI(); + return; + } -int QmitkMultiLabelSegmentationView::GetSizeFlags(bool width) -{ - if (!width) + if (m_ReferenceNode.IsNull()) { - return berry::Constants::MIN | berry::Constants::MAX | berry::Constants::FILL; + this->UpdateGUI(); + return; } - else + + mitk::Image::ConstPointer referenceImage = dynamic_cast(m_ReferenceNode->GetData()); + if (referenceImage.IsNull()) { - return 0; + this->UpdateGUI(); + return; } -} -int QmitkMultiLabelSegmentationView::ComputePreferredSize(bool width, - int /*availableParallel*/, - int /*availablePerpendicular*/, - int preferredResult) -{ - if (width == false) + if (m_WorkingNode.IsNotNull()) { - return 100; + this->OnLooseLabelSetConnection(); } - else + + m_WorkingNode = nodes.first(); + m_ToolManager->SetWorkingData(m_WorkingNode); + + if (m_WorkingNode.IsNotNull()) { - return preferredResult; + if (m_AutoSelectionEnabled) + { + // hide all segmentation nodes to later show only the automatically selected ones + mitk::DataStorage::SetOfObjects::ConstPointer segmentationNodes = + this->GetDataStorage()->GetSubset(m_SegmentationPredicate); + for (mitk::DataStorage::SetOfObjects::const_iterator iter = segmentationNodes->begin(); iter != segmentationNodes->end(); ++iter) + { + (*iter)->SetVisibility(false); + } + } + m_WorkingNode->SetVisibility(true); + + this->OnEstablishLabelSetConnection(); + m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); + + this->InitializeRenderWindows(referenceImage->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, false); } + + this->UpdateGUI(); } -/************************************************************************/ -/* 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); + auto workingImage = dynamic_cast(workingNode->GetData()); + if (nullptr == workingImage) + { + return; + } 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); if (m_ReferenceNode.IsNull()) { QMessageBox::information( - m_Parent, "New Segmentation Session", "Please load and select a patient image before starting some action."); + m_Parent, "New Segmentation", "Please load and select an image before starting some action."); return; } mitk::Image::ConstPointer referenceImage = dynamic_cast(m_ReferenceNode->GetData()); if (referenceImage.IsNull()) { QMessageBox::information( - m_Parent, "New Segmentation Session", "Reference data needs to be an image in order to create a new segmentation."); + m_Parent, "New segmentation", "Reference data needs to be an image in order to create a new segmentation."); return; } 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."); + m_Parent, "New segmentation", "Please load and select a multilabel segmentation 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."); + m_Parent, "New segmentation", "Please load and select a multilabel segmentation before starting some action."); return; } - QmitkNewSegmentationDialog* dialog = new QmitkNewSegmentationDialog(m_Parent); - dialog->SetSuggestionList(mitk::OrganNamesHandling::GetDefaultOrganColorString()); + // ask about the name and organ type of the new segmentation + auto dialog = new QmitkNewSegmentationDialog(m_Parent); + QStringList organColors = mitk::OrganNamesHandling::GetDefaultOrganColorString(); + dialog->SetSuggestionList(organColors); dialog->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(); + UpdateGUI(); m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); this->InitializeRenderWindows(referenceImage->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, false); } void QmitkMultiLabelSegmentationView::OnSavePreset() { QmitkAbstractNodeSelectionWidget::NodeList nodes; nodes.append(m_WorkingNode); QmitkCreateMultiLabelPresetAction action; action.Run(nodes); } void QmitkMultiLabelSegmentationView::OnLoadPreset() { QmitkAbstractNodeSelectionWidget::NodeList nodes; nodes.append(m_WorkingNode); QmitkLoadMultiLabelPresetAction action; action.Run(nodes); } 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_ReferenceNodeSelector->GetSelectedNode(); + mitk::DataNode::Pointer referenceNode = m_ToolManager->GetReferenceData(0); + if (referenceNode.IsNull()) + { + MITK_ERROR << "'Create new segmentation' button should never be clickable unless a reference image is selected."; + return; + } - if (!referenceNode) + mitk::Image::ConstPointer referenceImage = dynamic_cast(referenceNode->GetData()); + if (referenceImage.IsNull()) { QMessageBox::information( - m_Parent, "New Segmentation Session", "Please load and select a patient image before starting some action."); + m_Parent, "New segmentation", "Please load and select an image before starting some action."); return; } - m_ToolManager->ActivateTool(-1); - - mitk::Image::ConstPointer referenceImage = dynamic_cast(referenceNode->GetData()); - assert(referenceImage); + if (referenceImage->GetDimension() <= 1) + { + QMessageBox::information(m_Parent, "New segmentation", "Segmentation is currently not supported for 2D images"); + return; + } const auto currentTimePoint = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint(); unsigned int imageTimeStep = 0; if (referenceImage->GetTimeGeometry()->IsValidTimePoint(currentTimePoint)) { imageTimeStep = referenceImage->GetTimeGeometry()->TimePointToTimeStep(currentTimePoint); } auto segTemplateImage = referenceImage; if (referenceImage->GetDimension() > 3) { - auto result = QMessageBox::question(m_Parent, tr("Create a static or dynamic segmentation?"), tr("The patient image has multiple time steps.\n\nDo you want to create a static segmentation that is identical for all time steps or do you want to create a dynamic segmentation to segment individual time steps?"), tr("Create static segmentation"), tr("Create dynamic segmentation"), QString(), 0, 0); + auto result = QMessageBox::question(m_Parent, + tr("Create a static or dynamic segmentation?"), + tr("The selected image has multiple time steps.\n\nDo you want to create a static " + "segmentation that is identical for all time steps or do you want to create a " + "dynamic segmentation to segment individual time steps?"), + tr("Create static segmentation"), tr("Create dynamic segmentation"), + QString(), 0, 0); if (result == 0) { auto selector = mitk::ImageTimeSelector::New(); selector->SetInput(referenceImage); selector->SetTimeNr(0); selector->Update(); const auto refTimeGeometry = referenceImage->GetTimeGeometry(); auto newTimeGeometry = mitk::ProportionalTimeGeometry::New(); newTimeGeometry->SetFirstTimePoint(refTimeGeometry->GetMinimumTimePoint()); newTimeGeometry->SetStepDuration(refTimeGeometry->GetMaximumTimePoint() - refTimeGeometry->GetMinimumTimePoint()); mitk::Image::Pointer newImage = selector->GetOutput(); newTimeGeometry->SetTimeStepGeometry(referenceImage->GetGeometry(imageTimeStep), 0); newImage->SetTimeGeometry(newTimeGeometry); segTemplateImage = newImage; } } QString newName = QString::fromStdString(referenceNode->GetName()); newName.append("-labels"); bool ok = false; - newName = QInputDialog::getText(m_Parent, "New Segmentation Session", "New name:", QLineEdit::Normal, newName, &ok); + newName = QInputDialog::getText(m_Parent, "New segmentation", "New name:", QLineEdit::Normal, newName, &ok); if (!ok) { return; } + if (newName.isEmpty()) + { + newName = "Unnamed"; + } + this->WaitCursorOn(); mitk::LabelSetImage::Pointer workingImage = mitk::LabelSetImage::New(); try { workingImage->Initialize(segTemplateImage); } 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"); + QMessageBox::information(m_Parent, tr("New segmentation"), tr("Could not create a new segmentation.\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); - } + this->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); + if (m_RenderWindowPart) + m_RenderWindowPart->SetSelectedPosition(pos); } void QmitkMultiLabelSegmentationView::OnResetView() { - if (m_IRenderWindowPart) - m_IRenderWindowPart->ForceImmediateUpdate(); + if (m_RenderWindowPart) + m_RenderWindowPart->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); + auto workingImage = dynamic_cast(workingNode->GetData()); + if (nullptr == workingImage) + { + return; + } 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); + auto workingImage = dynamic_cast(workingNode->GetData()); + if (nullptr == workingImage) + { + return; + } 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(); + UpdateGUI(); 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); + + auto workingImage = dynamic_cast(workingNode->GetData()); + if (nullptr == workingImage) + { + return; + } 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); + + auto workingImage = dynamic_cast(workingNode->GetData()); + if (nullptr == workingImage) + { + return; + } 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); + auto workingImage = dynamic_cast(workingNode->GetData()); + if (nullptr == workingImage) + { + return; + } this->WaitCursorOn(); workingImage->SetActiveLayer(layer); this->WaitCursorOff(); - UpdateControls(); + UpdateGUI(); 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); + auto workingImage = dynamic_cast(workingNode->GetData()); + if (nullptr == workingImage) + { + return; + } workingImage->GetLabel(0)->SetLocked(checked); } -void QmitkMultiLabelSegmentationView::OnReferenceSelectionChanged(QList /*nodes*/) +void QmitkMultiLabelSegmentationView::OnInterpolationSelectionChanged(int index) { - m_ToolManager->ActivateTool(-1); - - auto refNode = m_Controls.m_ReferenceNodeSelector->GetSelectedNode(); - m_ReferenceNode = refNode; - m_ToolManager->SetReferenceData(m_ReferenceNode); - - if (m_ReferenceNode.IsNotNull()) + if (index == 1) { - auto segPredicate = mitk::NodePredicateAnd::New(m_SegmentationPredicate.GetPointer(), mitk::NodePredicateSubGeometry::New(refNode->GetData()->GetGeometry())); + 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(); + } +} - m_Controls.m_WorkingNodeSelector->SetNodePredicate(segPredicate); +/**********************************************************************/ +/* private */ +/**********************************************************************/ +void QmitkMultiLabelSegmentationView::CreateQtPartControl(QWidget *parent) +{ + m_Parent = parent; - if (m_AutoSelectionEnabled) + m_Controls.setupUi(parent); + + m_Controls.m_tbSavePreset->setIcon(QmitkStyleManager::ThemeIcon(QStringLiteral(":/org_mitk_icons/icons/awesome/scalable/actions/document-save.svg"))); + m_Controls.m_tbLoadPreset->setIcon(QmitkStyleManager::ThemeIcon(QStringLiteral(":/org_mitk_icons/icons/awesome/scalable/actions/document-open.svg"))); + + // *------------------------ + // * 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_ReferenceNodeSelector->SetDataStorage(this->GetDataStorage()); + m_Controls.m_ReferenceNodeSelector->SetNodePredicate(m_ReferencePredicate); + 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_WorkingNodeSelector->SetDataStorage(this->GetDataStorage()); + m_Controls.m_WorkingNodeSelector->SetNodePredicate(m_SegmentationPredicate); + 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_ReferenceNodeSelector, + &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, + this, &QmitkMultiLabelSegmentationView::OnReferenceSelectionChanged); + connect(m_Controls.m_WorkingNodeSelector, + &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, + this, &QmitkMultiLabelSegmentationView::OnSegmentationSelectionChanged); + + // *------------------------ + // * ToolManager + // *------------------------ + + m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(mitk::ToolManagerProvider::MULTILABEL_SEGMENTATION); + m_ToolManager->SetDataStorage(*(this->GetDataStorage())); + m_ToolManager->InitializeTools(); + m_Controls.m_ManualToolSelectionBox2D->SetToolManager(*m_ToolManager); + 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, QOverload::of(&QComboBox::activated), this, &QmitkMultiLabelSegmentationView::OnInterpolationSelectionChanged); + + m_Controls.m_cbInterpolation->setCurrentIndex(0); + m_Controls.m_swInterpolation->hide(); + + m_Controls.m_gbInterpolation->hide(); // See T27436 + + QString segTools2D = tr("Add Subtract Fill Erase Paint Wipe 'Region Growing' 'Live Wire'"); + QString segTools3D = tr("Threshold"); + + 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)) { - // 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); - } + segTools2D.append(QString(" '%1'").arg(tool->GetName())); + } + else if (std::regex_search(tool->GetNameOfClass(), extSegTool3DRegEx)) + { + segTools3D.append(QString(" '%1'").arg(tool->GetName())); } - m_ReferenceNode->SetVisibility(true); } - UpdateControls(); -} + // *------------------------ + // * ToolSelection 2D + // *------------------------ -void QmitkMultiLabelSegmentationView::OnSegmentationSelectionChanged(QList /*nodes*/) -{ - m_ToolManager->ActivateTool(-1); + 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, &QmitkToolSelectionBox::ToolSelected, + this, &QmitkMultiLabelSegmentationView::OnManualTool2DSelected); - if (m_ReferenceNode.IsNull()) - { - QMessageBox::information( - m_Parent, "Selected segmentation changed", "Please load and select a patient image before starting some action."); - return; - } + // *------------------------ + // * ToolSelection 3D + // *------------------------ - mitk::Image::ConstPointer referenceImage = dynamic_cast(m_ReferenceNode->GetData()); - if (referenceImage.IsNull()) - { - QMessageBox::information( - m_Parent, "Selected segmentation changed", "Reference data needs to be an image in order to create a new segmentation."); - return; - } + 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(3); + m_Controls.m_ManualToolSelectionBox3D->SetEnabledMode( + QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); - if (m_WorkingNode.IsNotNull()) - OnLooseLabelSetConnection(); + // *------------------------* + // * Connect Buttons + // *------------------------* - m_WorkingNode = m_Controls.m_WorkingNodeSelector->GetSelectedNode(); - m_ToolManager->SetWorkingData(m_WorkingNode); - if (m_WorkingNode.IsNotNull()) - { - OnEstablishLabelSetConnection(); + connect(m_Controls.m_pbNewLabel, &QToolButton::clicked, this, &QmitkMultiLabelSegmentationView::OnNewLabel); + connect(m_Controls.m_tbSavePreset, &QToolButton::clicked, this, &QmitkMultiLabelSegmentationView::OnSavePreset); + connect(m_Controls.m_tbLoadPreset, &QToolButton::clicked, this, &QmitkMultiLabelSegmentationView::OnLoadPreset); + connect(m_Controls.m_pbNewSegmentationSession, &QToolButton::clicked, this, &QmitkMultiLabelSegmentationView::OnNewSegmentationSession); + connect(m_Controls.m_pbShowLabelTable, &QToolButton::toggled, this, &QmitkMultiLabelSegmentationView::OnShowLabelTable); - if (m_AutoSelectionEnabled) - { - // 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); + // *------------------------* + // * Connect LabelSetWidget + // *------------------------* + + connect(m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::goToLabel, + this, &QmitkMultiLabelSegmentationView::OnGoToLabel); + connect(m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::resetView, + this, &QmitkMultiLabelSegmentationView::OnResetView); + + // *------------------------* + // * DATA SLECTION WIDGET + // *------------------------* + + connect(m_Controls.m_btAddLayer, &QToolButton::clicked, this, &QmitkMultiLabelSegmentationView::OnAddLayer); + connect(m_Controls.m_btDeleteLayer, &QToolButton::clicked, this, &QmitkMultiLabelSegmentationView::OnDeleteLayer); + connect(m_Controls.m_btPreviousLayer, &QToolButton::clicked, this, &QmitkMultiLabelSegmentationView::OnPreviousLayer); + connect(m_Controls.m_btNextLayer, &QToolButton::clicked, this, &QmitkMultiLabelSegmentationView::OnNextLayer); + connect(m_Controls.m_btLockExterior, &QToolButton::toggled, this, &QmitkMultiLabelSegmentationView::OnLockExteriorToggled); + connect(m_Controls.m_cbActiveLayer, QOverload::of(&QComboBox::currentIndexChanged), this, &QmitkMultiLabelSegmentationView::OnChangeLayer); + + 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_tbSavePreset->setEnabled(false); + m_Controls.m_tbLoadPreset->setEnabled(false); + m_Controls.m_pbShowLabelTable->setEnabled(false); + + // set callback function for already existing segmentation nodes + mitk::DataStorage::SetOfObjects::ConstPointer allSegmentations = GetDataStorage()->GetSubset(m_SegmentationPredicate); + for (mitk::DataStorage::SetOfObjects::const_iterator iter = allSegmentations->begin(); iter != allSegmentations->end(); ++iter) + { + mitk::DataNode* node = *iter; + auto command = itk::SimpleMemberCommand::New(); + command->SetCallbackFunction(this, &QmitkMultiLabelSegmentationView::ValidateSelectionInput); + m_WorkingDataObserverTags.insert(std::pair( + node, node->GetProperty("visible")->AddObserver(itk::ModifiedEvent(), command))); } - UpdateControls(); - if (m_WorkingNode.IsNotNull()) + auto command = itk::SimpleMemberCommand::New(); + command->SetCallbackFunction(this, &QmitkMultiLabelSegmentationView::ValidateSelectionInput); + m_RenderingManagerObserverTag = + mitk::RenderingManager::GetInstance()->AddObserver(mitk::RenderingManagerViewsInitializedEvent(), command); + + m_RenderWindowPart = this->GetRenderWindowPart(); + if (nullptr != m_RenderWindowPart) { - m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); - this->InitializeRenderWindows(referenceImage->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, false); + this->RenderWindowPartActivated(m_RenderWindowPart); } + + // Make sure the GUI notices if appropriate data is already present on creation. + // Should be done last, if everything else is configured because it triggers the autoselection of data. + m_Controls.m_ReferenceNodeSelector->SetAutoSelectNewNodes(true); + m_Controls.m_WorkingNodeSelector->SetAutoSelectNewNodes(true); + + this->UpdateGUI(); } -void QmitkMultiLabelSegmentationView::OnInterpolationSelectionChanged(int index) +void QmitkMultiLabelSegmentationView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { - if (index == 1) + if (m_RenderWindowPart != renderWindowPart) { - m_Controls.m_SurfaceBasedInterpolatorWidget->m_Controls.m_btStart->setChecked(false);//OnToggleWidgetActivation(false); - m_Controls.m_swInterpolation->setCurrentIndex(0); - m_Controls.m_swInterpolation->show(); + m_RenderWindowPart = renderWindowPart; } - else if (index == 2) + + if (m_Parent) { - m_Controls.m_SliceBasedInterpolatorWidget->m_Controls.m_btStart->setChecked(false); - m_Controls.m_swInterpolation->setCurrentIndex(1); - m_Controls.m_swInterpolation->show(); + m_Parent->setEnabled(true); } - else + + // tell the interpolation about tool manager, data storage and render window part + QList controllers; + controllers.push_back(m_RenderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()); + controllers.push_back(m_RenderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()); + controllers.push_back(m_RenderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()); + m_Controls.m_SliceBasedInterpolatorWidget->SetSliceNavigationControllers(controllers); +} + +void QmitkMultiLabelSegmentationView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* /*renderWindowPart*/) +{ + m_RenderWindowPart = nullptr; + if (m_Parent) { - 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(); + m_Parent->setEnabled(false); } } -/************************************************************************/ -/* protected */ -/************************************************************************/ void QmitkMultiLabelSegmentationView::OnPreferencesChanged(const berry::IBerryPreferences* prefs) { - m_AutoSelectionEnabled = prefs->GetBool("auto selection", false); + bool slimView = prefs->GetBool("slim view", false); + m_Controls.m_ManualToolSelectionBox2D->SetShowNames(!slimView); + m_Controls.m_ManualToolSelectionBox3D->SetShowNames(!slimView); - mitk::BoolProperty::Pointer drawOutline = mitk::BoolProperty::New(prefs->GetBool("draw outline", true)); - 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); + m_AutoSelectionEnabled = prefs->GetBool("auto selection", false); - 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)); - // 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)); - // force render window update to show outline - segmentation->GetData()->Modified(); - } - } - } + this->ApplyDisplayOptions(); } -void QmitkMultiLabelSegmentationView::NodeRemoved(const mitk::DataNode *node) +void QmitkMultiLabelSegmentationView::NodeAdded(const mitk::DataNode* node) { - bool isHelperObject(false); - node->GetBoolProperty("helper object", isHelperObject); - if (isHelperObject) + if (!m_SegmentationPredicate->CheckNode(node)) { return; } - if (m_ReferenceNode.IsNotNull() && dynamic_cast(node->GetData())) + auto command = itk::SimpleMemberCommand::New(); + command->SetCallbackFunction(this, &QmitkMultiLabelSegmentationView::ValidateSelectionInput); + m_WorkingDataObserverTags.insert(std::pair( + const_cast(node), node->GetProperty("visible")->AddObserver(itk::ModifiedEvent(), command))); + + ApplyDisplayOptions(const_cast(node)); +} + +void QmitkMultiLabelSegmentationView::NodeRemoved(const mitk::DataNode* node) +{ + if (m_SegmentationPredicate->CheckNode(node)) { // remove all possible contour markers of the segmentation mitk::DataStorage::SetOfObjects::ConstPointer allContourMarkers = this->GetDataStorage()->GetDerivations( node, mitk::NodePredicateProperty::New("isContourMarker", mitk::BoolProperty::New(true))); ctkPluginContext *context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService *service = context->getService(ppmRef); for (mitk::DataStorage::SetOfObjects::ConstIterator it = allContourMarkers->Begin(); it != allContourMarkers->End(); ++it) { std::string nodeName = node->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int id = atof(nodeName.substr(t + 1).c_str()) - 1; service->RemovePlanePosition(id); this->GetDataStorage()->Remove(it->Value()); } context->ungetService(ppmRef); service = nullptr; } + + mitk::DataNode* tempNode = const_cast(node); + //Remove observer if one was registered + auto finding = m_WorkingDataObserverTags.find(tempNode); + if (finding != m_WorkingDataObserverTags.end()) + { + node->GetProperty("visible")->RemoveObserver(m_WorkingDataObserverTags[tempNode]); + m_WorkingDataObserverTags.erase(tempNode); + } +} + +void QmitkMultiLabelSegmentationView::ApplyDisplayOptions() +{ + if (!m_Parent) + { + return; + } + + mitk::DataNode::Pointer workingData = m_ToolManager->GetWorkingData(0); + mitk::DataStorage::SetOfObjects::ConstPointer allImages = this->GetDataStorage()->GetSubset(m_SegmentationPredicate); + for (mitk::DataStorage::SetOfObjects::const_iterator iter = allImages->begin(); iter != allImages->end(); ++iter) + { + this->ApplyDisplayOptions(*iter); + } + + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +} + +void QmitkMultiLabelSegmentationView::ApplyDisplayOptions(mitk::DataNode* node) +{ + if (nullptr == node) + { + return; + } + + auto drawOutline = mitk::BoolProperty::New(GetPreferences()->GetBool("draw outline", true)); + auto labelSetImage = dynamic_cast(node->GetData()); + if (nullptr != labelSetImage) + { + // node is a multi label segmentation + node->SetProperty("labelset.contour.active", drawOutline); + // force render window update to show outline + node->GetData()->Modified(); + } + else if (nullptr != node->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; + node->GetBoolProperty("binary", isBinary); + if (isBinary) + { + node->SetProperty("outline binary", drawOutline); + node->SetProperty("outline width", mitk::FloatProperty::New(2.0)); + // force render window update to show outline + node->GetData()->Modified(); + } + } } void QmitkMultiLabelSegmentationView::OnEstablishLabelSetConnection() { if (m_WorkingNode.IsNull()) { return; } - mitk::LabelSetImage *workingImage = dynamic_cast(m_WorkingNode->GetData()); - assert(workingImage); + + auto workingImage = dynamic_cast(m_WorkingNode->GetData()); + if (nullptr == workingImage) + { + // node is a "single label" / "binary" image --> no label set + return; + } 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); // Removed in T27851 to have a chance to react to AfterChangeLayerEvent. Did it brake something? // workingImage->BeforeChangeLayerEvent += mitk::MessageDelegate( // this, &QmitkMultiLabelSegmentationView::OnLooseLabelSetConnection); workingImage->AfterChangeLayerEvent += mitk::MessageDelegate( - this, &QmitkMultiLabelSegmentationView::UpdateControls); + this, &QmitkMultiLabelSegmentationView::UpdateGUI); } void QmitkMultiLabelSegmentationView::OnLooseLabelSetConnection() { if (m_WorkingNode.IsNull()) + { return; + } - auto* workingImage = dynamic_cast(m_WorkingNode->GetData()); - + auto workingImage = dynamic_cast(m_WorkingNode->GetData()); if (nullptr == workingImage) - return; // data (type) was changed in-place, e.g. LabelSetImage -> Image + { + // data (type) was changed in-place, e.g. LabelSetImage -> (binary) image + return; + } // 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); // Removed in T27851 to have a chance to react to AfterChangeLayerEvent. Did it brake something? // workingImage->BeforeChangeLayerEvent -= mitk::MessageDelegate( // this, &QmitkMultiLabelSegmentationView::OnLooseLabelSetConnection); workingImage->AfterChangeLayerEvent -= mitk::MessageDelegate( - this, &QmitkMultiLabelSegmentationView::UpdateControls); + this, &QmitkMultiLabelSegmentationView::UpdateGUI); } -void QmitkMultiLabelSegmentationView::SetFocus() +void QmitkMultiLabelSegmentationView::ResetMouseCursor() { + if (m_MouseCursorSet) + { + mitk::ApplicationCursor::GetInstance()->PopCursor(); + m_MouseCursorSet = false; + } } -void QmitkMultiLabelSegmentationView::UpdateControls() +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::UpdateGUI() { mitk::DataNode* referenceNode = m_ToolManager->GetReferenceData(0); bool hasReferenceNode = referenceNode != nullptr; mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); - bool hasValidWorkingNode = workingNode != nullptr; + bool hasWorkingNode = workingNode != nullptr; + m_Controls.m_pbNewSegmentationSession->setEnabled(false); 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_tbSavePreset->setEnabled(false); m_Controls.m_tbLoadPreset->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 (hasReferenceNode) + { + m_Controls.m_pbNewSegmentationSession->setEnabled(true); + } - if (hasValidWorkingNode) + if (hasWorkingNode) { - // TODO adapt tool manager so that this check is done there, e.g. convenience function + m_Controls.m_pbNewLabel->setEnabled(true); + m_Controls.m_btLockExterior->setEnabled(true); + m_Controls.m_tbSavePreset->setEnabled(true); + m_Controls.m_tbLoadPreset->setEnabled(true); + m_Controls.m_pbShowLabelTable->setEnabled(true); + m_Controls.m_LabelSetWidget->setEnabled(true); + m_Controls.m_btAddLayer->setEnabled(true); + + m_Controls.m_cbActiveLayer->blockSignals(true); + m_Controls.m_cbActiveLayer->clear(); + mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); - hasValidWorkingNode = workingImage != nullptr; - if (hasValidWorkingNode) + if (nullptr != workingImage) { - m_Controls.m_pbNewLabel->setEnabled(true); - m_Controls.m_btLockExterior->setEnabled(true); - m_Controls.m_tbSavePreset->setEnabled(true); - m_Controls.m_tbLoadPreset->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)); } + + int activeLayer = workingImage->GetActiveLayer(); 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) + if (hasWorkingNode && hasReferenceNode) { + m_Controls.m_gbInterpolation->setEnabled(true); + m_Controls.m_SliceBasedInterpolatorWidget->setEnabled(true); + m_Controls.m_SurfaceBasedInterpolatorWidget->setEnabled(true); + int layer = -1; referenceNode->GetIntProperty("layer", layer); workingNode->SetIntProperty("layer", layer + 1); } - this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_ALL); + this->ValidateSelectionInput(); } -void QmitkMultiLabelSegmentationView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) +void QmitkMultiLabelSegmentationView::ValidateSelectionInput() { - if (m_IRenderWindowPart != renderWindowPart) - { - m_IRenderWindowPart = renderWindowPart; - m_Parent->setEnabled(true); + this->UpdateWarningLabel(""); - 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); - } -} + // the argument is actually not used + // enable status depends on the tool manager selection + m_Controls.m_ManualToolSelectionBox2D->setEnabled(false); + m_Controls.m_ManualToolSelectionBox3D->setEnabled(false); -void QmitkMultiLabelSegmentationView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* /*renderWindowPart*/) -{ - m_ToolManager->ActivateTool(-1); - m_IRenderWindowPart = nullptr; - m_Parent->setEnabled(false); -} + mitk::DataNode* referenceNode = m_Controls.m_ReferenceNodeSelector->GetSelectedNode(); + mitk::DataNode* workingNode = m_Controls.m_WorkingNodeSelector->GetSelectedNode(); -void QmitkMultiLabelSegmentationView::ResetMouseCursor() -{ - if (m_MouseCursorSet) + if (nullptr == referenceNode) { - mitk::ApplicationCursor::GetInstance()->PopCursor(); - m_MouseCursorSet = false; + return; } -} -void QmitkMultiLabelSegmentationView::SetMouseCursor(const us::ModuleResource resource, int hotspotX, int hotspotY) -{ - // Remove previously set mouse cursor - if (m_MouseCursorSet) - this->ResetMouseCursor(); + if (nullptr == workingNode) + { + return; + } - if (resource) + mitk::IRenderWindowPart* renderWindowPart = this->GetRenderWindowPart(); + auto referenceNodeIsVisible = renderWindowPart && + referenceNode->IsVisible(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer()); + if (!referenceNodeIsVisible) { - us::ModuleResourceStream cursor(resource, std::ios::binary); - mitk::ApplicationCursor::GetInstance()->PushCursor(cursor, hotspotX, hotspotY); - m_MouseCursorSet = true; + this->UpdateWarningLabel(tr("The selected reference image is currently not visible!")); + return; } -} -void QmitkMultiLabelSegmentationView::InitializeListeners() -{ - if (m_Interactor.IsNull()) + auto workingNodeIsVisible = renderWindowPart && + workingNode->IsVisible(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer()); + if (!workingNodeIsVisible) { - 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(); - } + this->UpdateWarningLabel(tr("The selected segmentation is currently not visible!")); + return; + } - m_Interactor = mitk::SegmentationInteractor::New(); - if (!m_Interactor->LoadStateMachine("SegmentationInteraction.xml", module)) + /* + * Here we check whether the geometry of the selected segmentation image is aligned with the worldgeometry. + * At the moment it is not supported to use a geometry different from the selected image for reslicing. + * For further information see Bug 16063 + */ + const mitk::BaseGeometry *workingNodeGeo = workingNode->GetData()->GetGeometry(); + const mitk::BaseGeometry *worldGeo = + renderWindowPart->GetQmitkRenderWindow("3d")->GetSliceNavigationController()->GetCurrentGeometry3D(); + if (nullptr != workingNodeGeo && nullptr != worldGeo) + { + if (mitk::Equal(*workingNodeGeo->GetBoundingBox(), *worldGeo->GetBoundingBox(), mitk::eps, true)) { - MITK_WARN << "Error loading state machine"; + m_ToolManager->SetReferenceData(referenceNode); + m_ToolManager->SetWorkingData(workingNode); + m_Controls.m_ManualToolSelectionBox2D->setEnabled(true); + m_Controls.m_ManualToolSelectionBox3D->setEnabled(true); + return; } + } - if (!m_Interactor->SetEventConfig("ConfigSegmentation.xml", module)) - { - MITK_WARN << "Error loading state machine configuration"; - } + m_ToolManager->SetReferenceData(referenceNode); + m_ToolManager->SetWorkingData(nullptr); + this->UpdateWarningLabel(tr("Please perform a reinit on the segmentation image!")); +} - // Register as listener via micro services - us::ServiceProperties props; - props["name"] = std::string("SegmentationInteraction"); - m_ServiceRegistration = - us::GetModuleContext()->RegisterService(m_Interactor.GetPointer(), props); +void QmitkMultiLabelSegmentationView::UpdateWarningLabel(QString text) +{ + if (text.size() == 0) + { + m_Controls.lblSegmentationWarnings->hide(); + } + else + { + m_Controls.lblSegmentationWarnings->show(); } + m_Controls.lblSegmentationWarnings->setText("" + text + ""); } 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 afef29785d..e7979bab60 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.h +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.h @@ -1,175 +1,171 @@ /*============================================================================ 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 +#ifndef QMITKMULTILABELSEGMENTATIONVIEW_H +#define QMITKMULTILABELSEGMENTATIONVIEW_H #include "ui_QmitkMultiLabelSegmentationControls.h" -// berry -#include +#include +#include -class QmitkRenderWindow; +#include /** - * \ingroup ToolManagerEtAl - * \ingroup org_mitk_gui_qt_multilabelsegmentation_internal - */ -class QmitkMultiLabelSegmentationView : public QmitkAbstractView, public mitk::ILifecycleAwarePart +* @brief The multilabel segmentation view provides a set of tool to use different segmentation +* algorithms. +* It provides two selection widgets to load an image node and a segmentation node +* on which to perform the segmentation. Creating new segmentation nodes is also possible. +* The available segmentation tools are grouped into "2D"- and "3D"-tools. +* +* Most segmentation tools / algorithms need some kind of user interaction, where the +* user is asked to draw something in the image display or set some seed points / start values. +* The tools also often provide additional propeties so that a user can modify the +* algorithm's behavior. +* +* In contrast to the basic QmitkSegmentationView this class additionally provides options to +* work with different layers (create new layers, switch between layers). +* Moreover, a multilabel widget displays all the existing labels of a multilabel segmentation +* for the currently active layer. +* The multilabel widget allows to control the labels by creatin new one, removing existing ones, +* showing / hiding single labels, merging labels, (re-)naming them etc. +* +* Interpolation for multilabel segmentations is currently not implemented. +*/ +class QmitkMultiLabelSegmentationView : public QmitkAbstractView, public mitk::IRenderWindowPartListener { Q_OBJECT public: + static const std::string VIEW_ID; QmitkMultiLabelSegmentationView(); ~QmitkMultiLabelSegmentationView() override; - typedef std::map NodeTagMapType; +private Q_SLOTS: - // 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); + // reaction to the selection of a new reference image in the selection widget + void OnReferenceSelectionChanged(QList nodes); -protected slots: + // reaction to the selection of a new segmentation image in the selection widget + void OnSegmentationSelectionChanged(QList nodes); // 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 "Save Preset" void OnSavePreset(); // reaction to button "Load Preset" void OnLoadPreset(); // 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(QList nodes); - - // reaction to the selection of a new Segmentation (working) image in the DataStorage combobox - void OnSegmentationSelectionChanged(QList nodes); - // reaction to ... void OnInterpolationSelectionChanged(int); -protected: +private: + + void CreateQtPartControl(QWidget *parent) override; + + void SetFocus() override {} + + void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) override; + void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) override; - // reimplemented from QmitkAbstractView void OnPreferencesChanged(const berry::IBerryPreferences* prefs) override; - // reimplemented from QmitkAbstractView + void NodeAdded(const mitk::DataNode *node) override; + void NodeRemoved(const mitk::DataNode* node) override; - void OnEstablishLabelSetConnection(); + // make sure all images / segmentations look according to the user preference settings + void ApplyDisplayOptions(); - void OnLooseLabelSetConnection(); + // decorates a DataNode according to the user preference settings + void ApplyDisplayOptions(mitk::DataNode* node); - void SetFocus() override; + void OnEstablishLabelSetConnection(); - void UpdateControls(); + void OnLooseLabelSetConnection(); - void RenderWindowPartActivated(mitk::IRenderWindowPart *renderWindowPart); + void ResetMouseCursor(); - void RenderWindowPartDeactivated(mitk::IRenderWindowPart *renderWindowPart); + void SetMouseCursor(const us::ModuleResource&, int hotspotX, int hotspotY); - void ResetMouseCursor(); + void UpdateGUI(); - void SetMouseCursor(const us::ModuleResource, int hotspotX, int hotspotY); + void ValidateSelectionInput(); - void InitializeListeners(); + void UpdateWarningLabel(QString text); - /// \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::IRenderWindowPart *m_RenderWindowPart; mitk::ToolManager *m_ToolManager; mitk::DataNode::Pointer m_ReferenceNode; mitk::DataNode::Pointer m_WorkingNode; + typedef std::map NodeTagMapType; + NodeTagMapType m_WorkingDataObserverTags; + unsigned int m_RenderingManagerObserverTag; + mitk::NodePredicateAnd::Pointer m_ReferencePredicate; mitk::NodePredicateAnd::Pointer m_SegmentationPredicate; bool m_AutoSelectionEnabled; bool m_MouseCursorSet; - 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 +#endif // QMITKMULTILABELSEGMENTATIONVIEW_H diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.cpp index 057e60feec..a79f58c5bf 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.cpp @@ -1,176 +1,175 @@ /*============================================================================ 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 "QmitkSegmentationPreferencePage.h" #include #include #include #include #include #include #include #include #include #include QmitkSegmentationPreferencePage::QmitkSegmentationPreferencePage() : m_MainControl(nullptr), m_SlimViewCheckBox(nullptr), m_RadioOutline(nullptr), m_RadioOverlay(nullptr), + m_SelectionModeCheckBox(nullptr), m_SmoothingCheckBox(nullptr), m_SmoothingSpinBox(nullptr), m_DecimationSpinBox(nullptr), m_ClosingSpinBox(nullptr), - m_SelectionModeCheckBox(nullptr), m_Initializing(false) { + } QmitkSegmentationPreferencePage::~QmitkSegmentationPreferencePage() { } void QmitkSegmentationPreferencePage::Init(berry::IWorkbench::Pointer ) { } void QmitkSegmentationPreferencePage::CreateQtControl(QWidget* parent) { m_Initializing = true; berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); m_SegmentationPreferencesNode = prefService->GetSystemPreferences()->Node("/org.mitk.views.segmentation"); m_MainControl = new QWidget(parent); auto formLayout = new QFormLayout; formLayout->setHorizontalSpacing(8); formLayout->setVerticalSpacing(24); m_SlimViewCheckBox = new QCheckBox("Hide tool button texts and increase icon size", m_MainControl); formLayout->addRow("Slim view", m_SlimViewCheckBox); auto displayOptionsLayout = new QVBoxLayout; m_RadioOutline = new QRadioButton( "Draw as outline", m_MainControl); displayOptionsLayout->addWidget( m_RadioOutline ); m_RadioOverlay = new QRadioButton( "Draw as transparent overlay", m_MainControl); displayOptionsLayout->addWidget( m_RadioOverlay ); formLayout->addRow( "2D display", displayOptionsLayout ); + m_SelectionModeCheckBox = new QCheckBox("Enable auto-selection mode", m_MainControl); + m_SelectionModeCheckBox->setToolTip("Automatically select a patient image and a segmentation if available"); + formLayout->addRow("Data node selection mode", m_SelectionModeCheckBox); + auto surfaceLayout = new QFormLayout; surfaceLayout->setSpacing(8); m_SmoothingCheckBox = new QCheckBox("Use image spacing as smoothing value hint", m_MainControl); surfaceLayout->addRow(m_SmoothingCheckBox); connect(m_SmoothingCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnSmoothingCheckboxChecked(int))); m_SmoothingSpinBox = new QDoubleSpinBox(m_MainControl); m_SmoothingSpinBox->setMinimum(0.0); m_SmoothingSpinBox->setSingleStep(0.5); m_SmoothingSpinBox->setValue(1.0); m_SmoothingSpinBox->setToolTip("The Smoothing value is used as variance for a gaussian blur."); surfaceLayout->addRow("Smoothing value (mm)", m_SmoothingSpinBox); m_DecimationSpinBox = new QDoubleSpinBox(m_MainControl); m_DecimationSpinBox->setMinimum(0.0); m_DecimationSpinBox->setMaximum(0.99); m_DecimationSpinBox->setSingleStep(0.1); m_DecimationSpinBox->setValue(0.5); m_DecimationSpinBox->setToolTip("Valid range is [0, 1). High values increase decimation, especially when very close to 1. A value of 0 disables decimation."); surfaceLayout->addRow("Decimation rate", m_DecimationSpinBox); m_ClosingSpinBox = new QDoubleSpinBox(m_MainControl); m_ClosingSpinBox->setMinimum(0.0); m_ClosingSpinBox->setMaximum(1.0); m_ClosingSpinBox->setSingleStep(0.1); m_ClosingSpinBox->setValue(0.0); m_ClosingSpinBox->setToolTip("Valid range is [0, 1]. Higher values increase closing. A value of 0 disables closing."); surfaceLayout->addRow("Closing Ratio", m_ClosingSpinBox); - m_SelectionModeCheckBox = new QCheckBox("Enable auto-selection mode", m_MainControl); - m_SelectionModeCheckBox->setToolTip("Automatically select a patient image and a segmentation if available"); - formLayout->addRow("Data node selection mode",m_SelectionModeCheckBox); - formLayout->addRow("Smoothed surface creation", surfaceLayout); m_MainControl->setLayout(formLayout); this->Update(); m_Initializing = false; } QWidget* QmitkSegmentationPreferencePage::GetQtControl() const { return m_MainControl; } bool QmitkSegmentationPreferencePage::PerformOk() { m_SegmentationPreferencesNode->PutBool("slim view", m_SlimViewCheckBox->isChecked()); m_SegmentationPreferencesNode->PutBool("draw outline", m_RadioOutline->isChecked()); m_SegmentationPreferencesNode->PutBool("smoothing hint", m_SmoothingCheckBox->isChecked()); m_SegmentationPreferencesNode->PutDouble("smoothing value", m_SmoothingSpinBox->value()); m_SegmentationPreferencesNode->PutDouble("decimation rate", m_DecimationSpinBox->value()); m_SegmentationPreferencesNode->PutDouble("closing ratio", m_ClosingSpinBox->value()); m_SegmentationPreferencesNode->PutBool("auto selection", m_SelectionModeCheckBox->isChecked()); return true; } void QmitkSegmentationPreferencePage::PerformCancel() { } void QmitkSegmentationPreferencePage::Update() { - //m_EnableSingleEditing->setChecked(m_SegmentationPreferencesNode->GetBool("Single click property editing", true)); - m_SlimViewCheckBox->setChecked(m_SegmentationPreferencesNode->GetBool("slim view", false)); if (m_SegmentationPreferencesNode->GetBool("draw outline", true) ) { - m_RadioOutline->setChecked( true ); + m_RadioOutline->setChecked(true); } else { - m_RadioOverlay->setChecked( true ); + m_RadioOverlay->setChecked(true); } + m_SelectionModeCheckBox->setChecked(m_SegmentationPreferencesNode->GetBool("auto selection", true)); + if (m_SegmentationPreferencesNode->GetBool("smoothing hint", true)) { m_SmoothingCheckBox->setChecked(true); m_SmoothingSpinBox->setDisabled(true); } else { m_SmoothingCheckBox->setChecked(false); m_SmoothingSpinBox->setEnabled(true); } - m_SelectionModeCheckBox->setChecked( m_SegmentationPreferencesNode->GetBool("auto selection", true) ); - m_SmoothingSpinBox->setValue(m_SegmentationPreferencesNode->GetDouble("smoothing value", 1.0)); m_DecimationSpinBox->setValue(m_SegmentationPreferencesNode->GetDouble("decimation rate", 0.5)); m_ClosingSpinBox->setValue(m_SegmentationPreferencesNode->GetDouble("closing ratio", 0.0)); } void QmitkSegmentationPreferencePage::OnSmoothingCheckboxChecked(int state) { if (state != Qt::Unchecked) m_SmoothingSpinBox->setDisabled(true); else m_SmoothingSpinBox->setEnabled(true); } diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.h b/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.h index 9d7e1100e9..5b38f81271 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.h +++ b/Plugins/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.h @@ -1,79 +1,70 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QmitkSegmentationPreferencePage_h_included #define QmitkSegmentationPreferencePage_h_included #include "org_mitk_gui_qt_segmentation_Export.h" #include #include "berryIQtPreferencePage.h" class QWidget; class QCheckBox; class QRadioButton; class QDoubleSpinBox; class MITK_QT_SEGMENTATION QmitkSegmentationPreferencePage : public QObject, public berry::IQtPreferencePage { Q_OBJECT Q_INTERFACES(berry::IPreferencePage) public: QmitkSegmentationPreferencePage(); ~QmitkSegmentationPreferencePage() override; void Init(berry::IWorkbench::Pointer workbench) override; void CreateQtControl(QWidget* widget) override; QWidget* GetQtControl() const override; - /// - /// \see IPreferencePage::PerformOk() - /// bool PerformOk() override; - /// - /// \see IPreferencePage::PerformCancel() - /// void PerformCancel() override; - /// - /// \see IPreferencePage::Update() - /// void Update() override; protected slots: void OnSmoothingCheckboxChecked(int); protected: QWidget* m_MainControl; QCheckBox* m_SlimViewCheckBox; QRadioButton* m_RadioOutline; QRadioButton* m_RadioOverlay; + QCheckBox* m_SelectionModeCheckBox; QCheckBox* m_SmoothingCheckBox; QDoubleSpinBox* m_SmoothingSpinBox; QDoubleSpinBox* m_DecimationSpinBox; QDoubleSpinBox* m_ClosingSpinBox; - QCheckBox* m_SelectionModeCheckBox; bool m_Initializing; berry::IPreferences::Pointer m_SegmentationPreferencesNode; }; #endif /* QMITKDATAMANAGERPREFERENCEPAGE_H_ */ 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 09ab641aa5..cbe3ef5e96 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationControls.ui +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationControls.ui @@ -1,529 +1,289 @@ 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 - - Selected Image - - - - - 0 - 0 - + + + + + 0 + 40 + - + + + + + Segmentation + + + + + + 0 + 40 + + + - - - 0 - 0 - - Create a new segmentation &New... - - - :/segmentation/btnNew.png:/segmentation/btnNew.png - Qt::ToolButtonTextOnly - - - - - 0 - 40 - - - - - - - - - 0 - 40 - + + + + + 0 + 0 + + + true + - - - - - - 0 - 0 - - - - - - - - - 200 - 0 - 0 - - - - - - - 200 - 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 - - - - - - - 200 - 0 - 0 - - - - - - - - - MS Shell Dlg 2 - 8 - 50 - false - false - false - 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 + + + + Qt::Vertical + + + + 20 + 40 + + + + QmitkSingleNodeSelectionWidget QWidget
QmitkSingleNodeSelectionWidget.h
1
QmitkToolSelectionBox QWidget
QmitkToolSelectionBox.h
- QmitkSlicesInterpolator + QmitkToolGUIArea QWidget -
QmitkSlicesInterpolator.h
+
QmitkToolGUIArea.h
- QmitkToolGUIArea + QmitkSlicesInterpolator QWidget -
QmitkToolGUIArea.h
+
QmitkSlicesInterpolator.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 e35c714c0d..1c1181fdf1 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp @@ -1,909 +1,822 @@ /*============================================================================ 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 "mitkPluginActivator.h" -#include - -#include "mitkVtkResliceInterpolationProperty.h" +// blueberry +#include -#include "mitkApplicationCursor.h" -#include "mitkSegmentationObjectFactory.h" -#include "mitkPluginActivator.h" -#include "mitkCameraController.h" -#include "mitkLabelSetImage.h" -#include "mitkImageTimeSelector.h" -#include "mitkNodePredicateSubGeometry.h" +// mitk +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// Qmitk +#include #include +#include -#include "usModuleResource.h" -#include "usModuleResourceStream.h" +// us +#include +#include -//micro service to get the ToolManager instance -#include "mitkToolManagerProvider.h" +// Qt +#include -#include #include const std::string QmitkSegmentationView::VIEW_ID = "org.mitk.views.segmentation"; QmitkSegmentationView::QmitkSegmentationView() : m_Parent(nullptr) , m_Controls(nullptr) , m_RenderWindowPart(nullptr) + , m_ToolManager(nullptr) + , m_ReferenceNode(nullptr) + , m_WorkingNode(nullptr) + , m_AutoSelectionEnabled(false) , m_MouseCursorSet(false) - , m_DataSelectionChanged(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 isDwi = mitk::NodePredicateDataType::New("DiffusionImage"); + auto isDti = mitk::NodePredicateDataType::New("TensorImage"); + auto 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); + auto isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); + auto isMask = mitk::NodePredicateAnd::New(isBinary, isImage); - mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); - mitk::NodePredicateNot::Pointer isNotBinaryPredicate = mitk::NodePredicateNot::New(isBinaryPredicate); + auto validSegmentations = mitk::NodePredicateOr::New(); + validSegmentations->AddPredicate(mitk::TNodePredicateDataType::New()); + validSegmentations->AddPredicate(isMask); - mitk::NodePredicateAnd::Pointer isABinaryImagePredicate = mitk::NodePredicateAnd::New(m_IsOfTypeImagePredicate, isBinaryPredicate); - mitk::NodePredicateAnd::Pointer isNotABinaryImagePredicate = mitk::NodePredicateAnd::New(m_IsOfTypeImagePredicate, isNotBinaryPredicate); + m_SegmentationPredicate = mitk::NodePredicateAnd::New(); + m_SegmentationPredicate->AddPredicate(validSegmentations); + m_SegmentationPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); + m_SegmentationPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("hidden object"))); - auto isMLImageType = mitk::TNodePredicateDataType::New(); - mitk::NodePredicateAnd::Pointer isAMLImagePredicate = mitk::NodePredicateAnd::New(isMLImageType, m_IsNotAHelperObject); - mitk::NodePredicateAnd::Pointer isNotAMLImagePredicate = mitk::NodePredicateAnd::New(mitk::NodePredicateNot::New(isMLImageType), m_IsNotAHelperObject); - - m_IsASegmentationImagePredicate = mitk::NodePredicateOr::New(isABinaryImagePredicate, isAMLImagePredicate); - m_IsAPatientImagePredicate = mitk::NodePredicateAnd::New(isNotABinaryImagePredicate, isNotAMLImagePredicate); + m_ReferencePredicate = mitk::NodePredicateAnd::New(); + m_ReferencePredicate->AddPredicate(validImages); + m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(m_SegmentationPredicate)); + m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); + m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("hidden object"))); } QmitkSegmentationView::~QmitkSegmentationView() { if (m_Controls) { - SetToolSelectionBoxesEnabled(false); // deactivate all tools - mitk::ToolManagerProvider::GetInstance()->GetToolManager()->ActivateTool(-1); + m_ToolManager->ActivateTool(-1); // removing all observers for (NodeTagMapType::iterator dataIter = m_WorkingDataObserverTags.begin(); dataIter != m_WorkingDataObserverTags.end(); ++dataIter) { (*dataIter).first->GetProperty("visible")->RemoveObserver((*dataIter).second); } m_WorkingDataObserverTags.clear(); mitk::RenderingManager::GetInstance()->RemoveObserver(m_RenderingManagerObserverTag); ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); service->RemoveAllPlanePositions(); context->ungetService(ppmRef); - SetToolManagerSelection(nullptr, nullptr); + + m_ToolManager->SetReferenceData(nullptr); + m_ToolManager->SetWorkingData(nullptr); } delete m_Controls; } -void QmitkSegmentationView::NewNodeObjectsGenerated(mitk::ToolManager::DataVectorType* nodes) +/**********************************************************************/ +/* private Q_SLOTS */ +/**********************************************************************/ +void QmitkSegmentationView::OnReferenceSelectionChanged(QList nodes) { - if (!nodes) return; + m_ToolManager->ActivateTool(-1); - 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 - } + if (nodes.empty()) + { + m_Controls->segImageSelector->SetNodePredicate(m_SegmentationPredicate); + m_ReferenceNode = nullptr; + m_ToolManager->SetReferenceData(m_ReferenceNode); + this->UpdateGUI(); + return; + } + + m_ReferenceNode = nodes.first(); + m_ToolManager->SetReferenceData(m_ReferenceNode); + if (m_ReferenceNode.IsNotNull()) + { + // set a predicate such that a segmentation fits the selected reference image geometry + auto segPredicate = mitk::NodePredicateAnd::New(m_SegmentationPredicate.GetPointer(), + mitk::NodePredicateSubGeometry::New(m_ReferenceNode->GetData()->GetGeometry())); + + m_Controls->segImageSelector->SetNodePredicate(segPredicate); + + if (m_AutoSelectionEnabled) + { + // hide all image nodes to later show only the automatically selected ones + mitk::DataStorage::SetOfObjects::ConstPointer imageNodes = + this->GetDataStorage()->GetSubset(m_ReferencePredicate); + for (mitk::DataStorage::SetOfObjects::const_iterator iter = imageNodes->begin(); iter != imageNodes->end(); ++iter) + { + (*iter)->SetVisibility(false); + } + } + m_ReferenceNode->SetVisibility(true); + } + + this->UpdateGUI(); } -void QmitkSegmentationView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) +void QmitkSegmentationView::OnSegmentationSelectionChanged(QList nodes) { - if (m_RenderWindowPart != renderWindowPart) + m_ToolManager->ActivateTool(-1); + + if (nodes.empty()) { - m_RenderWindowPart = renderWindowPart; + m_WorkingNode = nullptr; + m_ToolManager->SetWorkingData(m_WorkingNode); + this->UpdateGUI(); + return; } - if (m_Parent) + if (m_ReferenceNode.IsNull()) { - m_Parent->setEnabled(true); + this->UpdateGUI(); + return; } - // tell the interpolation about tool manager, data storage and render window part - if (m_Controls) + mitk::Image::ConstPointer referenceImage = dynamic_cast(m_ReferenceNode->GetData()); + if (referenceImage.IsNull()) { - 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); + this->UpdateGUI(); + return; } -} -void QmitkSegmentationView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* /*renderWindowPart*/) -{ - m_RenderWindowPart = nullptr; - if (m_Parent) + m_WorkingNode = nodes.first(); + m_ToolManager->SetWorkingData(m_WorkingNode); + if (m_WorkingNode.IsNotNull()) { - m_Parent->setEnabled(false); + if (m_AutoSelectionEnabled) + { + // hide all segmentation nodes to later show only the automatically selected ones + mitk::DataStorage::SetOfObjects::ConstPointer segmentationNodes = + this->GetDataStorage()->GetSubset(m_SegmentationPredicate); + for (mitk::DataStorage::SetOfObjects::const_iterator iter = segmentationNodes->begin(); iter != segmentationNodes->end(); ++iter) + { + (*iter)->SetVisibility(false); + } + } + m_WorkingNode->SetVisibility(true); + this->InitializeRenderWindows(referenceImage->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, 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); - } - - auto autoSelectionEnabled = prefs->GetBool("auto selection", true); - m_Controls->patImageSelector->SetAutoSelectNewNodes(autoSelectionEnabled); - m_Controls->segImageSelector->SetAutoSelectNewNodes(autoSelectionEnabled); - this->ForceDisplayPreferencesUponAllImages(); + this->UpdateGUI(); } void QmitkSegmentationView::CreateNewSegmentation() { - mitk::DataNode::Pointer node = mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetReferenceData(0); - if (node.IsNull()) + mitk::DataNode::Pointer referenceNode = m_ToolManager->GetReferenceData(0); + if (referenceNode.IsNull()) { MITK_ERROR << "'Create new segmentation' button should never be clickable unless a reference image is selected."; return; } - mitk::Image::ConstPointer referenceImage = dynamic_cast(node->GetData()); + mitk::Image::ConstPointer referenceImage = dynamic_cast(referenceNode->GetData()); if (referenceImage.IsNull()) { - MITK_ERROR << "Reference data needs to be an image in order to create a new segmentation."; + QMessageBox::information( + m_Parent, "New segmentation", "Please load and select an image before starting some action."); return; } if (referenceImage->GetDimension() <= 1) { - QMessageBox::information(nullptr, tr("Segmentation"), tr("Segmentation is currently not supported for 2D images")); + QMessageBox::information(m_Parent, "New segmentation", "Segmentation is currently not supported for 2D images"); return; } - // ask about the name and organ type of the new segmentation - auto 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; - } + m_ToolManager->ActivateTool(-1); const auto currentTimePoint = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint(); unsigned int imageTimeStep = 0; if (referenceImage->GetTimeGeometry()->IsValidTimePoint(currentTimePoint)) { imageTimeStep = referenceImage->GetTimeGeometry()->TimePointToTimeStep(currentTimePoint); } auto segTemplateImage = referenceImage; if (referenceImage->GetDimension() > 3) { auto result = QMessageBox::question(m_Parent, tr("Create a static or dynamic segmentation?"), - tr("The patient image has multiple time steps.\n\nDo you want to create a static " + tr("The selected image has multiple time steps.\n\nDo you want to create a static " "segmentation that is identical for all time steps or do you want to create a " "dynamic segmentation to segment individual time steps?"), - tr("Create static segmentation"), - tr("Create dynamic segmentation"), + tr("Create static segmentation"), tr("Create dynamic segmentation"), QString(), 0, 0); if (result == 0) { auto selector = mitk::ImageTimeSelector::New(); selector->SetInput(referenceImage); selector->SetTimeNr(0); selector->Update(); const auto refTimeGeometry = referenceImage->GetTimeGeometry(); auto newTimeGeometry = mitk::ProportionalTimeGeometry::New(); newTimeGeometry->SetFirstTimePoint(refTimeGeometry->GetMinimumTimePoint()); newTimeGeometry->SetStepDuration(refTimeGeometry->GetMaximumTimePoint() - refTimeGeometry->GetMinimumTimePoint()); mitk::Image::Pointer newImage = selector->GetOutput(); newTimeGeometry->SetTimeStepGeometry(referenceImage->GetGeometry(imageTimeStep), 0); newImage->SetTimeGeometry(newTimeGeometry); segTemplateImage = newImage; } } - // create a new image of the same dimensions and smallest possible pixel type - auto toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); - auto firstTool = toolManager->GetToolById(0); - if (nullptr == firstTool) + QString newName = QString::fromStdString(referenceNode->GetName()); + newName.append("-labels"); + + // ask about the name and organ type of the new segmentation + auto dialog = new QmitkNewSegmentationDialog(m_Parent); + QStringList organColors = mitk::OrganNamesHandling::GetDefaultOrganColorString(); + dialog->SetSuggestionList(organColors); + dialog->SetSegmentationName(newName); + + int dialogReturnValue = dialog->exec(); + if (dialogReturnValue == QDialog::Rejected) { return; } std::string newNodeName = dialog->GetSegmentationName().toStdString(); if (newNodeName.empty()) { - newNodeName = "no_name"; + newNodeName = "Unnamed"; + } + + // create a new image of the same dimensions and smallest possible pixel type + auto firstTool = m_ToolManager->GetToolById(0); + if (nullptr == firstTool) + { + return; } mitk::DataNode::Pointer emptySegmentation = nullptr; try { emptySegmentation = firstTool->CreateEmptySegmentationNode(segTemplateImage, newNodeName, dialog->GetColor()); } catch (const std::bad_alloc &) { - QMessageBox::warning(nullptr, tr("Create new segmentation"), tr("Could not allocate memory for new segmentation")); + QMessageBox::warning(m_Parent, tr("New segmentation"), tr("Could not allocate memory for new segmentation")); } if (nullptr == emptySegmentation) { return; // could have been aborted by user } // initialize "showVolume"-property to false to prevent recalculating the volume while working on the segmentation emptySegmentation->SetProperty("showVolume", mitk::BoolProperty::New(false)); mitk::OrganNamesHandling::UpdateOrganList(organColors, dialog->GetSegmentationName(), dialog->GetColor()); // escape ';' here (replace by '\;') QString stringForStorage = organColors.replaceInStrings(";", "\\;").join(";"); MITK_DEBUG << "Will store: " << stringForStorage; this->GetPreferences()->Put("Organ-Color-List", stringForStorage); this->GetPreferences()->Flush(); - this->GetDataStorage()->Add(emptySegmentation, node); + this->GetDataStorage()->Add(emptySegmentation, referenceNode); - if (mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0)) + if (m_ToolManager->GetWorkingData(0)) { - mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0)->SetSelected(false); + m_ToolManager->GetWorkingData(0)->SetSelected(false); } emptySegmentation->SetSelected(true); m_Controls->segImageSelector->SetCurrentSelectedNode(emptySegmentation); this->InitializeRenderWindows(referenceImage->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, false); } -void QmitkSegmentationView::OnVisiblePropertyChanged() +void QmitkSegmentationView::OnManualTool2DSelected(int id) { - this->CheckRenderingState(); -} + this->ResetMouseCursor(); + mitk::StatusBar::GetInstance()->DisplayText(""); -void QmitkSegmentationView::NodeAdded(const mitk::DataNode *node) -{ - if (!m_IsASegmentationImagePredicate->CheckNode(node)) + if (id >= 0) { - return; - } + std::string text = "Active Tool: \""; + text += m_ToolManager->GetToolById(id)->GetName(); + text += "\""; + mitk::StatusBar::GetInstance()->DisplayText(text.c_str()); - 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))); - - ApplyDisplayOptions(const_cast(node)); + us::ModuleResource resource = m_ToolManager->GetToolById(id)->GetCursorIconResource(); + this->SetMouseCursor(resource, 0, 0); + } } -void QmitkSegmentationView::NodeRemoved(const mitk::DataNode* node) +void QmitkSegmentationView::OnShowMarkerNodes(bool state) { - 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; + mitk::SegTool2D::Pointer manualSegmentationTool; - service->RemovePlanePosition(id); - - this->GetDataStorage()->Remove(it->Value()); - } + unsigned int numberOfExistingTools = m_ToolManager->GetTools().size(); - context->ungetService(ppmRef); - service = nullptr; + for (unsigned int i = 0; i < numberOfExistingTools; i++) + { + manualSegmentationTool = dynamic_cast(m_ToolManager->GetToolById(i)); - if ((mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0) == node) && m_Controls->patImageSelector->GetSelectedNode().IsNotNull()) + if (manualSegmentationTool) { - this->SetToolManagerSelection(mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetReferenceData(0), nullptr); - this->UpdateWarningLabel(tr("Select or create a segmentation")); + if (state == true) + { + manualSegmentationTool->SetShowMarkerNodes(true); + } + else + { + manualSegmentationTool->SetShowMarkerNodes(false); + } } - - mitk::Image* image = dynamic_cast(node->GetData()); - mitk::SurfaceInterpolationController::GetInstance()->RemoveInterpolationSession(image); - } - - mitk::DataNode* tempNode = const_cast(node); - //Remove observer if one was registered - auto finding = m_WorkingDataObserverTags.find(tempNode); - if (finding != m_WorkingDataObserverTags.end()) - { - node->GetProperty("visible")->RemoveObserver(m_WorkingDataObserverTags[tempNode]); - m_WorkingDataObserverTags.erase(tempNode); } } -void QmitkSegmentationView::OnPatientSelectionChanged(QList nodes) +/**********************************************************************/ +/* private */ +/**********************************************************************/ +void QmitkSegmentationView::CreateQtPartControl(QWidget* parent) { - if(! nodes.empty()) - { - this->UpdateWarningLabel(""); - auto node = nodes.first(); + m_Parent = parent; - auto segPredicate = mitk::NodePredicateAnd::New(m_IsASegmentationImagePredicate.GetPointer(), mitk::NodePredicateSubGeometry::New(node->GetData()->GetGeometry())); + m_Controls = new Ui::QmitkSegmentationControls; + m_Controls->setupUi(parent); - m_Controls->segImageSelector->SetNodePredicate(segPredicate); + m_Controls->patImageSelector->SetDataStorage(GetDataStorage()); + m_Controls->patImageSelector->SetNodePredicate(m_ReferencePredicate); + 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."); - mitk::DataNode* segNode = m_Controls->segImageSelector->GetSelectedNode(); - this->SetToolManagerSelection(node, segNode); - if (segNode) - { - //Doing this we can assure that the segmentation 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->CheckRenderingState(); - } - else - { - this->SetToolSelectionBoxesEnabled( false ); - this->UpdateWarningLabel(tr("Select or create a segmentation")); - } - } - else - { - m_Controls->segImageSelector->SetNodePredicate(m_IsASegmentationImagePredicate); - this->UpdateWarningLabel(tr("Please select an image!")); - this->SetToolSelectionBoxesEnabled( false ); - } -} + m_Controls->segImageSelector->SetDataStorage(GetDataStorage()); + m_Controls->segImageSelector->SetNodePredicate(m_SegmentationPredicate); + 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."); -void QmitkSegmentationView::OnSegmentationSelectionChanged(QList nodes) -{ - if (nodes.empty()) - { - this->UpdateWarningLabel(tr("Select or create a segmentation")); - this->SetToolSelectionBoxesEnabled( false ); - return; - } + connect(m_Controls->patImageSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, + this, &QmitkSegmentationView::OnReferenceSelectionChanged); + connect(m_Controls->segImageSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, + this, &QmitkSegmentationView::OnSegmentationSelectionChanged); + + m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); + m_ToolManager->SetDataStorage(*(this->GetDataStorage())); + m_ToolManager->InitializeTools(); - auto refNode = m_Controls->patImageSelector->GetSelectedNode(); - auto segNode = nodes.front(); + QString segTools2D = tr("Add Subtract Fill Erase Paint Wipe 'Region Growing' 'Live Wire' '2D Fast Marching'"); + QString segTools3D = tr("Threshold 'UL Threshold' Otsu 'Fast Marching 3D' 'Region Growing 3D' Watershed Picking"); - if (!refNode) + std::regex extSegTool2DRegEx("SegTool2D$"); + std::regex extSegTool3DRegEx("SegTool3D$"); + + auto tools = m_ToolManager->GetTools(); + for (const auto &tool : tools) { - this->UpdateWarningLabel(tr("Please select the matching patient image!")); - this->SetToolSelectionBoxesEnabled(false); - this->SetToolManagerSelection(nullptr, segNode); - return; + 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())); + } } - this->CheckRenderingState(); - if ( m_Controls->lblSegmentationWarnings->isVisible()) // "this->CheckRenderingState()" caused a warning. we do not need to go any further - return; + // all part of open source MITK + m_Controls->m_ManualToolSelectionBox2D->SetToolManager(*m_ToolManager); + 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, &QmitkToolSelectionBox::ToolSelected, + this, &QmitkSegmentationView::OnManualTool2DSelected); - this->SetToolManagerSelection(refNode, segNode); + //setup 3D Tools + m_Controls->m_ManualToolSelectionBox3D->SetToolManager(*m_ToolManager); + m_Controls->m_ManualToolSelectionBox3D->SetGenerateAccelerators(true); + m_Controls->m_ManualToolSelectionBox3D->SetToolGUIArea(m_Controls->m_ManualToolGUIContainer3D); + m_Controls->m_ManualToolSelectionBox3D->SetDisplayedToolGroups(segTools3D.toStdString()); + m_Controls->m_ManualToolSelectionBox3D->SetLayoutColumns(3); + m_Controls->m_ManualToolSelectionBox3D->SetEnabledMode( + QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); - 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); - refNode->GetIntProperty("layer", layer); - layer++; - segNode->SetProperty("layer", mitk::IntProperty::New(layer)); - } - else - { - this->SetToolSelectionBoxesEnabled(false); - this->UpdateWarningLabel(tr("Select or create a segmentation")); - } + // create signal/slot connections + connect(m_Controls->btnNewSegmentation, &QToolButton::clicked, this, &QmitkSegmentationView::CreateNewSegmentation); + connect(m_Controls->m_SlicesInterpolator, &QmitkSlicesInterpolator::SignalShowMarkerNodes, this, &QmitkSegmentationView::OnShowMarkerNodes); - mitk::IRenderWindowPart* renderWindowPart = this->GetRenderWindowPart(); - if (!renderWindowPart || !segNode->IsVisible(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer())) + // set callback function for already existing segmentation nodes + mitk::DataStorage::SetOfObjects::ConstPointer allSegmentations = GetDataStorage()->GetSubset(m_SegmentationPredicate); + for (mitk::DataStorage::SetOfObjects::const_iterator iter = allSegmentations->begin(); iter != allSegmentations->end(); ++iter) { - this->UpdateWarningLabel(tr("The selected segmentation is currently not visible!")); - this->SetToolSelectionBoxesEnabled( false ); + mitk::DataNode* node = *iter; + auto command = itk::SimpleMemberCommand::New(); + command->SetCallbackFunction(this, &QmitkSegmentationView::ValidateSelectionInput); + m_WorkingDataObserverTags.insert(std::pair( + node, node->GetProperty("visible")->AddObserver(itk::ModifiedEvent(), command))); } -} - -void QmitkSegmentationView::OnShowMarkerNodes (bool state) -{ - mitk::SegTool2D::Pointer manualSegmentationTool; - unsigned int numberOfExistingTools = mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetTools().size(); + auto command = itk::SimpleMemberCommand::New(); + command->SetCallbackFunction(this, &QmitkSegmentationView::ValidateSelectionInput); + m_RenderingManagerObserverTag = + mitk::RenderingManager::GetInstance()->AddObserver(mitk::RenderingManagerViewsInitializedEvent(), command); - for(unsigned int i = 0; i < numberOfExistingTools; i++) + m_RenderWindowPart = this->GetRenderWindowPart(); + if (nullptr != m_RenderWindowPart) { - manualSegmentationTool = dynamic_cast(mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetToolById(i)); - - if (manualSegmentationTool) - { - if(state == true) - { - manualSegmentationTool->SetShowMarkerNodes( true ); - } - else - { - manualSegmentationTool->SetShowMarkerNodes( false ); - } - } + this->RenderWindowPartActivated(m_RenderWindowPart); } + + // Make sure the GUI notices if appropriate data is already present on creation. + // Should be done last, if everything else is configured because it triggers the autoselection of data. + m_Controls->patImageSelector->SetAutoSelectNewNodes(true); + m_Controls->segImageSelector->SetAutoSelectNewNodes(true); + + this->UpdateGUI(); } -void QmitkSegmentationView::OnContourMarkerSelected(const mitk::DataNode *node) +void QmitkSegmentationView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { - QmitkRenderWindow* selectedRenderWindow = nullptr; - auto* renderWindowPart = this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN); - auto* axialRenderWindow = renderWindowPart->GetQmitkRenderWindow("axial"); - auto* sagittalRenderWindow = renderWindowPart->GetQmitkRenderWindow("sagittal"); - auto* coronalRenderWindow = renderWindowPart->GetQmitkRenderWindow("coronal"); - auto* _3DRenderWindow = renderWindowPart->GetQmitkRenderWindow("3d"); - bool PlanarFigureInitializedWindow = false; - - // find initialized renderwindow - if (node->GetBoolProperty("PlanarFigureInitializedWindow", - PlanarFigureInitializedWindow, axialRenderWindow->GetRenderer())) - { - selectedRenderWindow = axialRenderWindow; - } - if (!selectedRenderWindow && node->GetBoolProperty( - "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, - sagittalRenderWindow->GetRenderer())) - { - selectedRenderWindow = sagittalRenderWindow; - } - if (!selectedRenderWindow && node->GetBoolProperty( - "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, - coronalRenderWindow->GetRenderer())) - { - selectedRenderWindow = coronalRenderWindow; - } - if (!selectedRenderWindow && node->GetBoolProperty( - "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, - _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; + if (m_RenderWindowPart != renderWindowPart) + { + m_RenderWindowPart = renderWindowPart; + } - { - ctkPluginContext* context = mitk::PluginActivator::getContext(); - ctkServiceReference ppmRef = context->getServiceReference(); - mitk::PlanePositionManagerService* service = context->getService(ppmRef); - selectedRenderWindow->GetSliceNavigationController()->ExecuteOperation(service->GetPlanePosition(id)); - context->ungetService(ppmRef); - } + if (m_Parent) + { + m_Parent->setEnabled(true); + } - selectedRenderWindow->GetRenderer()->GetCameraController()->Fit(); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - } + // tell the interpolation about tool manager, data storage and render window part + if (m_Controls) + { + 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(m_ToolManager, controllers); + } } -void QmitkSegmentationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList &nodes) +void QmitkSegmentationView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* /*renderWindowPart*/) { - if (nodes.size() != 0) + m_RenderWindowPart = nullptr; + if (m_Parent) { - std::string markerName = "Position"; - unsigned int numberOfNodes = nodes.size(); - std::string nodeName = nodes.at(0)->GetName(); - if ((numberOfNodes == 1) && (nodeName.find(markerName) == 0)) - { - this->OnContourMarkerSelected(nodes.at(0)); - return; - } + m_Parent->setEnabled(false); } } -void QmitkSegmentationView::OnTabWidgetChanged(int id) +void QmitkSegmentationView::OnPreferencesChanged(const berry::IBerryPreferences* prefs) { - //always disable tools on tab changed - mitk::ToolManagerProvider::GetInstance()->GetToolManager()->ActivateTool(-1); + if (m_Controls != nullptr) + { + bool slimView = prefs->GetBool("slim view", false); + m_Controls->m_ManualToolSelectionBox2D->SetShowNames(!slimView); + m_Controls->m_ManualToolSelectionBox3D->SetShowNames(!slimView); + } - //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 + m_AutoSelectionEnabled = prefs->GetBool("auto selection", false); - //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 - } + this->ApplyDisplayOptions(); } -void QmitkSegmentationView::SetToolManagerSelection(mitk::DataNode* referenceData, mitk::DataNode* workingData) +void QmitkSegmentationView::NodeAdded(const mitk::DataNode* node) { - // 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)); - - m_Controls->btnNewSegmentation->setEnabled(referenceData != nullptr); + if (!m_SegmentationPredicate->CheckNode(node)) + { + return; + } + + auto command = itk::SimpleMemberCommand::New(); + command->SetCallbackFunction(this, &QmitkSegmentationView::ValidateSelectionInput); + m_WorkingDataObserverTags.insert(std::pair( + const_cast(node), node->GetProperty("visible")->AddObserver(itk::ModifiedEvent(), command))); + + this->ApplyDisplayOptions(const_cast(node)); } -void QmitkSegmentationView::ForceDisplayPreferencesUponAllImages() +void QmitkSegmentationView::NodeRemoved(const mitk::DataNode* node) { - if (!m_Parent) - { - return; - } + if (m_SegmentationPredicate->CheckNode(node)) + { + // 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))); - // 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) - } + ctkPluginContext* context = mitk::PluginActivator::getContext(); + ctkServiceReference ppmRef = context->getServiceReference(); + mitk::PlanePositionManagerService* service = context->getService(ppmRef); - mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); - mitk::DataNode::Pointer referenceData = toolManager->GetReferenceData(0); - mitk::DataNode::Pointer workingData = toolManager->GetWorkingData(0); + 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; - // 1. - if (referenceData.IsNotNull()) - { - // iterate all images - mitk::DataStorage::SetOfObjects::ConstPointer allImages = this->GetDataStorage()->GetSubset(m_IsASegmentationImagePredicate); + service->RemovePlanePosition(id); - for ( mitk::DataStorage::SetOfObjects::const_iterator iter = allImages->begin(); iter != allImages->end(); ++iter) + this->GetDataStorage()->Remove(it->Value()); + } - { - mitk::DataNode* node = *iter; - // apply display preferences - ApplyDisplayOptions(node); + context->ungetService(ppmRef); + service = nullptr; - // set visibility - node->SetVisibility(node == referenceData); - } - } + mitk::Image* image = dynamic_cast(node->GetData()); + mitk::SurfaceInterpolationController::GetInstance()->RemoveInterpolationSession(image); + } - // 2. - if (workingData.IsNotNull()) - workingData->SetVisibility(true); + mitk::DataNode* tempNode = const_cast(node); + //Remove observer if one was registered + auto finding = m_WorkingDataObserverTags.find(tempNode); + if (finding != m_WorkingDataObserverTags.end()) + { + node->GetProperty("visible")->RemoveObserver(m_WorkingDataObserverTags[tempNode]); + m_WorkingDataObserverTags.erase(tempNode); + } +} - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +void QmitkSegmentationView::ApplyDisplayOptions() +{ + if (!m_Parent) + { + return; + } + + if (!m_Controls) + { + return; // might happen on initialization (preferences loaded) + } + + mitk::DataNode::Pointer workingData = m_ToolManager->GetWorkingData(0); + mitk::DataStorage::SetOfObjects::ConstPointer allImages = this->GetDataStorage()->GetSubset(m_SegmentationPredicate); + for (mitk::DataStorage::SetOfObjects::const_iterator iter = allImages->begin(); iter != allImages->end(); ++iter) + { + this->ApplyDisplayOptions(*iter); + } + + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSegmentationView::ApplyDisplayOptions(mitk::DataNode* node) { - if (!node) + if (nullptr == node) { return; } - mitk::BoolProperty::Pointer drawOutline = mitk::BoolProperty::New(GetPreferences()->GetBool("draw outline", true)); - mitk::LabelSetImage* labelSetImage = dynamic_cast(node->GetData()); + auto drawOutline = mitk::BoolProperty::New(GetPreferences()->GetBool("draw outline", true)); + auto 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)); // 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)); // force render window update to show outline node->GetData()->Modified(); } } } -void QmitkSegmentationView::CheckRenderingState() +void QmitkSegmentationView::OnContourMarkerSelected(const mitk::DataNode* node) { - mitk::IRenderWindowPart* renderWindowPart = this->GetRenderWindowPart(); - mitk::DataNode* workingNode = m_Controls->segImageSelector->GetSelectedNode(); - - if (!workingNode) + QmitkRenderWindow* selectedRenderWindow = nullptr; + auto* renderWindowPart = this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN); + auto* axialRenderWindow = renderWindowPart->GetQmitkRenderWindow("axial"); + auto* sagittalRenderWindow = renderWindowPart->GetQmitkRenderWindow("sagittal"); + auto* coronalRenderWindow = renderWindowPart->GetQmitkRenderWindow("coronal"); + auto* _3DRenderWindow = renderWindowPart->GetQmitkRenderWindow("3d"); + bool PlanarFigureInitializedWindow = false; + + // find initialized renderwindow + if (node->GetBoolProperty("PlanarFigureInitializedWindow", + PlanarFigureInitializedWindow, axialRenderWindow->GetRenderer())) { - this->SetToolSelectionBoxesEnabled(false); - this->UpdateWarningLabel(tr("Select or create a segmentation")); - return; + 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; } - bool selectedNodeIsVisible = renderWindowPart && workingNode->IsVisible(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer()); - if (!selectedNodeIsVisible) + // make node visible + if (selectedRenderWindow) { - this->SetToolSelectionBoxesEnabled(false); - this->UpdateWarningLabel(tr("The selected segmentation is currently not visible!")); - return; + 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(); } +} - /* - * 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 - */ - const mitk::BaseGeometry *workingNodeGeo = workingNode->GetData()->GetGeometry(); - const mitk::BaseGeometry* worldGeo = renderWindowPart->GetQmitkRenderWindow("3d")->GetSliceNavigationController()->GetCurrentGeometry3D(); - if (nullptr != workingNodeGeo && nullptr != worldGeo) +void QmitkSegmentationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) +{ + if (nodes.size() != 0) { - if (mitk::Equal(*workingNodeGeo->GetBoundingBox(), *worldGeo->GetBoundingBox(), mitk::eps, true)) + std::string markerName = "Position"; + unsigned int numberOfNodes = nodes.size(); + std::string nodeName = nodes.at(0)->GetName(); + if ((numberOfNodes == 1) && (nodeName.find(markerName) == 0)) { - this->SetToolManagerSelection(m_Controls->patImageSelector->GetSelectedNode(), workingNode); - this->SetToolSelectionBoxesEnabled(true); - this->UpdateWarningLabel(""); + this->OnContourMarkerSelected(nodes.at(0)); return; } } - - this->SetToolManagerSelection(m_Controls->patImageSelector->GetSelectedNode(), nullptr); - this->SetToolSelectionBoxesEnabled(false); - this->UpdateWarningLabel(tr("Please perform a reinit on the segmentation image!")); } -void QmitkSegmentationView::UpdateWarningLabel(QString text) +void QmitkSegmentationView::ResetMouseCursor() { - if (text.size() == 0) - m_Controls->lblSegmentationWarnings->hide(); - else - m_Controls->lblSegmentationWarnings->show(); - m_Controls->lblSegmentationWarnings->setText("" + text + ""); + if (m_MouseCursorSet) + { + mitk::ApplicationCursor::GetInstance()->PopCursor(); + m_MouseCursorSet = false; + } } -void QmitkSegmentationView::CreateQtPartControl(QWidget* parent) +void QmitkSegmentationView::SetMouseCursor(const us::ModuleResource& resource, int hotspotX, int hotspotY) { - // 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->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")); + // Remove previously set mouse cursor + if (m_MouseCursorSet) + this->ResetMouseCursor(); - if (m_Controls->patImageSelector->GetSelectedNode().IsNotNull()) - { - UpdateWarningLabel(tr("Select or create a new segmentation")); - } - - m_Controls->segImageSelector->SetDataStorage(GetDataStorage()); - 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 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, &QmitkToolSelectionBox::ToolSelected, this, &QmitkSegmentationView::OnManualTool2DSelected); - - //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); + if (resource) + { + us::ModuleResourceStream cursor(resource, std::ios::binary); + mitk::ApplicationCursor::GetInstance()->PushCursor(cursor, hotspotX, hotspotY); + m_MouseCursorSet = true; + } +} - //Hide 3D selection box, show 2D selection box - m_Controls->m_ManualToolSelectionBox3D->hide(); - m_Controls->m_ManualToolSelectionBox2D->show(); +void QmitkSegmentationView::UpdateGUI() +{ + mitk::DataNode* referenceNode = m_ToolManager->GetReferenceData(0); + bool hasReferenceNode = referenceNode != nullptr; - // update the list of segmentations - toolManager->NewNodeObjectsGenerated += mitk::MessageDelegate1(this, &QmitkSegmentationView::NewNodeObjectsGenerated); + mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); + bool hasWorkingNode = workingNode != nullptr; - // create signal/slot connections - connect(m_Controls->patImageSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkSegmentationView::OnPatientSelectionChanged); - connect(m_Controls->segImageSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkSegmentationView::OnSegmentationSelectionChanged); + m_Controls->btnNewSegmentation->setEnabled(false); + m_Controls->m_SlicesInterpolator->setEnabled(false); - connect(m_Controls->btnNewSegmentation, &QToolButton::clicked, this, &QmitkSegmentationView::CreateNewSegmentation); - connect(m_Controls->tabWidgetSegmentationTools, &QTabWidget::currentChanged, this, &QmitkSegmentationView::OnTabWidgetChanged); - connect(m_Controls->m_SlicesInterpolator, &QmitkSlicesInterpolator::SignalShowMarkerNodes, this, &QmitkSegmentationView::OnShowMarkerNodes); + if (hasReferenceNode) + { + m_Controls->btnNewSegmentation->setEnabled(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))); - } + if (hasWorkingNode && hasReferenceNode) + { + m_Controls->m_SlicesInterpolator->setEnabled(true); - itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); - command->SetCallbackFunction(this, &QmitkSegmentationView::CheckRenderingState); - m_RenderingManagerObserverTag = mitk::RenderingManager::GetInstance()->AddObserver(mitk::RenderingManagerViewsInitializedEvent(), command); + int layer = -1; + referenceNode->GetIntProperty("layer", layer); + workingNode->SetIntProperty("layer", layer + 1); + } - SetToolManagerSelection(m_Controls->patImageSelector->GetSelectedNode(), m_Controls->segImageSelector->GetSelectedNode()); + this->ValidateSelectionInput(); +} - m_RenderWindowPart = this->GetRenderWindowPart(); +void QmitkSegmentationView::ValidateSelectionInput() +{ + this->UpdateWarningLabel(""); - if (nullptr != m_RenderWindowPart) - this->RenderWindowPartActivated(m_RenderWindowPart); + // the argument is actually not used + // enable status depends on the tool manager selection + m_Controls->m_ManualToolSelectionBox2D->setEnabled(false); + m_Controls->m_ManualToolSelectionBox3D->setEnabled(false); - //Should be done last, if everything else is configured because it triggers the autoselection of data. - m_Controls->patImageSelector->SetAutoSelectNewNodes(true); - m_Controls->segImageSelector->SetAutoSelectNewNodes(true); -} + mitk::DataNode* referenceNode = m_Controls->patImageSelector->GetSelectedNode(); + mitk::DataNode* workingNode = m_Controls->segImageSelector->GetSelectedNode(); -void QmitkSegmentationView::SetFocus() -{ - m_Controls->btnNewSegmentation->setFocus(); -} + if (nullptr == referenceNode) + { + return; + } -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(""); - } -} + if (nullptr == workingNode) + { + return; + } -void QmitkSegmentationView::ResetMouseCursor() -{ - if ( m_MouseCursorSet ) - { - mitk::ApplicationCursor::GetInstance()->PopCursor(); - m_MouseCursorSet = false; - } -} + mitk::IRenderWindowPart* renderWindowPart = this->GetRenderWindowPart(); + auto workingNodeIsVisible = renderWindowPart && + workingNode->IsVisible(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer()); + if (!workingNodeIsVisible) + { + this->UpdateWarningLabel(tr("The selected segmentation is currently not visible!")); + return; + } -void QmitkSegmentationView::SetMouseCursor( const us::ModuleResource& resource, int hotspotX, int hotspotY ) -{ - // Remove previously set mouse cursor - if (m_MouseCursorSet) - this->ResetMouseCursor(); + /* + * Here we check whether the geometry of the selected segmentation image is aligned with the worldgeometry. + * At the moment it is not supported to use a geometry different from the selected image for reslicing. + * For further information see Bug 16063 + */ + const mitk::BaseGeometry *workingNodeGeo = workingNode->GetData()->GetGeometry(); + const mitk::BaseGeometry *worldGeo = + renderWindowPart->GetQmitkRenderWindow("3d")->GetSliceNavigationController()->GetCurrentGeometry3D(); + if (nullptr != workingNodeGeo && nullptr != worldGeo) + { + if (mitk::Equal(*workingNodeGeo->GetBoundingBox(), *worldGeo->GetBoundingBox(), mitk::eps, true)) + { + m_ToolManager->SetReferenceData(referenceNode); + m_ToolManager->SetWorkingData(workingNode); + m_Controls->m_ManualToolSelectionBox2D->setEnabled(true); + m_Controls->m_ManualToolSelectionBox3D->setEnabled(true); + return; + } + } - if (resource) - { - us::ModuleResourceStream cursor(resource, std::ios::binary); - mitk::ApplicationCursor::GetInstance()->PushCursor(cursor, hotspotX, hotspotY); - m_MouseCursorSet = true; - } + m_ToolManager->SetReferenceData(referenceNode); + m_ToolManager->SetWorkingData(nullptr); + this->UpdateWarningLabel(tr("Please perform a reinit on the segmentation image!")); } -void QmitkSegmentationView::SetToolSelectionBoxesEnabled(bool status) +void QmitkSegmentationView::UpdateWarningLabel(QString text) { - if (status) + if (text.size() == 0) { - m_Controls->m_ManualToolSelectionBox2D->RecreateButtons(); - m_Controls->m_ManualToolSelectionBox3D->RecreateButtons(); + m_Controls->lblSegmentationWarnings->hide(); } - - m_Controls->m_ManualToolSelectionBox2D->setEnabled(status); - m_Controls->m_ManualToolSelectionBox3D->setEnabled(status); - m_Controls->m_SlicesInterpolator->setEnabled(status); + else + { + m_Controls->lblSegmentationWarnings->show(); + } + m_Controls->lblSegmentationWarnings->setText("" + text + ""); } diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h index 3ea9d5b5dc..7b3187260b 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h @@ -1,133 +1,122 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QMITKSEGMENTATIONVIEW_H #define QMITKSEGMENTATIONVIEW_H +#include "ui_QmitkSegmentationControls.h" + #include -#include #include #include -#include "ui_QmitkSegmentationControls.h" - -class QmitkRenderWindow; - /** -* @brief +* @brief The segmentation view provides a set of tool to use different segmentation algorithms. +* It provides two selection widgets to load an image node and a segmentation node +* on which to perform the segmentation. Creating new segmentation nodes is also possible. +* The available segmentation tools are grouped into "2D"- and "3D"-tools. * +* Most segmentation tools / algorithms need some kind of user interaction, where the +* user is asked to draw something in the image display or set some seed points / start values. +* The tools also often provide additional propeties so that a user can modify the +* algorithm's behavior. * +* Additionally the view provides an option to create "2D"- and "3D"-interpolations between +* neighboring segmentation masks on unsegmented slices. */ class QmitkSegmentationView : public QmitkAbstractView, public mitk::IRenderWindowPartListener { Q_OBJECT public: - QmitkSegmentationView(); + static const std::string VIEW_ID; + QmitkSegmentationView(); ~QmitkSegmentationView() override; - typedef std::map NodeTagMapType; - - void NewNodeObjectsGenerated(mitk::ToolManager::DataVectorType*); - - 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 CheckRenderingState(); +private Q_SLOTS: - static const std::string VIEW_ID; - - protected slots: + // reaction to the selection of a new reference image in the selection widget + void OnReferenceSelectionChanged(QList nodes); - void OnPatientSelectionChanged(QList nodes); + // reaction to the selection of a new segmentation image in the selection widget void OnSegmentationSelectionChanged(QList nodes); // reaction to the button "New segmentation" void CreateNewSegmentation(); void OnManualTool2DSelected(int id); - void OnVisiblePropertyChanged(); - void OnShowMarkerNodes(bool); - void OnTabWidgetChanged(int); +private: -protected: - - // a type for handling lists of DataNodes - typedef std::vector NodeList; - - // GUI setup void CreateQtPartControl(QWidget* parent) override; - // propagate BlueBerry selection to ToolManager for manual segmentation - void SetToolManagerSelection(mitk::DataNode* referenceData, mitk::DataNode* workingData); + void SetFocus() override {} + + void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) override; + void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) override; - // make sure all images/segmentations look as selected by the users in this view's preferences - void ForceDisplayPreferencesUponAllImages(); + void OnPreferencesChanged(const berry::IBerryPreferences* prefs) override; - // decorates a DataNode according to the user preference settings - void ApplyDisplayOptions(mitk::DataNode* node); + void NodeAdded(const mitk::DataNode *node) override; - void ResetMouseCursor(); + void NodeRemoved(const mitk::DataNode* node) override; - void SetMouseCursor(const us::ModuleResource&, int hotspotX, int hotspotY); + // make sure all images / segmentations look according to the user preference settings + void ApplyDisplayOptions(); - void SetToolSelectionBoxesEnabled(bool); + // decorates a DataNode according to the user preference settings + void ApplyDisplayOptions(mitk::DataNode* node); // If a contourmarker is selected, the plane in the related widget will be reoriented according to the marker`s geometry void OnContourMarkerSelected(const mitk::DataNode* node); void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList &nodes) override; - void NodeRemoved(const mitk::DataNode* node) override; + void ResetMouseCursor(); - void NodeAdded(const mitk::DataNode *node) override; + void SetMouseCursor(const us::ModuleResource&, int hotspotX, int hotspotY); - void UpdateWarningLabel(QString text/*, bool overwriteExistingText = true*/); + void UpdateGUI(); + + void ValidateSelectionInput(); + + void UpdateWarningLabel(QString text); - // 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; + mitk::ToolManager* m_ToolManager; - bool m_DataSelectionChanged; + mitk::DataNode::Pointer m_ReferenceNode; + mitk::DataNode::Pointer m_WorkingNode; + typedef std::map NodeTagMapType; NodeTagMapType m_WorkingDataObserverTags; - unsigned int m_RenderingManagerObserverTag; - mitk::NodePredicateNot::Pointer m_IsNotAHelperObject; - mitk::NodePredicateAnd::Pointer m_IsOfTypeImagePredicate; - mitk::NodePredicateOr::Pointer m_IsASegmentationImagePredicate; - mitk::NodePredicateAnd::Pointer m_IsAPatientImagePredicate; + mitk::NodePredicateAnd::Pointer m_ReferencePredicate; + mitk::NodePredicateAnd::Pointer m_SegmentationPredicate; + + bool m_AutoSelectionEnabled; + bool m_MouseCursorSet; + }; #endif // QMITKSEGMENTATIONVIEW_H