// // ******************************************************************** // * License and Disclaimer * // * * // * The GAMOS software is copyright of the Copyright Holders of * // * the GAMOS Collaboration. It is provided under the terms and * // * conditions of the GAMOS Software License, included in the file * // * LICENSE and available at http://fismed.ciemat.es/GAMOS/license .* // * These include a list of copyright holders. * // * * // * Neither the authors of this software system, nor their employing * // * institutes,nor the agencies providing financial support for this * // * work make any representation or warranty, express or implied, * // * regarding this software system or assume any liability for its * // * use. Please see the license in the file LICENSE and URL above * // * for the full disclaimer and the limitation of liability. * // * * // * This code implementation is the result of the scientific and * // * technical work of the GAMOS collaboration. * // * By using, copying, modifying or distributing the software (or * // * any work based on the software) you agree to acknowledge its * // * use in resulting scientific publications, and indicate your * // * acceptance of all terms of the GAMOS Software license. * // ******************************************************************** // /*------------------------------------------------------- PET Reconstruction. GAMOS Collaboration. CIEMAT 2009-11 -- ssrb_fbp.cc -- mario.canadas@ciemat.es -------------------------------------------------------*/ /*------------------------------------------------------ Description : SSRB - FBP method, using 3D sinograms. Input data: Nbins * Ntang * (Nrings * Nrings), unsigned short 16 bit (.hv .v Interfile format) Jan 2011: Bug: Line 160: "filt = new double[P/2]" changed to "filt = new double[P/2+1]" -------------------------------------------------------*/ #include "./include/ssrb_fbp.hh" #ifndef PI #define PI 3.14159265358979323846 #endif void PrintArgList(){ cout << " -------------------------- \n" " Description : \n" " This program applies a SSRB-FBP2D method to reconstruct PET images. \n" " Input data: Projection data (3D-sinogram) with dimension Nbins * Ntang * Nrings*Nrings, unsigned short 16 bit (.hv .v Interfile format) \n" " \n" // ARGUMENTS: " Arguments convention: \n" " -m SSRB: Maximum ring difference (by default: -1 = n_planes-1), \n" " -i Image size, number of X and Y pixels (by default: -1 = Number of bins in sinogram), \n" " -x Pixel size, (by default: -1 = sinogram bin size) \n" " \n" " -f Apodization window (Low pass) for filtering : \n" " 1, Hamming gener. (by default, it includes Hann window and ramplak) \n" " 2, Butterworth order . \n" " 3, Shepp-Logan. \n" " -a Alpha parameter for Hamming gener. window (by default: 1 = Ramp filter), \n" " -b Order for Butterworth window (by default: 1) . \n" " -c Cutoff frecuency, relative to Nyquist frec: delta_rho/2 (by default: 0.75), \n" " \n" " -t Type of the input file (by default: 0 = Interfile), \n" " -n Name of the output image file (w/o extension: .hdr .img, Interfile), \n" " \n" " -h (Help) Printing arguments list \n" " -v Verbosity (by default:0=silent, 3=debug), \n" // " -o Output type --> TO DO \n" " \n" " PET Reconstruction. \n" " CIEMAT - GAMOS Collaboration 2009-11 \n" " mario.canadas@ciemat.es \n" // " -------------------------- \n" " -------------------------- \n"; } int main(int argc,char *argv[]) { if (argc==1){ PrintArgList(); exit(1); } for (int i = 1; i < argc; i++) { /* Check for a switch (leading "-"). */ if (argv[i][0] == '-') { /* Use the next character to decide what to do. */ switch (argv[i][1]) { case 'a': alpha = atof(argv[++i]); break; case 'b': Butt_n = atof(argv[++i]); break; case 'c': Nf_cut = atof(argv[++i]); break; case 't': typeINfile = atoi(argv[++i]); break; case 'f': type_f = atoi(argv[++i]); break; case 'm': MRDiff = atoi(argv[++i]); break; case 'i': M = atoi(argv[++i]); break; case 'r': norm = atoi(argv[++i]); break; case 'n': fileOUTname = argv[++i]; break; case 'v': verbos = atoi(argv[++i]); break; case 'x': delta_x = atof(argv[++i]); break; case 'h': PrintArgList(); exit(0); break; case 'o': break; } } else{ fileINname=argv[i]; } } double elapTime; clock_t beginT, beginT_AfterINIT, endT, endT_AFTER_wr; beginT = clock(); cout << "ssrb_fbp2D::Input file name: " << fileINname << endl; ReadSinoDim(); if (span==0 && MRDiff==-1) MRDiff = n_planes - 1; cout << "ssrb::input parameters: rings = " << n_planes << "; bins = " << n_bin << "; ang_views = " << n_ang << " .. pixDim: "<< pixDim << " ringDim: " << sliceDim << endl; cout << "ssrb::input parameters: Max. Ring Diff. = " << MRDiff << endl; //"; Span = " << span << endl; cout << "ssrb::output 2Dsino: slices = " << 2*n_planes-1 << "; sliceDim: " << sliceDim/2 << endl; cout << "... " << endl; read_sino3D(); cout << "3Dsino read" << endl; cout << "... " << endl; //Create sino2D, SSRB algorithm int plane2D, i, j, k; n_slices=2*n_planes-1; sino2D = new float**[n_bin]; planesNorm = new int[n_slices]; // for normalization: for(i=0;i max. 2*n_planes - 1 //Max Ring Difference: if (abs((k/n_planes - k%n_planes)) <= MRDiff) { // Z1= p3D / n_planes; Z2= p3D % n_planes planesNorm[plane2D]++; sino2D[i][j][plane2D]=(float)sino3D[i][j][k]+ sino2D[i][j][plane2D]; // cout << "3Dp= " << k << " plane2D= "<< plane2D << endl; } } // } /* else{ int offset= (int)((n_planes_file - 2*n_planes + 1)/2 ); int lastSegP; k=0; for(int s=0;s<=nSEG;s++){ //TO DO: añadir aqui MRDiff!!!! if(s==0){ while(k<2*n_planes-1){ planesNorm[k]++; sino2D[i][j][k]=(float)sino3D[i][j][k]; k++; } }else{ plane2D=s*span-1; while(k0){ for(k=0;k<(2*n_planes-1);k++){ if (planesNorm[k]>1) sino2D[i][j][k]=sino2D[i][j][k]/(float)planesNorm[k]; } } } } //write_sino2D(); //free_sinos(); FREE sinos 3D: for(i=0;i=R (R=n_bin) int n; n=(int)ceil(log(n_bin)/log(2)); P=(int)pow(2,n); // Mem. allocation of in_data, out_data (temporal data fftw_complex) and plan (fftw_plan), to be used for filtering with FFTW libraries (type: fftw_complex) int Pd2 = P/2+1; filt = new double[Pd2]; fftw_complex *out_data; double *in_data; fftw_plan plan_D, plan_I; in_data = (double*) fftw_malloc(sizeof(double)*P); out_data = (fftw_complex*) fftw_malloc(sizeof(fftw_complex)*Pd2); plan_D = fftw_plan_dft_r2c_1d(P,in_data,out_data, FFTW_ESTIMATE); plan_I = fftw_plan_dft_c2r_1d(P,out_data,in_data, FFTW_ESTIMATE); //(*)FFTW NOTE: if input data in[i] are purely real numbers, the DFT output satisfies the "Hermitian" redundancy: out[i] is the conjugate of out[n-i]. // (for multidimensional: For example, consider the transform of a two-dimensional real array of size n0 by n1. // The output of the r2c transform is a two-dimensional complex array of size n0 by n1/2+1, where the y dimension has been cut nearly in half because of redundancies in the output.) // Mem. allocation for other temporal variables: costheta = new double[n_ang]; sintheta = new double[n_ang]; xc = new double*[M]; for(i=0;i cuantification factor) } } ///////cout<< in_data[33][0] << endl; ///////cout<< in_data[33][0]/P << endl; ///////cout<< "..." << endl; // BACKPROJECTION per slice fastBP(k); } endT_AFTER_wr=clock(); write_INTERFILE(fileOUTname, image, M, M, n_slices, delta_x, delta_slice); fftw_free(in_data); fftw_free(out_data); fftw_destroy_plan(plan_D); fftw_destroy_plan(plan_I); free_data(); endT = clock(); elapTime = ((double)(endT - beginT))/CLOCKS_PER_SEC; double elapTime_perSlice = ( (double)(beginT_AfterINIT - beginT + endT - endT_AFTER_wr) + (double)(endT_AFTER_wr - beginT_AfterINIT)/n_slices )/CLOCKS_PER_SEC; cout << "fbp2D::Process time(s): " << elapTime << endl; cout << "fbp2D::Process time(s) per slice: " << elapTime_perSlice << endl; } // end main void ReadSinoDim(){ char nameIN_hv[512]; strcpy(nameIN_hv, fileINname); strcat(nameIN_hv, ".hv"); if (typeINfile==0){ theINfile_hv = fopen( nameIN_hv , "r" ); // open text file "theFile" } if (theINfile_hv==NULL) { printf ("Error opening file \n"); exit (1); } char cadena[100]; char *c; c= fgets (cadena, 20, theINfile_hv); while (c != NULL) { if ( strcmp("!matrix size [1] :=", cadena) == 0 ){ fscanf (theINfile_hv, "%d",&n_bin); c= fgets (cadena, 1000, theINfile_hv); c= fgets (cadena, 33, theINfile_hv); fscanf (theINfile_hv, "%f",&pixDim); }else if ( strcmp("!matrix size [2] :=", cadena) == 0 ) { fscanf (theINfile_hv, "%d",&n_ang); }else if ( strcmp("!matrix size [3] :=", cadena) == 0 ) { fscanf (theINfile_hv, "%d",&n_planes_file); c= fgets (cadena, 1000, theINfile_hv); c= fgets (cadena, 33, theINfile_hv); fscanf (theINfile_hv, "%f",&sliceDim); c=NULL; } c= fgets (cadena, 1000, theINfile_hv); c= fgets (cadena, 20, theINfile_hv); } fclose(theINfile_hv); if (span==0){ n_planes=(int)sqrt((float)n_planes_file); // Total 3D planes = rings * rings } else{ nSEG= (((2*(MRDiff+1)+1)/span) - 1)/2; // TO DO: now only for span==3 !!!!!! n_planes= (n_planes_file + 2*nSEG*span*(nSEG+1) - 2*nSEG + 1) / (4*nSEG + 2); } } void read_sino3D(){ int i,j,k; char nameIN_v[512]; strcpy(nameIN_v,fileINname); strcat(nameIN_v, ".v"); theINfile_v=fopen(nameIN_v, "rb"); if (theINfile_v==NULL) { printf ("Error opening file (.v) \n"); exit (1); } SINO_TYPE *sino_line; sino_line = (SINO_TYPE*) malloc( n_bin*n_ang*n_planes_file*sizeof(SINO_TYPE)); fread(sino_line,1,n_bin*n_ang*n_planes_file*sizeof(SINO_TYPE), theINfile_v); fclose(theINfile_v); //--- Initialize sino3D with data read from file--- sino3D = new SINO_TYPE**[n_bin]; for(i=0;i MRDiff for(k=0;k<(n_planes_file);k++){ sino3D[i][j][k]=sino_line[ k*n_ang*n_bin + j*n_bin + i]; } } } free(sino_line); } void calculate_filter(){ double temp_f; double f_cut = Nf_cut / (2*delta_rho); // Nyquist frecuency = 1 / (2*delta_rho) for(int r=1;r<=P/2;r++){ temp_f=(double)r/(delta_rho*(double)P); switch (type_f) { case 1: // Hamming generalizad if(temp_f=0 && rl