diff --git a/Modules/Multilabel/mitkLabelSetImageHelper.cpp b/Modules/Multilabel/mitkLabelSetImageHelper.cpp index 8b4eaed591..0e46068ab6 100644 --- a/Modules/Multilabel/mitkLabelSetImageHelper.cpp +++ b/Modules/Multilabel/mitkLabelSetImageHelper.cpp @@ -1,77 +1,149 @@ /*============================================================================ 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::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 = mitk::DataNode::New(); newSegmentationNode->SetData(newLabelSetImage); newSegmentationNode->SetName(newSegmentationName); // set additional image information newLabelSetImage->GetExteriorLabel()->SetProperty("name.parent", mitk::StringProperty::New(referenceNode->GetName())); newLabelSetImage->GetExteriorLabel()->SetProperty("name.image", mitk::StringProperty::New(newSegmentationName)); // 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::Label::Pointer mitk::LabelSetImageHelper::CreateNewLabel(const LabelSetImage* labelSetImage) { - int numberOfLabels = labelSetImage->GetActiveLabelSet()->GetNumberOfLabels(); + if (nullptr == labelSetImage) + return nullptr; + + const std::regex genericLabelNameRegEx("New label ([1-9][0-9]*)"); + int maxGenericLabelNumber = 0; + + std::vector> colorsInUse; + + const auto numLabelSets = labelSetImage->GetNumberOfLayers(); + + for (std::remove_const_t i = 0; i < numLabelSets; ++i) + { + auto labelSet = labelSetImage->GetLabelSet(i); + auto labelEndIter = labelSet->IteratorConstEnd(); - std::string labelName = "New label " + std::to_string(numberOfLabels); + for (auto labelIter = labelSet->IteratorConstBegin(); labelIter != labelEndIter; ++labelIter) + { + auto label = labelIter->second; + auto labelName = labelIter->second->GetName(); + std::smatch match; - mitk::LookupTable::Pointer lookupTable = mitk::LookupTable::New(); + 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(); + newLabel->SetName("New label " + std::to_string(maxGenericLabelNumber + 1)); + + auto lookupTable = mitk::LookupTable::New(); lookupTable->SetType(mitk::LookupTable::LookupTableType::MULTILABEL); - double rgb[3]; - lookupTable->GetColor(numberOfLabels, rgb); - mitk::Color labelColor; - labelColor.Set(static_cast(rgb[0]), static_cast(rgb[1]), static_cast(rgb[2])); - - mitk::Label::Pointer newLabel = mitk::Label::New(); - newLabel->SetName(labelName); - newLabel->SetColor(labelColor); + + 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; } diff --git a/Modules/Multilabel/mitkLabelSetImageHelper.h b/Modules/Multilabel/mitkLabelSetImageHelper.h index 44c6fc4187..ddcdfa39ab 100644 --- a/Modules/Multilabel/mitkLabelSetImageHelper.h +++ b/Modules/Multilabel/mitkLabelSetImageHelper.h @@ -1,60 +1,59 @@ /*============================================================================ 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 MITKLABELSETIMAGEHELPER_H #define MITKLABELSETIMAGEHELPER_H #include #include #include namespace mitk { /** * */ namespace LabelSetImageHelper { /** * @brief This function creates and returns a new data node containing the given image as data. * The segmentation node is named according to the given reference data node. * Some properties are set to automatically link the segmentation node with its parent node. * * @param referenceNode The reference node from which the name of the new segmentation node * is derived. * @param initialSegmentationImage The segmentation image that is used to initialize the label set image. * @param segmentationName An optional name for the new segmentation node. * * @return The new segmentation node as a data node pointer. */ MITKMULTILABEL_EXPORT mitk::DataNode::Pointer CreateNewSegmentationNode(const DataNode* referenceNode, const Image* initialSegmentationImage = nullptr, const std::string& segmentationName = std::string()); /** - * @brief This function creates and returns a new label. The label is automatically assigned a - * label name, depending on the current number of labels of the active label set of the + * @brief This function creates and returns a new label. The label is automatically assigned an + * unused generic label name, depending on existing label names in all label sets of the * given label set image. - * The color of the label is derived from the MULTILABEL lookup table, depending on the - * number of labels. + * The color of the label is selected from the MULTILABEL lookup table, following the same + * rules of the naming to likely chose a unique color. * - * @param labelSetImage The label set image from which the number of labels of the active label - * set is derived. + * @param labelSetImage The label set image that the new label is added to * - * @return The new labe as a pointer. + * @return The new label. */ MITKMULTILABEL_EXPORT mitk::Label::Pointer CreateNewLabel(const LabelSetImage* labelSetImage); } // namespace LabelSetImageHelper } // namespace mitk #endif // MITKLABELSETIMAGEHELPER_H