1 /*=========================================================================
4 Module: $RCSfile: exMoveImagesToSingleSerieUID.cxx,v $
6 Date: $Date: 2007/05/23 14:18:05 $
7 Version: $Revision: 1.5 $
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();
118 int verbose = am->ArgMgrDefined("verbose");
120 std::string patName = am->ArgMgrGetString("patname", "g^PatientName");
121 float zSpacing = am->ArgMgrGetFloat("zSpacing", 1.0);
123 const char *dirIn = am->ArgMgrGetString("dirin");
124 const char *dirOut = am->ArgMgrGetString("dirout");
126 int userDefinedStudy = am->ArgMgrDefined("studyUID");
127 const char *studyUID = am->ArgMgrGetString("studyUID");
129 // not described *on purpose* in the Usage !
130 int userDefinedSerie = am->ArgMgrDefined("serieUID");
131 const char *serieUID = am->ArgMgrGetString("serieUID");
133 int loadMode = GDCM_NAME_SPACE::LD_ALL;
134 if ( am->ArgMgrDefined("noshadowseq") )
135 loadMode |= GDCM_NAME_SPACE::LD_NOSHADOWSEQ;
138 if ( am->ArgMgrDefined("noshadow") )
139 loadMode |= GDCM_NAME_SPACE::LD_NOSHADOW;
140 if ( am->ArgMgrDefined("noseq") )
141 loadMode |= GDCM_NAME_SPACE::LD_NOSEQ;
144 /* if unused Param we give up */
145 if ( am->ArgMgrPrintUnusedLabels() )
147 am->ArgMgrUsage(usage);
152 delete am; // ------ we don't need Arguments Manager any longer ------
154 // ====== Deal with a (single level, single Patient) Directory ======
157 //std::cout << "dirIn [" << dirIn << "]" << std::endl;
158 if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(dirIn) )
160 std::cout << "KO : [" << dirIn << "] is not a Directory." << std::endl;
167 std::cout << "OK : [" << dirIn << "] is a Directory." << std::endl;
170 std::string systemCommand;
171 std::string strDirNameout(dirOut); // to please gcc 4
172 std::cout << "Check for output directory :[" << dirOut << "]."
174 if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(dirOut) ) // dirout not found
176 systemCommand = "mkdir " +strDirNameout; // create it!
178 std::cout << systemCommand << std::endl;
179 system (systemCommand.c_str());
180 if ( ! GDCM_NAME_SPACE::DirList::IsDirectory(dirOut) ) // be sure it worked
182 std::cout << "KO : not a dir : [" << dirOut << "] (creation failure ?)" << std::endl;
189 std::cout << "Directory [" << dirOut << "] created." << std::endl;
194 std::cout << "Output Directory [" << dirOut << "] already exists; Used as is." << std::endl;
197 GDCM_NAME_SPACE::DirList dirList(dirIn,false); // gets (at single level) the file list
198 GDCM_NAME_SPACE::DirListType fileList = dirList.GetFilenames();
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();
209 strStudyUID = studyUID;
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
218 std::string strSerieUID;
219 if ( !userDefinedSerie)
220 strSerieUID = GDCM_NAME_SPACE::Util::CreateUniqueUID();
222 strSerieUID = serieUID;
224 GDCM_NAME_SPACE::File *f;
225 GDCM_NAME_SPACE::FileHelper *fh;
226 std::string fullFilename, lastFilename;
227 float zPositionComponent = 0.0;
229 for( GDCM_NAME_SPACE::DirListType::iterator it = fileList.begin();
230 it != fileList.end();
234 f = GDCM_NAME_SPACE::File::New( );
235 f->SetLoadMode(loadMode);
236 f->SetFileName( it->c_str() );
239 std::cout << "file [" << it->c_str() << "]" << std::endl;
243 std::cout << "fail to load [" << it->c_str() << "]" << std::endl;
248 // Load the pixels in RAM.
250 fh = GDCM_NAME_SPACE::FileHelper::New(f);
251 uint8_t *imageData = fh->GetImageDataRaw(); // Don't convert (Gray Pixels + LUT) into (RGB pixels) ?!?
253 std::cout << "fail to read [" << it->c_str() << std::endl;
254 fh->SetWriteTypeToDcmExplVR();
256 fh->InsertEntryString(strStudyUID,0x0020,0x000d,"UI");
257 fh->InsertEntryString(strSerieUID,0x0020,0x000e,"UI");
258 fh->InsertEntryString(patName,0x0010,0x0010, "PN"); // Patient's Name
260 // ==================================================================================================
262 // This is a dirty heuristics, but no other way :-(
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
271 // Aware use is free to supply his own one !
273 if (! f->CheckIfEntryExist(0x0020,0x0037) ) // 0020 0037 DS 6 Image Orientation (Patient)
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
277 char charImagePosition[256];
279 sprintf(charImagePosition,"0.0\\0.0\\%f",zPositionComponent);
280 zPositionComponent += zSpacing;
282 if (! f->CheckIfEntryExist(0x0020,0x0032) ) //0020 0032 DS 3 Image Position (Patient)
283 fh->InsertEntryString(charImagePosition,0x0020,0x0032, "DS");
285 if (! f->CheckIfEntryExist(0x0020,0x1041) ) // 0020 0x1041 DS 1 Slice Location
287 sprintf(charImagePosition,"%f",zPositionComponent);
288 fh->InsertEntryString(charImagePosition,0x0020,0x1041, "DS");
292 // ==================================================================================================
295 fh->SetContentType(GDCM_NAME_SPACE::UNMODIFIED_PIXELS_IMAGE);
297 lastFilename = GDCM_NAME_SPACE::Util::GetName( fullFilename );
298 std::string fullWriteFilename = strDirNameout + GDCM_NAME_SPACE::GDCM_FILESEPARATOR
301 std::cout << "Write : [" << fullWriteFilename << "]" << std::endl;
303 if (!fh->Write(fullWriteFilename))
305 std::cout << "Fail to write :[" << fullWriteFilename << "]"