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