diff --git a/Modules/DICOMReader/TODOs.txt b/Modules/DICOMReader/TODOs.txt index c12f7a98d9..a091613045 100644 --- a/Modules/DICOMReader/TODOs.txt +++ b/Modules/DICOMReader/TODOs.txt @@ -1,36 +1,36 @@ Important [ ] ONLY load a pre-sorted list [ ] Either NRRD cache option or slice-by-slice loading [x] Performance of mitkdump / DICOMReaderSelector (TagCache?) - the note in GDCM..Reader::GetTagValue() is correct. This piece of code is taking lots of time. Approx. half of the time is tag scanning, the other half is construction of block describing properties, which accesses GetTagValue. [x] - maybe we can evaluate these properties in a lazy way (only when asked for). Solution: Yes, this helps, implemented. [x] Sorting by "Image Time" seems undeterministic (clarkson test data) [x] - Numeric conversion of "1.2.3.4" yields 1.2 on Windows, seems to fail on Linux(?) - need to verify that the whole string (except whitespace at the begin/end) was converted Solution: GetTagValue as String does a right-trim plus we check after conversion! Works. -[ ] Implement Configurator::GetBuiltIn3DReaders() (don't ignore "classic reader") +[x] Implement Configurator::GetBuiltIn3DReaders() (don't ignore "classic reader") [ ] Complete MITK properties of images: level/window and color type (MONOCHROME1/2) [ ] Check input images fo DICOMness and non-multi-frameness [ ] Use CanReadFile() in selection! [ ] Check TODO in mitkDICOMTag.cpp [ ] Configurable precision for tag value comparisons [x] Images are upside-down in some cases - error was hidden assumption somewhere: filenames for ImageSeriesReader need to be in an order that goes along the image normals, not in the opposite direction Questionable [ ] Fallback to filename instead of instance UID? Nice-to-have [ ] Multi-Frame images (DCMTK) [ ] ... diff --git a/Modules/DICOMReader/mitkDICOMFileReaderSelector.cpp b/Modules/DICOMReader/mitkDICOMFileReaderSelector.cpp index 7ee1bf1581..100003b88b 100644 --- a/Modules/DICOMReader/mitkDICOMFileReaderSelector.cpp +++ b/Modules/DICOMReader/mitkDICOMFileReaderSelector.cpp @@ -1,226 +1,233 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkDICOMFileReaderSelector.h" #include "mitkDICOMReaderConfigurator.h" #include "mitkModuleContext.h" #include #include #include #include mitk::DICOMFileReaderSelector ::DICOMFileReaderSelector() { } mitk::DICOMFileReaderSelector ::~DICOMFileReaderSelector() { } +std::list +mitk::DICOMFileReaderSelector +::GetAllConfiguredReaders() const +{ + return m_Readers; +} + void mitk::DICOMFileReaderSelector ::AddConfigsFromResources(const std::string& path) { std::vector configs = GetModuleContext()->GetModule()->FindResources(path, "*.xml", false); for (std::vector::iterator iter = configs.begin(); iter != configs.end(); ++iter) { ModuleResource& resource = *iter; if (resource.IsValid()) { ModuleResourceStream stream(resource); // read all into string s std::string s; stream.seekg(0, std::ios::end); s.reserve(stream.tellg()); stream.seekg(0, std::ios::beg); s.assign((std::istreambuf_iterator(stream)), std::istreambuf_iterator()); //MITK_INFO << "------------ One resource with content\n" << s << "\n------- end -------"; this->AddConfig(s); } } } void mitk::DICOMFileReaderSelector ::AddConfigFromResource(ModuleResource& resource) { if (resource.IsValid()) { ModuleResourceStream stream(resource); // read all into string s std::string s; stream.seekg(0, std::ios::end); s.reserve(stream.tellg()); stream.seekg(0, std::ios::beg); s.assign((std::istreambuf_iterator(stream)), std::istreambuf_iterator()); //MITK_INFO << "------------ One resource with content\n" << s << "\n------- end -------"; this->AddConfig(s); } } void mitk::DICOMFileReaderSelector ::AddConfigFromResource(const std::string& resourcename) { ModuleResource r = GetModuleContext()->GetModule()->GetResource(resourcename); this->AddConfigFromResource(r); } void mitk::DICOMFileReaderSelector ::LoadBuiltIn3DConfigs() { //this->AddConfigsFromResources("configurations/3D"); // in this order of preference... this->AddConfigFromResource("configurations/3D/instancenumber.xml"); this->AddConfigFromResource("configurations/3D/imageposition.xml"); this->AddConfigFromResource("configurations/3D/slicelocation.xml"); this->AddConfigFromResource("configurations/3D/imagetime.xml"); } void mitk::DICOMFileReaderSelector ::LoadBuiltIn3DnTConfigs() { this->AddConfigsFromResources("configurations/3DnT"); } void mitk::DICOMFileReaderSelector ::AddConfig(const std::string& xmlDescription) { DICOMReaderConfigurator::Pointer configurator = DICOMReaderConfigurator::New(); DICOMFileReader::Pointer reader = configurator->CreateFromUTF8ConfigString(xmlDescription); if (reader.IsNotNull()) { m_Readers.push_back( reader ); m_PossibleConfigurations.push_back(xmlDescription); } else { std::stringstream ss; ss << "Could not parse reader configuration. Ignoring it."; throw std::invalid_argument( ss.str() ); } } void mitk::DICOMFileReaderSelector ::AddConfigFile(const std::string& filename) { std::ifstream file(filename.c_str()); std::string s; file.seekg(0, std::ios::end); s.reserve(file.tellg()); file.seekg(0, std::ios::beg); s.assign((std::istreambuf_iterator(file)), std::istreambuf_iterator()); this->AddConfig(s); } void mitk::DICOMFileReaderSelector ::SetInputFiles(StringList filenames) { m_InputFilenames = filenames; } const mitk::StringList& mitk::DICOMFileReaderSelector ::GetInputFiles() const { return m_InputFilenames; } mitk::DICOMFileReader::Pointer mitk::DICOMFileReaderSelector ::GetFirstReaderWithMinimumNumberOfOutputImages() { ReaderList workingCandidates; // let all readers analyze the file set unsigned int readerIndex(0); for (ReaderList::iterator rIter = m_Readers.begin(); rIter != m_Readers.end(); ++readerIndex, ++rIter) { (*rIter)->SetInputFiles( m_InputFilenames ); try { (*rIter)->AnalyzeInputFiles(); workingCandidates.push_back( *rIter ); MITK_INFO << "Reader " << readerIndex << " (" << (*rIter)->GetConfigurationLabel() << ") suggests " << (*rIter)->GetNumberOfOutputs() << " 3D blocks"; if ((*rIter)->GetNumberOfOutputs() == 1) { MITK_DEBUG << "Early out with reader #" << readerIndex << " (" << (*rIter)->GetConfigurationLabel() << "), less than 1 block is not possible"; return *rIter; } } catch (std::exception& e) { MITK_ERROR << "Reader " << readerIndex << " (" << (*rIter)->GetConfigurationLabel() << ") threw exception during file analysis, ignoring this reader. Exception: " << e.what(); } catch (...) { MITK_ERROR << "Reader " << readerIndex << " (" << (*rIter)->GetConfigurationLabel() << ") threw unknown exception during file analysis, ignoring this reader."; } } DICOMFileReader::Pointer bestReader; unsigned int minimumNumberOfOutputs = std::numeric_limits::max(); readerIndex = 0; unsigned int bestReaderIndex(0); // select the reader with the minimum number of mitk::Images as output for (ReaderList::iterator rIter = workingCandidates.begin(); rIter != workingCandidates.end(); ++readerIndex, ++rIter) { if ( (*rIter)->GetNumberOfOutputs() < minimumNumberOfOutputs ) { minimumNumberOfOutputs = (*rIter)->GetNumberOfOutputs(); bestReader = *rIter; bestReaderIndex = readerIndex; } } MITK_DEBUG << "Decided for reader #" << bestReaderIndex << " (" << bestReader->GetConfigurationLabel() << ")"; MITK_DEBUG << m_PossibleConfigurations[bestReaderIndex]; return bestReader; } diff --git a/Modules/DICOMReader/mitkDICOMFileReaderSelector.h b/Modules/DICOMReader/mitkDICOMFileReaderSelector.h index 7133c5a7b3..e8c332aff6 100644 --- a/Modules/DICOMReader/mitkDICOMFileReaderSelector.h +++ b/Modules/DICOMReader/mitkDICOMFileReaderSelector.h @@ -1,95 +1,101 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkDICOMFileReaderSelector_h #define mitkDICOMFileReaderSelector_h #include "mitkDICOMFileReader.h" #include namespace mitk { /** \ingroup DICOMReaderModule \brief Simple best-reader selection. This class implements a process of comparing different DICOMFileReader%s and selecting the reader with the minimal number of mitk::Image%s in its output. The code found in this class can - just be used to select a reader using this simple strategy - be taken as an example of how to use DICOMFileReader%s To create a selection of potential readers, the class makes use of mitk::DICOMReaderConfigurator, i.e. DICOMFileReaderSelector also expects the configuration files/strings to be in the format expected by mitk::DICOMReaderConfigurator. Two convenience methods load "default" configurations from compiled-in resources: LoadBuiltIn3DConfigs() and LoadBuiltIn3DnTConfigs(). */ class DICOMReader_EXPORT DICOMFileReaderSelector : public itk::LightObject { public: + typedef std::list ReaderList; + mitkClassMacro( DICOMFileReaderSelector, itk::LightObject ) itkNewMacro( DICOMFileReaderSelector ) /// \brief Add a configuration as expected by DICOMReaderConfigurator. /// Configs can only be reset by instantiating a new DICOMFileReaderSelector. void AddConfig(const std::string& xmlDescription); /// \brief Add a configuration as expected by DICOMReaderConfigurator. /// Configs can only be reset by instantiating a new DICOMFileReaderSelector. void AddConfigFile(const std::string& filename); /// \brief Load 3D image creating configurations from the MITK module system (see \ref mitk::Module::FindResources). /// For a default set of configurations, look into the directory Resources of the DICOMReader module. void LoadBuiltIn3DConfigs(); /// \brief Load 3D+t image creating configurations from the MITK module system (see \ref mitk::Module::FindResources). /// For a default set of configurations, look into the directory Resources of the DICOMReader module. void LoadBuiltIn3DnTConfigs(); + /// \brief Return all the DICOMFileReader%s that are currently used for selection by this class. + /// The readers returned by this method depend on what config files have been added earlier + /// (or which of the built-in readers have been loaded) + ReaderList GetAllConfiguredReaders() const; + /// Input files void SetInputFiles(StringList filenames); /// Input files const StringList& GetInputFiles() const; /// Execute the analysis and selection process. The first reader with a minimal number of outputs will be returned. DICOMFileReader::Pointer GetFirstReaderWithMinimumNumberOfOutputImages(); protected: DICOMFileReaderSelector(); virtual ~DICOMFileReaderSelector(); void AddConfigsFromResources(const std::string& path); void AddConfigFromResource(const std::string& resourcename); void AddConfigFromResource(ModuleResource& resource); private: StringList m_PossibleConfigurations; StringList m_InputFilenames; - typedef std::list ReaderList; ReaderList m_Readers; }; } // namespace #endif // mitkDICOMFileReaderSelector_h