diff --git a/Plugins/org.mitk.gui.qt.segmentation/files.cmake b/Plugins/org.mitk.gui.qt.segmentation/files.cmake index dbb3f2d89e..99032b0f3d 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/files.cmake +++ b/Plugins/org.mitk.gui.qt.segmentation/files.cmake @@ -1,70 +1,73 @@ set(SRC_CPP_FILES QmitkSegmentationPreferencePage.cpp ) set(INTERNAL_CPP_FILES mitkPluginActivator.cpp QmitkSegmentationView.cpp QmitkCreatePolygonModelAction.cpp QmitkAutocropAction.cpp QmitkAutocropLabelSetImageAction.cpp Common/QmitkDataSelectionWidget.cpp + Common/QmitkLayersWidget.cpp SegmentationUtilities/QmitkSegmentationUtilitiesView.cpp SegmentationUtilities/QmitkSegmentationUtilityWidget.cpp SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.cpp SegmentationUtilities/ContourModelToImage/QmitkContourModelToImageWidget.cpp SegmentationUtilities/MorphologicalOperations/QmitkMorphologicalOperationsWidget.cpp SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.cpp ) set(UI_FILES src/internal/QmitkSegmentationViewControls.ui src/internal/Common/QmitkDataSelectionWidgetControls.ui + src/internal/Common/QmitkLayersWidgetControls.ui src/internal/SegmentationUtilities/QmitkSegmentationUtilitiesViewControls.ui src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidgetControls.ui src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidgetControls.ui src/internal/SegmentationUtilities/ContourModelToImage/QmitkContourModelToImageWidgetControls.ui src/internal/SegmentationUtilities/MorphologicalOperations/QmitkMorphologicalOperationsWidgetControls.ui src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidgetControls.ui ) set(MOC_H_FILES src/QmitkSegmentationPreferencePage.h src/internal/mitkPluginActivator.h src/internal/QmitkSegmentationView.h src/internal/QmitkCreatePolygonModelAction.h src/internal/QmitkAutocropAction.h src/internal/QmitkAutocropLabelSetImageAction.h src/internal/Common/QmitkDataSelectionWidget.h + src/internal/Common/QmitkLayersWidget.h src/internal/SegmentationUtilities/QmitkSegmentationUtilitiesView.h src/internal/SegmentationUtilities/QmitkSegmentationUtilityWidget.h src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.h src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.h src/internal/SegmentationUtilities/ContourModelToImage/QmitkContourModelToImageWidget.h src/internal/SegmentationUtilities/MorphologicalOperations/QmitkMorphologicalOperationsWidget.h src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.h ) set(CACHED_RESOURCE_FILES resources/segmentation.svg resources/segmentation_utilities.svg plugin.xml ) set(QRC_FILES resources/segmentation.qrc resources/SegmentationUtilities.qrc resources/BooleanOperationsWidget.qrc resources/MorphologicalOperationsWidget.qrc ) set(CPP_FILES) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkLayersWidget.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkLayersWidget.cpp new file mode 100644 index 0000000000..fc0d43bdf8 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkLayersWidget.cpp @@ -0,0 +1,237 @@ +/*============================================================================ + +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 "QmitkLayersWidget.h" +#include + +// mitk +#include +#include +#include + +// Qt +#include + +QmitkLayersWidget::QmitkLayersWidget(QWidget *parent) + : QWidget(parent) + , m_Controls(new Ui::QmitkLayersWidgetControls) + , m_ToolManager(nullptr) +{ + m_Controls->setupUi(this); + + m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); + + connect(m_Controls->addLayerButton, &QToolButton::clicked, this, &QmitkLayersWidget::OnAddLayer); + connect(m_Controls->deleteLayerButton, &QToolButton::clicked, this, &QmitkLayersWidget::OnDeleteLayer); + connect(m_Controls->previousLayerButton, &QToolButton::clicked, this, &QmitkLayersWidget::OnPreviousLayer); + connect(m_Controls->nextLayerButton, &QToolButton::clicked, this, &QmitkLayersWidget::OnNextLayer); + connect(m_Controls->activeLayerComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &QmitkLayersWidget::OnChangeLayer); + + this->UpdateGUI(); +} + +QmitkLayersWidget::~QmitkLayersWidget() +{ + delete m_Controls; +} + +void QmitkLayersWidget::UpdateGUI() +{ + m_Controls->addLayerButton->setEnabled(false); + m_Controls->deleteLayerButton->setEnabled(false); + m_Controls->previousLayerButton->setEnabled(false); + m_Controls->nextLayerButton->setEnabled(false); + m_Controls->activeLayerComboBox->setEnabled(false); + + mitk::LabelSetImage* workingImage = this->GetWorkingImage(); + if (nullptr == workingImage) + { + return; + } + + m_Controls->addLayerButton->setEnabled(true); + + m_Controls->activeLayerComboBox->blockSignals(true); + m_Controls->activeLayerComboBox->clear(); + + unsigned int numberOfLayers = workingImage->GetNumberOfLayers(); + for (unsigned int lidx = 0; lidx < numberOfLayers; ++lidx) + { + m_Controls->activeLayerComboBox->addItem(QString::number(lidx)); + } + + unsigned int activeLayer = workingImage->GetActiveLayer(); + m_Controls->activeLayerComboBox->setCurrentIndex(activeLayer); + m_Controls->activeLayerComboBox->blockSignals(false); + + m_Controls->deleteLayerButton->setEnabled(numberOfLayers > 1); + m_Controls->previousLayerButton->setEnabled(activeLayer > 0); + m_Controls->nextLayerButton->setEnabled(activeLayer != numberOfLayers - 1); + m_Controls->activeLayerComboBox->setEnabled(numberOfLayers > 0); +} + +mitk::LabelSetImage* QmitkLayersWidget::GetWorkingImage() +{ + mitk::DataNode* workingNode = GetWorkingNode(); + if (nullptr == workingNode) + { + return nullptr; + } + + auto workingImage = dynamic_cast(workingNode->GetData()); + return workingImage; +} + +mitk::DataNode* QmitkLayersWidget::GetWorkingNode() +{ + mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); + return workingNode; +} + +void QmitkLayersWidget::OnAddLayer() +{ + m_ToolManager->ActivateTool(-1); + + auto workingImage = this->GetWorkingImage(); + if (nullptr == workingImage) + { + return; + } + + try + { + this->WaitCursorOn(); + workingImage->AddLayer(); + this->WaitCursorOff(); + } + catch (mitk::Exception& e) + { + this->WaitCursorOff(); + MITK_ERROR << "Exception caught: " << e.GetDescription(); + QMessageBox::information( + this, "Add layer", "Could not add a new layer. See error log for details.\n"); + return; + } + + this->UpdateGUI(); + emit LayersChanged(); +} + +void QmitkLayersWidget::OnDeleteLayer() +{ + m_ToolManager->ActivateTool(-1); + + auto workingImage = this->GetWorkingImage(); + 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( + this, "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( + this, "Delete layer", "Could not delete the currently active layer. See error log for details.\n"); + return; + } + + this->UpdateGUI(); + emit LayersChanged(); +} + +void QmitkLayersWidget::OnPreviousLayer() +{ + auto workingImage = this->GetWorkingImage(); + if (nullptr == workingImage) + { + return; + } + + this->OnChangeLayer(workingImage->GetActiveLayer() - 1); +} + +void QmitkLayersWidget::OnNextLayer() +{ + auto workingImage = this->GetWorkingImage(); + if (nullptr == workingImage) + { + return; + } + + this->OnChangeLayer(workingImage->GetActiveLayer() + 1); +} + +void QmitkLayersWidget::OnChangeLayer(int layer) +{ + m_ToolManager->ActivateTool(-1); + + auto workingImage = this->GetWorkingImage(); + if (nullptr == workingImage) + { + return; + } + + try + { + this->WaitCursorOn(); + workingImage->SetActiveLayer(layer); + this->WaitCursorOff(); + } + catch (mitk::Exception& e) + { + this->WaitCursorOff(); + MITK_ERROR << "Exception caught: " << e.GetDescription(); + QMessageBox::information( + this, "Change layer", "Could not change the layer. See error log for details.\n"); + return; + } + + this->UpdateGUI(); + emit LayersChanged(); +} + +void QmitkLayersWidget::WaitCursorOn() +{ + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); +} + +void QmitkLayersWidget::WaitCursorOff() +{ + this->RestoreOverrideCursor(); +} + +void QmitkLayersWidget::RestoreOverrideCursor() +{ + QApplication::restoreOverrideCursor(); +} + diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkLayersWidget.h b/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkLayersWidget.h new file mode 100644 index 0000000000..654e154968 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkLayersWidget.h @@ -0,0 +1,79 @@ +/*============================================================================ + +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 QMITKLAYERSWIDGET_H +#define QMITKLAYERSWIDGET_H + +// Qt +#include + +namespace Ui +{ + class QmitkLayersWidgetControls; +} + +namespace mitk +{ + class DataNode; + class LabelSetImage; + class ToolManager; +} + +class QmitkLayersWidget : public QWidget +{ + Q_OBJECT + +public: + + explicit QmitkLayersWidget(QWidget* parent = nullptr); + ~QmitkLayersWidget() override; + + void UpdateGUI(); + +Q_SIGNALS: + + void LayersChanged(); + +private: + + mitk::LabelSetImage* GetWorkingImage(); + + mitk::DataNode* GetWorkingNode(); + + // 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); + + void WaitCursorOn(); + + void WaitCursorOff(); + + void RestoreOverrideCursor(); + + Ui::QmitkLayersWidgetControls* m_Controls; + + mitk::ToolManager* m_ToolManager; + +}; + +#endif diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkLayersWidgetControls.ui b/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkLayersWidgetControls.ui new file mode 100644 index 0000000000..f2941e4af5 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkLayersWidgetControls.ui @@ -0,0 +1,177 @@ + + + QmitkLayersWidgetControls + + + + 0 + 0 + 300 + 75 + + + + + 0 + 0 + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Layers + + + + + + 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 + 0 + + + + + + + + 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 + + + + + + + + 50 + 30 + + + + + 40 + 30 + + + + Switch to a layer + + + + 0 + + + + + + + + + + + + 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 24d5e2ecfe..087fe8aeb8 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp @@ -1,813 +1,820 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkSegmentationView.h" #include "mitkPluginActivator.h" // blueberry #include // mitk #include #include #include #include #include #include #include #include #include #include #include // Qmitk #include #include #include // us #include #include // Qt #include #include const std::string QmitkSegmentationView::VIEW_ID = "org.mitk.views.segmentation"; QmitkSegmentationView::QmitkSegmentationView() : m_Parent(nullptr) , m_Controls(nullptr) , m_RenderWindowPart(nullptr) , m_ToolManager(nullptr) , m_ReferenceNode(nullptr) , m_WorkingNode(nullptr) , m_AutoSelectionEnabled(false) , m_MouseCursorSet(false) { auto isImage = mitk::TNodePredicateDataType::New(); auto isDwi = mitk::NodePredicateDataType::New("DiffusionImage"); auto isDti = mitk::NodePredicateDataType::New("TensorImage"); auto isOdf = mitk::NodePredicateDataType::New("OdfImage"); auto isSegment = mitk::NodePredicateDataType::New("Segment"); auto validImages = mitk::NodePredicateOr::New(); validImages->AddPredicate(mitk::NodePredicateAnd::New(isImage, mitk::NodePredicateNot::New(isSegment))); validImages->AddPredicate(isDwi); validImages->AddPredicate(isDti); validImages->AddPredicate(isOdf); auto isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); auto isMask = mitk::NodePredicateAnd::New(isBinary, isImage); auto validSegmentations = mitk::NodePredicateOr::New(); validSegmentations->AddPredicate(mitk::TNodePredicateDataType::New()); validSegmentations->AddPredicate(isMask); m_SegmentationPredicate = mitk::NodePredicateAnd::New(); m_SegmentationPredicate->AddPredicate(validSegmentations); m_SegmentationPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); m_SegmentationPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("hidden object"))); m_ReferencePredicate = mitk::NodePredicateAnd::New(); m_ReferencePredicate->AddPredicate(validImages); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(m_SegmentationPredicate)); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("hidden object"))); } QmitkSegmentationView::~QmitkSegmentationView() { if (nullptr != m_Controls) { // deactivate all tools m_ToolManager->ActivateTool(-1); // removing all observers for (NodeTagMapType::iterator dataIter = m_WorkingDataObserverTags.begin(); dataIter != m_WorkingDataObserverTags.end(); ++dataIter) { (*dataIter).first->GetProperty("visible")->RemoveObserver((*dataIter).second); } m_WorkingDataObserverTags.clear(); mitk::RenderingManager::GetInstance()->RemoveObserver(m_RenderingManagerObserverTag); ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); service->RemoveAllPlanePositions(); context->ungetService(ppmRef); m_ToolManager->SetReferenceData(nullptr); m_ToolManager->SetWorkingData(nullptr); } delete m_Controls; } /**********************************************************************/ /* private Q_SLOTS */ /**********************************************************************/ void QmitkSegmentationView::OnReferenceSelectionChanged(QList nodes) { m_ToolManager->ActivateTool(-1); if (nodes.empty()) { m_Controls->workingNodeSelector->SetNodePredicate(m_SegmentationPredicate); m_ReferenceNode = nullptr; m_ToolManager->SetReferenceData(m_ReferenceNode); this->UpdateGUI(); return; } m_ReferenceNode = nodes.first(); m_ToolManager->SetReferenceData(m_ReferenceNode); if (m_ReferenceNode.IsNotNull()) { // set a predicate such that a segmentation fits the selected reference image geometry auto segPredicate = mitk::NodePredicateAnd::New(m_SegmentationPredicate.GetPointer(), mitk::NodePredicateSubGeometry::New(m_ReferenceNode->GetData()->GetGeometry())); m_Controls->workingNodeSelector->SetNodePredicate(segPredicate); if (m_AutoSelectionEnabled) { // hide all image nodes to later show only the automatically selected ones mitk::DataStorage::SetOfObjects::ConstPointer imageNodes = this->GetDataStorage()->GetSubset(m_ReferencePredicate); for (mitk::DataStorage::SetOfObjects::const_iterator iter = imageNodes->begin(); iter != imageNodes->end(); ++iter) { (*iter)->SetVisibility(false); } } m_ReferenceNode->SetVisibility(true); } this->UpdateGUI(); } void QmitkSegmentationView::OnSegmentationSelectionChanged(QList nodes) { m_ToolManager->ActivateTool(-1); // Remove observer if one was registered auto finding = m_WorkingDataObserverTags.find(m_WorkingNode); if (finding != m_WorkingDataObserverTags.end()) { m_WorkingNode->GetProperty("visible")->RemoveObserver(m_WorkingDataObserverTags[m_WorkingNode]); m_WorkingDataObserverTags.erase(m_WorkingNode); } if (nodes.empty()) { m_WorkingNode = nullptr; m_ToolManager->SetWorkingData(m_WorkingNode); this->UpdateGUI(); return; } if (m_ReferenceNode.IsNull()) { this->UpdateGUI(); return; } mitk::Image::ConstPointer referenceImage = dynamic_cast(m_ReferenceNode->GetData()); if (referenceImage.IsNull()) { this->UpdateGUI(); return; } m_WorkingNode = nodes.first(); m_ToolManager->SetWorkingData(m_WorkingNode); if (m_WorkingNode.IsNotNull()) { if (m_AutoSelectionEnabled) { // hide all segmentation nodes to later show only the automatically selected ones mitk::DataStorage::SetOfObjects::ConstPointer segmentationNodes = this->GetDataStorage()->GetSubset(m_SegmentationPredicate); for (mitk::DataStorage::SetOfObjects::const_iterator iter = segmentationNodes->begin(); iter != segmentationNodes->end(); ++iter) { (*iter)->SetVisibility(false); } } m_WorkingNode->SetVisibility(true); auto command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::ValidateSelectionInput); m_WorkingDataObserverTags.insert(std::pair(m_WorkingNode, m_WorkingNode->GetProperty("visible")->AddObserver(itk::ModifiedEvent(), command))); this->InitializeRenderWindows(referenceImage->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, false); } this->UpdateGUI(); } void QmitkSegmentationView::OnNewSegmentation() { m_ToolManager->ActivateTool(-1); mitk::DataNode::Pointer referenceNode = m_ToolManager->GetReferenceData(0); if (referenceNode.IsNull()) { MITK_ERROR << "'Create new segmentation' button should never be clickable unless a reference image is selected."; return; } mitk::Image::ConstPointer referenceImage = dynamic_cast(referenceNode->GetData()); if (referenceImage.IsNull()) { QMessageBox::information( m_Parent, "New segmentation", "Please load and select an image before starting some action."); return; } if (referenceImage->GetDimension() <= 1) { QMessageBox::information( m_Parent, "New segmentation", "Segmentation is currently not supported for 2D images"); return; } const auto currentTimePoint = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetSelectedTimePoint(); unsigned int imageTimeStep = 0; if (referenceImage->GetTimeGeometry()->IsValidTimePoint(currentTimePoint)) { imageTimeStep = referenceImage->GetTimeGeometry()->TimePointToTimeStep(currentTimePoint); } auto segTemplateImage = referenceImage; if (referenceImage->GetDimension() > 3) { auto result = QMessageBox::question(m_Parent, tr("Create a static or dynamic segmentation?"), tr("The selected image has multiple time steps.\n\nDo you want to create a static " "segmentation that is identical for all time steps or do you want to create a " "dynamic segmentation to segment individual time steps?"), tr("Create static segmentation"), tr("Create dynamic segmentation"), QString(), 0, 0); if (result == 0) { auto selector = mitk::ImageTimeSelector::New(); selector->SetInput(referenceImage); selector->SetTimeNr(0); selector->Update(); const auto refTimeGeometry = referenceImage->GetTimeGeometry(); auto newTimeGeometry = mitk::ProportionalTimeGeometry::New(); newTimeGeometry->SetFirstTimePoint(refTimeGeometry->GetMinimumTimePoint()); newTimeGeometry->SetStepDuration(refTimeGeometry->GetMaximumTimePoint() - refTimeGeometry->GetMinimumTimePoint()); mitk::Image::Pointer newImage = selector->GetOutput(); newTimeGeometry->SetTimeStepGeometry(referenceImage->GetGeometry(imageTimeStep), 0); newImage->SetTimeGeometry(newTimeGeometry); segTemplateImage = newImage; } } QString newName = QString::fromStdString(referenceNode->GetName()); newName.append("-labels"); // ask about the name and organ type of the new segmentation auto dialog = new QmitkNewSegmentationDialog(m_Parent); QStringList organColors = mitk::OrganNamesHandling::GetDefaultOrganColorString(); dialog->SetSuggestionList(organColors); dialog->SetSegmentationName(newName); int dialogReturnValue = dialog->exec(); if (dialogReturnValue == QDialog::Rejected) { return; } std::string newNodeName = dialog->GetSegmentationName().toStdString(); if (newNodeName.empty()) { newNodeName = "Unnamed"; } // create a new image of the same dimensions and smallest possible pixel type auto firstTool = m_ToolManager->GetToolById(0); if (nullptr == firstTool) { return; } mitk::DataNode::Pointer emptySegmentation = nullptr; try { emptySegmentation = firstTool->CreateEmptySegmentationNode(segTemplateImage, newNodeName, dialog->GetColor()); } catch (const std::bad_alloc &) { QMessageBox::warning(m_Parent, tr("New segmentation"), tr("Could not allocate memory for new segmentation")); } if (nullptr == emptySegmentation) { return; // could have been aborted by user } // initialize "showVolume"-property to false to prevent recalculating the volume while working on the segmentation emptySegmentation->SetProperty("showVolume", mitk::BoolProperty::New(false)); mitk::OrganNamesHandling::UpdateOrganList(organColors, dialog->GetSegmentationName(), dialog->GetColor()); // escape ';' here (replace by '\;') QString stringForStorage = organColors.replaceInStrings(";", "\\;").join(";"); MITK_DEBUG << "Will store: " << stringForStorage; this->GetPreferences()->Put("Organ-Color-List", stringForStorage); this->GetPreferences()->Flush(); this->GetDataStorage()->Add(emptySegmentation, referenceNode); if (m_ToolManager->GetWorkingData(0)) { m_ToolManager->GetWorkingData(0)->SetSelected(false); } emptySegmentation->SetSelected(true); m_Controls->workingNodeSelector->SetCurrentSelectedNode(emptySegmentation); } void QmitkSegmentationView::OnManualTool2DSelected(int id) { this->ResetMouseCursor(); mitk::StatusBar::GetInstance()->DisplayText(""); if (id >= 0) { std::string text = "Active Tool: \""; text += m_ToolManager->GetToolById(id)->GetName(); text += "\""; mitk::StatusBar::GetInstance()->DisplayText(text.c_str()); us::ModuleResource resource = m_ToolManager->GetToolById(id)->GetCursorIconResource(); this->SetMouseCursor(resource, 0, 0); } } void QmitkSegmentationView::OnShowMarkerNodes(bool state) { mitk::SegTool2D::Pointer manualSegmentationTool; unsigned int numberOfExistingTools = m_ToolManager->GetTools().size(); for (unsigned int i = 0; i < numberOfExistingTools; i++) { manualSegmentationTool = dynamic_cast(m_ToolManager->GetToolById(i)); if (nullptr == manualSegmentationTool) { continue; } manualSegmentationTool->SetShowMarkerNodes(state); } } +void QmitkSegmentationView::OnLayersChanged() +{ + m_Controls->labelSetWidget->ResetAllTableWidgetItems(); +} + /**********************************************************************/ /* private */ /**********************************************************************/ void QmitkSegmentationView::CreateQtPartControl(QWidget* parent) { m_Parent = parent; m_Controls = new Ui::QmitkSegmentationViewControls; m_Controls->setupUi(parent); // *------------------------ // * DATA SELECTION WIDGETS // *------------------------ m_Controls->referenceNodeSelector->SetDataStorage(GetDataStorage()); m_Controls->referenceNodeSelector->SetNodePredicate(m_ReferencePredicate); m_Controls->referenceNodeSelector->SetInvalidInfo("Select an image"); m_Controls->referenceNodeSelector->SetPopUpTitel("Select an image"); m_Controls->referenceNodeSelector->SetPopUpHint("Select an image that should be used to define the geometry and bounds of the segmentation."); m_Controls->workingNodeSelector->SetDataStorage(GetDataStorage()); m_Controls->workingNodeSelector->SetNodePredicate(m_SegmentationPredicate); m_Controls->workingNodeSelector->SetInvalidInfo("Select a segmentation"); m_Controls->workingNodeSelector->SetPopUpTitel("Select a segmentation"); m_Controls->workingNodeSelector->SetPopUpHint("Select a segmentation that should be modified. Only segmentation with the same geometry and within the bounds of the reference image are selected."); connect(m_Controls->referenceNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkSegmentationView::OnReferenceSelectionChanged); connect(m_Controls->workingNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkSegmentationView::OnSegmentationSelectionChanged); // *------------------------ // * TOOLMANAGER // *------------------------ m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); m_ToolManager->SetDataStorage(*(this->GetDataStorage())); m_ToolManager->InitializeTools(); QString segTools2D = tr("Add Subtract Fill Erase Paint Wipe 'Region Growing' 'Live Wire' '2D Fast Marching'"); QString segTools3D = tr("Threshold 'UL Threshold' Otsu 'Fast Marching 3D' 'Region Growing 3D' Watershed Picking"); #ifdef __linux__ segTools3D.append(" nnUNet"); // plugin not enabled for MacOS / Windows #endif std::regex extSegTool2DRegEx("SegTool2D$"); std::regex extSegTool3DRegEx("SegTool3D$"); auto tools = m_ToolManager->GetTools(); for (const auto &tool : tools) { if (std::regex_search(tool->GetNameOfClass(), extSegTool2DRegEx)) { segTools2D.append(QString(" '%1'").arg(tool->GetName())); } else if (std::regex_search(tool->GetNameOfClass(), extSegTool3DRegEx)) { segTools3D.append(QString(" '%1'").arg(tool->GetName())); } } // setup 2D tools m_Controls->toolSelectionBox2D->SetToolManager(*m_ToolManager); m_Controls->toolSelectionBox2D->SetGenerateAccelerators(true); m_Controls->toolSelectionBox2D->SetToolGUIArea(m_Controls->toolGUIArea2D); m_Controls->toolSelectionBox2D->SetDisplayedToolGroups(segTools2D.toStdString()); m_Controls->toolSelectionBox2D->SetLayoutColumns(3); m_Controls->toolSelectionBox2D->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); connect(m_Controls->toolSelectionBox2D, &QmitkToolSelectionBox::ToolSelected, this, &QmitkSegmentationView::OnManualTool2DSelected); // setup 3D Tools m_Controls->toolSelectionBox3D->SetToolManager(*m_ToolManager); m_Controls->toolSelectionBox3D->SetGenerateAccelerators(true); m_Controls->toolSelectionBox3D->SetToolGUIArea(m_Controls->toolGUIArea3D); m_Controls->toolSelectionBox3D->SetDisplayedToolGroups(segTools3D.toStdString()); m_Controls->toolSelectionBox3D->SetLayoutColumns(3); m_Controls->toolSelectionBox3D->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); // create signal/slot connections connect(m_Controls->newSegmentationButton, &QToolButton::clicked, this, &QmitkSegmentationView::OnNewSegmentation); connect(m_Controls->slicesInterpolator, &QmitkSlicesInterpolator::SignalShowMarkerNodes, this, &QmitkSegmentationView::OnShowMarkerNodes); + connect(m_Controls->layersWidget, &QmitkLayersWidget::LayersChanged, this, &QmitkSegmentationView::OnLayersChanged); + auto command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::ValidateSelectionInput); m_RenderingManagerObserverTag = mitk::RenderingManager::GetInstance()->AddObserver(mitk::RenderingManagerViewsInitializedEvent(), command); m_RenderWindowPart = this->GetRenderWindowPart(); if (nullptr != m_RenderWindowPart) { this->RenderWindowPartActivated(m_RenderWindowPart); } // Make sure the GUI notices if appropriate data is already present on creation. // Should be done last, if everything else is configured because it triggers the autoselection of data. m_Controls->referenceNodeSelector->SetAutoSelectNewNodes(true); m_Controls->workingNodeSelector->SetAutoSelectNewNodes(true); this->UpdateGUI(); } void QmitkSegmentationView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { if (m_RenderWindowPart != renderWindowPart) { m_RenderWindowPart = renderWindowPart; } if (nullptr != m_Parent) { m_Parent->setEnabled(true); } // tell the interpolation about tool manager, data storage and render window part if (nullptr != m_Controls && nullptr != m_RenderWindowPart) { m_Controls->slicesInterpolator->SetDataStorage(this->GetDataStorage()); QList controllers; controllers.push_back(m_RenderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()); controllers.push_back(m_RenderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()); controllers.push_back(m_RenderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()); m_Controls->slicesInterpolator->Initialize(m_ToolManager, controllers); } } void QmitkSegmentationView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* /*renderWindowPart*/) { m_RenderWindowPart = nullptr; if (nullptr != m_Parent) { m_Parent->setEnabled(false); } } void QmitkSegmentationView::OnPreferencesChanged(const berry::IBerryPreferences* prefs) { if (nullptr != m_Controls) { bool slimView = prefs->GetBool("slim view", false); m_Controls->toolSelectionBox2D->SetShowNames(!slimView); m_Controls->toolSelectionBox3D->SetShowNames(!slimView); } m_AutoSelectionEnabled = prefs->GetBool("auto selection", false); this->ApplyDisplayOptions(); } void QmitkSegmentationView::NodeAdded(const mitk::DataNode* node) { if (m_SegmentationPredicate->CheckNode(node)) { this->ApplyDisplayOptions(const_cast(node)); } } void QmitkSegmentationView::NodeRemoved(const mitk::DataNode* node) { if (!m_SegmentationPredicate->CheckNode(node)) { return; } // remove all possible contour markers of the segmentation mitk::DataStorage::SetOfObjects::ConstPointer allContourMarkers = this->GetDataStorage()->GetDerivations( node, mitk::NodePredicateProperty::New("isContourMarker", mitk::BoolProperty::New(true))); ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); for (mitk::DataStorage::SetOfObjects::ConstIterator it = allContourMarkers->Begin(); it != allContourMarkers->End(); ++it) { std::string nodeName = node->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int id = atof(nodeName.substr(t + 1).c_str()) - 1; service->RemovePlanePosition(id); this->GetDataStorage()->Remove(it->Value()); } context->ungetService(ppmRef); service = nullptr; mitk::Image* image = dynamic_cast(node->GetData()); mitk::SurfaceInterpolationController::GetInstance()->RemoveInterpolationSession(image); } void QmitkSegmentationView::ApplyDisplayOptions() { if (nullptr == m_Parent) { return; } if (nullptr == m_Controls) { return; // might happen on initialization (preferences loaded) } mitk::DataStorage::SetOfObjects::ConstPointer allImages = this->GetDataStorage()->GetSubset(m_SegmentationPredicate); for (mitk::DataStorage::SetOfObjects::const_iterator iter = allImages->begin(); iter != allImages->end(); ++iter) { this->ApplyDisplayOptions(*iter); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSegmentationView::ApplyDisplayOptions(mitk::DataNode* node) { if (nullptr == node) { return; } auto drawOutline = mitk::BoolProperty::New(GetPreferences()->GetBool("draw outline", true)); auto labelSetImage = dynamic_cast(node->GetData()); if (nullptr != labelSetImage) { // node is a multi label segmentation, // its outline property can be set in the segmentation preference page node->SetProperty("labelset.contour.active", drawOutline); // force render window update to show outline node->GetData()->Modified(); } else if (nullptr != node->GetData()) { // node is a legacy binary segmentation bool isBinary = false; node->GetBoolProperty("binary", isBinary); if (isBinary) { node->SetProperty("outline binary", drawOutline); node->SetProperty("outline width", mitk::FloatProperty::New(2.0)); // force render window update to show outline node->GetData()->Modified(); } } } void QmitkSegmentationView::OnContourMarkerSelected(const mitk::DataNode* node) { QmitkRenderWindow* selectedRenderWindow = nullptr; auto* renderWindowPart = this->GetRenderWindowPart(mitk::WorkbenchUtil::OPEN); auto* axialRenderWindow = renderWindowPart->GetQmitkRenderWindow("axial"); auto* sagittalRenderWindow = renderWindowPart->GetQmitkRenderWindow("sagittal"); auto* coronalRenderWindow = renderWindowPart->GetQmitkRenderWindow("coronal"); auto* threeDRenderWindow = renderWindowPart->GetQmitkRenderWindow("3d"); bool PlanarFigureInitializedWindow = false; // find initialized renderwindow if (node->GetBoolProperty("PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, axialRenderWindow->GetRenderer())) { selectedRenderWindow = axialRenderWindow; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, sagittalRenderWindow->GetRenderer())) { selectedRenderWindow = sagittalRenderWindow; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, coronalRenderWindow->GetRenderer())) { selectedRenderWindow = coronalRenderWindow; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, threeDRenderWindow->GetRenderer())) { selectedRenderWindow = threeDRenderWindow; } // make node visible if (nullptr != selectedRenderWindow) { std::string nodeName = node->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int id = atof(nodeName.substr(t + 1).c_str()) - 1; ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); selectedRenderWindow->GetSliceNavigationController()->ExecuteOperation(service->GetPlanePosition(id)); context->ungetService(ppmRef); selectedRenderWindow->GetRenderer()->GetCameraController()->Fit(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkSegmentationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) { if (0 == nodes.size()) { return; } std::string markerName = "Position"; unsigned int numberOfNodes = nodes.size(); std::string nodeName = nodes.at(0)->GetName(); if ((numberOfNodes == 1) && (nodeName.find(markerName) == 0)) { this->OnContourMarkerSelected(nodes.at(0)); return; } } void QmitkSegmentationView::ResetMouseCursor() { if (m_MouseCursorSet) { mitk::ApplicationCursor::GetInstance()->PopCursor(); m_MouseCursorSet = false; } } void QmitkSegmentationView::SetMouseCursor(const us::ModuleResource& resource, int hotspotX, int hotspotY) { // Remove previously set mouse cursor if (m_MouseCursorSet) { this->ResetMouseCursor(); } if (resource) { us::ModuleResourceStream cursor(resource, std::ios::binary); mitk::ApplicationCursor::GetInstance()->PushCursor(cursor, hotspotX, hotspotY); m_MouseCursorSet = true; } } void QmitkSegmentationView::UpdateGUI() { mitk::DataNode* referenceNode = m_ToolManager->GetReferenceData(0); bool hasReferenceNode = referenceNode != nullptr; mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); bool hasWorkingNode = workingNode != nullptr; m_Controls->newSegmentationButton->setEnabled(false); m_Controls->slicesInterpolator->setEnabled(false); if (hasReferenceNode) { m_Controls->newSegmentationButton->setEnabled(true); } if (hasWorkingNode && hasReferenceNode) { m_Controls->slicesInterpolator->setEnabled(true); int layer = -1; referenceNode->GetIntProperty("layer", layer); workingNode->SetIntProperty("layer", layer + 1); } this->ValidateSelectionInput(); } void QmitkSegmentationView::ValidateSelectionInput() { this->UpdateWarningLabel(""); // the argument is actually not used // enable status depends on the tool manager selection m_Controls->toolSelectionBox2D->setEnabled(false); m_Controls->toolSelectionBox3D->setEnabled(false); mitk::DataNode* referenceNode = m_Controls->referenceNodeSelector->GetSelectedNode(); mitk::DataNode* workingNode = m_Controls->workingNodeSelector->GetSelectedNode(); if (nullptr == referenceNode) { return; } if (nullptr == workingNode) { return; } mitk::IRenderWindowPart* renderWindowPart = this->GetRenderWindowPart(); auto workingNodeIsVisible = renderWindowPart && workingNode->IsVisible(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer()); if (!workingNodeIsVisible) { this->UpdateWarningLabel(tr("The selected segmentation is currently not visible!")); return; } /* * Here we check whether the geometry of the selected segmentation image is aligned with the worldgeometry. * At the moment it is not supported to use a geometry different from the selected image for reslicing. * For further information see Bug 16063 */ const mitk::BaseGeometry* workingNodeGeo = workingNode->GetData()->GetGeometry(); const mitk::BaseGeometry* worldGeo = renderWindowPart->GetQmitkRenderWindow("3d")->GetSliceNavigationController()->GetCurrentGeometry3D(); if (nullptr != workingNodeGeo && nullptr != worldGeo) { if (mitk::Equal(*workingNodeGeo->GetBoundingBox(), *worldGeo->GetBoundingBox(), mitk::eps, true)) { m_ToolManager->SetReferenceData(referenceNode); m_ToolManager->SetWorkingData(workingNode); m_Controls->toolSelectionBox2D->setEnabled(true); m_Controls->toolSelectionBox3D->setEnabled(true); return; } } m_ToolManager->SetReferenceData(referenceNode); m_ToolManager->SetWorkingData(nullptr); this->UpdateWarningLabel(tr("Please perform a reinit on the segmentation image!")); } void QmitkSegmentationView::UpdateWarningLabel(QString text) { if (text.size() == 0) { m_Controls->selectionWarningLabel->hide(); } else { m_Controls->selectionWarningLabel->show(); m_Controls->selectionWarningLabel->setText("" + text + ""); } } diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h index 041c233ece..f417676bff 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h @@ -1,129 +1,131 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QMITKSEGMENTATIONVIEW_H #define QMITKSEGMENTATIONVIEW_H #include "ui_QmitkSegmentationViewControls.h" #include #include #include /** * @brief The segmentation view provides a set of tool to use different segmentation algorithms. * It provides two selection widgets to load an image node and a segmentation node * on which to perform the segmentation. Creating new segmentation nodes is also possible. * The available segmentation tools are grouped into "2D"- and "3D"-tools. * * Most segmentation tools / algorithms need some kind of user interaction, where the * user is asked to draw something in the image display or set some seed points / start values. * The tools also often provide additional propeties so that a user can modify the * algorithm's behavior. * * This class additionally provides options to work with different layers (create new layers, * switch between layers). * Moreover, a multilabel widget displays all the existing labels of a multilabel segmentation * for the currently active layer. * The multilabel widget allows to control the labels by creatin new one, removing existing ones, * showing / hiding single labels, merging labels, (re-)naming them etc. * * Additionally the view provides an option to create "2D"- and "3D"-interpolations between * neighboring segmentation masks on unsegmented slices. */ class QmitkSegmentationView : public QmitkAbstractView, public mitk::IRenderWindowPartListener { Q_OBJECT public: static const std::string VIEW_ID; QmitkSegmentationView(); ~QmitkSegmentationView() override; private Q_SLOTS: // reaction to the selection of a new reference image in the selection widget void OnReferenceSelectionChanged(QList nodes); // reaction to the selection of a new segmentation image in the selection widget void OnSegmentationSelectionChanged(QList nodes); // reaction to the button "New segmentation" void OnNewSegmentation(); void OnManualTool2DSelected(int id); void OnShowMarkerNodes(bool); + void OnLayersChanged(); + private: void CreateQtPartControl(QWidget* parent) override; void SetFocus() override {} void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) override; void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) override; void OnPreferencesChanged(const berry::IBerryPreferences* prefs) override; void NodeAdded(const mitk::DataNode* node) override; void NodeRemoved(const mitk::DataNode* node) override; // make sure all images / segmentations look according to the user preference settings void ApplyDisplayOptions(); // decorates a DataNode according to the user preference settings void ApplyDisplayOptions(mitk::DataNode* node); // If a contourmarker is selected, the plane in the related widget will be reoriented according to the marker`s geometry void OnContourMarkerSelected(const mitk::DataNode* node); void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList &nodes) override; void ResetMouseCursor(); void SetMouseCursor(const us::ModuleResource&, int hotspotX, int hotspotY); void UpdateGUI(); void ValidateSelectionInput(); void UpdateWarningLabel(QString text); QWidget* m_Parent; Ui::QmitkSegmentationViewControls* m_Controls; mitk::IRenderWindowPart* m_RenderWindowPart; mitk::ToolManager* m_ToolManager; mitk::DataNode::Pointer m_ReferenceNode; mitk::DataNode::Pointer m_WorkingNode; typedef std::map NodeTagMapType; NodeTagMapType m_WorkingDataObserverTags; unsigned int m_RenderingManagerObserverTag; mitk::NodePredicateAnd::Pointer m_ReferencePredicate; mitk::NodePredicateAnd::Pointer m_SegmentationPredicate; bool m_AutoSelectionEnabled; bool m_MouseCursorSet; }; #endif // QMITKSEGMENTATIONVIEW_H diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationViewControls.ui b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationViewControls.ui index 36201b819b..a9d41d9142 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationViewControls.ui @@ -1,273 +1,289 @@ QmitkSegmentationViewControls 0 0 300 600 0 0 0 0 Data selection Selected image 0 40 Selected segmentation 0 40 Create a new segmentation New... Qt::ToolButtonTextOnly 0 0 true + + + + + 0 + 0 + + + + 0 0 QTabWidget::tab-bar { alignment: middle; } 0 2D tools 0 0 50 false 0 0 50 false 0 0 50 false Qt::Vertical 20 40 3D tools 0 0 50 false 0 0 50 false Qt::Vertical 20 40 Qt::Vertical 20 40 QmitkSingleNodeSelectionWidget QWidget
QmitkSingleNodeSelectionWidget.h
1
+ + QmitkLayersWidget + QWidget +
internal/Common/QmitkLayersWidget.h
+ 1 +
QmitkToolSelectionBox QWidget
QmitkToolSelectionBox.h
QmitkToolGUIArea QWidget
QmitkToolGUIArea.h
QmitkSlicesInterpolator QWidget
QmitkSlicesInterpolator.h