algebraic lens distortion
|
00001 /* 00002 * Copyright 2009, 2010 IPOL Image Processing On Line http://www.ipol.im/ 00003 * 00004 * This program is free software: you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation, either version 3 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00016 */ 00017 00036 #include "lens_distortion.h" 00037 00041 int n_iterations=0; 00042 int f_evaluations=0; 00043 double tol_lambda= 1e-8; 00052 int test_compatibility_lens_distortion_model(double *a,int Na,double max_radius) 00053 { 00054 int k; 00055 double r,*b;/* AUXILIAR VARIABLES */ 00056 /* WE INIT TO NULL ALL POINTERS */ 00057 b=NULL; 00058 00059 /* WE ALLOCATE MEMORY */ 00060 b=(double*)malloc( sizeof(double)*(Na+1) ); 00061 // WE BUILD THE DERIVATIVE OF THE POLYNOMIAL 00062 for(k=1;k<=Na;k++) b[k]=(k+1)*a[k]; 00063 for(r=1;r<max_radius;r+=1.){ 00064 if( ami_polynomial_evaluation(b,Na,r)<0 ) {free(b); return(-1.);} 00065 } 00066 free(b); 00067 return(0); 00068 00069 } 00070 00071 00079 int ami_line2d_calculation( 00080 double line[3] , 00081 double **Points2D , 00082 int N 00083 ) 00084 { 00085 int i,j,k; /* AUXILIAR VARIABLES */ 00086 double suu,suv,svv,um,vm,h,r[4][3],min,aux,norm; /* AUXILIAR VARIABLES */ 00087 double zero=0.00000000000001; /* AUXILIAR VARIABLES */ 00088 00089 if(N<2) { 00090 printf("Number of point to calculate the line must be >2\n"); 00091 return(-1); 00092 } 00093 00094 suu=0; 00095 suv=0; 00096 svv=0; 00097 um=0; 00098 vm=0; 00099 00100 for(i=0; i<N; i++) { 00101 um+=Points2D[i][0]; 00102 vm+=Points2D[i][1]; 00103 } 00104 00105 um/=N; 00106 vm/=N; 00107 00108 for(i=0; i<N; i++) { 00109 suu+=(Points2D[i][0]-um)*(Points2D[i][0]-um); 00110 svv+=(Points2D[i][1]-vm)*(Points2D[i][1]-vm); 00111 suv+=(Points2D[i][0]-um)*(Points2D[i][1]-vm); 00112 } 00113 00114 suu/=N; 00115 svv/=N; 00116 suv/=N; 00117 00118 if(fabs(suv)<= zero) { 00119 if(suu<svv && svv>zero) { 00120 line[0]=1; 00121 line[1]=0; 00122 line[2]=-um; 00123 return(0); 00124 } 00125 if(svv<suu && suu>zero) { 00126 line[0]=0; 00127 line[1]=1; 00128 line[2]=-vm; 00129 return(0); 00130 } 00131 printf(" It is not possible to calculate the 2D line\n"); 00132 return(-1); 00133 } 00134 00135 r[2][1]=r[3][1]=r[0][0]=r[1][0]=1.; 00136 h=0.5*(suu-svv)/suv; 00137 00138 if(h>0) { 00139 r[0][1]=-h-sqrt(1.+h*h); 00140 r[0][2]=-(um+r[0][1]*vm); 00141 r[1][1]=-1./r[0][1]; 00142 r[1][2]=-(um+r[1][1]*vm); 00143 r[2][0]=h+sqrt(1.+h*h); 00144 r[2][2]=-(r[2][0]*um+vm); 00145 r[3][0]=-1./r[2][0]; 00146 r[3][2]=-(r[3][0]*um+vm); 00147 } 00148 else { 00149 r[0][1]=-h+sqrt(1+h*h); 00150 r[0][2]=-(um+r[0][1]*vm); 00151 r[1][1]=-1./r[0][1]; 00152 r[1][2]=-(um+r[1][1]*vm); 00153 r[2][0]=h-sqrt(1+h*h); 00154 r[2][2]=-(r[2][0]*um+vm); 00155 r[3][0]=-1./r[2][0]; 00156 r[3][2]=-(r[3][0]*um+vm); 00157 } 00158 00159 for(j=0; j<4; j++) { 00160 norm=sqrt(r[j][0]*r[j][0]+r[j][1]*r[j][1]); 00161 for(i=0; i<3; i++) 00162 r[j][i]/=norm; 00163 } 00164 00165 min=0.; 00166 k=0; 00167 00168 for(i=0; i<N; i++) { 00169 aux=r[0][0]*Points2D[i][0]+r[0][1]*Points2D[i][1]+r[0][2]; 00170 min+=fabs(aux); 00171 } 00172 00173 for(j=1; j<4; j++) { 00174 h=0; 00175 for(i=0; i<N; i++) { 00176 aux=r[j][0]*Points2D[i][0]+r[j][1]*Points2D[i][1]+r[j][2]; 00177 h+=fabs(aux); 00178 } 00179 if(h<min) { 00180 k=j; 00181 min=h; 00182 } 00183 } 00184 00185 line[0]=r[k][0]; 00186 line[1]=r[k][1]; 00187 line[2]=r[k][2]; 00188 return(0); 00189 } 00190 00191 00192 00203 int ami_lens_distortion_polynomial_update_distance_2v( 00204 double *x, double *y, 00205 int Np , 00206 double *a , 00207 int Na , 00208 double x0,double y0 , 00209 int k1 , 00210 int k2 , 00211 double **pol , 00212 double alpha) 00213 { 00214 int i,j,k; /* AUXILIAR VARIABLES */ 00215 double *A,*x2,*y2,*d1,*d2; /* AUXILIAR VARIABLES */ 00216 double aux,**pol1,**pol2,**p_xx,**p_xy,**p_yy; /* AUXILIAR VARIABLES */ 00217 00218 A=x2=y2=d1=d2=NULL; 00219 pol1=pol2=p_xx=p_xy=p_yy=NULL; 00220 00221 /* WE CHECK alpha VALUE */ 00222 if(alpha==0) return(0); 00223 00224 /* WE ALLOCATE MEMORY */ 00225 A=(double*)malloc( sizeof(double)*Np ); 00226 x2=(double*)malloc( sizeof(double)*Np ); 00227 y2=(double*)malloc( sizeof(double)*Np ); 00228 d1=(double*)malloc( sizeof(double)*Np ); 00229 d2=(double*)malloc( sizeof(double)*Np ); 00230 ami_calloc2d(pol1,double,2,2); 00231 ami_calloc2d(pol2,double,2,2); 00232 ami_calloc2d(p_xx,double,3,3); 00233 ami_calloc2d(p_xy,double,3,3); 00234 ami_calloc2d(p_yy,double,3,3); 00235 00236 /* WE COMPUTE THE DISTANCE TO THE IMAGE CENTER */ 00237 for(i=0; i<Np; i++) 00238 d1[i]=sqrt( (x[i]-x0)*(x[i]-x0)+(y[i]-y0)*(y[i]-y0) ); 00239 00240 /* WE COMPUTE THE POINT TRANSFORMATION WITH THE CURRENT LENS DISTORTION MODEL */ 00241 for(i=0; i<Np; i++) { 00242 A[i]=ami_polynomial_evaluation(a,Na,d1[i]); 00243 x2[i]=x0+(x[i]-x0)*A[i]; 00244 y2[i]=y0+(y[i]-y0)*A[i]; 00245 } 00246 /* WE COMPUTE THE POLYNOMS CORRESPONDING TO THE DISTANCE ERROR */ 00247 for(i=0; i<=2; i++) for(j=0; j<=2; j++) p_xx[i][j]=0.; 00248 00249 for(i=0; i<Np; i++) { 00250 aux=0; 00251 for(k=1; k<=Na; k++) if(k!=k1 && k!=k2) aux+=a[k]*pow(d1[i],(double) k); 00252 pol1[0][0]=aux*d1[i]; 00253 pol1[1][0]=pow(d1[i],(double) k1+1); 00254 pol1[0][1]=pow(d1[i],(double) k2+1); 00255 ami_2v_polynom_multiplication(pol1,1,pol1,1,p_xx); 00256 } 00257 00258 for(i=0; i<=2; i++) for(j=0; j<=2; j++) p_xx[i][j]=alpha*p_xx[i][j]/Np; 00259 00260 /* WE UPDATE THE ERROR POLYNOM */ 00261 ami_2v_polynom_multiplication(p_xx,2,p_xx,2,pol); 00262 00263 /* WE FREE THE MEMORY */ 00264 if(A!=NULL) free(A); 00265 if(x2!=NULL)free(x2); 00266 if(y2!=NULL) free(y2); 00267 if(d1!=NULL) free(d1); 00268 if(d2!=NULL) free(d2); 00269 if(p_xx!=NULL) ami_free2d(p_xx); 00270 if(p_xy!=NULL) ami_free2d(p_xy); 00271 if(p_yy!=NULL)ami_free2d(p_yy); 00272 if(pol1!=NULL)ami_free2d(pol1); 00273 if(pol2!=NULL) ami_free2d(pol2); 00274 00275 return(0); 00276 } 00277 00278 00289 double ami_lens_distortion_estimation_2v( 00290 double **x,double **y , 00291 int Nl , 00292 int *Np , 00293 double x0,double y0 , 00294 double *a , 00295 int Na , 00296 int k1 , 00297 int k2 , 00298 double alpha , 00299 double max_radius 00300 ) 00301 { 00302 int i,k,m; /* AUXILIAR VARIABLES */ 00303 double **pol_v2,d,sum_Ad,sum_dd,A,Error=0; /* AUXILIAR VARIABLES */ 00304 00305 /* WE ALLOCATE MEMORY */ 00306 ami_calloc2d(pol_v2,double,5,5); 00307 00308 /* WE UPDATE a[0] BY MINIMIZING THE DISTANCE OF THE DISTORTED POINTS TO 00309 THE UNDISTORTED POINTS */ 00310 if(alpha>0) { 00311 sum_dd=sum_Ad=0; 00312 for(m=0; m<Nl; m++) { 00313 for(i=0; i<Np[m]; i++) { 00314 d=sqrt( (x[m][i]-x0)*(x[m][i]-x0)+(y[m][i]-y0)*(y[m][i]-y0) ); 00315 A=0; 00316 for(k=1; k<=Na; k++) A+=a[k]*pow(d,(double) k+1); 00317 sum_dd+=d*d; 00318 sum_Ad+=A*d; 00319 } 00320 } 00321 a[0]=1-sum_Ad/sum_dd; 00322 } 00323 00324 for(m=0; m<Nl; m++) { 00325 /* WE UPDATE DE POLYNOM TO MINIMIZE */ 00326 ami_lens_distortion_polynomial_update_2v(x[m],y[m],Np[m],a,Na,x0,y0,k1,k2,pol_v2); 00327 ami_lens_distortion_polynomial_update_distance_2v(x[m],y[m],Np[m],a,Na,x0,y0,k1,k2,pol_v2,alpha); 00328 } 00329 00330 /* WE UPDATE THE POLYNOMIAL LENS DISTORTION MODEL */ 00331 ami_lens_distortion_model_update_2v(a,Na,k1,k2,pol_v2,max_radius); 00332 ami_free2d(pol_v2); 00333 for(m=0; m<Nl; m++) 00334 Error+=ami_LensDistortionEnergyError(x[m],y[m],Np[m],x0,y0,a,Na); 00335 return(Error/Nl); 00336 } 00337 00346 int ami_lens_distortion_model_update_2v( 00347 double *a , 00348 int Na , 00349 int k1 , 00350 int k2 , 00351 double **pol , 00352 double max_radius 00353 ) 00354 { 00355 int j,i,M,Nr=0,m=Na; /* AUXILIAR VARIABLES */ 00356 double *x,**pol_x,**pol_y,*pol_r,xr,yr,Emin,*rx,*ry,*b2,*p3,*b;/* AUXILIAR VARIABLES */ 00357 double sx,sy,Energy; /* NORMALIZATION FACTORS */ /* AUXILIAR VARIABLES */ 00358 double p_r3[6][6][19]; /* AUXILIAR VARIABLES */ 00359 00360 x=pol_r=rx=ry=b2=p3=NULL; /*Added by Luis Gomez*/ 00361 pol_x=pol_y=NULL; /*Added by Luis Gomez*/ 00362 00363 for(i=0; i<6; i++) for(j=0; j<6; j++) for(m=0; m<19; m++) p_r3[i][j][m]=0.; 00364 00365 /* WE ALLOCATE MEMORY */ 00366 x=(double*)malloc( sizeof(double)*3 ); 00367 ami_calloc2d(pol_x,double,5,5); 00368 ami_calloc2d(pol_y,double,5,5); 00369 p3=(double*) malloc(sizeof(double)*5); 00370 b=(double*)malloc( sizeof(double)*(Na+1) ); 00371 // WE FILL THE AUXILIARY LENS DISTORTION MODEL 00372 for(i=0;i<=Na;i++) b[i]=a[i]; 00373 00374 /* WE NORMALIZE POLYNOM COEFFICIENT */ 00375 sx=pow(pol[4][0],(double) 0.25); 00376 sy=pow(pol[0][4],(double) 0.25); 00377 for(i=0; i<=4; i++) { 00378 for(j=0; j<=4; j++) { 00379 if(i>0) pol[i][j]/=pow(sx,(double) i); 00380 if(j>0) pol[i][j]/=pow(sy,(double) j); 00381 } 00382 } 00383 00384 /* WE COMPUTE THE DERIVATIVES OF THE POLYNOM */ 00385 ami_2v_polynom_derivatives(pol,4,pol_x, pol_y); 00386 00387 /* WE FILL THE MATRIX TO COMPUTE THE DETERMINANT */ 00388 for(i=0; i<=3; i++) { 00389 for(m=0; m<=4; m++) { 00390 p_r3[2][i+2][m]=p_r3[1][i+1][m]=p_r3[0][i][m]=pol_x[3-i][m]; 00391 p_r3[5][i+2][m]=p_r3[4][i+1][m]=p_r3[3][i][m]=pol_y[3-i][m]; 00392 } 00393 } 00394 /* WE COMPUTE THE RESOLVENT POLYNOM */ 00395 pol_r=(double*) malloc(sizeof(double)*19); 00396 ami_polynom_determinant(p_r3,18,6,pol_r); 00397 00398 /* WE COMPUTE THE RESOLVENT POLYNOM DEGREE */ 00399 for(i=0; i<=18; i++) { 00400 if(pol_r[i]!=0) Nr=i; 00401 } 00402 /* WE COMPUTE THE ROOT OF THE RESOLVENT POLYNOM */ 00403 rx=(double*) malloc(sizeof(double)*Nr); 00404 ry=(double*) malloc(sizeof(double)*Nr); 00405 b2=(double*) malloc(sizeof(double)*(Nr+1)); 00406 for(i=0; i<=Nr; i++) b2[i]=pol_r[Nr-i]; 00407 for(i=0; i<Nr; i++) { 00408 rx[i]=0.0; /*Added by Luis Gomez*/ 00409 ry[i]=0.0; 00410 } 00411 Nr=ami_polynomial_root(b2,Nr,rx,ry); 00412 /* WE COMPUTE THE X COMPONENT BY REPLACING THE ROOTS IN THE DERIVATIVES 00413 OF THE POLYNOM */ 00414 xr=0; 00415 yr=0; 00416 Emin=10e90; 00417 for(i=0; i<Nr; i++) { 00418 if(fabs(ry[i])> 0.000000000000001) continue; 00419 ami_2v_polynom_to_1v_polynom(pol_x,4,p3,rx[i],1); 00420 M=ami_RootCubicPolynomial(p3,3,x); 00421 for(m=0; m<M; m++) { 00422 Energy=ami_2v_polynom_evaluation(pol,4,x[m],rx[i]); 00423 if(Energy<Emin) { 00424 b[k1]=a[k1]+(x[m]/sx); 00425 b[k2]=a[k2]+(rx[i]/sy); 00426 if(test_compatibility_lens_distortion_model(b,Na,max_radius)==0){ 00427 Emin=Energy; 00428 xr=rx[i]; 00429 yr=x[m]; 00430 } 00431 } 00432 } 00433 ami_2v_polynom_to_1v_polynom(pol_y,4,p3,rx[i],1); 00434 M=ami_RootCubicPolynomial(p3,3,x); 00435 for(m=0; m<M; m++) { 00436 Energy=ami_2v_polynom_evaluation(pol,4,x[m],rx[i]); 00437 if(Energy<Emin) { 00438 b[k1]=a[k1]+(x[m]/sx); 00439 b[k2]=a[k2]+(rx[i]/sy); 00440 if(test_compatibility_lens_distortion_model(b,Na,max_radius)==0){ 00441 Emin=Energy; 00442 xr=rx[i]; 00443 yr=x[m]; 00444 } 00445 } 00446 } 00447 } 00448 /* WE UPDATE THE DISTORSION POLYNOMIAL MODEL */ 00449 a[k1]+=(yr/sx); 00450 a[k2]+=(xr/sy); 00451 00452 /* WE FREE THE MEMORY */ 00453 if(x!=NULL) free(x); 00454 if(pol_x!=NULL) ami_free2d(pol_x); 00455 if(pol_y!=NULL) ami_free2d(pol_y); 00456 if(pol_r!=NULL) free(pol_r); 00457 if(p3!=NULL) free(p3); 00458 if(rx!=NULL) free(rx); 00459 if(ry!=NULL) free(ry); 00460 if(b2!=NULL) free(b2); 00461 if(b!=NULL) free(b); 00462 return(0); 00463 } 00464 00465 00474 int ami_lens_distortion_polynomial_update_2v( 00475 double *x, double *y , 00476 int Np , 00477 double *a , 00478 int Na , 00479 double x0,double y0 , 00480 int k1 , 00481 int k2 , 00482 double **pol 00483 ) 00484 { 00485 int i,j; /* AUXILIAR VARIABLES */ 00486 double *A,*x2,*y2,*d1,*d2,x2_m,y2_m,s_xx,s_yy,xA_m; /* AUXILIAR VARIABLES */ 00487 double xd1_m,yA_m,yd1_m,xd2_m,yd2_m; /* AUXILIAR VARIABLES */ 00488 double paso,**pol1,**pol2,**p_xx,**p_xy,**p_yy; /* AUXILIAR VARIABLES */ 00489 00490 A=x2=y2=d1=d2=NULL; 00491 pol1=pol2=p_xx=p_xy=p_yy=NULL; 00492 00493 /* WE ALLOCATE MEMORY */ 00494 A=(double*)malloc( sizeof(double)*Np ); 00495 x2=(double*)malloc( sizeof(double)*Np ); 00496 y2=(double*)malloc( sizeof(double)*Np ); 00497 d1=(double*)malloc( sizeof(double)*Np ); 00498 d2=(double*)malloc( sizeof(double)*Np ); 00499 ami_calloc2d(pol1,double,2,2); 00500 ami_calloc2d(pol2,double,2,2); 00501 ami_calloc2d(p_xx,double,3,3); 00502 ami_calloc2d(p_xy,double,3,3); 00503 ami_calloc2d(p_yy,double,3,3); 00504 00505 /* WE COMPUTE THE DISTANCE TO THE IMAGE CENTER */ 00506 for(i=0; i<Np; i++) 00507 d1[i]=sqrt( (x[i]-x0)*(x[i]-x0)+(y[i]-y0)*(y[i]-y0) ); 00508 00509 /* WE COMPUTE THE POINT TRANSFORMATION WITH THE CURRENT LENS DISTORTION MODEL */ 00510 for(i=0; i<Np; i++) { 00511 A[i]=ami_polynomial_evaluation(a,Na,d1[i]); 00512 x2[i]=x0+(x[i]-x0)*A[i]; 00513 y2[i]=y0+(y[i]-y0)*A[i]; 00514 } 00515 00516 /* WE COMPUTE THE DISTANCE POWER k1 AND k2 (THE COEFFICIENT OF THE LENS 00517 DISTORTION MODEL TO BE UPDATED */ 00518 for(i=0; i<Np; i++) { 00519 paso=d1[i]; 00520 d1[i]=pow(paso,(double) k1); 00521 d2[i]=pow(paso,(double) k2); 00522 } 00523 00524 /* WE COMPUTE THE VARIANCE OF THE TRANSFORMED POINTS */ 00525 x2_m=0; 00526 for(i=0; i<Np; i++) x2_m+=x2[i]; 00527 x2_m/=Np; 00528 s_xx=0; 00529 for(i=0; i<Np; i++) s_xx+=(x2[i]-x2_m)*(x2[i]-x2_m); 00530 s_xx/=Np; 00531 y2_m=0; 00532 for(i=0; i<Np; i++) y2_m+=y2[i]; 00533 y2_m/=Np; 00534 s_yy=0; 00535 for(i=0; i<Np; i++) s_yy+=(y2[i]-y2_m)*(y2[i]-y2_m); 00536 s_yy/=Np; 00537 00538 /* WE COMPUTE SOME AVERAGES WE NEED */ 00539 xA_m=0; 00540 for(i=0; i<Np; i++) xA_m+=(x[i]-x0)*A[i]; 00541 xA_m/=Np; 00542 xd1_m=0; 00543 for(i=0; i<Np; i++) xd1_m+=(x[i]-x0)*d1[i]; 00544 xd1_m/=Np; 00545 xd2_m=0; 00546 for(i=0; i<Np; i++) xd2_m+=(x[i]-x0)*d2[i]; 00547 xd2_m/=Np; 00548 yA_m=0; 00549 for(i=0; i<Np; i++) yA_m+=(y[i]-y0)*A[i]; 00550 yA_m/=Np; 00551 yd1_m=0; 00552 for(i=0; i<Np; i++) yd1_m+=(y[i]-y0)*d1[i]; 00553 yd1_m/=Np; 00554 yd2_m=0; 00555 for(i=0; i<Np; i++) yd2_m+=(y[i]-y0)*d2[i]; 00556 yd2_m/=Np; 00557 00558 /* WE COMPUTE THE POLYNOMS OF THE SECOND ORDER MOMENT OF THE POINT 00559 p_xx p_xy AND p_yy DISTRIBUTION */ 00560 for(i=0; i<Np; i++) { 00561 pol1[0][0]=(x[i]-x0)*A[i]-xA_m; 00562 pol1[1][0]=(x[i]-x0)*d1[i]-xd1_m; 00563 pol1[0][1]=(x[i]-x0)*d2[i]-xd2_m; 00564 pol2[0][0]=(y[i]-y0)*A[i]-yA_m; 00565 pol2[1][0]=(y[i]-y0)*d1[i]-yd1_m; 00566 pol2[0][1]=(y[i]-y0)*d2[i]-yd2_m; 00567 ami_2v_polynom_multiplication(pol1,1,pol1,1,p_xx); 00568 ami_2v_polynom_multiplication(pol1,1,pol2,1,p_xy); 00569 ami_2v_polynom_multiplication(pol2,1,pol2,1,p_yy); 00570 } 00571 for(i=0; i<=2; i++) for(j=0; j<=2; j++) p_xx[i][j]/=1. /*s_max*/ ; 00572 ami_2v_polynom_multiplication(p_xx,2,p_yy,2,pol); 00573 for(i=0; i<=2; i++) for(j=0; j<=2; j++) p_xx[i][j]=-p_xy[i][j]/1. /*s_max*/; 00574 ami_2v_polynom_multiplication(p_xy,2,p_xx,2,pol); 00575 00576 /* WE FREE THE MEMORY */ 00577 if(A!=NULL) free(A); 00578 if(x2!=NULL) free(x2); 00579 if(y2!=NULL) free(y2); 00580 if(d1!=NULL) free(d1); 00581 if(d2!=NULL) free(d2); 00582 ami_free2d(p_xx); 00583 ami_free2d(p_xy); 00584 ami_free2d(p_yy); 00585 ami_free2d(pol1); 00586 ami_free2d(pol2); 00587 00588 return(0); 00589 } 00590 00600 void ami_2v_polynom_derivatives( 00601 double **p , 00602 int N , 00603 double **p_x , 00604 double **p_y 00605 ) 00606 { 00607 int i,j; /* AUXILIAR VARIABLES */ 00608 00609 for(i=0; i<=N; i++) 00610 for(j=0; j<=N; j++) 00611 p_x[i][j]=p_y[i][j]=0; 00612 00613 for(i=1; i<=N; i++) 00614 for(j=0; j<=N; j++) 00615 p_x[i-1][j]=i*p[i][j]; 00616 00617 for(i=0; i<=N; i++) 00618 for(j=1; j<=N; j++) 00619 p_y[i][j-1]=j*p[i][j]; 00620 00621 } 00622 00623 00630 void ami_polynom_determinant( 00631 double p[6][6][19], 00632 int Np, 00633 int Nd, 00634 double *q 00635 ) 00636 { 00637 int i,j,k,l,m,cont; /* AUXILIAR VARIABLES */ 00638 double *q2; /* AUXILIAR VARIABLES */ 00639 double p2[6][6][19]; /* AUXILIAR VARIABLES */ 00640 00641 q2=NULL; 00642 00643 if(Nd==1) { 00644 for(i=0; i<=18; i++) q[i]=p[0][0][i]; 00645 return; 00646 } 00647 00648 for(i=0; i<6; i++) for(j=0; j<6; j++) for(m=0; m<19; m++) p2[i][j][m]=0.; 00649 q2=(double*)malloc(sizeof(double)* (Np+1)); 00650 00651 for(i=0; i<=Np; i++) q[i]=0; 00652 cont=-1; 00653 for(i=0; i<Nd; i++) { 00654 for(k=0; k<=Np; k++) q2[k]=0; 00655 cont*=-1; 00656 for(k=0; k<(Nd-1); k++) { 00657 for(l=0; l<(Nd-1); l++) { 00658 for(m=0; m<=Np; m++) { 00659 p2[k][l][m]= p[k+1][l>=i?l+1:l][m]; 00660 } 00661 } 00662 } 00663 ami_polynom_determinant(p2,Np,Nd-1,q2); 00664 if(cont<0) for(m=0; m<=Np; m++) q2[m]=-q2[m]; 00665 q=ami_1v_polynom_multiplication(p[0][i],Np,q2,Np,q); 00666 } 00667 if(q2!=NULL) free(q2); 00668 } 00669 00676 double ami_2v_polynom_evaluation( 00677 double **p1 , 00678 int N1 , 00679 double x,double y 00680 ) 00681 { 00682 int i,j; /* AUXILIAR VARIABLES */ 00683 double *p,*q,eval; /* AUXILIAR VARIABLES */ 00684 00685 p=q=NULL; 00686 00687 p=(double*)malloc(sizeof(double)*(N1+1)); 00688 q=(double*)malloc(sizeof(double)*(N1+1)); 00689 00690 for(i=0; i<=N1; i++) { 00691 for(j=0; j<=N1; j++) p[j]=p1[i][j]; 00692 q[i]=ami_polynomial_evaluation(p,N1,y); 00693 } 00694 eval=ami_polynomial_evaluation(q,N1,x); 00695 if(p!=NULL) free(p); 00696 if(q!=NULL) free(q); 00697 return(eval); 00698 } 00699 00708 void ami_2v_polynom_to_1v_polynom( 00709 double **p1 , 00710 int N1 , 00711 double *p3 , 00712 double z , 00713 int flat) 00714 { 00715 int i,j; /* AUXILIAR VARIABLES */ 00716 double *p; /* AUXILIAR VARIABLES */ 00717 00718 p=NULL; 00719 p=(double*)malloc(sizeof(double)*(N1+1)); 00720 if(flat==1) { 00721 for(i=0; i<=N1; i++) { 00722 for(j=0; j<=N1; j++) p[j]=p1[i][j]; 00723 p3[i]=ami_polynomial_evaluation(p,N1,z); 00724 } 00725 } 00726 else { 00727 for(i=0; i<=N1; i++) { 00728 for(j=0; j<=N1; j++) p[j]=p1[j][i]; 00729 p3[i]=ami_polynomial_evaluation(p,N1,z); 00730 } 00731 } 00732 if(p!=NULL) free(p); 00733 00734 } 00735 00744 double* ami_1v_polynom_multiplication( 00745 double *p1 , 00746 int N1 , 00747 double *p2 , 00748 int N2 , 00749 double *p3 00750 ) 00751 { 00752 int i,j; /* AUXILIAR VARIABLES */ 00753 00754 /* WE MULTIPLY THE POLYNOMS */ 00755 for(i=0; i<=N1; i++) { 00756 if(p1[i]!=0) { 00757 for(j=0; j<=N2; j++) 00758 if(p2[j]!=0) 00759 p3[i+j]+=p1[i]*p2[j]; 00760 } 00761 } 00762 return(p3); 00763 } 00771 void ami_2v_polynom_multiplication( 00772 double **p1 , 00773 int N1 , 00774 double **p2 , 00775 int N2 , 00776 double **p3 00777 ) 00778 { 00779 int i,j,k,l; 00780 for(i=0; i<=N1; i++) { 00781 for(j=0; j<=N1; j++) { 00782 if(p1[i][j]!=0) { 00783 for(k=0; k<=N2; k++) 00784 for(l=0; l<=N2; l++) 00785 if(p2[k][l]!=0 ) 00786 p3[i+k][j+l]+=p1[i][j]*p2[k][l]; 00787 } 00788 } 00789 } 00790 } 00791 00799 int ami_RootCubicPolynomial( 00800 double *a , 00801 int N , 00802 double *x 00803 ) 00804 { 00805 double a1,a2,a3,Q,R,S,T,D,A; /* AUXILIAR VARIABLES */ 00806 00807 if(N!=3 || a[3]==0) return(-100000); 00808 a1=a[2]/a[3]; 00809 a2=a[1]/a[3]; 00810 a3=a[0]/a[3]; 00811 Q=(3*a2-a1*a1)/9.; 00812 R=(9*a1*a2-27*a3-2*a1*a1*a1)/54.; 00813 D=Q*Q*Q+R*R; 00814 00815 if(D>0) { 00816 S=R+sqrt(D); 00817 T=R-sqrt(D); 00818 if(S>0) S=pow(S,(double)1./3.); 00819 else S=-pow(-S,(double)1./3.); 00820 if(T>0) T=pow(T,(double)1./3.); 00821 else T=-pow(-T,(double)1./3.); 00822 x[0]=S+T-a1/3.; 00823 return(1); 00824 } 00825 else { 00826 double PI2=acos(-1.); 00827 if(Q!=0) A=acos(R/sqrt(-Q*Q*Q)); 00828 else A=0; 00829 00830 Q=2.*sqrt(-Q); 00831 x[0]=Q*cos(A/3.)-a1/3.; 00832 x[1]=Q*cos(A/3.+2.*PI2/3.)-a1/3.; 00833 x[2]=Q*cos(A/3+4.*PI2/3.)-a1/3.; 00834 00835 if(fabs(x[0])>fabs(x[1])) { 00836 Q=x[1]; 00837 x[1]=x[0]; 00838 x[0]=Q; 00839 } 00840 if(fabs(x[0])>fabs(x[2])) { 00841 Q=x[2]; 00842 x[2]=x[0]; 00843 x[0]=Q; 00844 } 00845 if(fabs(x[1])>fabs(x[2])) { 00846 Q=x[2]; 00847 x[2]=x[1]; 00848 x[1]=Q; 00849 } 00850 00851 return(3); 00852 } 00853 } 00860 double ami_polynomial_evaluation( 00861 double *a , 00862 int Na , 00863 double x 00864 ) 00865 { 00866 double sol=a[Na]; /* AUXILIAR VARIABLES */ 00867 int i; /* AUXILIAR VARIABLES */ 00868 for(i=Na-1; i>-1; i--) sol=sol*x+a[i]; 00869 return(sol); 00870 } 00871 00872 00881 int ami_lens_distortion_polynomial_update( 00882 double *x, double *y , 00883 int Np , 00884 double *a , 00885 int Na , 00886 double x0,double y0 , 00887 int k , 00888 double *pol 00889 ) 00890 { 00891 int i,j; /* AUXILIAR VARIABLES */ 00892 double *A,*x2,*y2,*d,x2_m,y2_m,s_xx,s_yy,xA_m,xd_m,yA_m,yd_m;/* AUXILIAR VARIABLES */ 00893 double pol1[5],pol2[5],pol3[5]; /* AUXILIAR VARIABLES */ 00894 00895 A=x2=y2=d=NULL; 00896 00897 /* WE ALLOCATE MEMORY */ 00898 A=(double*)malloc( sizeof(double)*Np ); 00899 x2=(double*)malloc( sizeof(double)*Np ); 00900 y2=(double*)malloc( sizeof(double)*Np ); 00901 d=(double*)malloc( sizeof(double)*Np ); 00902 00903 /* WE COMPUTE THE DISTANCE TO THE IMAGE CENTER */ 00904 for(i=0; i<Np; i++) 00905 d[i]=sqrt( (x[i]-x0)*(x[i]-x0)+(y[i]-y0)*(y[i]-y0) ); 00906 00907 /* WE COMPUTE THE POINT TRANSFORMATION WITH THE CURRENT LENS DISTORTION MODEL */ 00908 for(i=0; i<Np; i++) { 00909 A[i]=ami_polynomial_evaluation(a,Na,d[i]); 00910 x2[i]=x0+(x[i]-x0)*A[i]; 00911 y2[i]=y0+(y[i]-y0)*A[i]; 00912 } 00913 00914 /* WE COMPUTE THE DISTANCE POWER k (THE COEFFICIENT OF THE LENS DISTORTION MODEL 00915 TO BE UPDATED */ 00916 for(i=0; i<Np; i++) d[i]=pow(d[i],(double) k); 00917 00918 /* WE COMPUTE THE VARIANCE OF THE TRANSFORMED POINTS */ 00919 x2_m=0; 00920 for(i=0; i<Np; i++) x2_m+=x2[i]; 00921 x2_m/=Np; 00922 s_xx=0; 00923 for(i=0; i<Np; i++) s_xx+=(x2[i]-x2_m)*(x2[i]-x2_m); 00924 s_xx/=Np; 00925 y2_m=0; 00926 for(i=0; i<Np; i++) y2_m+=y2[i]; 00927 y2_m/=Np; 00928 s_yy=0; 00929 for(i=0; i<Np; i++) s_yy+=(y2[i]-y2_m)*(y2[i]-y2_m); 00930 s_yy/=Np; 00931 00932 /* WE COMPUTE SOME AVERAGES WE NEED */ 00933 xA_m=0; 00934 for(i=0; i<Np; i++) xA_m+=(x[i]-x0)*A[i]; 00935 xA_m/=Np; 00936 xd_m=0; 00937 for(i=0; i<Np; i++) xd_m+=(x[i]-x0)*d[i]; 00938 xd_m/=Np; 00939 yA_m=0; 00940 for(i=0; i<Np; i++) yA_m+=(y[i]-y0)*A[i]; 00941 yA_m/=Np; 00942 yd_m=0; 00943 for(i=0; i<Np; i++) yd_m+=(y[i]-y0)*d[i]; 00944 yd_m/=Np; 00945 00946 /* WE COMPUTE THE POLYNOMIAL TO MINIMIZE */ 00947 for(i=0; i<5; i++) pol1[i]=pol2[i]=pol3[i]=0; 00948 for(i=0; i<Np; i++) { 00949 pol1[0]+=((x[i]-x0)*A[i]-xA_m)*((x[i]-x0)*A[i]-xA_m); 00950 pol1[1]+=2.*((x[i]-x0)*A[i]-xA_m)*((x[i]-x0)*d[i]-xd_m); 00951 pol1[2]+=((x[i]-x0)*d[i]-xd_m)*((x[i]-x0)*d[i]-xd_m); 00952 pol2[0]+=((y[i]-y0)*A[i]-yA_m)*((y[i]-y0)*A[i]-yA_m); 00953 pol2[1]+=2.*((y[i]-y0)*A[i]-yA_m)*((y[i]-y0)*d[i]-yd_m); 00954 pol2[2]+=((y[i]-y0)*d[i]-yd_m)*((y[i]-y0)*d[i]-yd_m); 00955 pol3[0]+=((y[i]-y0)*A[i]-yA_m)*((x[i]-x0)*A[i]-xA_m); 00956 pol3[1]+=((y[i]-y0)*A[i]-yA_m)*((x[i]-x0)*d[i]-xd_m)+ 00957 ((y[i]-y0)*d[i]-yd_m)*((x[i]-x0)*A[i]-xA_m); 00958 pol3[2]+=((y[i]-y0)*d[i]-yd_m)*((x[i]-x0)*d[i]-xd_m); 00959 } 00960 00961 for(i=0; i<3; i++) { 00962 for(j=0; j<3; j++) { 00963 pol[i+j]+=(pol1[i]*pol2[j]-pol3[i]*pol3[j])/1. /*s_max*/; 00964 } 00965 } 00966 00967 /* WE FREE MEMORY */ 00968 if(A!=NULL) free(A); 00969 if(x2!=NULL) free(x2); 00970 if(y2!=NULL) free(y2); 00971 if(d!=NULL) free(d); 00972 return(0); 00973 } 00974 00982 int ami_lens_distortion_model_update( 00983 double *a , 00984 int Na , 00985 int k , 00986 double *pol , 00987 double max_radius 00988 ) 00989 { 00990 int j,i,M=Na; /* AUXILIAR VARIABLES */ 00991 double *x,*b,*b2,p[3]; /* AUXILIAR VARIABLES */ 00992 00993 x=b=NULL; 00994 00995 /* WE ALLOCATE MEMORY */ 00996 x=(double*)malloc( sizeof(double)*3 ); 00997 b=(double*)malloc( sizeof(double)*4 ); 00998 b2=(double*)malloc( sizeof(double)*(Na+1) ); 00999 // WE FILL THE AUXILIARY LENS DISTORTION MODEL 01000 for(i=0;i<=Na;i++) b2[i]=a[i]; 01001 01002 b[0]=pol[1]; 01003 b[1]=2*pol[2]; 01004 b[2]=3.*pol[3]; 01005 b[3]=4.*pol[4]; 01006 M=ami_RootCubicPolynomial(b,3,x); 01007 01008 for(i=0; i<M; i++) p[i]=ami_polynomial_evaluation(pol,4,x[i]); 01009 01010 double Error=1e30; 01011 j=M; 01012 for(i=0;i<M;i++){ 01013 b2[k]=a[k]+x[i]; 01014 if(test_compatibility_lens_distortion_model(b2,Na,max_radius)==0){ 01015 if(p[i]<Error){ 01016 j=i; 01017 Error=p[i]; 01018 } 01019 } 01020 } 01021 01022 if(j<M) a[k]+=x[j]; 01023 01024 if(x!=NULL) free(x); 01025 if(b!=NULL) free(b); 01026 if(b2!=NULL) free(b2); 01027 return(0); 01028 } 01029 01038 double ami_LensDistortionEnergyError( 01039 double *x,double *y , 01040 int Np , 01041 double x0,double y0 , 01042 double *a , 01043 int Na 01044 ) 01045 { 01046 int i; /* AUXILIAR VARIABLES */ 01047 double A,*x2,*y2,d,x2_m,y2_m,s_xx,s_yy,s_xy; /* AUXILIAR VARIABLES */ 01048 01049 x2=y2=NULL; 01050 01051 /* WE ALLOCATE MEMORY */ 01052 x2=(double*)malloc( sizeof(double)*Np ); 01053 y2=(double*)malloc( sizeof(double)*Np ); 01054 01055 /* WE COMPUTE THE POINT TRANSFORMATION USING THE LENS DISTORTION MODEL*/ 01056 for(i=0; i<Np; i++) { 01057 d=sqrt( (x[i]-x0)*(x[i]-x0)+(y[i]-y0)*(y[i]-y0) ); 01058 A=ami_polynomial_evaluation(a,Na,d); 01059 x2[i]=x0+(x[i]-x0)*A; 01060 y2[i]=y0+(y[i]-y0)*A; 01061 } 01062 /* WE COMPUTE THE VARIANCE OF THE TRANSFORMED POINTS */ 01063 x2_m=0; 01064 for(i=0; i<Np; i++) x2_m+=x2[i]; 01065 x2_m/=Np; 01066 s_xx=0; 01067 for(i=0; i<Np; i++) s_xx+=(x2[i]-x2_m)*(x2[i]-x2_m); 01068 s_xx/=Np; 01069 y2_m=0; 01070 for(i=0; i<Np; i++) y2_m+=y2[i]; 01071 y2_m/=Np; 01072 s_yy=0; 01073 for(i=0; i<Np; i++) s_yy+=(y2[i]-y2_m)*(y2[i]-y2_m); 01074 s_yy/=Np; 01075 s_xy=0; 01076 for(i=0; i<Np; i++) s_xy+=(y2[i]-y2_m)*(x2[i]-x2_m); 01077 s_xy/=Np; 01078 01079 /* WE FREE MEMORY */ 01080 if(x2!=NULL) free(x2); 01081 if(y2!=NULL) free(y2); 01082 return((s_xx*s_yy-s_xy*s_xy)); 01083 } 01084 01093 double ami_LensDistortionEnergyError_Vmin( 01094 double *x,double *y , 01095 int Np , 01096 double x0,double y0 , 01097 double *a , 01098 int Na 01099 ) 01100 { 01101 int i; /* AUXILIAR VARIABLES */ 01102 double A,*x2,*y2,d,x2_m,y2_m,s_xx,s_yy,s_max,s_xy; /* AUXILIAR VARIABLES */ 01103 01104 x2=y2=NULL; 01105 01106 /* WE ALLOCATE MEMORY */ 01107 x2=(double*)malloc( sizeof(double)*Np ); 01108 y2=(double*)malloc( sizeof(double)*Np ); 01109 01110 /* WE COMPUTE THE POINT TRANSFORMATION USING THE LENS DISTORTION MODEL*/ 01111 for(i=0; i<Np; i++) { 01112 d=sqrt( (x[i]-x0)*(x[i]-x0)+(y[i]-y0)*(y[i]-y0) ); 01113 A=ami_polynomial_evaluation(a,Na,d); 01114 x2[i]=x0+(x[i]-x0)*A; 01115 y2[i]=y0+(y[i]-y0)*A; 01116 } 01117 /* WE COMPUTE THE VARIANCE OF THE TRANSFORMED POINTS */ 01118 x2_m=0; 01119 for(i=0; i<Np; i++) x2_m+=x2[i]; 01120 x2_m/=Np; 01121 s_xx=0; 01122 for(i=0; i<Np; i++) s_xx+=(x2[i]-x2_m)*(x2[i]-x2_m); 01123 s_xx/=Np; 01124 y2_m=0; 01125 for(i=0; i<Np; i++) y2_m+=y2[i]; 01126 y2_m/=Np; 01127 s_yy=0; 01128 for(i=0; i<Np; i++) s_yy+=(y2[i]-y2_m)*(y2[i]-y2_m); 01129 s_yy/=Np; 01130 s_xy=0; 01131 for(i=0; i<Np; i++) s_xy+=(y2[i]-y2_m)*(x2[i]-x2_m); 01132 s_xy/=Np; 01133 s_max=s_xx>s_yy?s_xx:s_yy; 01134 01135 /* WE FREE MEMORY */ 01136 if(x2!=NULL) free(x2); 01137 if(y2!=NULL) free(y2); 01138 return((s_xx*s_yy-s_xy*s_xy)/s_max); 01139 } 01140 01141 01149 double ami_lens_distortion_estimation( 01150 double **x,double **y , 01151 int Nl , 01152 int *Np , 01153 double x0,double y0 , 01154 double *a , 01155 int Na , 01156 int k , 01157 double alpha , 01159 double max_radius 01160 ) 01161 01162 { 01163 double *pol,sum_dd,sum_Ad,d,A,Error=0; /* AUXILIAR VARIABLES */ 01164 int m,i,j; /* AUXILIAR VARIABLES */ 01165 pol=NULL; 01166 01167 /* WE ALLOCATE MEMORY */ 01168 pol=(double*)malloc( sizeof(double)*5 ); 01169 01170 for(i=0; i<=4; i++) pol[i]=0.; 01171 01172 /* WE ADAPT a[0] TO MINIMIZE THE SQUARE OF THE DISTANCE BEWTEEN 01173 DISTORTED AND UNDISTORDED POINTS */ 01174 if(alpha>0) { 01175 sum_dd=sum_Ad=0; 01176 for(m=0; m<Nl; m++) { 01177 for(i=0; i<Np[m]; i++) { 01178 d=sqrt( (x[m][i]-x0)*(x[m][i]-x0)+(y[m][i]-y0)*(y[m][i]-y0) ); 01179 A=0; 01180 for(j=1; j<=Na; j++) A+=a[j]*pow(d,(double) j+1); 01181 sum_dd+=d*d; 01182 sum_Ad+=A*d; 01183 } 01184 } 01185 a[0]=1-sum_Ad/sum_dd; 01186 } 01187 /* WE COMPUTE THE LENS DISTORTION MODEL */ 01188 for(i=0; i<Nl; i++) { 01189 ami_lens_distortion_polynomial_update(x[i],y[i],Np[i],a,Na,x0,y0,k,pol); 01190 } 01191 ami_lens_distortion_model_update(a,Na,k,pol,max_radius); 01192 /* WE FREE THE MEMORY */ 01193 if(pol!=NULL) free(pol); 01194 for(i=0; i<Nl; i++) Error+=ami_LensDistortionEnergyError(x[i],y[i],Np[i],x0,y0,a,Na); 01195 return(Error/Nl); 01196 } 01197 01205 void ami_lens_distortion_zoom_normalization( 01206 double **x,double **y , 01207 int Nl , 01208 int *Np , 01209 double *a , 01210 int Na 01211 ) 01212 { 01213 int i,k,m,N=0; /* AUXILIAR VARIABLES */ 01214 double Z,d,sum_Ad,A,x0,y0; /* AUXILIAR VARIABLES */ 01215 01216 x0=a[5]; 01217 y0=a[6]; 01218 /* WE UPDATE a BY ESTIMATING A ZOOM FACTOR Z */ 01219 sum_Ad=0; 01220 for(m=0; m<Nl; m++) { 01221 for(i=0; i<Np[m]; i++) { 01222 N++; 01223 d=sqrt( (x[m][i]-x0)*(x[m][i]-x0)+(y[m][i]-y0)*(y[m][i]-y0) ); 01224 A=a[0]; 01225 for(k=1; k<=Na; k++) A+=a[k]*pow(d,(double) k); 01226 sum_Ad+=A*A; 01227 } 01228 } 01229 Z=sqrt((double) N/sum_Ad); 01230 for(k=0; k<=Na; k++) a[k]*=Z; 01231 } 01232 01246 int calculate_points( 01247 double *amin , 01248 double **points_2D_modified , 01249 int N , 01250 int Na , 01251 double x0 , 01252 double y0 01253 ) 01254 { 01255 double d1,sol; /* AUXILIAR VARIABLES */ 01256 int i,j; /* AUXILIAR VARIABLES */ 01257 01258 /* Calculate the distance from each point to the center of the image */ 01259 /* WE COMPUTE THE POINT TRANSFORMATION WITH THE CURRENT LENS DISTORTION MODEL */ 01260 for(i=0; i<N; i++) 01261 { 01262 d1=sqrt(pow(points_2D_modified[i][0]-x0,2.0)+pow(points_2D_modified[i][1]-y0,2.0)); 01263 sol=amin[Na]; 01264 for(j=Na-1; j>-1; j--) sol=sol*d1+amin[j]; 01265 points_2D_modified[i][0]=(points_2D_modified[i][0]-x0)*sol+x0; 01266 points_2D_modified[i][1]=(points_2D_modified[i][1]-y0)*sol+y0; 01267 } 01268 return(0); 01269 } 01270 01278 double distance_function( 01279 double *solution , 01280 double **x , 01281 double **y , 01282 int Nl , 01283 int *Np , 01284 int Na 01285 ) 01286 { 01287 double **points_2D_modified,*amin,sum,f_objective,a,b,c,tmp;/* AUXILIAR VARIABLES */ 01288 double line[3],x0,y0; /* AUXILIAR VARIABLES */ 01289 int i,j; /* AUXILIAR VARIABLES */ 01290 points_2D_modified=NULL; 01291 amin=NULL; 01292 01293 ami_calloc1d(amin,double,Na+1); 01294 for(i=0; i<=Na; i++) amin[i]=solution[i]; 01295 x0=solution[5]; 01296 y0=solution[6]; 01297 01298 f_evaluations++; 01299 f_objective=0.0; 01300 for (i=0; i<Nl; i++) { 01301 points_2D_modified=(double**)malloc(sizeof(double*)*Np[i]); 01302 for(j=0; j<Np[i]; j++) { 01303 points_2D_modified[j]=(double*)malloc(sizeof(double)*2); 01304 points_2D_modified[j][0]=x[i][j]; 01305 points_2D_modified[j][1]=y[i][j]; 01306 } 01307 calculate_points(amin,points_2D_modified,Np[i],Na,x0,y0); 01308 ami_line2d_calculation(line,points_2D_modified,Np[i]); 01309 a=line[1]; 01310 b=line[0]; 01311 c=line[2]; 01312 tmp=pow(a,2.0)+pow(b,2.0); 01313 sum=0.0; 01314 for(j=0; j<Np[i]; j++) 01315 sum=sum+pow(b*points_2D_modified[j][0]+a*points_2D_modified[j][1]+c,2.0); 01316 01317 sum=sum/tmp; 01318 sum=sum/(double)Np[i]; 01319 f_objective=f_objective+sum; 01320 for(j=0; j<Np[i]; j++) { 01321 free(points_2D_modified[j]); 01322 } 01323 free(points_2D_modified); 01324 } 01325 f_objective=f_objective/(double)Nl; 01326 free(amin); 01327 return(f_objective); 01328 } 01329 01338 double find_lambda( 01339 double lambda1 , 01340 double lambda2 , 01341 double lambda3 , 01342 double f_1 , 01343 double f_2 , 01344 double f_3 , 01345 double *amin_copy , 01346 double *amin , 01347 double **x , 01348 double **y , 01349 int Nl , 01350 int *Np , 01351 int Na , 01352 double *grad_f , 01353 int *change_k 01354 ) 01355 01356 { 01357 int Naa=7; /* AUXILIAR VARIABLES */ 01358 double f_min,lambda,lambda_tmp1; /* AUXILIAR VARIABLES */ 01359 double lambda_tmp2,f_tmp1=f_3,f_tmp2=f_2,f=f_1; /* AUXILIAR VARIABLES */ 01360 int i; /* AUXILIAR VARIABLES */ 01361 /* minimum is in (lambda1,lambda2) */ 01362 lambda_tmp1=(lambda2+lambda1)/2.0; 01363 for(i=0; i<Naa; i++) { 01364 if(change_k[i]==1) *(amin_copy+i)=*(amin+i)-lambda_tmp1*(*(grad_f+i)); 01365 } 01366 f_tmp1=distance_function(amin_copy,x,y,Nl,Np,Na); 01367 if(f_tmp1<f_1) return(lambda_tmp1); 01368 01369 lambda_tmp2=(lambda3+lambda2)/2.0; 01370 for(i=0; i<Naa; i++) { 01371 if(change_k[i]==1) *(amin_copy+i)=*(amin+i)-lambda_tmp2*(*(grad_f+i)); 01372 } 01373 f_tmp2=distance_function(amin_copy,x,y,Nl,Np,Na); 01374 if(f_tmp2<f_1) return(lambda_tmp2); 01375 f=f_1; 01376 do { 01377 f_min=f; 01378 lambda=lambda1+1e-8; 01379 for(i=0; i<Naa; i++) { 01380 if(change_k[i]==1) *(amin_copy+i)=*(amin+i)-lambda*(*(grad_f+i)); 01381 } 01382 f=distance_function(amin_copy,x,y,Nl,Np,Na); 01383 } while(f<f_min); 01384 return(lambda); 01385 } 01386 01387 01396 double minimize_cuadratic_polynom( 01397 double lambda1 , 01398 double lambda2 , 01399 double lambda3 , 01400 double f_1 , 01401 double f_2 , 01402 double f_3 , 01403 double *amin_copy , 01404 double *amin , 01405 double **x , 01406 double **y , 01407 int Nl , 01408 int *Np , 01409 int Na , 01410 double *grad_f , 01411 int *change_k 01413 ) 01414 { 01415 01416 double a12,a23,a31,b12,b23,b31,min_lambda; /* AUXILIAR VARIABLES */ 01417 01418 a12=lambda1-lambda2; 01419 a23=lambda2-lambda3; 01420 a31=lambda3-lambda1; 01421 b12=pow(lambda1,2.0)-pow(lambda2,2.0); 01422 b23=pow(lambda2,2.0)-pow(lambda3,2.0); 01423 b31=pow(lambda3,2.0)-pow(lambda1,2.0); 01424 01425 min_lambda=0.5*(b23*f_1+b31*f_2+b12*f_3); 01426 min_lambda=min_lambda/(a23*f_1+a31*f_2+a12*f_3); 01427 /* to avoid numerical errors, we check the condition*/ 01428 /* lambda1<min_lambda<lambda3 */ 01429 if((lambda1<min_lambda)&&(min_lambda<lambda3)) return(min_lambda); 01430 else { 01431 min_lambda=find_lambda(lambda1,lambda2,lambda3,f_1,f_2,f_3, 01432 amin_copy,amin,x,y,Nl,Np,Na,grad_f,change_k); 01433 return(min_lambda); 01434 01435 } 01436 } 01437 01447 double cuadratic_fitting( 01448 double *amin_copy , 01449 double *amin , 01450 double **x , 01451 double **y , 01452 int Nl , 01453 int *Np , 01454 int Na , 01455 double lambda1 , 01456 double lambda2 , 01457 double lambda3 , 01458 double f_1 , 01459 double f_2 , 01460 double f_3 , 01461 double *grad_f , 01462 int *change_k 01463 ) 01464 { 01465 double minimo_lambda,f_minimo; /* AUXILIAR VARIABLES */ 01466 double error=1e100; /* AUXILIAR VARIABLES */ 01467 int iterations_lambda,i; /* AUXILIAR VARIABLES */ 01468 int Naa=7; /* AUXILIAR VARIABLES */ 01469 01470 iterations_lambda=0; 01471 /* We loop till getting the minimum */ 01472 while(error>tol_lambda) { 01473 01474 minimo_lambda=minimize_cuadratic_polynom(lambda1,lambda2,lambda3,f_1,f_2,f_3, 01475 amin_copy,amin,x,y,Nl,Np,Na,grad_f,change_k); 01476 for(i=0; i<Naa; i++) { 01477 if(change_k[i]==1) *(amin_copy+i)=*(amin+i)-minimo_lambda*(*(grad_f+i)); 01478 } 01479 f_minimo=distance_function(amin_copy,x,y,Nl,Np,Na); 01480 if(minimo_lambda>lambda2) { 01481 if(f_minimo>f_2) { 01482 lambda3=minimo_lambda; 01483 f_3=f_minimo; 01484 } 01485 else { 01486 lambda1=lambda2; 01487 f_1=f_2; 01488 lambda2=minimo_lambda; 01489 f_2=f_minimo; 01490 } 01491 } 01492 else { 01493 if(f_minimo>=f_2) { 01494 lambda1=minimo_lambda; 01495 f_1=f_minimo; 01496 } 01497 else { 01498 lambda3=lambda2; 01499 f_3=f_2; 01500 lambda2=minimo_lambda; 01501 f_2=f_minimo; 01502 } 01503 } 01504 error=fabs(lambda3-lambda1); 01505 if(f_minimo==f_2) lambda2=lambda2+tol_lambda; 01506 iterations_lambda++; 01507 if(iterations_lambda==max_itera_lambda) return(lambda2); 01508 } 01509 return(lambda2); 01510 } 01511 01520 double minimize_lambda( 01521 double *amin , 01522 double **x , 01523 double **y , 01524 int Nl , 01525 int *Np , 01526 int Na , 01527 double *grad_f , 01528 double f , 01529 int *change_k 01530 ) 01531 { 01532 double lambda1,lambda2,lambda3,lambda; /* AUXILIAR VARIABLES */ 01533 double f_1,f_2,f_3=0.0,last_f3,last_f2; /* AUXILIAR VARIABLES */ 01534 double tol_ff=1.0e-10; /* AUXILIAR VARIABLES */ 01535 double *amin_copy; /* AUXILIAR VARIABLES */ 01536 int i,Naa; /* AUXILIAR VARIABLES */ 01537 01538 Naa=7; /* AUXILIAR VARIABLES */ 01539 amin_copy=NULL; 01540 amin_copy=(double*)malloc( sizeof(double)*(Naa) ); 01541 01542 f_1=f; 01543 /* search the TTP points */ 01544 lambda1=0.0; 01545 /* search lambda2 */ 01546 lambda2=fabs(grad_f[2]); 01547 for(i=0; i<Naa; i++)*(amin_copy+i)=*(amin+i)-lambda2*(*(grad_f+i)); 01548 f_2=distance_function(amin_copy,x,y,Nl,Np,Na); 01549 01550 if(f_2>f_1) { 01551 lambda3=lambda2; 01552 f_3=f_2; 01553 /* search lambda2 by dividing the (lambda1,lambda3) interval */ 01554 lambda2=lambda3/2.0; 01555 while(1) { 01556 last_f2=f_2; 01557 for(i=0; i<Naa; i++) { 01558 if(change_k[i]==1) *(amin_copy+i)=*(amin+i)-lambda2*(*(grad_f+i)); 01559 } 01560 f_2=distance_function(amin_copy,x,y,Nl,Np,Na); 01561 if(f_2<f_1) break; 01562 if(fabs((f_2-last_f2)/last_f2)<=tol_ff) { /* Avoid the flat zone */ 01563 if(amin_copy!=NULL) free(amin_copy); /*free memory*/ 01564 return(lambda2); 01565 } 01566 lambda2=lambda2/2.0; 01567 } 01568 } 01569 else { 01570 /* search lambda3 by increasing the (lambda1,lambda2) interval */ 01571 lambda3=lambda2*2.0; 01572 while(1) { 01573 last_f3=f_3; 01574 for(i=0; i<Naa; i++) { 01575 if(change_k[i]==1) *(amin_copy+i)=*(amin+i)-lambda3*(*(grad_f+i)); 01576 } 01577 f_3=distance_function(amin_copy,x,y,Nl,Np,Na); 01578 if(f_3>f_2) break; 01579 if(fabs((f_3-last_f3)/last_f3)<=tol_ff) { /* Avoid the flat zone */ 01580 if(amin_copy!=NULL) free(amin_copy); /* Free memory */ 01581 return(lambda3); /* Avoid the flat zone */ 01582 } 01583 lambda3=2*lambda3; 01584 } 01585 } 01586 /* We have the points satisfying the TTP condition 01587 lambda1,f_1;lambda_2,f_2;lambda3,f_3 01588 minimize the cuadratic polynom */ 01589 lambda=cuadratic_fitting(amin_copy,amin,x,y,Nl,Np,Na,lambda1,lambda2,lambda3,f_1,f_2,f_3,grad_f,change_k); 01590 if(amin_copy!=NULL) free(amin_copy); 01591 return(lambda); 01592 } 01593 01601 double gradient_method( 01602 double *solution , 01603 double **x , 01604 double **y , 01605 int Nl , 01606 int *Np , 01607 int Na , 01608 int *change_k , 01609 int zoom , 01610 int optimize_center 01611 ) 01612 { 01613 double *grad_f,f_objective,last_f=1.0e100; /* AUXILIAR VARIABLES */ 01614 double kk,lambda; /* AUXILIAR VARIABLES */ 01615 int i; /* AUXILIAR VARIABLES */ 01616 01617 01618 grad_f=NULL; 01619 ami_calloc1d(grad_f,double,7); 01620 01621 f_objective=distance_function(solution,x,y,Nl,Np,Na); 01622 while(fabs((f_objective-last_f)/last_f)>tol_f) { 01623 last_f=f_objective; 01624 for(i=0; i<7; i++) { 01625 /* Move along each axis and incremental step to calculate the derivative */ 01626 if(change_k[i]==1) { 01627 kk=solution[i]; 01628 solution[i]=kk+delta; 01629 grad_f[i]=(distance_function(solution,x,y,Nl,Np,Na)-f_objective)/delta; 01630 solution[i]=kk; 01631 } 01632 } 01633 /* Activate to stop the gradient when the gradient_norm<tol_norma gradient_norm=0.0; 01634 for(i=0;i<7;i++) gradient_norm=gradient_norm+pow(grad_f[i],2.0); 01635 gradient_norm=sqrt(gradient_norm); if(gradient_norm<=tol_norma) break; */ 01636 lambda=minimize_lambda(solution,x,y,Nl,Np,Na,grad_f,f_objective,change_k); 01637 for(i=0; i<7; i++) if(change_k[i]==1) *(solution+i)=*(solution+i)-lambda*(*(grad_f+i)); 01638 n_iterations++; 01639 f_objective=distance_function(solution,x,y,Nl,Np,Na); 01640 /* Activate to have the trace of the execution */ 01641 //printf("\nIteracion=%d\tf=%1.18f\t|grad(f)|=%1.18f",n_iteraciones,f_objective,gradient_norm); 01642 //for(i=0;i<7;i++) printf("\n(in gradient) solution[%d]=%f",i,solution[i]); 01643 //system("pause"); 01644 if(n_iterations==max_itera) break; 01645 } 01647 if(zoom==1) ami_lens_distortion_zoom_normalization(x,y,Nl,Np,solution,Na); 01648 if(grad_f!=NULL) free(grad_f); 01649 return(0); 01650 } 01651 01660 int optimize( 01661 double *solution , 01662 double **x , 01663 double **y , 01664 double **xx , 01665 double **yy , 01666 int Nl , 01667 int *Np , 01668 int Na , 01669 double factor_n , 01670 int zoom , 01671 FILE *fp1 , 01672 int optimize_center 01673 ) 01674 { 01675 01676 int starttime, stoptime,i; /* AUXILIAR VARIABLES */ 01677 double paso,Emin,Vmin,D; /* AUXILIAR VARIABLES */ 01678 double timeused,x0,y0,x00,y00,*amin,factor_n_new; /* AUXILIAR VARIABLES */ 01679 int *change_k; /* TO INDICATE WHAT VARIABLE IS 01680 GOING TO BE OPTIMIZED BY GRADIENT METHOD */ 01681 01682 change_k=NULL; 01683 amin=NULL; 01684 01685 x00=solution[5]; 01686 y00=solution[6]; /* WE COPY THE ORIGINAL CENTER OF DISTORTION (pixels) */ 01687 f_evaluations=0; 01688 n_iterations=0; 01689 01690 solution[5]=0.0; 01691 solution[6]=0.0; /* TO CALCULATE IN NORMALIZED COORDINATES */ 01692 ami_calloc1d(change_k,int,7); /* BY DEFAULT, INITIALIZED TO 0 */ 01693 change_k[2]=1; 01694 change_k[4]=1; /* OPTIMIZED ONLY K2 AND K4 */ 01695 starttime = clock(); 01696 /* GRADIENT METHOD WORKS WITH NORMALIZED UNITS */ 01697 if(optimize_center==1) { 01698 change_k[5]=1; 01699 change_k[6]=1; /*OPTIMIZE THE CENTER OF DISTORTION */ 01700 gradient_method(solution,x,y,Nl,Np,Na,change_k,zoom,optimize_center); 01701 } 01702 else gradient_method(solution,x,y,Nl,Np,Na,change_k,zoom,optimize_center); 01703 stoptime = clock(); 01704 timeused = difftime(stoptime,starttime); 01705 x0=solution[5]; 01706 y0=solution[6]; /* WE RECOVER THE CENTER OF DISTORTION, OPTIMIZED OR NOT */ 01707 01708 /* Final solution is in solution (distortion parameters) and it is normalized */ 01709 /* We undo the un-normalization to have the solution in pixels */ 01710 if(optimize_center==1) { /* WE CALCULATE THE NEW CENTER OF DISTORTION IN PIXELS */ 01711 x0=x0+x00; 01712 y0=y0+y00; 01713 } 01714 else { 01715 x0=x00; 01716 y0=y00; 01717 } 01718 01719 /* WE TRANSFORM THE SOLUTION IN NORMALIZED COORDINATES TO PIXEL UNITS */ 01720 if(optimize_center==0) { 01721 paso=1.0; 01722 for(i=0; i<=Na; i++) { 01723 solution[i]=solution[i]*paso; 01724 paso/=factor_n; 01725 } 01726 } 01727 else { 01728 factor_n_new=calculate_factor_n(xx,yy,Nl,Np,x0,y0); 01729 paso=1.0; 01730 for(i=0; i<=Na; i++) { 01731 solution[i]=solution[i]*paso; 01732 paso/=factor_n_new; 01733 } 01734 } 01735 solution[5]=x0; 01736 solution[6]=y0; /* WE UPDATE THE SOLUTION (CENTER OF DISTORTION) */ 01737 amin=NULL; 01738 ami_calloc1d(amin,double,Na+1); /* WE RECOVER THE amin SOLUTION */ 01739 for(i=0; i<=Na; i++) amin[i]=solution[i]; /* WE UPDATE THE SOLUTION (ldm) */ 01740 /* We get the final solution and print into a file */ 01741 fprintf(fp1,"\nMODIFIED VARIABLES THROUGH OPTIMIZATION:"); 01742 for(i=0; i<=Na; i++) if(change_k[i]==1) fprintf(fp1,"\tk[%d]",i); 01743 if(optimize_center==1) fprintf(fp1,", (x0,y0)"); 01744 Emin=0.0; 01745 for(i=0; i<Nl; i++)Emin+=ami_LensDistortionEnergyError(xx[i],yy[i],Np[i],x0,y0,amin,Na); 01746 Emin=Emin/(double)Nl; 01747 Vmin=0.0; 01748 for(i=0; i<Nl; i++)Vmin+=ami_LensDistortionEnergyError_Vmin(xx[i],yy[i],Np[i],x0,y0,amin,Na); 01749 Vmin=Vmin/(double)Nl; 01750 D=distance_function(solution,xx,yy,Nl,Np,Na); 01751 fprintf(fp1,"\n\n(Emin, Vmin, D) = (%1.4e, %1.4e, %1.4e)",Emin,Vmin,D); 01752 fprintf(fp1,"\n\nDistortion parameters:\n"); 01753 for(i=0; i<=Na; i++) fprintf(fp1,"k[%d] = %1.15e\n",i,amin[i]); 01754 fprintf(fp1,"\nCenter of distortion (x0,y0) = (%f, %f)\n",x0,y0); 01755 fprintf(fp1,"\nNumber of gradient iterations= %d",n_iterations); 01756 fprintf(fp1,"\nCPU_time = %f (seconds)",timeused/(double)CLOCKS_PER_SEC); 01757 fprintf(fp1,"\nf_evaluations = %d",f_evaluations); 01758 if(change_k!=NULL) free(change_k); /* FREE THE MEMORY */ 01759 return(1); 01760 } 01761 01762 01771 int algebraic_method_pre_gradient( 01772 int Nl , 01773 int *Np , 01774 double *a , 01775 double **x , 01776 double **y , 01777 double **xx , 01778 double **yy , 01779 double factor_n , 01780 int zoom , 01781 FILE *fp1 , 01782 int optimize_center , 01783 double max_radius 01784 ) 01785 { 01786 01787 double aux,Emin; /* AUXILIAR VARIABLES */ 01788 int Na=4; /* DEGREE OF THE POLYNOM */ 01789 01790 if(zoom==0) { 01791 fprintf(fp1,"*************************************************************************\n"); 01792 fprintf(fp1," ALGEBRAIC METHOD + GRADIENT: WITHOUT ZOOM (Na = 4) \n"); 01793 fprintf(fp1,"*************************************************************************"); 01794 } 01795 01796 else { 01797 fprintf(fp1,"\n*************************************************************************\n"); 01798 fprintf(fp1,"* ALGEBRAIC METHOD + GRADIENT: WITH ZOOM (Na = 4) \n"); 01799 fprintf(fp1,"*************************************************************************"); 01800 } 01801 01802 01803 double x0,y0,x00,y00; 01804 x0=a[5]; 01805 y0=a[6]; /* WE CAPTURE THE CENTER OF DISTORTION */ 01806 x00=x0; 01807 y00=y0; /* WE COPY THE ORIGINAL CENTER OF DISTORTION */ 01808 01809 fprintf(fp1,"\n2 parameters, 1 iteration, variables updated:\t2, 4"); 01810 01811 if(optimize_center==0){ //IT WORKS FROM THE TRIVIAL SOLUTION 01812 a[0]=1.0; /* trivial solution */ 01813 for(int i=1; i<=Na; i++) a[i]=0.0; 01814 /* WE RUN A SAFE PREVIOUS ITERATION TO AVOID CONVERGENCE PROBLEMS*/ 01815 Emin=ami_lens_distortion_estimation(x,y,Nl,Np,(double) 0.,(double) 0.,a,Na,2,(double) 0.,max_radius); 01816 Emin=ami_lens_distortion_estimation(x,y,Nl,Np,(double) 0.,(double) 0.,a,Na,4,(double) 0.,max_radius); 01817 /* WE RUN THE ALGEBRAIC METHOD FOR BOTH PARAMETERS IN ONE ITERATION */ 01818 Emin=ami_lens_distortion_estimation_2v(x,y,Nl,Np,(double) 0.,(double) 0.,a,Na,2,4,(double) 0.,max_radius); 01819 01820 /* WE SET THE ORIGINAL CENTER OF DISTORTION */ 01821 a[5]=x00; 01822 a[6]=y00; 01823 01824 /* APPLY THE GRADIENT METHOD FROM THE ALGEBRAIC SOLUTION */ 01825 optimize(a,x,y,xx,yy,Nl,Np,Na,factor_n,zoom,fp1,optimize_center); 01826 } 01827 01828 else{ /* A SOLUTION -PIXELS- HAS BEEN CALCULATED WHEN SEARCHING FOR THE 01829 BEST CENTER OF DISTORTION*/ 01830 /* NORMALIZE COORDINATES */ 01831 double paso=1.0; 01832 for(int i=0; i<=Na; i++) { 01833 a[i]=a[i]*paso; 01834 paso/=factor_n; 01835 } 01836 a[5]=x00; /* WE COPY THE ORIGINAL CENTER OF DISTORTION */ 01837 a[6]=y00; /* WE COPY THE ORIGINAL CENTER OF DISTORTION */ 01838 /* APPLY THE GRADIENT METHOD FROM THE SOLUTION */ 01839 optimize(a,x,y,xx,yy,Nl,Np,Na,factor_n,zoom,fp1,optimize_center); 01840 } 01841 return(1); 01842 } 01843 01852 int trivial_solution( 01853 int Nl , 01854 int *Np , 01855 double *a , 01856 double **xx , 01857 double **yy , 01858 double factor_n , 01859 FILE *fp1 , 01860 double *trivial , 01861 int optimize_center 01862 ) 01863 { 01864 int starttime, stoptime,i,m,Na; 01865 double *amin,Emin,Vmin=factor_n,D,x0,y0; 01866 double timeused; 01867 01868 /* WE CAPTURE THE CENTER OF DISTORTION */ 01869 x0=a[5]; 01870 y0=a[6]; 01871 01872 /* WE DEFINE THE GRADE OF THE LENS DISTORTION POLYNOM (MAXIMUM GRADE) */ 01873 /* WE KEEP THE ORIGINAL FORMAT OF THE ALGEBRAIC FUNCTIONS */ 01874 Na=4; 01875 01876 ami_calloc1d(amin,double,Na+1); 01877 for(i=0; i<=Na; i++) amin[i]=a[i]; 01878 01879 fprintf(fp1,"****************************************************************************"); 01880 fprintf(fp1,"\n LENS DISTORTION MODEL: OUTPUT FILE "); 01881 fprintf(fp1,"\n CALCULATED USING NORMALIZED COORDINATES (SOLUTION IN PIXELS) "); 01882 fprintf(fp1,"\n\nALGEBRAIC METHOD: IT DOES NOT OPTIMIZE THE CENTER OF DISTORTION"); 01883 fprintf(fp1,"\nGRADIENT METHOD: IT IMPROVES THE PREVIOUS ALGEBRAIC SOLUTION"); 01884 fprintf(fp1,"\n "); 01885 fprintf(fp1,"\n THE CENTER OF DISTORTION IS OPTIMIZED IF INDICATED"); 01886 fprintf(fp1,"\n****************************************************************************\n"); 01887 01888 if(optimize_center==1) fprintf(fp1,"\n\t\tThe center of distortion is going to be optimized.\n"); 01889 else fprintf(fp1,"\n\t\tThe center of distortion is not going to be optimized.\n"); 01890 fprintf(fp1,"\n****************************************************************************\n"); 01891 01892 01893 /* WE DO THE CALCULATION IN NORMALIZED COORDINATES AND TRANSFORM TO PIXELS AT THE END */ 01894 /* SOLUTION AND DISTORTION PARAMETERS: IN PIXELS */ 01895 /* //////////////////////////////////////////////////////////////////////////////////////////// */ 01896 /* ******************************WE MEASURE CPU TIME FOR CALCULATIONS ONLY********************* */ 01897 /* //////////////////////////////////////////////////////////////////////////////////////////// */ 01898 /* WE COMPUTE THE DISTORTION MODEL */ 01899 /* WE ESTIMATE THE Emin,Vmin IN PIXELS */ 01900 fprintf(fp1," TRIVIAL SOLUTION (Na = 4): "); 01901 fprintf(fp1,"\n****************************************************************************\n"); 01902 fprintf(fp1,"Center of distortion (x0,y0) = (%f,%f)",x0,y0); 01903 starttime = clock(); 01904 Emin=0; 01905 for(m=0; m<Nl; m++) Emin+=ami_LensDistortionEnergyError(xx[m],yy[m],Np[m],x0,y0,amin,Na); 01906 Emin=Emin/(double)Nl; 01907 Vmin=0; 01908 for(m=0; m<Nl; m++) Vmin+=ami_LensDistortionEnergyError_Vmin(xx[m],yy[m],Np[m],x0,y0,amin,Na); 01909 Vmin=Vmin/(double)Nl; 01910 stoptime = clock(); 01911 timeused = difftime(stoptime,starttime); 01912 D=distance_function(a,xx,yy,Nl,Np,Na); 01913 fprintf(fp1,"\n(Emin, Vmin, D) = (%1.4e, %1.4e, %1.4e)",Emin,Vmin,D); 01914 fprintf(fp1,"\nDistortion parameters:\n"); 01915 for(i=0; i<=Na; i++) fprintf(fp1,"k[%d] = %1.15e\n",i,a[i]); 01916 fprintf(fp1,"\nCPU_time=%f (seconds)",timeused/(double)CLOCKS_PER_SEC); 01917 fprintf(fp1," \n*************************************************************************\n\n\n"); 01918 /* SAVE THE TRIVIAL VALUES TO CALCULATE THE % IMPROVEMENT */ 01919 trivial[0]=Emin; 01920 trivial[1]=Vmin; 01921 trivial[2]=D; 01922 free(amin); 01923 return(1); 01924 } 01925 01926 01934 int search_for_best_center( 01935 int Nl , 01936 int *Np , 01937 double *a , 01938 double **xx , 01939 double **yy , 01940 int width , 01941 int height , 01942 double max_radius 01943 ) 01944 { 01945 int Na=4;/* WE DEFINE THE GRADE OF THE LENS DISTORTION POLYNOM (MAXIMUM GRADE) */ 01946 01947 /* WE CALCULATE THE ALGEBRAIC SOLUTION FOR THE GIVEN CENTER OF DISTORTION */ 01948 /* WE WORK USING PIXELS UNITS */ 01949 double initial_Emin=0.0; 01950 int x_c=floor(a[5]); /* WE CAPTURE THE INDICATED CENTER OF DISTORTION (X) */ 01951 int y_c=floor(a[6]); /* WE CAPTURE THE INDICATED CENTER OF DISTORTION (Y) */ 01952 int best_x_c, best_y_c; /* AUXILIAR VARIABLE TO STORE THE BEST SOLUTION FOUND */ 01953 01954 float Emin,timeused; 01955 float **aux_image; /* AUXILIAR VARIABLES */ 01956 int starttime, stoptime,n_iterations=0; /* AUXILIAR VARIABLES */ 01957 01958 aux_image=NULL; 01959 // TO SPEED-UP CALCULATION OF OPTIMIZED CENTER OF DISTORTION, 01960 //WE AVOID TO RECALCULATE ENERGY FUNCTION AT PREVIOUS 01961 // CALCULATED POSITIONS WITHIN THE IMAGE 01962 /* WE ALLOCATE MEMORY FOR AUXIlIAR IMAGE MATRIX */ 01963 aux_image=(float**)malloc(sizeof(float*)*width); 01964 for(int i=0; i<(int)width; i++) aux_image[i]=(float*)malloc( sizeof(float)*height ); 01965 // WE INITIALIZE THE aux_image MATRIX TO -1.0 01966 for(int i=0; i<width; i++) 01967 for(int j=0; j<height; j++) aux_image[i][j]=-1.0; 01968 01969 /* WE RUN A SAFE PREVIOUS ITERATION TO AVOID CONVERGENCE PROBLEMS*/ 01970 initial_Emin=ami_lens_distortion_estimation(xx,yy,Nl,Np,(double) x_c,(double) y_c,a,Na,2,(double) 0.,max_radius); 01971 initial_Emin=ami_lens_distortion_estimation(xx,yy,Nl,Np,(double) x_c,(double) y_c,a,Na,4,(double) 0.,max_radius); 01972 /* WE RUN THE ALGEBRAIC METHOD FOR BOTH PARAMETERS IN ONE ITERATION */ 01973 initial_Emin=ami_lens_distortion_estimation_2v(xx,yy,Nl,Np,(double) x_c,(double) y_c,a,Na,2,4,(double) 0.,max_radius); 01974 01975 /* initial_Emin has the algebraic solution for the given center of distortion. 01976 The corresponding solution is in vector a */ 01977 /* This initial_Emin solution is the initial one to compare with, for the patch search */ 01978 /* we scan iteratively the image looking for the best center of distortion */ 01979 float last_Emin=1e100; 01980 best_x_c=x_c; 01981 best_y_c=y_c; 01982 int patch_half=floor((double)patch_size/2.0); 01983 starttime = clock(); 01984 while(fabs(initial_Emin-last_Emin)>tol_f) { 01985 last_Emin=initial_Emin; 01986 n_iterations++; 01987 int lim_inf_x=x_c-patch_half; 01988 int lim_sup_x=x_c+patch_half; 01989 int lim_inf_y=y_c-patch_half; 01990 int lim_sup_y=y_c+patch_half; 01991 //#pragma omp parallel for 01992 /* we scan the rectangular patch: pixel precission, subpixel is reached through gradient */ 01993 for(int i=lim_inf_x; i<=lim_sup_x; i++) { 01994 if(i>=0 && i<=width) { // we check that we are inside the image (x-axis) 01995 for(int j=lim_inf_y; j<=lim_sup_y; j++) { 01996 if(j>=0 && j<=height) { // we check that we are inside the image (y-axis) 01997 if(aux_image[i][j]==-1.0) { // we check if this value is already calculated 01998 a[2]=0.0; 01999 a[4]=0.0; // we reset the a vector 02000 /* REMARK: ACTIVATE THE NEXT TWO LINES IF THERE ARE CONVERGENCE PROBLEMS */ 02001 Emin=ami_lens_distortion_estimation(xx,yy,Nl,Np,(double) i,(double) j,a,Na,2,(double) 0.,max_radius); 02002 Emin=ami_lens_distortion_estimation(xx,yy,Nl,Np,(double) i,(double) j,a,Na,4,(double) 0.,max_radius); 02003 Emin=ami_lens_distortion_estimation_2v(xx,yy,Nl,Np,(double) i,(double) j,a,Na,2,4,(double) 0., max_radius); 02004 aux_image[i][j]=Emin; //we save the value for possible use in new iterations 02005 } 02006 else Emin=aux_image[i][j]; 02007 if(Emin<initial_Emin) { 02008 initial_Emin=Emin; /* We save the best solution */ 02009 best_x_c=i; 02010 best_y_c=j; /* We save the best center of distortion found */ 02011 } 02012 } 02013 } 02014 } 02015 } 02016 x_c=best_x_c; 02017 y_c=best_y_c; 02018 printf("\nitera=%d,(x_c,y_c)=(%d,%d), Emin=%1.7e, last_Emin=%1.7e",n_iterations,best_x_c,best_y_c,initial_Emin,last_Emin); 02019 if(n_iterations==max_itera_patch) break; 02020 } 02021 stoptime = clock(); 02022 timeused = difftime(stoptime,starttime); 02023 a[5]=best_x_c; 02024 a[6]=best_y_c; /* We update the new distortion center coordinates */ 02025 printf("\n****************************************************************************"); 02026 printf("\nCPU time Optimizing Center of Distortion=%f (seconds)",timeused/(double)CLOCKS_PER_SEC); 02027 printf("\n****************************************************************************"); 02028 //we free the memory 02029 if(aux_image!=NULL) { 02030 for(int j=0; j<height; j++) { 02031 if(aux_image[j]!=NULL) free(aux_image[j]); 02032 } 02033 free(aux_image); 02034 } 02035 return(1); 02036 } 02037 02038 02044 int read_line_primitives( 02045 char filename[300] , 02046 int *Nl , 02047 int **Np , 02048 double ***x , 02049 double ***y ) 02050 { 02051 FILE *fp_1; 02052 int i,j,k; 02053 float tmp1,tmp2; 02054 if(!(fp_1=fopen(filename,"r"))) { 02055 printf("Error while opening the file %s\n",filename); 02056 return(1); 02057 } 02058 02059 fscanf(fp_1,"%d\n",Nl); /*get number of lines*/ 02060 if((*Nl)<=0) { 02061 printf("Error: The number of lines is 0 %s\n",filename); 02062 return(2); 02063 } 02064 *Np=(int*)malloc( sizeof(int)*(*Nl)); 02065 *x=(double**)malloc( sizeof(double*)*(*Nl) ); /* x pixels coordinates */ 02066 *y=(double**)malloc( sizeof(double*)*(*Nl) ); /* y pixels coordinates */ 02067 02068 printf("Nl=%d\n",*Nl); 02069 for(i=0; i<(*Nl); i++) { 02070 fscanf(fp_1,"%d",&k); /*get number of points for the "i" line */ 02071 (*Np)[i]=k; 02072 printf("Np[%d]=%d\n",i,(*Np)[i]); 02073 (*x)[i]=(double*)malloc( sizeof(double)*k ); 02074 (*y)[i]=(double*)malloc( sizeof(double)*k); 02075 for(j=0; j<k; j++) { 02076 fscanf(fp_1,"%f %f\n",&tmp1,&tmp2); 02077 (*x)[i][j]=tmp1; 02078 (*y)[i][j]=tmp2; 02079 printf("x[%d][%d]=%f x[%d][%d]=%f\n",i,j,(*x)[i][j],i,j,(*y)[i][j]); 02080 } 02081 } 02082 fclose(fp_1); 02083 return(0); 02084 } 02085 02093 double calculate_factor_n( 02094 double **xx , 02095 double **yy , 02096 int Nl , 02097 int *Np , 02098 double x0 , 02099 double y0 02100 ) 02101 { 02102 double **x_aux,**y_aux; /* AUXILIAR MATRICES TO COPY THE X,Y COORDINATES */ 02103 double factor_n=0.0; /* AUXILIAR VARIABLE */ 02104 int i,m, cont=0; /* AUXILIAR VARIABLE */ 02105 02106 /* WE ALLOCATE MEMORY FOR AUXILARY POINTS AND WE NORMALIZE ORIGINAL POINTS */ 02107 x_aux=(double**)malloc( sizeof(double*)*Nl); /* x pixels coordinates */ 02108 y_aux=(double**)malloc( sizeof(double*)*Nl); /* y pixels coordinates */ 02109 for(i=0; i<Nl; i++) { 02110 x_aux[i]=(double*)malloc( sizeof(double)*Np[i] ); 02111 y_aux[i]=(double*)malloc( sizeof(double)*Np[i] ); 02112 } 02113 02114 for(m=0; m<Nl; m++) { 02115 for(i=0; i<Np[m]; i++) { 02116 cont++; 02117 x_aux[m][i]=xx[m][i]; 02118 y_aux[m][i]=yy[m][i]; 02119 x_aux[m][i]-=x0; 02120 y_aux[m][i]-=y0; 02121 factor_n+=x_aux[m][i]*x_aux[m][i]+y_aux[m][i]*y_aux[m][i]; 02122 } 02123 } 02124 factor_n=sqrt(factor_n/cont); 02125 /* WE FREE THE MEMORY */ 02126 if(x_aux!=NULL) { 02127 for(i=0; i<Nl; i++) { 02128 if(x_aux[i]!=NULL) free(x_aux[i]); 02129 } 02130 free(x_aux); 02131 } 02132 if(y_aux!=NULL) { 02133 for(i=0; i<Nl; i++) { 02134 if(y_aux[i]!=NULL) free(y_aux[i]); 02135 } 02136 free(y_aux); 02137 } 02138 02139 return(factor_n); 02140 } 02141 02142 02156 void ami_lens_distortion_model_evaluation( 02157 double *a, // INPUT POLYNOMIAL DISTORTION MODEL 02158 int Na, // INPUT DEGREE OF POLYNOMIAL DISTORTION MODEL 02159 double xc,double yc, // INPUT CENTER OF DISTORTION 02160 double x_input,double y_input, // INPUT POINT 02161 double *x_output,double *y_output // OUTPUT UNDISTORTED POINT 02162 ) 02163 { 02164 double norm=sqrt((x_input-xc)*(x_input-xc)+(y_input-yc)*(y_input-yc)); 02165 double A=ami_polynomial_evaluation(a,Na,norm); 02166 *x_output=xc+(x_input-xc)*A; 02167 *y_output=yc+(y_input-yc)*A; 02168 } 02169 02170 02182 double ami_inverse_lens_distortion_newton_raphson( 02183 double x,double y, /* POINT TO INVERSE (INPUT)*/ 02184 double x0,double y0, /* CENTER OF THE IMAGE (INPUT)*/ 02185 double *xt,double *yt, /* INVERVE POINT TRANSFORMED (OUTPUT) */ 02186 double *a, /* LENS DISTORTION MODEL POLYNOM */ 02187 int Na) /* DEGREE OF THE LENS DISTORTION MODEL POLYNOM */ 02188 { 02189 if(a[Na]==0.) return(-1); 02190 02191 // AUXILIARY VARIABLES 02192 double *b,*b2,root2,root; 02193 02194 // WE ALLOCATE MEMORY 02195 b=(double*)malloc( sizeof(double)*(Na+2) ); 02196 b2=(double*)malloc( sizeof(double)*(Na+2) ); 02197 02198 // WE DEFINE THE POLYNOM WE NEED TO COMPUTE ROOTS AND THE DERIVATIVE */ 02199 for(int i=1; i<(Na+2); i++){ b[i]=a[i-1];} 02200 for(int i=0; i<(Na+1); i++){ b2[i]=a[i]*(i+1);} 02201 root=sqrt((x-x0)*(x-x0)+(y-y0)*(y-y0)); 02202 if(root==0){*xt=x; *yt=y; free(b); free(b2);return(0.);} 02203 b[0]=-root; 02204 //NEWTON-RAPHSON TO COMPUTE THE POLYNOMIAL ROOT 02205 for(int k=0;k<10000;k++){ 02206 double pol_eval=ami_polynomial_evaluation(b,Na+1,root); 02207 double pol_der=ami_polynomial_evaluation(b2,Na,root); 02208 if(pol_der==0.) break; 02209 root2=root-pol_eval/pol_der; 02210 if(fabs(root-root2)<(fabs(root)*1e-8)){ 02211 root=root2; 02212 // printf("k=%d ",k); 02213 break; 02214 } 02215 root=root2; 02216 } 02217 02218 *xt=x0+(x-x0)*root/(-b[0]); 02219 *yt=y0+(y-y0)*root/(-b[0]); 02220 02221 // WE CHECK THE RESULT 02222 /* double x_output,y_output; 02223 ami_lens_distortion_model_evaluation(a,Na,x0,y0,*xt,*yt,&x_output,&y_output); 02224 printf("root=%lf (x,y)=(%1.0lf,%1.0lf) output (x,y)=(%lf,%lf) \n",root,x,y,x_output,y_output); 02225 system("pause"); */ 02226 02227 free(b); 02228 free(b2); 02229 return( ( (root+b[0])*(root+b[0]) ) ); 02230 } 02231 02232 02243 int build_l1r_vector(std::vector<double> &l1r,ami::point2d<double> &dc, double max_distance_corner,int Na, double *a) 02244 { 02245 //BUILD INTERMEDIATE VECTOR WITH L-1(r) FROM CENTER TO FURTHEST CORNER 02246 if(a[Na]==0.) return(-1); 02247 l1r.resize((int)(max_distance_corner+1.5)); 02248 02249 // AUXILIARY VARIABLES 02250 double *b,*b2,root2,root=1.; 02251 02252 // WE ALLOCATE MEMORY 02253 b=(double*)malloc( sizeof(double)*(Na+2) ); 02254 b2=(double*)malloc( sizeof(double)*(Na+2) ); 02255 02256 // WE DEFINE THE POLYNOM WE NEED TO COMPUTE ROOTS AND THE DERIVATIVE */ 02257 for(int i=1; i<(Na+2); i++){ b[i]=a[i-1];} 02258 for(int i=0; i<(Na+1); i++){ b2[i]=a[i]*(i+1);} 02259 02260 // WE BUILD THE VECTOR OF INVERSE LENS DISTORTION FUNCTION 02261 for(int dist=1; dist<(int)(max_distance_corner+1.5); dist++) 02262 { 02263 // WE DEFINE THE POLYNOM WE NEED TO COMPUTE ROOTS AND THE DERIVATIVE */ 02264 b[0]=-dist; 02265 02266 //NEWTON-RAPHSON TO COMPUTE THE POLYNOMIAL ROOT 02267 for(int k=0;k<10000;k++){ 02268 double pol_eval=ami_polynomial_evaluation(b,Na+1,root); 02269 double pol_der=ami_polynomial_evaluation(b2,Na,root); 02270 if(pol_der==0.) break; 02271 root2=root-pol_eval/pol_der; 02272 if(fabs(root-root2)<(fabs(root)*1e-8)){ 02273 root=root2; 02274 //printf("k=%d ",k); 02275 break; 02276 } 02277 root=root2; 02278 } 02279 02280 //PUSH RESULT 02281 l1r[dist]=root/dist; 02282 } 02283 free(b); 02284 free(b2); 02285 l1r[0]=l1r[1]; 02286 02287 return 0; 02288 } 02289 02290 02299 ami::image<unsigned char> undistort_image_inverse_fast(ami::image<unsigned char> input_image,int Na, 02300 double *a,ami::point2d<double> dc,const double &image_amplification_factor) 02301 { 02302 int width0=input_image.width(); 02303 int height0=input_image.height(); 02304 int size =width0*height0; 02305 int width=(int) (width0*image_amplification_factor); 02306 int height=(int) (height0*image_amplification_factor); 02307 int sizenew =width*height; 02308 02309 // WE CREATE OUTPUT IMAGE 02310 ami::image<unsigned char> output_image(width,height,0,0,0); 02311 02312 //CALCULATE MAXIMUM DISTANCE FROM CENTRE TO A CORNER 02313 ami::point2d<double> corner(0,0); 02314 double max_distance_corner= (dc-corner).norm(); 02315 corner.y=height0; 02316 double distance_corner=(dc-corner).norm(); 02317 if(distance_corner>max_distance_corner) max_distance_corner=distance_corner; 02318 corner.x=width0; 02319 distance_corner=(dc-corner).norm(); 02320 if(distance_corner>max_distance_corner) max_distance_corner=distance_corner; 02321 corner.y=0; 02322 distance_corner=(dc-corner).norm(); 02323 if(distance_corner>max_distance_corner) max_distance_corner=distance_corner; 02324 02325 //BUILD INTERMEDIATE VECTOR 02326 std::vector<double> l1r; 02327 if(Na==0) { 02328 output_image=input_image; 02329 return(output_image); 02330 } 02331 if(build_l1r_vector(l1r,dc,max_distance_corner,Na,a)==-1) { 02332 output_image=input_image; 02333 return(output_image); 02334 } 02335 02336 int nc,n2,i,j,n2new; 02337 for (nc=0; nc<3; nc++) 02338 { 02339 n2=nc*size; 02340 n2new=nc*sizenew; 02341 #pragma omp parallel for \ 02342 shared(width,height,width0,height0,output_image,input_image,size,nc,n2)\ 02343 private(i,j) 02344 for(i=0; i<height; i++) { 02345 for(j=0; j<width; j++) { 02346 ami::point2d<double> temp((double) j/image_amplification_factor,(double) i/image_amplification_factor); 02347 double distance_centre= (dc-ami::point2d<double>((double) temp.x,(double) temp.y)).norm(); 02348 //INTERPOLATION 02349 int ind=(int)distance_centre; 02350 double dl1r=l1r[ind]+(distance_centre-ind)*(l1r[ind+1]-l1r[ind]); 02351 ami::point2d<double> p; 02352 p.x=dc.x+(temp.x-dc.x)*dl1r; 02353 p.y=dc.y+(temp.y-dc.y)*dl1r; 02354 int m = (int)p.y; 02355 int n = (int)p.x; 02356 02357 if(0<=m && m<height0 && 0<=n && n<width0) 02358 { 02359 //COLOUR INTERPOLATION 02360 double di=p.y-m; 02361 double dj=p.x-n; 02362 unsigned int k=i*width+j; 02363 unsigned int k0=m*width0+n; 02364 double accum=0; 02365 double w_accum=0; 02366 double w=((1.-di)*(1.-dj)); 02367 02368 accum+=(double)w*input_image[k0+n2]; 02369 w_accum+=w; 02370 02371 02372 if( (di*(1.-dj))>0. && (m+1)<height0) 02373 { 02374 k0=(m+1)*width0+n; 02375 w=(di*(1.-dj)); 02376 accum+=(double)w*input_image[k0+n2]; 02377 w_accum+=w; 02378 } 02379 if( ((1-di)*(dj))>0. && (n+1)<width0) 02380 { 02381 k0=(m)*width0+n+1; 02382 w=(1.-di)*(dj); 02383 accum+=(double)w*input_image[k0+n2]; 02384 w_accum+=w; 02385 } 02386 if( ((di)*(dj))>0. && (n+1)<width0 && (m+1)<height0) 02387 { 02388 k0=(m+1)*width0+n+1; 02389 w=(di)*(dj); 02390 accum+=(double)w*input_image[k0+n2]; 02391 w_accum+=w; 02392 } 02393 02394 02395 if(w_accum>0.) output_image[k+n2new]=(unsigned char) (accum/w_accum); 02396 } 02397 } 02398 } 02399 } 02400 02401 return(output_image); 02402 }