]> Creatis software - gdcm.git/blob - Example/exMoveImagesToSingleSerieUID.cxx
comments
[gdcm.git] / Example / exMoveImagesToSingleSerieUID.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: exMoveImagesToSingleSerieUID.cxx,v $
5   Language:  C++
6   Date:      $Date: 2007/10/01 09:33:20 $
7   Version:   $Revision: 1.6 $
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
119    bool verbose = ( 0 != am->ArgMgrDefined("verbose") );
120    
121    std::string patName = am->ArgMgrGetString("patname", "g^PatientName");
122    float zSpacing = am->ArgMgrGetFloat("zSpacing", 1.0);
123       
124    const char *dirIn   = am->ArgMgrGetString("dirin");
125    const char *dirOut  = am->ArgMgrGetString("dirout");
126
127    bool userDefinedStudy = ( 0 != am->ArgMgrDefined("userDefinedStudy") );
128    const char *studyUID  = am->ArgMgrGetString("studyUID");
129
130 // not described *on purpose* in the Usage ! 
131    bool userDefinedSerie = ( 0 != am->ArgMgrDefined("userDefinedSerie") );
132   
133    const char *serieUID  = am->ArgMgrGetString("serieUID");      
134  
135    int loadMode = GDCM_NAME_SPACE::LD_ALL;
136    if ( am->ArgMgrDefined("noshadowseq") )
137       loadMode |= GDCM_NAME_SPACE::LD_NOSHADOWSEQ;
138    else 
139    {
140    if ( am->ArgMgrDefined("noshadow") )
141          loadMode |= GDCM_NAME_SPACE::LD_NOSHADOW;
142       if ( am->ArgMgrDefined("noseq") )
143          loadMode |= GDCM_NAME_SPACE::LD_NOSEQ;
144    }
145         
146    /* if unused Param we give up */
147    if ( am->ArgMgrPrintUnusedLabels() )
148    {
149       am->ArgMgrUsage(usage);
150       delete am;
151       return 0;
152    }
153
154    delete am;  // ------ we don't need Arguments Manager any longer ------
155    
156  // ====== Deal with a (single level, single Patient) Directory ======
157  
158  
159    //std::cout << "dirIn [" << dirIn << "]" << std::endl;
160    if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(dirIn) )
161    {
162       std::cout << "KO : [" << dirIn << "] is not a Directory." << std::endl;
163       return 0;
164
165    }
166    else
167    {
168       if (verbose)
169          std::cout << "OK : [" << dirIn << "] is a Directory." << std::endl;
170    }   
171   
172    std::string systemCommand;
173    std::string strDirNameout(dirOut);          // to please gcc 4   
174    std::cout << "Check for output directory :[" << dirOut << "]."
175              <<std::endl;
176    if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(dirOut) )    // dirout not found
177    {
178       systemCommand = "mkdir " +strDirNameout;        // create it!
179       if (verbose)
180          std::cout << systemCommand << std::endl;
181       system (systemCommand.c_str());
182       if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(dirOut) ) // be sure it worked
183       {
184           std::cout << "KO : not a dir : [" << dirOut << "] (creation failure ?)" << std::endl;
185       return 0;
186
187       }
188       else
189       {
190         if (verbose)
191            std::cout << "Directory [" << dirOut << "] created." << std::endl;
192       }
193    }
194    else
195    {
196       std::cout << "Output Directory [" << dirOut << "] already exists; Used as is." << std::endl;
197    }  
198
199    GDCM_NAME_SPACE::DirList dirList(dirIn,false); // gets (at single level) the file list
200    GDCM_NAME_SPACE::DirListType fileList = dirList.GetFilenames();
201
202    // 'Study Instance UID'
203    // The user is allowed to create his own Study, 
204    //          keeping the same 'Study Instance UID' for various images
205    // The user may add images to a 'Manufacturer Study',
206    //          adding new Series to an already existing Study
207    std::string strStudyUID;
208    if ( !userDefinedStudy)
209       strStudyUID =  GDCM_NAME_SPACE::Util::CreateUniqueUID();
210    else
211       strStudyUID = studyUID;
212
213    // 'Serie Instance UID'
214    // The user is allowed to create his own Series, 
215    // keeping the same 'Serie Instance UID' for various images
216    // The user shouldn't add any image to a 'Manufacturer Serie'
217    // but there is no way no to prevent him for doing that
218
219    std::string strSerieUID; 
220    if ( !userDefinedSerie)   
221       strSerieUID =  GDCM_NAME_SPACE::Util::CreateUniqueUID();
222    else      
223       strSerieUID = serieUID;
224
225    GDCM_NAME_SPACE::File *f;
226    GDCM_NAME_SPACE::FileHelper *fh;
227    std::string fullFilename, lastFilename;
228    float zPositionComponent = 0.0;
229    
230    for( GDCM_NAME_SPACE::DirListType::iterator it  = fileList.begin();
231                                  it != fileList.end();
232                                  ++it )
233    {
234       fullFilename = *it;
235       f = GDCM_NAME_SPACE::File::New( );
236       f->SetLoadMode(loadMode);
237       f->SetFileName( it->c_str() );
238
239       if (verbose)
240          std::cout << "file [" << it->c_str() << "]" << std::endl;
241       if ( !f->Load() )
242       {
243          if (verbose)
244             std::cout << "fail to load [" << it->c_str() << "]" << std::endl;   
245          f->Delete();
246          continue;
247       }
248
249       // Load the pixels in RAM.
250    
251       fh = GDCM_NAME_SPACE::FileHelper::New(f);
252       fh->SetKeepOverlays( true );
253       uint8_t *imageData = fh->GetImageDataRaw(); // Don't convert (Gray Pixels + LUT) into (RGB pixels) ?!?
254       if (!imageData)
255          std::cout << "fail to read [" << it->c_str() << std::endl;
256       fh->SetWriteTypeToDcmExplVR();
257
258       fh->InsertEntryString(strStudyUID,0x0020,0x000d,"UI");      
259       fh->InsertEntryString(strSerieUID,0x0020,0x000e,"UI");
260       fh->InsertEntryString(patName,0x0010,0x0010, "PN");   // Patient's Name
261
262 // ==================================================================================================
263
264 // This is a dirty heuristics, but no other way :-(
265
266 // if Image Orientation (Patient) is not present
267 //    I create one, (as Axial) 
268 //    if Image Position (Patient) is not present
269 //       I create one, incrementing  zPositionComponent up by user supplied zSpacing
270 //    if Slice Location is not present 
271 //       I create one, as zPositionComponent
272 //
273 // Aware use is free to supply his own one !    
274     
275       if (! f->CheckIfEntryExist(0x0020,0x0037) ) // 0020 0037 DS 6 Image Orientation (Patient)
276       {
277          fh->InsertEntryString("1.0\\0.0\\0.0\\0.0\\1.0\\0.0",0x0020,0x0037, "DS"); //[1\0\0\0\1\0] : Axial
278
279          char charImagePosition[256];
280      
281          sprintf(charImagePosition,"0.0\\0.0\\%f",zPositionComponent);
282          zPositionComponent += zSpacing;
283  
284          if (! f->CheckIfEntryExist(0x0020,0x0032) ) //0020 0032 DS 3 Image Position (Patient)
285             fh->InsertEntryString(charImagePosition,0x0020,0x0032, "DS"); 
286     
287          if (! f->CheckIfEntryExist(0x0020,0x1041) ) // 0020 0x1041 DS 1 Slice Location
288          {
289             sprintf(charImagePosition,"%f",zPositionComponent);
290             fh->InsertEntryString(charImagePosition,0x0020,0x1041, "DS");
291           }    
292       } 
293
294 // ==================================================================================================
295
296               
297       fh->SetContentType(GDCM_NAME_SPACE::UNMODIFIED_PIXELS_IMAGE);
298       
299       lastFilename =  GDCM_NAME_SPACE::Util::GetName( fullFilename );
300       std::string fullWriteFilename = strDirNameout + GDCM_NAME_SPACE::GDCM_FILESEPARATOR 
301                                         + lastFilename;
302       if (verbose)
303          std::cout << "Write : [" << fullWriteFilename << "]" << std::endl;
304
305       if (!fh->Write(fullWriteFilename))
306       {
307          std::cout << "Fail to write :[" << fullWriteFilename << "]"
308                    << std::endl;
309       } 
310  
311       fh->Delete();
312       f->Delete();
313    }
314    return 1;
315 }