diff --git a/Modules/CEST/autoload/IO/mitkCESTGenericDICOMReaderService.cpp b/Modules/CEST/autoload/IO/mitkCESTGenericDICOMReaderService.cpp index 4c84f976c1..0276670704 100644 --- a/Modules/CEST/autoload/IO/mitkCESTGenericDICOMReaderService.cpp +++ b/Modules/CEST/autoload/IO/mitkCESTGenericDICOMReaderService.cpp @@ -1,397 +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 "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 +namespace { - 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"; - }; + } + + std::string META_FILE_OPTION_NAME_MERGE() + { + return "CEST.MergeAllSeries"; + } + +} + +namespace mitk +{ + DICOMTagPath DICOM_IMAGING_FREQUENCY_PATH() + { + return mitk::DICOMTagPath(0x0018, 0x0084); + } CESTDICOMManualReaderService::CESTDICOMManualReaderService(const CustomMimeType& mimeType, const std::string& description) : BaseDICOMReaderService(mimeType, description) { IFileIO::Options options; - options[OPTION_NAME_B1().c_str()] = 0.0; - options[OPTION_NAME_PULSE().c_str()] = 0.0; - options[OPTION_NAME_DC().c_str()] = 0.0; + options[OPTION_NAME_B1()] = 0.0; + options[OPTION_NAME_PULSE()] = 0.0; + options[OPTION_NAME_DC()] = 0.0; std::vector 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; + normalizationStrategy.push_back(OPTION_NAME_NORMALIZE_AUTOMATIC()); + normalizationStrategy.push_back(OPTION_NAME_NORMALIZE_NO()); + options[OPTION_NAME_NORMALIZE()] = 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; + mergeStrategy.push_back(OPTION_NAME_MERGE_NO()); + mergeStrategy.push_back(OPTION_NAME_MERGE_YES()); + options[OPTION_NAME_MERGE()] = 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) + namespace { - auto finding = root.find(key); - if (finding != root.not_found()) + void ExtractOptionFromPropertyTree(const std::string& key, boost::property_tree::ptree& root, std::map& options) { - try + auto finding = root.find(key); + if (finding != root.not_found()) { - options[key] = finding->second.get_value(); - } - catch (const boost::property_tree::ptree_bad_data & /*e*/) - { - 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)) + IFileIO::Options ExtractOptionsFromFile(const std::string& file) { - try + boost::property_tree::ptree root; + + if (itksys::SystemTools::FileExists(file)) { - boost::property_tree::read_json(file, root, std::locale("C")); + 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(); + } } - catch (const boost::property_tree::json_parser_error & e) + else { - MITK_WARN << "Could not parse CEST meta file. Fall back to default values. Error was:\n" << e.what(); + MITK_DEBUG << "CEST meta file does not exist. Fall back to default values. CEST meta file path: " << file; } - } - 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_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.; + IFileIO::Options 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(META_FILE_OPTION_NAME_MERGE(), root, options); + + return options; } - if (sourceFinding != sourceOptions.end() && us::any_cast(sourceFinding->second) != 0. && replaceValue) + void TransferOption(const mitk::IFileIO::Options& sourceOptions, const std::string& sourceName, mitk::IFileIO::Options& options, const std::string& newName) { - 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); + auto sourceFinding = sourceOptions.find(sourceName); + auto finding = options.find(newName); - bool replaceValue = finding == options.end(); - if (!replaceValue) - { - try + bool replaceValue = finding == options.end(); + if (!replaceValue) { - us::any_cast(finding->second); + replaceValue = us::any_cast(finding->second) == 0.; } - catch (const us::BadAnyCastException& /*e*/) + + if (sourceFinding != sourceOptions.end() && us::any_cast(sourceFinding->second) != 0. && replaceValue) { - replaceValue = true; - //if we cannot cast in string the user has not make a selection yet + options[newName] = sourceFinding->second; } } - if (sourceFinding != sourceOptions.end() && us::any_cast(sourceFinding->second) != OPTION_NAME_MERGE_NO() && replaceValue) + void TransferMergeOption(const mitk::IFileIO::Options& sourceOptions, const std::string& sourceName, mitk::IFileIO::Options& options, const std::string& newName) { - options[newName] = sourceFinding->second; + 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 made 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_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()); + TransferMergeOption(fileOptions, META_FILE_OPTION_NAME_MERGE(), 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(); + auto 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 std::string normalizationStrategy = userOptions.find(OPTION_NAME_NORMALIZE())->second.ToString(); - for (auto &item : dicomResult) + for (const auto &item : dicomResult) { auto fileOptions = ExtractOptionsFromFile(this->GetCESTMetaFilePath()); IFileIO::Options options; 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 == 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); } + 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 33757deafe..f44507dc8a 100644 --- a/Modules/CEST/autoload/IO/mitkCESTGenericDICOMReaderService.h +++ b/Modules/CEST/autoload/IO/mitkCESTGenericDICOMReaderService.h @@ -1,52 +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 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: + 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 0c2344667e..c9be3c3167 100644 --- a/Modules/CEST/autoload/IO/mitkCESTIOActivator.cpp +++ b/Modules/CEST/autoload/IO/mitkCESTIOActivator.cpp @@ -1,101 +1,102 @@ /*============================================================================ 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) + for (const 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_CESTDICOMReader = std::make_unique(); + m_CESTDICOMManualWithMetaFileReader = std::make_unique(MitkCESTIOMimeTypes::CEST_DICOM_WITH_META_FILE_MIMETYPE(), "CEST DICOM Manual Reader"); + m_CESTDICOMManualWithOutMetaFileReader = std::make_unique(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) + for (const auto& ref : refs) { this->RegisterTagsOfInterest(m_Context->GetService(ref)); m_Context->UngetService(ref); } } } } void CESTIOActivator::Unload(us::ModuleContext *) { for (auto& elem : m_MimeTypes) { delete elem; + elem = nullptr; } } 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/mitkCESTIOMimeTypes.cpp b/Modules/CEST/autoload/IO/mitkCESTIOMimeTypes.cpp index ed2c8cb5bf..449b415072 100644 --- a/Modules/CEST/autoload/IO/mitkCESTIOMimeTypes.cpp +++ b/Modules/CEST/autoload/IO/mitkCESTIOMimeTypes.cpp @@ -1,229 +1,229 @@ /*============================================================================ 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 "mitkCESTIOMimeTypes.h" #include "mitkIOMimeTypes.h" #include #include #include #include #include #include namespace mitk { std::vector MitkCESTIOMimeTypes::Get() { std::vector mimeTypes; // order matters here (descending rank for mime types) mimeTypes.push_back(CEST_DICOM_WITH_META_FILE_MIMETYPE().Clone()); mimeTypes.push_back(CEST_DICOM_MIMETYPE().Clone()); mimeTypes.push_back(CEST_DICOM_WITHOUT_META_FILE_MIMETYPE().Clone()); return mimeTypes; } // Mime Types MitkCESTIOMimeTypes::MitkCESTDicomMimeType::MitkCESTDicomMimeType() : IOMimeTypes::BaseDicomMimeType(CEST_DICOM_MIMETYPE_NAME()) { this->SetCategory(IOMimeTypes::CATEGORY_IMAGES()); this->SetComment("CEST DICOM"); } bool MitkCESTIOMimeTypes::MitkCESTDicomMimeType::AppliesTo(const std::string &path) const { bool canRead(IOMimeTypes::BaseDicomMimeType::AppliesTo(path)); // fix for bug 18572 // Currently this function is called for writing as well as reading, in that case // the image information can of course not be read // This is a bug, this function should only be called for reading. if (!itksys::SystemTools::FileExists(path.c_str())) { return canRead; } // end fix for bug 18572 if (!canRead) { return canRead; } mitk::DICOMDCMTKTagScanner::Pointer scanner = mitk::DICOMDCMTKTagScanner::New(); mitk::DICOMTag siemensCESTprivateTag(0x0029, 0x1020); mitk::StringList relevantFiles; relevantFiles.push_back(path); scanner->AddTag(siemensCESTprivateTag); scanner->SetInputFiles(relevantFiles); scanner->Scan(); mitk::DICOMTagCache::Pointer tagCache = scanner->GetScanCache(); mitk::DICOMImageFrameList imageFrameList = mitk::ConvertToDICOMImageFrameList(tagCache->GetFrameInfoList()); bool mapNotEmpty = false; if (!imageFrameList.empty()) { mitk::DICOMImageFrameInfo* firstFrame = imageFrameList.begin()->GetPointer(); std::string byteString = tagCache->GetTagValue(firstFrame, siemensCESTprivateTag).value; if (byteString.empty()) { return false; } mitk::CustomTagParser tagParser(relevantFiles[0]); auto parsedPropertyList = tagParser.ParseDicomPropertyString(byteString); - mapNotEmpty = parsedPropertyList->GetMap()->size() > 0; + mapNotEmpty = !parsedPropertyList->GetMap()->empty(); } return mapNotEmpty; } MitkCESTIOMimeTypes::MitkCESTDicomMimeType *MitkCESTIOMimeTypes::MitkCESTDicomMimeType::Clone() const { return new MitkCESTDicomMimeType(*this); } MitkCESTIOMimeTypes::MitkCESTDicomMimeType MitkCESTIOMimeTypes::CEST_DICOM_MIMETYPE() { return MitkCESTDicomMimeType(); } std::string MitkCESTIOMimeTypes::CEST_DICOM_MIMETYPE_NAME() { // create a unique and sensible name for this mime type static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".image.dicom.cest"; return name; } MitkCESTIOMimeTypes::MitkCESTDicomWithMetaFileMimeType::MitkCESTDicomWithMetaFileMimeType() : IOMimeTypes::BaseDicomMimeType(CEST_DICOM_WITH_META_FILE_NAME()) { this->SetCategory(IOMimeTypes::CATEGORY_IMAGES()); this->SetComment("CEST DICOM"); } bool MitkCESTIOMimeTypes::MitkCESTDicomWithMetaFileMimeType::AppliesTo(const std::string& path) const { bool canRead(IOMimeTypes::BaseDicomMimeType::AppliesTo(path)); // fix for bug 18572 // Currently this function is called for writing as well as reading, in that case // the image information can of course not be read // This is a bug, this function should only be called for reading. if (!itksys::SystemTools::FileExists(path.c_str())) { return canRead; } // end fix for bug 18572 if (!canRead) { return canRead; } std::string dir = path; if (!itksys::SystemTools::FileIsDirectory(path)) { dir = itksys::SystemTools::GetProgramPath(path); } std::string metafilePath = dir +"/" + "CEST_META.json"; canRead = itksys::SystemTools::FileExists(metafilePath.c_str()); return canRead; } MitkCESTIOMimeTypes::MitkCESTDicomWithMetaFileMimeType* MitkCESTIOMimeTypes::MitkCESTDicomWithMetaFileMimeType::Clone() const { return new MitkCESTDicomWithMetaFileMimeType(*this); } MitkCESTIOMimeTypes::MitkCESTDicomWithMetaFileMimeType MitkCESTIOMimeTypes::CEST_DICOM_WITH_META_FILE_MIMETYPE() { return MitkCESTDicomWithMetaFileMimeType(); } std::string MitkCESTIOMimeTypes::CEST_DICOM_WITH_META_FILE_NAME() { // create a unique and sensible name for this mime type static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".image.dicom.cest.generic.meta"; return name; } MitkCESTIOMimeTypes::MitkCESTDicomWOMetaFileMimeType::MitkCESTDicomWOMetaFileMimeType() : IOMimeTypes::BaseDicomMimeType(CEST_DICOM_WITHOUT_META_FILE_NAME()) { this->SetCategory(IOMimeTypes::CATEGORY_IMAGES()); this->SetComment("CEST DICOM"); } bool MitkCESTIOMimeTypes::MitkCESTDicomWOMetaFileMimeType::AppliesTo(const std::string& path) const { bool canRead(IOMimeTypes::BaseDicomMimeType::AppliesTo(path)); // fix for bug 18572 // Currently this function is called for writing as well as reading, in that case // the image information can of course not be read // This is a bug, this function should only be called for reading. if (!itksys::SystemTools::FileExists(path.c_str())) { return canRead; } // end fix for bug 18572 if (!canRead) { return canRead; } std::string dir = path; if (!itksys::SystemTools::FileIsDirectory(path)) { dir = itksys::SystemTools::GetProgramPath(path); } std::string metafilePath = dir + "/" + "CEST_META.json"; canRead = !itksys::SystemTools::FileExists(metafilePath.c_str()); return canRead; } MitkCESTIOMimeTypes::MitkCESTDicomWOMetaFileMimeType* MitkCESTIOMimeTypes::MitkCESTDicomWOMetaFileMimeType::Clone() const { return new MitkCESTDicomWOMetaFileMimeType(*this); } MitkCESTIOMimeTypes::MitkCESTDicomWOMetaFileMimeType MitkCESTIOMimeTypes::CEST_DICOM_WITHOUT_META_FILE_MIMETYPE() { return MitkCESTDicomWOMetaFileMimeType(); } std::string MitkCESTIOMimeTypes::CEST_DICOM_WITHOUT_META_FILE_NAME() { // create a unique and sensible name for this mime type static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".image.dicom.cest.generic.nometa"; return name; } } diff --git a/Modules/Core/include/mitkIOMimeTypes.h b/Modules/Core/include/mitkIOMimeTypes.h index 472aaf028d..c51f1eb3d0 100644 --- a/Modules/Core/include/mitkIOMimeTypes.h +++ b/Modules/Core/include/mitkIOMimeTypes.h @@ -1,103 +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. ============================================================================*/ #ifndef MITKIOMIMETYPES_H #define MITKIOMIMETYPES_H #include "mitkCustomMimeType.h" #include namespace mitk { /** * @ingroup IO * @brief The IOMimeTypes class */ class MITKCORE_EXPORT IOMimeTypes { public: /** Base mime types for all kind of DICOM images, that can be reused by more specific mime types based on DICOM images.*/ class MITKCORE_EXPORT BaseDicomMimeType : public CustomMimeType { public: BaseDicomMimeType(const std::string &name); - BaseDicomMimeType(const BaseDicomMimeType& other); + BaseDicomMimeType(const BaseDicomMimeType& other) = default; bool AppliesTo(const std::string& path) const override; BaseDicomMimeType* Clone() const override; }; class MITKCORE_EXPORT DicomMimeType : public BaseDicomMimeType { public: DicomMimeType(); DicomMimeType *Clone() const override; }; static std::vector Get(); static std::string DEFAULT_BASE_NAME(); // application/vnd.mitk static std::string CATEGORY_IMAGES(); // Images static std::string CATEGORY_SURFACES(); // Surfaces // ------------------------------ VTK formats ---------------------------------- static CustomMimeType VTK_IMAGE_MIMETYPE(); // (mitk::Image) vti static CustomMimeType VTK_IMAGE_LEGACY_MIMETYPE(); // (mitk::Image) vtk static CustomMimeType VTK_PARALLEL_IMAGE_MIMETYPE(); // (mitk::Image) pvti static CustomMimeType VTK_POLYDATA_MIMETYPE(); // (mitk::Surface) vtp, vtk static CustomMimeType VTK_POLYDATA_LEGACY_MIMETYPE(); // (mitk::Surface) vtk static CustomMimeType VTK_PARALLEL_POLYDATA_MIMETYPE(); // (mitk::Surface) pvtp static CustomMimeType STEREOLITHOGRAPHY_MIMETYPE(); // (mitk::Surface) stl static CustomMimeType WAVEFRONT_OBJ_MIMETYPE(); // (mitk::Surface) obj static CustomMimeType STANFORD_PLY_MIMETYPE(); // (mitk::Surface) ply static std::string STEREOLITHOGRAPHY_NAME(); // DEFAULT_BASE_NAME.stl static std::string VTK_IMAGE_NAME(); // DEFAULT_BASE_NAME.vtk.image static std::string VTK_IMAGE_LEGACY_NAME(); // DEFAULT_BASE_NAME.vtk.image.legacy static std::string VTK_PARALLEL_IMAGE_NAME(); // DEFAULT_BASE_NAME.vtk.parallel.image static std::string VTK_POLYDATA_NAME(); // DEFAULT_BASE_NAME.vtk.polydata static std::string VTK_POLYDATA_LEGACY_NAME(); // DEFAULT_BASE_NAME.vtk.polydata.legacy static std::string VTK_PARALLEL_POLYDATA_NAME(); // DEFAULT_BASE_NAME.vtk.parallel.polydata static std::string WAVEFRONT_OBJ_NAME(); // DEFAULT_BASE_NAME.obj static std::string STANFORD_PLY_NAME(); // DEFAULT_BASE_NAME.ply // ------------------------- Image formats (ITK based) -------------------------- static CustomMimeType NRRD_MIMETYPE(); // nrrd, nhdr static CustomMimeType NIFTI_MIMETYPE(); static CustomMimeType RAW_MIMETYPE(); // raw static DicomMimeType DICOM_MIMETYPE(); static std::string NRRD_MIMETYPE_NAME(); // DEFAULT_BASE_NAME.nrrd static std::string NIFTI_MIMETYPE_NAME(); static std::string RAW_MIMETYPE_NAME(); // DEFAULT_BASE_NAME.raw static std::string DICOM_MIMETYPE_NAME(); // ------------------------------ MITK formats ---------------------------------- static CustomMimeType POINTSET_MIMETYPE(); // mps static CustomMimeType GEOMETRY_DATA_MIMETYPE(); // .mitkgeometry static std::string POINTSET_MIMETYPE_NAME(); // DEFAULT_BASE_NAME.pointset private: // purposely not implemented IOMimeTypes(); IOMimeTypes(const IOMimeTypes &); }; } #endif // MITKIOMIMETYPES_H diff --git a/Modules/Core/src/IO/mitkIOMimeTypes.cpp b/Modules/Core/src/IO/mitkIOMimeTypes.cpp index ad668de0d3..e9cf938b29 100644 --- a/Modules/Core/src/IO/mitkIOMimeTypes.cpp +++ b/Modules/Core/src/IO/mitkIOMimeTypes.cpp @@ -1,363 +1,359 @@ /*============================================================================ 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_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; } }