Geant4  9.6.p02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DicomHandler.cc
Go to the documentation of this file.
1 //
2 // ********************************************************************
3 // * License and Disclaimer *
4 // * *
5 // * The Geant4 software is copyright of the Copyright Holders of *
6 // * the Geant4 Collaboration. It is provided under the terms and *
7 // * conditions of the Geant4 Software License, included in the file *
8 // * LICENSE and available at http://cern.ch/geant4/license . These *
9 // * include a list of copyright holders. *
10 // * *
11 // * Neither the authors of this software system, nor their employing *
12 // * institutes,nor the agencies providing financial support for this *
13 // * work make any representation or warranty, express or implied, *
14 // * regarding this software system or assume any liability for its *
15 // * use. Please see the license in the file LICENSE and URL above *
16 // * for the full disclaimer and the limitation of liability. *
17 // * *
18 // * This code implementation is the result of the scientific and *
19 // * technical work of the GEANT4 collaboration. *
20 // * By using, copying, modifying or distributing the software (or *
21 // * any work based on the software) you agree to acknowledge its *
22 // * use in resulting scientific publications, and indicate your *
23 // * acceptance of all terms of the Geant4 Software license. *
24 // ********************************************************************
25 //
28 //
29 // The code was written by :
30 // *Louis Archambault louis.archambault@phy.ulaval.ca,
31 // *Luc Beaulieu beaulieu@phy.ulaval.ca
32 // +Vincent Hubert-Tremblay at tigre.2@sympatico.ca
33 //
34 //
35 // *Centre Hospitalier Universitaire de Quebec (CHUQ),
36 // Hotel-Dieu de Quebec, departement de Radio-oncologie
37 // 11 cote du palais. Quebec, QC, Canada, G1R 2J6
38 // tel (418) 525-4444 #6720
39 // fax (418) 691 5268
40 //
41 // + University Laval, Quebec (QC) Canada
42 //*******************************************************
43 //
44 //*******************************************************
45 //
51 //*******************************************************
52 
53 #include "DicomHandler.hh"
54 #include "globals.hh"
55 #include "G4ios.hh"
56 #include <fstream>
57 
58 #include <cctype>
59 #include <cstring>
60 
61 
62 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
64  : DATABUFFSIZE(8192), LINEBUFFSIZE(5020), FILENAMESIZE(512),
65  fCompression(0), fNFiles(0), fRows(0), fColumns(0),
66  fBitAllocated(0), fMaxPixelValue(0), fMinPixelValue(0),
67  fPixelSpacingX(0.), fPixelSpacingY(0.),
68  fSliceThickness(0.), fSliceLocation(0.),
69  fRescaleIntercept(0), fRescaleSlope(0),
70  fLittleEndian(true), fImplicitEndian(false),
71  fPixelRepresentation(0) {
72 
73 }
74 
75 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
77  ;
78 }
79 
80 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
81 G4int DicomHandler::ReadFile(FILE *dicom, char * filename2)
82 {
83  G4cout << " ReadFile " << filename2 << G4endl;
84  G4int returnvalue = 0; size_t rflag = 0;
85  char * buffer = new char[LINEBUFFSIZE];
86 
87  fImplicitEndian = false;
88  fLittleEndian = true;
89 
90  rflag = std::fread( buffer, 1, 128, dicom ); // The first 128 bytes
91  //are not important
92  // Reads the "DICOM" letters
93  rflag = std::fread( buffer, 1, 4, dicom );
94  // if there is no preamble, the FILE pointer is rewinded.
95  if(std::strncmp("DICM", buffer, 4) != 0) {
96  std::fseek(dicom, 0, SEEK_SET);
97  fImplicitEndian = true;
98  }
99 
100  short readGroupId; // identify the kind of input data
101  short readElementId; // identify a particular type information
102  short elementLength2; // deal with element length in 2 bytes
103  //unsigned int elementLength4; // deal with element length in 4 bytes
104  unsigned long elementLength4; // deal with element length in 4 bytes
105 
106  char * data = new char[DATABUFFSIZE];
107 
108 
109  // Read information up to the pixel data
110  while(true) {
111 
112  //Reading groups and elements :
113  readGroupId = 0;
114  readElementId = 0;
115  // group ID
116  rflag = std::fread(buffer, 2, 1, dicom);
117  GetValue(buffer, readGroupId);
118  // element ID
119  rflag = std::fread(buffer, 2, 1, dicom);
120  GetValue(buffer, readElementId);
121 
122  // Creating a tag to be identified afterward
123  G4int tagDictionary = readGroupId*0x10000 + readElementId;
124 
125  // beginning of the pixels
126  if(tagDictionary == 0x7FE00010) break;
127 
128  // VR or element length
129  rflag = std::fread(buffer,2,1,dicom);
130  GetValue(buffer, elementLength2);
131 
132  // If value representation (VR) is OB, OW, SQ, UN, added OF and UT
133  //the next length is 32 bits
134  if((elementLength2 == 0x424f || // "OB"
135  elementLength2 == 0x574f || // "OW"
136  elementLength2 == 0x464f || // "OF"
137  elementLength2 == 0x5455 || // "UT"
138  elementLength2 == 0x5153 || // "SQ"
139  elementLength2 == 0x4e55) && // "UN"
140  !fImplicitEndian ) { // explicit VR
141 
142  rflag = std::fread(buffer, 2, 1, dicom); // Skip 2 reserved bytes
143 
144  // element length
145  rflag = std::fread(buffer, 4, 1, dicom);
146  GetValue(buffer, elementLength4);
147 
148  if(elementLength2 == 0x5153)
149  {
150  if(elementLength4 == 0xFFFFFFFF)
151  {
152  read_undefined_nested( dicom );
153  elementLength4=0;
154  } else{
155  if(read_defined_nested( dicom, elementLength4 )==0){
156  G4cerr << "Function read_defined_nested() failed!" << G4endl;
157  exit(-10); }
158  }
159  } else {
160  // Reading the information with data
161  rflag = std::fread(data, elementLength4,1,dicom);
162  }
163 
164 
165  } else {
166 
167  if(!fImplicitEndian || readGroupId == 2) { // explicit with VR different than previous ones
168 
169  //G4cout << "Reading DICOM files with Explicit VR"<< G4endl;
170  // element length (2 bytes)
171  rflag = std::fread(buffer, 2, 1, dicom);
172  GetValue(buffer, elementLength2);
173  elementLength4 = elementLength2;
174 
175  rflag = std::fread(data, elementLength4, 1, dicom);
176 
177  } else { // Implicit VR
178 
179  //G4cout << "Reading DICOM files with Implicit VR"<< G4endl;
180 
181  // element length (4 bytes)
182  if(std::fseek(dicom, -2, SEEK_CUR) != 0) {
183  G4cerr << "[DicomHandler] fseek failed" << G4endl;
184  exit(-10);}
185 
186  rflag = std::fread(buffer, 4, 1, dicom);
187  GetValue(buffer, elementLength4);
188 
189  //G4cout << std::hex<< elementLength4 << G4endl;
190 
191  if(elementLength4 == 0xFFFFFFFF)
192  {
193  read_undefined_nested(dicom);
194  elementLength4=0;
195  } else{
196  rflag = std::fread(data, elementLength4, 1, dicom);
197  }
198 
199  }
200  }
201 
202  // NULL termination
203  data[elementLength4] = '\0';
204 
205  // analyzing information
206  GetInformation(tagDictionary, data);
207  }
208 
209  // Creating files to store information
210  std::ofstream foutG4DCM;
211  G4String fnameG4DCM = G4String(filename2) + ".g4dcm";
212  foutG4DCM.open(fnameG4DCM);
213  G4cout << "### Writing of " << fnameG4DCM << " ### " << G4endl;
214 
215  foutG4DCM << fMaterialIndices.size() << G4endl;
216  //--- Write materials
217  unsigned int ii = 0;
218  std::map<G4float,G4String>::const_iterator ite;
219  for( ite = fMaterialIndices.begin(); ite != fMaterialIndices.end(); ite++, ii++ ){
220  foutG4DCM << ii << " " << (*ite).second << G4endl;
221  }
222  //--- Write number of voxels (assume only one voxel in Z)
223  foutG4DCM << fColumns/fCompression << " " << fRows/fCompression << " 1 " << G4endl;
224  //--- Write minimum and maximum extensions
225  foutG4DCM << -fPixelSpacingX*fColumns/2. << " " << fPixelSpacingX*fColumns/2. << G4endl;
226  foutG4DCM << -fPixelSpacingY*fRows/2. << " " << fPixelSpacingY*fRows/2. <<
227  G4endl;
228  foutG4DCM << fSliceLocation-fSliceThickness/2. << " " << fSliceLocation+fSliceThickness/2. << G4endl;
229  // foutG4DCM << fCompression << G4endl;
230 
231  ReadData( dicom, filename2 );
232 
233  StoreData( foutG4DCM );
234 
235  foutG4DCM.close();
236 
237  //
238  delete [] buffer;
239  delete [] data;
240 
241  if (rflag) return returnvalue;
242  return returnvalue;
243 }
244 
245 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
246 void DicomHandler::GetInformation(G4int & tagDictionary, char * data) {
247  if(tagDictionary == 0x00280010 ) { // Number of Rows
248  GetValue(data, fRows);
249  std::printf("[0x00280010] Rows -> %i\n",fRows);
250 
251  } else if(tagDictionary == 0x00280011 ) { // Number of fColumns
252  GetValue(data, fColumns);
253  std::printf("[0x00280011] Columns -> %i\n",fColumns);
254 
255  } else if(tagDictionary == 0x00280102 ) { // High bits ( not used )
256  short highBits;
257  GetValue(data, highBits);
258  std::printf("[0x00280102] High bits -> %i\n",highBits);
259 
260  } else if(tagDictionary == 0x00280100 ) { // Bits allocated
261  GetValue(data, fBitAllocated);
262  std::printf("[0x00280100] Bits allocated -> %i\n", fBitAllocated);
263 
264  } else if(tagDictionary == 0x00280101 ) { // Bits stored ( not used )
265  short bitStored;
266  GetValue(data, bitStored);
267  std::printf("[0x00280101] Bits stored -> %i\n",bitStored);
268 
269  } else if(tagDictionary == 0x00280106 ) { // Min. pixel value
270  GetValue(data, fMinPixelValue);
271  std::printf("[0x00280106] Min. pixel value -> %i\n", fMinPixelValue);
272 
273  } else if(tagDictionary == 0x00280107 ) { // Max. pixel value
274  GetValue(data, fMaxPixelValue);
275  std::printf("[0x00280107] Max. pixel value -> %i\n", fMaxPixelValue);
276 
277  } else if(tagDictionary == 0x00281053) { // Rescale slope
278  fRescaleSlope = atoi(data);
279  std::printf("[0x00281053] Rescale Slope -> %d\n", fRescaleSlope);
280 
281  } else if(tagDictionary == 0x00281052 ) { // Rescalse intercept
282  fRescaleIntercept = atoi(data);
283  std::printf("[0x00281052] Rescale Intercept -> %d\n", fRescaleIntercept );
284 
285  } else if(tagDictionary == 0x00280103 ) {
286  // Pixel representation ( functions not design to read signed bits )
287  fPixelRepresentation = atoi(data); // 0: unsigned 1: signed
288  std::printf("[0x00280103] Pixel Representation -> %i\n", fPixelRepresentation);
289  if(fPixelRepresentation == 1 ) {
290  std::printf("### PIXEL REPRESENTATION = 1, BITS ARE SIGNED, ");
291  std::printf("DICOM READING SCAN FOR UNSIGNED VALUE, POSSIBLE ");
292  std::printf("ERROR !!!!!! -> \n");
293  }
294 
295  } else if(tagDictionary == 0x00080006 ) { // Modality
296  std::printf("[0x00080006] Modality -> %s\n", data);
297 
298  } else if(tagDictionary == 0x00080070 ) { // Manufacturer
299  std::printf("[0x00080070] Manufacturer -> %s\n", data);
300 
301  } else if(tagDictionary == 0x00080080 ) { // Institution Name
302  std::printf("[0x00080080] Institution Name -> %s\n", data);
303 
304  } else if(tagDictionary == 0x00080081 ) { // Institution Address
305  std::printf("[0x00080081] Institution Address -> %s\n", data);
306 
307  } else if(tagDictionary == 0x00081040 ) { // Institution Department Name
308  std::printf("[0x00081040] Institution Department Name -> %s\n", data);
309 
310  } else if(tagDictionary == 0x00081090 ) { // Manufacturer's Model Name
311  std::printf("[0x00081090] Manufacturer's Model Name -> %s\n", data);
312 
313  } else if(tagDictionary == 0x00181000 ) { // Device Serial Number
314  std::printf("[0x00181000] Device Serial Number -> %s\n", data);
315 
316  } else if(tagDictionary == 0x00080008 ) { // Image type ( not used )
317  std::printf("[0x00080008] Image Types -> %s\n", data);
318 
319  } else if(tagDictionary == 0x00283000 ) { // Modality LUT Sequence ( not used )
320  std::printf("[0x00283000] Modality LUT Sequence SQ 1 -> %s\n", data);
321 
322  } else if(tagDictionary == 0x00283002 ) { // LUT Descriptor ( not used )
323  std::printf("[0x00283002] LUT Descriptor US or SS 3 -> %s\n", data);
324 
325  } else if(tagDictionary == 0x00283003 ) { // LUT Explanation ( not used )
326  std::printf("[0x00283003] LUT Explanation LO 1 -> %s\n", data);
327 
328  } else if(tagDictionary == 0x00283004 ) { // Modality LUT ( not used )
329  std::printf("[0x00283004] Modality LUT Type LO 1 -> %s\n", data);
330 
331  } else if(tagDictionary == 0x00283006 ) { // LUT Data ( not used )
332  std::printf("[0x00283006] LUT Data US or SS -> %s\n", data);
333 
334  } else if(tagDictionary == 0x00283010 ) { // VOI LUT ( not used )
335  std::printf("[0x00283010] VOI LUT Sequence SQ 1 -> %s\n", data);
336 
337  } else if(tagDictionary == 0x00280120 ) { // Pixel Padding Value ( not used )
338  std::printf("[0x00280120] Pixel Padding Value US or SS 1 -> %s\n", data);
339 
340  } else if(tagDictionary == 0x00280030 ) { // Pixel Spacing
341  G4String datas(data);
342  int iss = datas.find('\\');
343  fPixelSpacingX = atof( datas.substr(0,iss).c_str() );
344  fPixelSpacingY = atof( datas.substr(iss+2,datas.length()).c_str() );
345 
346  } else if(tagDictionary == 0x00200037 ) { // Image Orientation ( not used )
347  std::printf("[0x00200037] Image Orientation (Phantom) -> %s\n", data);
348 
349  } else if(tagDictionary == 0x00200032 ) { // Image Position ( not used )
350  std::printf("[0x00200032] Image Position (Phantom,mm) -> %s\n", data);
351 
352  } else if(tagDictionary == 0x00180050 ) { // Slice Thickness
353  fSliceThickness = atof(data);
354  std::printf("[0x00180050] Slice Thickness (mm) -> %f\n", fSliceThickness);
355 
356  } else if(tagDictionary == 0x00201041 ) { // Slice Location
357  fSliceLocation = atof(data);
358  std::printf("[0x00201041] Slice Location -> %f\n", fSliceLocation);
359 
360  } else if(tagDictionary == 0x00280004 ) { // Photometric Interpretation ( not used )
361  std::printf("[0x00280004] Photometric Interpretation -> %s\n", data);
362 
363  } else if(tagDictionary == 0x00020010) { // Endian
364  if(strcmp(data, "1.2.840.10008.1.2") == 0)
365  fImplicitEndian = true;
366  else if(strncmp(data, "1.2.840.10008.1.2.2", 19) == 0)
367  fLittleEndian = false;
368  //else 1.2.840..10008.1.2.1 (explicit little endian)
369 
370  std::printf("[0x00020010] Endian -> %s\n", data);
371  }
372 
373  // others
374  else {
375  //std::printf("[0x%x] -> %s\n", tagDictionary, data);
376  ;
377  }
378 
379 }
380 
381 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
382 void DicomHandler::StoreData(std::ofstream& foutG4DCM)
383 {
384  G4int mean;
386  G4bool overflow = false;
387 
388  //----- Print indices of material
389  if(fCompression == 1) { // no fCompression: each pixel has a density value)
390  for( G4int ww = 0; ww < fRows; ww++) {
391  for( G4int xx = 0; xx < fColumns; xx++) {
392  mean = fTab[ww][xx];
393  density = Pixel2density(mean);
394  foutG4DCM << GetMaterialIndex( density ) << " ";
395  }
396  foutG4DCM << G4endl;
397  }
398 
399  } else {
400  // density value is the average of a square region of
401  // fCompression*fCompression pixels
402  for(G4int ww = 0; ww < fRows ;ww += fCompression ) {
403  for(G4int xx = 0; xx < fColumns ;xx +=fCompression ) {
404  overflow = false;
405  mean = 0;
406  for(int sumx = 0; sumx < fCompression; sumx++) {
407  for(int sumy = 0; sumy < fCompression; sumy++) {
408  if(ww+sumy >= fRows || xx+sumx >= fColumns) overflow = true;
409  mean += fTab[ww+sumy][xx+sumx];
410  }
411  if(overflow) break;
412  }
413  mean /= fCompression*fCompression;
414 
415  if(!overflow) {
416  density = Pixel2density(mean);
417  foutG4DCM << GetMaterialIndex( density ) << " ";
418  }
419  }
420  foutG4DCM << G4endl;
421  }
422 
423  }
424 
425  //----- Print densities
426  if(fCompression == 1) { // no fCompression: each pixel has a density value)
427  for( G4int ww = 0; ww < fRows; ww++) {
428  for( G4int xx = 0; xx < fColumns; xx++) {
429  mean = fTab[ww][xx];
430  density = Pixel2density(mean);
431  foutG4DCM << density << " ";
432  if( xx%8 == 3 ) foutG4DCM << G4endl; // just for nicer reading
433  }
434  }
435 
436  } else {
437  // density value is the average of a square region of
438  // fCompression*fCompression pixels
439  for(G4int ww = 0; ww < fRows ;ww += fCompression ) {
440  for(G4int xx = 0; xx < fColumns ;xx +=fCompression ) {
441  overflow = false;
442  mean = 0;
443  for(int sumx = 0; sumx < fCompression; sumx++) {
444  for(int sumy = 0; sumy < fCompression; sumy++) {
445  if(ww+sumy >= fRows || xx+sumx >= fColumns) overflow = true;
446  mean += fTab[ww+sumy][xx+sumx];
447  }
448  if(overflow) break;
449  }
450  mean /= fCompression*fCompression;
451 
452  if(!overflow) {
453  density = Pixel2density(mean);
454  foutG4DCM << density << " ";
455  if( xx/fCompression%8 == 3 ) foutG4DCM << G4endl; // just for nicer reading
456  }
457  }
458  }
459 
460  }
461 
462 }
463 
464 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
465 void DicomHandler::ReadMaterialIndices( std::ifstream& finData)
466 {
467  unsigned int nMate;
468  G4String mateName;
469  G4float densityMax;
470  finData >> nMate;
471  if( finData.eof() ) return;
472 
473  G4cout << " ReadMaterialIndices " << nMate << G4endl;
474  for( unsigned int ii = 0; ii < nMate; ii++ ){
475  finData >> mateName >> densityMax;
476  fMaterialIndices[densityMax] = mateName;
477  G4cout << ii << " ReadMaterialIndices " << mateName << " " << densityMax << G4endl;
478  }
479 
480 }
481 
482 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
483 unsigned int DicomHandler::GetMaterialIndex( G4float density )
484 {
485  std::map<G4float,G4String>::reverse_iterator ite;
486  G4int ii = fMaterialIndices.size();
487  for( ite = fMaterialIndices.rbegin(); ite != fMaterialIndices.rend(); ite++, ii-- ) {
488  if( density >= (*ite).first ) {
489  break;
490  }
491  }
492  //- G4cout << " GetMaterialIndex " << density << " = " << ii << G4endl;
493  return ii;
494 
495 }
496 
497 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
498 G4int DicomHandler::ReadData(FILE *dicom,char * filename2)
499 {
500  G4int returnvalue = 0; size_t rflag = 0;
501 
502  // READING THE PIXELS :
503  G4int w = 0;
504 
505  fTab = new G4int*[fRows];
506  for ( G4int i = 0; i < fRows; i ++ ) {
507  fTab[i] = new G4int[fColumns];
508  }
509 
510  if(fBitAllocated == 8) { // Case 8 bits :
511 
512  std::printf("@@@ Error! Picture != 16 bits...\n");
513  std::printf("@@@ Error! Picture != 16 bits...\n");
514  std::printf("@@@ Error! Picture != 16 bits...\n");
515 
516  unsigned char ch = 0;
517 
518  for(G4int j = 0; j < fRows; j++) {
519  for(G4int i = 0; i < fColumns; i++) {
520  w++;
521  rflag = std::fread( &ch, 1, 1, dicom);
522  fTab[j][i] = ch*fRescaleSlope + fRescaleIntercept;
523  }
524  }
525  returnvalue = 1;
526 
527  } else { // from 12 to 16 bits :
528  char sbuff[2];
529  short pixel;
530  for( G4int j = 0; j < fRows; j++) {
531  for( G4int i = 0; i < fColumns; i++) {
532  w++;
533  rflag = std::fread(sbuff, 2, 1, dicom);
534  GetValue(sbuff, pixel);
535  fTab[j][i] = pixel*fRescaleSlope + fRescaleIntercept;
536  }
537  }
538  }
539 
540  // Creation of .g4 files wich contains averaged density data
541  char * nameProcessed = new char[FILENAMESIZE];
542  FILE* fileOut;
543 
544  std::sprintf(nameProcessed,"%s.g4dcmb",filename2);
545  fileOut = std::fopen(nameProcessed,"w+b");
546  std::printf("### Writing of %s ###\n",nameProcessed);
547 
548  unsigned int nMate = fMaterialIndices.size();
549  rflag = std::fwrite(&nMate, sizeof(unsigned int), 1, fileOut);
550  //--- Write materials
551  std::map<G4float,G4String>::const_iterator ite;
552  for( ite = fMaterialIndices.begin(); ite != fMaterialIndices.end(); ite++ ){
553  G4String mateName = (*ite).second;
554  for( G4int ii = (*ite).second.length(); ii < 40; ii++ ) {
555  mateName += " ";
556  } //mateName = const_cast<char*>(((*ite).second).c_str());
557 
558  const char* mateNameC = mateName.c_str();
559  rflag = std::fwrite(mateNameC, sizeof(char),40, fileOut);
560  }
561 
562  unsigned int fRowsC = fRows/fCompression;
563  unsigned int fColumnsC = fColumns/fCompression;
564  unsigned int planesC = 1;
565  G4float pixelLocationXM = -fPixelSpacingX*fColumns/2.;
566  G4float pixelLocationXP = fPixelSpacingX*fColumns/2.;
567  G4float pixelLocationYM = -fPixelSpacingY*fRows/2.;
568  G4float pixelLocationYP = fPixelSpacingY*fRows/2.;
569  G4float fSliceLocationZM = fSliceLocation-fSliceThickness/2.;
570  G4float fSliceLocationZP = fSliceLocation+fSliceThickness/2.;
571  //--- Write number of voxels (assume only one voxel in Z)
572  rflag = std::fwrite(&fRowsC, sizeof(unsigned int), 1, fileOut);
573  rflag = std::fwrite(&fColumnsC, sizeof(unsigned int), 1, fileOut);
574  rflag = std::fwrite(&planesC, sizeof(unsigned int), 1, fileOut);
575  //--- Write minimum and maximum extensions
576  rflag = std::fwrite(&pixelLocationXM, sizeof(G4float), 1, fileOut);
577  rflag = std::fwrite(&pixelLocationXP, sizeof(G4float), 1, fileOut);
578  rflag = std::fwrite(&pixelLocationYM, sizeof(G4float), 1, fileOut);
579  rflag = std::fwrite(&pixelLocationYP, sizeof(G4float), 1, fileOut);
580  rflag = std::fwrite(&fSliceLocationZM, sizeof(G4float), 1, fileOut);
581  rflag = std::fwrite(&fSliceLocationZP, sizeof(G4float), 1, fileOut);
582  // rflag = std::fwrite(&fCompression, sizeof(unsigned int), 1, fileOut);
583 
584  std::printf("%8i %8i\n",fRows,fColumns);
585  std::printf("%8f %8f\n",fPixelSpacingX,fPixelSpacingY);
586  std::printf("%8f\n", fSliceThickness);
587  std::printf("%8f\n", fSliceLocation);
588  std::printf("%8i\n", fCompression);
589 
590  G4int compSize = fCompression;
591  G4int mean;
593  G4bool overflow = false;
594 
595  //----- Write index of material for each pixel
596  if(compSize == 1) { // no fCompression: each pixel has a density value)
597  for( G4int ww = 0; ww < fRows; ww++) {
598  for( G4int xx = 0; xx < fColumns; xx++) {
599  mean = fTab[ww][xx];
600  density = Pixel2density(mean);
601  unsigned int mateID = GetMaterialIndex( density );
602  rflag = std::fwrite(&mateID, sizeof(unsigned int), 1, fileOut);
603  }
604  }
605 
606  } else {
607  // density value is the average of a square region of
608  // fCompression*fCompression pixels
609  for(G4int ww = 0; ww < fRows ;ww += compSize ) {
610  for(G4int xx = 0; xx < fColumns ;xx +=compSize ) {
611  overflow = false;
612  mean = 0;
613  for(int sumx = 0; sumx < compSize; sumx++) {
614  for(int sumy = 0; sumy < compSize; sumy++) {
615  if(ww+sumy >= fRows || xx+sumx >= fColumns) overflow = true;
616  mean += fTab[ww+sumy][xx+sumx];
617  }
618  if(overflow) break;
619  }
620  mean /= compSize*compSize;
621 
622  if(!overflow) {
623  density = Pixel2density(mean);
624  unsigned int mateID = GetMaterialIndex( density );
625  rflag = std::fwrite(&mateID, sizeof(unsigned int), 1, fileOut);
626  }
627  }
628 
629  }
630  }
631 
632  //----- Write density for each pixel
633  if(compSize == 1) { // no fCompression: each pixel has a density value)
634  for( G4int ww = 0; ww < fRows; ww++) {
635  for( G4int xx = 0; xx < fColumns; xx++) {
636  mean = fTab[ww][xx];
637  density = Pixel2density(mean);
638  rflag = std::fwrite(&density, sizeof(G4float), 1, fileOut);
639  }
640  }
641 
642  } else {
643  // density value is the average of a square region of
644  // fCompression*fCompression pixels
645  for(G4int ww = 0; ww < fRows ;ww += compSize ) {
646  for(G4int xx = 0; xx < fColumns ;xx +=compSize ) {
647  overflow = false;
648  mean = 0;
649  for(int sumx = 0; sumx < compSize; sumx++) {
650  for(int sumy = 0; sumy < compSize; sumy++) {
651  if(ww+sumy >= fRows || xx+sumx >= fColumns) overflow = true;
652  mean += fTab[ww+sumy][xx+sumx];
653  }
654  if(overflow) break;
655  }
656  mean /= compSize*compSize;
657 
658  if(!overflow) {
659  density = Pixel2density(mean);
660  rflag = std::fwrite(&density, sizeof(G4float), 1, fileOut);
661  }
662  }
663 
664  }
665  }
666 
667  rflag = std::fclose(fileOut);
668 
669  delete [] nameProcessed;
670 
671  /* for ( G4int i = 0; i < fRows; i ++ ) {
672  delete [] fTab[i];
673  }
674  delete [] fTab;
675  */
676 
677  if (rflag) return returnvalue;
678  return returnvalue;
679 }
680 
681 /*
682  G4int DicomHandler::displayImage(char command[300])
683  {
684  // Display DICOM images using ImageMagick
685  char commandName[500];
686  std::sprintf(commandName,"display %s",command);
687  std::printf(commandName);
688  G4int i = system(commandName);
689  return (G4int )i;
690  }
691 */
692 
693 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
694 G4float DicomHandler::Pixel2density(G4int pixel)
695 {
696  G4float density = -1.;
697  G4int nbrequali = 0;
698  G4double deltaCT = 0;
699  G4double deltaDensity = 0;
700 
701  // CT2Density.dat contains the calibration curve to convert CT (Hounsfield)
702  // number to physical density
703  std::ifstream calibration("CT2Density.dat");
704  calibration >> nbrequali;
705 
706  G4double * valuedensity = new G4double[nbrequali];
707  G4double * valueCT = new G4double[nbrequali];
708 
709  if(!calibration) {
710  G4cerr << "@@@ No value to transform pixels in density!" << G4endl;
711  exit(1);
712 
713  } else { // calibration was successfully opened
714  for(G4int i = 0; i < nbrequali; i++) { // Loop to store all the pts in CT2Density.dat
715  calibration >> valueCT[i] >> valuedensity[i];
716  }
717  }
718  calibration.close();
719 
720  for(G4int j = 1; j < nbrequali; j++) {
721  if( pixel >= valueCT[j-1] && pixel < valueCT[j]) {
722 
723  deltaCT = valueCT[j] - valueCT[j-1];
724  deltaDensity = valuedensity[j] - valuedensity[j-1];
725 
726  // interpolating linearly
727  density = valuedensity[j] - ((valueCT[j] - pixel)*deltaDensity/deltaCT );
728  break;
729  }
730  }
731 
732  if(density < 0.) {
733  std::printf("@@@ Error density = %f && Pixel = %i (0x%x) && deltaDensity/deltaCT = %f\n",density,pixel,pixel, deltaDensity/deltaCT);
734  }
735 
736  delete [] valuedensity;
737  delete [] valueCT;
738 
739  return density;
740 }
741 
742 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
744 {
745  std::ifstream checkData("Data.dat");
746  char * oneLine = new char[128];
747 
748  if(!(checkData.is_open())) { //Check existance of Data.dat
749 
750  G4cout << "\nDicomG4 needs Data.dat :\n\tFirst line: number of image pixel for a "
751  << "voxel (G4Box)\n\tSecond line: number of images (CT slices) to "
752  << "read\n\tEach following line contains the name of a Dicom image except "
753  << "for the .dcm extension\n";
754  exit(0);
755  }
756 
757  checkData >> fCompression;
758  checkData >> fNFiles;
759  G4String oneName;
760  checkData.getline(oneLine,100);
761  std::ifstream testExistence;
762  G4bool existAlready = true;
763  for(G4int rep = 0; rep < fNFiles; rep++) {
764  checkData.getline(oneLine,100);
765  oneName = oneLine;
766  oneName += ".g4dcm"; // create dicomFile.g4dcm
767  G4cout << fNFiles << " test file " << oneName << G4endl;
768  testExistence.open(oneName.data());
769  if(!(testExistence.is_open())) {
770  existAlready = false;
771  testExistence.clear();
772  testExistence.close();
773  }
774  testExistence.clear();
775  testExistence.close();
776  }
777 
778  ReadMaterialIndices( checkData );
779 
780  checkData.close();
781  delete [] oneLine;
782 
783  if( existAlready == false ) { // The files *.g4dcm have to be created
784 
785  G4cout << "\nAll the necessary images were not found in processed form, starting "
786  << "with .dcm images\n";
787 
788  FILE * dicom;
789  FILE * lecturePref;
790  char * fCompressionc = new char[LINEBUFFSIZE];
791  char * maxc = new char[LINEBUFFSIZE];
792  //char name[300], inputFile[300];
793  char * name = new char[FILENAMESIZE];
794  char * inputFile = new char[FILENAMESIZE];
795  G4int rflag;
796 
797  lecturePref = std::fopen("Data.dat","r");
798  rflag = std::fscanf(lecturePref,"%s",fCompressionc);
799  fCompression = atoi(fCompressionc);
800  rflag = std::fscanf(lecturePref,"%s",maxc);
801  fNFiles = atoi(maxc);
802  G4cout << " fNFiles " << fNFiles << G4endl;
803 
804  for( G4int i = 1; i <= fNFiles; i++ ) { // Begin loop on filenames
805 
806  rflag = std::fscanf(lecturePref,"%s",inputFile);
807  std::sprintf(name,"%s.dcm",inputFile);
808  std::cout << "check 1: " << name << std::endl;
809  // Open input file and give it to gestion_dicom :
810  std::printf("### Opening %s and reading :\n",name);
811  dicom = std::fopen(name,"rb");
812  // Reading the .dcm in two steps:
813  // 1. reading the header
814  // 2. reading the pixel data and store the density in Moyenne.dat
815  if( dicom != 0 ) {
816  ReadFile(dicom,inputFile);
817  } else {
818  G4cout << "\nError opening file : " << name << G4endl;
819  }
820  rflag = std::fclose(dicom);
821  }
822  rflag = std::fclose(lecturePref);
823 
824  delete [] fCompressionc;
825  delete [] maxc;
826  delete [] name;
827  delete [] inputFile;
828  if (rflag) return;
829  }
830 }
831 
832 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
833 template <class Type>
834 void DicomHandler::GetValue(char * _val, Type & _rval) {
835 
836 #if BYTE_ORDER == BIG_ENDIAN
837  if(fLittleEndian) { // little endian
838 #else // BYTE_ORDER == LITTLE_ENDIAN
839  if(!fLittleEndian) { // big endian
840 #endif
841  const int SIZE = sizeof(_rval);
842  char ctemp;
843  for(int i = 0; i < SIZE/2; i++) {
844  ctemp = _val[i];
845  _val[i] = _val[SIZE - 1 - i];
846  _val[SIZE - 1 - i] = ctemp;
847  }
848  }
849  _rval = *(Type *)_val;
850 }
851 
852 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
853 G4int DicomHandler::read_defined_nested(FILE * nested,G4int SQ_Length)
854 {
855  // VARIABLES
856  unsigned short item_GroupNumber;
857  unsigned short item_ElementNumber;
858  G4int item_Length;
859  G4int items_array_length=0;
860  char * buffer= new char[LINEBUFFSIZE];
861  size_t rflag = 0;
862 
863  while(items_array_length < SQ_Length)
864  {
865  rflag = std::fread(buffer, 2, 1, nested);
866  GetValue(buffer, item_GroupNumber);
867 
868  rflag = std::fread(buffer, 2, 1, nested);
869  GetValue(buffer, item_ElementNumber);
870 
871  rflag = std::fread(buffer, 4, 1, nested);
872  GetValue(buffer, item_Length);
873 
874  rflag = std::fread(buffer, item_Length, 1, nested);
875 
876  items_array_length= items_array_length+8+item_Length;
877  }
878 
879  delete [] buffer;
880 
881  if( SQ_Length>items_array_length )
882  return 0;
883  else
884  return 1;
885  if (rflag) return 1;
886 }
887 
888 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
889 void DicomHandler::read_undefined_nested(FILE * nested)
890 {
891  // VARIABLES
892  unsigned short item_GroupNumber;
893  unsigned short item_ElementNumber;
894  unsigned int item_Length;
895  char * buffer= new char[LINEBUFFSIZE];
896  size_t rflag = 0;
897 
898  do
899  {
900  rflag = std::fread(buffer, 2, 1, nested);
901  GetValue(buffer, item_GroupNumber);
902 
903  rflag = std::fread(buffer, 2, 1, nested);
904  GetValue(buffer, item_ElementNumber);
905 
906  rflag = std::fread(buffer, 4, 1, nested);
907  GetValue(buffer, item_Length);
908 
909  if(item_Length!=0xffffffff)
910  rflag = std::fread(buffer, item_Length, 1, nested);
911  else
912  read_undefined_item(nested);
913 
914 
915  } while(item_GroupNumber!=0xFFFE || item_ElementNumber!=0xE0DD || item_Length!=0);
916 
917  delete [] buffer;
918  if (rflag) return;
919 }
920 
921 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
922 void DicomHandler::read_undefined_item(FILE * nested)
923 {
924  // VARIABLES
925  unsigned short item_GroupNumber;
926  unsigned short item_ElementNumber;
927  G4int item_Length; size_t rflag = 0;
928  char *buffer= new char[LINEBUFFSIZE];
929 
930  do
931  {
932  rflag = std::fread(buffer, 2, 1, nested);
933  GetValue(buffer, item_GroupNumber);
934 
935  rflag = std::fread(buffer, 2, 1, nested);
936  GetValue(buffer, item_ElementNumber);
937 
938  rflag = std::fread(buffer, 4, 1, nested);
939  GetValue(buffer, item_Length);
940 
941 
942  if(item_Length!=0)
943  rflag = std::fread(buffer,item_Length,1,nested);
944 
945  }
946  while(item_GroupNumber!=0xFFFE || item_ElementNumber!=0xE00D || item_Length!=0);
947 
948  delete [] buffer;
949  if (rflag) return;
950 }