diff --git a/Modules/DICOMReader/include/mitkBaseDICOMReaderService.h b/Modules/DICOMReader/include/mitkBaseDICOMReaderService.h index ed9be04529..8052d78f5b 100644 --- a/Modules/DICOMReader/include/mitkBaseDICOMReaderService.h +++ b/Modules/DICOMReader/include/mitkBaseDICOMReaderService.h @@ -1,60 +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 MITKBASEDICOMREADERSERVICE_H #define MITKBASEDICOMREADERSERVICE_H #include #include #include "MitkDICOMReaderExports.h" namespace mitk { /** Base class for service wrappers that make DICOMFileReader from the DICOMReader module usable. */ class MITKDICOMREADER_EXPORT BaseDICOMReaderService : public AbstractFileReader { public: BaseDICOMReaderService(const std::string& description); BaseDICOMReaderService(const mitk::CustomMimeType& customType, const std::string& description); using AbstractFileReader::Read; /** Uses this->GetRelevantFile() and this->GetReader to load the image. * data and puts it into base data instances-*/ std::vector > Read() override; IFileReader::ConfidenceLevel GetConfidenceLevel() const override; protected: /** Returns the list of all DCM files that are in the same directory * like this->GetLocalFileName().*/ - mitk::StringList GetRelevantFiles() const; + mitk::StringList GetDICOMFilesInSameDirectory() const; /** Returns the reader instance that should be used. The descission may be based * one the passed relevant file list.*/ virtual mitk::DICOMFileReader::Pointer GetReader(const mitk::StringList& relevantFiles) const = 0; }; class IPropertyProvider; /** Helper function that generates a name string (e.g. for DataNode names) from the DICOM properties of the passed provider instance. If the instance is nullptr, or has no dicom properties DataNode::NO_NAME_VALUE() will be returned.*/ std::string MITKDICOMREADER_EXPORT GenerateNameFromDICOMProperties(const mitk::IPropertyProvider* provider); } #endif // MITKBASEDICOMREADERSERVICE_H diff --git a/Modules/DICOMReader/include/mitkDICOMFilesHelper.h b/Modules/DICOMReader/include/mitkDICOMFilesHelper.h index 5a80333bd4..104b7f2511 100644 --- a/Modules/DICOMReader/include/mitkDICOMFilesHelper.h +++ b/Modules/DICOMReader/include/mitkDICOMFilesHelper.h @@ -1,37 +1,41 @@ /*============================================================================ 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 MITKDICOMFILESHELPER_H #define MITKDICOMFILESHELPER_H #include #include #include namespace mitk { typedef std::vector DICOMFilePathList; /** Helper functions. Searches for all files in the directory of the passed file path. All files will be checked if they are DICOM files. All DICOM files will be added to the result and returned. @remark The helper does no sorting of any kind.*/ DICOMFilePathList GetDICOMFilesInSameDirectory(const std::string& filePath); /** All passed files will be checked if they are DICOM files. All DICOM files will be added to the result and returned. @remark The helper does no sorting of any kind.*/ DICOMFilePathList FilterForDICOMFiles(const DICOMFilePathList& fileList); + +/** Returns all DICOM files passed with fileList that have the same series instance UID then the passed refFilePath. +@pre refFilePath must point to a valid DICOM file.*/ +DICOMFilePathList FilterDICOMFilesForSameSeries(const std::string& refFilePath, const DICOMFilePathList& fileList); } #endif // MITKDICOMFILESHELPER_H diff --git a/Modules/DICOMReader/src/mitkBaseDICOMReaderService.cpp b/Modules/DICOMReader/src/mitkBaseDICOMReaderService.cpp index 7133c0a14f..9ce4dd008d 100644 --- a/Modules/DICOMReader/src/mitkBaseDICOMReaderService.cpp +++ b/Modules/DICOMReader/src/mitkBaseDICOMReaderService.cpp @@ -1,209 +1,208 @@ /*============================================================================ 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 "mitkBaseDICOMReaderService.h" #include #include #include #include #include #include #include #include "legacy/mitkDicomSeriesReader.h" #include #include #include "mitkIPropertyProvider.h" #include "mitkPropertyNameHelper.h" #include #include #include namespace mitk { BaseDICOMReaderService::BaseDICOMReaderService(const std::string& description) : AbstractFileReader(CustomMimeType(IOMimeTypes::DICOM_MIMETYPE()), description) { } BaseDICOMReaderService::BaseDICOMReaderService(const mitk::CustomMimeType& customType, const std::string& description) : AbstractFileReader(customType, description) { } std::vector > BaseDICOMReaderService::Read() { std::vector result; - std::string fileName = this->GetLocalFileName(); + const std::string fileName = this->GetLocalFileName(); //special handling of Philips 3D US DICOM. //Copied from DICOMSeriesReaderService if (DicomSeriesReader::IsPhilips3DDicom(fileName)) { MITK_INFO << "it is a Philips3D US Dicom file" << std::endl; mitk::LocaleSwitch localeSwitch("C"); std::locale previousCppLocale(std::cin.getloc()); std::locale l("C"); std::cin.imbue(l); DataNode::Pointer node = DataNode::New(); mitk::DicomSeriesReader::StringContainer stringvec; stringvec.push_back(fileName); if (DicomSeriesReader::LoadDicomSeries(stringvec, *node)) { BaseData::Pointer data = node->GetData(); StringProperty::Pointer nameProp = StringProperty::New(itksys::SystemTools::GetFilenameName(fileName)); data->GetPropertyList()->SetProperty("name", nameProp); result.push_back(data); } std::cin.imbue(previousCppLocale); return result; } //Normal DICOM handling (It wasn't a Philips 3D US) - mitk::StringList relevantFiles = this->GetRelevantFiles(); - - // check whether directory or file - // if directory try to find first file within it instead - // We only support this for a single directory at once - if (relevantFiles.empty()) - { - bool pathIsDirectory = itksys::SystemTools::FileIsDirectory(this->GetLocalFileName()); - if (pathIsDirectory) - { - itksys::Directory input; - input.Load(this->GetLocalFileName().c_str()); - - std::vector files; - for (unsigned long idx = 0; idxGetLocalFileName() + "/" + std::string(input.GetFile(idx)); - files.push_back(fullpath.c_str()); - } - } - relevantFiles = files; - } - } + mitk::StringList relevantFiles = this->GetDICOMFilesInSameDirectory(); if (relevantFiles.empty()) { MITK_INFO << "DICOMReader service found no relevant files in specified location. No data is loaded. Location: "<GetReader(relevantFiles); + bool pathIsDirectory = itksys::SystemTools::FileIsDirectory(fileName); + + if (!pathIsDirectory) + { + relevantFiles = mitk::FilterDICOMFilesForSameSeries(fileName, relevantFiles); + } + + mitk::DICOMFileReader::Pointer reader = this->GetReader(relevantFiles); if(reader.IsNull()) { MITK_INFO << "DICOMReader service found no suitable reader configuration for relevant files."; } else { + if (!pathIsDirectory) + { //we ensure that we only load the relevant image block files + for (unsigned int outputIndex = 0; outputIndex < reader->GetNumberOfOutputs(); ++outputIndex) + { + const auto frameList = reader->GetOutput(outputIndex).GetImageFrameList(); + + auto finding = std::find_if(frameList.begin(), frameList.end(), [&](const DICOMImageFrameInfo::Pointer& frame) { return frame->Filename == fileName; }); + + if (finding != frameList.end()) + { //we have the block containing the fileName -> these are the realy relevant files. + relevantFiles.resize(frameList.size()); + std::transform(frameList.begin(), frameList.end(), relevantFiles.begin(), [](const DICOMImageFrameInfo::Pointer& frame) { return frame->Filename; }); + break; + } + } + } const unsigned int ntotalfiles = relevantFiles.size(); for( unsigned int i=0; i< ntotalfiles; i++) { m_ReadFiles.push_back( relevantFiles.at(i) ); } reader->SetAdditionalTagsOfInterest(mitk::GetCurrentDICOMTagsOfInterest()); reader->SetTagLookupTableToPropertyFunctor(mitk::GetDICOMPropertyForDICOMValuesFunctor); reader->SetInputFiles(relevantFiles); mitk::DICOMDCMTKTagScanner::Pointer scanner = mitk::DICOMDCMTKTagScanner::New(); scanner->AddTagPaths(reader->GetTagsOfInterest()); scanner->SetInputFiles(relevantFiles); scanner->Scan(); reader->SetTagCache(scanner->GetScanCache()); reader->AnalyzeInputFiles(); reader->LoadImages(); for (unsigned int i = 0; i < reader->GetNumberOfOutputs(); ++i) { const mitk::DICOMImageBlockDescriptor& desc = reader->GetOutput(i); mitk::BaseData::Pointer data = desc.GetMitkImage().GetPointer(); std::string nodeName = GenerateNameFromDICOMProperties(&desc); StringProperty::Pointer nameProp = StringProperty::New(nodeName); data->SetProperty("name", nameProp); result.push_back(data); } } } return result; } -StringList BaseDICOMReaderService::GetRelevantFiles() const +StringList BaseDICOMReaderService::GetDICOMFilesInSameDirectory() const { std::string fileName = this->GetLocalFileName(); mitk::StringList relevantFiles = mitk::GetDICOMFilesInSameDirectory(fileName); return relevantFiles; } IFileReader::ConfidenceLevel BaseDICOMReaderService::GetConfidenceLevel() const { IFileReader::ConfidenceLevel abstractConfidence = AbstractFileReader::GetConfidenceLevel(); if (Unsupported == abstractConfidence) { if (itksys::SystemTools::FileIsDirectory(this->GetInputLocation().c_str())) { // In principle we support dicom directories return Supported; } } return abstractConfidence; } std::string GenerateNameFromDICOMProperties(const mitk::IPropertyProvider* provider) { std::string nodeName = mitk::DataNode::NO_NAME_VALUE(); auto studyProp = provider->GetConstProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x1030).c_str()); if (studyProp.IsNotNull()) { nodeName = studyProp->GetValueAsString(); } auto seriesProp = provider->GetConstProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x103E).c_str()); if (seriesProp.IsNotNull()) { if (studyProp.IsNotNull()) { nodeName += " / "; } else { nodeName = ""; } nodeName += seriesProp->GetValueAsString(); } return nodeName; }; } diff --git a/Modules/DICOMReader/src/mitkDICOMFilesHelper.cpp b/Modules/DICOMReader/src/mitkDICOMFilesHelper.cpp index c0faed897c..0943993bb7 100644 --- a/Modules/DICOMReader/src/mitkDICOMFilesHelper.cpp +++ b/Modules/DICOMReader/src/mitkDICOMFilesHelper.cpp @@ -1,49 +1,80 @@ /*============================================================================ 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 "mitkDICOMFilesHelper.h" #include #include #include +#include mitk::DICOMFilePathList mitk::GetDICOMFilesInSameDirectory(const std::string& filePath) { DICOMFilePathList result; if (!filePath.empty()) { - std::string dir = itksys::SystemTools::GetFilenamePath(filePath); + + std::string dir = filePath; + if (!itksys::SystemTools::FileIsDirectory(filePath)) + { + dir = itksys::SystemTools::GetFilenamePath(filePath); + } gdcm::Directory directoryLister; directoryLister.Load(dir.c_str(), false); // non-recursive result = FilterForDICOMFiles(directoryLister.GetFilenames()); } return result; }; mitk::DICOMFilePathList mitk::FilterForDICOMFiles(const DICOMFilePathList& fileList) { mitk::DICOMFilePathList result; itk::GDCMImageIO::Pointer io = itk::GDCMImageIO::New(); for (auto aFile : fileList) { if (io->CanReadFile(aFile.c_str())) { result.push_back(aFile); } } return result; }; + +mitk::DICOMFilePathList mitk::FilterDICOMFilesForSameSeries(const std::string& refFilePath, const DICOMFilePathList& fileList) +{ + auto dicomFiles = FilterForDICOMFiles(fileList); + + //use the gdcm scanner directly instead of our wrapping classes, as it is a very simple task + //and I want to spare the indirection/overhead. + auto scanner = std::make_shared(); + + const gdcm::Tag seriesInstanceUIDTag(0x0020, 0x000e); + + scanner->AddTag(seriesInstanceUIDTag); //Series Instance UID; + + scanner->Scan({ refFilePath }); + auto uid = scanner->GetValue(refFilePath.c_str(), seriesInstanceUIDTag); + + if (uid != nullptr) + { + const std::string refUID = uid; + scanner->Scan(dicomFiles); + return scanner->GetAllFilenamesFromTagToValue(seriesInstanceUIDTag, refUID.c_str()); + } + + return mitk::DICOMFilePathList(); +}