16 #include <itkTimeProbesCollectorBase.h> 24 itk::MutexLock::Pointer mitk::DICOMITKSeriesGDCMReader::s_LocaleMutex = itk::MutexLock::New();
29 , m_FixTiltByShearing(m_DefaultFixTiltByShearing)
30 , m_SimpleVolumeReading( simpleVolumeImport )
31 , m_DecimalPlacesForOrientation( decimalPlacesForOrientation )
32 , m_ExternalCache(false)
34 this->EnsureMandatorySortersArePresent( decimalPlacesForOrientation, simpleVolumeImport );
41 , m_SortingResultInProgress( other.m_SortingResultInProgress )
42 , m_Sorter( other.m_Sorter )
45 , m_ReplacedCLocales( other.m_ReplacedCLocales )
46 , m_ReplacedCinLocales( other.m_ReplacedCinLocales )
47 , m_DecimalPlacesForOrientation( other.m_DecimalPlacesForOrientation )
48 , m_TagCache( other.m_TagCache )
49 , m_ExternalCache(other.m_ExternalCache)
64 this->m_SortingResultInProgress = other.m_SortingResultInProgress;
65 this->m_Sorter = other.m_Sorter;
68 this->m_ReplacedCLocales = other.m_ReplacedCLocales;
69 this->m_ReplacedCinLocales = other.m_ReplacedCinLocales;
70 this->m_DecimalPlacesForOrientation = other.m_DecimalPlacesForOrientation;
71 this->m_TagCache = other.m_TagCache;
78 if (
const auto* otherSelf = dynamic_cast<const Self*>( &other ) )
81 && *( this->m_EquiDistantBlocksSorter ) == *( otherSelf->m_EquiDistantBlocksSorter )
82 && ( fabs( this->m_DecimalPlacesForOrientation - otherSelf->m_DecimalPlacesForOrientation ) <
eps ) )
85 if ( this->m_Sorter.size() != otherSelf->m_Sorter.size() )
88 auto mySorterIter = this->m_Sorter.cbegin();
89 auto oSorterIter = otherSelf->m_Sorter.cbegin();
90 for ( ; mySorterIter != this->m_Sorter.cend() && oSorterIter != otherSelf->m_Sorter.cend();
91 ++mySorterIter, ++oSorterIter )
93 if ( !( **mySorterIter == **oSorterIter ) )
135 unsigned int sortIndex( 1 );
136 for (
auto sorterIter = m_Sorter.cbegin(); sorterIter != m_Sorter.cend(); ++sortIndex, ++sorterIter )
138 os <<
"Sorting step " << sortIndex <<
":" << std::endl;
139 ( *sorterIter )->PrintConfiguration( os,
" " );
142 os <<
"Sorting step " << sortIndex <<
":" << std::endl;
149 return setlocale( LC_NUMERIC,
nullptr );
154 s_LocaleMutex->Lock();
156 std::string currentCLocale = setlocale( LC_NUMERIC,
nullptr );
157 m_ReplacedCLocales.push( currentCLocale );
158 setlocale( LC_NUMERIC,
"C" );
160 std::locale currentCinLocale( std::cin.getloc() );
161 m_ReplacedCinLocales.push( currentCinLocale );
162 std::locale l(
"C" );
165 s_LocaleMutex->Unlock();
170 s_LocaleMutex->Lock();
172 if ( !m_ReplacedCLocales.empty() )
174 setlocale( LC_NUMERIC, m_ReplacedCLocales.top().c_str() );
175 m_ReplacedCLocales.pop();
179 MITK_WARN <<
"Mismatched PopLocale on DICOMITKSeriesGDCMReader.";
182 if ( !m_ReplacedCinLocales.empty() )
184 std::cin.imbue( m_ReplacedCinLocales.top() );
185 m_ReplacedCinLocales.pop();
189 MITK_WARN <<
"Mismatched PopLocale on DICOMITKSeriesGDCMReader.";
192 s_LocaleMutex->Unlock();
201 #if defined( MBILOG_ENABLE_DEBUG ) || defined( ENABLE_TIMING ) 202 #define timeStart( part ) timer.Start( part ); 203 #define timeStop( part ) timer.Stop( part ); 205 #define timeStart( part ) 206 #define timeStop( part ) 211 itk::TimeProbesCollectorBase timer;
220 if ( inputFilenames.empty() || !this->
CanHandleFile( inputFilenames.front() )
222 || !this->
CanHandleFile( inputFilenames[inputFilenames.size() / 2] )
226 MITK_DEBUG <<
"Reader unable to process files..";
233 if ( m_TagCache.IsNull() || ( m_TagCache->GetMTime()<this->GetMTime() && !m_ExternalCache ))
238 filescanner->SetInputFiles( inputFilenames );
245 m_TagCache = filescanner->GetScanCache();
254 m_SortingResultInProgress.clear();
255 m_SortingResultInProgress.push_back(m_TagCache->GetFrameInfoList());
260 unsigned int sorterIndex = 0;
261 for (
auto sorterIter = m_Sorter.cbegin(); sorterIter != m_Sorter.cend(); ++sorterIndex, ++sorterIter )
263 std::stringstream ss;
264 ss <<
"Sorting step " << sorterIndex;
266 m_SortingResultInProgress =
277 timeStop(
"EquiDistantBlocksSorter" );
283 m_SortingResultInProgress = this->
Condense3DBlocks( m_SortingResultInProgress );
291 o + m_SortingResultInProgress.size() );
292 for (
auto blockIter = m_SortingResultInProgress.cbegin(); blockIter != m_SortingResultInProgress.cend();
296 assert( !gdcmFrameInfoList.empty() );
309 assert( !frameList.empty() );
317 block.SetImageFrameList( frameList );
318 block.SetTiltInformation( tiltInfo );
326 #if defined( MBILOG_ENABLE_DEBUG ) || defined( ENABLE_TIMING ) 327 std::cout <<
"---------------------------------------------------------------" << std::endl;
328 timer.Report( std::cout );
329 std::cout <<
"---------------------------------------------------------------" << std::endl;
334 unsigned int sortingStepIndex,
const DICOMDatasetSorter::Pointer& sorter,
const SortingBlockList& input )
337 std::stringstream ss;
338 ss <<
"Sorting step " << sortingStepIndex <<
" '";
339 #if defined( MBILOG_ENABLE_DEBUG ) 340 sorter->PrintConfiguration( ss );
343 nextStepSorting.clear();
345 MITK_DEBUG <<
"================================================================================";
346 MITK_DEBUG <<
"DICOMITKSeriesGDCMReader: " << ss.str() <<
": " << input.size() <<
" groups input";
347 unsigned int groupIndex = 0;
349 for (
auto blockIter = input.cbegin(); blockIter != input.cend(); ++groupIndex, ++blockIter )
354 #if defined( MBILOG_ENABLE_DEBUG ) 355 MITK_DEBUG <<
"--------------------------------------------------------------------------------";
356 MITK_DEBUG <<
"DICOMITKSeriesGDCMReader: " << ss.str() <<
", dataset group " << groupIndex <<
" (" 357 << datasetList.size() <<
" datasets): ";
358 for (
auto oi = datasetList.cbegin(); oi != datasetList.cend(); ++oi )
360 MITK_DEBUG <<
" INPUT : " << ( *oi )->GetFilenameIfAvailable();
364 sorter->SetInput( datasetList );
366 unsigned int numberOfResultingBlocks = sorter->GetNumberOfOutputs();
368 for (
unsigned int b = 0; b < numberOfResultingBlocks; ++b )
372 for (
auto oi = blockResult.cbegin(); oi != blockResult.cend(); ++oi )
374 MITK_DEBUG <<
" OUTPUT(" << b <<
") :" << ( *oi )->GetFilenameIfAvailable();
378 nextStepSorting.push_back( sortedGdcmInfoFrameList );
382 return nextStepSorting;
388 if ( sopClassUID.empty() )
393 gdcm::UIDs uidKnowledge;
394 uidKnowledge.SetFromUID( sopClassUID.c_str() );
396 gdcm::UIDs::TSName gdcmType =
static_cast<gdcm::UIDs::TSName
>((gdcm::UIDs::TSType)uidKnowledge);
400 case gdcm::UIDs::CTImageStorage:
401 case gdcm::UIDs::MRImageStorage:
402 case gdcm::UIDs::PositronEmissionTomographyImageStorage:
403 case gdcm::UIDs::ComputedRadiographyImageStorage:
404 case gdcm::UIDs::DigitalXRayImageStorageForPresentation:
405 case gdcm::UIDs::DigitalXRayImageStorageForProcessing:
408 case gdcm::UIDs::NuclearMedicineImageStorage:
411 case gdcm::UIDs::SecondaryCaptureImageStorage:
426 for (
unsigned int o = 0; o < numberOfOutputs; ++o )
443 filenames.reserve( frames.size() );
444 for (
auto frameIter = frames.cbegin(); frameIter != frames.cend(); ++frameIter )
446 filenames.push_back( ( *frameIter )->Filename );
450 bool success(
true );
456 catch (
const std::exception& e )
459 MITK_ERROR <<
"Exception during image loading: " << e.what();
486 m_Sorter.push_front( sorter );
490 m_Sorter.push_back( sorter );
498 std::list<DICOMDatasetSorter::ConstPointer> result;
500 unsigned int sortIndex( 0 );
501 for (
auto sorterIter = m_Sorter.begin(); sorterIter != m_Sorter.end(); ++sortIndex, ++sorterIter )
505 result.push_back( ( *sorterIter ).GetPointer() );
512 void mitk::DICOMITKSeriesGDCMReader::EnsureMandatorySortersArePresent(
513 unsigned int decimalPlacesForOrientation,
bool simpleVolumeImport )
516 splitter->AddDistinguishingTag(
DICOMTag(0x0028, 0x0010) );
517 splitter->AddDistinguishingTag(
DICOMTag(0x0028, 0x0011) );
518 splitter->AddDistinguishingTag(
DICOMTag(0x0028, 0x0030) );
519 splitter->AddDistinguishingTag(
DICOMTag(0x0018, 0x1164) );
521 splitter->AddDistinguishingTag(
DICOMTag(0x0018, 0x0050) );
522 if ( simpleVolumeImport )
524 MITK_DEBUG <<
"Simple volume reading: ignoring number of frames";
528 splitter->AddDistinguishingTag(
DICOMTag(0x0028, 0x0008) );
573 return m_DecimalPlacesForOrientation;
583 m_TagCache = tagCache;
584 m_ExternalCache = tagCache.IsNotNull();
592 for (
auto sorterIter = m_Sorter.cbegin(); sorterIter != m_Sorter.cend(); ++sorterIter )
594 assert( sorterIter->IsNotNull() );
596 const DICOMTagList tags = ( *sorterIter )->GetTagsOfInterest();
597 completeList.insert( completeList.end(), tags.cbegin(), tags.cend() );
602 completeList.insert( completeList.end(), tags.cbegin(), tags.cend() );
605 completeList.insert( completeList.end(), tags.cbegin(), tags.cend() );
609 completeList.insert( completeList.end(), tags.cbegin(), tags.cend() );
613 for (
auto iter = tagList.cbegin();
614 iter != tagList.cend();
618 completeList.push_back( iter->first ) ;
void SetToleratedOriginOffsetToAdaptive(double fractionOfInterSliceDistanct=0.3) const
See Forced Configuration.
static DICOMTagList GetTagsOfInterest()
bool CanHandleFile(const std::string &filename) override
Indicate whether this reader can handle given file.
virtual bool LoadMitkImageForImageBlockDescriptor(DICOMImageBlockDescriptor &block) const
const GantryTiltInformation GetTiltInformation() const
Describe the gantry tilt of the acquisition.
void InternalPrintConfiguration(std::ostream &os) const override
Configuration description for human reader, to be implemented by sub-classes.
mitk::DICOMImageBlockDescriptor::TagLookupTableToPropertyFunctor GetTagLookupTableToPropertyFunctor() const
loader did not yet inspect any images, unknown fitness
bool operator==(const DICOMFileReader &other) const override
double GetToleratedOriginError() const
The sorting/splitting building-block of DICOMITKSeriesGDCMReader.
Flexible reader based on itk::ImageSeriesReader and GDCM, for single-slice modalities like CT...
static bool CanHandleFile(const std::string &filename)
std::vector< DICOMTag > DICOMTagList
static std::string GetActiveLocale()
Return active C locale.
void SetTagCache(const DICOMTagCache::Pointer &) override
A way to provide external knowledge about files and tag values is appreciated.
void SetNumberOfOutputs(unsigned int numberOfOutputs)
ConstSorterList GetFreelyConfiguredSortingElements() const
mitk::EquiDistantBlocksSorter::Pointer m_EquiDistantBlocksSorter
Representation of a DICOM tag.
Image::Pointer Load(const StringContainer &filenames, bool correctTilt, const GantryTiltInformation &tiltInfo)
void AnalyzeInputFiles() override
Runs the sorting / splitting process described in Loading strategy. Method required by DICOMFileReade...
void SetFixTiltByShearing(bool on)
Controls whether to "fix" tilted acquisitions by shearing the output (see Gantry tilt handling)...
virtual AdditionalTagsMapType GetAdditionalTagsOfInterest() const
double GetDecimalPlacesForOrientation() const
MITKDICOMREADER_EXPORT mitk::DICOMDatasetList ConvertToDICOMDatasetList(const DICOMDatasetAccessingImageFrameList &input)
void SetOutput(unsigned int index, const DICOMImageBlockDescriptor &output)
loader code and tests are established
virtual SortingBlockList Condense3DBlocks(SortingBlockList &resultOf3DGrouping)
"Hook" for sub-classes, see Sub-classes can condense multiple blocks into a single larger block ...
MITKDICOMREADER_EXPORT mitk::DICOMDatasetAccessingImageFrameList ConvertToDICOMDatasetAccessingImageFrameList(const DICOMDatasetList &input)
const DICOMImageFrameList & GetImageFrameList() const
List of frames that constitute the mitk::Image (DICOMImageFrames)
const StringList & GetInputFiles() const
This input files.
void PushLocale() const
Remember current locale on stack, activate "C" locale. "C" locale is required for correct parsing of ...
bool GetAcceptTwoSlicesGroups() const
bool LoadImages() override
Loads images using itk::ImageSeriesReader, potentially applies shearing to correct gantry tilt...
static SortingBlockList InternalExecuteSortingStep(unsigned int sortingStepIndex, const DICOMDatasetSorter::Pointer &sorter, const SortingBlockList &input)
Sorting step as described in Loading strategy.
loader code is not known to work with this SOP Class
loader code is implemented but not accompanied by tests
void SetMitkImage(Image::Pointer image)
The 3D mitk::Image that is loaded from the DICOM files of a DICOMImageFrameList.
unsigned int GetNumberOfOutputs() const
Number of outputs, only meaningful after calling AnalyzeInputFiles()
const std::list< DICOMDatasetSorter::ConstPointer > ConstSorterList
ReaderImplementationLevel
Describes how well the reader is tested for a certain file type (see mitk::DICOMFileReader).
void SetToleratedOriginOffset(double millimeters=0.005) const
See Forced Configuration.
void PopLocale() const
Activate last remembered locale from locale stack "C" locale is required for correct parsing of numbe...
bool IsToleratedOriginOffsetAbsolute() const
std::vector< DICOMImageFrameInfo::Pointer > DICOMImageFrameList
DICOMImageBlockDescriptor & InternalGetOutput(unsigned int index)
non-const access to the DICOMImageBlockDescriptor
DICOMImageBlockDescriptor::AdditionalTagsMapType AdditionalTagsMapType
Output descriptor for DICOMFileReader.
void SetTagCache(DICOMTagCache *privateCache)
virtual void AddSortingElement(DICOMDatasetSorter *sorter, bool atFront=false)
Add an element to the sorting procedure described in Loading strategy.
virtual bool LoadMitkImageForOutput(unsigned int o)
Loads the mitk::Image by means of an itk::ImageSeriesReader.
std::vector< std::string > StringList
std::vector< DICOMTagPath > DICOMTagPathList
std::vector< DICOMDatasetAccessingImageFrameList > SortingBlockList
MITKDICOMREADER_EXPORT mitk::DICOMImageFrameList ConvertToDICOMImageFrameList(const DICOMDatasetAccessingImageFrameList &input)
static ReaderImplementationLevel GetReaderImplementationLevel(const std::string sopClassUID)
Describe this reader's confidence for given SOP class UID.
std::vector< DICOMDatasetAccessingImageFrameInfo::Pointer > DICOMDatasetAccessingImageFrameList
Cuts a number after configured number of decimal places. An instance of this class can be used to avo...
loader code and tests are establised for specific parts of a SOP Class
DICOMITKSeriesGDCMReader & operator=(const DICOMITKSeriesGDCMReader &other)
MITKCORE_EXPORT const ScalarType eps
~DICOMITKSeriesGDCMReader() override
void SetAcceptTwoSlicesGroups(bool accept) const
Controls whether groups of only two images are accepted when ensuring consecutive slices via EquiDist...
DICOMFileReader & operator=(const DICOMFileReader &other)
std::vector< DICOMDatasetAccess * > DICOMDatasetList
Interface for DICOM readers that produce mitk::Images.
mitk::NormalDirectionConsistencySorter::Pointer m_NormalDirectionConsistencySorter
virtual DICOMTagCache::Pointer GetTagCache() const
DICOMITKSeriesGDCMReader(unsigned int decimalPlacesForOrientation=m_DefaultDecimalPlacesForOrientation, bool simpleVolumeImport=m_DefaultSimpleVolumeImport)
std::vector< std::string > StringContainer
bool GetFixTiltByShearing() const
bool m_SimpleVolumeReading
DICOMTagPathList GetTagsOfInterest() const override