diff --git a/Modules/Multilabel/mitkLabelSetImageConverter.cpp b/Modules/Multilabel/mitkLabelSetImageConverter.cpp index 8486db5c76..a6ca60fa02 100644 --- a/Modules/Multilabel/mitkLabelSetImageConverter.cpp +++ b/Modules/Multilabel/mitkLabelSetImageConverter.cpp @@ -1,145 +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 #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(); auto activeLayer = labelSetImage->GetActiveLayer(); for (decltype(numberOfLayers) layer = 0; layer < numberOfLayers; ++layer) { auto layerImage = mitk::ImageToItkImage( layer != activeLayer ? labelSetImage->GetLayerImage(layer) : labelSetImage); 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->GetLayerImage(0), ::ConvertLabelSetImageToImage, labelSetImage, image); } image->SetTimeGeometry(labelSetImage->GetTimeGeometry()->Clone()); } return image; } + template -static void ConvertImageToLabelSetImage(const itk::VectorImage *image, - mitk::LabelSetImage::Pointer &labelSetImage) +static void SplitVectorImage(const itk::VectorImage* image, + std::vector& result) { typedef itk::VectorImage VectorImageType; typedef itk::Image ImageType; typedef itk::VectorIndexSelectionCastImageFilter VectorIndexSelectorType; - labelSetImage = mitk::LabelSetImage::New(); - 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::CastToMitkImage(layerSelector->GetOutput(), layerImage); + mitk::Image::Pointer layerImage = mitk::GrabItkImageMemory(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 (layer == 0) + if (image.IsNotNull()) + { + if (image->GetChannelDescriptor().GetPixelType().GetPixelType() == itk::IOPixelEnum::VECTOR) { - labelSetImage->InitializeByLabeledImage(layerImage); + groupImages = SplitVectorImage(image); } else { - labelSetImage->AddLayer(layerImage); + groupImages.push_back(image); } } + auto labelSetImage = ConvertImageVectorToLabelSetImage(groupImages, image->GetTimeGeometry()); + + return labelSetImage; } -mitk::LabelSetImage::Pointer mitk::ConvertImageToLabelSetImage(Image::Pointer image) +mitk::LabelSetImage::Pointer mitk::ConvertImageVectorToLabelSetImage(const std::vector& images, const mitk::TimeGeometry* timeGeometry) { - LabelSetImage::Pointer labelSetImage; + LabelSetImage::Pointer labelSetImage = mitk::LabelSetImage::New(); - if (image.IsNotNull()) + for (auto& groupImage : images) { - if (image->GetChannelDescriptor().GetPixelType().GetPixelType() == itk::IOPixelEnum::VECTOR) + if (groupImage== images.front()) { - if (4 == image->GetDimension()) - { - AccessVectorFixedDimensionByItk_n(image, ::ConvertImageToLabelSetImage, 4, (labelSetImage)); - } - else - { - AccessVectorPixelTypeByItk_n(image, ::ConvertImageToLabelSetImage, (labelSetImage)); - } + labelSetImage->InitializeByLabeledImage(groupImage); } else { - labelSetImage = mitk::LabelSetImage::New(); - labelSetImage->InitializeByLabeledImage(image); + labelSetImage->AddLayer(groupImage); } - labelSetImage->SetTimeGeometry(image->GetTimeGeometry()->Clone()); } + labelSetImage->SetTimeGeometry(timeGeometry->Clone()); return labelSetImage; } + +mitk::LabelSet::Pointer mitk::GenerateLabelSetWithMappedValues(const LabelSet* sourceLabelset, std::vector > labelMapping) +{ + if (nullptr == sourceLabelset) + { + mitkThrow() << "Invalid usage; nullptr passed as labelset to GenerateLabelSetWithMappedValues."; + } + + auto result = LabelSet::New(); + + for (auto [sourceLabelID, destLabelID] : labelMapping) + { + auto clonedLabel = sourceLabelset->GetLabel(sourceLabelID)->Clone(); + clonedLabel->SetValue(destLabelID); + result->AddLabel(clonedLabel, false); + } + + return result; +} diff --git a/Modules/Multilabel/mitkLabelSetImageConverter.h b/Modules/Multilabel/mitkLabelSetImageConverter.h index 0677c4b5db..1e1b577d79 100644 --- a/Modules/Multilabel/mitkLabelSetImageConverter.h +++ b/Modules/Multilabel/mitkLabelSetImageConverter.h @@ -1,32 +1,40 @@ /*============================================================================ 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 mitkLabelSetImageConverter_h #define mitkLabelSetImageConverter_h #include namespace mitk { /** * \brief Convert mitk::LabelSetImage to mitk::Image (itk::VectorImage) */ MITKMULTILABEL_EXPORT Image::Pointer ConvertLabelSetImageToImage(LabelSetImage::ConstPointer labelSetImage); /** * \brief Convert mitk::Image to mitk::LabelSetImage, templating and differentation between itk::Image and * itk::VectorImage is internal */ MITKMULTILABEL_EXPORT LabelSetImage::Pointer ConvertImageToLabelSetImage(Image::Pointer image); + MITKMULTILABEL_EXPORT LabelSetImage::Pointer ConvertImageVectorToLabelSetImage(const std::vector& images, const TimeGeometry* timeGeometry); + + MITKMULTILABEL_EXPORT std::vector SplitVectorImage(const Image* vecImage); + + /** Function takes a label set and transfers all labels indicated in the label mapping (first element of pair) into a result label set. In the result label set + the cloned labels will have the label value indicated by the mapping (second element of pair). + @remark: Only labels will be transfered, nothing else. So things like message observers or m_ReservedLabelValuesFunctor must be copied explicitly.*/ + MITKMULTILABEL_EXPORT LabelSet::Pointer GenerateLabelSetWithMappedValues(const LabelSet* sourceLabelset, std::vector > labelMapping); } #endif diff --git a/Modules/Multilabel/mitkMultiLabelIOHelper.h b/Modules/Multilabel/mitkMultiLabelIOHelper.h index f9d3976ed6..a3bd60abf9 100644 --- a/Modules/Multilabel/mitkMultiLabelIOHelper.h +++ b/Modules/Multilabel/mitkMultiLabelIOHelper.h @@ -1,98 +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. ============================================================================*/ #ifndef mitkMultiLabelIOHelper_h #define mitkMultiLabelIOHelper_h +#include #include #include namespace tinyxml2 { class XMLDocument; class XMLElement; } namespace mitk { class BaseProperty; class LabelSetImage; class Label; + constexpr char* const PROPERTY_NAME_TIMEGEOMETRY_TYPE = "org.mitk.timegeometry.type"; + constexpr char* const PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS = "org.mitk.timegeometry.timepoints"; + constexpr char* const PROPERTY_KEY_TIMEGEOMETRY_TYPE = "org_mitk_timegeometry_type"; + constexpr char* const PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS = "org_mitk_timegeometry_timepoints"; + constexpr char* const PROPERTY_KEY_UID = "org_mitk_uid"; + /** * @brief The MultiLabelIOHelper is a static helper class that supports serialization of mitk::LabelSetImage * * This class provides static functions for converting mitk::Label into XML and also allows the serialization * of mitk::LabelSet as presets */ class MITKMULTILABEL_EXPORT MultiLabelIOHelper { public: /** * @brief Saves the mitk::LabelSet configuration of inputImage to presetFilename. * The preset is stored as "*.lsetp" * @param presetFilename the filename including the filesystem path * @param inputImage the input image from which the preset should be generated * @return true if the serialization was successful and false otherwise */ static bool SaveLabelSetImagePreset(const std::string &presetFilename, const mitk::LabelSetImage *inputImage); /** * @brief Loads an existing preset for a mitk::LabelSetImage from presetFilename and applies it to inputImage * @param presetFilename the filename of the preset including the filesystem path * @param inputImage the image to which the loaded preset will be applied * @return true if the deserilization was successful and false otherwise */ static bool LoadLabelSetImagePreset(const std::string &presetFilename, mitk::LabelSetImage *inputImage); /** * @brief Creates a mitk::Label from an XML element * @param labelElem the xml element from which a mitk::Label will be created * @return the created mitk::Label */ static itk::SmartPointer LoadLabelFromXMLDocument(const tinyxml2::XMLElement *labelElem); /** * @brief Creates an XML element from a mitk::Label * @param doc * @param label the mitk::Label from which the xml element will be created * @return the created XML element */ static tinyxml2::XMLElement *GetLabelAsXMLElement(tinyxml2::XMLDocument &doc, Label *label); /** * @brief Since a mitk::Label is basically a mitk::PropertyList this function coverts the label's properties into * XML * @param doc * @param key the property's key which will be used in the XML element * @param property the mitk::BaseProperty that should be converted * @return the created XML element */ static tinyxml2::XMLElement *PropertyToXMLElement(tinyxml2::XMLDocument& doc, const std::string &key, const BaseProperty *property); /** * @brief Since a mitk::Label is basically a mitk::PropertyList this function coverts a XML element into a property * @param key the property's key * @param prop the mitk::BaseProperty that will be created * @param elem the XML elem from which the property will be created * @return true if the conversion was successful and false otherwise */ static bool PropertyFromXMLElement(std::string &key, itk::SmartPointer &prop, const tinyxml2::XMLElement *elem); private: MultiLabelIOHelper(); }; } #endif