diff --git a/Modules/AlgorithmsExt/src/mitkPadImageFilter.cpp b/Modules/AlgorithmsExt/src/mitkPadImageFilter.cpp index b845c63879..1da308c532 100644 --- a/Modules/AlgorithmsExt/src/mitkPadImageFilter.cpp +++ b/Modules/AlgorithmsExt/src/mitkPadImageFilter.cpp @@ -1,105 +1,105 @@ /*============================================================================ 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 "mitkPadImageFilter.h" #include "mitkImageCast.h" #include #include "itkBinaryThresholdImageFilter.h" #include "itkConstantPadImageFilter.h" mitk::PadImageFilter::PadImageFilter() { this->SetNumberOfIndexedInputs(2); this->SetNumberOfRequiredInputs(2); m_BinaryFilter = false; m_PadConstant = -32766; m_LowerThreshold = -32766; m_UpperThreshold = -32765; } mitk::PadImageFilter::~PadImageFilter() { } template void mitk::PadImageFilter::GenerateDataInternal(SourceImageType* sourceItkImage, mitk::Image::Pointer outputImage) { mitk::Image::ConstPointer sourceImage = this->GetInput(0); mitk::Image::ConstPointer referenceImage = this->GetInput(1); mitk::BaseGeometry* imageGeometry = sourceImage->GetGeometry(); mitk::Point3D origin = imageGeometry->GetOrigin(); mitk::Vector3D spacing = imageGeometry->GetSpacing(); mitk::BaseGeometry* referenceImageGeometry = referenceImage->GetGeometry(); mitk::Point3D referenceOrigin = referenceImageGeometry->GetOrigin(); double outputOrigin[3]; itk::SizeValueType padLowerBound[3]; itk::SizeValueType padUpperBound[3]; int i; for (i = 0; i < 3; ++i) { outputOrigin[i] = referenceOrigin[i]; padLowerBound[i] = static_cast((origin[i] - referenceOrigin[i]) / spacing[i] + 0.5); padUpperBound[i] = referenceImage->GetDimension(i) - sourceImage->GetDimension(i) - padLowerBound[i]; } // The origin of the input image is passed through the filter and used as // output origin as well. Hence, it needs to be overwritten accordingly. sourceItkImage->SetOrigin(outputOrigin); typedef itk::ConstantPadImageFilter PadFilterType; - PadFilterType::Pointer padFilter = PadFilterType::New(); + typename PadFilterType::Pointer padFilter = PadFilterType::New(); padFilter->SetInput(sourceItkImage); padFilter->SetConstant(m_PadConstant); padFilter->SetPadLowerBound(padLowerBound); padFilter->SetPadUpperBound(padUpperBound); // If the Binary flag is set, use an additional binary threshold filter after // padding. if (m_BinaryFilter) { typedef itk::Image BinaryImageType; typedef itk::BinaryThresholdImageFilter BinaryFilterType; - BinaryFilterType::Pointer binaryFilter = BinaryFilterType::New(); + typename BinaryFilterType::Pointer binaryFilter = BinaryFilterType::New(); binaryFilter->SetInput(padFilter->GetOutput()); binaryFilter->SetLowerThreshold(m_LowerThreshold); binaryFilter->SetUpperThreshold(m_UpperThreshold); binaryFilter->SetInsideValue(1); binaryFilter->SetOutsideValue(0); binaryFilter->Update(); mitk::CastToMitkImage(binaryFilter->GetOutput(), outputImage); } else { padFilter->Update(); mitk::CastToMitkImage(padFilter->GetOutput(), outputImage); } } void mitk::PadImageFilter::GenerateData() { mitk::Image::Pointer image = this->GetInput(0); mitk::Image::Pointer outputImage = this->GetOutput(); AccessFixedDimensionByItk_1(image, GenerateDataInternal, 3, outputImage); outputImage->SetRequestedRegionToLargestPossibleRegion(); } diff --git a/Modules/Multilabel/mitkLabelSetImageConverter.cpp b/Modules/Multilabel/mitkLabelSetImageConverter.cpp index 995ea66462..83479a3718 100644 --- a/Modules/Multilabel/mitkLabelSetImageConverter.cpp +++ b/Modules/Multilabel/mitkLabelSetImageConverter.cpp @@ -1,407 +1,407 @@ /*============================================================================ 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 #include #include #include #include #include #include #include #include template static void ConvertLabelSetImageToImage(const itk::Image *, mitk::LabelSetImage::ConstPointer labelSetImage, mitk::Image::Pointer &image) { typedef itk::Image ImageType; typedef itk::ComposeImageFilter ComposeFilterType; typedef itk::ImageDuplicator DuplicatorType; auto numberOfLayers = labelSetImage->GetNumberOfLayers(); if (numberOfLayers > 1) { auto vectorImageComposer = ComposeFilterType::New(); for (decltype(numberOfLayers) layer = 0; layer < numberOfLayers; ++layer) { auto layerImage = mitk::ImageToItkImage( labelSetImage->GetGroupImage(layer)); vectorImageComposer->SetInput(layer, layerImage); } vectorImageComposer->Update(); // mitk::GrabItkImageMemory does not support 4D, this will handle 4D correctly // and create a memory managed copy image = mitk::ImportItkImage(vectorImageComposer->GetOutput())->Clone(); } else { auto layerImage = mitk::ImageToItkImage(labelSetImage); auto duplicator = DuplicatorType::New(); duplicator->SetInputImage(layerImage); duplicator->Update(); // mitk::GrabItkImageMemory does not support 4D, this will handle 4D correctly // and create a memory managed copy image = mitk::ImportItkImage(duplicator->GetOutput())->Clone(); } } mitk::Image::Pointer mitk::ConvertLabelSetImageToImage(LabelSetImage::ConstPointer labelSetImage) { Image::Pointer image; if (labelSetImage->GetNumberOfLayers() > 0) { if (labelSetImage->GetDimension() == 4) { AccessFixedDimensionByItk_n(labelSetImage, ::ConvertLabelSetImageToImage, 4, (labelSetImage, image)); } else { AccessByItk_2(labelSetImage->GetGroupImage(0), ::ConvertLabelSetImageToImage, labelSetImage, image); } image->SetTimeGeometry(labelSetImage->GetTimeGeometry()->Clone()); } return image; } template static void SplitVectorImage(const itk::VectorImage* image, std::vector& result) { typedef itk::VectorImage VectorImageType; typedef itk::Image ImageType; typedef itk::VectorIndexSelectionCastImageFilter VectorIndexSelectorType; auto numberOfLayers = image->GetVectorLength(); for (decltype(numberOfLayers) layer = 0; layer < numberOfLayers; ++layer) { auto layerSelector = VectorIndexSelectorType::New(); layerSelector->SetInput(image); layerSelector->SetIndex(layer); layerSelector->Update(); mitk::Image::Pointer layerImage = mitk::GrabItkImageMemoryChannel(layerSelector->GetOutput(), nullptr, nullptr, false); result.push_back(layerImage); } } std::vector mitk::SplitVectorImage(const Image* vecImage) { if (nullptr == vecImage) { mitkThrow() << "Invalid usage; nullptr passed to SplitVectorImage."; } if (vecImage->GetChannelDescriptor().GetPixelType().GetPixelType() != itk::IOPixelEnum::VECTOR) { mitkThrow() << "Invalid usage of SplitVectorImage; passed image is not a vector image. Present pixel type: "<< vecImage->GetChannelDescriptor().GetPixelType().GetPixelTypeAsString(); } std::vector result; if (4 == vecImage->GetDimension()) { AccessVectorFixedDimensionByItk_n(vecImage, ::SplitVectorImage, 4, (result)); } else { AccessVectorPixelTypeByItk_n(vecImage, ::SplitVectorImage, (result)); } for (auto image : result) { image->SetTimeGeometry(vecImage->GetTimeGeometry()->Clone()); } return result; } mitk::LabelSetImage::Pointer mitk::ConvertImageToLabelSetImage(Image::Pointer image) { std::vector groupImages; if (image.IsNotNull()) { if (image->GetChannelDescriptor().GetPixelType().GetPixelType() == itk::IOPixelEnum::VECTOR) { groupImages = SplitVectorImage(image); } else { groupImages.push_back(image); } } auto labelSetImage = ConvertImageVectorToLabelSetImage(groupImages, image->GetTimeGeometry()); return labelSetImage; } mitk::LabelSetImage::Pointer mitk::ConvertImageVectorToLabelSetImage(const std::vector& images, const mitk::TimeGeometry* timeGeometry) { LabelSetImage::Pointer labelSetImage = mitk::LabelSetImage::New(); for (auto& groupImage : images) { if (groupImage== images.front()) { labelSetImage->InitializeByLabeledImage(groupImage); } else { labelSetImage->AddLayer(groupImage); } } labelSetImage->SetTimeGeometry(timeGeometry->Clone()); return labelSetImage; } mitk::LabelSetImage::LabelVectorType mitk::GenerateLabelSetWithMappedValues(const LabelSetImage::ConstLabelVectorType& sourceLabelset, LabelValueMappingVector labelMapping) { LabelSetImage::LabelVectorType result; for (auto oldLabel : sourceLabelset) { auto finding = std::find_if(labelMapping.begin(), labelMapping.end(), [oldLabel](const std::pair& mapping) {return oldLabel->GetValue() == mapping.first; }); if (finding != labelMapping.end()) { auto clonedLabel = oldLabel->Clone(); clonedLabel->SetValue(finding->second); result.push_back(clonedLabel); } } return result; } template void ConvertImageToGroupImageInternal(const SourceImageType* sourceImage, mitk::Image* groupImage, mitk::LabelSetImage::LabelValueVectorType& foundLabels) { - using GroupImageType = typename SourceImageType::RebindImageType; + using GroupImageType = typename SourceImageType::template Rebind::Type; typedef itk::ImageRegionConstIteratorWithIndex SourceIteratorType; typedef itk::ImageRegionIterator TargetIteratorType; auto targetImage = mitk::ImageToItkImage< mitk::LabelSetImage::LabelValueType, SourceImageType::ImageDimension>(groupImage); TargetIteratorType targetIter(targetImage, targetImage->GetRequestedRegion()); targetIter.GoToBegin(); SourceIteratorType sourceIter(sourceImage, sourceImage->GetRequestedRegion()); sourceIter.GoToBegin(); std::set< mitk::LabelSetImage::LabelValueType> detecteValues; while (!sourceIter.IsAtEnd()) { const auto originalSourceValue = sourceIter.Get(); const auto sourceValue = static_cast(originalSourceValue); if (originalSourceValue > mitk::Label::MAX_LABEL_VALUE) { mitkThrow() << "Cannot initialize MultiLabelSegmentation by image. Image contains a pixel value that exceeds the label value range. Invalid pixel value:" << originalSourceValue; } targetIter.Set(sourceValue); if (sourceValue != mitk::Label::UNLABELED_VALUE) detecteValues.insert(sourceValue); ++sourceIter; ++targetIter; } foundLabels.clear(); foundLabels.insert(foundLabels.begin(), detecteValues.begin(), detecteValues.end()); } mitk::Image::Pointer mitk::ConvertImageToGroupImage(const Image* inputImage, mitk::LabelSetImage::LabelValueVectorType& foundLabels) { if (nullptr == inputImage || inputImage->IsEmpty() || !inputImage->IsInitialized()) mitkThrow() << "Invalid labeled image."; auto result = Image::New(); result->Initialize(mitk::MakePixelType(), *(inputImage->GetTimeGeometry())); try { if (result->GetDimension() == 3) { AccessFixedDimensionByItk_2(inputImage, ConvertImageToGroupImageInternal, 3, result, foundLabels); } else if (result->GetDimension() == 4) { AccessFixedDimensionByItk_2(inputImage, ConvertImageToGroupImageInternal, 4, result, foundLabels); } else { mitkThrow() << result->GetDimension() << "-dimensional group images not yet supported"; } } catch (Exception& e) { mitkReThrow(e) << "Could not initialize by provided labeled image."; } catch (...) { mitkThrow() << "Could not initialize by provided labeled image due to unknown error."; } return result; } bool mitk::CheckForLabelValueConflictsAndResolve(const mitk::LabelSetImage::LabelValueVectorType& newValues, mitk::LabelSetImage::LabelValueVectorType& usedLabelValues, mitk::LabelSetImage::LabelValueVectorType& correctedLabelValues) { bool corrected = false; correctedLabelValues.clear(); for (const auto newV : newValues) { auto finding = std::find(usedLabelValues.begin(), usedLabelValues.end(), newV); if (finding == usedLabelValues.end()) { correctedLabelValues.push_back(newV); usedLabelValues.push_back(newV); } else { const auto maxFinding = std::max_element(usedLabelValues.begin(), usedLabelValues.end()); if (*maxFinding == Label::MAX_LABEL_VALUE) mitkThrow() << "Cannot correct label values. All available values are used. A segmentation cannot contain more labels."; const auto correctedV = *(maxFinding)+1; correctedLabelValues.push_back(correctedV); usedLabelValues.push_back(correctedV); corrected = true; } } return corrected; } namespace { template void ClearBufferProcessing(ImageType* itkImage) { itkImage->FillBuffer(0); } void ClearImageBuffer(mitk::Image* image) { if (image->GetDimension() == 4) { //remark: this extra branch was added, because LabelSetImage instances can be //dynamic (4D), but AccessByItk by support only supports 2D and 3D. //The option to change the CMake default dimensions for AccessByItk was //dropped (for details see discussion in T28756) AccessFixedDimensionByItk(image, ClearBufferProcessing, 4); } else { AccessByItk(image, ClearBufferProcessing); } } } mitk::Image::Pointer mitk::CreateLabelMask(const LabelSetImage* segmentation, LabelSetImage::LabelValueType labelValue, bool createBinaryMap) { if (nullptr==segmentation) mitkThrow() << "Error, cannot create label mask. Passed segmentation is nullptr."; if (!segmentation->ExistLabel(labelValue)) mitkThrow() << "Error, cannot create label mask. Label ID is invalid. Invalid ID: " << labelValue; auto mask = mitk::Image::New(); // mask->Initialize(segmentation) does not work here if this label set image has a single slice, // since the mask would be automatically flattened to a 2-d image, whereas we expect the // original dimension of this label set image. Hence, initialize the mask more explicitly: mask->Initialize(segmentation->GetPixelType(), segmentation->GetDimension(), segmentation->GetDimensions()); mask->SetTimeGeometry(segmentation->GetTimeGeometry()->Clone()); ClearImageBuffer(mask); const auto groupID = segmentation->GetGroupIndexOfLabel(labelValue); auto destinationLabel = segmentation->GetLabel(labelValue)->Clone(); if (createBinaryMap) destinationLabel->SetValue(1); TransferLabelContent(segmentation->GetGroupImage(groupID), mask.GetPointer(), { destinationLabel }, LabelSetImage::UNLABELED_VALUE, LabelSetImage::UNLABELED_VALUE, false, { { labelValue, destinationLabel->GetValue()} }, MultiLabelSegmentation::MergeStyle::Replace, MultiLabelSegmentation::OverwriteStyle::IgnoreLocks); return mask; } std::pair mitk::CreateLabelClassMap(const LabelSetImage* segmentation, LabelSetImage::GroupIndexType groupID, const LabelSetImage::LabelValueVectorType& selectedLabels) { if (nullptr == segmentation) mitkThrow() << "Error, cannot create label class map. Passed segmentation is nullptr."; if (!segmentation->ExistGroup(groupID)) mitkThrow() << "Error, cannot create label class map. GroupID is invalid. Invalid ID: " << groupID; auto map = mitk::Image::New(); // map->Initialize(segmentation) does not work here if this label set image has a single slice, // since the map would be automatically flattened to a 2-d image, whereas we expect the // original dimension of this label set image. Hence, initialize the map more explicitly: map->Initialize(segmentation->GetPixelType(), segmentation->GetDimension(), segmentation->GetDimensions()); map->SetTimeGeometry(segmentation->GetTimeGeometry()->Clone()); ClearImageBuffer(map); // get relevant labels (as intersect of groupLabels and selectedLabels auto groupValues = segmentation->GetLabelValuesByGroup(groupID); LabelSetImage::LabelValueVectorType relevantGroupValues = std::accumulate(groupValues.begin(), groupValues.end(), LabelSetImage::LabelValueVectorType(), [&selectedLabels](LabelSetImage::LabelValueVectorType& result, LabelSetImage::LabelValueType element) { if (std::find(selectedLabels.begin(), selectedLabels.end(), element) != selectedLabels.end()) { result.push_back(element); } return result; }); // construct class mapping auto classToValueMap = LabelSetImageHelper::SplitLabelValuesByClassNamwe(segmentation, groupID, relevantGroupValues); ConstLabelVector destLabels; LabelValueMappingVector transferMapping; IDToLabelClassNameMapType classLookUp; for (const auto& [className, labelValues] : classToValueMap) { LabelSetImage::LabelValueType classValue = classLookUp.size() + 1; classLookUp.insert(std::make_pair(classValue, className)); destLabels.push_back(Label::New(classValue, className)); for (const auto& labelValue : labelValues) { transferMapping.emplace_back(std::make_pair(labelValue, classValue)); } } TransferLabelContent(segmentation->GetGroupImage(groupID), map.GetPointer(), destLabels, LabelSetImage::UNLABELED_VALUE, LabelSetImage::UNLABELED_VALUE, false, transferMapping, MultiLabelSegmentation::MergeStyle::Replace, MultiLabelSegmentation::OverwriteStyle::IgnoreLocks); return std::make_pair(map, classLookUp); } std::pair mitk::CreateLabelClassMap(const LabelSetImage* segmentation, LabelSetImage::GroupIndexType groupID) { return CreateLabelClassMap(segmentation, groupID, segmentation->GetLabelValuesByGroup(groupID)); } diff --git a/Modules/Multilabel/mitkLabelSetImageHelper.cpp b/Modules/Multilabel/mitkLabelSetImageHelper.cpp index 0b479c367d..ef69a6848d 100644 --- a/Modules/Multilabel/mitkLabelSetImageHelper.cpp +++ b/Modules/Multilabel/mitkLabelSetImageHelper.cpp @@ -1,194 +1,197 @@ /*============================================================================ 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 #include #include #include #include #include namespace { template std::array QuantizeColor(const T* color) { return { static_cast(std::round(color[0] * 255)), static_cast(std::round(color[1] * 255)), static_cast(std::round(color[2] * 255)) }; } mitk::Color FromLookupTableColor(const double* lookupTableColor) { mitk::Color color; color.Set( static_cast(lookupTableColor[0]), static_cast(lookupTableColor[1]), static_cast(lookupTableColor[2])); return color; } } mitk::DataNode::Pointer mitk::LabelSetImageHelper::CreateEmptySegmentationNode(const std::string& segmentationName) { auto newSegmentationNode = mitk::DataNode::New(); newSegmentationNode->SetName(segmentationName); // initialize "showVolume"-property to false to prevent recalculating the volume while working on the segmentation newSegmentationNode->SetProperty("showVolume", mitk::BoolProperty::New(false)); return newSegmentationNode; } mitk::DataNode::Pointer mitk::LabelSetImageHelper::CreateNewSegmentationNode(const DataNode* referenceNode, const Image* initialSegmentationImage, const std::string& segmentationName) { std::string newSegmentationName = segmentationName; if (newSegmentationName.empty()) { newSegmentationName = referenceNode->GetName(); newSegmentationName.append("-labels"); } if (nullptr == initialSegmentationImage) { return nullptr; } auto newLabelSetImage = mitk::LabelSetImage::New(); try { newLabelSetImage->Initialize(initialSegmentationImage); } catch (mitk::Exception &e) { mitkReThrow(e) << "Could not initialize new label set image."; return nullptr; } auto newSegmentationNode = CreateEmptySegmentationNode(newSegmentationName); newSegmentationNode->SetData(newLabelSetImage); return newSegmentationNode; } mitk::Label::Pointer mitk::LabelSetImageHelper::CreateNewLabel(const LabelSetImage* labelSetImage, const std::string& namePrefix, bool hideIDIfUnique) { if (nullptr == labelSetImage) return nullptr; const std::regex genericLabelNameRegEx(namePrefix + " ([1-9][0-9]*)"); int maxGenericLabelNumber = 0; std::vector> colorsInUse = { {0,0,0} }; //black is always in use. for (auto & label : labelSetImage->GetLabels()) { auto labelName = label->GetName(); std::smatch match; if (std::regex_match(labelName, match, genericLabelNameRegEx)) maxGenericLabelNumber = std::max(maxGenericLabelNumber, std::stoi(match[1].str())); const auto quantizedLabelColor = QuantizeColor(label->GetColor().data()); if (std::find(colorsInUse.begin(), colorsInUse.end(), quantizedLabelColor) == std::end(colorsInUse)) colorsInUse.push_back(quantizedLabelColor); } auto newLabel = mitk::Label::New(); if (hideIDIfUnique && 0==maxGenericLabelNumber) newLabel->SetName(namePrefix); else newLabel->SetName(namePrefix + " " + std::to_string(maxGenericLabelNumber + 1)); auto lookupTable = mitk::LookupTable::New(); lookupTable->SetType(mitk::LookupTable::LookupTableType::MULTILABEL); std::array lookupTableColor; const int maxTries = 25; bool newColorFound = false; for (int i = 0; i < maxTries; ++i) { lookupTable->GetColor(i, lookupTableColor.data()); auto quantizedLookupTableColor = QuantizeColor(lookupTableColor.data()); if (std::find(colorsInUse.begin(), colorsInUse.end(), quantizedLookupTableColor) == std::end(colorsInUse)) { newLabel->SetColor(FromLookupTableColor(lookupTableColor.data())); newColorFound = true; break; } } if (!newColorFound) { lookupTable->GetColor(labelSetImage->GetTotalNumberOfLabels(), lookupTableColor.data()); newLabel->SetColor(FromLookupTableColor(lookupTableColor.data())); } return newLabel; } mitk::LabelSetImageHelper::GroupIDToLabelValueMapType mitk::LabelSetImageHelper::SplitLabelValuesByGroup(const LabelSetImage* labelSetImage, const LabelSetImage::LabelValueVectorType& labelValues) { if (nullptr == labelSetImage) mitkThrow() << "Cannot split label values. Invalid LabelSetImage pointer passed"; GroupIDToLabelValueMapType result; for (auto value : labelValues) { auto groupID = labelSetImage->GetGroupIndexOfLabel(value); - auto& values = result[groupID]; //if groupID does not exist in result this call will init an empty vector. + //if groupID does not exist in result this call will also init an empty vector. result[groupID].push_back(value); } return result; } mitk::LabelSetImageHelper::LabelClassNameToLabelValueMapType mitk::LabelSetImageHelper::SplitLabelValuesByClassNamwe(const LabelSetImage* labelSetImage, LabelSetImage::GroupIndexType groupID) { if (nullptr == labelSetImage) mitkThrow() << "Cannot split label values. Invalid LabelSetImage pointer passed"; return SplitLabelValuesByClassNamwe(labelSetImage, groupID, labelSetImage->GetLabelValuesByGroup(groupID)); } mitk::LabelSetImageHelper::LabelClassNameToLabelValueMapType mitk::LabelSetImageHelper::SplitLabelValuesByClassNamwe(const LabelSetImage* labelSetImage, LabelSetImage::GroupIndexType groupID, const LabelSetImage::LabelValueVectorType& labelValues) { if (nullptr == labelSetImage) mitkThrow() << "Cannot split label values. Invalid LabelSetImage pointer passed"; LabelClassNameToLabelValueMapType result; for (auto value : labelValues) { - auto className = labelSetImage->GetLabel(value)->GetName(); + if (labelSetImage->GetGroupIndexOfLabel(value) == groupID) + { + auto className = labelSetImage->GetLabel(value)->GetName(); - auto& values = result[className]; //if className does not exist in result this call will init an empty vector. - result[className].push_back(value); + //if className does not exist in result this call will also init an empty vector. + result[className].push_back(value); + } } return result; } diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkConvertToMultiLabelSegmentationWidget.cpp b/Modules/SegmentationUI/SegmentationUtilities/QmitkConvertToMultiLabelSegmentationWidget.cpp index 7ca357ec74..003a20a37a 100644 --- a/Modules/SegmentationUI/SegmentationUtilities/QmitkConvertToMultiLabelSegmentationWidget.cpp +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkConvertToMultiLabelSegmentationWidget.cpp @@ -1,545 +1,543 @@ /*============================================================================ 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 #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 = nullptr; for (auto& node : nodes) { auto castedData = dynamic_cast(node->GetData()); if (castedData != nullptr) { if (refGeometry.IsNull() || mitk::IsSubGeometry(*refGeometry, *(castedData->GetGeometry()), mitk::NODE_PREDICATE_GEOMETRY_DEFAULT_CHECK_COORDINATE_PRECISION, mitk::NODE_PREDICATE_GEOMETRY_DEFAULT_CHECK_DIRECTION_PRECISION)) { 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::NodePredicateSubGeometry::Pointer geoPredicate; bool usedExternalGeo = false; std::string refNodeName; if (refNodeLambda.IsNotNull() && nullptr != refNodeLambda->GetData()) { geoPredicate = mitk::NodePredicateSubGeometry::New(refNodeLambda->GetData()->GetGeometry()); usedExternalGeo = true; refNodeName = refNodeLambda->GetName(); } if (geoPredicate.IsNull()) { auto imageNode = GetNodeWithLargestImageGeometry(nodes); if (nullptr != imageNode) { geoPredicate = mitk::NodePredicateSubGeometry::New(imageNode->GetData()->GetGeometry()); refNodeName = imageNode->GetName(); } } 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(); }); + m_Controls->outputSegSelector, [widget](bool) {widget->ConfigureWidgets(); }); connect(m_Controls->checkMultipleOutputs, &QCheckBox::toggled, - m_Controls->outputSegSelector, [widget](bool checked) {widget->ConfigureWidgets(); }); + m_Controls->outputSegSelector, [widget](bool) {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)); } else { m_Controls->inputNodesSelector->SetSelectionCheckFunction(CheckForSameGeometry(nullptr)); } 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->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::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 index dd3773ed72..cadb8c7f7f 100644 --- a/Modules/SegmentationUI/SegmentationUtilities/QmitkExtractFromMultiLabelSegmentationWidget.cpp +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkExtractFromMultiLabelSegmentationWidget.cpp @@ -1,158 +1,158 @@ /*============================================================================ 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->labelInspector->SetMultiSelectionMode(true); 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(); }); + this, [widget](bool) {widget->ConfigureWidgets(); }); connect(m_Controls->checkClassMap, &QCheckBox::toggled, - this, [widget](bool checked) {widget->ConfigureWidgets(); }); + this, [widget](bool) {widget->ConfigureWidgets(); }); connect(m_Controls->checkInstanceMask, &QCheckBox::toggled, - this, [widget](bool checked) {widget->ConfigureWidgets(); }); + this, [widget](bool) {widget->ConfigureWidgets(); }); connect(m_Controls->checkExtractSelected, &QCheckBox::toggled, - this, [widget](bool checked) {widget->ConfigureWidgets(); }); + this, [widget](bool) {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->GetGroupImageWorkarround(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,false); 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/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationUtilitiesView.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationUtilitiesView.cpp index c4eea174db..64449df9fd 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationUtilitiesView.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationUtilitiesView.cpp @@ -1,68 +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_ExtractFromSegWidget(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 a98c701d11..cbbc5d7504 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationUtilitiesView.h +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationUtilitiesView.h @@ -1,51 +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; + QmitkExtractFromMultiLabelSegmentationWidget* m_ExtractFromSegWidget; }; #endif