The flutter shutter camera simulator
|
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