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 #ifndef M_PI
00040 
00043 #define M_PI 3.14159265358979323846
00044 #endif
00045 
00046 #define ABS(x)    (((x) > 0) ? (x) : (-(x))) //absolute value
00047 #define eps   0.000001//epsilon definition
00048 #define POS(x) (((x) > 0) ? (x) : (0))
00049 
00050 
00051 
00056 
00075 void flutter_kernel(double *kernel_real, double *kernel_imag, int code_number,
00076                     int width, int height, float velocity, float deltat)
00077 {
00078 
00083 
00084 
00085 
00086     for (int j=0; j<height; j++)
00087     {
00088         float xi1=-width/2;
00089         for (int i=floor((width+1)/2); i<width; i++)
00090         {
00091 
00092             float xi=2*M_PI*velocity*deltat/width*xi1;
00093             xi1=xi1+1;
00094 
00095             for (int k=0; k<code_length; k++)
00096             {
00097 
00098                 kernel_imag[i+width*j] =kernel_imag[i+width*j]+
00099                                         code[code_number][k]*
00100                                         sin(-xi*(k+0.5));
00101                 kernel_real[i+width*j] =kernel_real[i+width*j]+
00102                                         code[code_number][k]*
00103                                         cos(-xi*(k+0.5));
00104 
00105 
00106             }
00107             if (ABS(xi)>eps)  //avoiding 0/0;else =deltat
00108             {
00109                 kernel_imag[i+width*j] =kernel_imag[i+width*j]*
00110                                         ((2.0*deltat)*sin(xi/2.0))/xi;
00111                 kernel_real[i+width*j] =kernel_real[i+width*j]*
00112                                         ((2.0*deltat)*sin(xi/2.0))/xi;
00113             }
00114             else
00115             {
00116                 kernel_imag[i+width*j]=deltat*kernel_imag[i+width*j];
00117                 kernel_real[i+width*j]=deltat*kernel_real[i+width*j];
00118             }
00119 
00120         }
00121 
00122         for (int i=0; i<floor((width+1)/2); i++)
00123         {
00124 
00125             float xi=2*M_PI*velocity*deltat/width*xi1;
00126             xi1=xi1+1;
00127 
00128             for (int k=0; k<code_length; k++)
00129             {
00130 
00131                 kernel_imag[i+width*j] =kernel_imag[i+width*j]+
00132                                         code[code_number][k]*
00133                                         sin(-xi*(k+0.5));
00134                 kernel_real[i+width*j] =kernel_real[i+width*j]+
00135                                         code[code_number][k]*
00136                                         cos(-xi*(k+0.5));
00137 
00138 
00139             }
00140             if (ABS(xi)>eps)  //avoiding 0/0;else =1
00141             {
00142                 kernel_imag[i+width*j] =kernel_imag[i+width*j]*
00143                                         ((2.0*deltat)*sin(xi/2.0))/xi;
00144                 kernel_real[i+width*j] =kernel_real[i+width*j]*
00145                                         ((2.0*deltat)*sin(xi/2.0))/xi;
00146             }
00147             else
00148             {
00149                 kernel_imag[i+width*j]=deltat*kernel_imag[i+width*j];
00150                 kernel_real[i+width*j]=deltat*kernel_real[i+width*j];
00151             }
00152 
00153         }
00154 
00155 
00156 
00157     }
00158 
00159 
00160 }
00161 
00162 
00163 
00164 
00169 
00187 void flutter_restore(double *acquired,int code_number, int width, int height,
00188                      float velocity, double *restored,
00189                      int border_size, float deltat)
00190 {
00193 
00194 
00195     int W=width+border_size; //new  width of image afer mirror
00196     double* Imsym = new double[W*height]; //new image allocation
00197 
00198 
00199 
00201     borders(acquired,Imsym,width,height);
00202 
00203 
00204 
00206     double* reOut = new double[W*height];
00207     double* imOut = new double[W*height];
00208 
00209     forward_fftw_simple(Imsym, W, height, reOut, imOut);
00210 
00211     delete [] Imsym;
00214     double* kernel_real = new double[W*height];
00215     double* kernel_imag = new double[W*height];
00216 
00217     for ( int i=0; i<W*height; i++)
00218     {
00219         kernel_real[i]=0.0f;
00220         kernel_imag[i]=0.0f;
00221     }
00222 
00223     flutter_kernel(kernel_real, kernel_imag, code_number, W, height,
00224                    velocity, deltat);
00225 
00226 
00228     fftw_division(reOut, imOut, kernel_real, kernel_imag, W, height);
00229     delete [] kernel_real;
00230     delete [] kernel_imag;
00231 
00232 
00233     backward_fftw_simple(reOut, imOut, restored, W, height);
00234     delete [] reOut;
00235     delete [] imOut;
00236 }
00237 
00238 
00239 
00240 
00241 
00242 
00248 
00257 float integral_code(int code_number, float deltat)
00258 {
00259     float I=0;
00260     for (int k=0; k<code_length; k++)
00261     {
00262         I=I+code[code_number][k];
00263 
00264     }
00265     return I*deltat;
00266 }
00267 
00268 
00269 
00270 
00275 
00298 void flutter_kernel_k(double *kernel_real, double *kernel_imag, int k,
00299                       int width, int height, float velocity, float deltat)
00300 {
00301 
00306 
00307 
00308     for (int j=0; j<height; j++)
00309     {
00310         float xi1=-width/2;
00311         for (int i=floor((width+1)/2); i<width; i++)
00312         {
00313 
00314             float xi=2*M_PI*velocity*deltat/width*xi1;
00315             xi1=xi1+1;
00316 
00317             kernel_imag[i+width*j] =sin(-xi*(k+0.5));
00318             kernel_real[i+width*j] =cos(-xi*(k+0.5));
00319 
00320 
00321 
00322             if (ABS(xi)>eps) //avoiding 0/0;else =1
00323             {
00324                 kernel_imag[i+width*j] =kernel_imag[i+width*j]*
00325                                         ((2.0*deltat)*sin(xi/2.0))/xi;
00326                 kernel_real[i+width*j] =kernel_real[i+width*j]*
00327                                         ((2.0*deltat)*sin(xi/2.0))/xi;
00328             }
00329             else
00330             {
00331                 kernel_imag[i+width*j]=deltat*kernel_imag[i+width*j];
00332                 kernel_real[i+width*j]=deltat*kernel_real[i+width*j];
00333             }
00334         }
00335         for (int i=0; i<floor((width+1)/2); i++)
00336         {
00337 
00338             float xi=2*M_PI*velocity*deltat/width*xi1;
00339             xi1=xi1+1;
00340 
00341             kernel_imag[i+width*j] =sin(-xi*(k+0.5));
00342             kernel_real[i+width*j] =cos(-xi*(k+0.5));
00343 
00344 
00345 
00346             if (ABS(xi)>eps) //avoiding 0/0;else =1
00347             {
00348                 kernel_imag[i+width*j] =kernel_imag[i+width*j]*
00349                                         ((2.0*deltat)*sin(xi/2.0))/xi;
00350                 kernel_real[i+width*j] =kernel_real[i+width*j]*
00351                                         ((2.0*deltat)*sin(xi/2.0))/xi;
00352             }
00353             else
00354             {
00355                 kernel_imag[i+width*j]=deltat*kernel_imag[i+width*j];
00356                 kernel_real[i+width*j]=deltat*kernel_real[i+width*j];
00357             }
00358         }
00359 
00360     }
00361 
00362 
00363 
00364 }
00365 
00370 
00384 void  add_poisson_noise(double *image, int width, int height, float snr)
00385 {
00386 
00387     int em;
00388     double lambda;
00389     bool rejected;
00390     double t;
00391     for (int i=0; i<width*height; i++)
00392     {
00393 
00394         lambda=POS(image[i]*snr*snr/100);
00395         //SNR FOR LEVEL 100 =>Poisson intensity to simulate
00396         // due to small errors mage[i]
00397         // can be \approx -10^{-6}
00398         // this avoids any trouble when taking the square root/
00400 
00401         if ((image[i]<5000/(snr*snr)))
00403 
00404         {
00405             lambda=exp(-lambda);
00406             em=-1;
00407             t=1;
00408             rejected=true;
00409             while (rejected)
00410             {
00411                 em=em+1;
00412                 t=t*mt_genrand_res53();
00413                 if (t<=lambda)
00414                 {
00415                     image[i]=100*em/(snr*snr);//rescaling
00416                     rejected=false;
00417                 }
00418             }
00419         }
00420         else 
00421         {
00422             image[i]=round(lambda +
00423                            ((double)sqrt(-2.0 * log(mt_genrand_res53()))
00424                             * (double)cos(2.0 * M_PI * mt_genrand_res53())*
00425                             (double)(sqrt(lambda))))*100/(snr*snr);
00426 
00427         }
00428 
00429     }
00430 }
00431 
00432 
00433 
00434 
00439 
00452 void flutter_numerical(double *acquired, int code_number, int width, int height,
00453                        float velocity, float deltat, float snr)
00454 {
00455     //A numerical flutter shutter is a sum of code_length analog flutter shutter
00456     // with codes : (0, ... , 0, ak , 0, ... , 0)
00457     // zeros except on k-th position : ak (=code[code_number][k])
00458 
00460     double* reOut = new double[width*height];
00461     double* imOut = new double[width*height];
00462 
00463     for ( int i=0; i<width*height; i++)
00464     {
00465         reOut[i]=0.0f;
00466         imOut[i]=0.0f;
00467     }
00468 
00469 
00471     forward_fftw_simple(acquired, width, height, reOut, imOut);
00472 
00475 
00476     for ( int i=0; i<width*height; i++)
00477     {
00478         acquired[i]=0.0f;
00479     }
00480 
00481 
00482     double** reOut_temp = new double*[code_length]; // to store the k-th
00483     double** imOut_temp = new double*[code_length]; // elementaryfourier transf.
00484     double** im_temp = new double*[code_length];//to store the k th observed
00485     double** kernel_real = new double*[code_length];// to store the k-th kernel
00486     double** kernel_imag = new double*[code_length];
00487 
00488     for (int k=0; k<code_length; k++)
00489     {
00490         reOut_temp[k] = new double[width*height];
00491         imOut_temp[k] = new double[width*height];
00492         im_temp[k] = new double[width*height];
00493         kernel_real[k] = new double[width*height];
00494         kernel_imag[k] = new double[width*height];
00495     }
00496 
00497 
00498 
00499 
00500     for ( int i=0; i<width*height; i++)
00501     {
00502         for (int k=0; k<code_length; k++)
00503         {
00504             reOut_temp[k][i]=reOut[i];
00505             imOut_temp[k][i]=imOut[i];
00506             im_temp[k][i]=0.0f;
00507             kernel_real[k][i]=0.0f;
00508             kernel_real[k][i]=0.0f;
00509         }
00510     }
00511 
00512     delete [] reOut;
00513     delete [] imOut;
00514 
00515 
00516 
00517     for (int k=0; k<code_length; k++)
00518     {
00519 
00520 //filling the k th kernel
00521         flutter_kernel_k(kernel_real[k], kernel_imag[k], k,
00522                          width, height, velocity, deltat);
00523 //convolution
00524         fftw_multiplication(reOut_temp[k], imOut_temp[k], kernel_real[k],
00525                             kernel_imag[k],
00526                             width , height);
00527 
00528         backward_fftw_simple(reOut_temp[k], imOut_temp[k], im_temp[k], width ,
00529                              height);
00530         //here im_temp[k] contains the k-th observed withtout noise
00531         //Noise:
00532         add_poisson_noise(im_temp[k], width, height, snr);
00533         //here im_temp contains the k-th observation
00534         //(and without flutter)
00535     }
00536 
00537 
00538 
00539     for (int k=0; k<code_length; k++)
00540     {
00541 
00542         for ( int i=0; i<width*height; i++)
00543         {
00544             //adding to get the observed and flutter effect (the code)
00545             acquired[i]=acquired[i]+code[code_number][k]*im_temp[k][i];
00546 
00547         }
00548         delete [] reOut_temp[k];
00549         delete [] imOut_temp[k];
00550         delete [] kernel_real[k];
00551         delete [] kernel_imag[k];
00552         delete [] im_temp[k];
00553     }
00554 
00555     delete [] reOut_temp;
00556     delete [] imOut_temp;
00557     delete [] kernel_real;
00558     delete [] kernel_imag;
00559     delete [] im_temp;
00560 
00561 
00562 }
00563 
00564 
00565 
00566 
00571 
00587 void flutter_analog(double *acquired, int code_number, int width,
00588                     int height, float velocity, float deltat,
00589                     float snr)
00590 {
00591 
00593     double* reOut = new double[width*height];
00594     double* imOut = new double[width*height];
00595     for ( int i=0; i<width*height; i++)
00596     {
00597         reOut[i]=0.0f;
00598         imOut[i]=0.0f;
00599     }
00600 
00602     forward_fftw_simple(acquired, width, height, reOut, imOut);
00603 
00606     double* kernel_real = new double[width*height];
00607     double* kernel_imag = new double[width*height];
00608     for ( int i=0; i<width*height; i++)
00609     {
00610         kernel_real[i]=0.0f;
00611         kernel_imag[i]=0.0f;
00612 
00613     }
00615     flutter_kernel(kernel_real, kernel_imag, code_number, width, height,
00616                    velocity, deltat);
00617 
00618 
00619 
00621     fftw_multiplication(reOut, imOut, kernel_real, kernel_imag, width , height);
00622     backward_fftw_simple(reOut, imOut, acquired, width , height);
00623     //Here noise_less contains the motion blurred landscape (no noise)
00624     delete [] reOut;
00625     delete [] imOut;
00626     delete [] kernel_real;
00627     delete [] kernel_imag;
00629 
00630     add_poisson_noise(acquired, width, height, snr);
00631 }
00632 
 All Files Functions Variables Typedefs Defines