]> Creatis software - gdcm.git/blob - Example/PcpdenseToDicom.cxx
Code factorization
[gdcm.git] / Example / PcpdenseToDicom.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: PcpdenseToDicom.cxx,v $
5   Language:  C++
6   Date:      $Date: 2011/09/12 11:11:30 $
7   Version:   $Revision: 1.10 $
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 #include <fstream>
20 #include <iostream>
21 //#include <values.h>
22
23 #if defined(__BORLANDC__)
24 #include <ctype.h>
25 #endif
26
27 #include "gdcmFile.h"
28 #include "gdcmFileHelper.h"
29 #include "gdcmDebug.h"
30 #include "gdcmDirList.h"
31 #include "gdcmUtil.h"
32 #include "gdcmArgMgr.h"
33
34 /**
35   * \brief   
36   *  Converts the "pcpdense" ".txt" (2008 version)  files into 16 bits Dicom Files,
37   * Hope they don't change soon!
38   */  
39
40 void MakeDicomImage(unsigned short int *tabVal, int X, int Y, std::string dcmImageName, const char * patientName, int nbFrames,
41                     std::string studyUID, std::string serieUID, std::string SerieDescr, int imgNum, bool m );
42
43 void LoadImage(std::ifstream &from,  unsigned short int *, int multFact);
44
45 void LoadImageX2(std::ifstream &from, unsigned short int *, int multFact);      
46 void RotateImage(unsigned short int *image, unsigned short int *image2, int NX, int NY);
47 void FlipImage  (unsigned short int *image, unsigned short int *image2, int NX, int NY);
48
49 void WholeBazar (unsigned short int *image, int NX, int NY, int numberOfSlices, std::string strStudyUID, std::string serieDescr, const char* patientName, bool multiframe, bool X2, int multFact, const char *rootfilename);
50 bool verbose;
51
52 int main(int argc, char *argv[])
53 {
54    START_USAGE(usage)
55    " \n pcpdenseToDicom :\n                                                   ",
56    "        Converts the '.txt' files into 16 bits Dicom-like Files,          ",
57    " usage:                                                                   ",
58    " pcpdenseToDicom rootfilename=...                                         ",
59    "                 (e.g.. :   meas_MID380_DENSE_stacked_slices_aif_FID81637)",
60    "                 numberOfSlices =  (default : 3)                          ",
61    "                 X2 : multiply x 2 image size                             ",
62    "                 multFact = (default : 1000) multiply pixel value by...   ",
63    "                 m :create multiframe files instead of image stacks       ", 
64    "                 [patientname = Patient's name]                           ",
65    "                 [verbose] [debug]                                        ",
66    "                                                                          ",
67    " verbose  : user wants to run the program in 'verbose mode'               ",
68    " debug    : *developer*  wants to run the program in 'debug mode'         ",
69    FINISH_USAGE
70
71    // ----- Initialize Arguments Manager ------
72       
73    GDCM_NAME_SPACE::ArgMgr *am = new GDCM_NAME_SPACE::ArgMgr(argc, argv);
74   
75    if (argc == 1 || am->ArgMgrDefined("usage")) 
76    {
77       am->ArgMgrUsage(usage); // Display 'usage'
78       delete am;
79       return 0;
80    }
81    // Seems that ArgMgrWantString doesn't work on MacOS   
82    if(!am->ArgMgrDefined("rootfilename"))
83    {
84       std::cout << "'rootfilename' is mandatory" << std::endl;
85       exit(0);   
86    }
87  
88    const char *rootfilename = am->ArgMgrWantString("rootfilename",usage);
89    int numberOfSlices       = am->ArgMgrGetInt("numberOfSlices",3);
90    int multFact             = am->ArgMgrGetInt("multFact",1000); 
91    const char *patientName  = am->ArgMgrGetString("patientname", "Patient^Name");
92          
93    if (am->ArgMgrDefined("debug"))
94       GDCM_NAME_SPACE::Debug::DebugOn();
95
96    verbose         = ( 0 != am->ArgMgrDefined("verbose") );    
97    bool X2         = ( 0 != am->ArgMgrDefined("X2") );
98    bool multiframe = ( 0 != am->ArgMgrDefined("m") );
99
100    // if unused Param we give up
101    if ( am->ArgMgrPrintUnusedLabels() )
102    { 
103       am->ArgMgrUsage(usage);
104       delete am;
105       return 0;
106    }
107    delete am;  // we don't need Argument Manager any longer
108
109    // ----- Begin Processing -----
110    
111    std::ostringstream Ecc;
112    std::ostringstream perf;
113    std::ostringstream WashoutTc;
114
115    std::string strSerieUID; 
116    std::string strStudyUID =  GDCM_NAME_SPACE::Util::CreateUniqueUID();
117    std::string /*dcmImageName,*/ textFileName, patientname, serieDescr;
118    std::string deb(rootfilename);
119    
120    unsigned short int *image;
121 //   unsigned short int *image2;
122   
123    int NX, NY;
124      
125   // Get some info
126   // -------------
127
128    {
129         Ecc.str(rootfilename); 
130         Ecc   << Ecc.str() << "_s0" << "_Ecc.txt";
131
132         std::ifstream fromEcc( Ecc.str().c_str() );             
133         if ( !fromEcc )
134         {
135            std::cout << "Can't open file [" << Ecc.str() << "]" << std::endl;
136            exit(0);
137         }
138         std::string str1;
139
140          fromEcc >> str1;
141          fromEcc >> str1;
142
143          fromEcc >> NX;
144          fromEcc >> NY;
145          std::cout << "NX, NY : " << NX << ", " << NY << std::endl; 
146    }
147
148    
149 serieDescr = "Ecc";      
150 WholeBazar(image,  NX,  NY,  numberOfSlices, strStudyUID, serieDescr, patientName,  multiframe, X2, multFact, rootfilename);
151
152 serieDescr = "perf";
153 WholeBazar(image,  NX,  NY,  numberOfSlices, strStudyUID, serieDescr, patientName,  multiframe, X2, multFact, rootfilename);
154
155 serieDescr = "WashoutTc";
156 WholeBazar(image,  NX,  NY,  numberOfSlices, strStudyUID, serieDescr, patientName,  multiframe, X2, multFact, rootfilename);
157
158   // delete []image;
159    return 1;            
160 }
161
162 // =====================================================================================================================
163
164 void LoadImage(std::ifstream &from,  unsigned short int *image, int multFact)
165 {
166 // in any file ".txt" :
167
168 /*
169 XY Dimensions           47          50
170      0.000000     0.000000     0.000000     0.000000     0.000000     0.000000
171      ...
172 */  
173
174    if (!from)
175       return;
176    
177    std::string str1;
178
179    from >> str1;
180    from >> str1;
181     
182    int NX, NY;
183    from >> NX;
184    from >> NY;
185    std::cout << "NX, NY : " << NX << ", " << NY << std::endl; 
186
187    float pixelValue;
188      
189     int i, j;
190     for( i=0;i<NY;i++) {
191         for(j=0;j<NX;j++) {
192            from >> pixelValue;
193            image[i*NX+j] = (unsigned short int)(pixelValue * multFact); // Why do we multiply by 1000? // JPR
194         }
195      }
196 }
197
198
199 // =====================================================================================================================
200
201 void LoadImageX2(std::ifstream &from,  unsigned short int *image, int multFact )
202 {
203 // in any file ".txt" :
204
205 /*
206 XY Dimensions           47          50
207      0.000000     0.000000     0.000000     0.000000     0.000000     0.000000
208      ...
209 */  
210
211    if (!from)
212       return;
213
214    std::string str1;
215
216     from >> str1;
217     from >> str1;
218     
219     int NX, NY;
220     from >> NX;
221     from >> NY;
222     std::cout << "NX, NY : " << NX << ", " << NY << std::endl; 
223
224      int k;
225      for( k=0;k<NX*NY*4;k++)
226           image[k] = 0;
227
228     float pixelValue;
229      
230      int i, j;
231  /*
232      for( i=0;i<NY;i++) {
233            for(j=0;j<NX;j++) {
234               from >> pixelValue;
235               pixelValue*=1000.;  // Why do we multiply by 1000? // JPR
236               image[i*4*NX + j*2] = image[i*4*NX + j*2+1] =  image[(i*4+2)*NX + j*2] =  image[(i*4+2)*NX + j*2+1] = (unsigned short int)(pixelValue);  
237            }
238      }
239  */
240  
241      int lgrLigneNvlleImage = NX+NX;
242      int debLigneNvlleImage = 0;
243      for( i=0;i<NY;i++) {
244            for(j=0;j<NX;j++) {
245               from >> pixelValue;
246               pixelValue*=multFact;  // Why do we multiply by 1000? // JPR
247               image[debLigneNvlleImage + j+j] = 
248               image[debLigneNvlleImage + j+j +1] = 
249               image[debLigneNvlleImage + lgrLigneNvlleImage +j+j] = 
250               image[debLigneNvlleImage + lgrLigneNvlleImage + j+j +1] = 
251                  (unsigned short int)(pixelValue);
252            }
253            debLigneNvlleImage += 2*lgrLigneNvlleImage;  
254      }
255 }
256 // =====================================================================================================================================
257 void RotateImage(unsigned short int *image, unsigned short int *image2, int NX, int NY)
258 {
259      int k = 0;
260      for( int i=0;i<NY;i++) {
261            for(int j=0;j<NX;j++) {
262               image2[NY*j + i] = image[k];
263               k++;   
264            }
265      }
266 }
267
268
269 // =====================================================================================================================================
270 void FlipImage(unsigned short int *image, unsigned short int *image2, int NX, int NY)
271 {
272      unsigned short int temp;
273      for(int i=0;i<NY/2;i++) {
274            for(int j=0;j<NX;j++) {
275               temp = image[NX*i + j];
276               image2[NX*i + j] = image[NX*(NY-i-1) + j];
277               image2[NX*(NY-i-1) + j] = temp;
278            }
279      }
280 }
281
282 // =====================================================================================================================================
283
284 void WholeBazar(unsigned short int *image, int NX, int NY, int numberOfSlices, std::string strStudyUID, std::string serieDescr, const char *patientName, bool multiframe, bool X2, int multFact, const char *rootfilename)
285 {   
286    unsigned short int *image2;
287    std::string strSerieUID =  GDCM_NAME_SPACE::Util::CreateUniqueUID();
288    std::string deb(rootfilename);
289    std::ostringstream Ecc;
290    std::string dcmImageName;
291
292    int mult;
293    if (X2)
294       mult=4;
295    else
296       mult=1;
297
298    if (multiframe) {
299       image  = new unsigned short int[NX*NY*mult*numberOfSlices];
300       image2 = new unsigned short int[NX*NY*mult*numberOfSlices];
301    } else {
302       image  = new unsigned short int[NX*NY*mult];
303       image2 = new unsigned short int[NX*NY*mult];
304    }
305    
306    if (!multiframe) {            
307      for (int i=0; i<numberOfSlices; i++)
308      {  
309         Ecc.str(rootfilename); 
310         //Ecc << Ecc.str() << "_s" << i << "_Ecc.txt";
311         Ecc << Ecc.str() << "_s" << i << "_" << serieDescr << ".txt";
312       
313         std::ifstream fromEcc( Ecc.str().c_str() );             
314         if ( !fromEcc )
315         {
316            std::cout << "Can't open file [" << Ecc.str() << "]" << std::endl;
317            exit(0);
318         }
319         std::cout << "Open file [" << Ecc.str() << "] : OK" << std::endl;
320         dcmImageName = Ecc.str() + ".dcm";
321
322         if (X2)
323         {
324            LoadImageX2(fromEcc, image, multFact);
325            RotateImage(image, image2, NX*2, NY*2);
326            FlipImage(image2,  image2, NY*2, NX*2);  
327            MakeDicomImage(image, NY*2, NX*2, dcmImageName, patientName, 1, strStudyUID, strSerieUID, serieDescr, i, multiframe );
328         }
329         else
330         {  
331            LoadImage(fromEcc, image, multFact);
332            RotateImage(image, image2, NX, NY);
333            FlipImage(image2,  image2, NY, NX);   
334            MakeDicomImage(image2, NY, NX,     dcmImageName, patientName, 1, strStudyUID, strSerieUID, serieDescr, i, multiframe );
335         }         
336         fromEcc.close();
337
338      } // end : for (int i=0; i<numberOfSlices
339    }
340    
341    if (multiframe) {  
342      for (int i=0; i<numberOfSlices; i++)
343      {  
344         Ecc.str(rootfilename);
345         //Ecc   << Ecc.str()    << "_s" << i << "_Ecc.txt";
346         Ecc   << Ecc.str()    << "_s" << i << "_" << serieDescr << ".txt";
347       
348         std::ifstream fromEcc( Ecc.str().c_str() );             
349         if ( !fromEcc )
350         {
351            std::cout << "Can't open file [" << Ecc.str() << "]" << std::endl;
352            exit(0);
353         }
354
355         std::cout << "Open file [" << Ecc.str() << "] : OK" << std::endl;
356         if (X2)
357         {
358           LoadImageX2(fromEcc ,&image[NX*NY*4*i] , multFact);
359           RotateImage(&image[NX*NY*4*i], &image2[NX*NY*4*i], NX*2, NY*2);  
360           FlipImage( &image2[NX*NY*4*i], &image2[NX*NY*4*i], NY*2, NX*2);  
361         }
362         else
363         {
364           LoadImage(fromEcc, &image[NX*NY*i], multFact );
365           RotateImage(&image[NX*NY*i], &image2[NX*NY*i], NX, NY);  
366           FlipImage( &image2[NX*NY*i], &image2[NX*NY*i], NY, NX);  
367         }
368         
369         fromEcc.close();
370      } // end : for (int i=0; i<numberOfSlices
371      
372  //    dcmImageName = deb + "_Ecc.dcm";
373      dcmImageName = deb + "_" +  serieDescr + ".dcm";     
374      if (X2)     
375         MakeDicomImage(image2, NY*2, NX*2, dcmImageName, patientName, numberOfSlices, strStudyUID, strSerieUID, serieDescr, 0, multiframe );
376      else
377         MakeDicomImage(image2, NY, NX,     dcmImageName, patientName, numberOfSlices, strStudyUID, strSerieUID, serieDescr, 0, multiframe );   
378    }  // end : if (multiframe)
379 }
380
381 //=====================================================================================================================================
382
383 void MakeDicomImage(unsigned short int *tabVal, int X, int Y, std::string dcmImageName, const char * patientName, int nbFrames, std::string studyUID, std::string serieUID, std::string SerieDescr, int imgNum, bool m)
384 {
385
386 std::cout << "========================> in MakeDicomImage : dcmImageName = [" << dcmImageName << "] NX= " << X << " NY= " << Y << std::endl;
387  // GDCM_NAME_SPACE::Debug::DebugOn();
388   
389    std::ostringstream str;
390
391    GDCM_NAME_SPACE::File *file;
392    file = GDCM_NAME_SPACE::File::New();       
393       
394   // Set the image size
395    str.str(""); 
396    str << X;
397    file->InsertEntryString(str.str(),0x0028,0x0011,"US"); // Columns
398    str.str("");
399    str << Y;
400    file->InsertEntryString(str.str(),0x0028,0x0010,"US"); // Rows
401
402   // Set the pixel type
403   //      16; //8, 16, 32
404    file->InsertEntryString("16",0x0028,0x0100,"US"); // Bits Allocated
405    
406    str.str("");
407    str << 16; // may be 12 or 16 if componentSize =16
408    file->InsertEntryString("16",0x0028,0x0101,"US"); // Bits Stored
409    file->InsertEntryString("15",0x0028,0x0102,"US"); // High Bit
410
411   // Set the pixel representation // 0/1 , 0=unsigned
412    file->InsertEntryString("1",0x0028,0x0103, "US"); // Pixel Representation
413    
414   // Set the samples per pixel // 1:Grey level, 3:RGB
415    file->InsertEntryString("1",0x0028,0x0002, "US"); // Samples per Pixel
416
417
418    if (nbFrames != 1)
419    {
420       str.str("");
421       str << nbFrames;
422       file->InsertEntryString(str.str(),0x0028,0x0008,"IS"); // Number of Frames  
423    }
424   
425    if (strlen(patientName) != 0)
426       file->InsertEntryString(patientName,0x0010,0x0010, "PN"); // Patient's Name
427
428    file->InsertEntryString(studyUID, 0x0020, 0x000d, "UI");
429    file->InsertEntryString(serieUID, 0x0020, 0x000e, "UI");
430  
431    file->InsertEntryString(SerieDescr,0x0008,0x103e, "LO");  // Series Description 
432
433 // 0020 0037 DS 6 Image Orientation (Patient)   
434    file->InsertEntryString("1.0\\0.0\\0.0\\0.0\\1.0\\0.0",0x0020,0x0037, "DS"); //[1\0\0\0\1\0] : Axial   (Tant pis!)
435    
436 // 0020 0032 DS 3 Image Position (Patient)   
437    char charImagePosition[256];
438    sprintf(charImagePosition,"0.0\\0.0\\%f",(float)imgNum);
439    file->InsertEntryString(charImagePosition,0x0020,0x0032, "DS");  //0020 0032 DS 3 Image Position (Patient)        
440
441 // 0020 0x1041 DS 1 Slice Location 
442         sprintf(charImagePosition,"%f",float(imgNum));
443         file->InsertEntryString(charImagePosition,0x0020,0x1041, "DS");   
444 /*
445   // Set Rescale Intercept
446         str.str("");
447         str << div;  
448         file->InsertEntryString(str.str(),0x0028,0x1052,"DS");
449
450   // Set Rescale Slope
451         str.str("");
452         str << mini;  
453         file->InsertEntryString(str.str(),0x0028,0x1053,"DS");
454 */
455
456    GDCM_NAME_SPACE::FileHelper *fileH;
457    fileH = GDCM_NAME_SPACE::FileHelper::New(file);
458    // cast is just to avoid warnings (*no* conversion is performed)
459    //fileH->SetImageData((uint8_t *)img,int(maxX*maxY)*sizeof(uint16_t)); // troubles when maxX, mayY are *actually* float!
460    
461    fileH->SetImageData((uint8_t *)tabVal,X*Y*nbFrames*sizeof(uint16_t));
462    fileH->SetWriteModeToRaw(); 
463    fileH->SetWriteTypeToDcmExplVR();
464         
465    if( !fileH->Write(dcmImageName))
466       std::cout << "Failed for [" << dcmImageName << "]\n"
467                 << "           File is unwrittable" << std::endl;
468
469   // file->Print();
470            
471   // delete img;
472    file->Delete();
473    fileH->Delete(); 
474    std::cout << "========================> out of MakeDicomImage : " << std::endl; 
475 }
476
477
478 // =====================================================================================================================