Slicer  5.0
Slicer is a multi-platform, free and open source software package for visualization and medical image computing
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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