]> Creatis software - gdcm.git/blob - Doc/Website/HowToUseGdcm.html
Update
[gdcm.git] / Doc / Website / HowToUseGdcm.html
1 <pre>
2 {{{
3 This is a vi-able/notepad-able document to (try to) explain in a few words 
4 how to use efficently gdcm.
5 -->Feel free to send/add your comments/suggestions/modifications.
6 -->Don't try to 'beautify' this page.
7 (I plane to rewrite it in html, as soon as there is enough 'content' within it)
8
9 HTH
10 Jean-Pierre Roux
11
12 ------------------------------------------------------------------------
13
14 0) Intro
15 ========
16 1) How to Read a DICOM file
17 ===========================
18 1-1) using raw C++
19 1-1-1) A single file
20 1-1-1-1) Deal with the file header
21 1-1-1-2) Load the 'pixels' in memory
22 1-1-1-3) Get the value of a single Dicom DataElement 
23 1-1-1-4) Get the value of a Dicom Sequence  
24 1-1-2) A File Set
25
26 1-2) using VTK
27 1-2-1) A single file
28 1-2-2) A File Set
29
30 1-3) using ITK
31 1-3-1) A single file
32 1-3-2) A File Set
33
34 1-4) Retrictions for Python users
35
36 2) How to write DICOM file
37 ==========================
38 2-1) using raw C++
39 2-1-1) A single file
40 2-1-1-1) Deal with optional DataElements
41 2-1-1-1-1) Add a single Dicom DataElement // TODO
42 2-1-1-1-2) Add a Dicom Sequence           // TODO
43 2-1-2) A File Set
44
45 2-2) using VTK
46
47 2-3) using ITK
48
49 2-4) Retrictions for Python users
50
51 3) Some 'Command line' utilities
52 ================================
53 3-) PrintFile
54 3-) exSerieHelper
55 3-) exXCoherentFileSet
56
57 3-) AnonymizeNoLoad
58 3-) AnonymizeMultiPatient
59 3-) AnonymizeDicomDir
60
61 3-) ReWrite
62 3-) RawToDicom
63 3-) exMoveImagesToSingleSerieUID
64
65 3-) vtkgdcmViewer2
66 3-) vtkgdcmSerieViewer2
67
68 3-) PrintDicomDir
69 3-) MakeDicomDir
70
71 ----------------------------------------------------------------------------
72
73 0) Intro
74 ========
75
76 If you are not familiar with DICOM files, use :
77
78 PrintFile filein=yourDicomFile.dcm
79
80 and have a look at the output.
81 You'll see a lot of self explanatory (?) lines, e.g.
82
83 D 0008|0021 [DA]   [Series Date]     [20020524]
84 D 0008|0060 [CS]   [Modality]        [US]
85 D 0018|602c [FD]   [Physical Delta X][0]
86 D 0020|0013 [IS]   [Instance Number] [5 ]
87 D 0028|0010 [US]   [Rows]            [480]
88 D 0011|0010 [  ]   [gdcm::Unknown]   [DLX_PATNT_01]
89 D 0028|1222 [OW]   [Segmented Green Palette Color Lookup Table Data]
90                                  ===> [gdcm::Binary data loaded;length = 113784]
91
92 0008|0021 : 'Group Number'|'Element Number' -> The Element identifier
93 Have a look at gdcm/Dicts/dicomV3.dic for the whole list of Elements
94  
95 DA        : The 'Value Representation' : DA for Date, US for Unsigned Short, ...
96 Have a look at gdcm/Dicts/dicomVR.dic for the set of possible values
97
98 [Series Date] : The 'official' English name of the Element
99 (When *you* have to deal with a given Element, its meaning should be clear for
100 *you*)
101
102 [20020524] : the value, printed in a human readable way.
103
104 If something like :
105 D 0028|1222 [OW] [Segmented Green Palette Color Lookup Table Data]
106                                  ===> [gdcm::Binary data loaded;length = 113784]
107 is displayed, it means that it's a 'long' binary area, gdcm (I) decided not to
108 show.
109
110 D 0011|0010 [  ]   [gdcm::Unknown]   [DLX_PATNT_01]
111 is a 'Private (or Shadow) Element', depending on the manufacturer.
112 It's *not* known within the 'official' Dicom Dictionnary.
113 Except if someone told you, you cannot guess the meaning of such an element.
114 Probabely, you'll never have to deal with Shadow Elements (hope so!).
115
116 You can find also something like : 
117
118 S 0018|6011 [SQ]                       [Sequence of Ultrasound Regions]
119    |  --- SQItem number 0
120    | D fffe|e000 [UL]                               [Item]
121    | D 0018|6018 [UL]             [Region Location Min X0] [32]
122    | D 0018|601a [UL]             [Region Location Min Y0] [24]
123    | D 0018|601c [UL]             [Region Location Max X1] [335]
124    | D 0018|601e [UL]             [Region Location Max Y1] [415]
125    | D 0018|602c [FD]                   [Physical Delta X] [0.0382653]
126    | D 0018|602e [FD]                   [Physical Delta Y] [0.0382653]
127    |  --- SQItem number 1
128    | D fffe|e000 [UL]                               [Item]
129    | D 0018|6018 [UL]             [Region Location Min X0] [336]
130    | D 0018|601a [UL]             [Region Location Min Y0] [24]
131    | D 0018|601c [UL]             [Region Location Max X1] [639]
132    | D 0018|601e [UL]             [Region Location Max Y1] [415]
133    | D 0018|602c [FD]                   [Physical Delta X] [0.0382653]
134    | D 0018|602e [FD]                   [Physical Delta Y] [0.0382653]
135    |  --- SQItem number 2
136    | D fffe|e000 [UL]                               [Item]
137    | D 0018|6018 [UL]             [Region Location Min X0] [32]
138    | D 0018|601a [UL]             [Region Location Min Y0] [40]
139    | D 0018|601c [UL]             [Region Location Max X1] [63]
140    | D 0018|601e [UL]             [Region Location Max Y1] [103]
141    | D 0018|6024 [US]         [Physical Units X Direction] [0]
142    | D 0018|6026 [US]         [Physical Units Y Direction] [0]
143    | D 0018|602c [FD]                   [Physical Delta X] [0]
144    | D 0018|602e [FD]                   [Physical Delta Y] [0]
145
146 0018|6011 is a 'Sequence' (SQ), composed of various Sequence Items(SQItem)
147 Each SQItem is a set of Elements (an Element may be a DataElement (D) or a
148 Sequence (S), recursively, within any level of embedding :
149
150 S 0029|263d [SQ]                                                                   []
151    |  --- SQItem number 0
152    | D fffe|e000 [UL]                                                              [Item ]
153    | D 0008|0000 [UL]                                                       [Group Length] [12]
154    | D 0008|0001 [UL]                                               [Length to End (RET) ] [28776]
155    | D 0029|0000 [UL]                                                       [Group Length] [28764]
156    | D 0029|002a [LO]                                                    [Private Creator] [SPI-P-Private_ICS Release 1;6 ]
157    | D 0029|2a02 [LO]                                                                   [] [PERFUSION_MR_T2STAR_GAMMA_VARIATE_ANALYSER]
158    | S 0029|2a06 [SQ]                                                                   []
159    |    |  --- SQItem number 0
160    |    | D fffe|e000 [UL]                                                              [Item ]
161    |    | D 0008|0000 [UL]                                                       [Group Length] [12]
162    |    | D 0008|0001 [UL]                                               [Length to End (RET) ] [20]
163    |    | D fffe|0000 [UL]                                                       [Group Length]
164    |    |  --- SQItem number 1
165    |    | D fffe|e000 [UL]                                                              [Item ]
166    |    | D 0008|0000 [UL]                                                       [Group Length] [12]
167    |    | D 0008|0001 [UL]                                               [Length to End (RET) ] [194]
168    |    | D 0029|0000 [UL]                                                       [Group Length] [182]
169    |    | D 0029|002a [LO]                                                    [Private Creator] [SPI-P-Private_ICS Release 1;6 ]
170    |    | S 0029|2a07 [SQ]                                                                   []
171    |    |    |  --- SQItem number 0
172    |    |    | D fffe|e000 [UL]                                                              [Item ]
173    |    |    | D 0008|0000 [UL]                                                       [Group Length] [12]
174    |    |    | D 0008|0001 [UL]                                               [Length to End (RET) ] [100]
175    |    |    | D 0029|0000 [UL]                                                       [Group Length] [88]
176    |    |    | D 0029|002a [LO]                                                    [Private Creator] [SPI-P-Private_ICS Release 1;6 ]
177    |    |    | D 0029|2a0a [US]                                                                   [] [1]
178    |    |    | D 0029|2a0b [US]                                                                   [] [2]
179    |    |    | D 0029|2a0c [US]                                                                   [] [2]
180    |    |    | D 0029|2a0d [US]                                                                   [] [1]
181    |    |    | D 0029|2a10 [US]                                                                   [] [1]
182    |    |    | S 0029|2a2e [SQ]                                                                   []
183    |    |    |    |  --- SQItem number 0
184    |    |    |    | D fffe|e000 [UL]                                                              [Item ]
185    |    |    |    | D 0008|0000 [UL]                                                       [Group Length] [12]
186    |    |    |    | D 0008|0001 [UL]                                               [Length to End (RET) ] [2266]
187    |    |    |    | D 0029|0000 [UL]                                                       [Group Length] [2254]
188    |    |    |    | D 0029|0025 [LO]                                                    [Private Creator] [SPI-P-Private_ICS Release 1;1 ]
189    |    |    |    | D 0029|0027 [LO]                                                    [Private Creator] [SPI-P-Private_ICS Release 1;3 ]
190    |    |    |    | D 0029|0028 [LO]                                                    [Private Creator] [SPI-P-Private_ICS Release 1;4 ]
191    |    |    |    | D 0029|2500 [SL]                                                                   [] [43]
192    |    |    |    | D 0029|256b [FD]                                                                   [] [0.5]
193    |    |    |    | D 0029|2700 [LO]                                                                   [] [L1]
194    |    |    |    | D 0029|276a [FL]                                                                   [] [0.35]
195    |    |    |    | S 0029|27c0 [SQ]                                                                   []
196    |    |    |    |    |  --- SQItem number 0
197    |    |    |    |    | D fffe|e000 [UL]                                                              [Item ]
198    |    |    |    |    | D 0008|0000 [UL]                                                       [Group Length] [12]
199    |    |    |    |    | D 0008|0001 [UL]                                               [Length to End (RET) ] [110]
200    |    |    |    |    | D 0029|0000 [UL]                                                       [Group Length] [98]
201    |    |    |    |    | D 0029|0027 [LO]                                                    [Private Creator] [SPI-P-Private_ICS Release 1;3 ]
202    |    |    |    |    | D 0029|27b0 [SL]                                                                   [] [0]
203    |    |    |    |    | D 0029|27b1 [FL]                                                                   [] [0]
204    |    |    |    |    | D 0029|27b2 [FL]                                                                   [] [0]
205    |    |    |    |    | D 0029|27b4 [FL]                                                                   [] [0]
206    |    |    |    |    | D 0029|27b9 [FL]                                                                   [] [1]   
207    | S 0029|2a14 [SQ]                                                                   []
208    |    |  --- SQItem number 0
209    |    | D fffe|e000 [UL]                                                              [Item ]
210    |    | D 0008|0000 [UL]                                                       [Group Length] [12]
211    
212 Probabely, you'll never have to deal with Sequences (hope so!).
213
214 1) How to Read a DICOM File
215 ===========================
216
217 1-1) using raw C++
218 ------------------
219
220 1-1-1) A single file
221 --------------------
222
223 1-1-1-1) Deal with the file header
224
225 The first step is to load the file header :
226
227            gdcm::File *f = new gdcm::File();
228                   f->SetLoadMode(LD_NOSEQ);              | depending on what
229                   f->SetLoadMode(LD_NOSHADOW);           | you want *not* 
230                   f->SetLoadMode(LD_NOSEQ | LD_NOSHADOW);| to load from the
231                   f->SetLoadMode(LD_NOSHADOWSEQ);        | target file
232            f->SetFileName(fileName);
233            f->Load( );
234
235 Note :
236 The 'long' Data Element (>4096 char) are not loaded by default
237 You may modify this default length :
238            f->SetMaxSizeLoadEntry(int yourOwnMaxSize);
239 Or ask to force the loading of given Data Elements, whatever their size is:  
240             f->AddForceLoadElement (uint16_t group, uint16_t elem);
241 before calling gdcm::File::Load();
242
243 Note :
244 Except if you are really aware about it, do *not* use SetLoadMode().
245 LD_ALL is the default.
246
247 Check if the file is gdcm-readable.
248
249            if ( !f->IsReadable() )
250              std::cout << "major troubles on [" << f->GetFileName() <<"]"
251                        << std::endl;
252
253 Decide if this is a 'File Of Interest' for you.
254 Check some fields, e.g
255
256            std::string StudyDate           = f->GetEntryString(0x0008,0x0020);
257            std::string PatientName         = f->GetEntryString(0x0010,0x0010);
258            std::string PatientID           = f->GetEntryString(0x0010,0x0020);
259            std::string PatientSex          = f->GetEntryString(0x0010,0x0040);
260            std::string Modality            = f->GetEntryString(0x0008,0x0060);
261
262 (or whatever you feel like ...)
263
264 1-1-1-2) Load the 'pixels' in memory
265
266 Next step is to load the pixels in memory.
267 Uncompression (JPEG lossless, JPEG lossy, JPEG 2000, RLE, ...) 
268 is automatically performed if necessary.
269
270            gdcm::FileHelper *fh = gdcm::FileHelper::New(f);
271            void *imageData = fh->GetImageDataRaw();
272            uint32_t dataSize = fh->GetImageDataRawSize();
273
274 Generally, you work on 'Grey level' images (as opposed to RGB images).
275 Depending on the Pixel size (8/16/32 bits) and the Pixel Type (signed/unsigned),
276 you cast the imageData
277
278           std::string pixelType = f->GetPixelType();
279   
280 Possible values are : 
281
282 - "8U"  unsigned  8 bit,
283 - "8S"    signed  8 bit,
284 - "16U" unsigned 16 bit,
285 - "16S"   signed 16 bit,
286 - "32U" unsigned 32 bit,
287 - "32S"   signed 32 bit,
288 - (NEITHER 'float' NOR 'double' pixels in DICOM!)
289    
290            int dimX = f->GetXSize();
291            int dimY = f->GetYSize();
292            int dimZ = f->GetZSize(); // meaningfull only for 'Volumes' or 'multiframe files'
293            int dimT = f->GetTSize(); // meaningfull only for 4D objects (?)
294
295 Now, you can enjoy your image !
296
297 Sometimes, you deal with 'colour' images :-(
298 They may be stored, on disc, as :
299      RGB pixels, 
300      RGB planes, 
301      YBR pixels, 
302      YBR planes
303      Grey level images + LUT.
304
305 You'll get an 'RGB Pixels' image in memory if you use: 
306
307            gdcm::FileHelper *fh = gdcm::FileHelper::New(f);
308            void *imageData = fh->GetImageData();
309            uint32_t dataSize = fh->GetImageDataSize();
310
311 If you don't want to convert a "Grey level images + LUT" into "RGB Pixel image" use
312            gdcm::FileHelper *fh = gdcm::FileHelper::New(f);
313            void *imageData = fh->GetImageDataRaw();
314            uint32_t dataSize = fh->GetImageDataRawSize();
315
316 1-1-1-3) Get the value of a single Dicom DataElement 
317
318 1-1-1-3-1) as a std::string
319
320 - some DataEntries are 'human readable' (those whose VR is AE, DA, DS, PN, SH, TM)
321   Get their value using group number-element number :
322   std::string patientName = f->GetEntryString(0x0010,0x0010);
323   
324 - Some DataEntries are stored with their own binary representation, but maybe you feel like 
325   to get them in a 'human readable' form (those whose VR is FL, FD, SL, SS, UL, US)
326   Get their value using group number-element number : 
327   std::string rowNumber =f->GetEntryString(0x0028, 0x0010);// nb of Rows
328   
329   (of course, the very often used DataEntries have their own accessors :
330   e.g. GetXsize, GetYSize, GetSpacing, GetImageOrientationPatient, GetImagePositionPatient,
331        GetRescaleSlope, GetRescaleIntercept, GetNumberOfScalarComponents, etc -see gdcmFile.h-)
332   
333
334 1-1-1-3-3) as a void* pointer
335 - Some DataEntries are stored with their own binary representation, and you want to get them 'as they are'.
336   You will have to cast them, according to the knowledge you have about them.
337   LutRedData = (uint8_t*)f->GetEntryBinArea( 0x0028, 0x1201 ); 
338    
339 1-1-1-4) Get the value(s) of a Dicom Sequence           
340
341 Actually, a 'Dicom Sequence' is composed of a list a 'Sequence Items',
342 each Sequence Item is a set of DataElement (that can be a Sequence Element, recursively).
343 You have to get the Sequence element, to get its number of Sequence items, to iterate on each one.
344 e.g.:
345
346 SeqEntry *seqEntry = f->GetSeqEntry(0x3006,0x0020); //Structure Set ROI sequence
347 unsigned int n = seqEntry->GetNumberOfSQItems();    // useless : just to see !
348 currentItem = seqEntry->GetFirstSQItem(); // Get the first ROI
349 while (currentItem != NULL) {
350    std::string roiName = currentItem->GetEntryString(0x3006,0x0026);  //ROI name
351    std::string roiDescr = currentItem->GetEntryString(0x3006,0x0028); //ROI description
352    ...
353    // do what you want with the current ROI
354    currentItem = seqEntry->GetNextSQItem(); // Get the next ROI
355 }
356
357
358 1-1-2) A File Set
359 -----------------
360
361 If you are 150 % sure of the files you're dealing with, just read the files you
362 feel like, and concatenate the pixels.
363
364 Sometimes you are not sure at all (say : you were given a CDROM with an amount
365 of images, laying in a Directories tree-like structure, you don't know anything
366 about the Patients, and so on)
367
368 A class gdcm::SerieHelper is designed to help solving this problem.
369 Use it as follows.
370
371     gdcm::SerieHelper *sh = gdcm::SerieHelper::New();
372     while (int i=0; i < nbOfFiles; i++) {
373        sh->AddFileName(currentFileName[i]);
374     }
375     
376 You can also pass a 'root directory', and ask or not for recursive parsing.
377     gdcm::SerieHelper *sh = gdcm::SerieHelper::New();
378     sh->SetDirectory(yourRootDirectoryName, true); // true : recursive parsing
379
380 Files are 'splitted' into as many 'Single Serie UID File Set' 
381   as Series Instance UID ( 0020|000e );
382
383 // -------- skip this one, for a first reading ! -----------
384
385 Sometimes, the Serie UID is not enough to disseminate properly the images.
386 We may want to disseminate into multiple sub serie when needed.
387
388 Use :
389 void SerieHelper::SetUseSeriesDetails(bool s);
390    /// This function will add the following DICOM tag as being part of a
391    /// 'fake' uid. :
392    /// 0020 0011 Series Number
393    /// 0018 0024 Sequence Name
394    /// 0018 0050 Slice Thickness
395    /// 0028 0010 Rows
396    /// 0028 0011 Columns 
397
398 If it's not enough for you, use :    
399 void SerieHelper::AddSeriesDetail(uint16_t group, uint16_t elem, bool convert);
400
401 std::string SerieHelper::CreateUniqueSeriesIdentifier(gdcm::File *inFile);
402 void SerieHelper::CreateDefaultUniqueSeriesIdentifier();
403
404 You may also create a "tokenizable' File Identifier of your own, using :
405 void SerieHelper::AddSeriesDetail(uint16_t group, uint16_t elem, bool convert);
406 and
407 std::string SerieHelper::CreateUserDefinedFileIdentifier(gdcm::File *inFile);
408 and use it as you feel like.
409
410 // ------------ Resume reading, here !--------------------
411  
412 If you want to 'order' the files within each 'Single Serie UID File Set'
413 (to build a volume, for instance), use :
414   
415    gdcm::FileList *l = sh->GetFirstSingleSerieUIDFileSet();
416    while (l)
417    { 
418       sh->OrderFileList(l);  // sort the list
419       l = sh->GetNextSingleSerieUIDFileSet();
420    } 
421     
422   The sorting will be performed on the ImagePositionPatient;
423   if not found, on ImageNumber;
424   if not found, on the File Name.
425   
426   Aware user is allowed to pass his own comparison function 
427   (if he knows, for instance, the files must be sorted on 'Trigger Time')
428   He will use the method
429   void SerieHelper::SetUserLessThanFunction( bool(*) userFunc((File *,File *) ); 
430   He may ask for a reverse sorting : 
431   sh->SetSortOrderToReverse();
432   or back to Direct Order 
433   sh->SetSortOrderToDirect();
434   
435   If, for any reason of his own, user already get the file headers,
436   he may add the gdcm::File (instead of the file name) to the SerieHelper.
437
438     gdcm::SerieHelper *sh = gdcm::SerieHelper::New();
439     while (int i=0; i < nbOfFiles; i++) {
440        sh->AddFile(currentFile[i]);
441     }                           
442  * \warning : this method should be used by aware users only!
443  *            User is supposed to know the files he want to deal with
444  *           and consider them they belong to the same Set
445  *           (even if their Serie UID is different)
446  *           user will probabely OrderFileList() this list (actually, ordering
447  *           user choosen gdm::File is the sole interest of this method)
448  *           Moreover, using vtkGdcmReader::SetCoherentFileList() will avoid
449  *           vtkGdcmReader parsing twice the same files.
450  *           *no* coherence check is performed, but those specified
451  *           by SerieHelper::AddRestriction()
452  
453    User may want to exclude some files.
454    He will use
455     void SerieHelper::AddRestriction(uint16_t group, uint16_t elem,
456                                  std::string const &value, int op);
457 op belongs to :
458
459 /// \brief comparison operators
460    GDCM_EQUAL ,
461    GDCM_DIFFERENT,
462    GDCM_GREATER,
463    GDCM_GREATEROREQUAL,
464    GDCM_LESS,
465    GDCM_LESSOREQUAL
466 e.g. 
467     gdcm::SerieHelper *sh = gdcm::SerieHelper::New();
468     sh->AddRestriction(0x0010,0x0040,"F",GDCM_EQUAL);      // Patient's Sex
469     sh->AddRestriction(0x0008,0x0060,"MR",GDCM_DIFFERENT); // Modality 
470     while (int i=0; i < nbOfFiles; i++) { 
471     ...
472 User wants to deal only with Female patient, any Modality but MR (why not?)
473    
474 Maybe user knows there are several images with the same position
475 and *no dicom field* may discriminates them.
476 He wants to drop the 'duplicate images'
477    
478      sh->SetDropDuplicatePositions(true);
479
480 Sometimes the previous stuff is *not enough* !
481
482 Within a SingleSerieUIDFileSet, you can have have various orientations,
483 or various positions, at various times. (not only various position , at a single
484 time, for a single orientation).
485
486 User may consider that dealing only with the 'Series Instance UID' 
487 is not enough and wishes to 'refine' the image selection :
488
489 Suppose he has a Single Serie UID File Set (gdcm::FileList).
490 He may ask to split it into several 'X Coherent File Sets' (X stands for
491 'Extra').
492
493 gdcm::SerieHelper *s;
494 gdcm::XCoherentFileSetmap xcm;
495 gdcm::FileList *l = s->GetFirstSingleSerieUIDFileSet(); // or what you want
496
497
498  The following methods must be called by user, depending on 
499  what *he* wants to do, at application time.
500   - *he* only  knows what his Series contain ! - 
501  They return a std::map of Filesets (actually : a std::map of std::vector<gdcm::File* >).
502  
503 He may ask for 'splitting' on the Orientation:
504            gdcm::XCoherentFileSetmap xcm = s->SplitOnOrientation(l);
505    
506 He may ask for 'splitting' on the Position:
507            gdcm::XCoherentFileSetmap xcm = s->SplitOnPosition(l);
508    
509 He may ask for 'splitting' on the any DataElement you feel like :   
510            gdcm::XCoherentFileSetmap xcm = s->SplitOnTagValue(l, group,elem);
511
512  
513 He can now work on each 'X Coherent File Set' within the std::map
514
515 for (gdcm::XCoherentFileSetmap::iterator i = xcm.begin();
516                                          i != xcm.end();
517                                        ++i)
518 {
519
520    // ask for 'ordering' according to the 'Image Position Patient'
521    // Sorting the Fileset (*) is mandatory!
522    // ( computing an accurate Series ZSpacing -whenever possible- is a side effect ...)
523      
524    s->OrderFileList((*i).second);  // sort the XCoherent Fileset
525 }  
526
527 (have a look at gdcm/Examples/exXCoherentFileSet.cxx for an example)
528
529 1-2) using VTK
530 --------------
531 a vtkGdcmReader() method ( derived from vtkReader() ) is available.
532
533 1-2-1) A single file
534 --------------------
535
536    vtkGdcmReader *reader = vtkGdcmReader::New();
537    reader->SetFileName( yourDicomFilename );      
538    reader->SetLoadMode( yourLoadMode); // See C++ part 
539    reader->Update();
540    vtkImageData* ima = reader->GetOutput();
541    int* Size = ima->GetDimensions();   
542  // -> Enjoy it.     
543
544 1-2-2) A File Set
545 -----------------
546
547 If you are 150 % sure of the files you're dealing with, just 'add' the files you
548 feel like:
549
550    vtkGdcmReader *reader = vtkGdcmReader::New();
551    for(int i=1; i< yourNumberOfFiles; i++)
552          reader->AddFileName( yourTableOfFileNames[i] );     
553    reader->SetLoadMode( yourLoadMode); // See C++ part 
554    reader->Update();
555    vtkImageData* ima = reader->GetOutput();
556    int* Size = ima->GetDimensions();
557  // -> Enjoy it.
558  
559  Warning : The first file is assumed to be the reference file.
560  All the inconsistent files (different sizes, pixel types, etc) are discarted
561  and replaced by a black image ! 
562  
563       User is allowed to pass a Pointer to a function of his own
564       to allow modification of pixel order (i.e. : Mirror, UpsideDown, )
565       to gdcm::FileHeleper, using SetUserFunction(userSuppliedFunction)
566
567       described as : void userSuppliedFunction(uint8_t *im, gdcm::File *f);
568
569       NB : the "uint8_t *" type of first param is just for prototyping.
570         User will Cast it according what he found with f->GetPixelType()
571         See vtkgdcmSerieViewer for an example
572  
573
574 Many users expect from vtkGdcmReader it 'orders' the images 
575 (Actually, that's the job of gdcm::SerieHelper ...)
576 When user knows the files with same Serie UID have same sizes, 
577 same 'pixel' type, same color convention, ... 
578 the right way to proceed is as follow :
579
580         gdcm::SerieHelper *sh= new gdcm::SerieHelper();
581    //      if user wants *not* to load some parts of the file headers
582         sh->SetLoadMode(yourLoadMode);
583
584    //      if user wants *not* to load some files
585         sh->AddRestriction(group, element, value, operator);
586         sh->AddRestriction( ...
587         sh->SetDirectory(directoryWithImages);
588
589    //      if user *knows* how to order his files
590         sh->SetUserLessThanFunction(userSuppliedComparisonFunction);
591    //      or/and
592    //      if user wants to sort reverse order
593         sh->SetSortOrderToReverse();
594    
595    //      here, we suppose only the first 'Single SerieUID' Fileset is of interest
596    //      Just iterate using sh->NextSingleSerieUIDFileSet()
597    //      if you want to get all of them
598         gdcm::FileList *l = sh->GetFirstSingleSerieUIDFileSet();
599
600    //      if user is doesn't trust too much the files with same Serie UID
601         if ( !sh->IsCoherent(l) )
602            return; // not same sizes, or not same 'pixel type' -> stop
603    
604    // Maybe user knows there are several images with the same position
605    // and *no dicom field* may discriminates them.
606    // He wants to drop the 'duplicate images'
607    
608         sh->SetDropDuplicatePositions(true); 
609
610    // Sorting the Fileset (*) is mandatory!
611    // ( computing an accurate Series ZSpacing is a side effect ...)  
612         sh->OrderFileList(l);
613
614         vtkGdcmReader *reader = vtkGdcmReader::New();
615    //      if user wants to modify pixel order (Mirror, TopDown, ...)
616    //      he has to supply the function that does the job
617    //      (a *very* simple example is given in vtkgdcmSerieViewer.cxx)
618         reader->SetUserFunction (userSuppliedFunction);
619
620    //      to pass a 'Single SerieUID' Fileset as produced by gdcm::SerieHelper
621         reader->SetCoherentFileList(l);
622         reader->Update();
623
624
625 //-----------------
626 (*)
627 User may also pass an 'X Coherent Fileset', created by one of the following
628 methods : (see 1-1-2 for more details)
629  
630            xcm = sh->SplitOnOrientation(l); 
631            xcm = sh->SplitOnPosition(l);   
632            xcm = sh->SplitOnTagValue(l, groupelem[0],groupelem[1]);
633 //----------------
634
635
636 You can see a full example in vtk/vtkgdcmSerieViewer2.cxx
637 e.g.
638 vtkgdcmSerieViewer dirname=Dentist mirror
639 vtkgdcmSerieViewer dirname=Dentist reverse
640 vtkgdcmSerieViewer dirname=Dentist reverse upsidedown
641
642
643 1-4) Retrictions for Python users
644 ---------------------------------
645
646 None of the methods receiving a function pointer, or a gdcm::File as a parameter
647 is wrapable by swig.
648 :-(
649
650
651 2) How to write DICOM file
652 ==========================
653
654 2-1) using raw C++
655 ------------------
656
657 2-1-1) A single file
658 --------------------
659 In C++, if you have already the pixels in main memory, 
660 you just have to process as follow :
661
662 --> Create an empty gdcm::File
663         gdcm::File *file = gdcm::File::New();
664
665         std::ostringstream str;
666
667 // --> Set the mandatory fields
668   // Set the image size
669         str.str("");
670         str << sizeY;
671         file->InsertEntryString(str.str(),0x0028,0x0010,"US"); // Rows
672         str.str("");
673         str << sizeX;
674         file->InsertEntryString(str.str(),0x0028,0x0011,"US"); // Columns
675         str.str("");
676         str << sizeZ;
677         file->InsertEntryString(str.str(),0x0028,0x0008, "IS"); // Nbr of Frames
678   // Set the pixel type
679         str.str("");
680         str << componentSize; //8, 16, 32
681         file->InsertEntryString(str.str(),0x0028,0x0100,"US"); // Bits Allocated
682         str.str("");
683         str << componentUse; // may be 12 or 16 if componentSize =16
684         file->InsertEntryString(str.str(),0x0028,0x0101,"US"); // Bits Stored
685         str.str("");
686         str << componentSize - 1 ;
687         file->InsertEntryString(str.str(),0x0028,0x0102,"US"); // High Bit
688   // Set the pixel representation // 0/1
689         str.str("");
690         str << img.sign;
691         file->InsertEntryString(str.str(),0x0028,0x0103, "US"); // Pixel Representation
692   // Set the samples per pixel // 1:Grey level, 3:RGB
693         str.str("");
694         str << components;
695         file->InsertEntryString(str.str(),0x0028,0x0002, "US"); // Samples per Pixel
696
697 //--> Set Optional fields
698       se further how to deal with optional fields
699
700 //--> Create a gdcm::FileHelper
701        gdcm::FileHelper *fileH = gdcm::FileHelper::New(file);
702
703 //--> Tell the FileHelper what you did for creating the image:
704
705       // gdcm cannot guess how user built his image 
706       //  (and therefore cannot be clever about some Dicom fields)
707       // It's up to the user to tell gdcm what he did.
708       // -1) user created ex nihilo his own image and wants to write it 
709       //     as a Dicom image.
710       // USER_OWN_IMAGE
711       // -2) user modified the pixels of an existing image.
712       // FILTERED_IMAGE
713       // -3) user created a new image, using existing a set of images 
714       //    (eg MIP, MPR, cartography image)
715       //  CREATED_IMAGE
716       // -4) user modified/added some tags *without processing* the pixels 
717       //     (anonymization, ...)
718       //  UNMODIFIED_PIXELS_IMAGE
719       // -Probabely some more to be added
720       //(see gdcmFileHelper.h for more explanations)
721
722       // Use :
723       
724       fileH->SetContentType(GDCM_NAME_SPACE::USER_OWN_IMAGE);
725       fileH->SetContentType(GDCM_NAME_SPACE::FILTERED_IMAGE);
726       fileH->SetContentType(GDCM_NAME_SPACE::CREATED_IMAGE);
727       fileH->SetContentType(GDCM_NAME_SPACE::UNMODIFIED_PIXELS_IMAGE);
728       
729       // depending on what you did before!
730
731 //--> Set the compression type : 
732       fileH->SetWriteTypeToJPEG();      // lossles compression        
733       fileH->SetWriteTypeToJPEG2000();  // lossles compression 
734       fileH->SetWriteTypeToDcmExplVR(); // Explicit Value Representation (no compression)
735       fileH->SetWriteTypeToDcmImplVR(); // Implicit Value Representation (no compression)
736       
737       fileH->SetWriteModeToRaw();       // Probabely you don't want to convert any LUT into RGB pixels ...
738
739 //--> Set the Image Data
740        fileH->SetImageData((unsigned char *)imageData,size);
741       // ( Casting as 'unsigned char *' is just to avoid warnings.
742       // It doesn't change the values. )
743       // or
744        fileH->SetUserData((unsigned char *)imageData,size); // performs compression, when required
745             
746 //-> Write !      
747       fileH->Write(fileName.str());
748
749 //This works for a single image (singleframe or multiframe)
750
751 2-1-1-1) Deal with optional DataElements          // TODO : finish it
752     Any Data Element may be added (it's up to the user to understand what he is doing!)
753     The supplied methods 'InsertXxx' will create the DataElement or replace it if it already exists.  
754     Have a look at gdcm/Dict/dicomV3.dic to see what are the various DICOM fields, with their VR.
755     
756 2-1-1-1-1) Add a single Dicom DataElement          // TODO : finish it
757
758    use :
759    DataEntry * File::InsertEntryString(std::string const &value,
760                                    uint16_t group, uint16_t elem,
761                                    VRKey const &vr = GDCM_VRUNKNOWN);
762   
763    // (e.g. : patient name, patient ID, ... , or what you want,
764    //  using their Dicom identifier, and 'VR'
765       file->InsertEntryString("MyOwnPatient" ,0x0010,0x0010,"PN"); // 0010 0010 : Patient's Name
766    
767     DataEntry * File:InsertEntryBinArea(uint8_t *binArea, int lgth,
768                                     uint16_t group, uint16_t elem,
769                                     VRKey const &vr = GDCM_VRUNKNOWN);  
770    
771 2-1-1-1-2) Add a Dicom Sequence           // TODO : finish it
772    SeqEntry * File::InsertSeqEntry(uint16_t group, uint16_t elem);
773    
774 2-1-2) A File Set
775 -----------------
776 /// \todo : write it!
777
778
779 // If you deal with a Serie of images, it up to you to tell gdcm, for each image,
780 // what are the values of
781 // 0020 0032 DS 3 Image Position (Patient)
782 // 0020 0037 DS 6 Image Orientation (Patient)
783
784 // You will probabely want that all the images of your file set belong to the same 'Serie'
785
786
787 2-2) using VTK
788 --------------
789
790 /// \todo : write it!
791
792 2-2-1) A single file
793 --------------------
794
795 /// \todo : finish it!
796
797 // User of the CVS version of VTK 5 may set some 'Medical Image Properties'
798 // Only the predefined DataElements are available :
799 // PatientName, PatientID, PatientAge, PatientSex, PatientBirthDate, StudyID
800 // It's reasonably enough for any 'decent use'
801 //
802 // todo : explain how to use it.
803 //vtkMedicalImageProperties
804
805    // Aware user is allowed to pass his own gdcm::File *, 
806    //  so he may set *any Dicom field* he wants.
807    // (including his own Shadow Elements, or any gdcm::SeqEntry)
808    // gdcm::FileHelper::CheckMandatoryElements() will check inconsistencies,
809    // as far as it knows how.
810    // Sorry, not yet available under Python.
811    //vtkSetMacro(GdcmFile, gdcm::File *);
812    
813 void vtkGdcmWriter::SetGdcmFile(gdcm::File *);
814
815    // gdcm cannot guess how user built his image 
816    //  (and therefore cannot be clever about some Dicom fields)
817    // It's up to the user to tell gdcm what he did.
818    // -1) user created ex nihilo his own image and wants to write it 
819    //     as a Dicom image.
820    // USER_OWN_IMAGE
821    // -2) user modified the pixels of an existing image.
822    // FILTERED_IMAGE
823    // -3) user created a new image, using existing a set of images 
824    //    (eg MIP, MPR, cartography image)
825    //  CREATED_IMAGE
826    // -4) user modified/added some tags *without processing* the pixels 
827    //     (anonymization..
828    //  UNMODIFIED_PIXELS_IMAGE
829    // -Probabely some more to be added
830    //(see gdcmFileHelper.h for more explanations)
831    
832    // User is allowed to use the following methods:
833    
834 void vtkGdcmWriter::SetContentTypeToUserOwnImage()                           
835 void vtkGdcmWriter::SetContentTypeToFilteredImage()                            
836 void vtkGdcmWriter::SetContentTypeToUserCreatedImage()                        
837 vtkGdcmWriter::void SetContentTypeToUnmodifiedPixelsImage()
838    
839   // depending on what he did before!
840   
841                       
842
843 2-2-2) A File Set
844 -----------------
845 /// \todo : write it!
846
847
848 2-3) using ITK
849 --------------
850 /// \todo : write it!
851
852 2-4) Retrictions for Python users
853 ---------------------------------
854 /// \todo : write it!
855
856 3) Some 'Command line' utilities  /// \todo: finish it!
857 ================================
858
859 3-) PrintFile
860 3-) exSerieHelper
861 3-) exXCoherentFileSet
862
863 3-) AnonymizeNoLoad
864 3-) AnonymizeMultiPatient
865 3-) AnonymizeDicomDir
866
867 3-) ReWrite
868 3-) RawToDicom
869 3-) exMoveImagesToSingleSerieUID
870
871 3-) vtkgdcmViewer2
872 3-) vtkgdcmSerieViewer2
873
874 3-) PrintDicomDir
875 3-) MakeDicomDir
876 }}}
877 </pre>