Slicer  5.0
Slicer is a multi-platform, free and open source software package for visualization and medical image computing
vtkITKArchetypeImageSeriesReader.h
Go to the documentation of this file.
1 /*=========================================================================
2 
3 Copyright Brigham and Women's Hospital (BWH) All Rights Reserved.
4 
5 See COPYRIGHT.txt
6 or http://www.slicer.org/copyright/copyright.txt for details.
7 
8 Program: vtkITK
9 Module: $HeadURL$
10 Date: $Date$
11 Version: $Revision$
12 
13 ==========================================================================*/
14 
15 #ifndef __vtkITKArchetypeImageSeriesReader_h
16 #define __vtkITKArchetypeImageSeriesReader_h
17 
18 // VTKITK includes
19 #include "vtkITK.h"
20 
21 // VTK includes
22 #include "vtkImageAlgorithm.h"
23 class vtkMatrix4x4;
24 
25 // ITK includes
26 #include "itkImageIOBase.h"
27 #include "itkMetaDataDictionary.h"
28 #include "itkSpatialOrientation.h"
29 
30 // STD includes
31 #include <algorithm>
32 #include <string>
33 #include <vector>
34 
45 class VTK_ITK_EXPORT vtkITKArchetypeImageSeriesReader : public vtkImageAlgorithm
46 {
47 public:
49  vtkTypeMacro(vtkITKArchetypeImageSeriesReader,vtkImageAlgorithm);
50  void PrintSelf(ostream& os, vtkIndent indent) override;
51 
52  typedef itk::SpatialOrientation::ValidCoordinateOrientationFlags CoordinateOrientationCode;
53 
56  vtkSetStringMacro(Archetype);
57  vtkGetStringMacro(Archetype);
58 
61  unsigned int GetNumberOfFileNames();
64  const std::vector<std::string>& GetFileNames();
65 
70  unsigned int AddFileName( const char* filename );
71  const char* GetFileName( unsigned int n );
72  void ResetFileNames();
73 
77  vtkSetVector3Macro(DefaultDataSpacing,double);
78  vtkGetVector3Macro(DefaultDataSpacing,double);
79 
84  vtkSetVector3Macro(DefaultDataOrigin,double);
85  vtkGetVector3Macro(DefaultDataOrigin,double);
86 
90  vtkSetMacro(FileNameSliceOffset,int);
91  vtkGetMacro(FileNameSliceOffset,int);
92 
97  vtkSetMacro(FileNameSliceSpacing,int);
98  vtkGetMacro(FileNameSliceSpacing,int);
99 
103  vtkSetMacro(FileNameSliceCount,int);
104  vtkGetMacro(FileNameSliceCount,int);
105 
107  virtual int CanReadFile(const char* filename);
108 
112  {
113  this->DesiredCoordinateOrientation =
114  itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RAI;
116  this->UseNativeCoordinateOrientation = 0;
117  this->Modified();
118  }
120  {
121  this->DesiredCoordinateOrientation =
122  itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RSA;
124  this->UseNativeCoordinateOrientation = 0;
125  this->Modified();
126  }
128  {
129  this->DesiredCoordinateOrientation =
130  itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ASL;
132  this->UseNativeCoordinateOrientation = 0;
133  this->Modified();
134  }
136  {
137  this->UseNativeCoordinateOrientation = 1;
138  this->Modified();
139  }
140  vtkGetMacro(DesiredCoordinateOrientation, CoordinateOrientationCode);
141  vtkGetMacro(UseNativeCoordinateOrientation, char);
142 
148  {
149  UseNativeScalarType = 0;
150  this->SetOutputScalarType(VTK_DOUBLE);
151  }
153  {
154  UseNativeScalarType = 0;
155  this->SetOutputScalarType(VTK_FLOAT);
156  }
158  {
159  UseNativeScalarType = 0;
160  this->SetOutputScalarType(VTK_LONG);
161  }
163  {
164  UseNativeScalarType = 0;
165  this->SetOutputScalarType(VTK_UNSIGNED_LONG);
166  }
168  {
169  UseNativeScalarType = 0;
170  this->SetOutputScalarType(VTK_INT);
171  }
173  {
174  UseNativeScalarType = 0;
175  this->SetOutputScalarType(VTK_UNSIGNED_INT);
176  }
178  {
179  UseNativeScalarType = 0;
180  this->SetOutputScalarType(VTK_SHORT);
181  }
183  {
184  UseNativeScalarType = 0;
185  this->SetOutputScalarType(VTK_UNSIGNED_SHORT);
186  }
188  {
189  UseNativeScalarType = 0;
190  this->SetOutputScalarType(VTK_CHAR);
191  }
193  {
194  UseNativeScalarType = 0;
195  this->SetOutputScalarType(VTK_UNSIGNED_CHAR);
196  }
198  {
199  UseNativeScalarType = 1;
200  this->Modified();
201  }
202 
206  {
207  UseNativeOrigin = true;
208  }
209 
213  {
214  UseNativeOrigin = false;
215  }
216 
219  enum
220  {
221  GDCM = 0,
222  DCMTK
223  };
224  vtkSetClampMacro(DICOMImageIOApproach, int, vtkITKArchetypeImageSeriesReader::GDCM, vtkITKArchetypeImageSeriesReader::DCMTK);
225  vtkGetMacro(DICOMImageIOApproach, int);
228 
231  vtkSetMacro(OutputScalarType, int);
232  vtkGetMacro(OutputScalarType, int);
233 
236  vtkSetMacro(NumberOfComponents, unsigned int);
237  vtkGetMacro(NumberOfComponents, unsigned int);
238 
241  vtkSetMacro(SingleFile, int);
242  vtkGetMacro(SingleFile, int);
243 
246  vtkSetMacro(AnalyzeHeader, bool);
247  vtkGetMacro(AnalyzeHeader, bool);
248 
251  vtkSetMacro(UseOrientationFromFile, int);
252  vtkGetMacro(UseOrientationFromFile, int);
253 
256  vtkMatrix4x4* GetRasToIjkMatrix();
257 
260  vtkMatrix4x4* GetMeasurementFrameMatrix();
261 
263  vtkSetMacro(VoxelVectorType, int);
264  vtkGetMacro(VoxelVectorType, int);
265 
268  const itk::MetaDataDictionary &GetMetaDataDictionary() const;
269  std::vector<std::string> Tags;
270  std::vector<std::string> TagValues;
271  void ParseDictionary();
272 
273  unsigned int GetNumberOfItemsInDictionary();
274  bool HasKey( char* tag );
275  const char* GetNthKey( unsigned int n );
276  const char* GetNthValue( unsigned int n );
277  const char* GetTagValue( char* tag );
278 
281  {
282  return GroupingByTags;
283  }
284 
286  {
287  GroupingByTags = true;
288  }
289 
291  {
292  GroupingByTags = false;
293  }
294 
297  {
298  return SelectedUID;
299  }
300 
301  void SetSelectedUID( int v )
302  {
303  SelectedUID = v;
304  SetGroupingByTagsOn();
305  }
306 
309  {
310  return SelectedContentTime;
311  }
312 
314  {
315  SelectedContentTime = v;
316  SetGroupingByTagsOn();
317  }
318 
321  {
322  return SelectedTriggerTime;
323  }
324 
326  {
327  SelectedTriggerTime = v;
328  SetGroupingByTagsOn();
329  }
330 
333  {
334  return SelectedEchoNumbers;
335  }
336 
338  {
339  SelectedEchoNumbers = v;
340  SetGroupingByTagsOn();
341  }
342 
343 
346  {
347  return SelectedDiffusion;
348  }
349 
350  void SetSelectedDiffusion( int v )
351  {
352  SelectedDiffusion = v;
353  SetGroupingByTagsOn();
354  }
355 
358  {
359  return SelectedSlice;
360  }
361 
362  void SetSelectedSlice( int v )
363  {
364  SelectedSlice = v;
365  SetGroupingByTagsOn();
366  }
367 
370  {
371  return SelectedOrientation;
372  }
373 
375  {
376  SelectedOrientation = v;
377  SetGroupingByTagsOn();
378  }
379 
382  {
383  return this->SeriesInstanceUIDs.size();
384  }
385 
386  unsigned int GetNumberOfContentTime()
387  {
388  return this->ContentTime.size();
389  }
390 
391  unsigned int GetNumberOfTriggerTime()
392  {
393  return this->TriggerTime.size();
394  }
395 
396  unsigned int GetNumberOfEchoNumbers()
397  {
398  return this->EchoNumbers.size();
399  }
400 
402  {
403  return this->SliceLocation.size();
404  }
405 
407  {
408  return this->DiffusionGradientOrientation.size();
409  };
410 
412  {
413  return this->ImageOrientationPatient.size();
414  };
415 
417  {
418  return this->ImagePositionPatient.size();
419  }
420 
422  int ExistSeriesInstanceUID( const char* SeriesInstanceUID )
423  {
424  for (unsigned int k = 0; k < GetNumberOfSeriesInstanceUIDs(); k++)
425  {
426  if ( this->SeriesInstanceUIDs[k].find(SeriesInstanceUID) != std::string::npos )
427  {
428  return k;
429  }
430  }
431  return -1;
432  }
433 
434  int ExistContentTime( const char* contentTime )
435  {
436  for (unsigned int k = 0; k < GetNumberOfContentTime(); k++)
437  {
438  if ( this->ContentTime[k].find(contentTime) != std::string::npos )
439  {
440  return k;
441  }
442  }
443  return -1;
444  }
445 
446  int ExistTriggerTime( const char* triggerTime )
447  {
448  for (unsigned int k = 0; k < GetNumberOfTriggerTime(); k++)
449  {
450  if ( this->TriggerTime[k].find(triggerTime) != std::string::npos )
451  {
452  return k;
453  }
454  }
455  return -1;
456  }
457 
458  int ExistEchoNumbers( const char* echoNumbers )
459  {
460  for (unsigned int k = 0; k < GetNumberOfEchoNumbers(); k++)
461  {
462  if ( this->EchoNumbers[k].find(echoNumbers) != std::string::npos )
463  {
464  return k;
465  }
466  }
467  return -1;
468  }
469 
471  {
472  float a = 0;
473  for (int n = 0; n < 3; n++)
474  {
475  a += dgo[n]*dgo[n];
476  }
477 
478  for (unsigned int k = 0; k < GetNumberOfDiffusionGradientOrientation(); k++)
479  {
480  float b = 0;
481  float c = 0;
482  for (int n = 0; n < 3; n++)
483  {
484  b += this->DiffusionGradientOrientation[k][n] * this->DiffusionGradientOrientation[k][n];
485  c += this->DiffusionGradientOrientation[k][n] * dgo[n];
486  }
487  c = fabs(c)/sqrt(a*b);
488 
489  if ( c > 0.99999 )
490  {
491  return k;
492  }
493  }
494  return -1;
495  }
496 
497  int ExistSliceLocation( float sliceLocation )
498  {
499  std::vector<float>::iterator iter =
500  std::find(this->SliceLocation.begin(), this->SliceLocation.end(), sliceLocation);
501  return iter != this->SliceLocation.end() ?
502  std::distance(this->SliceLocation.begin(), iter) : -1;
503  }
504 
505  int ExistImageOrientationPatient( float * directionCosine )
506  {
508  float a = sqrt( directionCosine[0]*directionCosine[0] + directionCosine[1]*directionCosine[1] + directionCosine[2]*directionCosine[2] );
509  for (int k = 0; k < 3; k++)
510  {
511  directionCosine[k] /= a;
512  }
513  a = sqrt( directionCosine[3]*directionCosine[3] + directionCosine[4]*directionCosine[4] + directionCosine[5]*directionCosine[5] );
514  for (int k = 3; k < 6; k++)
515  {
516  directionCosine[k] /= a;
517  }
518 
519  for (unsigned int k = 0; k < GetNumberOfImageOrientationPatient(); k++)
520  {
521  std::vector<float> aVec = ImageOrientationPatient[k];
522  a = sqrt( aVec[0]*aVec[0] + aVec[1]*aVec[1] + aVec[2]*aVec[2] );
523  float b = (directionCosine[0]*aVec[0] + directionCosine[1]*aVec[1] + directionCosine[2]*aVec[2])/a;
524  if ( b < 0.99999 )
525  {
526  continue;
527  }
528 
529  a = sqrt( aVec[3]*aVec[3] + aVec[4]*aVec[4] + aVec[5]*aVec[5] );
530  b = (directionCosine[3]*aVec[3] + directionCosine[4]*aVec[4] + directionCosine[5]*aVec[5])/a;
531  if ( b > 0.99999 )
532  {
533  return k;
534  }
535  }
536  return -1;
537  }
538 
539  int ExistImagePositionPatient( float* ipp )
540  {
541  float a = 0;
542  for (int n = 0; n < 3; n++)
543  {
544  a += ipp[n]*ipp[n];
545  }
546 
547  for (unsigned int k = 0; k < GetNumberOfImagePositionPatient(); k++)
548  {
549  float b = 0;
550  float c = 0;
551  for (int n = 0; n < 3; n++)
552  {
553  b += this->ImagePositionPatient[k][n] * this->ImagePositionPatient[k][n];
554  c += this->ImagePositionPatient[k][n] * ipp[n];
555  }
556  c = fabs(c)/sqrt(a*b);
557  if ( c > 0.99999 )
558  {
559  return k;
560  }
561  }
562  return -1;
563  }
564 
566  const char* GetNthSeriesInstanceUID( unsigned int n )
567  {
568  if ( n >= this->GetNumberOfSeriesInstanceUIDs() )
569  {
570  return nullptr;
571  }
572  return this->SeriesInstanceUIDs[n].c_str();
573  }
574 
575  const char* GetNthContentTime( unsigned int n )
576  {
577  if ( n >= this->GetNumberOfContentTime() )
578  {
579  return nullptr;
580  }
581  return this->ContentTime[n].c_str();
582  }
583 
584  const char* GetNthTriggerTime( unsigned int n )
585  {
586  if ( n >= this->GetNumberOfTriggerTime() )
587  {
588  return nullptr;
589  }
590  return this->TriggerTime[n].c_str();
591  }
592 
593  const char* GetNthEchoNumbers( unsigned int n )
594  {
595  if ( n >= this->GetNumberOfEchoNumbers() )
596  {
597  return nullptr;
598  }
599  return this->EchoNumbers[n].c_str();
600  }
601 
602  float* GetNthDiffusionGradientOrientation( unsigned int n )
603  {
604  if ( n >= this->GetNumberOfDiffusionGradientOrientation() )
605  {
606  return nullptr;
607  }
608  float *dgo = new float [3];
609  for (int k = 0; k <3; k++)
610  {
611  dgo[k] = this->DiffusionGradientOrientation[n][k];
612  }
613  return dgo;
614  }
615 
616  float GetNthSliceLocation( unsigned int n )
617  {
618  if ( n >= this->GetNumberOfSliceLocation() )
619  {
620  return this->SliceLocation[0];
621  }
622  return this->SliceLocation[0];
623  }
624 
625  float* GetNthImageOrientationPatient( unsigned int n )
626  {
627  if ( n >= this->GetNumberOfImageOrientationPatient() )
628  {
629  return nullptr;
630  }
631  float *dgo = new float [6];
632  for (int k = 0; k <6; k++)
633  {
634  dgo[k] = this->ImageOrientationPatient[n][k];
635  }
636  return dgo;
637  }
638 
639  float* GetNthImagePositionPatient( unsigned int n )
640  {
641  if (n >= this->GetNumberOfImagePositionPatient() )
642  {
643  return nullptr;
644  }
645  float *ipp = new float [3];
646  for (int k = 0; k <3; k++)
647  {
648  ipp[k] = this->ImagePositionPatient[n][k];
649  }
650  return ipp;
651  }
652 
655  int InsertSeriesInstanceUIDs ( const char * aUID )
656  {
657  int k = ExistSeriesInstanceUID( aUID );
658  if ( k >= 0 )
659  {
660  return k;
661  }
662 
663  std::string aVector(aUID);
664  this->SeriesInstanceUIDs.push_back( aVector );
665  return (this->SeriesInstanceUIDs.size()-1);
666  }
667 
668  int InsertContentTime ( const char * aTime )
669  {
670  int k = ExistContentTime( aTime );
671  if ( k >= 0 )
672  {
673  return k;
674  }
675 
676  std::string aVector(aTime);
677  this->ContentTime.push_back( aVector );
678  return (this->ContentTime.size()-1);
679  }
680 
681  int InsertTriggerTime ( const char * aTime )
682  {
683  int k = ExistTriggerTime( aTime );
684  if ( k >= 0 )
685  {
686  return k;
687  }
688 
689  std::string aVector(aTime);
690  this->TriggerTime.push_back( aVector );
691  return (this->TriggerTime.size()-1);
692  }
693 
694  int InsertEchoNumbers ( const char * aEcho )
695  {
696  int k = ExistEchoNumbers( aEcho );
697  if ( k >= 0 )
698  {
699  return k;
700  }
701 
702  std::string aVector(aEcho);
703  this->EchoNumbers.push_back( aVector );
704  return (this->EchoNumbers.size()-1);
705  }
706 
708  {
709  int k = ExistDiffusionGradientOrientation( a );
710  if ( k >= 0 )
711  {
712  return k;
713  }
714  std::vector< float > aVector(3);
715  float aMag = sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]);
716  for (k = 0; k < 3; k++)
717  {
718  aVector[k] = a[k]/aMag;
719  }
720 
721  this->DiffusionGradientOrientation.push_back( aVector );
722  return (this->DiffusionGradientOrientation.size()-1);
723  }
724 
728  int InsertSliceLocation ( float a )
729  {
730  int k = ExistSliceLocation( a );
731  if ( k >= 0 )
732  {
733  return k;
734  }
735 
736  this->SliceLocation.push_back( a );
737  return (this->SliceLocation.size()-1);
738  }
742  {
743  int size = this->SliceLocation.size();
744  this->SliceLocation.push_back(
745  size > 0 ? this->SliceLocation.back() + 1 : 0.f);
746  return size;
747  }
748 
750  {
751  int k = ExistImageOrientationPatient( a );
752  if ( k >= 0 )
753  {
754  return k;
755  }
756  std::vector< float > aVector(6);
757  float aMag = sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]);
758  float bMag = sqrt(a[3]*a[3]+a[4]*a[4]+a[5]*a[5]);
759  for (k = 0; k < 3; k++)
760  {
761  aVector[k] = a[k]/aMag;
762  aVector[k+3] = a[k+3]/bMag;
763  }
764 
765  this->ImageOrientationPatient.push_back( aVector );
766  return (this->ImageOrientationPatient.size()-1);
767  }
768 
769  int InsertImagePositionPatient ( float *a )
770  {
771  int k = ExistImagePositionPatient( a );
772  if ( k >= 0 )
773  {
774  return k;
775  }
776 
777  std::vector< float > aVector(3);
778  for ( unsigned int i = 0; i < 3; i++ ) aVector[i] = a[i];
779  this->ImagePositionPatient.push_back( aVector );
780  return (this->ImagePositionPatient.size()-1);
781  }
782 
783  void AnalyzeDicomHeaders( );
784 
785  void AssembleNthVolume( int n );
786  int AssembleVolumeContainingArchetype();
787 
788  void GroupFiles ( int idxSeriesInstanceUID,
789  int idxContentTime,
790  int idxTriggerTime,
791  int idxEchoNumbers,
792  int idxDiffusionGradientOrientation,
793  int idxSliceLocation,
794  int idxImageOrientationPatient );
795 
796  const char* GetNthFileName ( int idxSeriesInstanceUID,
797  int idxContentTime,
798  int idxTriggerTime,
799  int idxEchoNumbers,
800  int idxDiffusionGradientOrientation,
801  int idxSliceLocation,
802  int idxImageOrientationPatient,
803  int n );
804 
805 
806 protected:
809 
811  static std::string GetMetaDataWithoutSpaces(const itk::MetaDataDictionary &dict, const std::string& tag);
812 
814  itk::ImageIOBase::Pointer GetImageIO(const char* filename);
815 
816  char *Archetype;
819  int DataExtent[6];
820 
822  unsigned int NumberOfComponents;
823 
824  std::vector<double> MetaDataScalarRangeMinima;
825  std::vector<double> MetaDataScalarRangeMaxima;
826  void GetScalarRangeMetaDataKeys(itk::ImageIOBase::Pointer imageIO,
827  std::string range_keys[2]);
828  void SetMetaDataScalarRangeToPointDataInfo(vtkImageData* data);
829 
830  double DefaultDataSpacing[3];
831  double DefaultDataOrigin[3];
832  float ScanAxis[3];
833  float ScanOrigin[3];
834 
838 
839  vtkMatrix4x4* RasToIjkMatrix;
840  vtkMatrix4x4* MeasurementFrameMatrix;
841 
845 
847 
856 
857  unsigned int IndexArchetype;
858 
859  std::vector<std::string> FileNames;
860  std::vector<std::pair <double, int> > FileNameSliceKey;
862  int RequestInformation(vtkInformation *, vtkInformationVector **, vtkInformationVector *) override;
863 
864  itk::MetaDataDictionary Dictionary;
865 
879 
880  std::vector<std::string> AllFileNames;
884 
885  std::vector<std::string> SeriesInstanceUIDs;
886  std::vector<std::string> ContentTime;
887  std::vector<std::string> TriggerTime;
888  std::vector<std::string> EchoNumbers;
889  std::vector< std::vector<float> > DiffusionGradientOrientation;
890  std::vector<float> SliceLocation;
891  std::vector< std::vector<float> > ImageOrientationPatient;
892  std::vector< std::vector<float> > ImagePositionPatient;
893 
895  std::vector<long int> IndexSeriesInstanceUIDs;
896  std::vector<long int> IndexContentTime;
897  std::vector<long int> IndexTriggerTime;
898  std::vector<long int> IndexEchoNumbers;
899  std::vector<long int> IndexDiffusionGradientOrientation;
900  std::vector<long int> IndexSliceLocation;
901  std::vector<long int> IndexImageOrientationPatient;
902  std::vector<long int> IndexImagePositionPatient;
903 
905 
906 private:
908  void operator=(const vtkITKArchetypeImageSeriesReader&) = delete;
909 };
910 
911 #endif
std::vector< long int > IndexSeriesInstanceUIDs
index of each dicom file into the above arrays
std::vector< std::vector< float > > ImageOrientationPatient
std::vector< std::vector< float > > DiffusionGradientOrientation
const char * GetNthSeriesInstanceUID(unsigned int n)
methods to get N-th discriminator
int ExistSeriesInstanceUID(const char *SeriesInstanceUID)
check the existence of given discriminator
void SetUseNativeOriginOff()
Use image center as origin
Read a series of files that have a common naming convention.
void SetUseNativeOriginOn()
Use image origin from the file
std::vector< std::pair< double, int > > FileNameSliceKey
unsigned int GetNumberOfSeriesInstanceUIDs()
get number of certain discriminators in the directory
bool GetGroupingByTags()
set/get functions for grouping by tags
int ExistImageOrientationPatient(float *directionCosine)
std::vector< std::vector< float > > ImagePositionPatient
itk::SpatialOrientation::ValidCoordinateOrientationFlags CoordinateOrientationCode
void SetDesiredCoordinateOrientationToAxial()
Set the orientation of the output image