]> Creatis software - gdcm.git/blob - Example/exMoveImagesToSingleSerieUID.cxx
Avoid warning
[gdcm.git] / Example / exMoveImagesToSingleSerieUID.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: exMoveImagesToSingleSerieUID.cxx,v $
5   Language:  C++
6   Date:      $Date: 2007/05/23 14:18:05 $
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 /*
19 Some old versions of VTK? ITK ? SeriesWriter weren't too much strict
20  when they did the job.
21  A lot of people has a lot of 'supposed to be Serie' directories
22  that, actually, aren't at all.
23  The following program converts them (hope so!)
24  
25  Le programme 'de convertion' s'utilise comme les 'filtres LibIDO'
26 (mots-clés et valeurs par defaut).
27
28 exMoveImagesToSingleSerieUID
29                                      ",
30 Converts the a Dicom file inside a single-level Directory
31  into a 'Single Study UID - Single SerieUID      
32   usage:
33 exMoveImagesToSingleSerieUID
34       dirin=inputDirectoryName                                   
35       dirout=outputDirectoryName                                  
36       [studyUID = ] [patName = ] [Zspacing = ]
37       [ { [noshadowseq] | [noshadow][noseq] } ]  [debug]
38       [verbose]",
39
40
41   dirin : single-level Directory containing the images 
42            (no recursive parsing)
43   dirout : will be created if doesn't exist                
44   studyUID   : *aware* user wants to add the serie  
45                     to an already existing study 
46
47
48 dirin : directory (un seul niveau) contenant les images
49 dirout : directory de sortie (cree s'il n'existe pas); le nom des images
50 est conservé.
51 studyUID : si on veut *ajouter* la serie qui va etre creee a une study
52 qui existe deja (il faut connaitre son Study UID)
53 patName : nom du patient (ca peut servir pour y voir plus clair sur les
54 logiciels cliniques)
55 Zspacing : si c'est important pour la visu 3D. Ca servira a calculer le
56 Slice Location (s'il n'existe pas deja) et la composante Z de
57 ImagePositionPatient (s'il n'existe pas)
58
59 // if Image Orientation (Patient) is not present
60 //    I create one, (as Axial)
61 //    if Image Position (Patient) is not present
62 //       I create one, incrementing  zPositionComponent up by user
63 supplied zSpacing
64 //    if Slice Location is not present
65 //       I create one, as zPositionComponent
66 //
67 */
68 #include "gdcmFile.h"
69 #include "gdcmFileHelper.h"
70 #include "gdcmCommon.h"
71 #include "gdcmDebug.h"
72 #include "gdcmDirList.h"
73 #include "gdcmUtil.h"
74
75 #include "gdcmArgMgr.h"
76
77 #include <iostream>
78
79 int main(int argc, char *argv[])
80 {   
81    START_USAGE(usage)
82    "\n exMoveImagesToSingleSerieUID :\n                                       ",
83    " Converts the Dicom files inside a single-level Directory                 ",
84    " into a 'Single Study UID - Single SerieUID' file set                     ",
85    " usage: exMoveImagesToSingleSerieUID                                      ",
86    "              dirin=inputDirectoryName                                    ",
87    "              dirout=outputDirectoryName                                  ",
88    "              [studyUID = ] [patName = ] [Zspacing = ]                    ",
89    "              [ { [noshadowseq] | [noshadow][noseq] } ]  [debug] [verbose]",
90    "                                                                          ",
91    "       dirin : single-level Directory containing the images               ",
92    "                                        (no recursive parsing)            ",   
93    "       dirout : will be created if doesn't exist                          ",
94    "                                                                          ",
95    "       studyUID   : *aware* user wants to add the serie                   ",
96    "                                             to an already existing study ",
97    "       noshadowseq: user doesn't want to load Private Sequences           ",
98    "       noshadow   : user doesn't want to load Private groups (odd number) ",
99    "       noseq      : user doesn't want to load Sequences                   ",
100    "       verbose    : user wants to run the program in 'verbose mode'       ",
101    "       debug      : developper wants to run the program in 'debug mode'   ",
102    FINISH_USAGE
103    
104    
105      // ----- Initialize Arguments Manager ------
106   
107    GDCM_NAME_SPACE::ArgMgr *am = new GDCM_NAME_SPACE::ArgMgr(argc, argv);
108   
109    if (am->ArgMgrDefined("usage") || argc == 1) 
110    {
111       am->ArgMgrUsage(usage); // Display 'usage'
112       delete am;
113       return 0;
114    }
115
116    if (am->ArgMgrDefined("debug"))
117       GDCM_NAME_SPACE::Debug::DebugOn(); 
118    int verbose  = am->ArgMgrDefined("verbose");
119    
120    std::string patName = am->ArgMgrGetString("patname", "g^PatientName");
121    float zSpacing = am->ArgMgrGetFloat("zSpacing", 1.0);
122       
123    const char *dirIn  = am->ArgMgrGetString("dirin");
124    const char *dirOut  = am->ArgMgrGetString("dirout");
125    
126    int userDefinedStudy = am->ArgMgrDefined("studyUID");
127    const char *studyUID  = am->ArgMgrGetString("studyUID");
128
129 // not described *on purpose* in the Usage ! 
130    int userDefinedSerie = am->ArgMgrDefined("serieUID");   
131    const char *serieUID  = am->ArgMgrGetString("serieUID");      
132  
133    int loadMode = GDCM_NAME_SPACE::LD_ALL;
134    if ( am->ArgMgrDefined("noshadowseq") )
135       loadMode |= GDCM_NAME_SPACE::LD_NOSHADOWSEQ;
136    else 
137    {
138    if ( am->ArgMgrDefined("noshadow") )
139          loadMode |= GDCM_NAME_SPACE::LD_NOSHADOW;
140       if ( am->ArgMgrDefined("noseq") )
141          loadMode |= GDCM_NAME_SPACE::LD_NOSEQ;
142    }
143         
144    /* if unused Param we give up */
145    if ( am->ArgMgrPrintUnusedLabels() )
146    {
147       am->ArgMgrUsage(usage);
148       delete am;
149       return 0;
150    }
151
152    delete am;  // ------ we don't need Arguments Manager any longer ------
153    
154  // ====== Deal with a (single level, single Patient) Directory ======
155  
156  
157    //std::cout << "dirIn [" << dirIn << "]" << std::endl;
158    if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(dirIn) )
159    {
160       std::cout << "KO : [" << dirIn << "] is not a Directory." << std::endl;
161       return 0;
162
163    }
164    else
165    {
166       if (verbose)
167          std::cout << "OK : [" << dirIn << "] is a Directory." << std::endl;
168    }   
169   
170    std::string systemCommand;
171    std::string strDirNameout(dirOut);          // to please gcc 4   
172    std::cout << "Check for output directory :[" << dirOut << "]."
173              <<std::endl;
174    if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(dirOut) )    // dirout not found
175    {
176       systemCommand = "mkdir " +strDirNameout;        // create it!
177       if (verbose)
178          std::cout << systemCommand << std::endl;
179       system (systemCommand.c_str());
180       if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(dirOut) ) // be sure it worked
181       {
182           std::cout << "KO : not a dir : [" << dirOut << "] (creation failure ?)" << std::endl;
183       return 0;
184
185       }
186       else
187       {
188         if (verbose)
189            std::cout << "Directory [" << dirOut << "] created." << std::endl;
190       }
191    }
192    else
193    {
194       std::cout << "Output Directory [" << dirOut << "] already exists; Used as is." << std::endl;
195    }  
196
197    GDCM_NAME_SPACE::DirList dirList(dirIn,false); // gets (at single level) the file list
198    GDCM_NAME_SPACE::DirListType fileList = dirList.GetFilenames();
199
200    // 'Study Instance UID'
201    // The user is allowed to create his own Study, 
202    //          keeping the same 'Study Instance UID' for various images
203    // The user may add images to a 'Manufacturer Study',
204    //          adding new Series to an already existing Study
205    std::string strStudyUID;
206    if ( !userDefinedStudy)
207       strStudyUID =  GDCM_NAME_SPACE::Util::CreateUniqueUID();
208    else
209       strStudyUID = studyUID;
210
211
212    // 'Serie Instance UID'
213    // The user is allowed to create his own Series, 
214    // keeping the same 'Serie Instance UID' for various images
215    // The user shouldn't add any image to a 'Manufacturer Serie'
216    // but there is no way no to prevent him for doing that
217    
218    std::string strSerieUID; 
219    if ( !userDefinedSerie)   
220       strSerieUID =  GDCM_NAME_SPACE::Util::CreateUniqueUID();
221    else      
222       strSerieUID = serieUID;
223         
224    GDCM_NAME_SPACE::File *f;
225    GDCM_NAME_SPACE::FileHelper *fh;
226    std::string fullFilename, lastFilename;
227    float zPositionComponent = 0.0;
228    
229    for( GDCM_NAME_SPACE::DirListType::iterator it  = fileList.begin();
230                                  it != fileList.end();
231                                  ++it )
232    {
233       fullFilename = *it;
234       f = GDCM_NAME_SPACE::File::New( );
235       f->SetLoadMode(loadMode);
236       f->SetFileName( it->c_str() );
237
238       if (verbose)
239          std::cout << "file [" << it->c_str() << "]" << std::endl;
240       if ( !f->Load() )
241       {
242          if (verbose)
243             std::cout << "fail to load [" << it->c_str() << "]" << std::endl;      
244          f->Delete();
245          continue;
246       }
247
248       // Load the pixels in RAM.    
249       
250       fh = GDCM_NAME_SPACE::FileHelper::New(f);     
251       uint8_t *imageData = fh->GetImageDataRaw(); // Don't convert (Gray Pixels + LUT) into (RGB pixels) ?!?
252       if (!imageData)
253          std::cout << "fail to read [" << it->c_str() << std::endl;
254       fh->SetWriteTypeToDcmExplVR();
255
256       fh->InsertEntryString(strStudyUID,0x0020,0x000d,"UI");      
257       fh->InsertEntryString(strSerieUID,0x0020,0x000e,"UI");
258       fh->InsertEntryString(patName,0x0010,0x0010, "PN");   // Patient's Name
259
260 // ==================================================================================================
261
262 // This is a dirty heuristics, but no other way :-(
263
264 // if Image Orientation (Patient) is not present
265 //    I create one, (as Axial) 
266 //    if Image Position (Patient) is not present
267 //       I create one, incrementing  zPositionComponent up by user supplied zSpacing
268 //    if Slice Location is not present 
269 //       I create one, as zPositionComponent
270 //
271 // Aware use is free to supply his own one !    
272     
273       if (! f->CheckIfEntryExist(0x0020,0x0037) ) // 0020 0037 DS 6 Image Orientation (Patient)
274       {
275          fh->InsertEntryString("1.0\\0.0\\0.0\\0.0\\1.0\\0.0",0x0020,0x0037, "DS"); //[1\0\0\0\1\0] : Axial
276
277          char charImagePosition[256];
278      
279          sprintf(charImagePosition,"0.0\\0.0\\%f",zPositionComponent);
280          zPositionComponent += zSpacing;
281  
282          if (! f->CheckIfEntryExist(0x0020,0x0032) ) //0020 0032 DS 3 Image Position (Patient)
283             fh->InsertEntryString(charImagePosition,0x0020,0x0032, "DS"); 
284     
285          if (! f->CheckIfEntryExist(0x0020,0x1041) ) // 0020 0x1041 DS 1 Slice Location
286          {
287             sprintf(charImagePosition,"%f",zPositionComponent);
288             fh->InsertEntryString(charImagePosition,0x0020,0x1041, "DS");
289           }    
290       } 
291
292 // ==================================================================================================
293
294               
295       fh->SetContentType(GDCM_NAME_SPACE::UNMODIFIED_PIXELS_IMAGE);
296       
297       lastFilename =  GDCM_NAME_SPACE::Util::GetName( fullFilename );
298       std::string fullWriteFilename = strDirNameout + GDCM_NAME_SPACE::GDCM_FILESEPARATOR 
299                                         + lastFilename;
300       if (verbose)
301          std::cout << "Write : [" << fullWriteFilename << "]" << std::endl;
302
303       if (!fh->Write(fullWriteFilename))
304       {
305          std::cout << "Fail to write :[" << fullWriteFilename << "]"
306                    << std::endl;
307       } 
308  
309       fh->Delete();
310       f->Delete();
311    }
312    return 1;
313 }