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