]> Creatis software - gdcm.git/blob - Example/PcpdenseToDicom.cxx
As requested, one serie per image
[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 23:27:41 $
7   Version:   $Revision: 1.11 $
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::ostringstream trueSerieDescr;   
291    std::string dcmImageName;
292
293    int mult;
294    if (X2)
295       mult=4;
296    else
297       mult=1;
298
299    if (multiframe) {
300       image  = new unsigned short int[NX*NY*mult*numberOfSlices];
301       image2 = new unsigned short int[NX*NY*mult*numberOfSlices];
302    } else {
303       image  = new unsigned short int[NX*NY*mult];
304       image2 = new unsigned short int[NX*NY*mult];
305    }
306    
307    if (!multiframe) {
308      for (int i=0; i<numberOfSlices; i++)
309      {  
310         Ecc.str(rootfilename); 
311         //Ecc << Ecc.str() << "_s" << i << "_Ecc.txt";
312         Ecc << Ecc.str() << "_s" << i << "_" << serieDescr << ".txt";
313
314         trueSerieDescr.str("");
315
316         trueSerieDescr  << serieDescr << "_" "s" << i;
317         //std::cout << "-------------------------------------------------------" << trueSerieDescr.str() << std::endl;
318     
319         std::ifstream fromEcc( Ecc.str().c_str() );             
320         if ( !fromEcc )
321         {
322            std::cout << "Can't open file [" << Ecc.str() << "]" << std::endl;
323            exit(0);
324         }
325         std::cout << "Open file [" << Ecc.str() << "] : OK" << std::endl;
326         dcmImageName = Ecc.str() + ".dcm";
327
328         if (X2)
329         {
330            LoadImageX2(fromEcc, image, multFact);
331            RotateImage(image, image2, NX*2, NY*2);
332            FlipImage(image2,  image2, NY*2, NX*2);  
333            MakeDicomImage(image, NY*2, NX*2, dcmImageName, patientName, 1, strStudyUID, strSerieUID, trueSerieDescr.str(), i, multiframe );
334         }
335         else
336         {  
337            LoadImage(fromEcc, image, multFact);
338            RotateImage(image, image2, NX, NY);
339            FlipImage(image2,  image2, NY, NX);   
340            MakeDicomImage(image2, NY, NX,     dcmImageName, patientName, 1, strStudyUID, strSerieUID, trueSerieDescr.str(), i, multiframe );
341         }         
342         fromEcc.close();
343
344      } // end : for (int i=0; i<numberOfSlices
345    }
346    
347    if (multiframe) {  
348      for (int i=0; i<numberOfSlices; i++)
349      {  
350         Ecc.str(rootfilename);
351         //Ecc   << Ecc.str()    << "_s" << i << "_Ecc.txt";
352         Ecc   << Ecc.str()    << "_s" << i << "_" << serieDescr << ".txt";
353       
354         std::ifstream fromEcc( Ecc.str().c_str() );             
355         if ( !fromEcc )
356         {
357            std::cout << "Can't open file [" << Ecc.str() << "]" << std::endl;
358            exit(0);
359         }
360
361         std::cout << "Open file [" << Ecc.str() << "] : OK" << std::endl;
362         if (X2)
363         {
364           LoadImageX2(fromEcc ,&image[NX*NY*4*i] , multFact);
365           RotateImage(&image[NX*NY*4*i], &image2[NX*NY*4*i], NX*2, NY*2);  
366           FlipImage( &image2[NX*NY*4*i], &image2[NX*NY*4*i], NY*2, NX*2);  
367         }
368         else
369         {
370           LoadImage(fromEcc, &image[NX*NY*i], multFact );
371           RotateImage(&image[NX*NY*i], &image2[NX*NY*i], NX, NY);  
372           FlipImage( &image2[NX*NY*i], &image2[NX*NY*i], NY, NX);  
373         }
374         
375         fromEcc.close();
376      } // end : for (int i=0; i<numberOfSlices
377      
378  //    dcmImageName = deb + "_Ecc.dcm";
379      dcmImageName = deb + "_" +  serieDescr + ".dcm";     
380      if (X2)     
381         MakeDicomImage(image2, NY*2, NX*2, dcmImageName, patientName, numberOfSlices, strStudyUID, strSerieUID, serieDescr, 0, multiframe );
382      else
383         MakeDicomImage(image2, NY, NX,     dcmImageName, patientName, numberOfSlices, strStudyUID, strSerieUID, serieDescr, 0, multiframe );   
384    }  // end : if (multiframe)
385 }
386
387 //=====================================================================================================================================
388
389 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)
390 {
391
392 //std::cout << "========================> in MakeDicomImage : dcmImageName = [" << dcmImageName << "] NX= " << X << " NY= " << Y << std::endl;
393  // GDCM_NAME_SPACE::Debug::DebugOn();
394   
395    std::ostringstream str;
396
397    GDCM_NAME_SPACE::File *file;
398    file = GDCM_NAME_SPACE::File::New();       
399       
400   // Set the image size
401    str.str(""); 
402    str << X;
403    file->InsertEntryString(str.str(),0x0028,0x0011,"US"); // Columns
404    str.str("");
405    str << Y;
406    file->InsertEntryString(str.str(),0x0028,0x0010,"US"); // Rows
407
408   // Set the pixel type
409   //      16; //8, 16, 32
410    file->InsertEntryString("16",0x0028,0x0100,"US"); // Bits Allocated
411    
412    str.str("");
413    str << 16; // may be 12 or 16 if componentSize =16
414    file->InsertEntryString("16",0x0028,0x0101,"US"); // Bits Stored
415    file->InsertEntryString("15",0x0028,0x0102,"US"); // High Bit
416
417   // Set the pixel representation // 0/1 , 0=unsigned
418    file->InsertEntryString("1",0x0028,0x0103, "US"); // Pixel Representation
419    
420   // Set the samples per pixel // 1:Grey level, 3:RGB
421    file->InsertEntryString("1",0x0028,0x0002, "US"); // Samples per Pixel
422
423
424    if (nbFrames != 1)
425    {
426       str.str("");
427       str << nbFrames;
428       file->InsertEntryString(str.str(),0x0028,0x0008,"IS"); // Number of Frames  
429    }
430   
431    if (strlen(patientName) != 0)
432       file->InsertEntryString(patientName,0x0010,0x0010, "PN"); // Patient's Name
433
434    file->InsertEntryString(studyUID, 0x0020, 0x000d, "UI");
435    file->InsertEntryString(serieUID, 0x0020, 0x000e, "UI");
436  
437    file->InsertEntryString(SerieDescr,0x0008,0x103e, "LO");  // Series Description 
438
439 // 0020 0037 DS 6 Image Orientation (Patient)   
440    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!)
441    
442 // 0020 0032 DS 3 Image Position (Patient)   
443    char charImagePosition[256];
444    sprintf(charImagePosition,"0.0\\0.0\\%f",(float)imgNum);
445    file->InsertEntryString(charImagePosition,0x0020,0x0032, "DS");  //0020 0032 DS 3 Image Position (Patient)        
446
447 // 0020 0x1041 DS 1 Slice Location 
448         sprintf(charImagePosition,"%f",float(imgNum));
449         file->InsertEntryString(charImagePosition,0x0020,0x1041, "DS");   
450 /*
451   // Set Rescale Intercept
452         str.str("");
453         str << div;  
454         file->InsertEntryString(str.str(),0x0028,0x1052,"DS");
455
456   // Set Rescale Slope
457         str.str("");
458         str << mini;  
459         file->InsertEntryString(str.str(),0x0028,0x1053,"DS");
460 */
461
462    GDCM_NAME_SPACE::FileHelper *fileH;
463    fileH = GDCM_NAME_SPACE::FileHelper::New(file);
464    // cast is just to avoid warnings (*no* conversion is performed)
465    //fileH->SetImageData((uint8_t *)img,int(maxX*maxY)*sizeof(uint16_t)); // troubles when maxX, mayY are *actually* float!
466    
467    fileH->SetImageData((uint8_t *)tabVal,X*Y*nbFrames*sizeof(uint16_t));
468    fileH->SetWriteModeToRaw(); 
469    fileH->SetWriteTypeToDcmExplVR();
470         
471    if( !fileH->Write(dcmImageName))
472       std::cout << "Failed for [" << dcmImageName << "]\n"
473                 << "           File is unwrittable" << std::endl;
474
475   // file->Print();
476            
477   // delete img;
478    file->Delete();
479    fileH->Delete(); 
480    //std::cout << "========================> out of MakeDicomImage : " << std::endl; 
481 }
482
483
484 // =====================================================================================================================