Slicer  4.11
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 
264  const itk::MetaDataDictionary &GetMetaDataDictionary() const;
265  std::vector<std::string> Tags;
266  std::vector<std::string> TagValues;
267  void ParseDictionary();
268 
269  unsigned int GetNumberOfItemsInDictionary();
270  bool HasKey( char* tag );
271  const char* GetNthKey( unsigned int n );
272  const char* GetNthValue( unsigned int n );
273  const char* GetTagValue( char* tag );
274 
277  {
278  return GroupingByTags;
279  }
280 
282  {
283  GroupingByTags = true;
284  }
285 
287  {
288  GroupingByTags = false;
289  }
290 
293  {
294  return SelectedUID;
295  }
296 
297  void SetSelectedUID( int v )
298  {
299  SelectedUID = v;
300  SetGroupingByTagsOn();
301  }
302 
305  {
306  return SelectedContentTime;
307  }
308 
310  {
311  SelectedContentTime = v;
312  SetGroupingByTagsOn();
313  }
314 
317  {
318  return SelectedTriggerTime;
319  }
320 
322  {
323  SelectedTriggerTime = v;
324  SetGroupingByTagsOn();
325  }
326 
329  {
330  return SelectedEchoNumbers;
331  }
332 
334  {
335  SelectedEchoNumbers = v;
336  SetGroupingByTagsOn();
337  }
338 
339 
342  {
343  return SelectedDiffusion;
344  }
345 
346  void SetSelectedDiffusion( int v )
347  {
348  SelectedDiffusion = v;
349  SetGroupingByTagsOn();
350  }
351 
354  {
355  return SelectedSlice;
356  }
357 
358  void SetSelectedSlice( int v )
359  {
360  SelectedSlice = v;
361  SetGroupingByTagsOn();
362  }
363 
366  {
367  return SelectedOrientation;
368  }
369 
371  {
372  SelectedOrientation = v;
373  SetGroupingByTagsOn();
374  }
375 
378  {
379  return this->SeriesInstanceUIDs.size();
380  }
381 
382  unsigned int GetNumberOfContentTime()
383  {
384  return this->ContentTime.size();
385  }
386 
387  unsigned int GetNumberOfTriggerTime()
388  {
389  return this->TriggerTime.size();
390  }
391 
392  unsigned int GetNumberOfEchoNumbers()
393  {
394  return this->EchoNumbers.size();
395  }
396 
398  {
399  return this->SliceLocation.size();
400  }
401 
403  {
404  return this->DiffusionGradientOrientation.size();
405  };
406 
408  {
409  return this->ImageOrientationPatient.size();
410  };
411 
413  {
414  return this->ImagePositionPatient.size();
415  }
416 
418  int ExistSeriesInstanceUID( const char* SeriesInstanceUID )
419  {
420  for (unsigned int k = 0; k < GetNumberOfSeriesInstanceUIDs(); k++)
421  {
422  if ( this->SeriesInstanceUIDs[k].find(SeriesInstanceUID) != std::string::npos )
423  {
424  return k;
425  }
426  }
427  return -1;
428  }
429 
430  int ExistContentTime( const char* contentTime )
431  {
432  for (unsigned int k = 0; k < GetNumberOfContentTime(); k++)
433  {
434  if ( this->ContentTime[k].find(contentTime) != std::string::npos )
435  {
436  return k;
437  }
438  }
439  return -1;
440  }
441 
442  int ExistTriggerTime( const char* triggerTime )
443  {
444  for (unsigned int k = 0; k < GetNumberOfTriggerTime(); k++)
445  {
446  if ( this->TriggerTime[k].find(triggerTime) != std::string::npos )
447  {
448  return k;
449  }
450  }
451  return -1;
452  }
453 
454  int ExistEchoNumbers( const char* echoNumbers )
455  {
456  for (unsigned int k = 0; k < GetNumberOfEchoNumbers(); k++)
457  {
458  if ( this->EchoNumbers[k].find(echoNumbers) != std::string::npos )
459  {
460  return k;
461  }
462  }
463  return -1;
464  }
465 
467  {
468  float a = 0;
469  for (int n = 0; n < 3; n++)
470  {
471  a += dgo[n]*dgo[n];
472  }
473 
474  for (unsigned int k = 0; k < GetNumberOfDiffusionGradientOrientation(); k++)
475  {
476  float b = 0;
477  float c = 0;
478  for (int n = 0; n < 3; n++)
479  {
480  b += this->DiffusionGradientOrientation[k][n] * this->DiffusionGradientOrientation[k][n];
481  c += this->DiffusionGradientOrientation[k][n] * dgo[n];
482  }
483  c = fabs(c)/sqrt(a*b);
484 
485  if ( c > 0.99999 )
486  {
487  return k;
488  }
489  }
490  return -1;
491  }
492 
493  int ExistSliceLocation( float sliceLocation )
494  {
495  std::vector<float>::iterator iter =
496  std::find(this->SliceLocation.begin(), this->SliceLocation.end(), sliceLocation);
497  return iter != this->SliceLocation.end() ?
498  std::distance(this->SliceLocation.begin(), iter) : -1;
499  }
500 
501  int ExistImageOrientationPatient( float * directionCosine )
502  {
504  float a = sqrt( directionCosine[0]*directionCosine[0] + directionCosine[1]*directionCosine[1] + directionCosine[2]*directionCosine[2] );
505  for (int k = 0; k < 3; k++)
506  {
507  directionCosine[k] /= a;
508  }
509  a = sqrt( directionCosine[3]*directionCosine[3] + directionCosine[4]*directionCosine[4] + directionCosine[5]*directionCosine[5] );
510  for (int k = 3; k < 6; k++)
511  {
512  directionCosine[k] /= a;
513  }
514 
515  for (unsigned int k = 0; k < GetNumberOfImageOrientationPatient(); k++)
516  {
517  std::vector<float> aVec = ImageOrientationPatient[k];
518  a = sqrt( aVec[0]*aVec[0] + aVec[1]*aVec[1] + aVec[2]*aVec[2] );
519  float b = (directionCosine[0]*aVec[0] + directionCosine[1]*aVec[1] + directionCosine[2]*aVec[2])/a;
520  if ( b < 0.99999 )
521  {
522  continue;
523  }
524 
525  a = sqrt( aVec[3]*aVec[3] + aVec[4]*aVec[4] + aVec[5]*aVec[5] );
526  b = (directionCosine[3]*aVec[3] + directionCosine[4]*aVec[4] + directionCosine[5]*aVec[5])/a;
527  if ( b > 0.99999 )
528  {
529  return k;
530  }
531  }
532  return -1;
533  }
534 
535  int ExistImagePositionPatient( float* ipp )
536  {
537  float a = 0;
538  for (int n = 0; n < 3; n++)
539  {
540  a += ipp[n]*ipp[n];
541  }
542 
543  for (unsigned int k = 0; k < GetNumberOfImagePositionPatient(); k++)
544  {
545  float b = 0;
546  float c = 0;
547  for (int n = 0; n < 3; n++)
548  {
549  b += this->ImagePositionPatient[k][n] * this->ImagePositionPatient[k][n];
550  c += this->ImagePositionPatient[k][n] * ipp[n];
551  }
552  c = fabs(c)/sqrt(a*b);
553  if ( c > 0.99999 )
554  {
555  return k;
556  }
557  }
558  return -1;
559  }
560 
562  const char* GetNthSeriesInstanceUID( unsigned int n )
563  {
564  if ( n >= this->GetNumberOfSeriesInstanceUIDs() )
565  {
566  return nullptr;
567  }
568  return this->SeriesInstanceUIDs[n].c_str();
569  }
570 
571  const char* GetNthContentTime( unsigned int n )
572  {
573  if ( n >= this->GetNumberOfContentTime() )
574  {
575  return nullptr;
576  }
577  return this->ContentTime[n].c_str();
578  }
579 
580  const char* GetNthTriggerTime( unsigned int n )
581  {
582  if ( n >= this->GetNumberOfTriggerTime() )
583  {
584  return nullptr;
585  }
586  return this->TriggerTime[n].c_str();
587  }
588 
589  const char* GetNthEchoNumbers( unsigned int n )
590  {
591  if ( n >= this->GetNumberOfEchoNumbers() )
592  {
593  return nullptr;
594  }
595  return this->EchoNumbers[n].c_str();
596  }
597 
598  float* GetNthDiffusionGradientOrientation( unsigned int n )
599  {
600  if ( n >= this->GetNumberOfDiffusionGradientOrientation() )
601  {
602  return nullptr;
603  }
604  float *dgo = new float [3];
605  for (int k = 0; k <3; k++)
606  {
607  dgo[k] = this->DiffusionGradientOrientation[n][k];
608  }
609  return dgo;
610  }
611 
612  float GetNthSliceLocation( unsigned int n )
613  {
614  if ( n >= this->GetNumberOfSliceLocation() )
615  {
616  return this->SliceLocation[0];
617  }
618  return this->SliceLocation[0];
619  }
620 
621  float* GetNthImageOrientationPatient( unsigned int n )
622  {
623  if ( n >= this->GetNumberOfImageOrientationPatient() )
624  {
625  return nullptr;
626  }
627  float *dgo = new float [6];
628  for (int k = 0; k <6; k++)
629  {
630  dgo[k] = this->ImageOrientationPatient[n][k];
631  }
632  return dgo;
633  }
634 
635  float* GetNthImagePositionPatient( unsigned int n )
636  {
637  if (n >= this->GetNumberOfImagePositionPatient() )
638  {
639  return nullptr;
640  }
641  float *ipp = new float [3];
642  for (int k = 0; k <3; k++)
643  {
644  ipp[k] = this->ImagePositionPatient[n][k];
645  }
646  return ipp;
647  }
648 
651  int InsertSeriesInstanceUIDs ( const char * aUID )
652  {
653  int k = ExistSeriesInstanceUID( aUID );
654  if ( k >= 0 )
655  {
656  return k;
657  }
658 
659  std::string aVector(aUID);
660  this->SeriesInstanceUIDs.push_back( aVector );
661  return (this->SeriesInstanceUIDs.size()-1);
662  }
663 
664  int InsertContentTime ( const char * aTime )
665  {
666  int k = ExistContentTime( aTime );
667  if ( k >= 0 )
668  {
669  return k;
670  }
671 
672  std::string aVector(aTime);
673  this->ContentTime.push_back( aVector );
674  return (this->ContentTime.size()-1);
675  }
676 
677  int InsertTriggerTime ( const char * aTime )
678  {
679  int k = ExistTriggerTime( aTime );
680  if ( k >= 0 )
681  {
682  return k;
683  }
684 
685  std::string aVector(aTime);
686  this->TriggerTime.push_back( aVector );
687  return (this->TriggerTime.size()-1);
688  }
689 
690  int InsertEchoNumbers ( const char * aEcho )
691  {
692  int k = ExistEchoNumbers( aEcho );
693  if ( k >= 0 )
694  {
695  return k;
696  }
697 
698  std::string aVector(aEcho);
699  this->EchoNumbers.push_back( aVector );
700  return (this->EchoNumbers.size()-1);
701  }
702 
704  {
705  int k = ExistDiffusionGradientOrientation( a );
706  if ( k >= 0 )
707  {
708  return k;
709  }
710  std::vector< float > aVector(3);
711  float aMag = sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]);
712  for (k = 0; k < 3; k++)
713  {
714  aVector[k] = a[k]/aMag;
715  }
716 
717  this->DiffusionGradientOrientation.push_back( aVector );
718  return (this->DiffusionGradientOrientation.size()-1);
719  }
720 
724  int InsertSliceLocation ( float a )
725  {
726  int k = ExistSliceLocation( a );
727  if ( k >= 0 )
728  {
729  return k;
730  }
731 
732  this->SliceLocation.push_back( a );
733  return (this->SliceLocation.size()-1);
734  }
738  {
739  int size = this->SliceLocation.size();
740  this->SliceLocation.push_back(
741  size > 0 ? this->SliceLocation.back() + 1 : 0.f);
742  return size;
743  }
744 
746  {
747  int k = ExistImageOrientationPatient( a );
748  if ( k >= 0 )
749  {
750  return k;
751  }
752  std::vector< float > aVector(6);
753  float aMag = sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]);
754  float bMag = sqrt(a[3]*a[3]+a[4]*a[4]+a[5]*a[5]);
755  for (k = 0; k < 3; k++)
756  {
757  aVector[k] = a[k]/aMag;
758  aVector[k+3] = a[k+3]/bMag;
759  }
760 
761  this->ImageOrientationPatient.push_back( aVector );
762  return (this->ImageOrientationPatient.size()-1);
763  }
764 
765  int InsertImagePositionPatient ( float *a )
766  {
767  int k = ExistImagePositionPatient( a );
768  if ( k >= 0 )
769  {
770  return k;
771  }
772 
773  std::vector< float > aVector(3);
774  for ( unsigned int i = 0; i < 3; i++ ) aVector[i] = a[i];
775  this->ImagePositionPatient.push_back( aVector );
776  return (this->ImagePositionPatient.size()-1);
777  }
778 
779  void AnalyzeDicomHeaders( );
780 
781  void AssembleNthVolume( int n );
782  int AssembleVolumeContainingArchetype();
783 
784  void GroupFiles ( int idxSeriesInstanceUID,
785  int idxContentTime,
786  int idxTriggerTime,
787  int idxEchoNumbers,
788  int idxDiffusionGradientOrientation,
789  int idxSliceLocation,
790  int idxImageOrientationPatient );
791 
792  const char* GetNthFileName ( int idxSeriesInstanceUID,
793  int idxContentTime,
794  int idxTriggerTime,
795  int idxEchoNumbers,
796  int idxDiffusionGradientOrientation,
797  int idxSliceLocation,
798  int idxImageOrientationPatient,
799  int n );
800 
801 
802 protected:
805 
807  static std::string GetMetaDataWithoutSpaces(const itk::MetaDataDictionary &dict, const std::string& tag);
808 
810  itk::ImageIOBase::Pointer GetImageIO(const char* filename);
811 
812  char *Archetype;
815  int DataExtent[6];
816 
818  unsigned int NumberOfComponents;
819 
820  std::vector<double> MetaDataScalarRangeMinima;
821  std::vector<double> MetaDataScalarRangeMaxima;
822  void GetScalarRangeMetaDataKeys(itk::ImageIOBase::Pointer imageIO,
823  std::string range_keys[2]);
824  void SetMetaDataScalarRangeToPointDataInfo(vtkImageData* data);
825 
826  double DefaultDataSpacing[3];
827  double DefaultDataOrigin[3];
828  float ScanAxis[3];
829  float ScanOrigin[3];
830 
834 
835  vtkMatrix4x4* RasToIjkMatrix;
836  vtkMatrix4x4* MeasurementFrameMatrix;
837 
841 
843 
852 
853  unsigned int IndexArchetype;
854 
855  std::vector<std::string> FileNames;
856  std::vector<std::pair <double, int> > FileNameSliceKey;
858  int RequestInformation(vtkInformation *, vtkInformationVector **, vtkInformationVector *) override;
859 
860  itk::MetaDataDictionary Dictionary;
861 
875 
876  std::vector<std::string> AllFileNames;
880 
881  std::vector<std::string> SeriesInstanceUIDs;
882  std::vector<std::string> ContentTime;
883  std::vector<std::string> TriggerTime;
884  std::vector<std::string> EchoNumbers;
885  std::vector< std::vector<float> > DiffusionGradientOrientation;
886  std::vector<float> SliceLocation;
887  std::vector< std::vector<float> > ImageOrientationPatient;
888  std::vector< std::vector<float> > ImagePositionPatient;
889 
891  std::vector<long int> IndexSeriesInstanceUIDs;
892  std::vector<long int> IndexContentTime;
893  std::vector<long int> IndexTriggerTime;
894  std::vector<long int> IndexEchoNumbers;
895  std::vector<long int> IndexDiffusionGradientOrientation;
896  std::vector<long int> IndexSliceLocation;
897  std::vector<long int> IndexImageOrientationPatient;
898  std::vector<long int> IndexImagePositionPatient;
899 
900 private:
902  void operator=(const vtkITKArchetypeImageSeriesReader&) = delete;
903 };
904 
905 #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