The flutter shutter camera simulator
|
00001 /*demo_flutter.cpp*/ 00002 /* 00003 * Copyright 2012 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 */ 00018 00085 #include <stdio.h> 00086 #include <stdlib.h> 00087 #include <iostream> 00088 #include <fstream> 00089 #include "mt19937ar.h" 00090 #include <math.h> 00091 #ifndef M_PI 00092 00095 #define M_PI 3.14159265358979323846 00096 #endif 00097 #include "io_png/io_png.h" 00098 #include "flutter.h" 00099 #include "standard_routines.h" 00100 #include "midway.h" 00101 #include "borders.h" 00102 #include "codes_flutter.cpp" 00103 using namespace std; 00104 00105 00153 int main(int argc, char **argv) 00154 { 00155 //Check arguments : IN/OUT; 00156 if (argc != 13) 00157 { 00158 std::cerr << " ****************************************** " << std::endl 00159 << " ****************** Flutter-Shutter *************** " << std::endl 00160 << " **************************************************** " << std::endl 00161 << "Usage: " << argv[0] << "Image.png Flag_{code} SNR " << std::endl 00162 << "Flag_{NUM | ANALOG} Velocity Deltat Imacquired.png " << std::endl 00163 << "ImReconstructed.png Groundtruth.png Imdiff.png " << std::endl 00164 << "Code_file_name.txt FT_code_file_name.txt " << std::endl 00165 << "Input : Image.png " << std::endl 00166 << "Image to use for the simulation " << std::endl 00167 << "(grayscale or color) PNG. " << std::endl 00168 << " Codes for the Flutter-Shutter Simulator " << std::endl 00169 << "Code : can be " << std::endl 00170 << "0 for Snapshot (classic strategy) " << std::endl 00171 << "or 1 for the Raskar-code " << std::endl 00172 << "or 2 for rand-code, a code whose coefficients come " << std::endl 00173 << "from a uniform R.V on [-1,1] " << std::endl 00174 << "3 for constant 1 code (accumulation, " << std::endl 00175 << "4 for Sinc-code (sinc code is the best code given v) " << std::endl 00176 << "5 for motion-invariant photography code " << std::endl 00177 << "SNR for the level 100 :100 by default " << std::endl 00178 << "Flag_{NUM | ANALOG} 0 for Numerical Flutter " << std::endl 00179 << "or 1 for Analog Flutter " << std::endl 00180 << "Velocity v " << std::endl 00181 << " Deltat : temporal sampling (float default 1) " << std::endl 00182 << "Outputs : " << std::endl 00183 << "Imacquired.png: acquired image in PNG. " << std::endl 00184 << "Imdiff: difference image (groundtruth and " << std::endl 00185 << "actual reconstruction) image in PNG. " << std::endl 00186 << "ImReconstructed: reconstructed in PNG. " << std::endl 00187 << "code_file_name: txt files that contains the " << std::endl 00188 << "code coefficients $a_k$ " << std::endl 00189 << "FT_code_file :txt file that contains the Fourier " << std::endl 00190 << "transform of the flutter Shutter function " << std::endl 00191 << "**************************************************** " << std::endl 00192 << "****** Yohann Tendero, 2012 ********************** " << std::endl 00193 << "**************************************************** " << std::endl; 00194 return 1; 00195 } 00196 00197 00198 00199 00200 00201 00202 00203 00216 const int code_length=52; //Length of the code 00217 const int num_plot_points=100; //number of points used for plots 00222 00223 float * Image_color; 00224 size_t width, height, channel_number; 00225 if (NULL == (Image_color = read_png_f32(argv[1], &width, &height, 00226 &channel_number))) 00227 { 00228 std::cerr << "Unable to load file " << argv[1] << std::endl; 00229 return 1; 00230 } 00231 00232 00238 00239 00241 float** restored_out = new float*[channel_number]; 00242 float** acquired_out = new float*[channel_number]; 00243 const int acquired_width=width-code_length; 00244 const int border_size=acquired_width; 00245 //Classic mirror symmetry adding 2*code_length in the direction of 00246 //the blur on each sides. 00247 const int restored_width=acquired_width+border_size; 00248 const int out_width=acquired_width-2*code_length;// avoid border effects. 00249 const int crop_translation=round(code_length/2); 00250 double** restored = new double*[channel_number]; 00251 double* acquired = new double[width*height]; 00252 double* acquired_crop= new double[acquired_width*height]; 00253 00254 // Read parameter 00255 int code_number=atoi(argv[2]); 00256 float snr=atof(argv[3]); 00257 int flag_num_ana_flutter=atoi(argv[4]); 00258 float velocity=atof(argv[5]); 00259 float deltat=atof(argv[6]); 00260 //Init of random generator here so 00261 //it will produce independant RV 00262 // for all k in the following loop 00263 mt_init_genrand((unsigned long int) time(NULL)); 00264 unsigned k; 00265 00266 00267 00268 for ( k=0; k<channel_number; k++) // LOOP OVER CHANNELS 00269 { 00270 00271 00272 00278 00279 00280 00281 00283 00284 00285 for (unsigned i=0; i<width*height; i++) 00286 acquired[i]=Image_color[k*width*height+i]; 00288 if (flag_num_ana_flutter==0)//analog case 00289 { 00290 flutter_analog(acquired, code_number, width, 00291 height, velocity, deltat, snr); 00292 } 00293 else 00294 { 00295 00296 flutter_numerical(acquired, code_number, width, height, 00297 velocity, deltat, snr); 00298 } 00299 00301 for (int column=0; column<acquired_width; column++) 00302 { 00303 for (unsigned line=0; line<height; line++) 00304 { 00305 acquired_crop[line*acquired_width+column]= 00306 acquired[line*(width)+column+crop_translation]; 00307 } 00308 } 00309 00310 00311 00317 00318 00319 00320 00321 00322 00323 restored[k] = new double[restored_width*height]; 00324 00325 flutter_restore(acquired_crop, code_number, acquired_width, height, 00326 velocity, restored[k], border_size, deltat); 00327 00328 00329 00331 restored_out[k] = new float[out_width*height]; 00332 acquired_out[k] = new float[out_width*height]; 00333 00334 for (int column=0; column<out_width; column++) 00335 { 00336 for (unsigned line=0; line<height; line++) 00337 { 00338 restored_out[k][line*out_width+column]= 00339 restored[k][line*(acquired_width+border_size)+column+ 00340 2*crop_translation]; 00341 acquired_out[k][line*out_width+column]= 00342 acquired[line*(acquired_width+code_length)+column+ 00343 3*crop_translation]; 00344 } 00345 } 00346 00347 00348 00349 00350 00351 } //END OF THE LOO FOR RGB 00352 for (unsigned k=0; k<channel_number; k++) 00353 delete [] restored[k]; 00354 delete [] acquired; 00355 delete [] acquired_crop; 00356 delete [] restored; 00357 00358 float normalization_factor=integral_code(code_number, deltat); 00361 float* acquired_color = new float[channel_number*out_width*height]; 00362 float* restored_color = new float[channel_number*out_width*height]; 00363 for (unsigned k=0; k<channel_number; k++) 00364 for (unsigned i=0; i<out_width*height; i++) 00365 { 00366 acquired_color[k*out_width*height+i]=acquired_out[k][i] 00367 /normalization_factor; 00368 restored_color[k*out_width*height+i]=restored_out[k][i]; 00369 } 00370 00371 for (unsigned k=0; k<channel_number; k++) 00372 { 00373 delete [] acquired_out[k]; 00374 delete [] restored_out[k]; 00375 } 00376 delete [] acquired_out; 00377 delete [] restored_out; 00378 00379 // the outputs with colors are acquired_color and acquired_color 00380 00381 00382 00384 float* Image_crop = new float[channel_number*out_width*height]; 00386 for (unsigned k=0; k<channel_number; k++) 00387 { 00388 for (int column=0; column<out_width; column++) 00389 { 00390 for (unsigned line=0; line<height; line++) 00391 { 00392 Image_crop[line*out_width+column+k*height*out_width]= 00393 Image_color[line*(width)+column+ 00394 3*crop_translation+k*height*width]; 00395 } 00396 } 00397 } 00398 00399 00400 free(Image_color); 00402 write_png_f32(argv[7],acquired_color,out_width,height,channel_number); 00403 delete [] acquired_color; 00404 00406 write_png_f32(argv[8],restored_color,out_width,height,channel_number); 00407 00409 write_png_f32(argv[9],Image_crop,out_width, height, channel_number); 00410 00416 00417 00418 00419 00420 00421 00422 00423 float* difference = new float[channel_number*out_width*height]; 00424 image_difference(Image_crop,restored_color, out_width, height, 00425 channel_number,difference); 00426 00428 RMSE(difference, out_width, height,channel_number,3*code_length,0); 00429 00431 dynamic_renormalization(difference, out_width, height,channel_number); 00432 00433 00434 00435 00440 00441 00442 00443 00444 00446 write_png_f32(argv[10],difference,out_width, height, channel_number); 00447 delete [] difference; 00448 00449 00452 00454 ofstream file_code(argv[11], ios::out | ios::trunc); 00455 // opening the file (erase if previous exists) 00456 if (file_code) 00457 { 00458 for (int k=0; k<code_length; k++) 00459 { 00460 file_code << code[atoi(argv[2])][k] <<";" << endl; 00461 } 00462 00463 file_code.close(); 00464 } 00465 else 00466 cerr << "Unable to open file !" << endl; 00467 00469 ofstream file_TFcode(argv[12], ios::out | ios::trunc); 00470 // opening the file (erase if previous exists) 00471 if (file_TFcode) 00472 { 00473 for (float xi=-M_PI; 00474 xi<=M_PI; 00475 xi=xi+2*M_PI/num_plot_points) 00476 { 00477 file_TFcode << xi << " " << 00478 abs_hat_alpha(code[atoi(argv[2])], code_length, xi*velocity, 00479 deltat) << endl; 00480 } 00481 00482 file_TFcode.close(); 00483 } 00484 else 00485 cerr << "Unable to open file !" << endl; 00486 00487 00488 00493 00495 int difference_crop2_width=out_width-2*code_length; 00496 float** Image_crop2 = new float*[channel_number]; 00497 float** restored_crop2 = new float*[channel_number]; 00498 00499 00500 for (unsigned k=0; k<channel_number; k++) 00501 { 00502 Image_crop2[k] = new float[difference_crop2_width*height]; 00503 restored_crop2[k] = new float[difference_crop2_width*height]; 00504 00505 00506 for (unsigned j=0; j<height; j++) 00507 { 00508 for (int i=0; i<difference_crop2_width; i++) 00511 { 00512 restored_crop2[k][i+(difference_crop2_width)*j]= 00513 restored_color[i+out_width*j+code_length 00514 +k*height*out_width]; 00515 Image_crop2[k][i+(difference_crop2_width)*j]= 00516 Image_crop[i+out_width*j+code_length+k*height*out_width]; 00517 00518 } 00519 } 00520 00521 midway(Image_crop2[k],restored_crop2[k],difference_crop2_width,height); 00522 } 00523 00524 00525 00526 00527 00528 delete [] restored_color; 00529 delete [] Image_crop; 00530 00531 00532 float* difference_crop2= 00533 new float[channel_number*difference_crop2_width*height]; 00534 float* Image_crop2_final = 00535 new float[channel_number*difference_crop2_width*height]; 00536 float* restored_crop2_final = 00537 new float[channel_number*difference_crop2_width*height]; 00538 00539 00540 00541 for ( k=0; k<channel_number; k++) 00542 for (unsigned i=0; i<difference_crop2_width*height; i++) 00543 { 00544 Image_crop2_final[k*difference_crop2_width*height+i]= 00545 Image_crop2[k][i]; 00546 restored_crop2_final[k*difference_crop2_width*height+i]= 00547 restored_crop2[k][i]; 00548 } 00549 00550 00551 for (unsigned k=0; k<channel_number; k++) 00552 { 00553 delete [] Image_crop2[k]; 00554 delete [] restored_crop2[k]; 00555 } 00556 delete [] Image_crop2; 00557 delete [] restored_crop2; 00558 00559 00560 00561 image_difference(Image_crop2_final,restored_crop2_final, 00562 difference_crop2_width, height,channel_number, 00563 difference_crop2); 00564 00565 00566 delete [] Image_crop2_final; 00567 delete [] restored_crop2_final; 00568 00569 00570 00573 RMSE(difference_crop2, difference_crop2_width, height, channel_number,0,1); 00574 00575 delete [] difference_crop2; 00576 00577 00578 00579 00580 return 0; 00581 }