]> Creatis software - gdcm.git/blob - Example/ToInTag.cxx
1b4f292df6bf354f84f12b8b05b76001fddf2703
[gdcm.git] / Example / ToInTag.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: ToInTag.cxx,v $
5   Language:  C++
6   Date:      $Date: 2007/10/24 08:03:10 $
7   Version:   $Revision: 1.20 $
8                                                                                 
9   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10   l'Image). All rights reserved. See Doc/License.txt or
11   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
12                                                                                 
13      This software is distributed WITHOUT ANY WARRANTY; without even
14      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15      PURPOSE.  See the above copyright notices for more information.
16                                                                                 
17 =========================================================================*/
18 #include "gdcmDocEntry.h"
19 #include "gdcmDicomDir.h"
20 #include "gdcmDicomDirPatient.h"
21 #include "gdcmFile.h"
22 #include "gdcmFileHelper.h"
23 #include "gdcmDirList.h"
24 #include "gdcmDebug.h"
25 #include "gdcmArgMgr.h"
26 #include "gdcmUtil.h"
27 #include "gdcmSerieHelper.h"
28
29 #include <iostream>
30
31 /**
32   * \brief   
33   *          - explores recursively the given directory
34   *          - keeps the requested series
35   *          - orders the gdcm-readable found Files
36   *            according to their Patient/Study/Serie/Image characteristics
37   *          - fills a single level Directory with *all* the files,
38   *            converted into a Brucker-like Dicom, Intags compliant
39   */  
40
41 typedef std::map<std::string, GDCM_NAME_SPACE::File*> SortedFiles;
42
43 int main(int argc, char *argv[]) 
44 {
45    START_USAGE(usage)
46    " \n ToInTag :\n                                                           ",
47    " - explores recursively the given directory,                              ",
48    " - keeps the requested series/ drops the unrequested series               ",
49    " - orders the gdcm-readable found Files according to their                ",
50    "           (0x0010, 0x0010) Patient's Name                                ",
51    "           (0x0020, 0x000e) Series Instance UID                           ",
52    "           (0x0020, 0x0032) Image Position (Patient)                      ",
53    "           (0x0018, 0x1060) Trigger Time                                  ",
54    "           (0x0018, 0x1312) In-plane Phase Encoding Direction             ",
55    " - fills a single level (*) Directory with *all* the files,               ",
56    "           converted into a Brucker-like Dicom, InTags compliant          ",
57    "   (*) actually : creates as many directories as Patients                 ",
58    "                  -that shouldn't appear, but being carefull is better!-  ",
59    " or                                                                       ",
60    " - fills a tree-like structure of directories as :                        ",
61    "        - Patient                                                         ",
62    "        -- Serie                                                          ",
63    "        --- Position                                                      ",
64    "        ---- Images (sorted by Trigger Time /                             ",
65    "                               Encoding Direction (Row, Column)           ",
66    "                                                                          ",
67    "      Note : when (0008|1090) [Model Name ] equals 'TrioTim ' :           ",
68    "         - (0008|103e)[Series Description ] is checked for                ",
69    "            '90' (-> COL) or '0' (-> ROW)                                 ",
70    "         - (0x0020, 0x000e) [Series Instance UID] is NOT dealt with,      ",
71    "           since row an col tagging are in 2 different Series             ",
72    "           DO NOT supply a directory holding different exams              ",
73    "           for the same Slice level!                                      ",
74    "      uses :                                                              ",
75    "           0x0021, 0x1020 : 'SLICE INDEX'                                 ",
76    "           0x0021, 0x1040 : 'FRAME INDEX'                                 ",
77    "           0x0020, 0x0012 : 'SESSION INDEX'  (Acquisition Number)         ",
78    "                                                                          ",
79    " usage:                                                                   ",
80    " -----                                                                    ",
81    " ToInTag          dirin=rootDirectoryName                                 ",
82    "                  dirout=outputDirectoryName                              ",
83    "                  {  [keep= list of seriesNumber to process]              ",
84    "                   | [drop= list of seriesNumber to ignore] }             ",
85    "                  [taggrid] [skel]                                        ",
86    "                  [input = {ACR|DCM|IDO}]                                 ", 
87    "                  [extent=image suffix (.IMA, .NEMA, .DCM, ...)]          ",
88    "                  [listonly] [split] [rubout]                             ",
89    "                  [noshadowseq][noshadow][noseq] [verbose] [debug]        ",
90    "                                                                          ",
91    " dirout : will be created if doesn't exist                                ",
92    " keep : if user wants to process a limited number of series               ",
93    "            he gives the list of 'SeriesNumber' (tag 0020|0011)           ",
94    " drop : if user wants to ignore a limited number of series                ",
95    "            he gives the list of 'SeriesNumber' (tag 0020|0011)           ",   
96    "        SeriesNumber are short enough to be human readable                ",
97    "        e.g : 1030,1035,1043                                              ", 
98    " taggrid : user knows all the images are 'grid' -ie: not 'col', not 'raw'-",
99    " extent : DO NOT forget the leading '.' !                                 ",
100    " input : IDO when *realy* old libIDO images                               ",
101    " skel: name skeleton eg : patName_1.nema -> skel=patName_                 ",
102    " split: creates a tree-like structure of directories as :                 ",
103    "        - Patient                                                         ",
104    "        -- Serie                                                          ",
105    "        --- Position                                                      ",
106    "        ---- Images (sorted by Trigger Time /                             ",
107    "                               Encoding Direction (Row, Column)           ",
108    " rubout : user asks to rubout burnt-in image number                       ",
109    " noshadowseq: user doesn't want to load Private Sequences                 ",
110    " noshadow : user doesn't want to load Private groups (odd number)         ",
111    " noseq    : user doesn't want to load Sequences                           ",
112    " verbose  : user wants to run the program in 'verbose mode'               ",
113    " debug    : *developer*  wants to run the program in 'debug mode'         ",
114    FINISH_USAGE
115
116
117    enum Index
118    { 
119       IND_PatientName,
120       IND_SerieInstanceUID,
121       IND_ImagePosition,
122       IND_TriggerTime,
123       IND_PhaseEncodingDirection,
124       IND_seriesDescription,
125       IND_FileName       
126    };
127    
128    std::cout << "inside ToInTag" << std::endl;
129    
130    // ----- Initialize Arguments Manager ------
131       
132    GDCM_NAME_SPACE::ArgMgr *am = new GDCM_NAME_SPACE::ArgMgr(argc, argv);
133   
134    if (argc == 1 || am->ArgMgrDefined("usage")) 
135    {
136       am->ArgMgrUsage(usage); // Display 'usage'
137       delete am;
138       return 0;
139    }
140
141    const char *dirNamein;   
142    dirNamein  = am->ArgMgrGetString("dirin","."); 
143
144    const char *dirNameout;   
145    dirNameout  = am->ArgMgrGetString("dirout",".");  
146    
147    int loadMode = GDCM_NAME_SPACE::LD_ALL;
148    if ( am->ArgMgrDefined("noshadowseq") )
149       loadMode |= GDCM_NAME_SPACE::LD_NOSHADOWSEQ;
150    else 
151    {
152    if ( am->ArgMgrDefined("noshadow") )
153          loadMode |= GDCM_NAME_SPACE::LD_NOSHADOW;
154       if ( am->ArgMgrDefined("noseq") )
155          loadMode |= GDCM_NAME_SPACE::LD_NOSEQ;
156    }
157
158    if (am->ArgMgrDefined("debug"))
159       GDCM_NAME_SPACE::Debug::DebugOn();
160       
161    int verbose  = am->ArgMgrDefined("verbose");
162    int split    = am->ArgMgrDefined("split");
163    int listonly = am->ArgMgrDefined("listonly");
164    
165    bool rubout = ( 0 != am->ArgMgrDefined("rubout") ); 
166            
167    int nbSeriesToKeep;
168    int *seriesToKeep = am->ArgMgrGetListOfInt("keep", &nbSeriesToKeep);
169    int nbSeriesToDrop;
170    int *seriesToDrop = am->ArgMgrGetListOfInt("drop", &nbSeriesToDrop);
171  
172    if ( nbSeriesToKeep!=0 && nbSeriesToDrop!=0)
173    {
174       std::cout << "KEEP and DROP are mutually exclusive !" << std::endl;
175       delete am;
176       return 0;         
177    }
178    
179    bool taggrid = ( 0 != am->ArgMgrDefined("taggrid") );
180       
181    bool hasSkel = ( 0 != am->ArgMgrDefined("hasSkel") );    
182    const char *skel;
183    if (hasSkel)
184       skel = am->ArgMgrGetString("skel");
185       
186    const char *extent  = am->ArgMgrGetString("extent",".DCM");
187    const char *input   = am->ArgMgrGetString("input","DCM");
188    
189    // if unused Param we give up
190    if ( am->ArgMgrPrintUnusedLabels() )
191    { 
192       am->ArgMgrUsage(usage);
193       delete am;
194       return 0;
195    }
196    delete am;  // we don't need Argument Manager any longer
197
198    // ----- Begin Processing -----
199    
200    if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(dirNamein) )
201    {
202       std::cout << "KO : [" << dirNamein << "] is not a Directory." << std::endl;
203       return 0;
204
205    }
206    else
207    {
208       std::cout << "OK : [" << dirNamein << "] is a Directory." << std::endl;
209    }
210
211    std::string systemCommand;
212    
213    std::cout << "Check for output directory :[" << dirNameout << "]."
214              <<std::endl;
215    if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(dirNameout) )    // dirout not found
216    {
217       std::string strDirNameout(dirNameout);          // to please gcc 4
218       systemCommand = "mkdir " +strDirNameout;        // create it!
219       if (verbose)
220          std::cout << systemCommand << std::endl;
221       system (systemCommand.c_str());
222       if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(dirNameout) ) // be sure it worked
223       {
224           std::cout << "KO : not a dir : [" << dirNameout << "] (creation failure ?)" << std::endl;
225       return 0;
226
227       }
228       else
229       {
230         std::cout << "Directory [" << dirNameout << "] created." << std::endl;
231       }
232    }
233    else
234    {
235        std::cout << "Output Directory [" << dirNameout << "] already exists; Used as is." << std::endl;
236    }
237     
238    std::string strDirNamein(dirNamein);
239    GDCM_NAME_SPACE::DirList dirList(strDirNamein, true); // get recursively the list of files
240    
241    if (listonly)
242    {
243       std::cout << "------------List of found files ------------" << std::endl;
244       dirList.Print();
245       std::cout << std::endl;
246    }
247    
248    GDCM_NAME_SPACE::DirListType fileNames;
249    fileNames = dirList.GetFilenames();
250    GDCM_NAME_SPACE::SerieHelper *s;              // Needed to use SerieHelper::AddSeriesDetail()
251    s = GDCM_NAME_SPACE::SerieHelper::New();
252
253    std::string token = "%%%"; // Hope it's enough!
254 /*       
255    std::cout << "---------------Print Serie--------------" << std::endl; 
256    s->SetDirectory(dirNamein, true); // true : recursive exploration 
257    s->SetUseSeriesDetails(true);  
258    s->AddSeriesDetail(0x0018, 0x1312);   
259    s->Print();
260 */
261   
262    GDCM_NAME_SPACE::File *f;
263    GDCM_NAME_SPACE::FileHelper *fh;
264    std::vector<std::string> tokens;
265    std::vector<std::string> tokensForFileName;
266    
267    // For Siemens pb, we need Manufacturer's Model Name
268    // (We read only the first file, to know)   
269    GDCM_NAME_SPACE::DirListType::iterator it1 = fileNames.begin();
270    f = GDCM_NAME_SPACE::File::New();
271    f->SetLoadMode(GDCM_NAME_SPACE::LD_ALL);
272    f->SetFileName( *it1 );
273    f->Load();
274    std::string modelName = f->GetEntryString(0x0008,0x1090);
275    f->Delete();   
276    
277 /*   
278    std::cout << "---------------Print Unique Series identifiers---------"  
279              << std::endl;     
280    std::string uniqueSeriesIdentifier;
281  
282    for (GDCM_NAME_SPACE::DirListType::iterator it) = fileNames.begin();  
283                                     it != fileNames.end();
284                                   ++it)
285    {
286       std::cout << "File Name : " << *it << std::endl;
287       f = GDCM_NAME_SPACE::File::New();
288       f->SetLoadMode(GDCM_NAME_SPACE::LD_ALL);
289       f->SetFileName( *it );
290       f->Load();
291         
292       uniqueSeriesIdentifier=s->CreateUniqueSeriesIdentifier(f);
293       std::cout << "                           [" <<
294                uniqueSeriesIdentifier  << "]" << std::endl;       
295       f->Delete();
296    }
297 */
298    
299    if (verbose)
300       std::cout << "------------------Print Break levels-----------------" << std::endl;
301
302    std::string userFileIdentifier;
303    SortedFiles sf;
304
305    s->AddSeriesDetail(0x0010, 0x0010, false); // Patient's Name
306    // for Siemens TrioTim, don't deal with 'Series Instance UID'
307    if ( !GDCM_NAME_SPACE::Util::DicomStringEqual(modelName,"TrioTim") )
308       s->AddSeriesDetail(0x0020, 0x000e, false); // Series Instance UID
309    else
310       s->AddSeriesDetail(0x9999, 0x9999, false); // dirty trick to ignore 'Series Instance UID'
311    s->AddSeriesDetail(0x0020, 0x0032, false); // Image Position (Patient)
312    s->AddSeriesDetail(0x0018, 0x1060, true);  // Trigger Time (true: convert to keep numerical order)
313    s->AddSeriesDetail(0x0018, 0x1312, false); // In-plane Phase Encoding Direction
314    s->AddSeriesDetail(0x0008, 0x103e, false); // Series Description (special Siemens ...)
315
316    //uint8_t *imageData; // Useless : pixels will not be loaded 
317                          //          (images are overwritten)
318          
319    for (GDCM_NAME_SPACE::DirListType::iterator it = fileNames.begin();  
320                                     it != fileNames.end();
321                                   ++it)
322    {
323       f = GDCM_NAME_SPACE::File::New();
324       f->SetLoadMode(loadMode);
325       f->SetFileName( *it );
326       f->Load();
327
328       std::string strSeriesNumber;
329       int seriesNumber;
330       int j;
331
332       // keep only requested Series      
333       bool keep = false;
334       if (nbSeriesToKeep != 0)
335       {
336          strSeriesNumber = f->GetEntryString(0x0020, 0x0011 );
337          seriesNumber = atoi( strSeriesNumber.c_str() );
338          for (j=0;j<nbSeriesToKeep; j++)
339          {
340             if(seriesNumber == seriesToKeep[j])
341             {
342                keep = true;
343                break;
344             }
345          }
346          if ( !keep)
347          {
348             f->Delete();
349             continue;
350          } 
351       }
352       // drop all unrequested Series
353       bool drop = false;
354       if (nbSeriesToDrop != 0)
355       {     
356          strSeriesNumber = f->GetEntryString(0x0020, 0x0011 );
357          seriesNumber = atoi( strSeriesNumber.c_str() );
358          for (j=0;j<nbSeriesToDrop; j++)
359          {
360             if(seriesNumber == seriesToDrop[j])
361             { 
362                drop = true;
363                break;
364             }
365         }
366         if (drop)
367         {
368            f->Delete();
369            continue;
370         }
371       }
372
373       userFileIdentifier=s->CreateUserDefinedFileIdentifier(f);
374       tokens.clear();
375       GDCM_NAME_SPACE::Util::Tokenize (userFileIdentifier, tokens, token);
376
377       int imageNum; // Within FileName
378       char newName[1024];
379
380       // sometimes Trigger Time is not found.
381       // CreateUserDefinedFileIdentifier is not aware of the pb.
382       // We use File name instead (hope it's significant)
383
384       if ( tokens[IND_TriggerTime] == GDCM_NAME_SPACE::GDCM_UNFOUND)
385       {
386          ///this is a trick to build up a lexicographical compliant name :
387          ///     eg : fich001.ima vs fich100.ima as opposed to fich1.ima vs fich100.ima
388          std::string name = GDCM_NAME_SPACE::Util::GetName( *it );
389          if (hasSkel)
390          {
391             GDCM_NAME_SPACE::Util::Tokenize (name, tokensForFileName, skel);
392             imageNum = atoi ( tokensForFileName[0].c_str() );
393             // probabely we could write something much more complicated using C++ !
394             sprintf (newName, "%s%06d%s", skel, imageNum, extent);
395             tokens[IND_TriggerTime] = newName;
396             tokensForFileName.clear();    
397          }
398          else
399             tokens[IND_TriggerTime] = name;
400
401          // Patient's Name
402          // Series Instance UID
403          // Image Position (Patient)
404          // Trigger Time
405          // In-plane Phase Encoding Direction
406          // Series Description
407          // FileName
408  
409          userFileIdentifier = tokens[IND_PatientName] + token + tokens[IND_SerieInstanceUID] + token + tokens[IND_ImagePosition] + token 
410                     + tokens[IND_TriggerTime] + token + tokens[IND_PhaseEncodingDirection] + token + tokens[IND_seriesDescription] + token
411                     + tokens[IND_FileName] + token;
412       }
413          
414       if (verbose) 
415          std::cout << "[" << userFileIdentifier  << "] : " << *it << std::endl;
416                
417       // storing in a map ensures automatic sorting !      
418       sf[userFileIdentifier] = f;
419    }
420    
421    if (verbose)
422       std::cout << "  " << std::endl;
423       
424    std::string fullFilename, lastFilename;
425    std::string previousPatientName, currentPatientName;
426    std::string previousSerieInstanceUID, currentSerieInstanceUID;
427    std::string previousImagePosition, currentImagePosition;
428    std::string previousPhaseEncodingDirection, currentPhaseEncodingDirection;
429    std::string previousTriggerTime, currentTriggerTime;
430    
431    std::string currentStudyUID;
432    std::string seriesDescription;  
433       
434    std::string writeDir, currentWriteDir;
435    std::string currentPatientWriteDir, currentSerieWriteDir, 
436                currentPositionWriteDir, currentPhaseEncodingDirectionWriteDir;
437
438    std::string fullWriteFilename;
439    std::string strExtent(extent); 
440            
441    writeDir = GDCM_NAME_SPACE::Util::NormalizePath(dirNameout);     
442    SortedFiles::iterator it2;
443  
444    previousPatientName            = "";
445    previousSerieInstanceUID       = "";   
446    previousImagePosition          = "";
447    previousPhaseEncodingDirection = "";
448    previousTriggerTime            = "";
449    
450    int sliceIndex = 0; // Is incremented *at the beginning* of processing
451    int frameIndex;
452    if (taggrid)
453        frameIndex = 0;
454    else
455        frameIndex = 1;
456       
457    int flag       = 0;
458        
459    GDCM_NAME_SPACE::File *currentFile;
460
461    std::string defaultStudyUID =  GDCM_NAME_SPACE::Util::CreateUniqueUID();
462    std::string defaultSerieUID;
463
464    for (it2 = sf.begin() ; it2 != sf.end(); ++it2)
465    {  
466       currentFile = it2->second;
467        
468       fullFilename =  currentFile->GetFileName();
469       lastFilename =  GDCM_NAME_SPACE::Util::GetName( fullFilename );
470       if (verbose) 
471       std::cout <<" ------------------------------------------------------------------------------" 
472                 << std::endl << " Deal with [" << it2->first << "] : ["<<fullFilename << "]" 
473                 << std::endl;
474      
475       tokens.clear();
476       GDCM_NAME_SPACE::Util::Tokenize (it2->first, tokens, token);
477    
478       currentPatientName            = tokens[IND_PatientName];
479       currentSerieInstanceUID       = tokens[IND_SerieInstanceUID];
480       currentImagePosition          = tokens[IND_ImagePosition];
481       currentTriggerTime            = tokens[IND_TriggerTime];
482       currentPhaseEncodingDirection = tokens[IND_PhaseEncodingDirection];
483       seriesDescription             = tokens[IND_seriesDescription];  // For Siemens pb
484
485       if ( currentImagePosition[0] == '-')
486           currentImagePosition[0] = 'M';
487       if ( currentImagePosition[0] == '+')
488           currentImagePosition[0] = 'P'; 
489
490       // Add a default ImagePositionPatient to avoid confusion at post processing time
491       if ( currentFile->GetEntryString(0x0020,0x0032) == GDCM_NAME_SPACE::GDCM_UNFOUND && 
492            currentFile->GetEntryString(0x0020,0x0030) == GDCM_NAME_SPACE::GDCM_UNFOUND )
493       {
494          currentFile->InsertEntryString("0.\\0.\\0.",0x0020, 0x0032, "DS" );
495       }
496
497       // Add a default ImagePositionPatient to avoid confusion at post processing time
498       if ( currentFile->GetEntryString(0x0020,0x0037) == GDCM_NAME_SPACE::GDCM_UNFOUND && 
499            currentFile->GetEntryString(0x0020,0x0035) == GDCM_NAME_SPACE::GDCM_UNFOUND )
500       {
501          currentFile->InsertEntryString("1.\\0.\\0.\\0.\\1.\\0.",0x0020, 0x0037, "DS" );
502       }
503
504       if (previousPatientName != currentPatientName)
505       {      
506          if ( currentFile->GetEntryString(0x0020,0x000d) == GDCM_NAME_SPACE::GDCM_UNFOUND) // Study UID
507          {
508             if (verbose)   
509                std::cout << "--- new  Study UID created" << std::endl;
510             defaultStudyUID =  GDCM_NAME_SPACE::Util::CreateUniqueUID();
511          }
512   
513          previousPatientName = currentPatientName;
514          if (verbose)   
515             std::cout << "==== new Patient  [" << currentPatientName  << "]" << std::endl;
516     
517          previousPatientName            = currentPatientName;
518          previousSerieInstanceUID       = ""; //currentSerieInstanceUID;
519          previousImagePosition          = ""; //currentImagePosition;
520          previousTriggerTime            = "";
521          previousPhaseEncodingDirection = ""; //currentPhaseEncodingDirection;
522   
523          currentPatientWriteDir = writeDir + currentPatientName;
524          //if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(currentPatientWriteDir) )
525            {
526               systemCommand   = "mkdir " + currentPatientWriteDir;
527               if (verbose)
528                  std::cout << systemCommand << std::endl;
529               system ( systemCommand.c_str() );
530          }
531       }
532       currentFile->InsertEntryString(defaultStudyUID, 0x0020, 0x000d, "UI" );
533       
534
535       if ( GDCM_NAME_SPACE::Util::DicomStringEqual(modelName,"TrioTim") ) // for Siemens TrioTim , don't deal with 'Series Instance UID'
536
537       if (previousSerieInstanceUID != currentSerieInstanceUID)
538       {        
539          if (verbose)
540             std::cout << "==== === new Serie [" << currentSerieInstanceUID << "]"
541                       << std::endl;
542       
543          if ( currentFile->GetEntryString(0x0020,0x000e) == GDCM_NAME_SPACE::GDCM_UNFOUND)
544          {
545             if (verbose)   
546                std::cout << "--- --- new  Serie UID created" << std::endl;
547             defaultSerieUID =  GDCM_NAME_SPACE::Util::CreateUniqueUID();
548            // currentFile->InsertEntryString(defaultSerieUID, 0x0020, 0x000e, "UI" );
549          }
550
551          if (split)
552          {
553              currentSerieWriteDir  = currentPatientWriteDir + GDCM_NAME_SPACE::GDCM_FILESEPARATOR
554                              + currentSerieInstanceUID;
555              systemCommand   = "mkdir " + currentSerieWriteDir;  
556              system (systemCommand.c_str());
557          }
558          previousSerieInstanceUID       = currentSerieInstanceUID;
559          previousImagePosition          = ""; //currentImagePosition;
560          previousPhaseEncodingDirection = ""; //currentPhaseEncodingDirection;
561       }
562       currentFile->InsertEntryString(defaultSerieUID, 0x0020, 0x000e, "UI" );
563             
564       // end of modelName != "TrioTim "
565    
566       if (previousImagePosition != currentImagePosition)
567       {
568          frameIndex = 1;
569          flag = 0;        
570          if (verbose)   
571             std::cout << "=== === === new Position [" << currentImagePosition  << "]"
572                       << std::endl;
573          if (split)
574          {
575              currentPositionWriteDir  = currentSerieWriteDir + GDCM_NAME_SPACE::GDCM_FILESEPARATOR
576                              + currentImagePosition;
577              systemCommand   = "mkdir " + currentPositionWriteDir;     
578              system (systemCommand.c_str()); 
579          }
580          previousImagePosition          = currentImagePosition;
581          previousPhaseEncodingDirection = ""; //currentPhaseEncodingDirection;
582          if (split)
583             sliceIndex = 1; // only *one* slice in a given directory
584          else
585             sliceIndex += 1;
586       }
587
588 // We don't split on Row/Column!
589 /*
590       if (previousPhaseEncodingDirection != currentPhaseEncodingDirection)
591       {        
592          if (verbose)
593             std::cout << "==== === === === new PhaseEncodingDirection [" 
594                       << currentPhaseEncodingDirection  << "]" << std::endl;
595       
596          if (split)
597          {
598              currentPhaseEncodingDirectionWriteDir  = currentPositionWriteDir 
599                              + GDCM_NAME_SPACE::GDCM_FILESEPARATOR
600                              + currentPhaseEncodingDirection;
601              systemCommand   = "mkdir " + currentPhaseEncodingDirectionWriteDir;     
602              system (systemCommand.c_str());
603          }
604
605          previousPhaseEncodingDirection = currentPhaseEncodingDirection;
606       }
607 */
608    
609       if ( GDCM_NAME_SPACE::Debug::GetDebugFlag())
610          std::cout << "--- --- --- --- --- " << it2->first << "  " 
611                    << (it2->second)->GetFileName() << " " 
612                    << GDCM_NAME_SPACE::Util::GetName( fullFilename ) << std::endl;           
613       
614       // Transform the image to be 'Brucker-Like'
615       // ----------------------------------------   
616     
617       // Deal with 0x0019, 0x1000 : 'FOV'
618       int nX = currentFile->GetXSize();
619       int nY = currentFile->GetYSize();
620       float pxSzX = currentFile->GetXSpacing();
621       float pxSzY = currentFile->GetYSpacing();
622       char fov[64];
623       sprintf(fov, "%f\\%f",nX*pxSzX, nY*pxSzY);
624       if (currentFile->IsVRCoherent(0x0019) == 1 )
625          currentFile->InsertEntryString(fov, 0x0019, 0x1000, "  ");
626       else     
627          currentFile->InsertEntryString(fov, 0x0019, 0x1000, "DS");
628
629      
630       // Deal with 0x0020, 0x0012 : 'SESSION INDEX'  (Acquisition Number)
631       std::string chSessionIndex;
632       // CLEANME
633
634       if (taggrid)
635       { 
636          chSessionIndex = "1";
637       }
638       else
639       {
640       /* for SIEMENS MRI :
641         D 0008|1090 [LO] [Manufacturer's Model Name ] [Triotim ]
642         we have to deal with :
643      
644         D 0008|103e [LO]  [Series Description ] [fl2d9_line PA 15 90deg] or anything that contains '90' !
645         D 0008|103e [LO]  [Series Description ] [fl2d9_line PA 15 0deg ]
646         (everything is flagged as 'ROW')
647       */  
648
649          if ( GDCM_NAME_SPACE::Util::DicomStringEqual(modelName,"TrioTim") )  
650          {
651             if (seriesDescription.find("90", 0) != std::string::npos)
652                chSessionIndex = "1";  // 90 deg -> COL
653             else if (seriesDescription.find("0", 0)!= std::string::npos)
654                chSessionIndex = "2";  // 0 deg -> ROW
655             else
656             {
657                std::cout << "====================== seriesDescription doesn't contain"
658                          << " neither '90' nor '0' (?!?) : ["
659                          << seriesDescription << "]" << std::endl;
660                chSessionIndex = "1";
661             }    
662          } 
663          else  // for all other 'normal' cases
664          {
665             if (currentPhaseEncodingDirection == "COL" || currentPhaseEncodingDirection == "COL " || currentPhaseEncodingDirection == " COL")
666                chSessionIndex = "1";
667             else if (currentPhaseEncodingDirection == "ROW" || currentPhaseEncodingDirection == "ROW "|| currentPhaseEncodingDirection == " ROW")
668                chSessionIndex = "2"; 
669             else
670             {
671                std::cout << "====================== PhaseEncodingDirection "
672                          << " neither COL nor ROW (?!?) : [ "
673                          << currentPhaseEncodingDirection << "]" << std::endl;
674                chSessionIndex = "1";
675             }
676          }
677       }
678       
679       if (currentFile->IsVRCoherent(0x0020) == 1 )     
680          currentFile->InsertEntryString(chSessionIndex, 0x0020, 0x0012, "  ");
681       else
682          currentFile->InsertEntryString(chSessionIndex, 0x0020, 0x0012, "IS");
683  
684       // Deal with  0x0021, 0x1020 : 'SLICE INDEX'
685       char chSliceIndex[5];
686       sprintf(chSliceIndex, "%04d", sliceIndex);
687       std::string strChSliceIndex(chSliceIndex);
688        
689       // Deal with  0x0021, 0x1040 : 'FRAME INDEX' 
690       char chFrameIndex[5];
691       sprintf(chFrameIndex, "%04d", frameIndex);
692
693       std::string stringVR;       
694       if (currentFile->IsVRCoherent(0x0021) == 1 )
695          stringVR = "  ";
696       else
697         stringVR = "IS";
698   
699       currentFile->InsertEntryString(strChSliceIndex, 0x0021, 0x1020, stringVR);
700       currentFile->InsertEntryString(chFrameIndex,    0x0021, 0x1040, stringVR);
701       
702       if (verbose) {     
703          std::cout << "0x0021, 0x1020 : strChSliceIndex " << strChSliceIndex << std::endl;
704          std::cout << "0x0021, 0x1040 : chFrameIndex  "   << chFrameIndex    << std::endl; 
705          std::cout << "0x0020, 0x0012 : chSessionIndex "  << chSessionIndex  << std::endl; 
706       }
707         
708       std::string strImagePositionPatient    = currentFile->GetEntryString(0x0020, 0x0032 );
709       if (strImagePositionPatient == GDCM_NAME_SPACE::GDCM_UNFOUND)
710       {
711          if (verbose)
712             std::cout << "Duplicate ImagePosition into ImagePositionPatient" << std::endl;
713          currentFile->InsertEntryString(currentFile->GetEntryString(0x0020, 0x0030), 0x0020, 0x0032, "DS" );
714       }  
715       
716       std::string strImageOrientationPatient = f->GetEntryString(0x0020, 0x0037 );
717       if (strImageOrientationPatient == GDCM_NAME_SPACE::GDCM_UNFOUND)
718       {
719          if (verbose)
720             std::cout << "Duplicate ImageOrientation into ImageOrientationPatient" << std::endl;          
721          currentFile->InsertEntryString(currentFile->GetEntryString(0x0020, 0x0035), 0x0020, 0x0037, "DS" );       
722       }
723        
724       if (taggrid  || strcmp(input, "IDO")==0 || strcmp(input, "ido")==0 )
725          frameIndex++;
726       else     
727       {     
728          if (flag == 0)
729          {       
730             flag = 1;
731          }
732          else
733          {
734             frameIndex++;
735             flag = 0;
736          }
737       } 
738                  
739       if (split)
740       
741          //fullWriteFilename = currentPhaseEncodingDirectionWriteDir + GDCM_NAME_SPACE::GDCM_FILESEPARATOR 
742          //                                + lastFilename + strExtent;      
743          fullWriteFilename = currentPositionWriteDir + GDCM_NAME_SPACE::GDCM_FILESEPARATOR 
744                                          + lastFilename + strExtent; 
745       else
746          fullWriteFilename = currentPatientWriteDir + GDCM_NAME_SPACE::GDCM_FILESEPARATOR 
747                                          + lastFilename + strExtent; 
748             
749       // Load the pixels in RAM.    
750       
751       fh = GDCM_NAME_SPACE::FileHelper::New(currentFile);     
752       uint8_t *imageData = fh->GetImageDataRaw(); // Don't convert (Gray Pixels + LUT) into (RGB pixels) ?!?
753       fh->SetWriteTypeToDcmExplVR();     
754       
755       if (rubout) {
756          // Put to Black the burnt-in number.
757          nX = currentFile->GetXSize();
758          nY = currentFile->GetYSize();
759          for(int y=nY-15; y<nY; y++)
760             for(int x=nX/3; x<nX/2+50; x++)
761               imageData[ y*nX*2 + x ] = 0;
762       }
763       
764       // We didn't make any computation on the pixels -> keep unchanged the following :
765       // 'Media Storage SOP Class UID' (0x0002,0x0002)
766       // 'SOP Class UID'               (0x0008,0x0016)
767       // 'Image Type'                  (0x0008,0x0008)
768       // 'Conversion Type'             (0x0008,0x0064)        
769       fh->SetContentType(GDCM_NAME_SPACE::UNMODIFIED_PIXELS_IMAGE);
770       
771       if (!fh->Write(fullWriteFilename))
772       {
773          std::cout << "Fail to write :[" << fullWriteFilename << "]"
774                    << std::endl;
775       } 
776       fh->Delete();                
777    }
778    return 0;
779  }
780