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 #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 }