diff --git a/Modules/CEST/autoload/IO/CMakeLists.txt b/Modules/CEST/autoload/IO/CMakeLists.txt index cb10fda5b5..0e9e46ddbb 100644 --- a/Modules/CEST/autoload/IO/CMakeLists.txt +++ b/Modules/CEST/autoload/IO/CMakeLists.txt @@ -1,6 +1,6 @@ MITK_CREATE_MODULE( CESTIO DEPENDS MitkCEST MitkDICOMReader PACKAGE_DEPENDS PRIVATE ITK|ITKIOGDCM - AUTOLOAD_WITH MitkCore + AUTOLOAD_WITH MitkDICOMReader ) diff --git a/Modules/CEST/autoload/IO/mitkCESTGenericDICOMReaderService.cpp b/Modules/CEST/autoload/IO/mitkCESTGenericDICOMReaderService.cpp index 7181193335..4c84f976c1 100644 --- a/Modules/CEST/autoload/IO/mitkCESTGenericDICOMReaderService.cpp +++ b/Modules/CEST/autoload/IO/mitkCESTGenericDICOMReaderService.cpp @@ -1,294 +1,397 @@ /*============================================================================ 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 "mitkCESTGenericDICOMReaderService.h" #include "mitkIOMimeTypes.h" #include #include #include #include #include +#include + #include "mitkCESTImageNormalizationFilter.h" #include "itksys/SystemTools.hxx" #include #include #include #include #include namespace mitk { + DICOMTagPath DICOM_IMAGING_FREQUENCY_PATH() + { + return mitk::DICOMTagPath(0x0018, 0x0084); + } + + std::string OPTION_NAME_B1() + { + return "B1 amplitude"; + }; + + std::string OPTION_NAME_PULSE() + { + return "Pulse duration [us]"; + }; + + std::string OPTION_NAME_DC() + { + return "Duty cycle [%]"; + }; + + std::string OPTION_NAME_NORMALIZE() + { + return "Normalize data"; + }; + + std::string OPTION_NAME_NORMALIZE_AUTOMATIC() + { + return "Automatic"; + }; + + std::string OPTION_NAME_NORMALIZE_NO() + { + return "No"; + }; + + std::string OPTION_NAME_MERGE() + { + return "Merge all series"; + }; + + std::string OPTION_NAME_MERGE_YES() + { + return "Yes"; + }; + + std::string OPTION_NAME_MERGE_NO() + { + return "No"; + }; + CESTDICOMManualReaderService::CESTDICOMManualReaderService(const CustomMimeType& mimeType, const std::string& description) : BaseDICOMReaderService(mimeType, description) { IFileIO::Options options; - options["B1 amplitude"] = 0.0; - options["CEST frequency [Hz]"] = 0.0; - options["Pulse duration [us]"] = 0.0; - options["Duty cycle [%]"] = 0.0; + options[OPTION_NAME_B1().c_str()] = 0.0; + options[OPTION_NAME_PULSE().c_str()] = 0.0; + options[OPTION_NAME_DC().c_str()] = 0.0; std::vector normalizationStrategy; - normalizationStrategy.push_back("Automatic"); - normalizationStrategy.push_back("No"); - options["Normalize data"] = normalizationStrategy; - + normalizationStrategy.push_back(OPTION_NAME_NORMALIZE_AUTOMATIC().c_str()); + normalizationStrategy.push_back(OPTION_NAME_NORMALIZE_NO().c_str()); + options[OPTION_NAME_NORMALIZE().c_str()] = normalizationStrategy; + std::vector mergeStrategy; + mergeStrategy.push_back(OPTION_NAME_MERGE_NO().c_str()); + mergeStrategy.push_back(OPTION_NAME_MERGE_YES().c_str()); + options[OPTION_NAME_MERGE().c_str()] = mergeStrategy; this->SetDefaultOptions(options); this->RegisterService(); } CESTDICOMManualReaderService::CESTDICOMManualReaderService(const mitk::CESTDICOMManualReaderService& other) : BaseDICOMReaderService(other) { } void ExtractOptionFromPropertyTree(const std::string& key, boost::property_tree::ptree& root, std::map& options) { auto finding = root.find(key); if (finding != root.not_found()) { - options[key] = finding->second.get_value(); + try + { + options[key] = finding->second.get_value(); + } + catch (const boost::property_tree::ptree_bad_data & /*e*/) + { + options[key] = finding->second.get_value(); + } } } IFileIO::Options ExtractOptionsFromFile(const std::string& file) { boost::property_tree::ptree root; if (itksys::SystemTools::FileExists(file)) { try { boost::property_tree::read_json(file, root, std::locale("C")); } catch (const boost::property_tree::json_parser_error & e) { MITK_WARN << "Could not parse CEST meta file. Fall back to default values. Error was:\n" << e.what(); } } else { MITK_DEBUG << "CEST meta file does not exist. Fall back to default values. CEST meta file path: " << file; } IFileIO::Options options; - ExtractOptionFromPropertyTree(CEST_PROPERTY_NAME_FREQ(),root, options); ExtractOptionFromPropertyTree(CEST_PROPERTY_NAME_B1Amplitude(), root, options); ExtractOptionFromPropertyTree(CEST_PROPERTY_NAME_PULSEDURATION(), root, options); ExtractOptionFromPropertyTree(CEST_PROPERTY_NAME_DutyCycle(), root, options); ExtractOptionFromPropertyTree(CEST_PROPERTY_NAME_OFFSETS(), root, options); ExtractOptionFromPropertyTree(CEST_PROPERTY_NAME_TREC(), root, options); + ExtractOptionFromPropertyTree("CEST.MergeAllSeries", root, options); return options; } void TransferOption(const mitk::IFileIO::Options& sourceOptions, const std::string& sourceName, mitk::IFileIO::Options& options, const std::string& newName) { auto sourceFinding = sourceOptions.find(sourceName); auto finding = options.find(newName); bool replaceValue = finding == options.end(); if (!replaceValue) { replaceValue = us::any_cast(finding->second) == 0.; } if (sourceFinding != sourceOptions.end() && us::any_cast(sourceFinding->second) != 0. && replaceValue) { options[newName] = sourceFinding->second; } } + void TransferMergeOption(const mitk::IFileIO::Options& sourceOptions, const std::string& sourceName, mitk::IFileIO::Options& options, const std::string& newName) + { + auto sourceFinding = sourceOptions.find(sourceName); + auto finding = options.find(newName); + + bool replaceValue = finding == options.end(); + if (!replaceValue) + { + try + { + us::any_cast(finding->second); + } + catch (const us::BadAnyCastException& /*e*/) + { + replaceValue = true; + //if we cannot cast in string the user has not make a selection yet + } + } + + if (sourceFinding != sourceOptions.end() && us::any_cast(sourceFinding->second) != OPTION_NAME_MERGE_NO() && replaceValue) + { + options[newName] = sourceFinding->second; + } + } + std::string CESTDICOMManualReaderService::GetCESTMetaFilePath() const { auto dir = itksys::SystemTools::GetFilenamePath(this->GetInputLocation()); std::string metafile = dir + "/" + "CEST_META.json"; return metafile; } std::string CESTDICOMManualReaderService::GetTRECFilePath() const { auto dir = itksys::SystemTools::GetFilenamePath(this->GetInputLocation()); std::string metafile = dir + "/" + "TREC.txt"; return metafile; } std::string CESTDICOMManualReaderService::GetLISTFilePath() const { auto dir = itksys::SystemTools::GetFilenamePath(this->GetInputLocation()); std::string metafile = dir + "/" + "LIST.txt"; return metafile; } IFileIO::Options CESTDICOMManualReaderService::GetOptions() const { auto options = AbstractFileReader::GetOptions(); if (!this->GetInputLocation().empty()) { auto fileOptions = ExtractOptionsFromFile(this->GetCESTMetaFilePath()); - TransferOption(fileOptions, CEST_PROPERTY_NAME_FREQ(), options, "CEST frequency [Hz]"); - TransferOption(fileOptions, CEST_PROPERTY_NAME_B1Amplitude(), options, "B1 amplitude"); - TransferOption(fileOptions, CEST_PROPERTY_NAME_PULSEDURATION(), options, "Pulse duration [us]"); - TransferOption(fileOptions, CEST_PROPERTY_NAME_DutyCycle(), options, "Duty cycle [%]"); + TransferOption(fileOptions, CEST_PROPERTY_NAME_B1Amplitude(), options, OPTION_NAME_B1()); + TransferOption(fileOptions, CEST_PROPERTY_NAME_PULSEDURATION(), options, OPTION_NAME_PULSE()); + TransferOption(fileOptions, CEST_PROPERTY_NAME_DutyCycle(), options, OPTION_NAME_DC()); + TransferMergeOption(fileOptions, "CEST.MergeAllSeries", options, OPTION_NAME_MERGE()); } return options; } us::Any CESTDICOMManualReaderService::GetOption(const std::string& name) const { this->GetOptions(); //ensure (default) options are set. return AbstractFileReader::GetOption(name); } DICOMFileReader::Pointer CESTDICOMManualReaderService::GetReader(const mitk::StringList& relevantFiles) const { mitk::DICOMFileReaderSelector::Pointer selector = mitk::DICOMFileReaderSelector::New(); + const std::string mergeStrategy = this->GetOption(OPTION_NAME_MERGE()).ToString(); + + if (mergeStrategy == OPTION_NAME_MERGE_YES()) + { + auto r = ::us::GetModuleContext()->GetModule()->GetResource("cest_DKFZ.xml"); + selector->AddConfigFromResource(r); + } + selector->LoadBuiltIn3DnTConfigs(); selector->SetInputFiles(relevantFiles); mitk::DICOMFileReader::Pointer reader = selector->GetFirstReaderWithMinimumNumberOfOutputImages(); if (reader.IsNotNull()) { //reset tag cache to ensure that additional tags of interest //will be regarded by the reader if set later on. reader->SetTagCache(nullptr); } return reader; }; std::vector> CESTDICOMManualReaderService::Read() { + const Options userOptions = this->GetOptions(); + + const std::string mergeStrategy = userOptions.find(OPTION_NAME_MERGE())->second.ToString(); + this->SetOnlyRegardOwnSeries(mergeStrategy != OPTION_NAME_MERGE_YES()); + std::vector result; std::vector dicomResult = BaseDICOMReaderService::Read(); - const Options userOptions = this->GetOptions(); - - const std::string normalizationStrategy = userOptions.find("Normalize data")->second.ToString(); + const std::string normalizationStrategy = userOptions.find(OPTION_NAME_NORMALIZE())->second.ToString(); for (auto &item : dicomResult) { auto fileOptions = ExtractOptionsFromFile(this->GetCESTMetaFilePath()); IFileIO::Options options; - TransferOption(userOptions, "CEST frequency [Hz]", options, CEST_PROPERTY_NAME_FREQ()); - TransferOption(userOptions, "B1 amplitude", options, CEST_PROPERTY_NAME_B1Amplitude()); - TransferOption(userOptions, "Pulse duration [us]", options, CEST_PROPERTY_NAME_PULSEDURATION()); - TransferOption(userOptions, "Duty cycle [%]", options, CEST_PROPERTY_NAME_DutyCycle()); - TransferOption(fileOptions, CEST_PROPERTY_NAME_FREQ(), options, CEST_PROPERTY_NAME_FREQ()); + TransferOption(userOptions, OPTION_NAME_B1(), options, CEST_PROPERTY_NAME_B1Amplitude()); + TransferOption(userOptions, OPTION_NAME_PULSE(), options, CEST_PROPERTY_NAME_PULSEDURATION()); + TransferOption(userOptions, OPTION_NAME_DC(), options, CEST_PROPERTY_NAME_DutyCycle()); TransferOption(fileOptions, CEST_PROPERTY_NAME_B1Amplitude(), options, CEST_PROPERTY_NAME_B1Amplitude()); TransferOption(fileOptions, CEST_PROPERTY_NAME_PULSEDURATION(), options, CEST_PROPERTY_NAME_PULSEDURATION()); TransferOption(fileOptions, CEST_PROPERTY_NAME_DutyCycle(), options, CEST_PROPERTY_NAME_DutyCycle()); TransferOption(fileOptions, CEST_PROPERTY_NAME_OFFSETS(), options, CEST_PROPERTY_NAME_OFFSETS()); TransferOption(fileOptions, CEST_PROPERTY_NAME_TREC(), options, CEST_PROPERTY_NAME_TREC()); auto trecValues = CustomTagParser::ReadListFromFile(this->GetTRECFilePath()); auto offsetValues = CustomTagParser::ReadListFromFile(this->GetLISTFilePath()); bool isCEST = !offsetValues.empty(); bool isT1 = !trecValues.empty(); if (!isCEST && !isT1) {//check if there are settings in the metafile auto finding = fileOptions.find(CEST_PROPERTY_NAME_OFFSETS()); if (finding != fileOptions.end()) { isCEST = true; offsetValues = finding->second.ToString(); }; finding = fileOptions.find(CEST_PROPERTY_NAME_TREC()); if (finding != fileOptions.end()) { isT1 = true; trecValues = finding->second.ToString(); }; } if (isCEST) { MITK_INFO << "CEST image detected due to LIST.txt or offset property in CEST_META.json"; options[CEST_PROPERTY_NAME_OFFSETS()] = offsetValues; } else if (isT1) { MITK_INFO << "T1 image detected due to TREC.txt or trec property in CEST_META.json"; options[CEST_PROPERTY_NAME_TREC()] = trecValues; } else { mitkThrow() << "Cannot load CEST/T1 file. No CEST offsets or T1 trec values specified. LIST.txt/TREC.txt or information in CEST_META.json is missing."; } for (const auto& option : options) { item->GetPropertyList()->SetStringProperty(option.first.c_str(), option.second.ToString().c_str()); } + auto freqProp = item->GetProperty(mitk::DICOMTagPathToPropertyName(DICOM_IMAGING_FREQUENCY_PATH()).c_str()); + + if (freqProp.IsNull()) + { + mitkThrow() << "Loaded image in invalid state. Does not contain the DICOM Imaging Frequency tag."; + } + SetCESTFrequencyMHz(item, mitk::ConvertDICOMStrToValue(freqProp->GetValueAsString())); + auto image = dynamic_cast(item.GetPointer()); if (isCEST) { try { auto offsets = ExtractCESTOffset(image); } catch (...) { mitkThrow() << "Cannot load CEST file. Number of CEST offsets do not equal the number of image time steps. Image time steps: " << image->GetTimeSteps() << "; offset values: " << offsetValues; } } else if (isT1) { try { auto t1s = ExtractCESTT1Time(image); } catch (...) { mitkThrow() << "Cannot load T1 file. Number of T1 times do not equal the number of image time steps. Image time steps: " << image->GetTimeSteps() << "; T1 values: " << trecValues; } } - if (normalizationStrategy == "Automatic" && mitk::IsNotNormalizedCESTImage(image)) + if (normalizationStrategy == OPTION_NAME_NORMALIZE_AUTOMATIC() && mitk::IsNotNormalizedCESTImage(image)) { MITK_INFO << "Unnormalized CEST image was loaded and will be normalized automatically."; auto normalizationFilter = mitk::CESTImageNormalizationFilter::New(); normalizationFilter->SetInput(image); normalizationFilter->Update(); auto normalizedImage = normalizationFilter->GetOutput(); auto nameProp = item->GetProperty("name"); if (!nameProp) { mitkThrow() << "Cannot load CEST file. Property \"name\" is missing after BaseDICOMReaderService::Read()."; } normalizedImage->SetProperty("name", mitk::StringProperty::New(nameProp->GetValueAsString() + "_normalized")); result.push_back(normalizedImage); } else { result.push_back(item); } } return result; } CESTDICOMManualReaderService *CESTDICOMManualReaderService::Clone() const { return new CESTDICOMManualReaderService(*this); } } diff --git a/Modules/CEST/autoload/IO/mitkCESTGenericDICOMReaderService.h b/Modules/CEST/autoload/IO/mitkCESTGenericDICOMReaderService.h index 46b2a6321f..33757deafe 100644 --- a/Modules/CEST/autoload/IO/mitkCESTGenericDICOMReaderService.h +++ b/Modules/CEST/autoload/IO/mitkCESTGenericDICOMReaderService.h @@ -1,51 +1,52 @@ /*============================================================================ 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 MITKCESTGenericDICOMReaderService_H #define MITKCESTGenericDICOMReaderService_H #include namespace mitk { /** Service wrapper that auto selects (using the mitk::DICOMFileReaderSelector) the best DICOMFileReader from the DICOMReader module and loads the CEST relevant meta data from a provided cest_meta.json file or provided from the user as reader options. */ class CESTDICOMManualReaderService : public BaseDICOMReaderService { public: CESTDICOMManualReaderService(const CustomMimeType& mimeType, const std::string& description); CESTDICOMManualReaderService(const mitk::CESTDICOMManualReaderService& other); /** Uses the AbstractFileReader Read function and add extra steps for CEST meta data */ using AbstractFileReader::Read; std::vector > Read() override; Options GetOptions() const override; us::Any GetOption(const std::string& name) const override; protected: std::string GetCESTMetaFilePath() const; std::string GetTRECFilePath() const; std::string GetLISTFilePath() const; mitk::DICOMFileReader::Pointer GetReader(const mitk::StringList& relevantFiles) const override; private: CESTDICOMManualReaderService* Clone() const override; }; + DICOMTagPath DICOM_IMAGING_FREQUENCY_PATH(); } #endif // MITKCESTGenericDICOMReaderService_H diff --git a/Modules/CEST/autoload/IO/mitkCESTIOActivator.cpp b/Modules/CEST/autoload/IO/mitkCESTIOActivator.cpp index 78e7955706..fd293302d9 100644 --- a/Modules/CEST/autoload/IO/mitkCESTIOActivator.cpp +++ b/Modules/CEST/autoload/IO/mitkCESTIOActivator.cpp @@ -1,56 +1,103 @@ /*============================================================================ 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 "mitkCESTIOActivator.h" #include "mitkCESTDICOMReaderService.h" #include "mitkCESTGenericDICOMReaderService.h" #include +#include #include "mitkCESTIOMimeTypes.h" +#include + namespace mitk { void CESTIOActivator::Load(us::ModuleContext *context) { us::ServiceProperties props; props[us::ServiceConstants::SERVICE_RANKING()] = 10; m_MimeTypes = mitk::MitkCESTIOMimeTypes::Get(); for (auto& mimeType : m_MimeTypes) { if (mimeType->GetName() == mitk::MitkCESTIOMimeTypes::CEST_DICOM_WITHOUT_META_FILE_NAME()) { // "w/o meta" mimetype should only registered with low priority. context->RegisterService(mimeType); } else { context->RegisterService(mimeType, props); } } m_CESTDICOMReader.reset(new CESTDICOMReaderService()); m_CESTDICOMManualWithMetaFileReader.reset(new CESTDICOMManualReaderService(MitkCESTIOMimeTypes::CEST_DICOM_WITH_META_FILE_MIMETYPE(), "CEST DICOM Manual Reader")); m_CESTDICOMManualWithOutMetaFileReader.reset(new CESTDICOMManualReaderService(MitkCESTIOMimeTypes::CEST_DICOM_WITHOUT_META_FILE_MIMETYPE(), "CEST DICOM Manual Reader")); + + m_Context = context; + { + std::lock_guard lock(m_Mutex); + // Listen for events pertaining to dictionary services. + m_Context->AddServiceListener(this, &CESTIOActivator::DICOMTagsOfInterestServiceChanged, + std::string("(&(") + us::ServiceConstants::OBJECTCLASS() + "=" + + us_service_interface_iid() + "))"); + // Query for any service references matching any language. + std::vector > refs = + context->GetServiceReferences(); + if (!refs.empty()) + { + for (auto ref : refs) + { + this->RegisterTagsOfInterest(m_Context->GetService(ref)); + m_Context->UngetService(ref); + } + } + } + + IDICOMTagsOfInterest* toiService = mitk::GetDicomTagsOfInterestService(); } void CESTIOActivator::Unload(us::ModuleContext *) { for (auto& elem : m_MimeTypes) { delete elem; } } + + void CESTIOActivator::RegisterTagsOfInterest(IDICOMTagsOfInterest* toiService) const + { + if (toiService != nullptr) + { + toiService->AddTagOfInterest(mitk::DICOM_IMAGING_FREQUENCY_PATH()); + } + } + + void CESTIOActivator::DICOMTagsOfInterestServiceChanged(const us::ServiceEvent event) + { + std::lock_guard lock(m_Mutex); + // If a dictionary service was registered, see if we + // need one. If so, get a reference to it. + if (event.GetType() == us::ServiceEvent::REGISTERED) + { + // Get a reference to the service object. + us::ServiceReference ref = event.GetServiceReference(); + this->RegisterTagsOfInterest(m_Context->GetService(ref)); + m_Context->UngetService(ref); + } + } } US_EXPORT_MODULE_ACTIVATOR(mitk::CESTIOActivator) diff --git a/Modules/CEST/autoload/IO/mitkCESTIOActivator.h b/Modules/CEST/autoload/IO/mitkCESTIOActivator.h index 4c34dc8a6c..5c19a699b0 100644 --- a/Modules/CEST/autoload/IO/mitkCESTIOActivator.h +++ b/Modules/CEST/autoload/IO/mitkCESTIOActivator.h @@ -1,42 +1,53 @@ /*============================================================================ 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 MITKCESTIOActivator_H #define MITKCESTIOActivator_H #include +#include #include #include #include +#include namespace mitk { struct IFileReader; class IDICOMTagsOfInterest; class CESTIOActivator : public us::ModuleActivator { public: void Load(us::ModuleContext *context) override; void Unload(us::ModuleContext *context) override; + private: + void RegisterTagsOfInterest(IDICOMTagsOfInterest* toiService) const; + void DICOMTagsOfInterestServiceChanged(const us::ServiceEvent event); + std::unique_ptr m_CESTDICOMReader; std::unique_ptr m_CESTDICOMManualWithMetaFileReader; std::unique_ptr m_CESTDICOMManualWithOutMetaFileReader; std::vector m_MimeTypes; + + // Module context + us::ModuleContext* m_Context; + /**mutex to guard the service listening */ + std::mutex m_Mutex; }; } #endif // MITKCESTIOActivator_H diff --git a/Modules/CEST/include/mitkCESTPropertyHelper.h b/Modules/CEST/include/mitkCESTPropertyHelper.h index bb7fba5d84..f23f9140b1 100644 --- a/Modules/CEST/include/mitkCESTPropertyHelper.h +++ b/Modules/CEST/include/mitkCESTPropertyHelper.h @@ -1,54 +1,60 @@ /*============================================================================ 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 __CEST_PROERTY_HELPER_H #define __CEST_PROERTY_HELPER_H #include "mitkIPropertyProvider.h" +#include "mitkIPropertyOwner.h" #include "MitkCESTExports.h" namespace mitk { const std::string MITKCEST_EXPORT CEST_PROPERTY_NAME_PREPERATIONTYPE(); const std::string MITKCEST_EXPORT CEST_PROPERTY_NAME_RECOVERYMODE(); const std::string MITKCEST_EXPORT CEST_PROPERTY_NAME_SPOILINGTYPE(); const std::string MITKCEST_EXPORT CEST_PROPERTY_NAME_OFFSETS(); const std::string MITKCEST_EXPORT CEST_PROPERTY_NAME_TREC(); const std::string MITKCEST_EXPORT CEST_PROPERTY_NAME_FREQ(); const std::string MITKCEST_EXPORT CEST_PROPERTY_NAME_PULSEDURATION(); const std::string MITKCEST_EXPORT CEST_PROPERTY_NAME_B1Amplitude(); const std::string MITKCEST_EXPORT CEST_PROPERTY_NAME_DutyCycle(); /**Helper function that gets the CEST B1 amplitude property ("CEST.B1Amplitude") from the passed property provider. If it is not possible to generate/get the value an mitk::Exception will be thrown.*/ double MITKCEST_EXPORT GetCESTB1Amplitude(const IPropertyProvider* provider); /**Helper function that gets the CEST frequency property ("CEST.FREQ") from the input image. If it is not possible to generate/get the value an mitk::Exception will be thrown. The value is returned in [MHz]. Normally in the property it is stored in [Hz].*/ double MITKCEST_EXPORT GetCESTFrequency(const IPropertyProvider* provider); + /**Helper function that sets the CEST frequency property ("CEST.FREQ") in the passed owner. + If it owner is nullptr nothing will be done. + The value is passed in [MHz] and set in the property in [Hz].*/ + void MITKCEST_EXPORT SetCESTFrequencyMHz(IPropertyOwner* owner, double freqInMHz); + /**Helper function that gets the CEST pulse duration property ("CEST.PulseDuration") from the input image. If it is not possible to generate/get the value an mitk::Exception will be thrown. The value is returned in [s]. Normally in the property it is stored in micro secs.*/ double MITKCEST_EXPORT GetCESTPulseDuration(const IPropertyProvider* provider); /**Helper function that gets the CEST duty cycle property ("CEST.DutyCycle") from the input image. If it is not possible to generate/get the value an mitk::Exception will be thrown. The value is returned as scaling factor (1 == 100%), in contrast to the porperty where it is stored as a percentage value (e.g. 56 %, so the function return will be 0.56).*/ double MITKCEST_EXPORT GetCESTDutyCycle(const IPropertyProvider* provider); } #endif // __CEST_PROERTY_HELPER_H diff --git a/Modules/CEST/src/mitkCESTPropertyHelper.cpp b/Modules/CEST/src/mitkCESTPropertyHelper.cpp index db92cbb338..f6c154afb4 100644 --- a/Modules/CEST/src/mitkCESTPropertyHelper.cpp +++ b/Modules/CEST/src/mitkCESTPropertyHelper.cpp @@ -1,137 +1,146 @@ /*============================================================================ 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 "mitkCESTPropertyHelper.h" #include "mitkDICOMProperty.h" +#include "mitkStringProperty.h" const std::string mitk::CEST_PROPERTY_NAME_PREPERATIONTYPE() { return "CEST.PreparationType"; -}; +} const std::string mitk::CEST_PROPERTY_NAME_RECOVERYMODE() { return "CEST.RecoveryMode"; -}; +} const std::string mitk::CEST_PROPERTY_NAME_SPOILINGTYPE() { return "CEST.SpoilingType"; -}; +} const std::string mitk::CEST_PROPERTY_NAME_OFFSETS() { return "CEST.Offsets"; -}; +} const std::string mitk::CEST_PROPERTY_NAME_TREC() { return std::string("CEST.TREC"); } const std::string mitk::CEST_PROPERTY_NAME_FREQ() { return std::string("CEST.FREQ"); } const std::string mitk::CEST_PROPERTY_NAME_PULSEDURATION() { return std::string("CEST.PulseDuration"); } const std::string mitk::CEST_PROPERTY_NAME_B1Amplitude() { return std::string("CEST.B1Amplitude"); } const std::string mitk::CEST_PROPERTY_NAME_DutyCycle() { return std::string("CEST.DutyCycle"); } double mitk::GetCESTB1Amplitude(const IPropertyProvider* provider) { if (!provider) { mitkThrow() << "Cannot determine B! amplitude. Passed property provider is invalid."; } double result = 0.0; auto prop = provider->GetConstProperty(CEST_PROPERTY_NAME_B1Amplitude().c_str()); if (prop.IsNotNull()) { result = mitk::ConvertDICOMStrToValue(prop->GetValueAsString()); } else mitkThrow() << "Cannot determine B! amplitude. Selected input has no property \"" << CEST_PROPERTY_NAME_B1Amplitude << "\""; return result; } double mitk::GetCESTFrequency(const IPropertyProvider* provider) { if (!provider) { mitkThrow() << "Cannot determine frequency. Passed property provider is invalid."; } double result = 0.0; auto prop = provider->GetConstProperty(CEST_PROPERTY_NAME_FREQ().c_str()); if (prop.IsNotNull()) { result = mitk::ConvertDICOMStrToValue(prop->GetValueAsString()) * 0.000001; } else mitkThrow() << "Cannot determine frequency. Selected input has no property \"" << CEST_PROPERTY_NAME_FREQ << "\""; return result; -}; +} + +void mitk::SetCESTFrequencyMHz(IPropertyOwner* owner, double freqInMHz) +{ + if (nullptr != owner) + { + owner->SetProperty(CEST_PROPERTY_NAME_FREQ().c_str(), mitk::StringProperty::New(ConvertValueToDICOMStr(freqInMHz * 1000000))); + } +} double mitk::GetCESTPulseDuration(const IPropertyProvider* provider) { if (!provider) { mitkThrow() << "Cannot determine pulse duration. Passed property provider is invalid."; } double result = 0.0; auto prop = provider->GetConstProperty(CEST_PROPERTY_NAME_PULSEDURATION().c_str()); if (prop.IsNotNull()) { result = mitk::ConvertDICOMStrToValue(prop->GetValueAsString()) * 0.000001; } else mitkThrow() << "Cannot determine pulse duration. Selected input has no property \"" << CEST_PROPERTY_NAME_PULSEDURATION << "\""; return result; -}; +} double mitk::GetCESTDutyCycle(const IPropertyProvider* provider) { if (!provider) { mitkThrow() << "Cannot determine duty cycle. Passed property provider is invalid."; } double result = 0.0; auto prop = provider->GetConstProperty(CEST_PROPERTY_NAME_DutyCycle().c_str()); if (prop.IsNotNull()) { result = mitk::ConvertDICOMStrToValue(prop->GetValueAsString()) * 0.01; } else mitkThrow() << "Cannot determine duty cycle. Selected input has no property \"" << CEST_PROPERTY_NAME_DutyCycle << "\""; return result; -}; +} diff --git a/Modules/Core/src/IO/mitkIOMimeTypes.cpp b/Modules/Core/src/IO/mitkIOMimeTypes.cpp index 801bde5c04..ad668de0d3 100644 --- a/Modules/Core/src/IO/mitkIOMimeTypes.cpp +++ b/Modules/Core/src/IO/mitkIOMimeTypes.cpp @@ -1,363 +1,363 @@ /*============================================================================ 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 "mitkIOMimeTypes.h" #include "mitkCustomMimeType.h" #include "mitkLogMacros.h" #include "itkGDCMImageIO.h" #include "itkMetaDataObject.h" #include #include namespace mitk { IOMimeTypes::BaseDicomMimeType::BaseDicomMimeType(const std::string& name) : CustomMimeType(name) { this->AddExtension("gdcm"); this->AddExtension("dcm"); this->AddExtension("DCM"); this->AddExtension("dc3"); this->AddExtension("DC3"); this->AddExtension("ima"); this->AddExtension("img"); this->SetCategory(CATEGORY_IMAGES()); this->SetComment("DICOM"); } IOMimeTypes::BaseDicomMimeType::BaseDicomMimeType(const BaseDicomMimeType& other) : CustomMimeType(other.GetName()) { } bool IOMimeTypes::BaseDicomMimeType::AppliesTo(const std::string &path) const { // check whether directory or file // if directory try to find first file within it instead bool pathIsDirectory = itksys::SystemTools::FileIsDirectory(path); std::string filepath = path; if (pathIsDirectory) { itksys::Directory input; input.Load(path.c_str()); std::vector files; for (unsigned long idx = 0; idxSetFileName(filepath); try { gdcmIO->ReadImageInformation(); } catch (const itk::ExceptionObject & /*err*/) { return false; } //DICOMRT modalities have specific reader, don't read with normal DICOM readers std::string modality; itk::MetaDataDictionary& dict = gdcmIO->GetMetaDataDictionary(); itk::ExposeMetaData(dict, "0008|0060", modality); - MITK_INFO << "DICOM Modality is " << modality; + MITK_DEBUG << "DICOM Modality detected by MimeType "<< this->GetName() << " is " << modality; if (modality == "RTSTRUCT" || modality == "RTDOSE" || modality == "RTPLAN") { return false; } else { return gdcmIO->CanReadFile(filepath.c_str()); } } IOMimeTypes::BaseDicomMimeType*IOMimeTypes::BaseDicomMimeType::Clone() const { return new BaseDicomMimeType(*this); } IOMimeTypes::DicomMimeType::DicomMimeType() : BaseDicomMimeType(DICOM_MIMETYPE_NAME()) { } IOMimeTypes::DicomMimeType* IOMimeTypes::DicomMimeType::Clone() const { return new DicomMimeType(*this); } std::vector IOMimeTypes::Get() { std::vector mimeTypes; // order matters here (descending rank for mime types) mimeTypes.push_back(NRRD_MIMETYPE().Clone()); mimeTypes.push_back(NIFTI_MIMETYPE().Clone()); mimeTypes.push_back(VTK_IMAGE_MIMETYPE().Clone()); mimeTypes.push_back(VTK_PARALLEL_IMAGE_MIMETYPE().Clone()); mimeTypes.push_back(VTK_IMAGE_LEGACY_MIMETYPE().Clone()); mimeTypes.push_back(DICOM_MIMETYPE().Clone()); mimeTypes.push_back(VTK_POLYDATA_MIMETYPE().Clone()); mimeTypes.push_back(VTK_PARALLEL_POLYDATA_MIMETYPE().Clone()); mimeTypes.push_back(VTK_POLYDATA_LEGACY_MIMETYPE().Clone()); mimeTypes.push_back(STEREOLITHOGRAPHY_MIMETYPE().Clone()); mimeTypes.push_back(WAVEFRONT_OBJ_MIMETYPE().Clone()); mimeTypes.push_back(STANFORD_PLY_MIMETYPE().Clone()); mimeTypes.push_back(RAW_MIMETYPE().Clone()); mimeTypes.push_back(POINTSET_MIMETYPE().Clone()); return mimeTypes; } CustomMimeType IOMimeTypes::VTK_IMAGE_MIMETYPE() { CustomMimeType mimeType(VTK_IMAGE_NAME()); mimeType.AddExtension("vti"); mimeType.SetCategory(CATEGORY_IMAGES()); mimeType.SetComment("VTK Image"); return mimeType; } CustomMimeType IOMimeTypes::VTK_IMAGE_LEGACY_MIMETYPE() { CustomMimeType mimeType(VTK_IMAGE_LEGACY_NAME()); mimeType.AddExtension("vtk"); mimeType.SetCategory(CATEGORY_IMAGES()); mimeType.SetComment("VTK Legacy Image"); return mimeType; } CustomMimeType IOMimeTypes::VTK_PARALLEL_IMAGE_MIMETYPE() { CustomMimeType mimeType(VTK_PARALLEL_IMAGE_NAME()); mimeType.AddExtension("pvti"); mimeType.SetCategory(CATEGORY_IMAGES()); mimeType.SetComment("VTK Parallel Image"); return mimeType; } CustomMimeType IOMimeTypes::VTK_POLYDATA_MIMETYPE() { CustomMimeType mimeType(VTK_POLYDATA_NAME()); mimeType.AddExtension("vtp"); mimeType.SetCategory(CATEGORY_SURFACES()); mimeType.SetComment("VTK PolyData"); return mimeType; } CustomMimeType IOMimeTypes::VTK_POLYDATA_LEGACY_MIMETYPE() { CustomMimeType mimeType(VTK_POLYDATA_LEGACY_NAME()); mimeType.AddExtension("vtk"); mimeType.SetCategory(CATEGORY_SURFACES()); mimeType.SetComment("VTK Legacy PolyData"); return mimeType; } CustomMimeType IOMimeTypes::VTK_PARALLEL_POLYDATA_MIMETYPE() { CustomMimeType mimeType(VTK_PARALLEL_POLYDATA_NAME()); mimeType.AddExtension("pvtp"); mimeType.SetCategory(CATEGORY_SURFACES()); mimeType.SetComment("VTK Parallel PolyData"); return mimeType; } CustomMimeType IOMimeTypes::STEREOLITHOGRAPHY_MIMETYPE() { CustomMimeType mimeType(STEREOLITHOGRAPHY_NAME()); mimeType.AddExtension("stl"); mimeType.SetCategory(CATEGORY_SURFACES()); mimeType.SetComment("Stereolithography"); return mimeType; } CustomMimeType IOMimeTypes::WAVEFRONT_OBJ_MIMETYPE() { CustomMimeType mimeType(WAVEFRONT_OBJ_NAME()); mimeType.AddExtension("obj"); mimeType.SetCategory(CATEGORY_SURFACES()); mimeType.SetComment("Wavefront OBJ"); return mimeType; } CustomMimeType IOMimeTypes::STANFORD_PLY_MIMETYPE() { CustomMimeType mimeType(STANFORD_PLY_NAME()); mimeType.AddExtension("ply"); mimeType.SetCategory(CATEGORY_SURFACES()); mimeType.SetComment("Stanford PLY"); return mimeType; } std::string IOMimeTypes::STEREOLITHOGRAPHY_NAME() { static std::string name = DEFAULT_BASE_NAME() + ".stl"; return name; } std::string IOMimeTypes::WAVEFRONT_OBJ_NAME() { static std::string name = DEFAULT_BASE_NAME() + ".obj"; return name; } std::string IOMimeTypes::STANFORD_PLY_NAME() { static std::string name = DEFAULT_BASE_NAME() + ".ply"; return name; } std::string IOMimeTypes::DEFAULT_BASE_NAME() { static std::string name = "application/vnd.mitk"; return name; } std::string IOMimeTypes::CATEGORY_IMAGES() { static std::string cat = "Images"; return cat; } std::string IOMimeTypes::CATEGORY_SURFACES() { static std::string cat = "Surfaces"; return cat; } std::string IOMimeTypes::VTK_IMAGE_NAME() { static std::string name = DEFAULT_BASE_NAME() + ".vtk.image"; return name; } std::string IOMimeTypes::VTK_IMAGE_LEGACY_NAME() { static std::string name = DEFAULT_BASE_NAME() + ".vtk.image.legacy"; return name; } std::string IOMimeTypes::VTK_PARALLEL_IMAGE_NAME() { static std::string name = DEFAULT_BASE_NAME() + ".vtk.parallel.image"; return name; } std::string IOMimeTypes::VTK_POLYDATA_NAME() { static std::string name = DEFAULT_BASE_NAME() + ".vtk.polydata"; return name; } std::string IOMimeTypes::VTK_POLYDATA_LEGACY_NAME() { static std::string name = DEFAULT_BASE_NAME() + ".vtk.polydata.legacy"; return name; } std::string IOMimeTypes::VTK_PARALLEL_POLYDATA_NAME() { static std::string name = DEFAULT_BASE_NAME() + ".vtk.parallel.polydata"; return name; } CustomMimeType IOMimeTypes::NRRD_MIMETYPE() { CustomMimeType mimeType(NRRD_MIMETYPE_NAME()); mimeType.AddExtension("nrrd"); mimeType.AddExtension("nhdr"); mimeType.SetCategory("Images"); mimeType.SetComment("NRRD"); return mimeType; } CustomMimeType IOMimeTypes::NIFTI_MIMETYPE() { CustomMimeType mimeType(NIFTI_MIMETYPE_NAME()); mimeType.AddExtension("nii"); mimeType.AddExtension("nii.gz"); mimeType.AddExtension("hdr"); mimeType.AddExtension("hdr.gz"); mimeType.AddExtension("img"); mimeType.AddExtension("img.gz"); mimeType.AddExtension("nia"); mimeType.SetCategory("Images"); mimeType.SetComment("Nifti"); return mimeType; } CustomMimeType IOMimeTypes::RAW_MIMETYPE() { CustomMimeType mimeType(RAW_MIMETYPE_NAME()); mimeType.AddExtension("raw"); mimeType.SetCategory("Images"); mimeType.SetComment("Raw data"); return mimeType; } IOMimeTypes::DicomMimeType IOMimeTypes::DICOM_MIMETYPE() { return DicomMimeType(); } std::string IOMimeTypes::NRRD_MIMETYPE_NAME() { static std::string name = DEFAULT_BASE_NAME() + ".image.nrrd"; return name; } std::string IOMimeTypes::NIFTI_MIMETYPE_NAME() { static std::string name = DEFAULT_BASE_NAME() + ".image.nifti"; return name; } std::string IOMimeTypes::RAW_MIMETYPE_NAME() { static std::string name = DEFAULT_BASE_NAME() + ".image.raw"; return name; } std::string IOMimeTypes::DICOM_MIMETYPE_NAME() { static std::string name = DEFAULT_BASE_NAME() + ".image.dicom"; return name; } CustomMimeType IOMimeTypes::POINTSET_MIMETYPE() { CustomMimeType mimeType(POINTSET_MIMETYPE_NAME()); mimeType.AddExtension("mps"); mimeType.SetCategory("Point Sets"); mimeType.SetComment("MITK Point Set"); return mimeType; } std::string IOMimeTypes::POINTSET_MIMETYPE_NAME() { static std::string name = DEFAULT_BASE_NAME() + ".pointset"; return name; } CustomMimeType IOMimeTypes::GEOMETRY_DATA_MIMETYPE() { mitk::CustomMimeType mimeType(DEFAULT_BASE_NAME() + ".geometrydata"); mimeType.AddExtension("mitkgeometry"); mimeType.SetCategory("Geometries"); mimeType.SetComment("GeometryData object"); return mimeType; } } diff --git a/Modules/DICOMReader/include/mitkDICOMProperty.h b/Modules/DICOMReader/include/mitkDICOMProperty.h index 895c9e8cda..20bd65cca6 100644 --- a/Modules/DICOMReader/include/mitkDICOMProperty.h +++ b/Modules/DICOMReader/include/mitkDICOMProperty.h @@ -1,65 +1,82 @@ /*============================================================================ 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 mitkDICOMProperty_h #define mitkDICOMProperty_h #include "mitkDICOMImageBlockDescriptor.h" #include "mitkTemporoSpatialStringProperty.h" #include "mitkDICOMTagPath.h" #include "MitkDICOMReaderExports.h" namespace mitk { typedef TemporoSpatialStringProperty DICOMProperty; /** Generation functor for DICOMFileReader classes to convert the collected tag values into DICOMProperty instances. */ MITKDICOMREADER_EXPORT mitk::BaseProperty::Pointer GetDICOMPropertyForDICOMValuesFunctor(const DICOMCachedValueLookupTable& cacheLookupTable); class PropertyList; class BaseData; /** Helper function that searches for all properties in a given property list that matches the passed path. * The result will be the matching properties in a map*/ MITKDICOMREADER_EXPORT std::map< std::string, BaseProperty::Pointer> GetPropertyByDICOMTagPath(const PropertyList* list, const DICOMTagPath& path); /** Helper function that searches for all properties in a given base data that matches the passed path. * The result will be the matching properties in a map*/ MITKDICOMREADER_EXPORT std::map< std::string, BaseProperty::Pointer> GetPropertyByDICOMTagPath(const BaseData* data, const DICOMTagPath& path); /**Helper function that can be used to convert the content of a DICOM property into the given return type. The function makes the following assumptions: 1. dcmValueString does only encode one number. 2. The value is encoded compliant to locale "C". @pre dcmValueString must be convertibel into the return type. If this is not the case an exception will be thrown. */ template TNumericReturnType ConvertDICOMStrToValue(const std::string& dcmValueString) { std::istringstream iss(dcmValueString); iss.imbue(std::locale("C")); TNumericReturnType d; if (!(iss >> d) || !(iss.eof())) { mitkThrow() << "Cannot convert string to value type. Type: " << typeid(TNumericReturnType).name() << "; String: " << dcmValueString; } return d; }; + /**Helper function that can be used to convert a numeric value into content of a DICOM property. + @pre value must be convertibel into a string. + If this is not the case an exception will be thrown. + */ + template + std::string ConvertValueToDICOMStr(const TNumericType value) + { + std::ostringstream oss(value); + oss.imbue(std::locale("C")); + if (!(oss << value)) + { + mitkThrow() << "Cannot convert value type to dicom string. Type: " << typeid(TNumericType).name() << "; value: " << value; + } + + return oss.str(); + }; + } #endif diff --git a/Modules/DICOMReader/test/mitkDICOMPropertyTest.cpp b/Modules/DICOMReader/test/mitkDICOMPropertyTest.cpp index cf891996ff..96218f9203 100644 --- a/Modules/DICOMReader/test/mitkDICOMPropertyTest.cpp +++ b/Modules/DICOMReader/test/mitkDICOMPropertyTest.cpp @@ -1,159 +1,166 @@ /*============================================================================ 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 "mitkDICOMProperty.h" #include "mitkImage.h" #include "mitkTestFixture.h" #include "mitkTestingMacros.h" class mitkDICOMPropertyTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkDICOMPropertyTestSuite); MITK_TEST(GetPropertyByDICOMTagPath); MITK_TEST(GetPropertyByDICOMTagPath_2); MITK_TEST(ConvertDICOMStrToValue); + MITK_TEST(ConvertValueToDICOMStr); CPPUNIT_TEST_SUITE_END(); private: mitk::DICOMTagPath simplePath; mitk::DICOMTagPath deepPath; mitk::DICOMTagPath deepPath2; mitk::DICOMTagPath deepPath_withAnyElement; mitk::DICOMTagPath deepPath_withAnySelection; mitk::DICOMTagPath deepPath_withSelection; mitk::DICOMTagPath deepPath_withSelection2; mitk::DICOMTagPath emptyPath; mitk::Image::Pointer data; std::string simplePathStr; std::string deepPathStr; std::string deepPath2Str; std::string deepPath_withSelectionStr; public: void setUp() override { simplePath.AddElement(0x0010, 0x0010); deepPath.AddElement(0x0010, 0x0011).AddElement(0x0020, 0x0022).AddElement(0x0030, 0x0033); deepPath2.AddElement(0x0010, 0x0011).AddElement(0x0020, 0x0023).AddElement(0x0030, 0x0033); deepPath_withAnyElement.AddElement(0x0010, 0x0011).AddAnyElement().AddElement(0x0030, 0x0033); deepPath_withAnySelection.AddElement(0x0010, 0x0011).AddAnySelection(0x0020, 0x0024).AddElement(0x0030, 0x0033); deepPath_withSelection.AddElement(0x0010, 0x0011).AddSelection(0x0020, 0x0024, 1).AddElement(0x0030, 0x0033); deepPath_withSelection2.AddElement(0x0010, 0x0011).AddSelection(0x0020, 0x0024, 2).AddElement(0x0030, 0x0033); simplePathStr = mitk::DICOMTagPathToPropertyName(simplePath); deepPathStr = mitk::DICOMTagPathToPropertyName(deepPath); deepPath2Str = mitk::DICOMTagPathToPropertyName(deepPath2); deepPath_withSelectionStr = mitk::DICOMTagPathToPropertyName(deepPath_withSelection); data = mitk::Image::New(); data->GetPropertyList()->SetStringProperty(simplePathStr.c_str(), "simplePath"); data->GetPropertyList()->SetStringProperty(deepPathStr.c_str(), "deepPath"); data->GetPropertyList()->SetStringProperty(deepPath2Str.c_str(), "deepPath2"); data->GetPropertyList()->SetStringProperty(deepPath_withSelectionStr.c_str(), "deepPath_withSelection"); data->GetPropertyList()->SetStringProperty("DICOM.0003.0003", "otherPath"); data->GetPropertyList()->SetStringProperty("not_a_dicom_prop", "not_a_dicom_prop"); } void tearDown() override { } void GetPropertyByDICOMTagPath() { std::map< std::string, mitk::BaseProperty::Pointer> result = mitk::GetPropertyByDICOMTagPath(data, simplePath); CPPUNIT_ASSERT(result.size() == 1); CPPUNIT_ASSERT_EQUAL(result.begin()->second->GetValueAsString(), std::string("simplePath")); result = mitk::GetPropertyByDICOMTagPath(data, deepPath); CPPUNIT_ASSERT(result.size() == 1); CPPUNIT_ASSERT_EQUAL(result.begin()->second->GetValueAsString(), std::string("deepPath")); result = mitk::GetPropertyByDICOMTagPath(data, deepPath2); CPPUNIT_ASSERT(result.size() == 1); CPPUNIT_ASSERT_EQUAL(result.begin()->second->GetValueAsString(), std::string("deepPath2")); result = mitk::GetPropertyByDICOMTagPath(data, deepPath_withAnyElement); CPPUNIT_ASSERT(result.size() == 3); CPPUNIT_ASSERT_EQUAL(result[deepPathStr]->GetValueAsString(), std::string("deepPath")); CPPUNIT_ASSERT_EQUAL(result[deepPath2Str]->GetValueAsString(), std::string("deepPath2")); CPPUNIT_ASSERT_EQUAL(result[deepPath_withSelectionStr]->GetValueAsString(), std::string("deepPath_withSelection")); result = mitk::GetPropertyByDICOMTagPath(data, deepPath_withSelection); CPPUNIT_ASSERT(result.size() == 1); CPPUNIT_ASSERT_EQUAL(result[deepPath_withSelectionStr]->GetValueAsString(), std::string("deepPath_withSelection")); result = mitk::GetPropertyByDICOMTagPath(data, deepPath_withSelection2); CPPUNIT_ASSERT(result.size() == 0); result = mitk::GetPropertyByDICOMTagPath(data, emptyPath); CPPUNIT_ASSERT(result.size() == 0); } void GetPropertyByDICOMTagPath_2() { std::map< std::string, mitk::BaseProperty::Pointer> result = mitk::GetPropertyByDICOMTagPath(data->GetPropertyList(), simplePath); CPPUNIT_ASSERT(result.size() == 1); CPPUNIT_ASSERT_EQUAL(result.begin()->second->GetValueAsString(), std::string("simplePath")); result = mitk::GetPropertyByDICOMTagPath(data->GetPropertyList(), deepPath); CPPUNIT_ASSERT(result.size() == 1); CPPUNIT_ASSERT_EQUAL(result.begin()->second->GetValueAsString(), std::string("deepPath")); result = mitk::GetPropertyByDICOMTagPath(data->GetPropertyList(), deepPath2); CPPUNIT_ASSERT(result.size() == 1); CPPUNIT_ASSERT_EQUAL(result.begin()->second->GetValueAsString(), std::string("deepPath2")); result = mitk::GetPropertyByDICOMTagPath(data->GetPropertyList(), deepPath_withAnyElement); CPPUNIT_ASSERT(result.size() == 3); CPPUNIT_ASSERT_EQUAL(result[deepPathStr]->GetValueAsString(), std::string("deepPath")); CPPUNIT_ASSERT_EQUAL(result[deepPath2Str]->GetValueAsString(), std::string("deepPath2")); CPPUNIT_ASSERT_EQUAL(result[deepPath_withSelectionStr]->GetValueAsString(), std::string("deepPath_withSelection")); result = mitk::GetPropertyByDICOMTagPath(data->GetPropertyList(), deepPath_withSelection); CPPUNIT_ASSERT(result.size() == 1); CPPUNIT_ASSERT_EQUAL(result[deepPath_withSelectionStr]->GetValueAsString(), std::string("deepPath_withSelection")); result = mitk::GetPropertyByDICOMTagPath(data->GetPropertyList(), deepPath_withSelection2); CPPUNIT_ASSERT(result.size() == 0); result = mitk::GetPropertyByDICOMTagPath(data->GetPropertyList(), emptyPath); CPPUNIT_ASSERT(result.size() == 0); } void ConvertDICOMStrToValue() { CPPUNIT_ASSERT_EQUAL(mitk::ConvertDICOMStrToValue("1.35"), 1.35); CPPUNIT_ASSERT_EQUAL(mitk::ConvertDICOMStrToValue("1"), 1.); CPPUNIT_ASSERT_THROW(mitk::ConvertDICOMStrToValue("1.35"), mitk::Exception); CPPUNIT_ASSERT_EQUAL(mitk::ConvertDICOMStrToValue("1"), 1); CPPUNIT_ASSERT_THROW(mitk::ConvertDICOMStrToValue("1,35"), mitk::Exception); CPPUNIT_ASSERT_THROW(mitk::ConvertDICOMStrToValue("nonumber"), mitk::Exception); } + void ConvertValueToDICOMStr() + { + CPPUNIT_ASSERT_EQUAL(mitk::ConvertValueToDICOMStr(1.35), std::string("1.35")); + CPPUNIT_ASSERT_EQUAL(mitk::ConvertValueToDICOMStr(1), std::string("1")); + } + }; MITK_TEST_SUITE_REGISTRATION(mitkDICOMProperty)