Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
mitkThreeDnTDICOMSeriesReader.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
15 
17 ::ThreeDnTDICOMSeriesReader(unsigned int decimalPlacesForOrientation)
18 :DICOMITKSeriesGDCMReader(decimalPlacesForOrientation)
19 ,m_Group3DandT(m_DefaultGroup3DandT)
20 {
21 }
22 
27 {
28 }
29 
32 {
33 }
34 
38 {
39  if (this != &other)
40  {
42  this->m_Group3DandT = other.m_Group3DandT;
43  }
44  return *this;
45 }
46 
47 bool
49 ::operator==(const DICOMFileReader& other) const
50 {
51  if (const auto* otherSelf = dynamic_cast<const Self*>(&other))
52  {
53  return
55  && this->m_Group3DandT == otherSelf->m_Group3DandT;
56  }
57  else
58  {
59  return false;
60  }
61 }
62 
63 void
66 {
67  m_Group3DandT = on;
68 }
69 
70 bool
73 {
74  return m_Group3DandT;
75 }
76 
80 {
81  if (!m_Group3DandT)
82  {
83  return resultOf3DGrouping; // don't work if nobody asks us to
84  }
85 
86  SortingBlockList remainingBlocks = resultOf3DGrouping;
87 
88  SortingBlockList non3DnTBlocks;
89  SortingBlockList true3DnTBlocks;
90  std::vector<unsigned int> true3DnTBlocksTimeStepCount;
91 
92  // we should describe our need for this tag as needed via a function
93  // (however, we currently know that the superclass will always need this tag)
94  const DICOMTag tagImagePositionPatient(0x0020, 0x0032);
95 
96  while (!remainingBlocks.empty())
97  {
98  // new block to fill up
99  const DICOMDatasetAccessingImageFrameList& firstBlock = remainingBlocks.front();
100  DICOMDatasetAccessingImageFrameList current3DnTBlock = firstBlock;
101  int current3DnTBlockNumberOfTimeSteps = 1;
102 
103  // get block characteristics of first block
104  const unsigned int currentBlockNumberOfSlices = firstBlock.size();
105  const std::string currentBlockFirstOrigin = firstBlock.front()->GetTagValueAsString( tagImagePositionPatient ).value;
106  const std::string currentBlockLastOrigin = firstBlock.back()->GetTagValueAsString( tagImagePositionPatient ).value;
107 
108  remainingBlocks.erase( remainingBlocks.begin() );
109 
110  // compare all other blocks against the first one
111  for (auto otherBlockIter = remainingBlocks.begin();
112  otherBlockIter != remainingBlocks.cend();
113  /*++otherBlockIter*/) // <-- inside loop
114  {
115  // get block characteristics from first block
116  const DICOMDatasetAccessingImageFrameList otherBlock = *otherBlockIter;
117 
118  const unsigned int otherBlockNumberOfSlices = otherBlock.size();
119  const std::string otherBlockFirstOrigin = otherBlock.front()->GetTagValueAsString( tagImagePositionPatient ).value;
120  const std::string otherBlockLastOrigin = otherBlock.back()->GetTagValueAsString( tagImagePositionPatient ).value;
121 
122  // add matching blocks to current3DnTBlock
123  // keep other blocks for later
124  if ( otherBlockNumberOfSlices == currentBlockNumberOfSlices
125  && otherBlockFirstOrigin == currentBlockFirstOrigin
126  && otherBlockLastOrigin == currentBlockLastOrigin
127  )
128  { // matching block
129  ++current3DnTBlockNumberOfTimeSteps;
130  current3DnTBlock.insert( current3DnTBlock.end(), otherBlock.begin(), otherBlock.end() ); // append
131  // remove this block from remainingBlocks
132  otherBlockIter = remainingBlocks.erase(otherBlockIter); // make sure iterator otherBlockIter is valid afterwards
133  }
134  else
135  {
136  ++otherBlockIter;
137  }
138  }
139 
140  // in any case, we now now all about the first block of our list ...
141  // ... and we wither call it 3D o 3D+t
142  if (current3DnTBlockNumberOfTimeSteps > 1)
143  {
144  true3DnTBlocks.push_back(current3DnTBlock);
145  true3DnTBlocksTimeStepCount.push_back(current3DnTBlockNumberOfTimeSteps);
146  }
147  else
148  {
149  non3DnTBlocks.push_back(current3DnTBlock);
150  }
151  }
152 
153  // create output for real 3D+t blocks (other outputs will be created by superclass)
154  // set 3D+t flag on output block
155  this->SetNumberOfOutputs( true3DnTBlocks.size() );
156  unsigned int o = 0;
157  for (auto blockIter = true3DnTBlocks.cbegin();
158  blockIter != true3DnTBlocks.cend();
159  ++o, ++blockIter)
160  {
161  // bad copy&paste code from DICOMITKSeriesGDCMReader, should be handled in a better way
162  DICOMDatasetAccessingImageFrameList gdcmFrameInfoList = *blockIter;
163  assert(!gdcmFrameInfoList.empty());
164 
165  // reverse frames if necessary
166  // update tilt information from absolute last sorting
167  const DICOMDatasetList datasetList = ConvertToDICOMDatasetList( gdcmFrameInfoList );
168  m_NormalDirectionConsistencySorter->SetInput( datasetList );
171  const GantryTiltInformation& tiltInfo = m_NormalDirectionConsistencySorter->GetTiltInformation();
172 
173  // set frame list for current block
174  const DICOMImageFrameList frameList = ConvertToDICOMImageFrameList( sortedGdcmInfoFrameList );
175  assert(!frameList.empty());
176 
178  block.SetTagCache( this->GetTagCache() ); // important: this must be before SetImageFrameList(), because SetImageFrameList will trigger reading of lots of interesting tags!
179  block.SetAdditionalTagsOfInterest(GetAdditionalTagsOfInterest());
180  block.SetTagLookupTableToPropertyFunctor(GetTagLookupTableToPropertyFunctor());
181  block.SetImageFrameList( frameList );
182  block.SetTiltInformation( tiltInfo );
183 
184  block.SetFlag("3D+t", true);
185  block.SetIntProperty("timesteps", true3DnTBlocksTimeStepCount[o]);
186  MITK_DEBUG << "Found " << true3DnTBlocksTimeStepCount[o] << " timesteps";
187 
188  this->SetOutput( o, block );
189  }
190 
191  return non3DnTBlocks;
192 }
193 
194 bool
197 {
198  bool success = true;
199 
200  unsigned int numberOfOutputs = this->GetNumberOfOutputs();
201  for (unsigned int o = 0; o < numberOfOutputs; ++o)
202  {
203  const DICOMImageBlockDescriptor& block = this->InternalGetOutput(o);
204 
205  if (block.GetFlag("3D+t", false))
206  {
207  success &= this->LoadMitkImageForOutput(o);
208  }
209  else
210  {
211  success &= DICOMITKSeriesGDCMReader::LoadMitkImageForOutput(o); // let superclass handle non-3D+t
212  }
213  }
214 
215  return success;
216 }
217 
218 bool
221 {
222  PushLocale();
223  const DICOMImageFrameList& frames = block.GetImageFrameList();
224  const GantryTiltInformation tiltInfo = block.GetTiltInformation();
225  const bool hasTilt = tiltInfo.IsRegularGantryTilt();
226 
227  const int numberOfTimesteps = block.GetNumberOfTimeSteps();
228 
229  if (numberOfTimesteps == 1)
230  {
232  }
233 
234  const int numberOfFramesPerTimestep = block.GetNumberOfFramesPerTimeStep();
235 
237  for (int timeStep = 0; timeStep<numberOfTimesteps; ++timeStep)
238  {
239  // use numberOfFramesPerTimestep frames for a new item in filenamesPerTimestep
240  ITKDICOMSeriesReaderHelper::StringContainer filenamesOfThisTimeStep;
241  auto timeStepStart = frames.cbegin() + timeStep * numberOfFramesPerTimestep;
242  auto timeStepEnd = frames.cbegin() + (timeStep+1) * numberOfFramesPerTimestep;
243  for (auto frameIter = timeStepStart;
244  frameIter != timeStepEnd;
245  ++frameIter)
246  {
247  filenamesOfThisTimeStep.push_back( (*frameIter)->Filename );
248  }
249  filenamesPerTimestep.push_back( filenamesOfThisTimeStep );
250  }
251 
253  mitk::Image::Pointer mitkImage = helper.Load3DnT( filenamesPerTimestep, m_FixTiltByShearing && hasTilt, tiltInfo );
254 
255  block.SetMitkImage( mitkImage );
256 
257  PopLocale();
258 
259  return true;
260 }
virtual bool LoadMitkImageForImageBlockDescriptor(DICOMImageBlockDescriptor &block) const
const GantryTiltInformation GetTiltInformation() const
Describe the gantry tilt of the acquisition.
mitk::DICOMImageBlockDescriptor::TagLookupTableToPropertyFunctor GetTagLookupTableToPropertyFunctor() const
bool operator==(const DICOMFileReader &other) const override
Flexible reader based on itk::ImageSeriesReader and GDCM, for single-slice modalities like CT...
bool operator==(const DICOMFileReader &other) const override
void SetNumberOfOutputs(unsigned int numberOfOutputs)
Representation of a DICOM tag.
Definition: mitkDICOMTag.h:32
virtual AdditionalTagsMapType GetAdditionalTagsOfInterest() const
#define MITK_DEBUG
Definition: mitkLogMacros.h:22
MITKDICOMREADER_EXPORT mitk::DICOMDatasetList ConvertToDICOMDatasetList(const DICOMDatasetAccessingImageFrameList &input)
void SetOutput(unsigned int index, const DICOMImageBlockDescriptor &output)
MITKDICOMREADER_EXPORT mitk::DICOMDatasetAccessingImageFrameList ConvertToDICOMDatasetAccessingImageFrameList(const DICOMDatasetList &input)
const DICOMImageFrameList & GetImageFrameList() const
List of frames that constitute the mitk::Image (DICOMImageFrames)
void PushLocale() const
Remember current locale on stack, activate "C" locale. "C" locale is required for correct parsing of ...
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()
Image::Pointer Load3DnT(const StringContainerList &filenamesLists, bool correctTilt, const GantryTiltInformation &tiltInfo)
SortingBlockList Condense3DBlocks(SortingBlockList &) override
Analyze the groups produced by DICOMITKSeriesGDCMReader for 3D+t properties. This method tests whethe...
void PopLocale() const
Activate last remembered locale from locale stack "C" locale is required for correct parsing of numbe...
std::vector< DICOMImageFrameInfo::Pointer > DICOMImageFrameList
DICOMImageBlockDescriptor & InternalGetOutput(unsigned int index)
non-const access to the DICOMImageBlockDescriptor
void SetGroup3DandT(bool on)
Control whether 3D+t grouping shall actually be attempted.
Output descriptor for DICOMFileReader.
void SetTagCache(DICOMTagCache *privateCache)
bool LoadMitkImageForImageBlockDescriptor(DICOMImageBlockDescriptor &block) const override
ThreeDnTDICOMSeriesReader & operator=(const ThreeDnTDICOMSeriesReader &other)
Extends DICOMITKSeriesGDCMReader by sorting/grouping into 3D+t image blocks.
bool LoadImages() override
Load via multiple calls to itk::ImageSeriesReader.
std::list< StringContainer > StringContainerList
virtual bool LoadMitkImageForOutput(unsigned int o)
Loads the mitk::Image by means of an itk::ImageSeriesReader.
ThreeDnTDICOMSeriesReader(unsigned int decimalPlacesForOrientation=Superclass::m_DefaultDecimalPlacesForOrientation)
std::vector< DICOMDatasetAccessingImageFrameList > SortingBlockList
MITKDICOMREADER_EXPORT mitk::DICOMImageFrameList ConvertToDICOMImageFrameList(const DICOMDatasetAccessingImageFrameList &input)
std::vector< DICOMDatasetAccessingImageFrameInfo::Pointer > DICOMDatasetAccessingImageFrameList
Gantry tilt analysis result.
DICOMITKSeriesGDCMReader & operator=(const DICOMITKSeriesGDCMReader &other)
bool IsRegularGantryTilt() const
Whether the shearing is a gantry tilt or more complicated.
std::vector< DICOMDatasetAccess * > DICOMDatasetList
Interface for DICOM readers that produce mitk::Images.
mitk::NormalDirectionConsistencySorter::Pointer m_NormalDirectionConsistencySorter
virtual DICOMTagCache::Pointer GetTagCache() const
bool GetFlag(const std::string &key, bool defaultValue) const
Convenience function around GetProperty()