source: trunk/examples/extended/medical/DICOM/src/DicomHandler.cc

Last change on this file was 1337, checked in by garnier, 14 years ago

tag geant4.9.4 beta 1 + modifs locales

File size: 28.7 KB
Line 
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//
26// The code was written by :
27//      *Louis Archambault louis.archambault@phy.ulaval.ca,
28//      *Luc Beaulieu beaulieu@phy.ulaval.ca
29//      +Vincent Hubert-Tremblay at tigre.2@sympatico.ca
30//
31//
32// *Centre Hospitalier Universitaire de Quebec (CHUQ),
33// Hotel-Dieu de Quebec, departement de Radio-oncologie
34// 11 cote du palais. Quebec, QC, Canada, G1R 2J6
35// tel (418) 525-4444 #6720
36// fax (418) 691 5268
37//
38// + Universit.AŽé Laval, QuŽébec (QC) Canada
39//*******************************************************
40//
41//*******************************************************
42//
43//*******************************************************
44//
45// DicomHandler.cc :
46//      - Handling of DICM images
47//      - Reading headers and pixels
48//      - Transforming pixel to density and creating *.g4dcm
49//        files
50//      - Definitions are in DicomHandler.hh
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
62DicomHandler::DicomHandler()
63    : DATABUFFSIZE(8192), LINEBUFFSIZE(5020), FILENAMESIZE(512),
64      compression(0), nFiles(0), rows(0), columns(0),
65      bitAllocated(0), maxPixelValue(0), minPixelValue(0),
66      pixelSpacingX(0.), pixelSpacingY(0.),
67      sliceThickness(0.), sliceLocation(0.),
68      rescaleIntercept(0), rescaleSlope(0),
69      littleEndian(true), implicitEndian(false),
70      pixelRepresentation(0) {
71    ;
72}
73
74DicomHandler::~DicomHandler() {
75    ;
76}
77
78G4int DicomHandler::ReadFile(FILE *dicom, char * filename2)
79{
80  G4cout << " ReadFile " << filename2 << G4endl;
81    G4int returnvalue = 0;
82    char * buffer = new char[LINEBUFFSIZE];
83
84    implicitEndian = false;
85    littleEndian = true;
86
87    std::fread( buffer, 1, 128, dicom ); // The first 128 bytes
88                                         //are not important
89    // Reads the "DICOM" letters
90    std::fread( buffer, 1, 4, dicom );
91    // if there is no preamble, the FILE pointer is rewinded.
92    if(std::strncmp("DICM", buffer, 4) != 0) {
93        std::fseek(dicom, 0, SEEK_SET);
94        implicitEndian = true;
95    }
96
97    short readGroupId;    // identify the kind of input data
98    short readElementId;  // identify a particular type information
99    short elementLength2; // deal with element length in 2 bytes
100    //unsigned int elementLength4; // deal with element length in 4 bytes
101    G4int elementLength4; // deal with element length in 4 bytes
102
103    char * data = new char[DATABUFFSIZE];
104
105 
106    // Read information up to the pixel data
107    while(true) {
108
109        //Reading groups and elements :
110        readGroupId = 0;
111        readElementId = 0;
112        // group ID
113        std::fread(buffer, 2, 1, dicom);
114        GetValue(buffer, readGroupId);
115        // element ID
116        std::fread(buffer, 2, 1, dicom);
117        GetValue(buffer, readElementId);
118
119        // Creating a tag to be identified afterward
120        G4int tagDictionary = readGroupId*0x10000 + readElementId;
121       
122        // beginning of the pixels
123            if(tagDictionary == 0x7FE00010) break;
124
125      // VR or element length
126        std::fread(buffer,2,1,dicom);
127        GetValue(buffer, elementLength2);
128         
129        // If value representation (VR) is OB, OW, SQ, UN, added OF and UT
130        //the next length is 32 bits
131        if((elementLength2 == 0x424f ||  // "OB"
132            elementLength2 == 0x574f ||  // "OW"
133            elementLength2 == 0x464f ||  // "OF"
134            elementLength2 == 0x5455 ||  // "UT"
135            elementLength2 == 0x5153 || //  "SQ"
136            elementLength2 == 0x4e55) && // "UN"
137           !implicitEndian ) {           // explicit VR
138
139            std::fread(buffer, 2, 1, dicom); // Skip 2 reserved bytes
140
141            // element length
142            std::fread(buffer, 4, 1, dicom);
143            GetValue(buffer, elementLength4);
144           
145            if(elementLength2 == 0x5153)
146            {
147             if(elementLength4 == 0xFFFFFFFF)
148              read_undefined_nested( dicom );
149             else{
150              if(read_defined_nested( dicom, elementLength4 )==0){
151               G4cerr << "Reading defined nested functin failed!" << G4endl;
152               exit(-10);              }
153              }
154            } else  { 
155            // Reading the information with data
156            std::fread(data, elementLength4,1,dicom);
157            } 
158
159               
160        }  else { 
161
162                if(!implicitEndian || readGroupId == 2) {  //  explicit with VR different than previous ones
163               
164                  //G4cout << "Reading  DICOM files with Explicit VR"<< G4endl;
165                  // element length (2 bytes)
166                  std::fread(buffer, 2, 1, dicom);
167                  GetValue(buffer, elementLength2);
168                  elementLength4 = elementLength2;
169                 
170                 
171                 
172                  std::fread(data, elementLength4, 1, dicom);
173               
174                } else {                                 // Implicit VR
175
176                  //G4cout << "Reading  DICOM files with Implicit VR"<< G4endl;
177   
178                  // element length (4 bytes)
179                  if(std::fseek(dicom, -2, SEEK_CUR) != 0) {
180                      G4cerr << "[DicomHandler] fseek failed" << G4endl;
181                      exit(-10);}
182
183                  std::fread(buffer, 4, 1, dicom);
184                  GetValue(buffer, elementLength4);
185
186                  //G4cout <<  std::hex<< elementLength4 << G4endl;
187             
188                  if(elementLength4 == 0xFFFFFFFF) 
189                   read_undefined_nested(dicom);
190                  else {
191                 
192                 
193                  std::fread(data, elementLength4, 1, dicom);
194               
195                 } 
196                     
197               } 
198        }
199
200        // NULL termination
201        data[elementLength4] = '\0';
202
203        // analyzing information
204        GetInformation(tagDictionary, data);
205    }
206
207    // Creating files to store information
208    std::ofstream foutG4DCM;
209    G4String fnameG4DCM = G4String(filename2) + ".g4dcm";
210    foutG4DCM.open(fnameG4DCM);
211    G4cout << "### Writing of " << fnameG4DCM << " ### " << G4endl;
212
213    foutG4DCM << fMaterialIndices.size() << G4endl;
214    //--- Write materials
215    unsigned int ii = 0;
216    std::map<G4float,G4String>::const_iterator ite;
217    for( ite = fMaterialIndices.begin(); ite != fMaterialIndices.end(); ite++, ii++ ){
218      foutG4DCM << ii << " " << (*ite).second << G4endl;
219    }
220    //--- Write number of voxels (assume only one voxel in Z)
221    foutG4DCM << rows/compression << " " << columns/compression << " 1 " << G4endl;
222    //--- Write minimum and maximum extensions
223    foutG4DCM << -pixelSpacingX*rows/2 << " " << pixelSpacingX*rows/2 << G4endl;
224    foutG4DCM << -pixelSpacingY*columns/2 << " " << pixelSpacingY*columns/2 << G4endl;
225    foutG4DCM << sliceLocation-sliceThickness/2. << " " << sliceLocation+sliceThickness/2. << G4endl;
226    //    foutG4DCM << compression << G4endl;
227   
228    ReadData( dicom, filename2 );
229   
230    StoreData( foutG4DCM );
231
232    foutG4DCM.close();
233
234    //
235    delete [] buffer;
236    delete [] data;
237
238    return returnvalue;
239}
240
241//
242void DicomHandler::GetInformation(G4int & tagDictionary, char * data) {
243    if(tagDictionary == 0x00280010 ) { // Number of Rows
244        GetValue(data, rows);
245        std::printf("[0x00280010] Rows -> %i\n",rows);
246
247    } else if(tagDictionary == 0x00280011 ) { // Number of columns
248        GetValue(data, columns);
249        std::printf("[0x00280011] Columns -> %i\n",columns);
250
251    } else if(tagDictionary == 0x00280102 ) { // High bits  ( not used )
252        short highBits;
253        GetValue(data, highBits);
254        std::printf("[0x00280102] High bits -> %i\n",highBits);
255
256    } else if(tagDictionary == 0x00280100 ) { // Bits allocated
257        GetValue(data, bitAllocated);
258        std::printf("[0x00280100] Bits allocated -> %i\n", bitAllocated);
259
260    } else if(tagDictionary == 0x00280101 ) { //  Bits stored ( not used )
261        short bitStored;
262        GetValue(data, bitStored);
263        std::printf("[0x00280101] Bits stored -> %i\n",bitStored);
264
265    } else if(tagDictionary == 0x00280106 ) { //  Min. pixel value
266        GetValue(data, minPixelValue);
267        std::printf("[0x00280106] Min. pixel value -> %i\n", minPixelValue);
268
269    } else if(tagDictionary == 0x00280107 ) { //  Max. pixel value
270        GetValue(data, maxPixelValue);
271        std::printf("[0x00280107] Max. pixel value -> %i\n", maxPixelValue);
272
273    } else if(tagDictionary == 0x00281053) { //  Rescale slope
274        rescaleSlope = atoi(data);
275        std::printf("[0x00281053] Rescale Slope -> %d\n", rescaleSlope);
276
277    } else if(tagDictionary == 0x00281052 ) { // Rescalse intercept
278        rescaleIntercept = atoi(data);
279        std::printf("[0x00281052] Rescale Intercept -> %d\n", rescaleIntercept );
280
281    } else if(tagDictionary == 0x00280103 ) {
282        //  Pixel representation ( functions not design to read signed bits )
283        pixelRepresentation = atoi(data); // 0: unsigned  1: signed
284        std::printf("[0x00280103] Pixel Representation -> %i\n", pixelRepresentation);
285        if(pixelRepresentation == 1 ) {
286            std::printf("### PIXEL REPRESENTATION = 1, BITS ARE SIGNED, ");
287            std::printf("DICOM READING SCAN FOR UNSIGNED VALUE, POSSIBLE ");
288            std::printf("ERROR !!!!!! -> \n");
289        }
290
291    } else if(tagDictionary == 0x00080006 ) { //  Modality
292        std::printf("[0x00080006] Modality -> %s\n", data);
293
294    } else if(tagDictionary == 0x00080070 ) { //  Manufacturer
295        std::printf("[0x00080070] Manufacturer -> %s\n", data);
296
297    } else if(tagDictionary == 0x00080080 ) { //  Institution Name
298        std::printf("[0x00080080] Institution Name -> %s\n", data);
299
300    } else if(tagDictionary == 0x00080081 ) { //  Institution Address
301        std::printf("[0x00080081] Institution Address -> %s\n", data);
302
303    } else if(tagDictionary == 0x00081040 ) { //  Institution Department Name
304        std::printf("[0x00081040] Institution Department Name -> %s\n", data);
305
306    } else if(tagDictionary == 0x00081090 ) { //  Manufacturer's Model Name
307        std::printf("[0x00081090] Manufacturer's Model Name -> %s\n", data);
308
309    } else if(tagDictionary == 0x00181000 ) { //  Device Serial Number
310        std::printf("[0x00181000] Device Serial Number -> %s\n", data);
311
312    } else if(tagDictionary == 0x00080008 ) { //  Image type ( not used )
313        std::printf("[0x00080008] Image Types -> %s\n", data);
314           
315    } else if(tagDictionary == 0x00283000 ) { //  Modality LUT Sequence ( not used )
316        std::printf("[0x00283000] Modality LUT Sequence SQ 1 -> %s\n", data);
317
318    } else if(tagDictionary == 0x00283002 ) { // LUT Descriptor ( not used )
319        std::printf("[0x00283002] LUT Descriptor US or SS 3 -> %s\n", data);
320
321    } else if(tagDictionary == 0x00283003 ) { // LUT Explanation ( not used )
322        std::printf("[0x00283003] LUT Explanation LO 1 -> %s\n", data);
323
324    } else if(tagDictionary == 0x00283004 ) { // Modality LUT ( not used )
325        std::printf("[0x00283004] Modality LUT Type LO 1 -> %s\n", data);
326
327    } else if(tagDictionary == 0x00283006 ) { // LUT Data ( not used )
328        std::printf("[0x00283006] LUT Data US or SS -> %s\n", data);
329
330    } else if(tagDictionary == 0x00283010 ) { // VOI LUT ( not used )
331        std::printf("[0x00283010] VOI LUT Sequence SQ 1 -> %s\n", data);
332
333    } else if(tagDictionary == 0x00280120 ) { // Pixel Padding Value ( not used )
334        std::printf("[0x00280120] Pixel Padding Value US or SS 1 -> %s\n", data);
335
336    } else if(tagDictionary == 0x00280030 ) { // Pixel Spacing
337      G4String datas(data);
338      int iss = datas.find('\\');
339      pixelSpacingX = atof( datas.substr(0,iss).c_str() );
340      pixelSpacingY = atof( datas.substr(iss+2,datas.length()).c_str() );
341
342    } else if(tagDictionary == 0x00200037 ) { // Image Orientation ( not used )
343        std::printf("[0x00200037] Image Orientation (Patient) -> %s\n", data);
344
345    } else if(tagDictionary == 0x00200032 ) { // Image Position ( not used )
346        std::printf("[0x00200032] Image Position (Patient,mm) -> %s\n", data);
347
348    } else if(tagDictionary == 0x00180050 ) { // Slice Thickness
349        sliceThickness = atof(data);
350        std::printf("[0x00180050] Slice Thickness (mm) -> %f\n", sliceThickness);
351
352    } else if(tagDictionary == 0x00201041 ) { // Slice Location
353        sliceLocation = atof(data);
354        std::printf("[0x00201041] Slice Location -> %f\n", sliceLocation);
355
356    } else if(tagDictionary == 0x00280004 ) { // Photometric Interpretation ( not used )
357        std::printf("[0x00280004] Photometric Interpretation -> %s\n", data);
358
359    } else if(tagDictionary == 0x00020010) { // Endian
360        if(strcmp(data, "1.2.840.10008.1.2") == 0)
361            implicitEndian = true;
362        else if(strncmp(data, "1.2.840.10008.1.2.2", 19) == 0)
363            littleEndian = false;
364        //else 1.2.840..10008.1.2.1 (explicit little endian)
365                   
366        std::printf("[0x00020010] Endian -> %s\n", data);
367    }
368
369    // others
370    else {
371        std::printf("[0x%x] -> %s\n", tagDictionary, data);
372
373    }
374
375}
376
377void DicomHandler::StoreData(std::ofstream& foutG4DCM) 
378{
379  G4int mean;
380  G4double density;
381  G4bool overflow = false;
382  G4int cpt=1;
383
384  //----- Print indices of material
385  if(compression == 1) { // no compression: each pixel has a density value)
386    for( G4int ww = 0; ww < rows; ww++) {
387      for( G4int xx = 0; xx < columns; xx++) {
388        mean = tab[ww][xx];
389        density = Pixel2density(mean);
390        foutG4DCM << GetMaterialIndex( density ) << " ";
391      }
392      foutG4DCM << G4endl;
393    }
394   
395  } else {
396    // density value is the average of a square region of
397    // compression*compression pixels
398    for(G4int ww = 0; ww < rows ;ww += compression ) {
399      for(G4int xx = 0; xx < columns ;xx +=compression ) {
400        overflow = false;
401        mean = 0;
402        for(int sumx = 0; sumx < compression; sumx++) {
403          for(int sumy = 0; sumy < compression; sumy++) {
404            if(ww+sumy >= rows || xx+sumx >= columns) overflow = true;
405            mean += tab[ww+sumy][xx+sumx];
406          }
407          if(overflow) break;
408        }
409        mean /= compression*compression;
410        cpt = 1;
411       
412        if(!overflow) {
413          G4double density = Pixel2density(mean);
414          foutG4DCM << GetMaterialIndex( density ) << " ";
415        }
416      }
417      foutG4DCM << G4endl;
418    }
419
420  }
421
422  //----- Print densities
423  if(compression == 1) { // no compression: each pixel has a density value)
424    for( G4int ww = 0; ww < rows; ww++) {
425      for( G4int xx = 0; xx < columns; xx++) {
426        mean = tab[ww][xx];
427        density = Pixel2density(mean);
428        foutG4DCM << density << " ";
429        if( xx%8 == 3 ) foutG4DCM << G4endl; // just for nicer reading
430      }
431    }
432   
433  } else {
434    // density value is the average of a square region of
435    // compression*compression pixels
436    for(G4int ww = 0; ww < rows ;ww += compression ) {
437      for(G4int xx = 0; xx < columns ;xx +=compression ) {
438        overflow = false;
439        mean = 0;
440        for(int sumx = 0; sumx < compression; sumx++) {
441          for(int sumy = 0; sumy < compression; sumy++) {
442            if(ww+sumy >= rows || xx+sumx >= columns) overflow = true;
443            mean += tab[ww+sumy][xx+sumx];
444          }
445          if(overflow) break;
446        }
447        mean /= compression*compression;
448        cpt = 1;
449       
450        if(!overflow) {
451          G4double density = Pixel2density(mean);
452          foutG4DCM << density  << " ";
453          if( xx/compression%8 == 3 ) foutG4DCM << G4endl; // just for nicer reading
454        }
455      }
456    }
457
458  }
459
460}
461
462void DicomHandler::ReadMaterialIndices( std::ifstream& finData)
463{
464  unsigned int nMate;
465  G4String mateName;
466  G4float densityMax;
467  finData >> nMate;
468  if( finData.eof() ) return;
469
470  G4cout << " ReadMaterialIndices " << nMate << G4endl;
471  for( unsigned int ii = 0; ii < nMate; ii++ ){
472    finData >> mateName >> densityMax;
473    fMaterialIndices[densityMax] = mateName;
474    G4cout << ii << " ReadMaterialIndices " << mateName << " " << densityMax << G4endl;
475  }
476
477}
478
479unsigned int DicomHandler::GetMaterialIndex( G4float density )
480{
481  std::map<G4float,G4String>::reverse_iterator ite;
482  G4int ii = fMaterialIndices.size();
483  for( ite = fMaterialIndices.rbegin(); ite != fMaterialIndices.rend(); ite++, ii-- ) {
484    if( density >= (*ite).first ) {
485      break;
486    }
487  }
488  //-  G4cout << " GetMaterialIndex " << density << " = " << ii << G4endl;
489  return  ii;
490
491}
492
493//
494G4int DicomHandler::ReadData(FILE *dicom,char * filename2)
495{
496    G4int returnvalue = 0;
497
498    //  READING THE PIXELS :
499    G4int w = 0;
500    G4int len = 0;
501   
502    tab = new G4int*[rows];
503    for ( G4int i = 0; i < rows; i ++ ) {
504      tab[i] = new G4int[columns];
505    }
506
507    if(bitAllocated == 8) { // Case 8 bits :
508
509        std::printf("@@@ Error! Picture != 16 bits...\n");
510        std::printf("@@@ Error! Picture != 16 bits...\n"); 
511        std::printf("@@@ Error! Picture != 16 bits...\n"); 
512
513        unsigned char ch = 0;
514
515        len = rows*columns;
516        for(G4int j = 0; j < rows; j++) {
517            for(G4int i = 0; i < columns; i++) {
518                w++;
519                std::fread( &ch, 1, 1, dicom);
520                tab[j][i] = ch*rescaleSlope + rescaleIntercept;
521            }
522        }
523        returnvalue = 1;
524
525    } else { //  from 12 to 16 bits :
526        char sbuff[2];
527        short pixel;
528        len = rows*columns;
529        for( G4int j = 0; j < rows; j++) {
530            for( G4int i = 0; i < columns; i++) {
531                w++;
532                std::fread(sbuff, 2, 1, dicom);
533                GetValue(sbuff, pixel);
534                tab[j][i] = pixel*rescaleSlope + rescaleIntercept;
535            }
536        }
537    }
538
539    // Creation of .g4 files wich contains averaged density data
540    char * nameProcessed = new char[FILENAMESIZE];
541    FILE* fileOut;
542
543    std::sprintf(nameProcessed,"%s.g4dcmb",filename2);
544    fileOut = std::fopen(nameProcessed,"w+b");
545    std::printf("### Writing of %s ###\n",nameProcessed);
546
547    unsigned int nMate = fMaterialIndices.size();
548    std::fwrite(&nMate, sizeof(unsigned int), 1, fileOut);
549    //--- Write materials
550    std::map<G4float,G4String>::const_iterator ite;
551    for( ite = fMaterialIndices.begin(); ite != fMaterialIndices.end(); ite++ ){
552      G4String mateName = (*ite).second;
553      for( G4int ii = (*ite).second.length(); ii < 40; ii++ ) {
554        mateName += " ";
555      }  //mateName = const_cast<char*>(((*ite).second).c_str());
556
557      const char* mateNameC = mateName.c_str();
558      std::fwrite(mateNameC, sizeof(char),40, fileOut);
559    }
560
561    unsigned int rowsC = rows/compression;
562    unsigned int columnsC = columns/compression;
563    unsigned int planesC = 1;
564    G4float pixelLocationXM = -pixelSpacingX*rows/2.;
565    G4float pixelLocationXP = pixelSpacingX*rows/2.;
566    G4float pixelLocationYM = -pixelSpacingY*rows/2.;
567    G4float pixelLocationYP = pixelSpacingY*rows/2.;
568    G4float sliceLocationZM = sliceLocation-sliceThickness/2.;
569    G4float sliceLocationZP = sliceLocation+sliceThickness/2.;
570    //--- Write number of voxels (assume only one voxel in Z)
571    std::fwrite(&rowsC, sizeof(unsigned int), 1, fileOut);
572    std::fwrite(&columnsC, sizeof(unsigned int), 1, fileOut);
573    std::fwrite(&planesC, sizeof(unsigned int), 1, fileOut);
574    //--- Write minimum and maximum extensions
575    std::fwrite(&pixelLocationXM, sizeof(G4float), 1, fileOut);
576    std::fwrite(&pixelLocationXP, sizeof(G4float), 1, fileOut);
577    std::fwrite(&pixelLocationYM, sizeof(G4float), 1, fileOut);
578    std::fwrite(&pixelLocationYP, sizeof(G4float), 1, fileOut);
579    std::fwrite(&sliceLocationZM, sizeof(G4float), 1, fileOut);
580    std::fwrite(&sliceLocationZP, sizeof(G4float), 1, fileOut);
581    //    std::fwrite(&compression, sizeof(unsigned int), 1, fileOut);
582
583    std::printf("%8i   %8i\n",rows,columns);
584    std::printf("%8f   %8f\n",pixelSpacingX,pixelSpacingY);
585    std::printf("%8f\n", sliceThickness);
586    std::printf("%8f\n", sliceLocation);
587    std::printf("%8i\n", compression);
588
589    G4int compSize = compression;
590    G4int mean;
591    G4float density;
592    G4bool overflow = false;
593    G4int cpt=1;
594
595    //----- Write index of material for each pixel
596    if(compSize == 1) { // no compression: each pixel has a density value)
597      for( G4int ww = 0; ww < rows; ww++) {
598        for( G4int xx = 0; xx < columns; xx++) {
599          mean = tab[ww][xx];
600          density = Pixel2density(mean);
601          unsigned int mateID = GetMaterialIndex( density );
602          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      // compression*compression pixels
609      for(G4int ww = 0; ww < rows ;ww += compSize ) {
610        for(G4int xx = 0; xx < columns ;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 >= rows || xx+sumx >= columns) overflow = true;
616              mean += tab[ww+sumy][xx+sumx];
617            }
618            if(overflow) break;
619          }
620          mean /= compSize*compSize;
621          cpt = 1;
622         
623          if(!overflow) {
624            density = Pixel2density(mean);
625            unsigned int mateID = GetMaterialIndex( density );
626            std::fwrite(&mateID, sizeof(unsigned int), 1, fileOut);
627          }
628        }
629       
630      }
631    }
632
633    //----- Write density for each pixel
634    if(compSize == 1) { // no compression: each pixel has a density value)
635      for( G4int ww = 0; ww < rows; ww++) {
636        for( G4int xx = 0; xx < columns; xx++) {
637          mean = tab[ww][xx];
638          density = Pixel2density(mean);
639          std::fwrite(&density, sizeof(G4float), 1, fileOut);
640        }
641      }
642     
643    } else {
644      // density value is the average of a square region of
645      // compression*compression pixels
646      for(G4int ww = 0; ww < rows ;ww += compSize ) {
647        for(G4int xx = 0; xx < columns ;xx +=compSize ) {
648          overflow = false;
649          mean = 0;
650          for(int sumx = 0; sumx < compSize; sumx++) {
651            for(int sumy = 0; sumy < compSize; sumy++) {
652              if(ww+sumy >= rows || xx+sumx >= columns) overflow = true;
653              mean += tab[ww+sumy][xx+sumx];
654            }
655            if(overflow) break;
656          }
657          mean /= compSize*compSize;
658          cpt = 1;
659         
660          if(!overflow) {
661            density = Pixel2density(mean);
662            std::fwrite(&density, sizeof(G4float), 1, fileOut);
663          }
664        }
665       
666      }
667    }
668   
669    std::fclose(fileOut);
670   
671    delete [] nameProcessed;
672
673    /*    for ( G4int i = 0; i < rows; i ++ ) {
674      delete [] tab[i];
675    }
676    delete [] tab;
677    */
678
679    return returnvalue;
680}
681
682/*
683  G4int DicomHandler::displayImage(char command[300])
684  {
685  //   Display DICOM images using ImageMagick
686  char commandName[500];
687  std::sprintf(commandName,"display  %s",command);
688  std::printf(commandName);
689  G4int i = system(commandName);
690  return (G4int )i;
691  }
692*/
693
694G4float 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
743void DicomHandler::CheckFileFormat()
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 >> compression;
758    checkData >> nFiles;
759    G4String oneName;
760    checkData.getline(oneLine,100);
761    std::ifstream testExistence;
762    G4bool existAlready = true;
763    for(G4int rep = 0; rep < nFiles; rep++) { 
764      checkData.getline(oneLine,100);
765      oneName = oneLine;
766      oneName += ".g4dcm"; // create dicomFile.g4dcm
767      G4cout << nFiles << " 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 * compressionc = 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
796        lecturePref = std::fopen("Data.dat","r");
797        std::fscanf(lecturePref,"%s",compressionc);
798        compression = atoi(compressionc);
799        std::fscanf(lecturePref,"%s",maxc);
800        nFiles = atoi(maxc);
801        G4cout << " nFiles " << nFiles << G4endl;
802
803        for( G4int i = 1; i <= nFiles; i++ ) { // Begin loop on filenames
804
805            std::fscanf(lecturePref,"%s",inputFile);
806            std::sprintf(name,"%s.dcm",inputFile);
807            std::cout << "check 1: " << name << std::endl;
808            //  Open input file and give it to gestion_dicom :
809            std::printf("### Opening %s and reading :\n",name);
810            dicom = std::fopen(name,"rb");
811            // Reading the .dcm in two steps:
812            //      1.  reading the header
813            //  2. reading the pixel data and store the density in Moyenne.dat
814            if( dicom != 0 ) {
815                ReadFile(dicom,inputFile);
816            } else {
817                G4cout << "\nError opening file : " << name << G4endl;
818            }
819            std::fclose(dicom);
820        }
821        std::fclose(lecturePref);
822
823        delete [] compressionc;
824        delete [] maxc;
825        delete [] name;
826        delete [] inputFile;
827
828    } 
829
830}
831
832
833template <class Type>
834void DicomHandler::GetValue(char * _val, Type & _rval) {
835
836#if BYTE_ORDER == BIG_ENDIAN
837    if(littleEndian) {      // little endian
838#else // BYTE_ORDER == LITTLE_ENDIAN
839    if(!littleEndian) {     // 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
852G4int DicomHandler::read_defined_nested(FILE * nested,G4int SQ_Length)
853{
854  //      VARIABLES
855  unsigned short item_GroupNumber;
856  unsigned short item_ElementNumber;
857  G4int item_Length;
858  G4int items_array_length=0;
859  char * buffer= new char[LINEBUFFSIZE];
860 
861
862  while(items_array_length < SQ_Length)
863  {
864   std::fread(buffer, 2, 1, nested);
865   GetValue(buffer, item_GroupNumber);
866   
867   std::fread(buffer, 2, 1, nested);
868   GetValue(buffer, item_ElementNumber);
869   
870   std::fread(buffer, 4, 1, nested);
871   GetValue(buffer, item_Length);
872   
873   std::fread(buffer, item_Length, 1, nested);
874   
875   items_array_length= items_array_length+8+item_Length;
876  }
877 
878  delete []buffer;
879 
880  if(SQ_Length>items_array_length)
881   return 0;
882  else
883   return 1;
884
885}
886
887void DicomHandler::read_undefined_nested(FILE * nested)
888{
889  //      VARIABLES
890  unsigned short item_GroupNumber;
891  unsigned short item_ElementNumber;
892  G4int item_Length;
893  char * buffer= new char[LINEBUFFSIZE];
894 
895
896  do
897  {
898   std::fread(buffer, 2, 1, nested);
899   GetValue(buffer, item_GroupNumber);
900   
901   std::fread(buffer, 2, 1, nested);
902   GetValue(buffer, item_ElementNumber);
903   
904   std::fread(buffer, 4, 1, nested);
905   GetValue(buffer, item_Length);
906   
907   if(item_Length!=0xffffffff)
908    std::fread(buffer, item_Length, 1, nested);
909   else
910    read_undefined_item(nested);
911   
912   
913  }while(item_GroupNumber!=0xFFFE || item_ElementNumber!=0xE0DD || item_Length!=0);
914
915  delete [] buffer;
916
917}
918
919void DicomHandler::read_undefined_item(FILE * nested)
920{
921  //      VARIABLES
922 unsigned short item_GroupNumber;
923 unsigned short item_ElementNumber;
924 G4int item_Length;
925 char *buffer= new char[LINEBUFFSIZE];
926 
927 do
928 {
929  std::fread(buffer, 2, 1, nested);
930  GetValue(buffer, item_GroupNumber);
931   
932  std::fread(buffer, 2, 1, nested);
933  GetValue(buffer, item_ElementNumber);
934   
935  std::fread(buffer, 4, 1, nested);
936  GetValue(buffer, item_Length);
937
938
939  if(item_Length!=0)
940   std::fread(buffer,item_Length,1,nested);
941
942 }
943 while(item_GroupNumber!=0xFFFE || item_ElementNumber!=0xE00D || item_Length!=0);
944 
945 delete []buffer;
946 
947}
Note: See TracBrowser for help on using the repository browser.