00001
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005
00006
00007
00008 #include "FMatrixComputeNonLinear.h"
00009
00010 #include <vcl_iostream.h>
00011
00012 #include <vnl/vnl_matrix.h>
00013 #include <vnl/algo/vnl_levenberg_marquardt.h>
00014 #include <vnl/vnl_double_2.h>
00015 #include <vnl/vnl_double_3.h>
00016 #include <vgl/vgl_homg_line_2d.h>
00017 #include <mvl/HomgNorm2D.h>
00018 #include <mvl/HomgPoint2D.h>
00019 #include <mvl/HomgLine2D.h>
00020 #include <mvl/HomgInterestPointSet.h>
00021 #include <mvl/FMatrix.h>
00022 #include <mvl/FManifoldProject.h>
00023 #include <mvl/FMatrixCompute7Point.h>
00024
00025
00026
00027 const int FMatrixComputeNonLinear_nparams = 7;
00028
00029
00030
00031
00032 FMatrixComputeNonLinear::FMatrixComputeNonLinear(PairMatchSetCorner* matches)
00033 : vnl_least_squares_function(FMatrixComputeNonLinear_nparams, matches->compute_match_count(), no_gradient),
00034 data_size_(matches->compute_match_count()),
00035 matches_(*matches),
00036 one_(true)
00037 {
00038
00039
00040 HomgInterestPointSet const* points1 = matches_.get_corners1();
00041 HomgInterestPointSet const* points2 = matches_.get_corners2();
00042 vcl_vector<HomgPoint2D> dead1, dead2;
00043 vcl_vector<int> point1_int, point2_int;
00044 matches_.extract_matches(dead1, point1_int, dead2, point2_int);
00045 data_size_ = matches_.count();
00046 points1_.resize(points1->size());
00047 points2_.resize(points2->size());
00048
00049
00050 for (int a = 0; a < data_size_; a++) {
00051 vnl_double_2 temp1;
00052 temp1 = points1->get_2d(point1_int[a]);
00053 points1_[a] = vgl_homg_point_2d<double>(temp1[0], temp1[1], 1.0);
00054 }
00055
00056 for (int a = 0; a < data_size_; a++) {
00057 vnl_double_2 temp2;
00058 temp2 = points2->get_2d(point2_int[a]);
00059 points2_[a] = vgl_homg_point_2d<double>(temp2[0], temp2[1], 1.0);
00060 }
00061 }
00062
00063
00064
00065
00066 bool FMatrixComputeNonLinear::compute_basis(FMatrix* F, vcl_vector<int> basis)
00067 {
00068 one_ = false;
00069 vcl_vector<vgl_homg_point_2d<double> > basis1(7), basis2(7);
00070 for (int i = 0; i < 7; i++) {
00071 int other = matches_.get_match_12(basis[i]);
00072 if (other == -1)
00073 vcl_cerr << "The basis index doesn't include a match for " << i << ".\n";
00074 else {
00075 vnl_double_2 p1 = matches_.get_corners1()->get_2d(basis[i]);
00076 vnl_double_2 p2 = matches_.get_corners2()->get_2d(other);
00077 basis1[i] = vgl_homg_point_2d<double>(p1[0], p1[1], 1.0);
00078 basis2[i] = vgl_homg_point_2d<double>(p2[0], p2[1], 1.0);
00079 }
00080 }
00081 basis1_ = basis1;
00082 basis2_ = basis2;
00083 return compute(F);
00084 }
00085
00086
00087
00088
00089 bool FMatrixComputeNonLinear::compute(FMatrix* F)
00090 {
00091 FMatrix F_final;
00092
00093 vcl_cerr << "FMatrixComputeNonLinear: matches = "<< data_size_ <<", using "<< FMatrixComputeNonLinear_nparams <<" parameters\n";
00094 double so_far = 1e+8;
00095 FMatrix norm_F = *F;
00096 if (one_)
00097 {
00098 for (p_ = 0; p_ < 3; p_++)
00099 {
00100 for (q_ = 0; q_ < 3; q_++)
00101 {
00102 for (r_ = 0; r_ < 4; r_++)
00103 {
00104 FMatrix norm_F = *F;
00105 int r1 = 0, c1 = 0, r2 = 0, c2 = 0;
00106 get_plan(r1, c1, r2, c2);
00107 vnl_matrix<double> mat;
00108 norm_F.get(&mat);
00109
00110 switch (r_) {
00111 case 0 :
00112 mat /= mat.get(r1, c1);
00113 break;
00114 case 1 :
00115 mat /= mat.get(r1, c2);
00116 break;
00117 case 2 :
00118 mat /= mat.get(r2, c1);
00119 break;
00120 case 3 :
00121 mat /= mat.get(r2, c2);
00122 break;
00123 default:
00124 break;
00125 }
00126
00127 vnl_vector<double> f_params(FMatrixComputeNonLinear_nparams);
00128 fmatrix_to_params(FMatrix(mat), f_params);
00129
00130 vnl_levenberg_marquardt lm(*this);
00131
00132
00133
00134 lm.set_max_function_evals(200);
00135 lm.set_f_tolerance(1e-6);
00136 lm.set_x_tolerance(1e-6);
00137
00138 lm.minimize(f_params);
00139
00140 if (lm.get_end_error() < so_far) {
00141 so_far = lm.get_end_error();
00142 vcl_cerr << "so_far : " << so_far << vcl_endl;
00143 norm_F = params_to_fmatrix(f_params);
00144 F_final = norm_F;
00145 vgl_homg_point_2d<double> e1, e2;
00146 F_final.get_epipoles(e1, e2);
00147 vcl_cerr << "Epipole locations 1 : " << e1 << " 2 : " << e2 << '\n';
00148 }
00149 }
00150 }
00151 }
00152 }
00153 else
00154 {
00155 F_orig_ = norm_F;
00156 vnl_vector<double> f_params(FMatrixComputeNonLinear_nparams, 0.0);
00157 FMatrix res = params_to_fmatrix(f_params);
00158 vnl_double_3x3 mat1 = norm_F.get_matrix();
00159 vnl_double_3x3 mat2 = res.get_matrix();
00160 mat1 /= mat1(2, 2);
00161 mat2 /= mat2(2, 2);
00162
00163 vnl_levenberg_marquardt lm(*this);
00164
00165
00166
00167 lm.set_max_function_evals(100);
00168 lm.set_f_tolerance(1e-4);
00169 lm.set_x_tolerance(1e-3);
00170 lm.set_epsilon_function(1e-4);
00171 lm.minimize(f_params);
00172
00173 if (lm.get_end_error() < so_far) {
00174 so_far = lm.get_end_error();
00175 vcl_cerr << "so_far : " << so_far << vcl_endl;
00176 for (int l = 0; l < 7; l++)
00177 vcl_cerr << f_params(l) << vcl_endl;
00178 norm_F = params_to_fmatrix(f_params);
00179 F_final = norm_F;
00180 lm.diagnose_outcome();
00181 vgl_homg_point_2d<double> e1, e2;
00182 F_final.get_epipoles(e1, e2);
00183 vcl_cerr << "Epipole locations 1 : " << e1 << " 2 : " << e2 << '\n';
00184 }
00185 }
00186 *F = F_final;
00187 return true;
00188 }
00189
00190
00191
00192 void FMatrixComputeNonLinear::f(const vnl_vector<double>& f_params, vnl_vector<double>& fx)
00193 {
00194 FMatrix F = params_to_fmatrix(f_params);
00195
00196 fx = calculate_residuals(&F);
00197 }
00198
00199
00200 void FMatrixComputeNonLinear::fmatrix_to_params(const FMatrix& F, vnl_vector<double>& params)
00201 {
00202
00203 int c1= 0, r1 = 0, c2 = 0, r2 = 0;
00204 get_plan(r1, c1, r2, c2);
00205 double b = 0.0, a = 0.0, c = 0.0;
00206 switch (r_) {
00207 case 0 :
00208 a = F.get(r1, c2);
00209 b = -F.get(r2, c1);
00210 c = -F.get(r2, c2);
00211 break;
00212 case 1 :
00213 a = F.get(r1, c1);
00214 b = -F.get(r2 ,c1);
00215 c = -F.get(r2, c2);
00216 break;
00217 case 2 :
00218 a = F.get(r1, c1);
00219 b = F.get(r1, c2);
00220 c = -F.get(r2, c2);
00221 break;
00222 case 3 :
00223 a = F.get(r1, c1);
00224 b = F.get(r1, c2);
00225 c = -F.get(r2, c1);
00226 break;
00227 default:
00228 break;
00229 }
00230 vgl_homg_point_2d<double> one, two;
00231 vnl_double_2 e1, e2;
00232 F.get_epipoles(one, two);
00233 vnl_double_3 e1h(one.x(), one.y(), one.w());
00234 vnl_double_3 e2h(two.x(), two.y(), two.w());
00235 e1h = e1h.normalize();
00236 e2h = e2h.normalize();
00237
00238 switch (p_) {
00239 case 0 :
00240 e1 = vnl_double_2(e1h[1]/e1h[0], e1h[2]/e1h[0]);
00241 break;
00242 case 1 :
00243 e1 = vnl_double_2(e1h[0]/e1h[1], e1h[2]/e1h[1]);
00244 break;
00245 case 2 :
00246 e1 = vnl_double_2(e1h[0]/e1h[2], e1h[1]/e1h[2]);
00247 break;
00248 default:
00249 break;
00250 }
00251 switch (q_) {
00252 case 0 :
00253 e2 = vnl_double_2(e2h[1]/e2h[0], e2h[2]/e2h[0]);
00254 break;
00255 case 1 :
00256 e2 = vnl_double_2(e2h[0]/e2h[1], e2h[2]/e2h[1]);
00257 break;
00258 case 2 :
00259 e2 = vnl_double_2(e2h[0]/e2h[2], e2h[1]/e2h[2]);
00260 break;
00261 default:
00262 break;
00263 }
00264 params.put(0, a);
00265 params.put(1, b);
00266 params.put(2, c);
00267 params.put(3, e1[0]);
00268 params.put(4, e1[1]);
00269 params.put(5, e2[0]);
00270 params.put(6, e2[1]);
00271 }
00272
00273
00274
00275 FMatrix FMatrixComputeNonLinear::params_to_fmatrix(const vnl_vector<double>& params)
00276 {
00277 FMatrix ret;
00278
00279 if (one_)
00280 {
00281 vnl_double_3x3 ref = ret.get_matrix();
00282
00283 int c1= 0, r1 = 0, c2 = 0, r2 = 0;
00284 get_plan(r1, c1, r2, c2);
00285 double a = params.get(0);
00286 double b = params.get(1);
00287 double c = params.get(2);
00288 double x = -params.get(3);
00289 double y = -params.get(4);
00290 double xd = -params.get(5);
00291 double yd = -params.get(6);
00292 double d;
00293 switch (r_)
00294 {
00295 case 0 :
00296 d = 1.0;
00297 ref.put(r1, c2, a);
00298 ref.put(r2, c1, -b);
00299 ref.put(r2, c2, -c);
00300 ref.put(r1, c1, d);
00301 ref.put(r1, p_, d*x + a*y);
00302 ref.put(r2, p_, -b*x - c*y);
00303 ref.put(q_, c1, d*xd - b*yd);
00304 ref.put(q_, c2, a*xd - c*yd);
00305 ref.put(q_, p_, xd*(d*x + a*y) - yd*(b*x + c*y));
00306 break;
00307 case 1 :
00308 d = 1.0;
00309 ref.put(r1, c1, a);
00310 ref.put(r2, c1, -b);
00311 ref.put(r2, c2, -c);
00312 ref.put(r1, c2, d);
00313 ref.put(r1, p_, a*x + d*y);
00314 ref.put(r2, p_, -b*x - c*y);
00315 ref.put(q_, c1, a*xd - b*yd);
00316 ref.put(q_, c2, d*xd - c*yd);
00317 ref.put(q_, p_, xd*(a*x + d*y) - yd*(b*x + c*y));
00318 break;
00319 case 2 :
00320 d = -1.0;
00321 ref.put(r1, c1, a);
00322 ref.put(r1, c2, b);
00323 ref.put(r2, c2, -c);
00324 ref.put(r2, c1, -d);
00325 ref.put(r1, p_, a*x + b*y);
00326 ref.put(r2, p_, -d*x - c*y);
00327 ref.put(q_, c1, a*xd - d*yd);
00328 ref.put(q_, c2, b*xd - c*yd);
00329 ref.put(q_, p_, xd*(a*x + b*y) - yd*(d*x + c*y));
00330 break;
00331 case 3 :
00332 d = -1.0;
00333 ref.put(r1, c1, a);
00334 ref.put(r1, c2, b);
00335 ref.put(r2, c1, -c);
00336 ref.put(r2, c2, -d);
00337 ref.put(r1, p_, a*x + b*y);
00338 ref.put(r2, p_, -c*x - d*y);
00339 ref.put(q_, c1, a*xd - c*yd);
00340 ref.put(q_, c2, b*xd - d*yd);
00341 ref.put(q_, p_, xd*(a*x + b*y) - yd*(c*x + d*y));
00342 break;
00343 default:
00344 break;
00345 }
00346 ret.set(ref);
00347 return ret;
00348 }
00349 else
00350 {
00351 vcl_vector<vgl_homg_point_2d<double> > new_points1(7);
00352 vgl_homg_point_2d<double> e1, e2;
00353 F_orig_.get_epipoles(e1, e2);
00354 double e1nx = e1.x()/e1.w(), e1ny = e1.y()/e1.w();
00355
00356 for (int i = 0; i < 7; i++) {
00357 double t1x = basis1_[i].x()/basis1_[i].w(), t1y = basis1_[i].y()/basis1_[i].w();
00358
00359 double grads1 = -(e1ny - t1y)/(e1nx - t1x);
00360
00361 new_points1[i] = vgl_homg_point_2d<double>(params[i]/grads1 + t1x, params[i]*grads1 + t1y, 1.0);
00362
00363 }
00364 FMatrixCompute7Point computor(true, true);
00365 vcl_vector<FMatrix*> ref;
00366 if (!computor.compute(new_points1, basis2_, ref))
00367 vcl_cerr << "FMatrixCompute7Point Failure\n";
00368 double final = 0.0;
00369 unsigned int num = 0;
00370 for (unsigned int l = 0; l < ref.size(); l++) {
00371 vnl_vector<double> res = calculate_residuals(ref[l]);
00372 double so_far = 0.0;
00373 for (unsigned int m = 0; m < res.size(); m++)
00374 so_far += res[m];
00375
00376 if (so_far < final) {
00377 final = so_far;
00378 num = l;
00379 }
00380 }
00381 ret = *ref[num];
00382
00383 for (unsigned int l = 0; l < ref.size(); l++)
00384 delete ref[l];
00385
00386 return ret;
00387 }
00388 }
00389
00390
00391 void FMatrixComputeNonLinear::get_plan(int &r1, int &c1, int &r2, int &c2)
00392 {
00393 switch (p_) {
00394 case 0 :
00395 c1 = 1;
00396 c2 = 2;
00397 break;
00398 case 1 :
00399 c1 = 0;
00400 c2 = 2;
00401 break;
00402 case 2 :
00403 c1 = 0;
00404 c2 = 1;
00405 break;
00406 default:
00407 break;
00408 }
00409 switch (q_) {
00410 case 0 :
00411 r1 = 1;
00412 r2 = 2;
00413 break;
00414 case 1 :
00415 r1 = 0;
00416 r2 = 2;
00417 break;
00418 case 2 :
00419 r1 = 0;
00420 r2 = 1;
00421 break;
00422 default:
00423 break;
00424 }
00425 }
00426
00427 static double perp_dist_squared(vgl_homg_point_2d<double> const& p,
00428 vgl_homg_line_2d <double> const& l)
00429 {
00430 double r = l.a()*p.x() + l.b()*p.y() + l.c()*p.w();
00431 if (r == 0) return 0.0;
00432 r /= p.w();
00433 return r * r / (l.a()*l.a() + l.b()*l.b());
00434 }
00435
00436 vnl_vector<double> FMatrixComputeNonLinear::calculate_residuals(FMatrix* F)
00437 {
00438 vnl_vector<double> fx(data_size_);
00439 vnl_matrix<double> f(3, 3, 0.0);
00440 F->get(&f);
00441 f /= f.rms();
00442 #if 0
00443 vnl_matrix<double> ft = f.transpose();
00444 vnl_matrix<double> z(3, 3, 0.0);
00445 z.put(0, 0, 1.0);z.put(1, 1, 1.0);
00446 vnl_matrix<double> pre1 = ft*z*f;
00447 vnl_matrix<double> pre2 = f*z*ft;
00448 #endif
00449
00450 for (int i = 0; i < data_size_; i++)
00451 {
00452 vgl_homg_point_2d<double> one = points1_[i], two = points2_[i];
00453 double t = 0.0;
00454 vgl_homg_line_2d<double> l1 = F->image2_epipolar_line(one);
00455 vgl_homg_line_2d<double> l2 = F->image1_epipolar_line(two);
00456 t += perp_dist_squared(two, l1);
00457 t += perp_dist_squared(one, l2);
00458 #if 0
00459 vnl_double_3 oi(1.0); oi[0]=one.x()/one.w(); oi[1]=one.y()/one.w();
00460 vnl_double_3 ti(1.0); ti[0]=two.x()/two.w(); ti[1]=two.x()/two.w();
00461 vnl_double_3 p1 = ti*pre1;
00462 vnl_double_3 p2 = oi*pre2;
00463 double p11 = p1[0]*oi[0] + p1[1]*oi[1] + p1[2]*oi[2];
00464 double p21 = p2[0]*ti[0] + p2[1]*ti[1] + p2[2]*ti[2];
00465 double factor = 1.0/ p11 + 1.0/ p21;
00466 #endif
00467 fx[i] = t;
00468 }
00469 return fx;
00470 }