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