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