]> Creatis software - gdcm.git/blob - Example/MagnetomVisionToBrucker.cxx
Add MagnetomVisionToBrucker
[gdcm.git] / Example / MagnetomVisionToBrucker.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: MagnetomVisionToBrucker.cxx,v $
5   Language:  C++
6   Date:      $Date: 2006/01/25 11:08:17 $
7   Version:   $Revision: 1.1 $
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
42 typedef std::map<std::string, gdcm::File*> SortedFiles;
43
44 int main(int argc, char *argv[]) 
45 {
46    START_USAGE(usage)
47    " \n MagnetomVisionToBrucker :\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 (RET)                          ",
54    "           (0x0018, 0x1060) Trigger Time                                  ",
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 are (sorted by Trigger Time /                          ",
65    "                     Encoding Direction (Row, Column)                     ",
66    "      use :                                                               ",
67    "           0x0021, 0x1020 : 'SLICE INDEX'                                 ",
68    "           0x0021, 0x1040 : 'FRAME INDEX'                                 ",
69    "           0x0020, 0x0012 : 'SESSION INDEX'  (Acquisition Number)         ",
70    " usage:                                                                   ",
71    " PhilipsToBrucker dirin=rootDirectoryName                                 ",
72    "                  dirout=outputDirectoryName                              ",
73    "                  {  [keep= list of seriesNumber to process]              ",
74    "                   | [drop= list of seriesNumber to ignore] }             ",
75    "                  [input = {ACR|DCM}]                                     ", 
76    "                  [extent=image suffix (.IMA, .NEMA, .DCM, ...)]          ",
77    "                  [listonly] [split]                                      ",
78    "                  [noshadowseq][noshadow][noseq] [verbose] [debug]        ",
79    "                                                                          ",
80    " dirout : will be created if doesn't exist                                ",
81    " keep : if user wants to process a limited number of series               ",
82    "            he gives the list of 'SeriesNumber' (tag 0020|0011)           ",
83    " drop : if user wants to ignore a limited number of series                ",
84    "            he gives the list of 'SeriesNumber' (tag 0020|0011)           ",   
85    "        SeriesNumber are short enough to be human readable                ",
86    "        e.g : 1030,1035,1043                                              ",
87    " extent : DO NOT forget the leading '.' !                                 ",
88    " split: creates a tree-like structure of directories as :                 ",
89    "        - Patient                                                         ",
90    "        -- Serie                                                          ",
91    "        --- Position                                                      ",
92    "            Images are (sorted by Trigger Time /                          ",
93    " noshadowseq: user doesn't want to load Private Sequences                 ",
94    " noshadow : user doesn't want to load Private groups (odd number)         ",
95    " noseq    : user doesn't want to load Sequences                           ",
96    " verbose  : user wants to run the program in 'verbose mode'               ",
97    " debug    : *developer*  wants to run the program in 'debug mode'         ",
98    FINISH_USAGE
99
100    // ----- Initialize Arguments Manager ------
101       
102    gdcm::ArgMgr *am = new gdcm::ArgMgr(argc, argv);
103   
104    if (argc == 1 || am->ArgMgrDefined("usage")) 
105    {
106       am->ArgMgrUsage(usage); // Display 'usage'
107       delete am;
108       return 0;
109    }
110
111    char *dirNamein;   
112    dirNamein  = am->ArgMgrGetString("dirin",(char *)"."); 
113
114    char *dirNameout;   
115    dirNameout  = am->ArgMgrGetString("dirout",(char *)".");  
116    
117    int loadMode = gdcm::LD_ALL;
118    if ( am->ArgMgrDefined("noshadowseq") )
119       loadMode |= gdcm::LD_NOSHADOWSEQ;
120    else 
121    {
122    if ( am->ArgMgrDefined("noshadow") )
123          loadMode |= gdcm::LD_NOSHADOW;
124       if ( am->ArgMgrDefined("noseq") )
125          loadMode |= gdcm::LD_NOSEQ;
126    }
127
128    if (am->ArgMgrDefined("debug"))
129       gdcm::Debug::DebugOn();
130       
131    bool verbose  = am->ArgMgrDefined("verbose");
132    bool split    = am->ArgMgrDefined("split");
133    bool listonly = am->ArgMgrDefined("listonly");
134          
135    int nbSeriesToKeep;
136    int *seriesToKeep = am->ArgMgrGetListOfInt("keep", &nbSeriesToKeep);
137    int nbSeriesToDrop;
138    int *seriesToDrop = am->ArgMgrGetListOfInt("drop", &nbSeriesToDrop);
139  
140    if ( nbSeriesToKeep!=0 && nbSeriesToDrop!=0)
141    {
142       std::cout << "KEEP and DROP are mutually exclusive !" << std::endl;
143       delete am;
144       return 0;         
145    }
146    
147    char *extent  = am->ArgMgrGetString("extent",".DCM");
148    
149    char *input =  am->ArgMgrGetString("input","DCM"); 
150          
151    // if unused Param we give up
152    if ( am->ArgMgrPrintUnusedLabels() )
153    { 
154       am->ArgMgrUsage(usage);
155       delete am;
156       return 0;
157    }
158    delete am;  // we don't need Argument Manager any longer
159
160    // ----- Begin Processing -----
161    
162    if ( ! gdcm::DirList::IsDirectory(dirNamein) )
163    {
164       std::cout << "KO : [" << dirNamein << "] is not a Directory." << std::endl;
165       exit(0);
166    }
167    else
168    {
169       std::cout << "OK : [" << dirNamein << "] is a Directory." << std::endl;
170    }
171
172    std::string systemCommand;
173    
174    std::cout << "Check for output directory :[" << dirNameout << "]."
175              <<std::endl;
176    if ( ! gdcm::DirList::IsDirectory(dirNameout) )    // dirout not found
177    {
178       std::string strDirNameout(dirNameout);          // to please gcc 4
179       systemCommand = "mkdir " +strDirNameout;        // create it!
180       if (verbose)
181          std::cout << systemCommand << std::endl;
182       system (systemCommand.c_str());
183       if ( ! gdcm::DirList::IsDirectory(dirNameout) ) // be sure it worked
184       {
185           std::cout << "KO : not a dir : [" << dirNameout << "] (creation failure ?)" << std::endl;
186           exit(0);
187       }
188       else
189       {
190         std::cout << "Directory [" << dirNameout << "] created." << std::endl;
191       }
192    }
193    else
194    {
195        std::cout << "Output Directory [" << dirNameout << "] already exists; Used as is." << std::endl;
196    }
197     
198    std::string strDirNamein(dirNamein);
199    gdcm::DirList dirList(strDirNamein, true); // get recursively the list of files
200    
201    if (listonly)
202    {
203       std::cout << "------------List of found files ------------" << std::endl;
204       dirList.Print();
205    }
206
207    gdcm::DirListType fileNames;
208    fileNames = dirList.GetFilenames();
209    gdcm::SerieHelper *s;              // Needed only to may use SerieHelper::AddSeriesDetail()
210    s = gdcm::SerieHelper::New();
211
212 /*       
213    std::cout << "---------------Print Serie--------------" << std::endl; 
214    s->SetDirectory(dirNamein, true); // true : recursive exploration 
215    s->SetUseSeriesDetails(true);  
216    s->AddSeriesDetail(0x0018, 0x1312);   
217    s->Print();
218 */
219   
220    gdcm::File *f;
221    gdcm::FileHelper *fh;
222 /*   
223    std::cout << "---------------Print Unique Series identifiers---------"  
224              << std::endl;     
225    std::string uniqueSeriesIdentifier;
226  
227    for (gdcm::DirListType::iterator it = fileNames.begin();  
228                                     it != fileNames.end();
229                                   ++it)
230    {
231       std::cout << "File Name : " << *it << std::endl;
232       f = gdcm::File::New();
233       f->SetLoadMode(gdcm::LD_ALL);
234       f->SetFileName( *it );
235       f->Load();
236         
237       uniqueSeriesIdentifier=s->CreateUniqueSeriesIdentifier(f);
238       std::cout << "                           [" <<
239                uniqueSeriesIdentifier  << "]" << std::endl;       
240       f->Delete();
241    }
242 */
243    
244    if (verbose)
245       std::cout << "------------------Print Break levels-----------------" << std::endl;
246
247    std::string userFileIdentifier; 
248    SortedFiles sf;
249
250    s->AddSeriesDetail(0x0010, 0x0010, false); // Patient's Name
251    s->AddSeriesDetail(0x0020, 0x0010, false); // Study ID - Siemens, in that time!
252    s->AddSeriesDetail(0x0020, 0x0030, false); // Image Position (RET)     
253    s->AddSeriesDetail(0x0020, 0x0013, false);  // Instance Number
254             //(called 'Trigger Time' in order not to change too much the code)
255       
256    for (gdcm::DirListType::iterator it = fileNames.begin();  
257                                     it != fileNames.end();
258                                   ++it)
259    {
260       f = gdcm::File::New();
261       f->SetLoadMode(loadMode);
262       f->SetFileName( *it );
263       f->Load();
264       
265       // keep only requested Series
266       std::string strSeriesNumber;
267       int seriesNumber;
268       int j;
269       
270       bool keep = false;
271       if (nbSeriesToKeep != 0)
272       {     
273          strSeriesNumber = f->GetEntryString(0x0020, 0x0011 );
274          seriesNumber = atoi( strSeriesNumber.c_str() );
275          for (j=0;j<nbSeriesToKeep; j++)
276          {
277             if(seriesNumber == seriesToKeep[j])
278             {
279                keep = true;
280                break;
281             }
282          }
283          if ( !keep)
284          {
285             f->Delete();
286             continue;
287          } 
288       }
289       // drop all unrequested Series
290       bool drop = false;
291       if (nbSeriesToDrop != 0)
292       {     
293          strSeriesNumber = f->GetEntryString(0x0020, 0x0011 );
294          seriesNumber = atoi( strSeriesNumber.c_str() );
295          for (j=0;j<nbSeriesToDrop; j++)
296          {
297             if(seriesNumber == seriesToDrop[j])
298             { 
299                drop = true;
300                break;
301             }
302         }
303         if (drop)
304         {
305            f->Delete();
306            continue;
307         }
308       }      
309
310       userFileIdentifier=s->CreateUserDefinedFileIdentifier(f); 
311      // userFileIdentifier += "_";
312       //userFileIdentifier += *it;       
313       std::cout << "                           [" <<
314               userFileIdentifier  << "]" << std::endl;
315       
316       // storing in a map ensures automatic sorting !      
317       sf[userFileIdentifier] = f;
318    }
319       
320    std::vector<std::string> tokens;
321    std::string fullFilename, lastFilename;
322    std::string previousPatientName, currentPatientName;
323    std::string previousSerieInstanceUID, currentSerieInstanceUID;
324    std::string previousImagePosition, currentImagePosition;
325    //std::string previousPhaseEncodingDirection, currentPhaseEncodingDirection;
326    std::string previousTriggerTime, currentTriggerTime;
327       
328    std::string writeDir, currentWriteDir;
329    std::string currentPatientWriteDir, currentSerieWriteDir, 
330                currentPositionWriteDir; // currentPhaseEncodingDirectionWriteDir;
331
332    std::string fullWriteFilename;
333    std::string strExtent(extent); 
334            
335    writeDir = gdcm::Util::NormalizePath(dirNameout);     
336    SortedFiles::iterator it2;
337  
338    previousPatientName            = "";
339    previousSerieInstanceUID       = "";   
340    previousImagePosition          = "";
341    //previousPhaseEncodingDirection = "";
342    previousTriggerTime            = "";
343    
344    int sliceIndex = 1;
345    int frameIndex = 1;
346    int flag       = 0;
347        
348    gdcm::File *currentFile;
349      
350    for (it2 = sf.begin() ; it2 != sf.end(); ++it2)
351    {  
352       currentFile = it2->second;
353        
354       fullFilename =  currentFile->GetFileName();
355       lastFilename =  gdcm::Util::GetName( fullFilename ); 
356       std::cout << "Try to write" <<lastFilename << std::endl;
357      
358       tokens.clear();
359       gdcm::Util::Tokenize (it2->first, tokens, "_");
360       
361       currentPatientName            = tokens[0];
362       currentSerieInstanceUID       = tokens[1];
363       currentImagePosition          = tokens[2];
364       currentTriggerTime            = tokens[3];
365       //currentPhaseEncodingDirection = tokens[4];           
366       
367       if ( currentImagePosition[0] == '-')
368           currentImagePosition[0] = 'M';
369       if ( currentImagePosition[0] == '+')
370           currentImagePosition[0] = 'P'; 
371       
372       if (previousPatientName != currentPatientName)
373       {
374          previousPatientName = currentPatientName;
375          if (verbose)   
376             std::cout << "==== new Patient  [" << currentPatientName  << "]" << std::endl;
377     
378          previousPatientName            = currentPatientName;
379          previousSerieInstanceUID       = ""; //currentSerieInstanceUID;
380          previousImagePosition          = ""; //currentImagePosition;
381          previousTriggerTime            = "";
382         // previousPhaseEncodingDirection = ""; //currentPhaseEncodingDirection;
383   
384          currentPatientWriteDir = writeDir + currentPatientName;
385          //if ( ! gdcm::DirList::IsDirectory(currentPatientWriteDir) )
386            {
387               systemCommand   = "mkdir " + currentPatientWriteDir;
388               if (verbose)
389                  std::cout << systemCommand << std::endl;
390               system ( systemCommand.c_str() );
391          }
392       }
393
394       if (previousSerieInstanceUID != currentSerieInstanceUID)
395       {        
396          if (verbose)   
397             std::cout << "==== === new Serie [" << currentSerieInstanceUID << "]"
398                       << std::endl;
399          if (split)
400          {
401              currentSerieWriteDir  = currentPatientWriteDir + gdcm::GDCM_FILESEPARATOR
402                              + currentSerieInstanceUID;
403              systemCommand   = "mkdir " + currentSerieWriteDir;  
404              system (systemCommand.c_str());
405          }
406          previousSerieInstanceUID       = currentSerieInstanceUID;
407          previousImagePosition          = ""; //currentImagePosition;
408          //previousPhaseEncodingDirection = ""; //currentPhaseEncodingDirection;
409       }
410
411       if (previousImagePosition != currentImagePosition)
412       {
413          frameIndex = 1;
414          flag = 0;        
415          if (verbose)   
416             std::cout << "=== === === new Position [" << currentImagePosition  << "]"
417                       << std::endl;
418          if (split)
419          {
420              currentPositionWriteDir  = currentSerieWriteDir + gdcm::GDCM_FILESEPARATOR
421                              + currentImagePosition;
422              systemCommand   = "mkdir " + currentPositionWriteDir;     
423              system (systemCommand.c_str()); 
424          }
425          previousImagePosition          = currentImagePosition;
426          //previousPhaseEncodingDirection = ""; //currentPhaseEncodingDirection;
427          sliceIndex += 1;
428       }      
429
430 // We don't split on Row/Column!
431 /*
432       if (previousPhaseEncodingDirection != currentPhaseEncodingDirection)
433       {        
434          if (verbose)   
435             std::cout << "==== === === === new PhaseEncodingDirection [" 
436                       << currentPhaseEncodingDirection  << "]" << std::endl;
437       
438          if (split)
439          {
440              currentPhaseEncodingDirectionWriteDir  = currentPositionWriteDir 
441                              + gdcm::GDCM_FILESEPARATOR
442                              + currentPhaseEncodingDirection;
443              systemCommand   = "mkdir " + currentPhaseEncodingDirectionWriteDir;     
444              system (systemCommand.c_str());     
445          }      
446     
447          previousPhaseEncodingDirection = currentPhaseEncodingDirection;
448       } 
449 */    
450       
451       if (verbose)
452          std::cout << "--- --- --- --- --- " << (it2->second)->GetFileName() 
453                    << std::endl;
454    
455       if ( gdcm::Debug::GetDebugFlag())
456          std::cout << "--- --- --- --- --- " << it2->first << "  " 
457                    << (it2->second)->GetFileName() << " " 
458                    << gdcm::Util::GetName( fullFilename ) << std::endl;           
459       
460       // Transform the image to be 'Brucker-Like'
461       // ----------------------------------------   
462     
463       // Deal with 0x0019, 0x1000 : 'FOV'
464       int nX = currentFile->GetXSize();
465       int nY = currentFile->GetYSize();
466       float pxSzX = currentFile->GetXSpacing();
467       float pxSzY = currentFile->GetYSpacing();
468       char fov[64];
469       sprintf(fov, "%f\\%f",nX*pxSzX, nY*pxSzY);
470       currentFile->InsertEntryString(fov, 0x0019, 0x1000, "DS");
471      
472       // Deal with 0x0020, 0x0012 : 'SESSION INDEX'  (Acquisition Number)
473       std::string chSessionIndex = "1";
474       /*
475       if (currentPhaseEncodingDirection == "ROW")
476          chSessionIndex = "1";
477       else
478          chSessionIndex = "2"; // suppose it's "COLUMN" !
479       currentFile->InsertEntryString(chSessionIndex, 0x0020, 0x0012, "IS");
480      */
481       // Deal with  0x0021, 0x1020 : 'SLICE INDEX'
482       char chSliceIndex[5];
483       sprintf(chSliceIndex, "%04d", sliceIndex);
484       std::string strChSliceIndex(chSliceIndex);
485       currentFile->InsertEntryString(strChSliceIndex, 0x0021, 0x1020, "IS");
486        
487       // Deal with  0x0021, 0x1040 : 'FRAME INDEX' 
488       char chFrameIndex[5];
489       sprintf(chFrameIndex, "%04d", frameIndex);
490       currentFile->InsertEntryString(chFrameIndex, 0x0021, 0x1040, "IS"); 
491       
492       if (flag == 0)
493       {       
494          flag = 1;
495       }
496       else
497       {
498          frameIndex++;
499          flag = 0;
500       }
501                     
502       if (split)
503       
504          //fullWriteFilename = currentPhaseEncodingDirectionWriteDir + gdcm::GDCM_FILESEPARATOR 
505          //                                + lastFilename + strExtent;      
506          fullWriteFilename = currentPositionWriteDir + gdcm::GDCM_FILESEPARATOR 
507                                          + lastFilename + strExtent; 
508       else
509          fullWriteFilename = currentPatientWriteDir + gdcm::GDCM_FILESEPARATOR 
510                                          + lastFilename + strExtent; 
511       
512       /*           
513       systemCommand  = "cp " + fullFilename + " " + fullWriteFilename;
514       std::cout << systemCommand << std::endl;
515       system (  systemCommand.c_str() );
516       */
517             
518       // Load the pixels in RAM.    
519       
520       fh = gdcm::FileHelper::New(currentFile);     
521       fh->GetImageDataRaw(); // Don't convert (Gray Pixels + LUT) into (RGB pixels) ?!?
522       fh->SetWriteTypeToDcmExplVR();
523       if (!fh->Write(fullWriteFilename))
524       {
525          std::cout << "Fail to write :[" << fullWriteFilename << "]"
526                    << std::endl;
527       } 
528       fh->Delete();                
529    }
530  }