]> Creatis software - gdcm.git/blob - Doc/Website/HowToUseGdcm.html
7817a2100dff8cc56205aaa450aacbb2541d2047
[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 will be automatically performed if necessary.
269
270 You first have to create a 'File Helper'
271
272            gdcm::FileHelper *fh = gdcm::FileHelper::New(f);
273
274 In some images,(where BitsAllocated=16, BitsUsed=8), 
275 the 'unused bits' are actually ... used for storing 'overlays'.
276 (e.g. : Patient / Aquisition / Institution informations, or drawings ...)
277 It's up to you to decide whether you want or not to load the overlays.
278 (Probabely, if you want to post-process the images, you dont' want!)
279
280            fh->SetKeepOverlays(true);  // default is : false
281
282            void *imageData = fh->GetImageDataRaw();
283            uint32_t dataSize = fh->GetImageDataRawSize();
284
285 Generally, you work on 'Grey level' images (as opposed to RGB images).
286 Depending on the Pixel size (8/16/32 bits) and the Pixel Type (signed/unsigned),
287 you cast the imageData
288
289           std::string pixelType = f->GetPixelType();
290   
291 Possible values are : 
292
293 - "8U"  unsigned  8 bit,
294 - "8S"    signed  8 bit,
295 - "16U" unsigned 16 bit,
296 - "16S"   signed 16 bit,
297 - "32U" unsigned 32 bit,
298 - "32S"   signed 32 bit,
299 - (NEITHER 'float' NOR 'double' pixels in DICOM!)
300    
301            int dimX = f->GetXSize();
302            int dimY = f->GetYSize();
303            int dimZ = f->GetZSize(); // meaningfull only for 'Volumes' or 'multiframe files'
304            int dimT = f->GetTSize(); // meaningfull only for 4D objects (?)
305
306 Sometimes, you deal with 'colour' images :-(
307 They may be stored, on disc, as :
308      RGB pixels, 
309      RGB planes, 
310      YBR pixels, 
311      YBR planes
312      Grey level images + LUT.
313
314 You'll get an 'RGB Pixels' image in memory if you use: 
315
316            gdcm::FileHelper *fh = gdcm::FileHelper::New(f);
317            void *imageData = fh->GetImageData();
318            uint32_t dataSize = fh->GetImageDataSize();
319
320 If you don't want to convert a "Grey level images + LUT" into "RGB Pixel image" use
321            gdcm::FileHelper *fh = gdcm::FileHelper::New(f);
322            void *imageData = fh->GetImageDataRaw();
323            uint32_t dataSize = fh->GetImageDataRawSize();
324    
325 Now, you can enjoy your image !   
326
327 1-1-1-3) Get the value of a single Dicom DataElement 
328
329 1-1-1-3-1) as a std::string
330
331 - some DataEntries are 'human readable' (those whose VR is AE, DA, DS, PN, SH, TM)
332   Get their value using group number-element number :
333   std::string patientName = f->GetEntryString(0x0010,0x0010);
334   
335 - Some DataEntries are stored with their own binary representation, but maybe you feel like 
336   to get them in a 'human readable' form (those whose VR is FL, FD, SL, SS, UL, US)
337   Get their value using group number-element number : 
338   std::string rowNumber =f->GetEntryString(0x0028, 0x0010);// nb of Rows
339   
340   (of course, the very often used DataEntries have their own accessors :
341   e.g. GetXsize, GetYSize, GetSpacing, GetImageOrientationPatient, GetImagePositionPatient,
342        GetRescaleSlope, GetRescaleIntercept, GetNumberOfScalarComponents, etc -see gdcmFile.h-)
343   
344
345 1-1-1-3-3) as a void* pointer
346 - Some DataEntries are stored with their own binary representation, and you want to get them 'as they are'.
347   You will have to cast them, according to the knowledge you have about them.
348   LutRedData = (uint8_t*)f->GetEntryBinArea( 0x0028, 0x1201 ); 
349    
350 1-1-1-4) Get the value(s) of a Dicom Sequence           
351
352 Actually, a 'Dicom Sequence' is composed of a list a 'Sequence Items',
353 each Sequence Item is a set of DataElement (that can be a Sequence Element, recursively).
354 You have to get the Sequence element, to get its number of Sequence items, to iterate on each one.
355 e.g.:
356
357 SeqEntry *seqEntry = f->GetSeqEntry(0x3006,0x0020); //Structure Set ROI sequence
358 unsigned int n = seqEntry->GetNumberOfSQItems();    // useless : just to see !
359 currentItem = seqEntry->GetFirstSQItem(); // Get the first ROI
360 while (currentItem != NULL) {
361    std::string roiName = currentItem->GetEntryString(0x3006,0x0026);  //ROI name
362    std::string roiDescr = currentItem->GetEntryString(0x3006,0x0028); //ROI description
363    ...
364    // do what you want with the current ROI
365    currentItem = seqEntry->GetNextSQItem(); // Get the next ROI
366 }
367
368
369 1-1-2) A File Set
370 -----------------
371
372 If you are 150 % sure of the files you're dealing with, just read the files you
373 feel like, and concatenate the pixels.
374
375 Sometimes you are not sure at all (say : you were given a CDROM with an amount
376 of images, laying in a Directories tree-like structure, you don't know anything
377 about the Patients, and so on)
378
379 A class gdcm::SerieHelper is designed to help solving this problem.
380 Use it as follows.
381
382     gdcm::SerieHelper *sh = gdcm::SerieHelper::New();
383     while (int i=0; i < nbOfFiles; i++) {
384        sh->AddFileName(currentFileName[i]);
385     }
386     
387 You can also pass a 'root directory', and ask or not for recursive parsing.
388     gdcm::SerieHelper *sh = gdcm::SerieHelper::New();
389     sh->SetDirectory(yourRootDirectoryName, true); // true : recursive parsing
390
391 Files are 'splitted' into as many 'Single Serie UID File Set' 
392   as Series Instance UID ( 0020|000e );
393
394 // -------- skip this one, for a first reading ! -----------
395
396 Sometimes, the Serie UID is not enough to disseminate properly the images.
397 We may want to disseminate into multiple sub series when needed.
398
399 Use :
400 void SerieHelper::SetUseSeriesDetails(bool s);
401    /// This function will add the following DICOM tag as being part of a
402    /// 'fake' uid. :
403    /// 0020 0011 Series Number
404    /// 0018 0024 Sequence Name
405    /// 0018 0050 Slice Thickness
406    /// 0028 0010 Rows
407    /// 0028 0011 Columns 
408
409 If it's not enough for you, use :    
410 void SerieHelper::AddSeriesDetail(uint16_t group, uint16_t elem, bool convert);
411
412 std::string SerieHelper::CreateUniqueSeriesIdentifier(gdcm::File *inFile);
413 void SerieHelper::CreateDefaultUniqueSeriesIdentifier();
414
415 You may also create a "tokenizable' File Identifier of your own, using :
416 void SerieHelper::AddSeriesDetail(uint16_t group, uint16_t elem, bool convert);
417 and
418 std::string SerieHelper::CreateUserDefinedFileIdentifier(gdcm::File *inFile);
419 and use it as you feel like.
420
421 // ------------ Resume reading, here !--------------------
422  
423 If you want to 'order' the files within each 'Single Serie UID File Set'
424 (to build a volume, for instance), use :
425   
426    gdcm::FileList *l = sh->GetFirstSingleSerieUIDFileSet();
427    while (l)
428    { 
429       sh->OrderFileList(l);  // sort the list
430       l = sh->GetNextSingleSerieUIDFileSet();
431    } 
432     
433   The sorting will be performed on the ImagePositionPatient;
434   if not found, on ImageNumber;
435   if not found, on the File Name.
436   
437   Aware user is allowed to pass his own comparison function 
438   (if he knows, for instance, the files must be sorted on 'Trigger Time')
439   He will use the method
440   void SerieHelper::SetUserLessThanFunction( bool(*) userFunc((File *,File *) ); 
441   He may ask for a reverse sorting : 
442   sh->SetSortOrderToReverse();
443   or back to Direct Order 
444   sh->SetSortOrderToDirect();
445   
446   If, for any reason of his own, user already get the file headers,
447   he may add the gdcm::File (instead of the file name) to the SerieHelper.
448
449     gdcm::SerieHelper *sh = gdcm::SerieHelper::New();
450     while (int i=0; i < nbOfFiles; i++) {
451        sh->AddFile(currentFile[i]);
452     }                           
453  * \warning : this method should be used by aware users only!
454  *            User is supposed to know the files he want to deal with
455  *           and consider them they belong to the same Set
456  *           (even if their Serie UID is different)
457  *           user will probabely OrderFileList() this list (actually, ordering
458  *           user choosen gdm::File is the sole interest of this method)
459  *           Moreover, using vtkGdcmReader::SetCoherentFileList() will avoid
460  *           vtkGdcmReader parsing twice the same files.
461  *           *no* coherence check is performed, but those specified
462  *           by SerieHelper::AddRestriction()
463  
464    User may want to exclude some files.
465    He will use
466     void SerieHelper::AddRestriction(uint16_t group, uint16_t elem,
467                                  std::string const &value, int op);
468 op belongs to :
469
470 /// \brief comparison operators
471    GDCM_EQUAL ,
472    GDCM_DIFFERENT,
473    GDCM_GREATER,
474    GDCM_GREATEROREQUAL,
475    GDCM_LESS,
476    GDCM_LESSOREQUAL
477 e.g. 
478     gdcm::SerieHelper *sh = gdcm::SerieHelper::New();
479     sh->AddRestriction(0x0010,0x0040,"F",GDCM_EQUAL);      // Patient's Sex
480     sh->AddRestriction(0x0008,0x0060,"MR",GDCM_DIFFERENT); // Modality 
481     while (int i=0; i < nbOfFiles; i++) { 
482     ...
483 User wants to deal only with Female patient, any Modality but MR (why not?)
484    
485 Maybe user knows there are several images with the same position
486 and *no dicom field* may discriminates them.
487 He wants to drop the 'duplicate images'
488    
489      sh->SetDropDuplicatePositions(true);
490
491 Sometimes the previous stuff is *not enough* !
492
493 Within a SingleSerieUIDFileSet, you can have have various orientations,
494 or various positions, at various times. (not only various position , at a single
495 time, for a single orientation).
496
497 User may consider that dealing only with the 'Series Instance UID' 
498 is not enough and wishes to 'refine' the image selection :
499
500 Suppose he has a Single Serie UID File Set (gdcm::FileList).
501 He may ask to split it into several 'X Coherent File Sets' (X stands for
502 'Extra').
503
504 gdcm::SerieHelper *s;
505 gdcm::XCoherentFileSetmap xcm;
506 gdcm::FileList *l = s->GetFirstSingleSerieUIDFileSet(); // or what you want
507
508
509  The following methods must be called by user, depending on 
510  what *he* wants to do, at application time.
511   - *he* only  knows what his Series contain ! - 
512  They return a std::map of Filesets (actually : a std::map of std::vector<gdcm::File* >).
513  
514 He may ask for 'splitting' on the Orientation:
515            gdcm::XCoherentFileSetmap xcm = s->SplitOnOrientation(l);
516    
517 He may ask for 'splitting' on the Position:
518            gdcm::XCoherentFileSetmap xcm = s->SplitOnPosition(l);
519    
520 He may ask for 'splitting' on the any DataElement you feel like :   
521            gdcm::XCoherentFileSetmap xcm = s->SplitOnTagValue(l, group,elem);
522
523  
524 He can now work on each 'X Coherent File Set' within the std::map
525
526 for (gdcm::XCoherentFileSetmap::iterator i = xcm.begin();
527                                          i != xcm.end();
528                                        ++i)
529 {
530
531    // ask for 'ordering' according to the 'Image Position Patient'
532    // Sorting the Fileset (*) is mandatory!
533    // ( computing an accurate Series ZSpacing -whenever possible- is a side effect ...)
534      
535    s->OrderFileList((*i).second);  // sort the XCoherent Fileset
536 }  
537
538 (have a look at gdcm/Examples/exXCoherentFileSet.cxx for an example)
539
540 1-2) using VTK
541 --------------
542 a vtkGdcmReader() method ( derived from vtkReader() ) is available.
543
544 1-2-1) A single file
545 --------------------
546
547    vtkGdcmReader *reader = vtkGdcmReader::New();
548    reader->SetFileName( yourDicomFilename );      
549    reader->SetLoadMode( yourLoadMode);   // See C++ part 
550    reader->SetKeepOverlays( true/false); // See C++ part    
551    reader->Update();
552    vtkImageData* ima = reader->GetOutput();
553    int* Size = ima->GetDimensions(); 
554      
555  // -> Enjoy it.     
556
557 1-2-2) A File Set
558 -----------------
559
560 If you are 150 % sure of the files you're dealing with, just 'add' the files you
561 feel like:
562
563    vtkGdcmReader *reader = vtkGdcmReader::New();
564    for(int i=1; i< yourNumberOfFiles; i++)
565          reader->AddFileName( yourTableOfFileNames[i] );     
566    reader->SetLoadMode( yourLoadMode);   // See C++ part 
567    reader->SetKeepOverlays( true/false); // See C++ part     
568    reader->Update();
569    vtkImageData* ima = reader->GetOutput();
570    int* Size = ima->GetDimensions();
571    
572  // -> Enjoy it.
573  
574  Warning : The first file is assumed to be the reference file.
575  All the inconsistent files (different sizes, pixel types, etc) are discarted
576  and replaced by a black image ! 
577  
578       User is allowed to pass a Pointer to a function of his own
579       to allow modification of pixel order (i.e. : Mirror, UpsideDown, )
580       to gdcm::FileHeleper, using SetUserFunction(userSuppliedFunction)
581
582       described as : void userSuppliedFunction(uint8_t *im, gdcm::File *f);
583
584       NB : the "uint8_t *" type of first param is just for prototyping.
585         User will Cast it according what he found with f->GetPixelType()
586         See vtkgdcmSerieViewer for an example
587  
588
589 Many users expect from vtkGdcmReader it 'orders' the images 
590 (Actually, that's the job of gdcm::SerieHelper ...)
591 When user knows the files with same Serie UID have same sizes, 
592 same 'pixel' type, same color convention, ... 
593 the right way to proceed is as follow :
594
595         gdcm::SerieHelper *sh= new gdcm::SerieHelper();
596    //      if user wants *not* to load some parts of the file headers
597         sh->SetLoadMode(yourLoadMode);
598
599    //      if user wants *not* to load some files
600         sh->AddRestriction(group, element, value, operator);
601         sh->AddRestriction( ...
602         sh->SetDirectory(directoryWithImages);
603
604    //      if user *knows* how to order his files
605         sh->SetUserLessThanFunction(userSuppliedComparisonFunction);
606    //      or/and
607    //      if user wants to sort reverse order
608         sh->SetSortOrderToReverse();
609    
610    //      here, we suppose only the first 'Single SerieUID' Fileset is of interest
611    //      Just iterate using sh->NextSingleSerieUIDFileSet()
612    //      if you want to get all of them
613         gdcm::FileList *l = sh->GetFirstSingleSerieUIDFileSet();
614
615    //      if user is doesn't trust too much the files with same Serie UID
616         if ( !sh->IsCoherent(l) )
617            return; // not same sizes, or not same 'pixel type' -> stop
618    
619    // Maybe user knows there are several images with the same position
620    // and *no dicom field* may discriminates them.
621    // He wants to drop the 'duplicate images'
622    
623         sh->SetDropDuplicatePositions(true); 
624
625    // Sorting the Fileset (*) is mandatory!
626    // ( computing an accurate Series ZSpacing is a side effect ...)  
627         sh->OrderFileList(l);
628
629         vtkGdcmReader *reader = vtkGdcmReader::New();
630    //      if user wants to modify pixel order (Mirror, TopDown, ...)
631    //      he has to supply the function that does the job
632    //      (a *very* simple example is given in vtkgdcmSerieViewer.cxx)
633         reader->SetUserFunction (userSuppliedFunction);
634
635    //      to pass a 'Single SerieUID' Fileset as produced by gdcm::SerieHelper
636         reader->SetCoherentFileList(l);
637         reader->Update();
638
639
640 //-----------------
641 (*)
642 User may also pass an 'X Coherent Fileset', created by one of the following
643 methods : (see 1-1-2 for more details)
644  
645            xcm = sh->SplitOnOrientation(l); 
646            xcm = sh->SplitOnPosition(l);   
647            xcm = sh->SplitOnTagValue(l, groupelem[0],groupelem[1]);
648 //----------------
649
650
651 You can see a full example in vtk/vtkgdcmSerieViewer2.cxx
652 e.g.
653 vtkgdcmSerieViewer dirname=Dentist mirror
654 vtkgdcmSerieViewer dirname=Dentist reverse
655 vtkgdcmSerieViewer dirname=Dentist reverse upsidedown
656
657
658 1-4) Retrictions for Python users
659 ---------------------------------
660
661 None of the methods receiving a function pointer, or a gdcm::File as a parameter
662 is wrapable by swig.
663 :-(
664
665
666 2) How to write DICOM file
667 ==========================
668
669 2-1) using raw C++
670 ------------------
671
672 2-1-1) A single file
673 --------------------
674 In C++, if you have already the pixels in main memory, 
675 you just have to process as follow :
676
677 --> Create an empty gdcm::File
678         gdcm::File *file = gdcm::File::New();
679
680         std::ostringstream str;
681
682 // --> Set the mandatory fields
683   // Set the image size
684         str.str("");
685         str << sizeY;
686         file->InsertEntryString(str.str(),0x0028,0x0010,"US"); // Rows
687         str.str("");
688         str << sizeX;
689         file->InsertEntryString(str.str(),0x0028,0x0011,"US"); // Columns
690         str.str("");
691         str << sizeZ;
692         file->InsertEntryString(str.str(),0x0028,0x0008, "IS"); // Nbr of Frames
693   // Set the pixel type
694         str.str("");
695         str << componentSize; //8, 16, 32
696         file->InsertEntryString(str.str(),0x0028,0x0100,"US"); // Bits Allocated
697         str.str("");
698         str << componentUse; // may be 12 or 16 if componentSize =16
699         file->InsertEntryString(str.str(),0x0028,0x0101,"US"); // Bits Stored
700         str.str("");
701         str << componentSize - 1 ;
702         file->InsertEntryString(str.str(),0x0028,0x0102,"US"); // High Bit
703   // Set the pixel representation // 0/1
704         str.str("");
705         str << img.sign;
706         file->InsertEntryString(str.str(),0x0028,0x0103, "US"); // Pixel Representation
707   // Set the samples per pixel // 1:Grey level, 3:RGB
708         str.str("");
709         str << components;
710         file->InsertEntryString(str.str(),0x0028,0x0002, "US"); // Samples per Pixel
711
712 //--> Set Optional fields
713       see further how to deal with optional fields
714
715 //--> Create a gdcm::FileHelper
716        gdcm::FileHelper *fileH = gdcm::FileHelper::New(file);
717
718 //--> Tell the FileHelper what you did for creating the image:
719
720       // gdcm cannot guess how user built his image 
721       //  (and therefore cannot be clever about some Dicom fields)
722       // It's up to the user to tell gdcm what he did.
723       // -1) user created ex nihilo his own image and wants to write it 
724       //     as a Dicom image.
725       // USER_OWN_IMAGE
726       // -2) user modified the pixels of an existing image.
727       // FILTERED_IMAGE
728       // -3) user created a new image, using existing a set of images 
729       //    (eg MIP, MPR, cartography image)
730       //  CREATED_IMAGE
731       // -4) user modified/added some tags *without processing* the pixels 
732       //     (anonymization, ...)
733       //  UNMODIFIED_PIXELS_IMAGE
734       // -Probabely some more to be added
735       //(see gdcmFileHelper.h for more explanations)
736
737       // Use :
738       
739       fileH->SetContentType(GDCM_NAME_SPACE::USER_OWN_IMAGE);
740       fileH->SetContentType(GDCM_NAME_SPACE::FILTERED_IMAGE);
741       fileH->SetContentType(GDCM_NAME_SPACE::CREATED_IMAGE);
742       fileH->SetContentType(GDCM_NAME_SPACE::UNMODIFIED_PIXELS_IMAGE);
743       
744       // depending on what you did before!
745
746 //--> Set the compression type : 
747       fileH->SetWriteTypeToJPEG();      // lossless compression        
748       fileH->SetWriteTypeToJPEG2000();  // lossless compression 
749       fileH->SetWriteTypeToDcmExplVR(); // Explicit Value Representation (no compression)
750       fileH->SetWriteTypeToDcmImplVR(); // Implicit Value Representation (no compression)
751       
752       fileH->SetWriteModeToRaw();       // Probabely you don't want to convert any LUT into RGB pixels ...
753
754 //--> Set the Image Data
755        fileH->SetImageData((unsigned char *)imageData,size);
756       // ( Casting as 'unsigned char *' is just to avoid warnings.
757       // It doesn't change the values. )
758       // or
759        fileH->SetUserData((unsigned char *)imageData,size); // performs compression, when required
760       // ( Casting as 'unsigned char *' is just to avoid warnings.
761       // It doesn't change the values. )
762                   
763 //-> Write !      
764       fileH->Write(fileName.str());
765
766 //This works for a single image (singleframe or multiframe)
767
768 2-1-1-1) Deal with optional DataElements          // TODO : finish it
769
770     Any Data Element may be added (it's up to the user to understand what he is doing!)
771     The supplied methods 'InsertXxx' will create the DataElement or replace it if it already exists.  
772     Have a look at gdcm/Dict/dicomV3.dic to see what are the various DICOM fields, with their VR.
773     
774 2-1-1-1-1) Add a single Dicom DataElement          // TODO : finish it
775
776    use :
777    DataEntry * File::InsertEntryString(std::string const &value,
778                                    uint16_t group, uint16_t elem,
779                                    VRKey const &vr = GDCM_VRUNKNOWN);
780   
781    // (e.g. : patient name, patient ID, ... , or what you want,
782    //  using their Dicom identifier, and 'VR'
783       file->InsertEntryString("MyOwnPatient" ,0x0010,0x0010,"PN"); // 0010 0010 : Patient's Name
784    
785     DataEntry * File:InsertEntryBinArea(uint8_t *binArea, int lgth,
786                                     uint16_t group, uint16_t elem,
787                                     VRKey const &vr = GDCM_VRUNKNOWN);  
788    
789 2-1-1-1-2) Add a Dicom Sequence           // TODO : finish it
790    SeqEntry * File::InsertSeqEntry(uint16_t group, uint16_t elem);
791    
792 2-1-2) A File Set
793 -----------------
794 /// \todo : write it!
795
796
797 // If you deal with a Serie of images, it up to you to tell gdcm, for each image,
798 // what are the values of
799 // 0020 0032 DS 3 Image Position (Patient)
800 // 0020 0037 DS 6 Image Orientation (Patient)
801
802 // You will probabely want that all the images of your file set belong to the same 'Serie'
803
804
805 2-2) using VTK
806 --------------
807
808 /// \todo : write it!
809
810 2-2-1) A single file
811 --------------------
812
813 /// \todo : finish it!
814
815 // User of the CVS version of VTK 5 may set some 'Medical Image Properties'
816 // Only the predefined DataElements are available :
817 // PatientName, PatientID, PatientAge, PatientSex, PatientBirthDate, StudyID
818 // It's reasonably enough for any 'decent use'
819 //
820 // todo : explain how to use it.
821 //vtkMedicalImageProperties
822
823    // Aware user is allowed to pass his own gdcm::File *, 
824    //  so he may set *any Dicom field* he wants.
825    // (including his own Shadow Elements, or any gdcm::SeqEntry)
826    // gdcm::FileHelper::CheckMandatoryElements() will check inconsistencies,
827    // as far as it knows how.
828    // Sorry, not yet available under Python.
829    
830      vtkSetMacro(GdcmFile, gdcm::File *);
831    
832 void vtkGdcmWriter::SetGdcmFile(gdcm::File *);
833
834    // gdcm cannot guess how user built his image 
835    //  (and therefore cannot be clever about some Dicom fields)
836    // It's up to the user to tell gdcm what he did.
837    // -1) user created ex nihilo his own image and wants to write it 
838    //     as a Dicom image.
839    // USER_OWN_IMAGE
840    // -2) user modified the pixels of an existing image.
841    // FILTERED_IMAGE
842    // -3) user created a new image, using existing a set of images 
843    //    (eg MIP, MPR, cartography image)
844    //  CREATED_IMAGE
845    // -4) user modified/added some tags *without processing* the pixels 
846    //     (anonymization..
847    //  UNMODIFIED_PIXELS_IMAGE
848    // -Probabely some more to be added
849    //(see gdcmFileHelper.h for more explanations)
850    
851    // User is allowed to use the following methods:
852    
853 void vtkGdcmWriter::SetContentTypeToUserOwnImage()                           
854 void vtkGdcmWriter::SetContentTypeToFilteredImage()                            
855 void vtkGdcmWriter::SetContentTypeToUserCreatedImage()                        
856 vtkGdcmWriter::void SetContentTypeToUnmodifiedPixelsImage()
857    
858   // depending on what he did before (see C++ part)
859   
860                       
861
862 2-2-2) A File Set
863 -----------------
864 /// \todo : write it!
865
866
867 2-3) using ITK
868 --------------
869 /// \todo : write it!
870
871 2-4) Retrictions for Python users
872 ---------------------------------
873 /// \todo : write it!
874
875 3) Some 'Command line' utilities  /// \todo: finish it!
876 ================================
877
878 3-) PrintFile
879 3-) exSerieHelper
880 3-) exXCoherentFileSet
881
882 3-) AnonymizeNoLoad
883 3-) AnonymizeMultiPatient
884 3-) AnonymizeDicomDir
885
886 3-) ReWrite
887 3-) RawToDicom
888 3-) exMoveImagesToSingleSerieUID
889
890 3-) vtkgdcmViewer2
891 3-) vtkgdcmSerieViewer2
892
893 3-) PrintDicomDir
894 3-) MakeDicomDir
895 }}}
896 </pre>