1 /*=========================================================================
4 Module: $RCSfile: exMoveImagesToSingleSerieUID.cxx,v $
6 Date: $Date: 2007/10/01 09:33:20 $
7 Version: $Revision: 1.6 $
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.
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.
17 =========================================================================*/
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!)
25 Le programme 'de convertion' s'utilise comme les 'filtres LibIDO'
26 (mots-clés et valeurs par defaut).
28 exMoveImagesToSingleSerieUID
30 Converts the a Dicom file inside a single-level Directory
31 into a 'Single Study UID - Single SerieUID
33 exMoveImagesToSingleSerieUID
34 dirin=inputDirectoryName
35 dirout=outputDirectoryName
36 [studyUID = ] [patName = ] [Zspacing = ]
37 [ { [noshadowseq] | [noshadow][noseq] } ] [debug]
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
48 dirin : directory (un seul niveau) contenant les images
49 dirout : directory de sortie (cree s'il n'existe pas); le nom des images
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
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)
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
64 // if Slice Location is not present
65 // I create one, as zPositionComponent
69 #include "gdcmFileHelper.h"
70 #include "gdcmCommon.h"
71 #include "gdcmDebug.h"
72 #include "gdcmDirList.h"
75 #include "gdcmArgMgr.h"
79 int main(int argc, char *argv[])
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]",
91 " dirin : single-level Directory containing the images ",
92 " (no recursive parsing) ",
93 " dirout : will be created if doesn't exist ",
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' ",
105 // ----- Initialize Arguments Manager ------
107 GDCM_NAME_SPACE::ArgMgr *am = new GDCM_NAME_SPACE::ArgMgr(argc, argv);
109 if (am->ArgMgrDefined("usage") || argc == 1)
111 am->ArgMgrUsage(usage); // Display 'usage'
116 if (am->ArgMgrDefined("debug"))
117 GDCM_NAME_SPACE::Debug::DebugOn();
119 bool verbose = ( 0 != am->ArgMgrDefined("verbose") );
121 std::string patName = am->ArgMgrGetString("patname", "g^PatientName");
122 float zSpacing = am->ArgMgrGetFloat("zSpacing", 1.0);
124 const char *dirIn = am->ArgMgrGetString("dirin");
125 const char *dirOut = am->ArgMgrGetString("dirout");
127 bool userDefinedStudy = ( 0 != am->ArgMgrDefined("userDefinedStudy") );
128 const char *studyUID = am->ArgMgrGetString("studyUID");
130 // not described *on purpose* in the Usage !
131 bool userDefinedSerie = ( 0 != am->ArgMgrDefined("userDefinedSerie") );
133 const char *serieUID = am->ArgMgrGetString("serieUID");
135 int loadMode = GDCM_NAME_SPACE::LD_ALL;
136 if ( am->ArgMgrDefined("noshadowseq") )
137 loadMode |= GDCM_NAME_SPACE::LD_NOSHADOWSEQ;
140 if ( am->ArgMgrDefined("noshadow") )
141 loadMode |= GDCM_NAME_SPACE::LD_NOSHADOW;
142 if ( am->ArgMgrDefined("noseq") )
143 loadMode |= GDCM_NAME_SPACE::LD_NOSEQ;
146 /* if unused Param we give up */
147 if ( am->ArgMgrPrintUnusedLabels() )
149 am->ArgMgrUsage(usage);
154 delete am; // ------ we don't need Arguments Manager any longer ------
156 // ====== Deal with a (single level, single Patient) Directory ======
159 //std::cout << "dirIn [" << dirIn << "]" << std::endl;
160 if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(dirIn) )
162 std::cout << "KO : [" << dirIn << "] is not a Directory." << std::endl;
169 std::cout << "OK : [" << dirIn << "] is a Directory." << std::endl;
172 std::string systemCommand;
173 std::string strDirNameout(dirOut); // to please gcc 4
174 std::cout << "Check for output directory :[" << dirOut << "]."
176 if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(dirOut) ) // dirout not found
178 systemCommand = "mkdir " +strDirNameout; // create it!
180 std::cout << systemCommand << std::endl;
181 system (systemCommand.c_str());
182 if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(dirOut) ) // be sure it worked
184 std::cout << "KO : not a dir : [" << dirOut << "] (creation failure ?)" << std::endl;
191 std::cout << "Directory [" << dirOut << "] created." << std::endl;
196 std::cout << "Output Directory [" << dirOut << "] already exists; Used as is." << std::endl;
199 GDCM_NAME_SPACE::DirList dirList(dirIn,false); // gets (at single level) the file list
200 GDCM_NAME_SPACE::DirListType fileList = dirList.GetFilenames();
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();
211 strStudyUID = studyUID;
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
219 std::string strSerieUID;
220 if ( !userDefinedSerie)
221 strSerieUID = GDCM_NAME_SPACE::Util::CreateUniqueUID();
223 strSerieUID = serieUID;
225 GDCM_NAME_SPACE::File *f;
226 GDCM_NAME_SPACE::FileHelper *fh;
227 std::string fullFilename, lastFilename;
228 float zPositionComponent = 0.0;
230 for( GDCM_NAME_SPACE::DirListType::iterator it = fileList.begin();
231 it != fileList.end();
235 f = GDCM_NAME_SPACE::File::New( );
236 f->SetLoadMode(loadMode);
237 f->SetFileName( it->c_str() );
240 std::cout << "file [" << it->c_str() << "]" << std::endl;
244 std::cout << "fail to load [" << it->c_str() << "]" << std::endl;
249 // Load the pixels in RAM.
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) ?!?
255 std::cout << "fail to read [" << it->c_str() << std::endl;
256 fh->SetWriteTypeToDcmExplVR();
258 fh->InsertEntryString(strStudyUID,0x0020,0x000d,"UI");
259 fh->InsertEntryString(strSerieUID,0x0020,0x000e,"UI");
260 fh->InsertEntryString(patName,0x0010,0x0010, "PN"); // Patient's Name
262 // ==================================================================================================
264 // This is a dirty heuristics, but no other way :-(
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
273 // Aware use is free to supply his own one !
275 if (! f->CheckIfEntryExist(0x0020,0x0037) ) // 0020 0037 DS 6 Image Orientation (Patient)
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
279 char charImagePosition[256];
281 sprintf(charImagePosition,"0.0\\0.0\\%f",zPositionComponent);
282 zPositionComponent += zSpacing;
284 if (! f->CheckIfEntryExist(0x0020,0x0032) ) //0020 0032 DS 3 Image Position (Patient)
285 fh->InsertEntryString(charImagePosition,0x0020,0x0032, "DS");
287 if (! f->CheckIfEntryExist(0x0020,0x1041) ) // 0020 0x1041 DS 1 Slice Location
289 sprintf(charImagePosition,"%f",zPositionComponent);
290 fh->InsertEntryString(charImagePosition,0x0020,0x1041, "DS");
294 // ==================================================================================================
297 fh->SetContentType(GDCM_NAME_SPACE::UNMODIFIED_PIXELS_IMAGE);
299 lastFilename = GDCM_NAME_SPACE::Util::GetName( fullFilename );
300 std::string fullWriteFilename = strDirNameout + GDCM_NAME_SPACE::GDCM_FILESEPARATOR
303 std::cout << "Write : [" << fullWriteFilename << "]" << std::endl;
305 if (!fh->Write(fullWriteFilename))
307 std::cout << "Fail to write :[" << fullWriteFilename << "]"