1 /*=========================================================================
4 Module: $RCSfile: PhilipsToBrucker2.cxx,v $
6 Date: $Date: 2006/01/17 15:58:30 $
7 Version: $Revision: 1.1 $
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 =========================================================================*/
18 #include "gdcmDocEntry.h"
19 #include "gdcmDicomDir.h"
20 #include "gdcmDicomDirPatient.h"
22 #include "gdcmFileHelper.h"
23 #include "gdcmDirList.h"
24 #include "gdcmDebug.h"
25 #include "gdcmArgMgr.h"
27 #include "gdcmSerieHelper.h"
33 * - explores recursively the given directory
34 * - keeps the requested series
35 * - orders the gdcm-readable found Files
36 * according to their Patient/Study/Serie/Image characteristics
37 * - fills a single level Directory with *all* the files,
38 * converted into a Brucker-like Dicom, Intags compliant
42 typedef std::map<std::string, gdcm::File*> SortedFiles;
44 int main(int argc, char *argv[])
47 " \n PhilipsToBrucker :\n ",
48 " - explores recursively the given directory, ",
49 " - keeps the requested series/ drops the unrequested series ",
50 " - orders the gdcm-readable found Files according to their ",
51 " (0x0010, 0x0010) Patient's Name ",
52 " (0x0020, 0x000e) Series Instance UID ",
53 " (0x0020, 0x0032) Image Position (Patient) ",
54 " (0x0018, 0x1060) Trigger Time ",
55 " (0x0018, 0x1312) In-plane Phase Encoding Direction ",
56 " - fills a single level (*) Directory with *all* the files, ",
57 " converted into a Brucker-like Dicom, InTags compliant ",
58 " (*) actually : creates as many directories as Patients ",
59 " -that shouldn't appear, but being carefull is better ! -",
61 " - fills a tree-like structure of directories as : ",
65 " Images are (sorted by Trigger Time / ",
66 " Encoding Direction (Row, Column) ",
68 " 0x0021, 0x1020 : 'SLICE INDEX' ",
69 " 0x0021, 0x1040 : 'FRAME INDEX' ",
70 " 0x0020, 0x0012 : 'SESSION INDEX' (Acquisition Number) ",
72 " PhilipsToBrucker dirin=rootDirectoryName ",
73 " dirout=outputDirectoryName ",
74 " { [keep= list of seriesNumber to process] ",
75 " | [drop= list of seriesNumber to ignore] } ",
76 " [extent=image suffix (.IMA, .NEMA, .DCM, ...)] ",
77 " [listonly] [split] ",
78 " [noshadowseq][noshadow][noseq] [verbose] [debug] ",
80 " dirout : will be created if doesn't exist ",
81 " keep : if user wants to process a limited number of series ",
82 " he gives the list of 'SeriesNumber' (tag 0020|0011) ",
83 " drop : if user wants to ignore a limited number of series ",
84 " he gives the list of 'SeriesNumber' (tag 0020|0011) ",
85 " SeriesNumber are short enough to be human readable ",
86 " e.g : 1030,1035,1043 ",
87 " extent : DO NOT forget the leading '.' ! ",
88 " split: creates a tree-like structure of directories as : ",
92 " ---- Images (sorted by Trigger Time) ",
93 " ----- Phase Encoding Direction (Row, Column) ",
94 " noshadowseq: user doesn't want to load Private Sequences ",
95 " noshadow : user doesn't want to load Private groups (odd number) ",
96 " noseq : user doesn't want to load Sequences ",
97 " verbose : user wants to run the program in 'verbose mode' ",
98 " debug : *developer* wants to run the program in 'debug mode' ",
101 // ----- Initialize Arguments Manager ------
103 gdcm::ArgMgr *am = new gdcm::ArgMgr(argc, argv);
105 if (argc == 1 || am->ArgMgrDefined("usage"))
107 am->ArgMgrUsage(usage); // Display 'usage'
113 dirNamein = am->ArgMgrGetString("dirin",(char *)".");
116 dirNameout = am->ArgMgrGetString("dirout",(char *)".");
118 int loadMode = gdcm::LD_ALL;
119 if ( am->ArgMgrDefined("noshadowseq") )
120 loadMode |= gdcm::LD_NOSHADOWSEQ;
123 if ( am->ArgMgrDefined("noshadow") )
124 loadMode |= gdcm::LD_NOSHADOW;
125 if ( am->ArgMgrDefined("noseq") )
126 loadMode |= gdcm::LD_NOSEQ;
129 if (am->ArgMgrDefined("debug"))
130 gdcm::Debug::DebugOn();
132 bool verbose = am->ArgMgrDefined("verbose");
133 bool split = am->ArgMgrDefined("split");
134 bool listonly = am->ArgMgrDefined("listonly");
137 int *seriesToKeep = am->ArgMgrGetListOfInt("keep", &nbSeriesToKeep);
139 int *seriesToDrop = am->ArgMgrGetListOfInt("drop", &nbSeriesToDrop);
141 if ( nbSeriesToKeep!=0 && nbSeriesToDrop!=0)
143 std::cout << "KEEP and DROP are mutually exclusive !" << std::endl;
148 char *extent = am->ArgMgrGetString("extent",".DCM");
150 // if unused Param we give up
151 if ( am->ArgMgrPrintUnusedLabels() )
153 am->ArgMgrUsage(usage);
157 delete am; // we don't need Argument Manager any longer
159 // ----- Begin Processing -----
161 if ( ! gdcm::DirList::IsDirectory(dirNamein) )
163 std::cout << "KO : [" << dirNamein << "] is not a Directory." << std::endl;
168 std::cout << "OK : [" << dirNamein << "] is a Directory." << std::endl;
171 std::string systemCommand;
173 std::cout << "Check for output directory :[" << dirNameout << "]."
175 if ( ! gdcm::DirList::IsDirectory(dirNameout) ) // dirout not found
177 std::string strDirNameout(dirNameout); // to please gcc 4
178 systemCommand = "mkdir " +strDirNameout; // create it!
180 std::cout << systemCommand << std::endl;
181 system (systemCommand.c_str());
182 if ( ! gdcm::DirList::IsDirectory(dirNameout) ) // be sure it worked
184 std::cout << "KO : not a dir : [" << dirNameout << "] (creation failure ?)" << std::endl;
189 std::cout << "Directory [" << dirNameout << "] created." << std::endl;
194 std::cout << "Output Directory [" << dirNameout << "] already exists; Used as is." << std::endl;
197 std::string strDirNamein(dirNamein);
198 gdcm::DirList dirList(strDirNamein, true); // get recursively the list of files
202 std::cout << "------------List of found files ------------" << std::endl;
206 gdcm::DirListType fileNames;
207 fileNames = dirList.GetFilenames();
208 gdcm::SerieHelper *s; // Needed only to may use SerieHelper::AddSeriesDetail()
209 s = gdcm::SerieHelper::New();
212 std::cout << "---------------Print Serie--------------" << std::endl;
213 s->SetDirectory(dirNamein, true); // true : recursive exploration
214 s->SetUseSeriesDetails(true);
215 s->AddSeriesDetail(0x0018, 0x1312);
220 gdcm::FileHelper *fh;
222 std::cout << "---------------Print Unique Series identifiers---------"
224 std::string uniqueSeriesIdentifier;
226 for (gdcm::DirListType::iterator it = fileNames.begin();
227 it != fileNames.end();
230 std::cout << "File Name : " << *it << std::endl;
231 f = gdcm::File::New();
232 f->SetLoadMode(gdcm::LD_ALL);
233 f->SetFileName( *it );
236 uniqueSeriesIdentifier=s->CreateUniqueSeriesIdentifier(f);
238 uniqueSeriesIdentifier << "]" << std::endl;
244 std::cout << "------------------Print Break levels-----------------" << std::endl;
246 std::string userFileIdentifier;
249 s->AddSeriesDetail(0x0010, 0x0010, false); // Patient's Name
250 s->AddSeriesDetail(0x0020, 0x000e, false); // Series Instance UID
251 s->AddSeriesDetail(0x0020, 0x0032, false); // Image Position (Patient)
252 s->AddSeriesDetail(0x0018, 0x1060, true); // Trigger Time (true: convert to keep numerical order)
253 s->AddSeriesDetail(0x0018, 0x1312, false); // In-plane Phase Encoding Direction
255 for (gdcm::DirListType::iterator it = fileNames.begin();
256 it != fileNames.end();
259 f = gdcm::File::New();
260 f->SetLoadMode(loadMode);
261 f->SetFileName( *it );
264 // keep only requested Series
265 std::string strSeriesNumber;
270 if (nbSeriesToKeep != 0)
272 strSeriesNumber = f->GetEntryString(0x0020, 0x0011 );
273 seriesNumber = atoi( strSeriesNumber.c_str() );
274 for (j=0;j<nbSeriesToKeep; j++)
276 if(seriesNumber == seriesToKeep[j])
288 // drop all unrequested Series
290 if (nbSeriesToDrop != 0)
292 strSeriesNumber = f->GetEntryString(0x0020, 0x0011 );
293 seriesNumber = atoi( strSeriesNumber.c_str() );
294 for (j=0;j<nbSeriesToDrop; j++)
296 if(seriesNumber == seriesToDrop[j])
309 userFileIdentifier=s->CreateUserDefinedFileIdentifier(f);
310 // userFileIdentifier += "_";
311 //userFileIdentifier += *it;
313 userFileIdentifier << "]" << std::endl;
315 // storing in a map ensures automatic sorting !
316 sf[userFileIdentifier] = f;
319 std::vector<std::string> tokens;
320 std::string fullFilename, lastFilename;
321 std::string previousPatientName, currentPatientName;
322 std::string previousSerieInstanceUID, currentSerieInstanceUID;
323 std::string previousImagePosition, currentImagePosition;
324 std::string previousPhaseEncodingDirection, currentPhaseEncodingDirection;
325 std::string previousTriggerTime, currentTriggerTime;
327 std::string writeDir, currentWriteDir;
328 std::string currentPatientWriteDir, currentSerieWriteDir,
329 currentPositionWriteDir, currentPhaseEncodingDirectionWriteDir;
331 std::string fullWriteFilename;
332 std::string strExtent(extent);
334 writeDir = gdcm::Util::NormalizePath(dirNameout);
335 SortedFiles::iterator it2;
337 previousPatientName = "";
338 previousSerieInstanceUID = "";
339 previousImagePosition = "";
340 previousPhaseEncodingDirection = "";
341 previousTriggerTime = "";
347 gdcm::File *currentFile;
349 for (it2 = sf.begin() ; it2 != sf.end(); ++it2)
351 currentFile = it2->second;
353 fullFilename = currentFile->GetFileName();
354 lastFilename = gdcm::Util::GetName( fullFilename );
355 std::cout << "Try to write" <<lastFilename << std::endl;
358 gdcm::Util::Tokenize (it2->first, tokens, "_");
360 currentPatientName = tokens[0];
361 currentSerieInstanceUID = tokens[1];
362 currentImagePosition = tokens[2];
363 currentTriggerTime = tokens[3];
364 currentPhaseEncodingDirection = tokens[4];
366 if ( currentImagePosition[0] == '-')
367 currentImagePosition[0] = 'M';
368 if ( currentImagePosition[0] == '+')
369 currentImagePosition[0] = 'P';
371 if (previousPatientName != currentPatientName)
373 previousPatientName = currentPatientName;
375 std::cout << "==== new Patient [" << currentPatientName << "]" << std::endl;
377 previousPatientName = currentPatientName;
378 previousSerieInstanceUID = ""; //currentSerieInstanceUID;
379 previousImagePosition = ""; //currentImagePosition;
380 previousTriggerTime = "";
381 previousPhaseEncodingDirection = ""; //currentPhaseEncodingDirection;
383 currentPatientWriteDir = writeDir + currentPatientName;
384 //if ( ! gdcm::DirList::IsDirectory(currentPatientWriteDir) )
386 systemCommand = "mkdir " + currentPatientWriteDir;
388 std::cout << systemCommand << std::endl;
389 system ( systemCommand.c_str() );
393 if (previousSerieInstanceUID != currentSerieInstanceUID)
396 std::cout << "==== === new Serie [" << currentSerieInstanceUID << "]"
400 currentSerieWriteDir = currentPatientWriteDir + gdcm::GDCM_FILESEPARATOR
401 + currentSerieInstanceUID;
402 systemCommand = "mkdir " + currentSerieWriteDir;
403 system (systemCommand.c_str());
405 previousSerieInstanceUID = currentSerieInstanceUID;
406 previousImagePosition = ""; //currentImagePosition;
407 previousPhaseEncodingDirection = ""; //currentPhaseEncodingDirection;
410 if (previousImagePosition != currentImagePosition)
415 std::cout << "=== === === new Position [" << currentImagePosition << "]"
419 currentPositionWriteDir = currentSerieWriteDir + gdcm::GDCM_FILESEPARATOR
420 + currentImagePosition;
421 systemCommand = "mkdir " + currentPositionWriteDir;
422 system (systemCommand.c_str());
424 previousImagePosition = currentImagePosition;
425 previousPhaseEncodingDirection = ""; //currentPhaseEncodingDirection;
429 // We don't split on Row/Column!
431 if (previousPhaseEncodingDirection != currentPhaseEncodingDirection)
434 std::cout << "==== === === === new PhaseEncodingDirection ["
435 << currentPhaseEncodingDirection << "]" << std::endl;
439 currentPhaseEncodingDirectionWriteDir = currentPositionWriteDir
440 + gdcm::GDCM_FILESEPARATOR
441 + currentPhaseEncodingDirection;
442 systemCommand = "mkdir " + currentPhaseEncodingDirectionWriteDir;
443 system (systemCommand.c_str());
446 previousPhaseEncodingDirection = currentPhaseEncodingDirection;
451 std::cout << "--- --- --- --- --- " << (it2->second)->GetFileName()
454 if ( gdcm::Debug::GetDebugFlag())
455 std::cout << "--- --- --- --- --- " << it2->first << " "
456 << (it2->second)->GetFileName() << " "
457 << gdcm::Util::GetName( fullFilename ) << std::endl;
459 // Transform the image to be 'Brucker-Like'
460 // ----------------------------------------
462 // Deal with 0x0019, 0x1000 : 'FOV'
463 int nX = currentFile->GetXSize();
464 int nY = currentFile->GetYSize();
465 float pxSzX = currentFile->GetXSpacing();
466 float pxSzY = currentFile->GetYSpacing();
468 sprintf(fov, "%f\\%f",nX*pxSzX, nY*pxSzY);
469 currentFile->InsertEntryString(fov, 0x0019, 0x1000, "DS");
471 // Deal with 0x0020, 0x0012 : 'SESSION INDEX' (Acquisition Number)
472 std::string chSessionIndex;
473 if (currentPhaseEncodingDirection == "ROW")
474 chSessionIndex = "1";
476 chSessionIndex = "2"; // suppose it's "COLUMN" !
477 currentFile->InsertEntryString(chSessionIndex, 0x0020, 0x0012, "IS");
479 // Deal with 0x0021, 0x1020 : 'SLICE INDEX'
480 char chSliceIndex[5];
481 sprintf(chSliceIndex, "%04d", sliceIndex);
482 std::string strChSliceIndex(chSliceIndex);
483 currentFile->InsertEntryString(strChSliceIndex, 0x0021, 0x1020, "IS");
485 // Deal with 0x0021, 0x1040 : 'FRAME INDEX'
486 char chFrameIndex[5];
487 sprintf(chFrameIndex, "%04d", frameIndex);
488 currentFile->InsertEntryString(chFrameIndex, 0x0021, 0x1040, "IS");
502 //fullWriteFilename = currentPhaseEncodingDirectionWriteDir + gdcm::GDCM_FILESEPARATOR
503 // + lastFilename + strExtent;
504 fullWriteFilename = currentPositionWriteDir + gdcm::GDCM_FILESEPARATOR
505 + lastFilename + strExtent;
507 fullWriteFilename = currentPatientWriteDir + gdcm::GDCM_FILESEPARATOR
508 + lastFilename + strExtent;
511 systemCommand = "cp " + fullFilename + " " + fullWriteFilename;
512 std::cout << systemCommand << std::endl;
513 system ( systemCommand.c_str() );
516 // Load the pixels in RAM.
518 fh = gdcm::FileHelper::New(currentFile);
519 fh->GetImageDataRaw(); // Don't convert (Gray Pixels + LUT) into (RGB pixels) ?!?
520 fh->SetWriteTypeToDcmExplVR();
521 if (!fh->Write(fullWriteFilename))
523 std::cout << "Fail to write :[" << fullWriteFilename << "]"
526 fh->gdcm::FileHelper::Delete();