diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkConvertToMultiLabelSegmentationWidget.cpp b/Modules/SegmentationUI/SegmentationUtilities/QmitkConvertToMultiLabelSegmentationWidget.cpp index f0ed4472a8..2ef47d8d58 100644 --- a/Modules/SegmentationUI/SegmentationUtilities/QmitkConvertToMultiLabelSegmentationWidget.cpp +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkConvertToMultiLabelSegmentationWidget.cpp @@ -1,530 +1,540 @@ /*============================================================================ 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 "QmitkConvertToMultiLabelSegmentationWidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static const char* const HelpText = "Select an image and a surface above"; mitk::NodePredicateBase::Pointer GetInputPredicate() { auto isImage = mitk::TNodePredicateDataType::New(); auto isNotSeg = mitk::NodePredicateNot::New(mitk::GetMultiLabelSegmentationPredicate()); auto isSurface = mitk::TNodePredicateDataType::New(); auto isContourModel = mitk::TNodePredicateDataType::New(); auto isContourModelSet = mitk::TNodePredicateDataType::New(); auto isData = mitk::NodePredicateOr::New(isImage, isContourModel, isContourModelSet); isData->AddPredicate(isSurface); auto isValidInput = mitk::NodePredicateAnd::New(isNotSeg, isData); isValidInput->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); isValidInput->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("hidden object"))); return isValidInput.GetPointer(); } const mitk::DataNode* GetNodeWithLargestImageGeometry(const QmitkNodeSelectionDialog::NodeList& nodes) { mitk::BaseGeometry::ConstPointer refGeometry; - mitk::DataNode* result; + mitk::DataNode* result = nullptr; for (auto& node : nodes) { auto castedData = dynamic_cast(node->GetData()); if (castedData != nullptr) { if (refGeometry.IsNull() || mitk::IsSubGeometry(*refGeometry, *(castedData->GetGeometry()))) { refGeometry = castedData->GetGeometry(); result = node; } } } return result; } QmitkNodeSelectionDialog::NodeList GetNoneImageNodes(const QmitkNodeSelectionDialog::NodeList& nodes) { QmitkNodeSelectionDialog::NodeList result; for (auto& node : nodes) { auto castedData = dynamic_cast(node->GetData()); if (castedData == nullptr) { result.push_back(node); } } return result; } QmitkNodeSelectionDialog::NodeList GetImageNodes(const QmitkNodeSelectionDialog::NodeList& nodes) { QmitkNodeSelectionDialog::NodeList result; for (auto& node : nodes) { auto castedData = dynamic_cast(node->GetData()); if (castedData != nullptr) { result.push_back(node); } } return result; } QmitkNodeSelectionDialog::SelectionCheckFunctionType CheckForSameGeometry(const mitk::DataNode* refNode) { mitk::DataNode::ConstPointer refNodeLambda = refNode; auto lambda = [refNodeLambda](const QmitkNodeSelectionDialog::NodeList& nodes) { if (nodes.empty()) { return std::string(); } - mitk::BaseGeometry::ConstPointer refGeometry; + mitk::NodePredicateSubGeometry::Pointer geoPredicate; bool usedExternalGeo = false; std::string refNodeName; if (refNodeLambda.IsNotNull() && nullptr != refNodeLambda->GetData()) { - refGeometry = refNodeLambda->GetData()->GetGeometry(); + geoPredicate = mitk::NodePredicateSubGeometry::New(refNodeLambda->GetData()->GetGeometry()); usedExternalGeo = true; refNodeName = refNodeLambda->GetName(); } - if (refGeometry.IsNull()) + if (geoPredicate.IsNull()) { auto imageNode = GetNodeWithLargestImageGeometry(nodes); if (nullptr != imageNode) { - refGeometry = imageNode->GetData()->GetGeometry(); + geoPredicate = mitk::NodePredicateSubGeometry::New(imageNode->GetData()->GetGeometry()); refNodeName = imageNode->GetName(); } } - auto geoPredicate = mitk::NodePredicateSubGeometry::New(refGeometry); - for (auto& node : nodes) { auto castedImageData = dynamic_cast(node->GetData()); if (nullptr != castedImageData) { if (!geoPredicate->CheckNode(node)) { std::stringstream ss; ss << "

Invalid selection: All selected images must have the same geometry or a sub geometry "; if (usedExternalGeo) ss << "of the selected reference/output"; ss << ".< / p>

Uses reference data: \""; ss << refNodeName << "\"

"; ss << "

Differing data selections i.a.: \""; ss << node->GetName() << "\"

"; return ss.str(); } } } return std::string(); }; return lambda; } QmitkConvertToMultiLabelSegmentationWidget::QmitkConvertToMultiLabelSegmentationWidget(mitk::DataStorage* dataStorage, QWidget* parent) : QWidget(parent), m_DataStorage(dataStorage) { m_Controls = new Ui::QmitkConvertToMultiLabelSegmentationWidgetControls; m_Controls->setupUi(this); m_Controls->inputNodesSelector->SetDataStorage(dataStorage); m_Controls->inputNodesSelector->SetNodePredicate(GetInputPredicate()); m_Controls->inputNodesSelector->SetSelectionCheckFunction(CheckForSameGeometry(nullptr)); m_Controls->inputNodesSelector->SetSelectionIsOptional(false); m_Controls->inputNodesSelector->SetInvalidInfo(QStringLiteral("Please select inputs (images, surfaces or contours) for conversion")); m_Controls->inputNodesSelector->SetPopUpTitel(QStringLiteral("Select inputs")); m_Controls->inputNodesSelector->SetPopUpHint(QStringLiteral("You may select multiple inputs for conversion. But all selected images must have the same geometry or a sub geometry.")); m_Controls->outputSegSelector->SetDataStorage(dataStorage); m_Controls->outputSegSelector->SetNodePredicate(mitk::GetMultiLabelSegmentationPredicate()); m_Controls->outputSegSelector->SetSelectionIsOptional(false); m_Controls->outputSegSelector->SetInvalidInfo(QStringLiteral("Please select the target segmentation")); m_Controls->outputSegSelector->SetPopUpTitel(QStringLiteral("Select target segmentation")); m_Controls->outputSegSelector->SetPopUpHint(QStringLiteral("Select the segmentation where the converted inputs should be added.")); m_Controls->outputSegSelector->SetAutoSelectNewNodes(true); + m_Controls->refNodeSelector->SetDataStorage(dataStorage); + m_Controls->refNodeSelector->SetNodePredicate(mitk::NodePredicateOr::New(GetInputPredicate(),mitk::GetMultiLabelSegmentationPredicate())); + m_Controls->refNodeSelector->SetSelectionIsOptional(false); + m_Controls->refNodeSelector->SetInvalidInfo(QStringLiteral("Please select a reference image or segmentation")); + m_Controls->refNodeSelector->SetPopUpTitel(QStringLiteral("Select a reference image or segmentation")); + m_Controls->refNodeSelector->SetPopUpHint(QStringLiteral("Select the image or segmentation that by used for the geometry of the conversion.")); + + this->ConfigureWidgets(); connect (m_Controls->btnConvert, &QAbstractButton::clicked, this, &QmitkConvertToMultiLabelSegmentationWidget::OnConvertPressed); connect(m_Controls->inputNodesSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkConvertToMultiLabelSegmentationWidget::OnInputSelectionChanged); + connect(m_Controls->refNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, + this, &QmitkConvertToMultiLabelSegmentationWidget::OnRefSelectionChanged); + connect(m_Controls->outputSegSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, + this, &QmitkConvertToMultiLabelSegmentationWidget::OnOutputSelectionChanged); auto widget = this; connect(m_Controls->radioAddToSeg, &QRadioButton::toggled, m_Controls->outputSegSelector, [widget](bool checked) {widget->ConfigureWidgets(); }); connect(m_Controls->checkMultipleOutputs, &QCheckBox::toggled, m_Controls->outputSegSelector, [widget](bool checked) {widget->ConfigureWidgets(); }); } QmitkConvertToMultiLabelSegmentationWidget::~QmitkConvertToMultiLabelSegmentationWidget() { } void QmitkConvertToMultiLabelSegmentationWidget::ConfigureWidgets() { m_InternalEvent = true; if (m_Controls->radioAddToSeg->isChecked()) { auto selectedNode = m_Controls->outputSegSelector->GetSelectedNode(); m_Controls->inputNodesSelector->SetSelectionCheckFunction(CheckForSameGeometry(selectedNode)); } m_Controls->outputSegSelector->setVisible(m_Controls->radioAddToSeg->isChecked()); if (m_Controls->radioNewSeg->isChecked()) { auto selectedNode = m_Controls->refNodeSelector->GetSelectedNode(); } m_Controls->checkMultipleOutputs->setVisible(m_Controls->radioNewSeg->isChecked()); - bool refNeeded = m_Controls->radioAddToSeg->isChecked() && !m_Controls->inputNodesSelector->GetSelectedNodes().empty() && nullptr == GetNodeWithLargestImageGeometry(m_Controls->inputNodesSelector->GetSelectedNodes()); + bool refNeeded = m_Controls->radioNewSeg->isChecked() && !m_Controls->inputNodesSelector->GetSelectedNodes().empty() && nullptr == GetNodeWithLargestImageGeometry(m_Controls->inputNodesSelector->GetSelectedNodes()); m_Controls->refNodeSelector->setVisible(refNeeded); if (refNeeded) m_Controls->inputNodesSelector->SetSelectionCheckFunction(CheckForSameGeometry(m_Controls->refNodeSelector->GetSelectedNode())); m_Controls->groupGrouping->setVisible(m_Controls->radioAddToSeg->isChecked() || !(m_Controls->checkMultipleOutputs->isChecked())); bool inputIsOK = !m_Controls->inputNodesSelector->GetSelectedNodes().empty() && !m_Controls->inputNodesSelector->CurrentSelectionViolatesCheckFunction(); bool outputIsOK = !m_Controls->radioAddToSeg->isChecked() || m_Controls->outputSegSelector->GetSelectedNode().IsNotNull(); bool refIsOK = !m_Controls->radioNewSeg->isChecked() || !m_Controls->refNodeSelector->isVisible() || m_Controls->refNodeSelector->GetSelectedNode().IsNotNull(); m_Controls->btnConvert->setEnabled(inputIsOK && outputIsOK && refIsOK); m_InternalEvent = false; } void QmitkConvertToMultiLabelSegmentationWidget::OnInputSelectionChanged(QmitkAbstractNodeSelectionWidget::NodeList /*nodes*/) { if (!m_InternalEvent) this->ConfigureWidgets(); } void QmitkConvertToMultiLabelSegmentationWidget::OnOutputSelectionChanged(QmitkAbstractNodeSelectionWidget::NodeList /*nodes*/) { if (!m_InternalEvent) this->ConfigureWidgets(); } void QmitkConvertToMultiLabelSegmentationWidget::OnRefSelectionChanged(QmitkAbstractNodeSelectionWidget::NodeList /*nodes*/) { if (!m_InternalEvent) this->ConfigureWidgets(); } void QmitkConvertToMultiLabelSegmentationWidget::OnConvertPressed() { auto dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNull()) { mitkThrow() << "QmitkConvertToMultiLabelSegmentationWidget is in invalid state. No datastorage is set."; } auto nodes = m_Controls->inputNodesSelector->GetSelectedNodes(); mitk::ProgressBar::GetInstance()->Reset(); mitk::ProgressBar::GetInstance()->AddStepsToDo(3 * nodes.size() + 1); if (m_Controls->radioNewSeg->isChecked() && m_Controls->checkMultipleOutputs->isChecked()) { for (auto& node : nodes) { this->ConvertNodes({ node }); } } else { this->ConvertNodes(nodes); } } mitk::Image::Pointer ConvertSurfaceToImage(const mitk::Image* refImage, const mitk::Surface* surface) { mitk::SurfaceToImageFilter::Pointer surfaceToImageFilter = mitk::SurfaceToImageFilter::New(); surfaceToImageFilter->MakeOutputBinaryOn(); surfaceToImageFilter->UShortBinaryPixelTypeOn(); surfaceToImageFilter->SetInput(surface); surfaceToImageFilter->SetImage(refImage); try { surfaceToImageFilter->Update(); } catch (itk::ExceptionObject& excpt) { MITK_ERROR << excpt.GetDescription(); return nullptr; } return surfaceToImageFilter->GetOutput(); } mitk::Image::Pointer ConvertContourModelSetToImage(mitk::Image* refImage, mitk::ContourModelSet* contourSet) { // Use mitk::ContourModelSetToImageFilter to fill the ContourModelSet into the image mitk::ContourModelSetToImageFilter::Pointer contourFiller = mitk::ContourModelSetToImageFilter::New(); contourFiller->SetImage(refImage); contourFiller->SetInput(contourSet); contourFiller->MakeOutputLabelPixelTypeOn(); try { contourFiller->Update(); } catch (const std::exception& e) { MITK_ERROR << "Error while converting contour model. " << e.what(); } catch (...) { MITK_ERROR << "Unknown error while converting contour model."; } return contourFiller->GetOutput(); } void CheckForLabelCollisionHelper(const QmitkNodeSelectionDialog::NodeList& nodes, const std::map& foundLabelsMap, mitk::LabelSetImage::LabelValueVectorType& usedLabelValues, std::map& labelsMappingMap) { for (const auto& node : nodes) { mitk::ProgressBar::GetInstance()->Progress(); const auto& foundLabels = foundLabelsMap.at(node); mitk::LabelSetImage::LabelValueVectorType correctedLabelValues; bool correctionNeeded = mitk::CheckForLabelValueConflictsAndResolve(foundLabels, usedLabelValues, correctedLabelValues); mitk::LabelValueMappingVector mapping; std::transform(foundLabels.begin(), foundLabels.end(), correctedLabelValues.begin(), std::back_inserter(mapping), [](mitk::LabelSetImage::LabelValueType a, mitk::LabelSetImage::LabelValueType b) { return std::make_pair(a, b); }); labelsMappingMap.emplace(node, mapping); } } void QmitkConvertToMultiLabelSegmentationWidget::ConvertNodes(const QmitkNodeSelectionDialog::NodeList& nodes) { auto noneImageNodes = GetNoneImageNodes(nodes); auto imageNodes = GetImageNodes(nodes); mitk::LabelSetImage::Pointer outputSeg; mitk::Image::Pointer refImage; const mitk::DataNode* refNode; if (m_Controls->radioAddToSeg->isChecked()) { outputSeg = dynamic_cast(m_Controls->outputSegSelector->GetSelectedNode()->GetData()); if (outputSeg->GetNumberOfLayers() > 0) { refImage = outputSeg->GetGroupImage(0); } else { //in case we work with a output seg, we need to generate a template image //reason is that the conversion filters used for surfaces or contours need images //as reference and MultiLabelSegmentations is currently empty. refImage = mitk::Image::New(); refImage->Initialize(mitk::MakePixelType(), *(outputSeg->GetTimeGeometry())); } } else { outputSeg = mitk::LabelSetImage::New(); auto inputNode = GetNodeWithLargestImageGeometry(m_Controls->inputNodesSelector->GetSelectedNodes()); if (nullptr != inputNode) { refNode = inputNode; refImage = dynamic_cast(inputNode->GetData()); outputSeg->Initialize(refImage); } else { refNode = m_Controls->refNodeSelector->GetSelectedNode(); refImage = dynamic_cast(refNode->GetData()); outputSeg->Initialize(refImage); } } //convert none image nodes to images std::map preparedImageMap; std::map foundLabelsMap; for (const auto& node : noneImageNodes) { mitk::ProgressBar::GetInstance()->Progress(); mitk::Image::Pointer convertedImage; auto surface = dynamic_cast(node->GetData()); auto contourModel = dynamic_cast(node->GetData()); auto contourModelSet = dynamic_cast(node->GetData()); if (nullptr != surface) { convertedImage = ConvertSurfaceToImage(refImage, surface); } else if (nullptr != contourModelSet) { convertedImage = ConvertContourModelSetToImage(refImage, contourModelSet); } else if (nullptr != contourModel) { auto contourModelSet = mitk::ContourModelSet::New(); contourModelSet->AddContourModel(contourModel); convertedImage = ConvertContourModelSetToImage(refImage, contourModelSet); } else { mitkThrow() << "Invalid state of QmitkConvertToMultiLabelSegmentationWidget. At least one input is of invalid type, that should not be possible to select. Invalid node: " << *(node.GetPointer()); } if (convertedImage.IsNotNull()) { preparedImageMap.emplace(node, convertedImage); //all none image data is converted to binary maps foundLabelsMap.emplace(node, mitk::LabelSetImage::LabelValueVectorType({ 1 })); } else { mitkThrow() << "Failed to convert an input. Failed node: " << *(node.GetPointer()); } } //prepare image nodes and get contained labels for (const auto& node : imageNodes) { mitk::ProgressBar::GetInstance()->Progress(); mitk::LabelSetImage::LabelValueVectorType foundLabels; mitk::ProgressBar::GetInstance()->Progress(); mitk::Image::Pointer convertedImage = mitk::ConvertImageToGroupImage(dynamic_cast(node->GetData()), foundLabels); preparedImageMap.emplace(node, convertedImage); foundLabelsMap.emplace(node, foundLabels); } //check for label collision and fix if needed mitk::LabelSetImage::LabelValueVectorType usedLabelValues = outputSeg->GetAllLabelValues(); std::map labelsMappingMap; CheckForLabelCollisionHelper(imageNodes, foundLabelsMap, usedLabelValues, labelsMappingMap); CheckForLabelCollisionHelper(noneImageNodes, foundLabelsMap, usedLabelValues, labelsMappingMap); //Ensure that we have the first layer to add mitk::LabelSetImage::GroupIndexType currentGroupIndex = 0; if (m_Controls->radioAddToSeg->isChecked() || 0 == outputSeg->GetNumberOfLayers()) { currentGroupIndex = outputSeg->AddLayer(); } //Transfer content and add labels for (const auto& node : imageNodes) { mitk::ProgressBar::GetInstance()->Progress(); if (m_Controls->radioSingleGroup->isChecked() && node != imageNodes.front()) currentGroupIndex = outputSeg->AddLayer(); const auto& labelsMapping = labelsMappingMap.at(node); for (auto [oldV, correctedV] : labelsMapping) { std::string name = "Value " + std::to_string(oldV); if (m_Controls->radioMergeGroup->isChecked()) name = node->GetName() + " " + name; auto label = mitk::LabelSetImageHelper::CreateNewLabel(outputSeg, name, true); label->SetValue(correctedV); outputSeg->AddLabel(label, currentGroupIndex, false, false); } mitk::TransferLabelContent(preparedImageMap.at(node), outputSeg->GetGroupImage(currentGroupIndex), outputSeg->GetConstLabelsByValue(outputSeg->GetLabelValuesByGroup(currentGroupIndex)), mitk::LabelSetImage::UNLABELED_VALUE, mitk::LabelSetImage::UNLABELED_VALUE, false, labelsMapping); } for (const auto& node : noneImageNodes) { mitk::ProgressBar::GetInstance()->Progress(); if (m_Controls->radioSingleGroup->isChecked() && (node != noneImageNodes.front() || !imageNodes.empty())) currentGroupIndex = outputSeg->AddLayer(); const auto& labelsMapping = labelsMappingMap.at(node); for (auto [oldV, correctedV] : labelsMapping) { auto label = mitk::LabelSetImageHelper::CreateNewLabel(outputSeg, node->GetName(), true); label->SetValue(correctedV); mitk::ColorProperty::ConstPointer colorProp = dynamic_cast(node->GetConstProperty("color").GetPointer()); if (colorProp.IsNotNull()) label->SetColor(colorProp->GetColor()); outputSeg->AddLabel(label, currentGroupIndex, false, false); } mitk::TransferLabelContent(preparedImageMap.at(node), outputSeg->GetGroupImage(currentGroupIndex), outputSeg->GetConstLabelsByValue(outputSeg->GetLabelValuesByGroup(currentGroupIndex)), mitk::LabelSetImage::UNLABELED_VALUE, mitk::LabelSetImage::UNLABELED_VALUE, false, labelsMapping); } if (m_Controls->radioAddToSeg->isChecked()) { m_Controls->outputSegSelector->GetSelectedNode()->Modified(); } else { mitk::DataNode::Pointer outNode = mitk::DataNode::New(); std::stringstream stream; stream << "ConvertedSeg"; if (nodes.size() == 1) { stream << "_" << nodes.front()->GetName(); } outNode->SetName(stream.str()); outNode->SetData(outputSeg); auto dataStorage = m_DataStorage.Lock(); dataStorage->Add(outNode); } mitk::ProgressBar::GetInstance()->Reset(); } diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkExtractFromMultiLabelSegmentationWidget.cpp b/Modules/SegmentationUI/SegmentationUtilities/QmitkExtractFromMultiLabelSegmentationWidget.cpp new file mode 100644 index 0000000000..5bee3dec40 --- /dev/null +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkExtractFromMultiLabelSegmentationWidget.cpp @@ -0,0 +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 "QmitkExtractFromMultiLabelSegmentationWidget.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +QmitkExtractFromMultiLabelSegmentationWidget::QmitkExtractFromMultiLabelSegmentationWidget(mitk::DataStorage* dataStorage, QWidget* parent) + : QWidget(parent), m_DataStorage(dataStorage) +{ + m_Controls = new Ui::QmitkExtractFromMultiLabelSegmentationWidgetControls; + m_Controls->setupUi(this); + + m_Controls->segNodeSelector->SetDataStorage(dataStorage); + m_Controls->segNodeSelector->SetNodePredicate(mitk::GetMultiLabelSegmentationPredicate()); + m_Controls->segNodeSelector->SetSelectionIsOptional(false); + m_Controls->segNodeSelector->SetInvalidInfo(QStringLiteral("Please select segmentation for extraction.")); + m_Controls->segNodeSelector->SetPopUpTitel(QStringLiteral("Select segmentation")); + m_Controls->segNodeSelector->SetPopUpHint(QStringLiteral("Select the segmentation that should be used as source for extraction.")); + + m_Controls->checkExtractSelected->setChecked(false); + + m_Controls->checkClassMap->setChecked(false); + m_Controls->checkInstanceMap->setChecked(true); + m_Controls->checkInstanceMask->setChecked(true); + + this->ConfigureWidgets(); + + connect (m_Controls->btnExtract, &QAbstractButton::clicked, this, &QmitkExtractFromMultiLabelSegmentationWidget::OnExtractPressed); + + connect(m_Controls->segNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, + this, &QmitkExtractFromMultiLabelSegmentationWidget::OnSegSelectionChanged); + + auto widget = this; + connect(m_Controls->checkInstanceMap, &QCheckBox::toggled, + this, [widget](bool checked) {widget->ConfigureWidgets(); }); + connect(m_Controls->checkClassMap, &QCheckBox::toggled, + this, [widget](bool checked) {widget->ConfigureWidgets(); }); + connect(m_Controls->checkInstanceMask, &QCheckBox::toggled, + this, [widget](bool checked) {widget->ConfigureWidgets(); }); + connect(m_Controls->checkExtractSelected, &QCheckBox::toggled, + this, [widget](bool checked) {widget->ConfigureWidgets(); }); + + m_Controls->segNodeSelector->SetAutoSelectNewNodes(true); +} + +QmitkExtractFromMultiLabelSegmentationWidget::~QmitkExtractFromMultiLabelSegmentationWidget() +{ + m_Controls->labelInspector->SetMultiLabelNode(nullptr); +} + +void QmitkExtractFromMultiLabelSegmentationWidget::ConfigureWidgets() +{ + m_InternalEvent = true; + m_Controls->labelInspector->setVisible(m_Controls->checkExtractSelected->isChecked()); + + bool isOK = (m_Controls->checkInstanceMap->isChecked() || m_Controls->checkInstanceMask->isChecked() || m_Controls->checkClassMap->isChecked()); + m_Controls->btnExtract->setEnabled(isOK); + + m_InternalEvent = false; +} + +void QmitkExtractFromMultiLabelSegmentationWidget::OnSegSelectionChanged(QmitkAbstractNodeSelectionWidget::NodeList /*nodes*/) +{ + if (!m_InternalEvent) + { + m_Controls->labelInspector->SetMultiLabelNode(m_Controls->segNodeSelector->GetSelectedNode()); + this->ConfigureWidgets(); + } +} + +void QmitkExtractFromMultiLabelSegmentationWidget::StoreToDataStorage(mitk::Image* image, const std::string& name, mitk::DataNode* parent) +{ + auto dataStorage = m_DataStorage.Lock(); + if (dataStorage.IsNull()) + { + mitkThrow() << "QmitkExtractFromMultiLabelSegmentationWidget is in invalid state. No datastorage is set."; + } + + mitk::DataNode::Pointer outNode = mitk::DataNode::New(); + outNode->SetName(name); + outNode->SetData(image); + + dataStorage->Add(outNode, parent); +} + +void QmitkExtractFromMultiLabelSegmentationWidget::OnExtractPressed() +{ + auto node = m_Controls->segNodeSelector->GetSelectedNodes().front(); + + auto seg = dynamic_cast(node->GetData()); + + auto selectedLabelValues = seg->GetAllLabelValues(); + if (m_Controls->checkExtractSelected->isChecked()) + selectedLabelValues = m_Controls->labelInspector->GetSelectedLabels(); + + auto groupLabelValueMap = mitk::LabelSetImageHelper::SplitLabelValuesByGroup(seg,selectedLabelValues); + + unsigned int numSteps = 0; + if (m_Controls->checkInstanceMap->isChecked()) numSteps += groupLabelValueMap.size(); + if (m_Controls->checkInstanceMask->isChecked()) numSteps += selectedLabelValues.size(); + if (m_Controls->checkClassMap->isChecked()) numSteps += groupLabelValueMap.size(); + + mitk::ProgressBar::GetInstance()->Reset(); + mitk::ProgressBar::GetInstance()->AddStepsToDo(numSteps); + + for (auto& [groupID, labelValues] : groupLabelValueMap) + { + if (m_Controls->checkInstanceMap->isChecked()) + { + auto image = seg->GetGroupImage(groupID)->Clone(); + std::string name = "InstanceMap group "+std::to_string(groupID); + this->StoreToDataStorage(image, name, node); + mitk::ProgressBar::GetInstance()->Progress(); + } + if (m_Controls->checkClassMap->isChecked()) + { + auto [image,lookup] = mitk::CreateLabelClassMap(seg, groupID, labelValues); + std::string name = "ClassMap group " + std::to_string(groupID); + this->StoreToDataStorage(image, name, node); + mitk::ProgressBar::GetInstance()->Progress(); + } + if (m_Controls->checkInstanceMask->isChecked()) + { + for (auto& labelValue : labelValues) + { + auto image = mitk::CreateLabelMask(seg,labelValue); + std::string name = "LabelMask " + seg->GetLabel(labelValue)->GetName() + " [" + std::to_string(labelValue) + "]"; + this->StoreToDataStorage(image, name, node); + mitk::ProgressBar::GetInstance()->Progress(); + } + } + } + mitk::ProgressBar::GetInstance()->Reset(); +} diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkExtractFromMultiLabelSegmentationWidget.h b/Modules/SegmentationUI/SegmentationUtilities/QmitkExtractFromMultiLabelSegmentationWidget.h new file mode 100644 index 0000000000..7b1c0880bf --- /dev/null +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkExtractFromMultiLabelSegmentationWidget.h @@ -0,0 +1,75 @@ +/*============================================================================ + +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 QmitkExtractFromMultiLabelSegmentationWidget_h +#define QmitkExtractFromMultiLabelSegmentationWidget_h + +#include +#include +#include + +#include "itkSmartPointer.h" + +#include + +namespace Ui +{ + class QmitkExtractFromMultiLabelSegmentationWidgetControls; +} + +namespace mitk +{ + class DataNode; + class DataStorage; + class Surface; + class Image; + class LabelSetImage; +} + +/*! + \brief QmitkExtractFromMultiLabelSegmentationWidget + + Widget that offers the GUI and logic to extract different images (class maps, instance maps + and instance masks) from a multi label segmentation. +*/ +class MITKSEGMENTATIONUI_EXPORT QmitkExtractFromMultiLabelSegmentationWidget : public QWidget +{ + Q_OBJECT + +public: + + /** @brief Default constructor, including creation of GUI elements and signals/slots connections. */ + explicit QmitkExtractFromMultiLabelSegmentationWidget(mitk::DataStorage* dataStorage, QWidget* parent = nullptr); + + /** @brief Default destructor. */ + ~QmitkExtractFromMultiLabelSegmentationWidget() override; + +private slots: + + /** @brief This slot is called if the selection in the workbench is changed. */ + void OnSegSelectionChanged(QmitkAbstractNodeSelectionWidget::NodeList /*nodes*/); + + /** @brief This slot is called if user activates the button to convert a surface into a binary image. */ + void OnExtractPressed(); + +private: + bool m_InternalEvent = false; + mitk::WeakPointer m_DataStorage; + + void ConfigureWidgets(); + + void StoreToDataStorage(mitk::Image* image, const std::string& name, mitk::DataNode* parent); + + Ui::QmitkExtractFromMultiLabelSegmentationWidgetControls* m_Controls; +}; + +#endif diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkExtractFromMultiLabelSegmentationWidgetControls.ui b/Modules/SegmentationUI/SegmentationUtilities/QmitkExtractFromMultiLabelSegmentationWidgetControls.ui new file mode 100644 index 0000000000..d63871e671 --- /dev/null +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkExtractFromMultiLabelSegmentationWidgetControls.ui @@ -0,0 +1,123 @@ + + + QmitkExtractFromMultiLabelSegmentationWidgetControls + + + + 0 + 0 + 408 + 316 + + + + + + + Segmentation; + + + + + + + + + + Extract only selected label(s) + + + + + + + + + + Outputs: + + + false + + + + 4 + + + 4 + + + 4 + + + 4 + + + 4 + + + + + If activated, the conversion will generate separate multi label segmentations for each input instead of joining all inputs in one multi label segmentation. + + + Label class map(s) + + + + + + + Label instance map(s) + + + + + + + Label instance mask(s) + + + + + + + + + + Extract + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + QmitkSingleNodeSelectionWidget + QWidget +
QmitkSingleNodeSelectionWidget.h
+ 1 +
+ + QmitkMultiLabelInspector + QWidget +
QmitkMultiLabelInspector.h
+ 1 +
+
+ + +
diff --git a/Modules/SegmentationUI/files.cmake b/Modules/SegmentationUI/files.cmake index fca289c644..5321ae76c6 100644 --- a/Modules/SegmentationUI/files.cmake +++ b/Modules/SegmentationUI/files.cmake @@ -1,129 +1,132 @@ set(CPP_FILES Qmitk/QmitkSegWithPreviewToolGUIBase.cpp Qmitk/QmitkMultiLabelSegWithPreviewToolGUIBase.cpp Qmitk/QmitkBinaryThresholdToolGUIBase.cpp Qmitk/QmitkBinaryThresholdToolGUI.cpp Qmitk/QmitkBinaryThresholdULToolGUI.cpp Qmitk/QmitkConfirmSegmentationDialog.cpp Qmitk/QmitkCopyToClipBoardDialog.cpp Qmitk/QmitkDrawPaintbrushToolGUI.cpp Qmitk/QmitkErasePaintbrushToolGUI.cpp Qmitk/QmitkEditableContourToolGUIBase.cpp Qmitk/QmitkGrowCutToolGUI.cpp Qmitk/QmitkLiveWireTool2DGUI.cpp Qmitk/QmitkLassoToolGUI.cpp Qmitk/QmitkOtsuTool3DGUI.cpp Qmitk/QmitkPaintbrushToolGUI.cpp Qmitk/QmitkPickingToolGUI.cpp Qmitk/QmitkSlicesInterpolator.cpp Qmitk/QmitkToolGUI.cpp Qmitk/QmitkToolGUIArea.cpp Qmitk/QmitkToolSelectionBox.cpp Qmitk/QmitknnUNetFolderParser.cpp Qmitk/QmitknnUNetToolGUI.cpp Qmitk/QmitknnUNetWorker.cpp Qmitk/QmitknnUNetGPU.cpp Qmitk/QmitkSurfaceStampWidget.cpp Qmitk/QmitkMaskStampWidget.cpp Qmitk/QmitkStaticDynamicSegmentationDialog.cpp Qmitk/QmitkSimpleLabelSetListWidget.cpp Qmitk/QmitkSegmentationTaskListWidget.cpp Qmitk/QmitkTotalSegmentatorToolGUI.cpp Qmitk/QmitkSetupVirtualEnvUtil.cpp Qmitk/QmitkMultiLabelInspector.cpp Qmitk/QmitkMultiLabelManager.cpp Qmitk/QmitkMultiLabelTreeModel.cpp Qmitk/QmitkMultiLabelTreeView.cpp Qmitk/QmitkMultiLabelPresetHelper.cpp Qmitk/QmitkLabelColorItemDelegate.cpp Qmitk/QmitkLabelToggleItemDelegate.cpp Qmitk/QmitkFindSegmentationTaskDialog.cpp Qmitk/QmitkSegmentAnythingToolGUI.cpp SegmentationUtilities/QmitkBooleanOperationsWidget.cpp SegmentationUtilities/QmitkContourModelToImageWidget.cpp SegmentationUtilities/QmitkImageMaskingWidget.cpp SegmentationUtilities/QmitkMorphologicalOperationsWidget.cpp SegmentationUtilities/QmitkSurfaceToImageWidget.cpp SegmentationUtilities/QmitkDataSelectionWidget.cpp SegmentationUtilities/QmitkConvertToMultiLabelSegmentationWidget.cpp + SegmentationUtilities/QmitkExtractFromMultiLabelSegmentationWidget.cpp ) set(H_FILES Qmitk/QmitkMultiLabelPresetHelper.h ) set(MOC_H_FILES Qmitk/QmitkSegWithPreviewToolGUIBase.h Qmitk/QmitkMultiLabelSegWithPreviewToolGUIBase.h Qmitk/QmitkBinaryThresholdToolGUIBase.h Qmitk/QmitkBinaryThresholdToolGUI.h Qmitk/QmitkBinaryThresholdULToolGUI.h Qmitk/QmitkConfirmSegmentationDialog.h Qmitk/QmitkCopyToClipBoardDialog.h Qmitk/QmitkDrawPaintbrushToolGUI.h Qmitk/QmitkErasePaintbrushToolGUI.h Qmitk/QmitkEditableContourToolGUIBase.h Qmitk/QmitkGrowCutToolGUI.h Qmitk/QmitkLiveWireTool2DGUI.h Qmitk/QmitkLassoToolGUI.h Qmitk/QmitkOtsuTool3DGUI.h Qmitk/QmitkPaintbrushToolGUI.h Qmitk/QmitkPickingToolGUI.h Qmitk/QmitkSlicesInterpolator.h Qmitk/QmitkToolGUI.h Qmitk/QmitkToolGUIArea.h Qmitk/QmitkToolSelectionBox.h Qmitk/QmitknnUNetFolderParser.h Qmitk/QmitknnUNetToolGUI.h Qmitk/QmitknnUNetGPU.h Qmitk/QmitknnUNetWorker.h Qmitk/QmitknnUNetEnsembleLayout.h Qmitk/QmitkSurfaceStampWidget.h Qmitk/QmitkMaskStampWidget.h Qmitk/QmitkStaticDynamicSegmentationDialog.h Qmitk/QmitkSimpleLabelSetListWidget.h Qmitk/QmitkSegmentationTaskListWidget.h Qmitk/QmitkTotalSegmentatorToolGUI.h Qmitk/QmitkSetupVirtualEnvUtil.h Qmitk/QmitkMultiLabelInspector.h Qmitk/QmitkMultiLabelManager.h Qmitk/QmitkMultiLabelTreeModel.h Qmitk/QmitkMultiLabelTreeView.h Qmitk/QmitkLabelColorItemDelegate.h Qmitk/QmitkLabelToggleItemDelegate.h Qmitk/QmitkFindSegmentationTaskDialog.h Qmitk/QmitkSegmentAnythingToolGUI.h SegmentationUtilities/QmitkBooleanOperationsWidget.h SegmentationUtilities/QmitkContourModelToImageWidget.h SegmentationUtilities/QmitkImageMaskingWidget.h SegmentationUtilities/QmitkMorphologicalOperationsWidget.h SegmentationUtilities/QmitkSurfaceToImageWidget.h SegmentationUtilities/QmitkDataSelectionWidget.h SegmentationUtilities/QmitkConvertToMultiLabelSegmentationWidget.h + SegmentationUtilities/QmitkExtractFromMultiLabelSegmentationWidget.h ) set(UI_FILES Qmitk/QmitkConfirmSegmentationDialog.ui Qmitk/QmitkGrowCutToolWidgetControls.ui Qmitk/QmitkOtsuToolWidgetControls.ui Qmitk/QmitkSurfaceStampWidgetGUIControls.ui Qmitk/QmitkMaskStampWidgetGUIControls.ui Qmitk/QmitknnUNetToolGUIControls.ui Qmitk/QmitkEditableContourToolGUIControls.ui Qmitk/QmitkSegmentationTaskListWidget.ui Qmitk/QmitkTotalSegmentatorGUIControls.ui Qmitk/QmitkMultiLabelInspectorControls.ui Qmitk/QmitkMultiLabelManagerControls.ui Qmitk/QmitkFindSegmentationTaskDialog.ui Qmitk/QmitkSegmentAnythingGUIControls.ui SegmentationUtilities/QmitkBooleanOperationsWidgetControls.ui SegmentationUtilities/QmitkContourModelToImageWidgetControls.ui SegmentationUtilities/QmitkImageMaskingWidgetControls.ui SegmentationUtilities/QmitkMorphologicalOperationsWidgetControls.ui SegmentationUtilities/QmitkSurfaceToImageWidgetControls.ui SegmentationUtilities/QmitkDataSelectionWidgetControls.ui SegmentationUtilities/QmitkConvertToMultiLabelSegmentationWidgetControls.ui + SegmentationUtilities/QmitkExtractFromMultiLabelSegmentationWidgetControls.ui ) set(QRC_FILES resources/SegmentationUI.qrc ) diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationUtilitiesView.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationUtilitiesView.cpp index 5b8f203088..c4eea174db 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationUtilitiesView.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationUtilitiesView.cpp @@ -1,64 +1,68 @@ /*============================================================================ 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 "QmitkSegmentationUtilitiesView.h" #include #include #include #include +#include QmitkSegmentationUtilitiesView::QmitkSegmentationUtilitiesView() : m_BooleanOperationsWidget(nullptr), m_ImageMaskingWidget(nullptr), m_MorphologicalOperationsWidget(nullptr), - m_ConvertToSegWidget(nullptr) + m_ConvertToSegWidget(nullptr), + m_ExtractFromSegWidget(nullptr) { } QmitkSegmentationUtilitiesView::~QmitkSegmentationUtilitiesView() { } void QmitkSegmentationUtilitiesView::CreateQtPartControl(QWidget* parent) { m_Controls.setupUi(parent); auto dataStorage = this->GetDataStorage(); m_BooleanOperationsWidget = new QmitkBooleanOperationsWidget(dataStorage, parent); m_ImageMaskingWidget = new QmitkImageMaskingWidget(dataStorage, parent); m_MorphologicalOperationsWidget = new QmitkMorphologicalOperationsWidget(dataStorage, parent); m_ConvertToSegWidget = new QmitkConvertToMultiLabelSegmentationWidget(dataStorage, parent); + m_ExtractFromSegWidget = new QmitkExtractFromMultiLabelSegmentationWidget(dataStorage, parent); this->AddUtilityWidget(m_BooleanOperationsWidget, QIcon(":/SegmentationUtilities/BooleanOperations_48x48.png"), "Boolean Operations"); this->AddUtilityWidget(m_ImageMaskingWidget, QIcon(":/SegmentationUtilities/ImageMasking_48x48.png"), "Image Masking"); this->AddUtilityWidget(m_MorphologicalOperationsWidget, QIcon(":/SegmentationUtilities/MorphologicalOperations_48x48.png"), "Morphological Operations"); this->AddUtilityWidget(m_ConvertToSegWidget, QIcon(":/SegmentationUtilities/SurfaceToImage_48x48.png"), "Convert to Segmentation"); + this->AddUtilityWidget(m_ExtractFromSegWidget, QIcon(":/SegmentationUtilities/SurfaceToImage_48x48.png"), "Extract from Segmentation"); } void QmitkSegmentationUtilitiesView::AddUtilityWidget(QWidget* widget, const QIcon& icon, const QString& text) { m_Controls.toolBox->addItem(widget, icon, text); } void QmitkSegmentationUtilitiesView::SetFocus() { m_Controls.toolBox->setFocus(); } void QmitkSegmentationUtilitiesView::RenderWindowPartActivated(mitk::IRenderWindowPart*) { } void QmitkSegmentationUtilitiesView::RenderWindowPartDeactivated(mitk::IRenderWindowPart*) { } diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationUtilitiesView.h b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationUtilitiesView.h index 61de70bffc..a98c701d11 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationUtilitiesView.h +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationUtilitiesView.h @@ -1,49 +1,51 @@ /*============================================================================ 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 QmitkSegmentationUtilitiesView_h #define QmitkSegmentationUtilitiesView_h #include #include #include class QmitkBooleanOperationsWidget; class QmitkImageMaskingWidget; class QmitkMorphologicalOperationsWidget; class QmitkConvertToMultiLabelSegmentationWidget; +class QmitkExtractFromMultiLabelSegmentationWidget; class QmitkSegmentationUtilitiesView : public QmitkAbstractView, public mitk::IRenderWindowPartListener { Q_OBJECT public: QmitkSegmentationUtilitiesView(); ~QmitkSegmentationUtilitiesView() override; void CreateQtPartControl(QWidget* parent) override; void SetFocus() override; void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) override; void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) override; private: void AddUtilityWidget(QWidget* widget, const QIcon& icon, const QString& text); Ui::QmitkSegmentationUtilitiesViewControls m_Controls; QmitkBooleanOperationsWidget* m_BooleanOperationsWidget; QmitkImageMaskingWidget* m_ImageMaskingWidget; QmitkMorphologicalOperationsWidget* m_MorphologicalOperationsWidget; + QmitkExtractFromMultiLabelSegmentationWidget* m_ExtractFromSegWidget; QmitkConvertToMultiLabelSegmentationWidget* m_ConvertToSegWidget; }; #endif