Slicer 5.13
Slicer is a multi-platform, free and open source software package for visualization and medical image computing
Loading...
Searching...
No Matches
vtkITKArchetypeImageSeriesReader.h
Go to the documentation of this file.
1/*=========================================================================
2
3Copyright Brigham and Women's Hospital (BWH) All Rights Reserved.
4
5See COPYRIGHT.txt
6or http://www.slicer.org/copyright/copyright.txt for details.
7
8Program: vtkITK
9Module: $HeadURL$
10Date: $Date$
11Version: $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"
23class 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
53class VTK_ITK_EXPORT vtkITKArchetypeImageSeriesReader : public vtkImageAlgorithm
54{
55public:
57 vtkTypeMacro(vtkITKArchetypeImageSeriesReader, vtkImageAlgorithm);
58 void PrintSelf(ostream& os, vtkIndent indent) override;
59
60 using CoordinateOrientationCode = itk::SpatialOrientationEnums::ValidCoordinateOrientations;
61
64 vtkSetStringMacro(Archetype);
65 vtkGetStringMacro(Archetype);
66
69 unsigned int GetNumberOfFileNames();
72 const std::vector<std::string>& GetFileNames();
73
78 unsigned int AddFileName(const char* filename);
79 const char* GetFileName(unsigned int n);
81
85 vtkSetVector3Macro(DefaultDataSpacing, double);
86 vtkGetVector3Macro(DefaultDataSpacing, double);
87
92 vtkSetVector3Macro(DefaultDataOrigin, double);
93 vtkGetVector3Macro(DefaultDataOrigin, double);
94
98 vtkSetMacro(FileNameSliceOffset, int);
99 vtkGetMacro(FileNameSliceOffset, int);
100
105 vtkSetMacro(FileNameSliceSpacing, int);
106 vtkGetMacro(FileNameSliceSpacing, int);
107
111 vtkSetMacro(FileNameSliceCount, int);
112 vtkGetMacro(FileNameSliceCount, int);
113
115 virtual int CanReadFile(const char* filename);
116
120 {
121 this->DesiredCoordinateOrientation = CoordinateOrientationCode::ITK_COORDINATE_ORIENTATION_RAI;
124 this->Modified();
125 }
127 {
128 this->DesiredCoordinateOrientation = CoordinateOrientationCode::ITK_COORDINATE_ORIENTATION_RSA;
131 this->Modified();
132 }
134 {
135 this->DesiredCoordinateOrientation = CoordinateOrientationCode::ITK_COORDINATE_ORIENTATION_ASL;
138 this->Modified();
139 }
141 {
143 this->Modified();
144 }
147
153 {
155 this->SetOutputScalarType(VTK_DOUBLE);
156 }
158 {
160 this->SetOutputScalarType(VTK_FLOAT);
161 }
163 {
165 this->SetOutputScalarType(VTK_LONG);
166 }
168 {
170 this->SetOutputScalarType(VTK_UNSIGNED_LONG);
171 }
173 {
175 this->SetOutputScalarType(VTK_INT);
176 }
178 {
180 this->SetOutputScalarType(VTK_UNSIGNED_INT);
181 }
183 {
185 this->SetOutputScalarType(VTK_SHORT);
186 }
188 {
190 this->SetOutputScalarType(VTK_UNSIGNED_SHORT);
191 }
193 {
195 this->SetOutputScalarType(VTK_CHAR);
196 }
198 {
200 this->SetOutputScalarType(VTK_UNSIGNED_CHAR);
201 }
203 {
205 this->Modified();
206 }
207
211
215
218 enum
219 {
220 GDCM = 0,
222 };
224 vtkGetMacro(DICOMImageIOApproach, int);
227
230 vtkSetMacro(OutputScalarType, int);
231 vtkGetMacro(OutputScalarType, int);
232
235 vtkSetMacro(NumberOfComponents, unsigned int);
236 vtkGetMacro(NumberOfComponents, unsigned int);
237
240 vtkSetMacro(SingleFile, int);
241 vtkGetMacro(SingleFile, int);
242
245 vtkSetMacro(AnalyzeHeader, bool);
246 vtkGetMacro(AnalyzeHeader, bool);
247
250 vtkSetMacro(UseOrientationFromFile, int);
251 vtkGetMacro(UseOrientationFromFile, int);
252
255 vtkMatrix4x4* GetRasToIjkMatrix();
256
260
262 vtkSetMacro(VoxelVectorType, int);
263 vtkGetMacro(VoxelVectorType, int);
264
267 const itk::MetaDataDictionary& GetMetaDataDictionary() const;
268 std::vector<std::string> Tags;
269 std::vector<std::string> TagValues;
271
273 bool HasKey(char* tag);
274 const char* GetNthKey(unsigned int n);
275 const char* GetNthValue(unsigned int n);
276 const char* GetTagValue(char* tag);
277
280
282
284
286 int GetSelectedUID() { return SelectedUID; }
287
288 void SetSelectedUID(int v)
289 {
290 SelectedUID = v;
292 }
293
296
298 {
301 }
302
305
307 {
310 }
311
314
316 {
319 }
320
323
325 {
328 }
329
332
334 {
335 SelectedSlice = v;
337 }
338
341
343 {
346 }
347
349 unsigned int GetNumberOfSeriesInstanceUIDs() { return this->SeriesInstanceUIDs.size(); }
350
351 unsigned int GetNumberOfContentTime() { return this->ContentTime.size(); }
352
353 unsigned int GetNumberOfTriggerTime() { return this->TriggerTime.size(); }
354
355 unsigned int GetNumberOfEchoNumbers() { return this->EchoNumbers.size(); }
356
357 unsigned int GetNumberOfSliceLocation() { return this->SliceLocation.size(); }
358
360
361 unsigned int GetNumberOfImageOrientationPatient() { return this->ImageOrientationPatient.size(); };
362
363 unsigned int GetNumberOfImagePositionPatient() { return this->ImagePositionPatient.size(); }
364
366 int ExistSeriesInstanceUID(const char* SeriesInstanceUID)
367 {
368 for (unsigned int k = 0; k < GetNumberOfSeriesInstanceUIDs(); k++)
369 {
370 if (this->SeriesInstanceUIDs[k].find(SeriesInstanceUID) != std::string::npos)
371 {
372 return k;
373 }
374 }
375 return -1;
376 }
377
378 int ExistContentTime(const char* contentTime)
379 {
380 for (unsigned int k = 0; k < GetNumberOfContentTime(); k++)
381 {
382 if (this->ContentTime[k].find(contentTime) != std::string::npos)
383 {
384 return k;
385 }
386 }
387 return -1;
388 }
389
390 int ExistTriggerTime(const char* triggerTime)
391 {
392 for (unsigned int k = 0; k < GetNumberOfTriggerTime(); k++)
393 {
394 if (this->TriggerTime[k].find(triggerTime) != std::string::npos)
395 {
396 return k;
397 }
398 }
399 return -1;
400 }
401
402 int ExistEchoNumbers(const char* echoNumbers)
403 {
404 for (unsigned int k = 0; k < GetNumberOfEchoNumbers(); k++)
405 {
406 if (this->EchoNumbers[k].find(echoNumbers) != std::string::npos)
407 {
408 return k;
409 }
410 }
411 return -1;
412 }
413
415 {
416 float a = 0;
417 for (int n = 0; n < 3; n++)
418 {
419 a += dgo[n] * dgo[n];
420 }
421
422 for (unsigned int k = 0; k < GetNumberOfDiffusionGradientOrientation(); k++)
423 {
424 float b = 0;
425 float c = 0;
426 for (int n = 0; n < 3; n++)
427 {
428 b += this->DiffusionGradientOrientation[k][n] * this->DiffusionGradientOrientation[k][n];
429 c += this->DiffusionGradientOrientation[k][n] * dgo[n];
430 }
431 c = fabs(c) / sqrt(a * b);
432
433 if (c > 0.99999)
434 {
435 return k;
436 }
437 }
438 return -1;
439 }
440
441 int ExistSliceLocation(float sliceLocation)
442 {
443 std::vector<float>::iterator iter = std::find(this->SliceLocation.begin(), this->SliceLocation.end(), sliceLocation);
444 return iter != this->SliceLocation.end() ? std::distance(this->SliceLocation.begin(), iter) : -1;
445 }
446
447 int ExistImageOrientationPatient(float* directionCosine)
448 {
450 float a = sqrt(directionCosine[0] * directionCosine[0] + directionCosine[1] * directionCosine[1] + directionCosine[2] * directionCosine[2]);
451 for (int k = 0; k < 3; k++)
452 {
453 directionCosine[k] /= a;
454 }
455 a = sqrt(directionCosine[3] * directionCosine[3] + directionCosine[4] * directionCosine[4] + directionCosine[5] * directionCosine[5]);
456 for (int k = 3; k < 6; k++)
457 {
458 directionCosine[k] /= a;
459 }
460
461 for (unsigned int k = 0; k < GetNumberOfImageOrientationPatient(); k++)
462 {
463 std::vector<float> aVec = ImageOrientationPatient[k];
464 a = sqrt(aVec[0] * aVec[0] + aVec[1] * aVec[1] + aVec[2] * aVec[2]);
465 float b = (directionCosine[0] * aVec[0] + directionCosine[1] * aVec[1] + directionCosine[2] * aVec[2]) / a;
466 if (b < 0.99999)
467 {
468 continue;
469 }
470
471 a = sqrt(aVec[3] * aVec[3] + aVec[4] * aVec[4] + aVec[5] * aVec[5]);
472 b = (directionCosine[3] * aVec[3] + directionCosine[4] * aVec[4] + directionCosine[5] * aVec[5]) / a;
473 if (b > 0.99999)
474 {
475 return k;
476 }
477 }
478 return -1;
479 }
480
482 {
483 // Positions are the same if they are closer than this distance (in mm)
484 const float tolerance = 1e-3;
485 for (unsigned int k = 0; k < GetNumberOfImagePositionPatient(); k++)
486 {
487 float squaredDistance = 0;
488 for (int n = 0; n < 3; n++)
489 {
490 const float difference = this->ImagePositionPatient[k][n] - ipp[n];
491 squaredDistance += difference * difference;
492 }
493 if (squaredDistance < tolerance * tolerance)
494 {
495 return k;
496 }
497 }
498 return -1;
499 }
500
502 const char* GetNthSeriesInstanceUID(unsigned int n)
503 {
504 if (n >= this->GetNumberOfSeriesInstanceUIDs())
505 {
506 return nullptr;
507 }
508 return this->SeriesInstanceUIDs[n].c_str();
509 }
510
511 const char* GetNthContentTime(unsigned int n)
512 {
513 if (n >= this->GetNumberOfContentTime())
514 {
515 return nullptr;
516 }
517 return this->ContentTime[n].c_str();
518 }
519
520 const char* GetNthTriggerTime(unsigned int n)
521 {
522 if (n >= this->GetNumberOfTriggerTime())
523 {
524 return nullptr;
525 }
526 return this->TriggerTime[n].c_str();
527 }
528
529 const char* GetNthEchoNumbers(unsigned int n)
530 {
531 if (n >= this->GetNumberOfEchoNumbers())
532 {
533 return nullptr;
534 }
535 return this->EchoNumbers[n].c_str();
536 }
537
539 {
541 {
542 return nullptr;
543 }
544 float* dgo = new float[3];
545 for (int k = 0; k < 3; k++)
546 {
547 dgo[k] = this->DiffusionGradientOrientation[n][k];
548 }
549 return dgo;
550 }
551
552 float GetNthSliceLocation(unsigned int n)
553 {
554 if (n >= this->GetNumberOfSliceLocation())
555 {
556 return this->SliceLocation[0];
557 }
558 return this->SliceLocation[0];
559 }
560
561 float* GetNthImageOrientationPatient(unsigned int n)
562 {
563 if (n >= this->GetNumberOfImageOrientationPatient())
564 {
565 return nullptr;
566 }
567 float* dgo = new float[6];
568 for (int k = 0; k < 6; k++)
569 {
570 dgo[k] = this->ImageOrientationPatient[n][k];
571 }
572 return dgo;
573 }
574
575 float* GetNthImagePositionPatient(unsigned int n)
576 {
577 if (n >= this->GetNumberOfImagePositionPatient())
578 {
579 return nullptr;
580 }
581 float* ipp = new float[3];
582 for (int k = 0; k < 3; k++)
583 {
584 ipp[k] = this->ImagePositionPatient[n][k];
585 }
586 return ipp;
587 }
588
591 int InsertSeriesInstanceUIDs(const char* aUID)
592 {
593 int k = ExistSeriesInstanceUID(aUID);
594 if (k >= 0)
595 {
596 return k;
597 }
598
599 std::string aVector(aUID);
600 this->SeriesInstanceUIDs.push_back(aVector);
601 return (this->SeriesInstanceUIDs.size() - 1);
602 }
603
604 int InsertContentTime(const char* aTime)
605 {
606 int k = ExistContentTime(aTime);
607 if (k >= 0)
608 {
609 return k;
610 }
611
612 std::string aVector(aTime);
613 this->ContentTime.push_back(aVector);
614 return (this->ContentTime.size() - 1);
615 }
616
617 int InsertTriggerTime(const char* aTime)
618 {
619 int k = ExistTriggerTime(aTime);
620 if (k >= 0)
621 {
622 return k;
623 }
624
625 std::string aVector(aTime);
626 this->TriggerTime.push_back(aVector);
627 return (this->TriggerTime.size() - 1);
628 }
629
630 int InsertEchoNumbers(const char* aEcho)
631 {
632 int k = ExistEchoNumbers(aEcho);
633 if (k >= 0)
634 {
635 return k;
636 }
637
638 std::string aVector(aEcho);
639 this->EchoNumbers.push_back(aVector);
640 return (this->EchoNumbers.size() - 1);
641 }
642
644 {
646 if (k >= 0)
647 {
648 return k;
649 }
650 std::vector<float> aVector(3);
651 float aMag = sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]);
652 for (k = 0; k < 3; k++)
653 {
654 aVector[k] = a[k] / aMag;
655 }
656
657 this->DiffusionGradientOrientation.push_back(aVector);
658 return (this->DiffusionGradientOrientation.size() - 1);
659 }
660
665 {
666 int k = ExistSliceLocation(a);
667 if (k >= 0)
668 {
669 return k;
670 }
671
672 this->SliceLocation.push_back(a);
673 return (this->SliceLocation.size() - 1);
674 }
675
678 {
679 int size = this->SliceLocation.size();
680 this->SliceLocation.push_back(size > 0 ? this->SliceLocation.back() + 1 : 0.f);
681 return size;
682 }
683
685 {
687 if (k >= 0)
688 {
689 return k;
690 }
691 std::vector<float> aVector(6);
692 float aMag = sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]);
693 float bMag = sqrt(a[3] * a[3] + a[4] * a[4] + a[5] * a[5]);
694 for (k = 0; k < 3; k++)
695 {
696 aVector[k] = a[k] / aMag;
697 aVector[k + 3] = a[k + 3] / bMag;
698 }
699
700 this->ImageOrientationPatient.push_back(aVector);
701 return (this->ImageOrientationPatient.size() - 1);
702 }
703
705 {
706 int k = ExistImagePositionPatient(a);
707 if (k >= 0)
708 {
709 return k;
710 }
711
712 std::vector<float> aVector(3);
713 for (unsigned int i = 0; i < 3; i++)
714 {
715 aVector[i] = a[i];
716 }
717 this->ImagePositionPatient.push_back(aVector);
718 return (this->ImagePositionPatient.size() - 1);
719 }
720
722
723 void AssembleNthVolume(int n);
725
726 void GroupFiles(int idxSeriesInstanceUID,
727 int idxContentTime,
728 int idxTriggerTime,
729 int idxEchoNumbers,
730 int idxDiffusionGradientOrientation,
731 int idxSliceLocation,
732 int idxImageOrientationPatient);
733
734 const char* GetNthFileName(int idxSeriesInstanceUID,
735 int idxContentTime,
736 int idxTriggerTime,
737 int idxEchoNumbers,
738 int idxDiffusionGradientOrientation,
739 int idxSliceLocation,
740 int idxImageOrientationPatient,
741 int n);
742
743 static bool ReadMeasurementFrameMatrixFromMetaDataDictionary(const itk::MetaDataDictionary& dictionary, vtkMatrix4x4* measurementFrameMatrix);
744
749 static bool IsListPixelComponentTypeInMetaDataDictionary(const itk::MetaDataDictionary& dictionary);
750
753 static bool IsNifti2File(const char* fileName);
754
758 static itk::ImageIOBase::Pointer CreateDICOMImageIO(int dicomImageIOApproach);
759
760protected:
763
765 static std::string GetMetaDataWithoutSpaces(const itk::MetaDataDictionary& dict, const std::string& tag);
766
768 itk::ImageIOBase::Pointer GetImageIO(const char* filename);
769
773 void ReportFileReadError(const std::string& fileName, const std::string& errorDetails);
774
779
781 unsigned int NumberOfComponents;
782
783 std::vector<double> MetaDataScalarRangeMinima;
784 std::vector<double> MetaDataScalarRangeMaxima;
785 void GetScalarRangeMetaDataKeys(itk::ImageIOBase::Pointer imageIO, std::string range_keys[2]);
787
790 float ScanAxis[3];
791 float ScanOrigin[3];
792
796
797 vtkMatrix4x4* RasToIjkMatrix;
799
803
805
814
815 unsigned int IndexArchetype;
816
817 std::vector<std::string> FileNames;
818 std::vector<std::pair<double, int>> FileNameSliceKey;
820 int RequestInformation(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override;
821
822 itk::MetaDataDictionary Dictionary;
823
837
838 std::vector<std::string> AllFileNames;
842
843 std::vector<std::string> SeriesInstanceUIDs;
844 std::vector<std::string> ContentTime;
845 std::vector<std::string> TriggerTime;
846 std::vector<std::string> EchoNumbers;
847 std::vector<std::vector<float>> DiffusionGradientOrientation;
848 std::vector<float> SliceLocation;
849 std::vector<std::vector<float>> ImageOrientationPatient;
850 std::vector<std::vector<float>> ImagePositionPatient;
851
853 std::vector<long int> IndexSeriesInstanceUIDs;
854 std::vector<long int> IndexContentTime;
855 std::vector<long int> IndexTriggerTime;
856 std::vector<long int> IndexEchoNumbers;
858 std::vector<long int> IndexSliceLocation;
859 std::vector<long int> IndexImageOrientationPatient;
860 std::vector<long int> IndexImagePositionPatient;
861
863
864private:
866 void operator=(const vtkITKArchetypeImageSeriesReader&) = delete;
867};
868
869#endif
bool GetGroupingByTags()
set/get functions for grouping by tags
void GetScalarRangeMetaDataKeys(itk::ImageIOBase::Pointer imageIO, std::string range_keys[2])
const char * GetNthFileName(int idxSeriesInstanceUID, int idxContentTime, int idxTriggerTime, int idxEchoNumbers, int idxDiffusionGradientOrientation, int idxSliceLocation, int idxImageOrientationPatient, int n)
std::vector< std::vector< float > > DiffusionGradientOrientation
virtual int CanReadFile(const char *filename)
Determine if the file can be read using ITK.
static bool IsListPixelComponentTypeInMetaDataDictionary(const itk::MetaDataDictionary &dictionary)
unsigned int AddFileName(const char *filename)
itk::SpatialOrientationEnums::ValidCoordinateOrientations CoordinateOrientationCode
int RequestInformation(vtkInformation *, vtkInformationVector **, vtkInformationVector *) override
std::vector< std::vector< float > > ImageOrientationPatient
void SetMetaDataScalarRangeToPointDataInfo(vtkImageData *data)
void SetDesiredCoordinateOrientationToAxial()
Set the orientation of the output image.
unsigned int GetNumberOfFileNames()
See how many file names were generated during ExecuteInformation.
void SetUseNativeOriginOn()
Use image origin from the file.
void PrintSelf(ostream &os, vtkIndent indent) override
int ExistImageOrientationPatient(float *directionCosine)
static vtkITKArchetypeImageSeriesReader * New()
static bool IsNifti2File(const char *fileName)
std::vector< std::vector< float > > ImagePositionPatient
virtual void SetDICOMImageIOApproach(int)
static std::string GetMetaDataWithoutSpaces(const itk::MetaDataDictionary &dict, const std::string &tag)
Get MetaData from dictionary, removing all whitespaces from the string.
vtkMatrix4x4 * GetRasToIjkMatrix()
Returns an IJK to RAS transformation matrix.
int ExistSeriesInstanceUID(const char *SeriesInstanceUID)
check the existence of given discriminator
const char * GetNthValue(unsigned int n)
unsigned int GetNumberOfItemsInDictionary()
void SetUseNativeOriginOff()
Use image center as origin.
void ReportFileReadError(const std::string &fileName, const std::string &errorDetails)
const char * GetTagValue(char *tag)
const char * GetNthSeriesInstanceUID(unsigned int n)
methods to get N-th discriminator
const itk::MetaDataDictionary & GetMetaDataDictionary() const
Return the MetaDataDictionary from the ITK layer.
const char * GetNthKey(unsigned int n)
void GroupFiles(int idxSeriesInstanceUID, int idxContentTime, int idxTriggerTime, int idxEchoNumbers, int idxDiffusionGradientOrientation, int idxSliceLocation, int idxImageOrientationPatient)
static bool ReadMeasurementFrameMatrixFromMetaDataDictionary(const itk::MetaDataDictionary &dictionary, vtkMatrix4x4 *measurementFrameMatrix)
std::vector< std::pair< double, int > > FileNameSliceKey
static itk::ImageIOBase::Pointer CreateDICOMImageIO(int dicomImageIOApproach)
unsigned int GetNumberOfSeriesInstanceUIDs()
get number of certain discriminators in the directory
vtkMatrix4x4 * GetMeasurementFrameMatrix()
Returns the Measurement frame matrix.
itk::ImageIOBase::Pointer GetImageIO(const char *filename)
Get the image IO for the specified filename.
const char * GetFileName(unsigned int n)
const std::vector< std::string > & GetFileNames()
Return all the file names.
virtual void SetOutputScalarType(int)
Get the file format. Pixels are this type in the file.
std::vector< long int > IndexSeriesInstanceUIDs
index of each dicom file into the above arrays