diff --git a/Modules/Multilabel/mitkLabelSetIOHelper.cpp b/Modules/Multilabel/mitkLabelSetIOHelper.cpp index 0106aa2fb0..6c9758199d 100644 --- a/Modules/Multilabel/mitkLabelSetIOHelper.cpp +++ b/Modules/Multilabel/mitkLabelSetIOHelper.cpp @@ -1,226 +1,233 @@ /*============================================================================ 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 "mitkLabelSetIOHelper.h" #include "mitkLabelSetImage.h" #include #include -bool mitk::LabelSetIOHelper::SaveLabelSetImagePreset(std::string &presetFilename, - mitk::LabelSetImage::Pointer &inputImage) +namespace { - if (presetFilename.find(".lsetp") == std::string::npos) + std::string EnsureExtension(const std::string& filename) { - presetFilename.append(".lsetp"); + const std::string extension = ".lsetp"; + + if (filename.size() < extension.size() || std::string::npos == filename.find(extension, filename.size() - extension.size())) + return filename + extension; + + return filename; } +} + +bool mitk::LabelSetIOHelper::SaveLabelSetImagePreset(const std::string &presetFilename, + mitk::LabelSetImage::Pointer &inputImage) +{ + const auto filename = EnsureExtension(presetFilename); auto *presetXmlDoc = new TiXmlDocument(); auto *decl = new TiXmlDeclaration("1.0", "", ""); presetXmlDoc->LinkEndChild(decl); auto *presetElement = new TiXmlElement("LabelSetImagePreset"); presetElement->SetAttribute("layers", inputImage->GetNumberOfLayers()); presetXmlDoc->LinkEndChild(presetElement); for (unsigned int layerIdx = 0; layerIdx < inputImage->GetNumberOfLayers(); layerIdx++) { auto *layerElement = new TiXmlElement("Layer"); layerElement->SetAttribute("index", layerIdx); layerElement->SetAttribute("labels", inputImage->GetNumberOfLabels(layerIdx)); presetElement->LinkEndChild(layerElement); for (unsigned int labelIdx = 0; labelIdx < inputImage->GetNumberOfLabels(layerIdx); labelIdx++) { TiXmlElement *labelAsXml = LabelSetIOHelper::GetLabelAsTiXmlElement(inputImage->GetLabel(labelIdx, layerIdx)); layerElement->LinkEndChild(labelAsXml); } } - bool wasSaved = presetXmlDoc->SaveFile(presetFilename); + bool wasSaved = presetXmlDoc->SaveFile(filename); delete presetXmlDoc; return wasSaved; } -void mitk::LabelSetIOHelper::LoadLabelSetImagePreset(std::string &presetFilename, +void mitk::LabelSetIOHelper::LoadLabelSetImagePreset(const std::string &presetFilename, mitk::LabelSetImage::Pointer &inputImage) { - if (presetFilename.find(".lsetp") == std::string::npos) - { - presetFilename.append(".lsetp"); - } + const auto filename = EnsureExtension(presetFilename); std::unique_ptr presetXmlDoc(new TiXmlDocument()); - bool ok = presetXmlDoc->LoadFile(presetFilename); + bool ok = presetXmlDoc->LoadFile(filename); if (!ok) return; TiXmlElement *presetElem = presetXmlDoc->FirstChildElement("LabelSetImagePreset"); if (!presetElem) { MITK_INFO << "No valid preset XML"; return; } int numberOfLayers; presetElem->QueryIntAttribute("layers", &numberOfLayers); for (int i = 0; i < numberOfLayers; i++) { TiXmlElement *layerElem = presetElem->FirstChildElement("Layer"); int numberOfLabels; layerElem->QueryIntAttribute("labels", &numberOfLabels); if (inputImage->GetLabelSet(i) == nullptr) inputImage->AddLayer(); TiXmlElement *labelElement = layerElem->FirstChildElement("Label"); if (labelElement == nullptr) break; for (int j = 0; j < numberOfLabels; j++) { mitk::Label::Pointer label = mitk::LabelSetIOHelper::LoadLabelFromTiXmlDocument(labelElement); if (label->GetValue() == 0) inputImage->SetExteriorLabel(label); else inputImage->GetLabelSet()->AddLabel(label); labelElement = labelElement->NextSiblingElement("Label"); if (labelElement == nullptr) break; } } } TiXmlElement *mitk::LabelSetIOHelper::GetLabelAsTiXmlElement(Label *label) { auto *labelElem = new TiXmlElement("Label"); // add XML contents const PropertyList::PropertyMap *propmap = label->GetMap(); for (auto iter = propmap->begin(); iter != propmap->end(); ++iter) { std::string key = iter->first; const BaseProperty *property = iter->second; TiXmlElement *element = PropertyToXmlElem(key, property); if (element) labelElem->LinkEndChild(element); } return labelElem; } mitk::Label::Pointer mitk::LabelSetIOHelper::LoadLabelFromTiXmlDocument(TiXmlElement *labelElem) { // reread TiXmlElement *propElem = labelElem->FirstChildElement("property"); std::string name; mitk::BaseProperty::Pointer prop; mitk::Label::Pointer label = mitk::Label::New(); while (propElem) { LabelSetIOHelper::PropertyFromXmlElem(name, prop, propElem); label->SetProperty(name, prop); propElem = propElem->NextSiblingElement("property"); } return label.GetPointer(); } TiXmlElement *mitk::LabelSetIOHelper::PropertyToXmlElem(const std::string &key, const BaseProperty *property) { auto *keyelement = new TiXmlElement("property"); keyelement->SetAttribute("key", key); keyelement->SetAttribute("type", property->GetNameOfClass()); // construct name of serializer class std::string serializername(property->GetNameOfClass()); serializername += "Serializer"; std::list allSerializers = itk::ObjectFactoryBase::CreateAllInstance(serializername.c_str()); if (allSerializers.size() < 1) MITK_ERROR << "No serializer found for " << property->GetNameOfClass() << ". Skipping object"; if (allSerializers.size() > 1) MITK_WARN << "Multiple serializers found for " << property->GetNameOfClass() << "Using arbitrarily the first one."; for (auto iter = allSerializers.begin(); iter != allSerializers.end(); ++iter) { if (auto *serializer = dynamic_cast(iter->GetPointer())) { serializer->SetProperty(property); try { TiXmlElement *valueelement = serializer->Serialize(); if (valueelement) keyelement->LinkEndChild(valueelement); } catch (std::exception &e) { MITK_ERROR << "Serializer " << serializer->GetNameOfClass() << " failed: " << e.what(); } break; } } return keyelement; } bool mitk::LabelSetIOHelper::PropertyFromXmlElem(std::string &key, mitk::BaseProperty::Pointer &prop, TiXmlElement *elem) { std::string type; elem->QueryStringAttribute("type", &type); elem->QueryStringAttribute("key", &key); // construct name of serializer class std::string serializername(type); serializername += "Serializer"; std::list allSerializers = itk::ObjectFactoryBase::CreateAllInstance(serializername.c_str()); if (allSerializers.size() < 1) MITK_ERROR << "No serializer found for " << type << ". Skipping object"; if (allSerializers.size() > 1) MITK_WARN << "Multiple deserializers found for " << type << "Using arbitrarily the first one."; for (auto iter = allSerializers.begin(); iter != allSerializers.end(); ++iter) { if (auto *serializer = dynamic_cast(iter->GetPointer())) { try { prop = serializer->Deserialize(elem->FirstChildElement()); } catch (std::exception &e) { MITK_ERROR << "Deserializer " << serializer->GetNameOfClass() << " failed: " << e.what(); return false; } break; } } if (prop.IsNull()) return false; return true; } diff --git a/Modules/Multilabel/mitkLabelSetIOHelper.h b/Modules/Multilabel/mitkLabelSetIOHelper.h index ff763d61fd..3800fda33a 100644 --- a/Modules/Multilabel/mitkLabelSetIOHelper.h +++ b/Modules/Multilabel/mitkLabelSetIOHelper.h @@ -1,91 +1,91 @@ /*============================================================================ 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 __mitkLabelSetIOHelper_h #define __mitkLabelSetIOHelper_h #include #include class TiXmlElement; namespace mitk { class BaseProperty; class LabelSetImage; class Label; /** * @brief The LabelSetIOHelper 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 LabelSetIOHelper { 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(std::string &presetFilename, + static bool SaveLabelSetImagePreset(const std::string &presetFilename, itk::SmartPointer &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 */ - static void LoadLabelSetImagePreset(std::string &presetFilename, + static void LoadLabelSetImagePreset(const std::string &presetFilename, itk::SmartPointer &inputImage); /** * @brief Creates a mitk::Label from a TiXmlElement * @param labelElem the xml element from which a mitk::Label will be created * @return the created mitk::Label */ static itk::SmartPointer LoadLabelFromTiXmlDocument(TiXmlElement *labelElem); /** * @brief Creates a TiXmlElement from a mitk::Label * @param label the mitk::Label from which the xml element will be created * @return the created TiXmlElement */ static TiXmlElement *GetLabelAsTiXmlElement(Label *label); /** * @brief Since a mitk::Label is basically a mitk::PropertyList this function coverts the label's properties into * XML * @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 TiXmlElement */ static TiXmlElement *PropertyToXmlElem(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 PropertyFromXmlElem(std::string &key, itk::SmartPointer &prop, TiXmlElement *elem); private: LabelSetIOHelper(); }; } #endif // __mitkLabelSetIOHelper_h