]> Creatis software - gdcm.git/blob - Example/SplitIntoXCoherentDirectories.cxx
no message
[gdcm.git] / Example / SplitIntoXCoherentDirectories.cxx
1 /*=========================================================================
2   
3   Program:   gdcm
4   Module:    $RCSfile: SplitIntoXCoherentDirectories.cxx,v $
5   Language:  C++
6   Date:      $Date: 2011/08/25 14:37:05 $
7   Version:   $Revision: 1.8 $
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 "gdcmSerieHelper.h"
19 #include "gdcmFileHelper.h"
20 #include "gdcmFile.h"
21 #include "gdcmDebug.h"
22 #include <iostream>
23 #include "gdcmDirList.h"
24 #include "gdcmUtil.h"
25 #include "gdcmArgMgr.h"
26 #include "gdcmDictSet.h"  // for GetName 
27 int main(int argc, char *argv[])
28 {
29
30    START_USAGE(usage)
31    "\n SplitIntoXCoherentDirectories :\n                                      ",
32    "Shows the various 'XCoherent' Filesets within a directory                 ",
33    "Optionaly copies the images in a Directories tree                         ",
34    "usage: exXCoherentFileSet {dirin=inputDirectoryName}                      ",
35    "                           dirout=outputDirectoryName                     ",
36    "                       { tag=group-elem | pos | ori } [sort]              ",
37    "                       [{ write | copy }] [studyUID = ]                   ",
38    "                       [ { [noshadowseq] | [noshadow][noseq] } ] [debug]  ",
39    "                                                                          ",
40    "       dirin : user wants to analyze *all* the files                      ",
41    "                            within the directory                          ",
42    "       copy  : user wants to copy the files into a directories tree       ",
43    "       write : user wants to rewrite the files into a directories tree    ",
44    "               each directory with the same 'Series Instance UID'         ",
45    "       dirout : will be created if doesn't exist                          ",
46    "       pos  : user wants to split each Single SerieUID Fileset on the     ",
47    "                         'Image Position '                                ",
48    "       ori  : user wants to split each Single SerieUID Fileset on the     ",
49    "                         'Image Orientation '                             ",
50    "       tag : group-elem    (in hexa, no space)                            ",
51    "                       the user wants to split on                         ",
52    "       sort :  user wants FileHelper to sort the images                   ",
53    "               Warning : will probabely crash if sort has no meaning      ",
54    "                (not only look at image names)                            ",
55    "       studyUID   : *aware* user wants to add the serie                   ",
56    "                                             to an already existing study ",
57    "       verbose    : user wants to run the program in 'verbose mode'       ",
58    "       debug      : developper wants to run the program in 'debug mode'   ",
59    FINISH_USAGE
60
61    // ----- Initialize Arguments Manager ------
62
63    GDCM_NAME_SPACE::ArgMgr *am = new GDCM_NAME_SPACE::ArgMgr(argc, argv);
64
65    if (am->ArgMgrDefined("usage") || argc == 1)
66    {
67       am->ArgMgrUsage(usage); // Display 'usage'
68       delete am;
69       return 0;
70    }
71
72    if (am->ArgMgrDefined("debug"))
73       GDCM_NAME_SPACE::Debug::DebugOn();
74  
75    int loadMode;
76    int maxSize;
77
78    const char *dirName  = am->ArgMgrGetString("dirin");
79    if (dirName == 0)
80    {
81        std::cout <<std::endl
82                  << "'dirin=' must be present;" 
83                  <<  std::endl;
84        am->ArgMgrUsage(usage); // Display 'usage'  
85        delete am;
86        return 0;
87    }
88
89    const char *dirNameout;   
90    dirNameout  = am->ArgMgrGetString("dirout",".");
91
92    bool pos  =    ( 0 != am->ArgMgrDefined("pos") ); 
93    bool ori  =    ( 0 != am->ArgMgrDefined("ori") );   
94    bool sort =    ( 0 != am->ArgMgrDefined("sort") );
95    bool copy =    ( 0 != am->ArgMgrDefined("copy") );
96    bool write =   ( 0 != am->ArgMgrDefined("write") );
97    bool verbose = ( 0 != am->ArgMgrDefined("verbose") );
98    bool tag     = ( 0 != am->ArgMgrDefined("tag") );
99
100    if( copy && write )
101    {
102       std::cout << "COPY and WRITE are mutually exclusive" << std::endl;
103       delete am;
104       return 0;
105    }
106
107    if( (tag && (pos || ori)) || (pos && (tag || ori)) || (ori && (tag || pos)) )
108    {
109       std::cout << " POS, ORI and TAG are mutually exclusive" << std::endl;
110       delete am;
111       return 0;      
112    }
113    
114    if( (!tag && !pos && !ori))
115    {
116       std::cout << " One of POS, ORI and TAG is mandatory!" << std::endl;
117       delete am;
118       return 0;      
119    }         
120    int nb;
121    uint16_t *groupelem;
122    if (tag)
123    {
124       groupelem = am->ArgMgrGetXInt16Enum("tag", &nb);
125       if (nb != 1)
126       {
127          std::cout << "TAG : one and only one group,elem!" << std::endl;
128          delete am;
129          return 0;
130       }
131    }      
132
133    bool userDefinedStudy = ( 0 != am->ArgMgrDefined("userDefinedStudy") );
134    const char *studyUID  = am->ArgMgrGetString("studyUID");
135             
136    /* if unused Param we give up */
137    if ( am->ArgMgrPrintUnusedLabels() )
138    {
139       am->ArgMgrUsage(usage);
140       delete am;
141       return 0;
142    } 
143  
144    delete am;  // ------ we don't need Arguments Manager any longer ------
145
146
147    GDCM_NAME_SPACE::SerieHelper *s;  
148    s = GDCM_NAME_SPACE::SerieHelper::New();
149
150    GDCM_NAME_SPACE::File *f;
151    s->SetLoadMode(GDCM_NAME_SPACE::LD_ALL); // Load everything for each File
152    s->SetDirectory(dirName, true);          // true : recursive exploration
153    
154    GDCM_NAME_SPACE::DirList dirlist(dirName, true); // recursive exploration
155    GDCM_NAME_SPACE::DirListType fileNames = dirlist.GetFilenames();
156    GDCM_NAME_SPACE::FileList *l = new GDCM_NAME_SPACE::FileList;
157
158    std::string replaceChar("_");
159 // Loop on all the gdcm-readable files
160    for (GDCM_NAME_SPACE::DirListType::iterator it = fileNames.begin();
161                                     it != fileNames.end();
162                                   ++it)
163    {
164       if (verbose)
165          std::cout << *it << std::endl;
166
167       if (write) {
168          loadMode = GDCM_NAME_SPACE::LD_ALL; // load any DataElement
169          maxSize  = 0x7fff;                  // load any length
170       } else {
171          loadMode = GDCM_NAME_SPACE::LD_NOSEQ | GDCM_NAME_SPACE::LD_NOSHADOW ; 
172          maxSize  = 0x0100;
173       }
174
175       f = GDCM_NAME_SPACE::File::New();
176       f->SetLoadMode(loadMode);
177       f->SetMaxSizeLoadEntry(maxSize);
178       f->SetFileName( *it );
179       f->Load();
180       l->push_back(f);
181    }
182
183    std::string systemCommand;
184    std::string filenameout;
185    if (write || copy) {
186       if (verbose)
187          std::cout << "Check for output directory :[" << dirNameout << "]."
188                    <<std::endl;
189       if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(dirNameout) )    // dirout not found
190       {
191          std::string strDirNameout(dirNameout);          // to please gcc 4
192          systemCommand = "mkdir \"" +strDirNameout + "\"";        // create it!
193          if (verbose)
194             std::cout << systemCommand << std::endl;
195          system (systemCommand.c_str());
196          if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(dirNameout) ) // be sure it worked
197          {
198              std::cout << "KO : not a dir : [" << dirNameout << "] (creation failure ?)" 
199                        << std::endl;
200          return 0;
201          }
202          else
203          {
204             if (verbose)
205                std::cout << "Directory [" << dirNameout << "] created." << std::endl;
206          }
207       }
208       else
209       {
210          if (verbose)
211             std::cout << "Output Directory [" << dirNameout
212                       << "] already exists; Used as is."
213                       << std::endl;
214       }
215    }
216       // --> End of checking supposed-to-be-directory names
217
218    int nbFiles;
219    std::string fileName;
220
221    // For all the Single SerieUID Files Sets of the GDCM_NAME_SPACE::Serie
222
223   // GDCM_NAME_SPACE::FileList *l = s->GetFirstSingleSerieUIDFileSet();
224
225    l = s->GetFirstSingleSerieUIDFileSet();
226    if (l == NULL) {
227       std::cout << "No Serie found ?!?" << std::endl;
228       exit (0);
229    }
230
231    GDCM_NAME_SPACE::XCoherentFileSetmap xcm;
232
233    std::string serieUID;
234    std::string currentSerieWriteDir = "";
235    std::string xCoherentWriteDir = "";
236    std::string xCoherentName = "";
237    std::string serieDirectory;
238    std::string lastFilename;
239    std::string rep("_");
240    int controlCount = 0;
241
242    // 'Study Instance UID'
243    // The user is allowed to create his own Study, 
244    //          keeping the same 'Study Instance UID' for various images
245    // The user may add images to a 'Manufacturer Study',
246    //          adding new Series to an already existing Study
247    std::string strStudyUID;
248    if (write) {
249       if ( !userDefinedStudy )
250          strStudyUID =  GDCM_NAME_SPACE::Util::CreateUniqueUID();
251       else
252          strStudyUID = studyUID;
253    }
254
255    while (l) // for each 'Single SerieUID FileSet' //===> Ignore 'Serie UID"
256    { 
257  currentSerieWriteDir = "";
258       nbFiles = l->size() ;
259       if ( l->size() > 2 ) // ignore a Directory with less than 2 images.
260                            // Why not ? Just an example, for testing!
261       {
262           // Just not to make too many modif in the code
263           //serieUID = "SingleSerie"; // s->GetCurrentSerieUIDFileSetUID();
264           serieUID = s->GetCurrentSerieUIDFileSetUID();
265           GDCM_NAME_SPACE::Util::ReplaceSpecChar(serieUID, rep);
266
267           // --- for write
268           if (write || copy)
269           {
270              currentSerieWriteDir = currentSerieWriteDir + dirNameout;
271              unsigned int l = strlen(dirNameout)-1;
272              if ( dirNameout[l] != '/'  &&  dirNameout[l] != '\\')
273                 currentSerieWriteDir = currentSerieWriteDir + GDCM_NAME_SPACE::GDCM_FILESEPARATOR;
274     
275              currentSerieWriteDir = currentSerieWriteDir + serieUID;
276              if (verbose)
277                 std::cout << "[" << currentSerieWriteDir<< "]" << std::endl;
278             // if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(currentSerieWriteDir) )
279              {     
280                 systemCommand   = "mkdir \"" + currentSerieWriteDir + "\"";
281                 system( systemCommand.c_str());
282                 if (verbose)
283                    std::cout <<  "1 " <<systemCommand << std::endl;
284              }
285          } 
286           // --- end for write
287     
288          std::cout << "Split the 'Single SerieUID' FileSet :[" 
289                    << serieUID
290                    << "]  " << nbFiles << " long" << std::endl;
291          std::cout << "-----------------------------------" << std::endl;
292   
293          if (ori) 
294             xcm = s->SplitOnOrientation(l);
295          else if (pos)
296             xcm = s->SplitOnPosition(l);
297          else if (groupelem != 0) {
298          // Crashes if DataElement not found
299          //std:: cout << GDCM_NAME_SPACE::Global::GetDicts()->GetDefaultPubDict()->GetEntry(groupelem[0],groupelem[1])->GetName() << std::endl;
300  
301             xcm = s->SplitOnTagValue(l, groupelem[0],groupelem[1] );
302          }
303
304          GDCM_NAME_SPACE::FileHelper *fh;
305
306          for (GDCM_NAME_SPACE::XCoherentFileSetmap::iterator i = xcm.begin(); 
307                                                   i != xcm.end();
308                                                 ++i)
309          {
310             xCoherentName = (*i).first;
311             if (verbose)
312                std::cout << "==========================================xCoherentName = " << xCoherentName << std::endl;
313              GDCM_NAME_SPACE::Util::ReplaceSpecChar(xCoherentName, rep);
314              // --- for write
315              if (write || copy)
316              {
317                 xCoherentWriteDir = currentSerieWriteDir + GDCM_NAME_SPACE::GDCM_FILESEPARATOR+ xCoherentName;
318                // if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(xCoherentWriteDir) )
319                 {      
320                    systemCommand   = "mkdir \"" + xCoherentWriteDir + "\"";
321                    system( systemCommand.c_str());
322                    if (verbose)
323                       std::cout << "2 " << systemCommand << std::endl;       
324                 }
325             } 
326             // --- end for write
327
328             if (ori)
329                std::cout << "Orientation : ";
330             else if (pos)
331                std::cout << "Position : ";
332             else if (groupelem != 0)
333                std::cout << "Tag (" << std::hex << groupelem[0]
334                          << "|" << groupelem[1] << ") value : ";
335             std::cout << "[" << (*i).first << "]" << std::endl;
336         
337             if (verbose)
338                std::cout << "xCoherentName [" << xCoherentName << "]" << std::endl;
339     
340            // Within a 'just to see' program, 
341            // OrderFileList() causes trouble, since some files
342            // (eg:MIP views) don't have 'Position', now considered as mandatory
343            // --> Activated on user demand.
344
345            if (sort) {
346               s->OrderFileList((*i).second);  // sort the XCoherent Fileset
347               std::cout << "ZSpacing for the file set " << s->GetZSpacing()
348                         << std::endl;
349            } 
350
351             std::string strSerieUID =  GDCM_NAME_SPACE::Util::CreateUniqueUID();
352
353             for (GDCM_NAME_SPACE::FileList::iterator it2 =  ((*i).second)->begin();
354                                           it2 != ((*i).second)->end();
355                                         ++it2)
356             {
357                controlCount ++;
358                fileName = (*it2)->GetFileName();
359                // --- for write
360                lastFilename =  GDCM_NAME_SPACE::Util::GetName( fileName );
361
362                // If you want to create file names of your own, here is the place!
363                // Just replace 'lastFilename' by anything that's better for you.
364                GDCM_NAME_SPACE:: Util::ReplaceSpecChar(lastFilename, replaceChar);
365
366                filenameout = xCoherentWriteDir  + GDCM_NAME_SPACE::GDCM_FILESEPARATOR+ lastFilename; 
367                if (write)
368                {  
369                   fh = GDCM_NAME_SPACE::FileHelper::New( (*it2) );
370                   fh->SetKeepOverlays( true );       
371                   fh->InsertEntryString(strSerieUID,0x0020,0x000e,"UI");
372                   unsigned int dataSize  = fh->GetImageDataRawSize();
373                   uint8_t *imageData = fh->GetImageDataRaw();// somewhat important : Loads the Pixels in memory !
374                   if (!imageData)
375                      std::cout << "fail to read [" << (*it2)->GetFileName() << std::endl;
376                   fh->SetWriteTypeToDcmExplVR();
377                   fh->SetContentType(GDCM_NAME_SPACE::UNMODIFIED_PIXELS_IMAGE);
378                   if (!fh->Write(filenameout))
379                   {
380                      std::cout << "Fail to write :[" << filenameout << "]"
381                                << std::endl;
382                   }
383                   fh->Delete();
384                }
385                else if (copy)
386                {
387                    systemCommand   = "cp \"" + fileName + "\" \"" + filenameout + "\"";
388                    system( systemCommand.c_str());
389                }
390                if (verbose)
391                      std::cout << "3 " << systemCommand << std::endl;
392             }
393          }
394          std::cout << std::endl;
395       }
396       l = s->GetNextSingleSerieUIDFileSet();
397    }
398     
399    if ( controlCount == 0 )
400       std::cout << "No suitable file was found!" << std::endl;
401
402    s->Delete();
403    return 0;
404 }