00001
00002 #include "vgl_h_matrix_2d_compute_linear.h"
00003
00004
00005
00006 #include <vcl_iostream.h>
00007 #include <vcl_cmath.h>
00008 #include <vcl_cassert.h>
00009 #include <vnl/vnl_inverse.h>
00010 #include <vnl/vnl_transpose.h>
00011 #include <vnl/algo/vnl_svd.h>
00012 #include <vgl/algo/vgl_norm_trans_2d.h>
00013
00014
00015
00016 vgl_h_matrix_2d_compute_linear::vgl_h_matrix_2d_compute_linear(bool allow_ideal_points):
00017 allow_ideal_points_(allow_ideal_points)
00018 {
00019 }
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 const int TM_UNKNOWNS_COUNT = 9;
00030 const double DEGENERACY_THRESHOLD = 0.00001;
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049 bool vgl_h_matrix_2d_compute_linear::
00050 solve_linear_problem(int equ_count,
00051 vcl_vector<vgl_homg_point_2d<double> > const& p1,
00052 vcl_vector<vgl_homg_point_2d<double> > const& p2,
00053 vgl_h_matrix_2d<double>& H)
00054 {
00055
00056 vnl_matrix<double> D(equ_count, TM_UNKNOWNS_COUNT);
00057 int n = p1.size();
00058 int row = 0;
00059 for (int i = 0; i < n; i++) {
00060 D(row, 0) = p1[i].x() * p2[i].w();
00061 D(row, 1) = p1[i].y() * p2[i].w();
00062 D(row, 2) = p1[i].w() * p2[i].w();
00063 D(row, 3) = 0;
00064 D(row, 4) = 0;
00065 D(row, 5) = 0;
00066 D(row, 6) = -p1[i].x() * p2[i].x();
00067 D(row, 7) = -p1[i].y() * p2[i].x();
00068 D(row, 8) = -p1[i].w() * p2[i].x();
00069 ++row;
00070
00071 D(row, 0) = 0;
00072 D(row, 1) = 0;
00073 D(row, 2) = 0;
00074 D(row, 3) = p1[i].x() * p2[i].w();
00075 D(row, 4) = p1[i].y() * p2[i].w();
00076 D(row, 5) = p1[i].w() * p2[i].w();
00077 D(row, 6) = -p1[i].x() * p2[i].y();
00078 D(row, 7) = -p1[i].y() * p2[i].y();
00079 D(row, 8) = -p1[i].w() * p2[i].y();
00080 ++row;
00081
00082 if (allow_ideal_points_) {
00083 D(row, 0) = p1[i].x() * p2[i].y();
00084 D(row, 1) = p1[i].y() * p2[i].y();
00085 D(row, 2) = p1[i].w() * p2[i].y();
00086 D(row, 3) = -p1[i].x() * p2[i].x();
00087 D(row, 4) = -p1[i].y() * p2[i].x();
00088 D(row, 5) = -p1[i].w() * p2[i].x();
00089 D(row, 6) = 0;
00090 D(row, 7) = 0;
00091 D(row, 8) = 0;
00092 ++row;
00093 }
00094 }
00095
00096 D.normalize_rows();
00097 vnl_svd<double> svd(D);
00098
00099
00100
00101
00102 if (svd.W(7)<DEGENERACY_THRESHOLD*svd.W(8)) {
00103 vcl_cerr << "vgl_h_matrix_2d_compute_linear : design matrix has rank < 8\n"
00104 << "vgl_h_matrix_2d_compute_linear : probably due to degenerate point configuration\n";
00105 return false;
00106 }
00107
00108 H.set(svd.nullvector().data_block());
00109 return true;
00110 }
00111
00112 bool vgl_h_matrix_2d_compute_linear::
00113 compute_p(vcl_vector<vgl_homg_point_2d<double> > const& points1,
00114 vcl_vector<vgl_homg_point_2d<double> > const& points2,
00115 vgl_h_matrix_2d<double>& H)
00116 {
00117
00118 assert(points1.size() == points2.size());
00119 int n = points1.size();
00120
00121 int equ_count = n * (allow_ideal_points_ ? 3 : 2);
00122 if (n * 2 < TM_UNKNOWNS_COUNT - 1) {
00123 vcl_cerr << "vgl_h_matrix_2d_compute_linear: Need at least 4 matches.\n";
00124 if (n == 0) vcl_cerr << "Could be vcl_vector setlength idiosyncrasies!\n";
00125 return false;
00126 }
00127
00128 vgl_norm_trans_2d<double> tr1, tr2;
00129 if (!tr1.compute_from_points(points1))
00130 return false;
00131 if (!tr2.compute_from_points(points2))
00132 return false;
00133 vcl_vector<vgl_homg_point_2d<double> > tpoints1, tpoints2;
00134 for (int i = 0; i<n; i++)
00135 {
00136 tpoints1.push_back(tr1(points1[i]));
00137 tpoints2.push_back(tr2(points2[i]));
00138 }
00139 vgl_h_matrix_2d<double> hh;
00140 if (!solve_linear_problem(equ_count, tpoints1, tpoints2, hh))
00141 return false;
00142
00143
00144
00145
00146
00147
00148
00149
00150 vgl_h_matrix_2d<double> tr2_inv = tr2.get_inverse();
00151 H = tr2_inv*hh*tr1;
00152 return true;
00153 }
00154
00155 bool vgl_h_matrix_2d_compute_linear::
00156 compute_l(vcl_vector<vgl_homg_line_2d<double> > const& lines1,
00157 vcl_vector<vgl_homg_line_2d<double> > const& lines2,
00158 vgl_h_matrix_2d<double>& H)
00159 {
00160
00161 assert(lines1.size() == lines2.size());
00162 int n = lines1.size();
00163 int equ_count = 2*n;
00164
00165
00166 vgl_norm_trans_2d<double> tr1, tr2;
00167 if (!tr1.compute_from_lines(lines1))
00168 return false;
00169 if (!tr2.compute_from_lines(lines2))
00170 return false;
00171 vcl_vector<vgl_homg_point_2d<double> > tlines1, tlines2;
00172 for (vcl_vector<vgl_homg_line_2d<double> >::const_iterator
00173 lit = lines1.begin(); lit != lines1.end(); lit++)
00174 {
00175
00176 vgl_homg_line_2d<double> l = tr1(*lit);
00177
00178 vgl_homg_point_2d<double> p(l.a(), l.b(), l.c());
00179 tlines1.push_back(p);
00180 }
00181 for (vcl_vector<vgl_homg_line_2d<double> >::const_iterator
00182 lit = lines2.begin(); lit != lines2.end(); lit++)
00183 {
00184
00185 vgl_homg_line_2d<double> l = tr2(*lit);
00186
00187 vgl_homg_point_2d<double> p(l.a(), l.b(), l.c());
00188 tlines2.push_back(p);
00189 }
00190
00191 vgl_h_matrix_2d<double> hl,hp,tr2inv;
00192 if (!solve_linear_problem(equ_count, tlines1, tlines2, hl))
00193 return false;
00194
00195
00196 vnl_matrix_fixed<double, 3, 3> const & Ml = hl.get_matrix();
00197 vnl_matrix_fixed<double, 3, 3> Mp = vnl_inverse_transpose(Ml);
00198 hp.set(Mp);
00199
00200
00201
00202
00203
00204
00205
00206
00207 tr2inv = tr2.get_inverse();
00208 H = tr2inv*hp*tr1;
00209 return true;
00210 }
00211
00212 bool vgl_h_matrix_2d_compute_linear::
00213 compute_pl(vcl_vector<vgl_homg_point_2d<double> > const& points1,
00214 vcl_vector<vgl_homg_point_2d<double> > const& points2,
00215 vcl_vector<vgl_homg_line_2d<double> > const& lines1,
00216 vcl_vector<vgl_homg_line_2d<double> > const& lines2,
00217 vgl_h_matrix_2d<double>& H)
00218 {
00219
00220 assert(points1.size() == points2.size());
00221 int np = points1.size();
00222
00223 assert(lines1.size() == lines2.size());
00224 int nl = lines1.size();
00225
00226 int equ_count = np * (allow_ideal_points_ ? 3 : 2) + 2*nl;
00227 if ((np+nl)*2+1 < TM_UNKNOWNS_COUNT)
00228 {
00229 vcl_cerr << "vgl_h_matrix_2d_compute_linear: Need at least 4 matches.\n";
00230 if (np+nl == 0) vcl_cerr << "Could be vcl_vector setlength idiosyncrasies!\n";
00231 return false;
00232 }
00233
00234 vgl_norm_trans_2d<double> tr1, tr2;
00235 if (!tr1.compute_from_points_and_lines(points1,lines1))
00236 return false;
00237 if (!tr2.compute_from_points_and_lines(points2,lines2))
00238 return false;
00239 vcl_vector<vgl_homg_point_2d<double> > tpoints1, tpoints2;
00240 for (int i = 0; i<np; i++)
00241 {
00242 tpoints1.push_back(tr1(points1[i]));
00243 tpoints2.push_back(tr2(points2[i]));
00244 }
00245 for (int i = 0; i<nl; i++)
00246 {
00247 double a=lines1[i].a(), b=lines1[i].b(), c=lines1[i].c(), d=vcl_sqrt(a*a+b*b);
00248 tpoints1.push_back(tr1(vgl_homg_point_2d<double>(-a*c,-b*c,d)));
00249 a=lines2[i].a(), b=lines2[i].b(), c=lines2[i].c(), d = vcl_sqrt(a*a+b*b);
00250 tpoints2.push_back(tr2(vgl_homg_point_2d<double>(-a*c,-b*c,d)));
00251 }
00252 vgl_h_matrix_2d<double> hh;
00253 if (!solve_linear_problem(equ_count, tpoints1, tpoints2, hh))
00254 return false;
00255
00256 vgl_h_matrix_2d<double> tr2_inv = tr2.get_inverse();
00257 H = tr2_inv*hh*tr1;
00258 return true;
00259 }
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278 bool vgl_h_matrix_2d_compute_linear::
00279 solve_weighted_least_squares(vcl_vector<vgl_homg_line_2d<double> > const& l1,
00280 vcl_vector<vgl_homg_line_2d<double> > const& l2,
00281 vcl_vector<double> const& w,
00282 vgl_h_matrix_2d<double>& H)
00283 {
00284 int Nc = l1.size();
00285
00286
00287 vnl_vector<double> two_w(2*Nc);
00288 int j =0;
00289 for (int i = 0; i<Nc; i++, j+=2)
00290 {
00291 two_w[j]=w[i];
00292 two_w[j+1]=w[i];
00293 }
00294 vnl_diag_matrix<double> W(two_w);
00295
00296
00297 vnl_matrix<double> D(2*Nc, TM_UNKNOWNS_COUNT);
00298 vnl_matrix<double> M(TM_UNKNOWNS_COUNT, TM_UNKNOWNS_COUNT);
00299
00300 int row = 0;
00301 for (int i = 0; i < Nc; i++)
00302 {
00303 D(row, 0) = l1[i].a() * l2[i].c();
00304 D(row, 1) = l1[i].b() * l2[i].c();
00305 D(row, 2) = l1[i].c() * l2[i].c();
00306 D(row, 3) = 0;
00307 D(row, 4) = 0;
00308 D(row, 5) = 0;
00309 D(row, 6) = -l1[i].a() * l2[i].a();
00310 D(row, 7) = -l1[i].b() * l2[i].a();
00311 D(row, 8) = -l1[i].c() * l2[i].a();
00312 ++row;
00313
00314 D(row, 0) = 0;
00315 D(row, 1) = 0;
00316 D(row, 2) = 0;
00317 D(row, 3) = l1[i].a() * l2[i].c();
00318 D(row, 4) = l1[i].b() * l2[i].c();
00319 D(row, 5) = l1[i].c() * l2[i].c();
00320 D(row, 6) = -l1[i].a() * l2[i].b();
00321 D(row, 7) = -l1[i].b() * l2[i].b();
00322 D(row, 8) = -l1[i].c() * l2[i].b();
00323 ++row;
00324 }
00325 M = vnl_transpose(D)*W*D;
00326 D.normalize_rows();
00327 vnl_svd<double> svd(D);
00328
00329
00330
00331
00332 if (svd.W(7)<DEGENERACY_THRESHOLD*svd.W(8)) {
00333 vcl_cerr << "vgl_h_matrix_2d_compute_linear : design matrix has rank < 8\n"
00334 << "vgl_h_matrix_2d_compute_linear : probably due to degenerate point configuration\n";
00335 return false;
00336 }
00337
00338 H.set(svd.nullvector().data_block());
00339 return true;
00340 }
00341
00342 bool vgl_h_matrix_2d_compute_linear::
00343 compute_l(vcl_vector<vgl_homg_line_2d<double> > const& lines1,
00344 vcl_vector<vgl_homg_line_2d<double> > const& lines2,
00345 vcl_vector<double> const & weights,
00346 vgl_h_matrix_2d<double>& H)
00347 {
00348
00349 assert(lines1.size() == lines2.size());
00350
00351
00352
00353 vgl_norm_trans_2d<double> tr1, tr2;
00354 if (!tr1.compute_from_lines(lines1))
00355 return false;
00356 if (!tr2.compute_from_lines(lines2))
00357 return false;
00358 vcl_vector<vgl_homg_line_2d<double> > tlines1, tlines2;
00359 for (vcl_vector<vgl_homg_line_2d<double> >::const_iterator
00360 lit = lines1.begin(); lit != lines1.end(); lit++)
00361 {
00362
00363 vgl_homg_line_2d<double> l = tr1(*lit);
00364 tlines1.push_back(l);
00365 }
00366 for (vcl_vector<vgl_homg_line_2d<double> >::const_iterator
00367 lit = lines2.begin(); lit != lines2.end(); lit++)
00368 {
00369
00370 vgl_homg_line_2d<double> l = tr2(*lit);
00371 tlines2.push_back(l);
00372 }
00373
00374 vgl_h_matrix_2d<double> hl,hp,tr2inv;
00375 if (!solve_weighted_least_squares(tlines1, tlines2, weights, hl))
00376 return false;
00377
00378
00379 vnl_matrix_fixed<double, 3, 3> const & Ml = hl.get_matrix();
00380
00381 if( vnl_det(Ml) == 0.0 )
00382 return false;
00383 vnl_matrix_fixed<double, 3, 3> Mp = vnl_inverse_transpose(Ml);
00384 hp.set(Mp);
00385
00386
00387
00388
00389
00390
00391
00392
00393 tr2inv = tr2.get_inverse();
00394 H = tr2inv*hp*tr1;
00395 return true;
00396 }