The flutter shutter camera simulator
flutter.cpp
Go to the documentation of this file.
00001 /*flutter.cpp*/
00002 /*
00003  * Copyright 2012, 2010 IPOL Image Processing On Line http://www.ipol.im/
00004  *
00005  * This program is free software: you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation, either version 3 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017  */
00031 #include <stdlib.h>
00032 #include <time.h>
00033 #include <math.h>
00034 #include "codes_flutter.cpp"
00035 #include "flutter.h"
00036 #include "fftw_routines.h"
00037 #include "borders.h"
00038 #include "mt19937ar.h"
00039 #ifdef _OPENMP
00040 #include <omp.h>
00041 #endif
00042 #ifndef M_PI
00043 
00046 #define M_PI 3.14159265358979323846
00047 #endif
00048 
00049 #define ABS(x)    (((x) > 0) ? (x) : (-(x))) //absolute value
00050 #define eps   0.000001//epsilon definition
00051 #define POS(x) (((x) > 0) ? (x) : (0))
00052 
00053 
00054 
00059 
00078 void flutter_kernel(double *kernel_real, double *kernel_imag, int code_number,
00079                     int width, int height, float velocity, float deltat)
00080 {
00081 
00086 
00087 
00088     double* imag_temp = new double[width*height];
00089     double* real_temp = new double[width*height];
00090     for(int i=0; i<width*height; i++)
00091     {
00092         imag_temp[i]=0;
00093         real_temp[i]=0;
00094     }
00095     for (int j=0; j<height; j++)
00096     {
00097         float xi1=-width/2;
00098         for (int i=0; i<width; i++)
00099         {
00100 
00101             float xi=2*M_PI*velocity*deltat/width*xi1;
00102             xi1=xi1+1;
00103 
00104             for (int k=0; k<code_length; k++)
00105             {
00106 
00107                 imag_temp[i+width*j] =imag_temp[i+width*j]+
00108                                       code[code_number][k]*
00109                                       sin(-xi*(k+0.5));
00110                 real_temp[i+width*j] =real_temp[i+width*j]+
00111                                       code[code_number][k]*
00112                                       cos(-xi*(k+0.5));
00113 
00114 
00115             }
00116             if (ABS(xi)>eps) //avoiding 0/0
00117             {
00118                 imag_temp[i+width*j] =imag_temp[i+width*j]*
00119                                       ((2.0*deltat)*sin(xi/2.0))/xi;
00120                 //ELSE =1;
00121                 real_temp[i+width*j] =real_temp[i+width*j]*
00122                                       ((2.0*deltat)*sin(xi/2.0))/xi;
00123                 //ELSE =1;  => HUMAN SHAPPED.
00124             }
00125 
00126         }
00127     }
00128     int i,j,x,y;
00129 
00130     for (j=0; j<height; j++)
00131         for (i=0; i<width; i++)
00132         {
00135             x=i;
00136             y=j;
00137             if (i<width/2 && j<height/2)
00138             {
00139                 x=i+width/2;
00140                 y=j+height/2;
00141             }
00142             if (i>=width/2 && j<height/2)
00143             {
00144                 x=i-width/2;
00145                 y=j+height/2;
00146             }
00147             if (i<width/2 && j>=height/2)
00148             {
00149                 x=i+width/2;
00150                 y=j-height/2;
00151             }
00152             if (i>=width/2 && j>=height/2)
00153             {
00154                 x=i-width/2;
00155                 y=j-height/2;
00156             }
00157             kernel_imag[j*width+i]=imag_temp[y*width+x];
00158             kernel_real[j*width+i]=real_temp[y*width+x];
00159         }
00160     delete [] imag_temp;
00161     delete [] real_temp;
00162 
00163 }
00164 
00165 
00166 
00167 
00172 
00190 void flutter_restore(double *acquired,int code_number, int width, int height,
00191                      float velocity, double *restored,
00192                      int border_size, float deltat)
00193 {
00196 
00197 
00198     int W=width+border_size; //new  width of image afer mirror
00199     double* Imsym = new double[W*height]; //new image allocation
00200 
00201 
00202 
00204     borders(acquired,Imsym,width,height);
00205 
00206 
00207 
00209     double* reOut = new double[W*height];
00210     double* imOut = new double[W*height];
00211 
00212     forward_fftw_simple(Imsym, W, height, reOut, imOut);
00213 
00214     delete [] Imsym;
00217     double* kernel_real = new double[W*height];
00218     double* kernel_imag = new double[W*height];
00219 
00220     for ( int i=0; i<W*height; i++)
00221     {
00222         kernel_real[i]=0.0f;
00223         kernel_imag[i]=0.0f;
00224     }
00225 
00226     flutter_kernel(kernel_real, kernel_imag, code_number, W, height,
00227                    velocity, deltat);
00228 
00229 
00231     fftw_division(reOut, imOut, kernel_real, kernel_imag, W, height);
00232     delete [] kernel_real;
00233     delete [] kernel_imag;
00234 
00235 
00236     backward_fftw_simple(reOut, imOut, restored, W, height);
00237     delete [] reOut;
00238     delete [] imOut;
00239 }
00240 
00241 
00242 
00243 
00244 
00245 
00251 
00260 float integral_code(int code_number, float deltat)
00261 {
00262     float I=0;
00263     for (int k=0; k<code_length; k++)
00264     {
00265         I=I+code[code_number][k];
00266 
00267     }
00268     return I*deltat;
00269 }
00270 
00271 
00272 
00273 
00278 
00301 void flutter_kernel_k(double *kernel_real, double *kernel_imag, int k,
00302                       int width, int height, float velocity, float deltat)
00303 {
00304 
00309 
00310 
00311     double* imag_temp = new double[width*height];
00312     double* real_temp = new double[width*height];
00313     for(int i=0; i<width*height; i++)
00314     {
00315         imag_temp[i]=0;
00316         real_temp[i]=0;
00317     }
00318     for (int j=0; j<height; j++)
00319     {
00320         float xi1=-width/2;
00321         for (int i=0; i<width; i++)
00322         {
00323 
00324             float xi=2*M_PI*velocity*deltat/width*xi1;
00325             xi1=xi1+1;
00326 
00327             imag_temp[i+width*j] =sin(-xi*(k+0.5));
00328             real_temp[i+width*j] =cos(-xi*(k+0.5));
00329 
00330 
00331 
00332             if (ABS(xi)>eps) //avoiding 0/0
00333             {
00334                 imag_temp[i+width*j] =imag_temp[i+width*j]*
00335                                       ((2.0*deltat)*sin(xi/2.0))/xi;
00336                 //ELSE =1;
00337                 real_temp[i+width*j] =real_temp[i+width*j]*
00338                                       ((2.0*deltat)*sin(xi/2.0))/xi;
00339                 //ELSE =1;  => HUMAN SHAPPED.
00340             }
00341         }
00342     }
00343     int i,j,x,y;
00344 
00345     for (j=0; j<height; j++)
00346         for (i=0; i<width; i++)
00347         {
00350             x=i;
00351             y=j;
00352             if (i<width/2 && j<height/2)
00353             {
00354                 x=i+width/2;
00355                 y=j+height/2;
00356             }
00357             if (i>=width/2 && j<height/2)
00358             {
00359                 x=i-width/2;
00360                 y=j+height/2;
00361             }
00362             if (i<width/2 && j>=height/2)
00363             {
00364                 x=i+width/2;
00365                 y=j-height/2;
00366             }
00367             if (i>=width/2 && j>=height/2)
00368             {
00369                 x=i-width/2;
00370                 y=j-height/2;
00371             }
00372             kernel_imag[j*width+i]=imag_temp[y*width+x];
00373             kernel_real[j*width+i]=real_temp[y*width+x];
00374         }
00375 
00376     delete [] imag_temp;
00377     delete [] real_temp;
00378 
00379 
00380 }
00381 
00386 
00400 void  add_poisson_noise(double *image, int width, int height, float snr)
00401 {
00402 
00403     int em;
00404     double lambda;
00405     bool rejected;
00406     double t;
00407     for (int i=0; i<width*height; i++)
00408     {
00409 
00410         lambda=POS(image[i]*snr*snr/100);
00411         //SNR FOR LEVEL 100 =>Poisson intensity to simulate
00412         // due to small errors mage[i]
00413         // can be \approx -10^{-6}
00414         // this avoids any trouble when taking the square root/
00416 
00417         if ((image[i]<5000/(snr*snr)))
00419 
00420         {
00421             lambda=exp(-lambda);
00422             em=-1;
00423             t=1;
00424             rejected=true;
00425             while (rejected)
00426             {
00427                 em=em+1;
00428                 t=t*mt_genrand_res53();
00429                 if (t<=lambda)
00430                 {
00431                     image[i]=100*em/(snr*snr);//rescaling
00432                     rejected=false;
00433                 }
00434             }
00435         }
00436         else 
00437         {
00438             image[i]=round(lambda +
00439                            ((double)sqrt(-2.0 * log(mt_genrand_res53()))
00440                             * (double)cos(2.0 * M_PI * mt_genrand_res53())*
00441                             (double)(sqrt(lambda))))*100/(snr*snr);
00442 
00443         }
00444 
00445     }
00446 }
00447 
00448 
00449 
00450 
00455 
00468 void flutter_numerical(double *acquired, int code_number, int width, int height,
00469                        float velocity, float deltat, float snr)
00470 {
00471     //A numerical flutter shutter is a sum of code_length analog flutter shutter
00472     // with codes : (0, ... , 0, ak , 0, ... , 0)
00473     // zeros except on k-th position : ak (=code[code_number][k])
00474 
00476     double* reOut = new double[width*height];
00477     double* imOut = new double[width*height];
00478 
00479     for ( int i=0; i<width*height; i++)
00480     {
00481         reOut[i]=0.0f;
00482         imOut[i]=0.0f;
00483     }
00484 
00485 
00487     forward_fftw_simple(acquired, width, height, reOut, imOut);
00488 
00491 
00492     for ( int i=0; i<width*height; i++)
00493     {
00494         acquired[i]=0.0f;
00495     }
00496 
00497 
00498     double** reOut_temp = new double*[code_length]; // to store the k-th
00499     double** imOut_temp = new double*[code_length]; // elementaryfourier transf.
00500     double** im_temp = new double*[code_length];//to store the k th observed
00501     double** kernel_real = new double*[code_length];// to store the k-th kernel
00502     double** kernel_imag = new double*[code_length];
00503 
00504     for (int k=0; k<code_length; k++)
00505     {
00506         reOut_temp[k] = new double[width*height];
00507         imOut_temp[k] = new double[width*height];
00508         im_temp[k] = new double[width*height];
00509         kernel_real[k] = new double[width*height];
00510         kernel_imag[k] = new double[width*height];
00511     }
00512 
00513 
00514 
00515 
00516     for ( int i=0; i<width*height; i++)
00517     {
00518         for (int k=0; k<code_length; k++)
00519         {
00520             reOut_temp[k][i]=reOut[i];
00521             imOut_temp[k][i]=imOut[i];
00522             im_temp[k][i]=0.0f;
00523             kernel_real[k][i]=0.0f;
00524             kernel_real[k][i]=0.0f;
00525         }
00526     }
00527 
00528     delete [] reOut;
00529     delete [] imOut;
00530 
00531 
00532 
00533     for (int k=0; k<code_length; k++)
00534     {
00535 
00536 //filling the k th kernel
00537         flutter_kernel_k(kernel_real[k], kernel_imag[k], k,
00538                          width, height, velocity, deltat);
00539 //convolution
00540         fftw_multiplication(reOut_temp[k], imOut_temp[k], kernel_real[k],
00541                             kernel_imag[k],
00542                             width , height);
00543 
00544         backward_fftw_simple(reOut_temp[k], imOut_temp[k], im_temp[k], width ,
00545                              height);
00546         //here im_temp[k] contains the k-th observed withtout noise
00547         //Noise:
00548         add_poisson_noise(im_temp[k], width, height, snr);
00549         //here im_temp contains the k-th observation
00550         //(and without flutter)
00551     }
00552 
00553 
00554 
00555     for (int k=0; k<code_length; k++)
00556     {
00557 
00558         for ( int i=0; i<width*height; i++)
00559         {
00560             //adding to get the observed and flutter effect
00561             acquired[i]=acquired[i]+code[code_number][k]*im_temp[k][i];
00562 
00563         }
00564         delete [] reOut_temp[k];
00565         delete [] imOut_temp[k];
00566         delete [] kernel_real[k];
00567         delete [] kernel_imag[k];
00568         delete [] im_temp[k];
00569     }
00570 
00571     delete [] reOut_temp;
00572     delete [] imOut_temp;
00573     delete [] kernel_real;
00574     delete [] kernel_imag;
00575     delete [] im_temp;
00576 
00577 
00578 }
00579 
00580 
00581 
00582 
00587 
00603 void flutter_analog(double *acquired, int code_number, int width,
00604                     int height, float velocity, float deltat,
00605                     float snr)
00606 {
00607 
00609     double* reOut = new double[width*height];
00610     double* imOut = new double[width*height];
00611     for ( int i=0; i<width*height; i++)
00612     {
00613         reOut[i]=0.0f;
00614         imOut[i]=0.0f;
00615     }
00616 
00618     forward_fftw_simple(acquired, width, height, reOut, imOut);
00619 
00622     double* kernel_real = new double[width*height];
00623     double* kernel_imag = new double[width*height];
00624     for ( int i=0; i<width*height; i++)
00625     {
00626         kernel_real[i]=0.0f;
00627         kernel_imag[i]=0.0f;
00628 
00629     }
00631     flutter_kernel(kernel_real, kernel_imag, code_number, width, height,
00632                    velocity, deltat);
00633 
00634 
00635 
00637     fftw_multiplication(reOut, imOut, kernel_real, kernel_imag, width , height);
00638     backward_fftw_simple(reOut, imOut, acquired, width , height);
00639     //Here noise_less contains the motion blurred landscape (no noise)
00640     delete [] reOut;
00641     delete [] imOut;
00642     delete [] kernel_real;
00643     delete [] kernel_imag;
00645 
00646     add_poisson_noise(acquired, width, height, snr);
00647 }
 All Files Functions Variables Typedefs Defines