1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkMedicalImageProperties.h
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 /**
16  * @class   vtkMedicalImageProperties
17  * @brief   some medical image properties.
18  *
19  * vtkMedicalImageProperties is a helper class that can be used by medical
20  * image readers and applications to encapsulate medical image/acquisition
21  * properties. Later on, this should probably be extended to add
22  * any user-defined property.
23  * @sa
24  * vtkMedicalImageReader2
25  */
26 
27 #ifndef vtkMedicalImageProperties_h
28 #define vtkMedicalImageProperties_h
29 
30 #include "vtkIOImageModule.h" // For export macro
31 #include "vtkObject.h"
32 
33 class vtkMedicalImagePropertiesInternals;
34 
35 class VTKIOIMAGE_EXPORT vtkMedicalImageProperties : public vtkObject
36 {
37 public:
38   static vtkMedicalImageProperties* New();
39   vtkTypeMacro(vtkMedicalImageProperties, vtkObject);
40   void PrintSelf(ostream& os, vtkIndent indent) override;
41 
42   /**
43    * Convenience method to reset all fields to an empty string/value
44    */
45   virtual void Clear();
46 
47   ///@{
48   /**
49    * Patient name
50    * For ex: DICOM (0010,0010) = DOE,JOHN
51    */
52   vtkSetStringMacro(PatientName);
53   vtkGetStringMacro(PatientName);
54   ///@}
55 
56   ///@{
57   /**
58    * Patient ID
59    * For ex: DICOM (0010,0020) = 1933197
60    */
61   vtkSetStringMacro(PatientID);
62   vtkGetStringMacro(PatientID);
63   ///@}
64 
65   ///@{
66   /**
67    * Patient age
68    * Format: nnnD, nnW, nnnM or nnnY (eventually nnD, nnW, nnY)
69    * with D (day), M (month), W (week), Y (year)
70    * For ex: DICOM (0010,1010) = 031Y
71    */
72   vtkSetStringMacro(PatientAge);
73   vtkGetStringMacro(PatientAge);
74   ///@}
75 
76   /**
77    * Take as input a string in VR=AS (DICOM PS3.5) and extract either
78    * different fields namely: year month week day
79    * Return 0 on error, 1 on success
80    * One can test fields if they are different from -1 upon success
81    */
82   static int GetAgeAsFields(const char* age, int& year, int& month, int& week, int& day);
83 
84   // For Tcl:
85   // From C++ use GetPatientAge + GetAgeAsField
86   // Those function parse a DICOM string, and return the value of the number
87   // expressed this is either expressed in year, month or days. Thus if a
88   // string is expressed in years
89   // GetPatientAgeDay/GetPatientAgeWeek/GetPatientAgeMonth will return 0
90   int GetPatientAgeYear();
91   int GetPatientAgeMonth();
92   int GetPatientAgeWeek();
93   int GetPatientAgeDay();
94 
95   ///@{
96   /**
97    * Patient sex
98    * For ex: DICOM (0010,0040) = M
99    */
100   vtkSetStringMacro(PatientSex);
101   vtkGetStringMacro(PatientSex);
102   ///@}
103 
104   ///@{
105   /**
106    * Patient birth date
107    * Format: yyyymmdd
108    * For ex: DICOM (0010,0030) = 19680427
109    */
110   vtkSetStringMacro(PatientBirthDate);
111   vtkGetStringMacro(PatientBirthDate);
112   ///@}
113 
114   // For Tcl:
115   // From C++ use GetPatientBirthDate + GetDateAsFields
116   int GetPatientBirthDateYear();
117   int GetPatientBirthDateMonth();
118   int GetPatientBirthDateDay();
119 
120   ///@{
121   /**
122    * Study Date
123    * Format: yyyymmdd
124    * For ex: DICOM (0008,0020) = 20030617
125    */
126   vtkSetStringMacro(StudyDate);
127   vtkGetStringMacro(StudyDate);
128   ///@}
129 
130   ///@{
131   /**
132    * Acquisition Date
133    * Format: yyyymmdd
134    * For ex: DICOM (0008,0022) = 20030617
135    */
136   vtkSetStringMacro(AcquisitionDate);
137   vtkGetStringMacro(AcquisitionDate);
138   ///@}
139 
140   // For Tcl:
141   // From C++ use GetAcquisitionDate + GetDateAsFields
142   int GetAcquisitionDateYear();
143   int GetAcquisitionDateMonth();
144   int GetAcquisitionDateDay();
145 
146   ///@{
147   /**
148    * Study Time
149    * Format: hhmmss.frac (any trailing component(s) can be omitted)
150    * For ex: DICOM (0008,0030) = 162552.0705 or 230012, or 0012
151    */
152   vtkSetStringMacro(StudyTime);
153   vtkGetStringMacro(StudyTime);
154   ///@}
155 
156   ///@{
157   /**
158    * Acquisition time
159    * Format: hhmmss.frac (any trailing component(s) can be omitted)
160    * For ex: DICOM (0008,0032) = 162552.0705 or 230012, or 0012
161    */
162   vtkSetStringMacro(AcquisitionTime);
163   vtkGetStringMacro(AcquisitionTime);
164   ///@}
165 
166   ///@{
167   /**
168    * Image Date aka Content Date
169    * Format: yyyymmdd
170    * For ex: DICOM (0008,0023) = 20030617
171    */
172   vtkSetStringMacro(ImageDate);
173   vtkGetStringMacro(ImageDate);
174   ///@}
175 
176   // For Tcl:
177   // From C++ use GetImageDate + GetDateAsFields
178   int GetImageDateYear();
179   int GetImageDateMonth();
180   int GetImageDateDay();
181 
182   /**
183    * Take as input a string in ISO 8601 date (YYYY/MM/DD) and extract the
184    * different fields namely: year month day
185    * Return 0 on error, 1 on success
186    */
187   static int GetDateAsFields(const char* date, int& year, int& month, int& day);
188 
189   /**
190    * Take as input a string in VR:TM format (HHMMSS) and extract the
191    * different fields namely: hour, minute and second
192    * Return 0 on error, 1 on success
193    */
194   static int GetTimeAsFields(
195     const char* time, int& hour, int& minute, int& second /* , long &milliseconds */);
196 
197   /**
198    * Take as input a string in ISO 8601 date (YYYY/MM/DD) and construct a
199    * locale date based on the different fields (see GetDateAsFields to extract
200    * different fields)
201    * Return 0 on error, 1 on success
202    */
203   static int GetDateAsLocale(const char* date, char* locale);
204 
205   ///@{
206   /**
207    * Image Time
208    * Format: hhmmss.frac (any trailing component(s) can be omitted)
209    * For ex: DICOM (0008,0033) = 162552.0705 or 230012, or 0012
210    */
211   vtkSetStringMacro(ImageTime);
212   vtkGetStringMacro(ImageTime);
213   ///@}
214 
215   ///@{
216   /**
217    * Image number
218    * For ex: DICOM (0020,0013) = 1
219    */
220   vtkSetStringMacro(ImageNumber);
221   vtkGetStringMacro(ImageNumber);
222   ///@}
223 
224   ///@{
225   /**
226    * Series number
227    * For ex: DICOM (0020,0011) = 902
228    */
229   vtkSetStringMacro(SeriesNumber);
230   vtkGetStringMacro(SeriesNumber);
231   ///@}
232 
233   ///@{
234   /**
235    * Series Description
236    * User provided description of the Series
237    * For ex: DICOM (0008,103e) = SCOUT
238    */
239   vtkSetStringMacro(SeriesDescription);
240   vtkGetStringMacro(SeriesDescription);
241   ///@}
242 
243   ///@{
244   /**
245    * Study ID
246    * For ex: DICOM (0020,0010) = 37481
247    */
248   vtkSetStringMacro(StudyID);
249   vtkGetStringMacro(StudyID);
250   ///@}
251 
252   ///@{
253   /**
254    * Study description
255    * For ex: DICOM (0008,1030) = BRAIN/C-SP/FACIAL
256    */
257   vtkSetStringMacro(StudyDescription);
258   vtkGetStringMacro(StudyDescription);
259   ///@}
260 
261   ///@{
262   /**
263    * Modality
264    * For ex: DICOM (0008,0060)= CT
265    */
266   vtkSetStringMacro(Modality);
267   vtkGetStringMacro(Modality);
268   ///@}
269 
270   ///@{
271   /**
272    * Manufacturer
273    * For ex: DICOM (0008,0070) = Siemens
274    */
275   vtkSetStringMacro(Manufacturer);
276   vtkGetStringMacro(Manufacturer);
277   ///@}
278 
279   ///@{
280   /**
281    * Manufacturer's Model Name
282    * For ex: DICOM (0008,1090) = LightSpeed QX/i
283    */
284   vtkSetStringMacro(ManufacturerModelName);
285   vtkGetStringMacro(ManufacturerModelName);
286   ///@}
287 
288   ///@{
289   /**
290    * Station Name
291    * For ex: DICOM (0008,1010) = LSPD_OC8
292    */
293   vtkSetStringMacro(StationName);
294   vtkGetStringMacro(StationName);
295   ///@}
296 
297   ///@{
298   /**
299    * Institution Name
300    * For ex: DICOM (0008,0080) = FooCity Medical Center
301    */
302   vtkSetStringMacro(InstitutionName);
303   vtkGetStringMacro(InstitutionName);
304   ///@}
305 
306   ///@{
307   /**
308    * Convolution Kernel (or algorithm used to reconstruct the data)
309    * For ex: DICOM (0018,1210) = Bone
310    */
311   vtkSetStringMacro(ConvolutionKernel);
312   vtkGetStringMacro(ConvolutionKernel);
313   ///@}
314 
315   ///@{
316   /**
317    * Slice Thickness (Nominal reconstructed slice thickness, in mm)
318    * For ex: DICOM (0018,0050) = 0.273438
319    */
320   vtkSetStringMacro(SliceThickness);
321   vtkGetStringMacro(SliceThickness);
322   virtual double GetSliceThicknessAsDouble();
323   ///@}
324 
325   ///@{
326   /**
327    * Peak kilo voltage output of the (x-ray) generator used
328    * For ex: DICOM (0018,0060) = 120
329    */
330   vtkSetStringMacro(KVP);
331   vtkGetStringMacro(KVP);
332   ///@}
333 
334   ///@{
335   /**
336    * Gantry/Detector tilt (Nominal angle of tilt in degrees of the scanning
337    * gantry.)
338    * For ex: DICOM (0018,1120) = 15
339    */
340   vtkSetStringMacro(GantryTilt);
341   vtkGetStringMacro(GantryTilt);
342   virtual double GetGantryTiltAsDouble();
343   ///@}
344 
345   ///@{
346   /**
347    * Echo Time
348    * (Time in ms between the middle of the excitation pulse and the peak of
349    * the echo produced)
350    * For ex: DICOM (0018,0081) = 105
351    */
352   vtkSetStringMacro(EchoTime);
353   vtkGetStringMacro(EchoTime);
354   ///@}
355 
356   ///@{
357   /**
358    * Echo Train Length
359    * (Number of lines in k-space acquired per excitation per image)
360    * For ex: DICOM (0018,0091) = 35
361    */
362   vtkSetStringMacro(EchoTrainLength);
363   vtkGetStringMacro(EchoTrainLength);
364   ///@}
365 
366   ///@{
367   /**
368    * Repetition Time
369    * The period of time in msec between the beginning of a pulse sequence and
370    * the beginning of the succeeding (essentially identical) pulse sequence.
371    * For ex: DICOM (0018,0080) = 2040
372    */
373   vtkSetStringMacro(RepetitionTime);
374   vtkGetStringMacro(RepetitionTime);
375   ///@}
376 
377   ///@{
378   /**
379    * Exposure time (time of x-ray exposure in msec)
380    * For ex: DICOM (0018,1150) = 5
381    */
382   vtkSetStringMacro(ExposureTime);
383   vtkGetStringMacro(ExposureTime);
384   ///@}
385 
386   ///@{
387   /**
388    * X-ray tube current (in mA)
389    * For ex: DICOM (0018,1151) = 400
390    */
391   vtkSetStringMacro(XRayTubeCurrent);
392   vtkGetStringMacro(XRayTubeCurrent);
393   ///@}
394 
395   ///@{
396   /**
397    * Exposure (The exposure expressed in mAs, for example calculated
398    * from Exposure Time and X-ray Tube Current)
399    * For ex: DICOM (0018,1152) = 114
400    */
401   vtkSetStringMacro(Exposure);
402   vtkGetStringMacro(Exposure);
403   ///@}
404 
405   ///@{
406   /**
407    * Get the direction cosine (default to 1,0,0,0,1,0)
408    */
409   vtkSetVector6Macro(DirectionCosine, double);
410   vtkGetVector6Macro(DirectionCosine, double);
411   ///@}
412 
413   // Interface to allow insertion of user define values, for instance in DICOM
414   // one would want to
415   // store the Protocol Name (0018,1030), in this case one would do:
416   // AddUserDefinedValue( "Protocol Name", "T1W/SE/1024" );
417   virtual void AddUserDefinedValue(const char* name, const char* value);
418   virtual const char* GetUserDefinedValue(const char* name);
419   virtual unsigned int GetNumberOfUserDefinedValues();
420   virtual const char* GetUserDefinedNameByIndex(unsigned int idx);
421   virtual const char* GetUserDefinedValueByIndex(unsigned int idx);
422   virtual void RemoveAllUserDefinedValues();
423 
424   ///@{
425   /**
426    * Add/Remove/Query the window/level presets that may have been associated
427    * to a medical image. Window is also known as 'width', level is also known
428    * as 'center'. The same window/level pair can not be added twice.
429    * As a convenience, a comment (aka Explanation) can be associated to
430    * a preset.
431    * For ex:
432    * \verbatim
433    * DICOM Window Center (0028,1050) = 00045\000470
434    * DICOM Window Width  (0028,1051) = 0106\03412
435    * DICOM Window Center Width Explanation (0028,1055) = WINDOW1\WINDOW2
436    * \endverbatim
437    */
438   virtual int AddWindowLevelPreset(double w, double l);
439   virtual void RemoveWindowLevelPreset(double w, double l);
440   virtual void RemoveAllWindowLevelPresets();
441   virtual int GetNumberOfWindowLevelPresets();
442   virtual int HasWindowLevelPreset(double w, double l);
443   virtual int GetWindowLevelPresetIndex(double w, double l);
444   virtual int GetNthWindowLevelPreset(int idx, double* w, double* l);
445   virtual double* GetNthWindowLevelPreset(int idx) VTK_SIZEHINT(2);
446   virtual void SetNthWindowLevelPresetComment(int idx, const char* comment);
447   virtual const char* GetNthWindowLevelPresetComment(int idx);
448   ///@}
449 
450   ///@{
451   /**
452    * Mapping from a sliceidx within a volumeidx into a DICOM Instance UID
453    * Some DICOM reader can populate this structure so that later on from
454    * a slice index in a vtkImageData volume we can backtrack and find out
455    * which 2d slice it was coming from
456    */
457   const char* GetInstanceUIDFromSliceID(int volumeidx, int sliceid);
458   void SetInstanceUIDFromSliceID(int volumeidx, int sliceid, const char* uid);
459   ///@}
460 
461   /**
462    * Provides the inverse mapping. Returns -1 if a slice for this uid is
463    * not found.
464    */
465   int GetSliceIDFromInstanceUID(int& volumeidx, const char* uid);
466 
467   typedef enum
468   {
469     AXIAL = 0,
470     CORONAL,
471     SAGITTAL
472   } OrientationType;
473 
474   int GetOrientationType(int volumeidx);
475   void SetOrientationType(int volumeidx, int orientation);
476   static const char* GetStringFromOrientationType(unsigned int type);
477 
478   /**
479    * Copy the contents of p to this instance.
480    */
481   virtual void DeepCopy(vtkMedicalImageProperties* p);
482 
483 protected:
484   vtkMedicalImageProperties();
485   ~vtkMedicalImageProperties() override;
486 
487   char* StudyDate;
488   char* AcquisitionDate;
489   char* StudyTime;
490   char* AcquisitionTime;
491   char* ConvolutionKernel;
492   char* EchoTime;
493   char* EchoTrainLength;
494   char* Exposure;
495   char* ExposureTime;
496   char* GantryTilt;
497   char* ImageDate;
498   char* ImageNumber;
499   char* ImageTime;
500   char* InstitutionName;
501   char* KVP;
502   char* ManufacturerModelName;
503   char* Manufacturer;
504   char* Modality;
505   char* PatientAge;
506   char* PatientBirthDate;
507   char* PatientID;
508   char* PatientName;
509   char* PatientSex;
510   char* RepetitionTime;
511   char* SeriesDescription;
512   char* SeriesNumber;
513   char* SliceThickness;
514   char* StationName;
515   char* StudyDescription;
516   char* StudyID;
517   char* XRayTubeCurrent;
518   double DirectionCosine[6];
519 
520   /**
521    * PIMPL Encapsulation for STL containers
522    */
523   vtkMedicalImagePropertiesInternals* Internals;
524 
525 private:
526   vtkMedicalImageProperties(const vtkMedicalImageProperties&) = delete;
527   void operator=(const vtkMedicalImageProperties&) = delete;
528 };
529 
530 #endif
531