00001
00002 #ifndef vpgl_camera_compute_cxx_
00003 #define vpgl_camera_compute_cxx_
00004
00005 #include "vpgl_camera_compute.h"
00006
00007
00008 #include <vcl_iostream.h>
00009 #include <vcl_cassert.h>
00010 #include <vcl_cstdlib.h>
00011 #include <vcl_cmath.h>
00012 #include <vnl/vnl_numeric_traits.h>
00013 #include <vnl/vnl_det.h>
00014 #include <vnl/vnl_inverse.h>
00015 #include <vnl/vnl_vector_fixed.h>
00016 #include <vnl/vnl_double_3.h>
00017 #include <vnl/vnl_matrix_fixed.h>
00018 #include <vnl/algo/vnl_svd.h>
00019 #include <vnl/algo/vnl_qr.h>
00020 #include <vgl/algo/vgl_rotation_3d.h>
00021 #include <vgl/algo/vgl_h_matrix_2d_compute_linear.h>
00022 #include <vgl/algo/vgl_h_matrix_3d.h>
00023 #include <vgl/vgl_homg_point_3d.h>
00024 #include <vpgl/algo/vpgl_ortho_procrustes.h>
00025 #include <vpgl/algo/vpgl_optimize_camera.h>
00026 #include <vgl/vgl_point_2d.h>
00027 #include <vgl/vgl_point_3d.h>
00028 #include <vgl/vgl_homg_point_2d.h>
00029 #include <vpgl/vpgl_lvcs.h>
00030 #include <vpgl/algo/vpgl_backproject.h>
00031
00032
00033
00034 bool
00035 vpgl_proj_camera_compute::compute(
00036 const vcl_vector< vgl_point_2d<double> >& image_pts,
00037 const vcl_vector< vgl_point_3d<double> >& world_pts,
00038 vpgl_proj_camera<double>& camera )
00039 {
00040 vcl_vector< vgl_homg_point_2d<double> > image_pts2;
00041 vcl_vector< vgl_homg_point_3d<double> > world_pts2;
00042 for (unsigned int i = 0; i < image_pts.size(); ++i)
00043 image_pts2.push_back( vgl_homg_point_2d<double>( image_pts[i] ) );
00044 for (unsigned int i = 0; i < world_pts.size(); ++i)
00045 world_pts2.push_back( vgl_homg_point_3d<double>( world_pts[i] ) );
00046 return compute( image_pts2, world_pts2, camera );
00047 }
00048
00049
00050
00051 bool
00052 vpgl_proj_camera_compute::compute(
00053 const vcl_vector< vgl_homg_point_2d<double> >& image_pts,
00054 const vcl_vector< vgl_homg_point_3d<double> >& world_pts,
00055 vpgl_proj_camera<double>& camera )
00056 {
00057 unsigned int num_correspondences = image_pts.size();
00058 if ( world_pts.size() < num_correspondences ) num_correspondences = world_pts.size();
00059 assert( num_correspondences >= 6 );
00060
00061
00062 vnl_matrix<double> S( 2*num_correspondences, 12, 0);
00063 for ( unsigned i = 0; i < num_correspondences; ++i ) {
00064 S(2*i,0) = -image_pts[i].w()*world_pts[i].x();
00065 S(2*i,1) = -image_pts[i].w()*world_pts[i].y();
00066 S(2*i,2) = -image_pts[i].w()*world_pts[i].z();
00067 S(2*i,3) = -image_pts[i].w()*world_pts[i].w();
00068 S(2*i,8) = image_pts[i].x()*world_pts[i].x();
00069 S(2*i,9) = image_pts[i].x()*world_pts[i].y();
00070 S(2*i,10) = image_pts[i].x()*world_pts[i].z();
00071 S(2*i,11) = image_pts[i].x()*world_pts[i].w();
00072 S(2*i+1,4) = -image_pts[i].w()*world_pts[i].x();
00073 S(2*i+1,5) = -image_pts[i].w()*world_pts[i].y();
00074 S(2*i+1,6) = -image_pts[i].w()*world_pts[i].z();
00075
00076 S(2*i+1,7) = -image_pts[i].w()*world_pts[i].w();
00077 S(2*i+1,8) = image_pts[i].y()*world_pts[i].x();
00078 S(2*i+1,9) = image_pts[i].y()*world_pts[i].y();
00079 S(2*i+1,10) = image_pts[i].y()*world_pts[i].z();
00080 S(2*i+1,11) = image_pts[i].y()*world_pts[i].w();
00081 }
00082 vnl_svd<double> svd( S );
00083 vnl_vector<double> c = svd.nullvector();
00084 vnl_matrix_fixed<double,3,4> cm;
00085 cm(0,0)=c(0); cm(0,1)=c(1); cm(0,2)=c(2); cm(0,3)=c(3);
00086 cm(1,0)=c(4); cm(1,1)=c(5); cm(1,2)=c(6); cm(1,3)=c(7);
00087 cm(2,0)=c(8); cm(2,1)=c(9); cm(2,2)=c(10); cm(2,3)=c(11);
00088 camera = vpgl_proj_camera<double>( cm );
00089 return true;
00090 }
00091
00092
00093
00094 bool
00095 vpgl_affine_camera_compute::compute(
00096 const vcl_vector< vgl_point_2d<double> >& image_pts,
00097 const vcl_vector< vgl_point_3d<double> >& world_pts,
00098 vpgl_affine_camera<double>& camera )
00099 {
00100 assert( image_pts.size() == world_pts.size() );
00101 assert( image_pts.size() > 3 );
00102
00103
00104 vnl_matrix<double> A( world_pts.size(), 4, 1 );
00105 for (unsigned int i = 0; i < world_pts.size(); ++i) {
00106 A(i,0) = world_pts[i].x(); A(i,1) = world_pts[i].y(); A(i,2) = world_pts[i].z();
00107 }
00108 vnl_vector<double> b1( image_pts.size() );
00109 vnl_vector<double> b2( image_pts.size() );
00110 for (unsigned int i = 0; i < image_pts.size(); ++i) {
00111 b1(i) = image_pts[i].x(); b2(i) = image_pts[i].y();
00112 }
00113 vnl_matrix<double> AtA = A.transpose()*A;
00114 vnl_svd<double> svd(AtA);
00115 if ( svd.rank() < 4 ) {
00116 vcl_cerr << "vpgl_affine_camera_compute:compute() cannot compute,\n"
00117 << " input data has insufficient rank.\n";
00118 return false;
00119 }
00120 vnl_matrix<double> S = svd.inverse()*A.transpose();
00121 vnl_vector_fixed<double,4> x1, x2;
00122 x1 = S*b1;
00123 x2 = S*b2;
00124
00125
00126 camera.set_rows( x1, x2 );
00127 return true;
00128 }
00129
00130
00131
00132
00133
00134 bool vpgl_perspective_camera_compute::
00135 compute( const vcl_vector< vgl_point_2d<double> >& image_pts,
00136 const vcl_vector< vgl_point_3d<double> >& world_pts,
00137 const vpgl_calibration_matrix<double>& K,
00138 vpgl_perspective_camera<double>& camera )
00139 {
00140 unsigned N = world_pts.size();
00141 if (image_pts.size()!=N)
00142 {
00143 vcl_cout << "Unequal points sets in"
00144 << " vpgl_perspective_camera_compute::compute()\n";
00145 return false;
00146 }
00147 if (N<6)
00148 {
00149 vcl_cout << "Need at least 6 points for"
00150 << " vpgl_perspective_camera_compute::compute()\n";
00151 return false;
00152 }
00153
00154
00155 vnl_matrix_fixed<double, 3, 3> km = K.get_matrix();
00156 vnl_matrix_fixed<double, 3, 3> k_inv = vnl_inverse<double>(km);
00157
00158
00159
00160
00161 vnl_matrix<double> wp(4, N);
00162 for (unsigned c = 0; c<N; ++c)
00163 {
00164 vgl_point_3d<double> p = world_pts[c];
00165 wp[0][c] = p.x(); wp[1][c] = p.y(); wp[2][c] = p.z();
00166 wp[3][c] = 1.0;
00167 }
00168 #ifdef CAMERA_DEBUG
00169 vcl_cout << "World Points\n" << wp << '\n';
00170 #endif
00171 vnl_svd<double> svd(wp);
00172 unsigned rank = svd.rank();
00173 if (rank != 4)
00174 {
00175 vcl_cout << "Insufficient rank for world point"
00176 << " matrix in vpgl_perspective_camera_compute::compute()\n";
00177 return false;
00178 }
00179
00180 vnl_matrix<double> V = svd.V();
00181 unsigned nr = V.rows(), nc = V.columns();
00182 vnl_matrix<double> null_space(nr, nc-4);
00183 for (unsigned c = 4; c<nc; ++c)
00184 for (unsigned r = 0; r<nr; ++r)
00185 null_space[r][c-4] = V[r][c];
00186 #ifdef CAMERA_DEBUG
00187 vcl_cout << "Null Space\n" << null_space << '\n';
00188 #endif
00189
00190 unsigned nrk = 3*(nc-4), nck = 3*nr;
00191 vnl_matrix<double> v2k(nrk, nck);
00192 for (unsigned r = 0; r<(nc-4); ++r)
00193 for (unsigned c = 0; c<nr; ++c)
00194 for (unsigned rk = 0; rk<3; ++rk)
00195 for (unsigned ck = 0; ck<3; ++ck)
00196 v2k[rk+3*r][ck+3*c] = k_inv[rk][ck]*null_space[c][r];
00197 #ifdef CAMERA_DEBUG
00198 vcl_cout << "V2K\n" << v2k << '\n';
00199 #endif
00200
00201 vnl_matrix<double> D(3*N, N);
00202 D.fill(0);
00203 for (unsigned c = 0; c<N; ++c)
00204 {
00205 vgl_point_2d<double> p = image_pts[c];
00206 D[3*c][c] = p.x(); D[3*c+1][c] = p.y(); D[3*c+2][c] = 1.0;
00207 }
00208 #ifdef CAMERA_DEBUG
00209 vcl_cout << "D\n" << D << '\n';
00210 #endif
00211
00212 vnl_matrix<double> M = v2k*D;
00213 vnl_svd<double> svdm(M);
00214
00215
00216 vnl_vector<double> depth = svdm.nullvector();
00217
00218 #ifdef CAMERA_DEBUG
00219 vcl_cout << "depths\n" << depth << '\n';
00220 #endif
00221
00222
00223 double average_depth = 0;
00224 unsigned nd = depth.size();
00225 for (unsigned i = 0; i<nd; ++i)
00226 average_depth += depth[i];
00227 average_depth /= nd;
00228 double max_dev = 0;
00229 for (unsigned i = 0; i<nd; ++i)
00230 {
00231 double dev = vcl_fabs(depth[i]-average_depth);
00232 if (dev>max_dev)
00233 max_dev = dev;
00234 }
00235 double norm_max_dev = max_dev/average_depth;
00236
00237
00238 if (norm_max_dev < 0.01)
00239 for (unsigned i = 0; i<nd; ++i)
00240 depth[i]=vcl_fabs(average_depth);
00241
00242
00243 vnl_matrix<double> X(3,N), Y(3,N);
00244 for (unsigned c = 0; c<N; ++c)
00245 {
00246 vgl_point_2d<double> pi = image_pts[c];
00247 vgl_point_3d<double> pw = world_pts[c];
00248
00249 X[0][c] = pi.x()*depth[c]; X[1][c] = pi.y()*depth[c]; X[2][c] = depth[c];
00250
00251 Y[0][c] = pw.x(); Y[1][c] = pw.y(); Y[2][c] = pw.z();
00252 }
00253
00254 vpgl_ortho_procrustes op(X, Y);
00255 if (!op.compute_ok())
00256 return false;
00257
00258 vgl_rotation_3d<double> R = op.R();
00259 vnl_matrix_fixed<double, 3, 3> rr = R.as_matrix();
00260
00261 vnl_vector_fixed<double, 3> t = op.t();
00262 #ifdef CAMERA_DEBUG
00263 vcl_cout << "translation\n" << t << '\n'
00264 << "scale = " << op.s() << '\n'
00265 << "residual = " << op.residual_mean_sq_error() << '\n';
00266 #endif
00267
00268 vnl_vector_fixed<double, 3> center = -(rr.transpose())*t;
00269 vgl_point_3d<double> vgl_center(center[0],center[1],center[2]);
00270 vpgl_perspective_camera<double> tcam;
00271 tcam.set_calibration(K);
00272 tcam.set_camera_center(vgl_center);
00273 tcam.set_rotation(R);
00274
00275
00276 vcl_vector<vgl_homg_point_3d<double> > h_world_pts;
00277 for (unsigned i = 0; i<N; ++i)
00278 h_world_pts.push_back(vgl_homg_point_3d<double>(world_pts[i]));
00279 camera = vpgl_optimize_camera::opt_orient_pos_cal(tcam, h_world_pts, image_pts, 0.00005, 20000);
00280 return true;
00281 }
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293 bool vpgl_perspective_camera_compute::
00294 compute_dlt (const vcl_vector< vgl_point_2d<double> >& image_pts,
00295 const vcl_vector< vgl_point_3d<double> >& world_pts,
00296 vpgl_perspective_camera<double> &camera,
00297 double &err)
00298 {
00299 if (image_pts.size() < 6) {
00300 vcl_cout<<"vpgl_perspective_camera_compute::compute needs at"
00301 << " least 6 points!" << vcl_endl;
00302 return false;
00303 }
00304 else if (image_pts.size() != world_pts.size()) {
00305 vcl_cout<<"vpgl_perspective_camera_compute::compute needs to"
00306 << " have input vectors of the same size!" << vcl_endl
00307 << "Currently, image_pts is size " << image_pts.size()
00308 << " and world_pts is size " << world_pts.size() << vcl_endl;
00309 return false;
00310 }
00311 else
00312 {
00313
00314
00315 int num_eqns = 2 * image_pts.size();
00316
00317
00318 int num_vars = 11;
00319
00320
00321 vnl_matrix<double> A(num_eqns, num_vars);
00322 vnl_vector<double> b(num_eqns);
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332 for (unsigned int i = 0; i < image_pts.size(); ++i)
00333 {
00334
00335 A.put(2*i, 0, world_pts[i].x());
00336 A.put(2*i, 1, world_pts[i].y());
00337 A.put(2*i, 2, world_pts[i].z());
00338 A.put(2*i, 3, 1.0);
00339
00340 A.put(2*i, 4, 0.0);
00341 A.put(2*i, 5, 0.0);
00342 A.put(2*i, 6, 0.0);
00343 A.put(2*i, 7, 0.0);
00344
00345 A.put(2*i, 8, -image_pts[i].x() * world_pts[i].x());
00346 A.put(2*i, 9, -image_pts[i].x() * world_pts[i].y());
00347 A.put(2*i, 10, -image_pts[i].x() * world_pts[i].z());
00348
00349
00350 A.put(2*i+1, 0, 0.0);
00351 A.put(2*i+1, 1, 0.0);
00352 A.put(2*i+1, 2, 0.0);
00353 A.put(2*i+1, 3, 0.0);
00354
00355 A.put(2*i+1, 4, world_pts[i].x());
00356 A.put(2*i+1, 5, world_pts[i].y());
00357 A.put(2*i+1, 6, world_pts[i].z());
00358 A.put(2*i+1, 7, 1.0);
00359
00360 A.put(2*i+1, 8, -image_pts[i].y() * world_pts[i].x());
00361 A.put(2*i+1, 9, -image_pts[i].y() * world_pts[i].y());
00362 A.put(2*i+1, 10, -image_pts[i].y() * world_pts[i].z());
00363
00364
00365 b[2 * i] = image_pts[i].x();
00366 b[2 * i + 1] = image_pts[i].y();
00367 }
00368
00369
00370 vnl_svd<double> svd(A);
00371 vnl_vector<double> x = svd.solve(b);
00372
00373
00374 vnl_matrix_fixed<double, 3, 4> proj;
00375
00376 for (int row = 0; row < 3; row++) {
00377 for (int col = 0; col < 4; col++) {
00378 if (row*4 + col < 11) {
00379 proj.put(row, col, x[row*4 + col]);
00380 }
00381 }
00382 }
00383
00384 proj.set(2, 3, 1.0);
00385
00386
00387 err = 0;
00388 for (unsigned int i = 0; i < image_pts.size(); ++i) {
00389 vnl_vector_fixed<double, 4> world_pt;
00390 world_pt[0] = world_pts[i].x();
00391 world_pt[1] = world_pts[i].y();
00392 world_pt[2] = world_pts[i].z();
00393 world_pt[3] = 1.0;
00394
00395 vnl_vector_fixed<double, 3> projed_pt = proj * world_pt;
00396
00397 projed_pt[0] /= projed_pt[2];
00398 projed_pt[1] /= projed_pt[2];
00399
00400 double dx = projed_pt[0] - image_pts[i].x();
00401 double dy = projed_pt[1] - image_pts[i].y();
00402
00403 err += dx*dy;
00404 }
00405
00406
00407 return vpgl_perspective_decomposition(proj, camera);
00408 }
00409 }
00410
00411
00412
00413
00414
00415
00416 bool vpgl_perspective_camera_compute::
00417 compute( const vcl_vector< vgl_point_2d<double> >& image_pts,
00418 const vcl_vector< vgl_point_2d<double> >& ground_pts,
00419 vpgl_perspective_camera<double>& camera )
00420 {
00421 unsigned num_pts = ground_pts.size();
00422 if (image_pts.size()!=num_pts)
00423 {
00424 vcl_cout << "Unequal points sets in"
00425 << " vpgl_perspective_camera_compute::compute()\n";
00426 return false;
00427 }
00428 if (num_pts<4)
00429 {
00430 vcl_cout << "Need at least 4 points for"
00431 << " vpgl_perspective_camera_compute::compute()\n";
00432 return false;
00433 }
00434
00435 vcl_vector<vgl_homg_point_2d<double> > pi, pg;
00436 for (unsigned i=0; i<num_pts; ++i) {
00437 #ifdef CAMERA_DEBUG
00438 vcl_cout << '('<<image_pts[i].x()<<", "<<image_pts[i].y()<<") -> "
00439 << '('<<ground_pts[i].x()<<", "<<ground_pts[i].y()<<')'<<vcl_endl;
00440 #endif
00441 pi.push_back(vgl_homg_point_2d<double>(image_pts[i].x(),image_pts[i].y()));
00442 pg.push_back(vgl_homg_point_2d<double>(ground_pts[i].x(),ground_pts[i].y()));
00443 }
00444
00445
00446 vgl_h_matrix_2d_compute_linear est_H;
00447 vnl_double_3x3 H = est_H.compute(pg,pi).get_matrix();
00448 if (vnl_det(H) > 0)
00449 H *= -1.0;
00450
00451
00452 vnl_double_3x3 Kinv = vnl_inverse(camera.get_calibration().get_matrix());
00453 vnl_double_3x3 A(Kinv*H);
00454
00455 vnl_vector_fixed<double,3> t = A.get_column(2);
00456 t.normalize();
00457
00458
00459 A.set_column(2, vnl_cross_3d(A.get_column(0), A.get_column(1)));
00460 vnl_svd<double> svdA(A.as_ref());
00461 vnl_double_3x3 R = svdA.U()*svdA.V().conjugate_transpose();
00462
00463
00464 int max_idx = 0;
00465 double max_dist = 0.0;
00466 for (unsigned int i=0; i < ground_pts.size(); ++i) {
00467 double d = (ground_pts[i]-vgl_point_2d<double>(0,0)).length();
00468 if (d >= max_dist) {
00469 max_dist = d;
00470 max_idx = i;
00471 }
00472 }
00473
00474
00475 vnl_vector_fixed<double,3> i1 = Kinv*vnl_double_3(image_pts[max_idx].x(),image_pts[max_idx].y(),1.0);
00476 vnl_vector_fixed<double,3> t1 = vnl_cross_3d(i1, t);
00477 vnl_vector_fixed<double,3> p1 = vnl_cross_3d(i1, R*vnl_double_3(ground_pts[max_idx].x(),ground_pts[max_idx].y(),1.0));
00478 double s = p1.magnitude()/t1.magnitude();
00479
00480
00481 t *= s;
00482 t = -R.transpose()*t;
00483
00484 camera.set_rotation(vgl_rotation_3d<double>(R));
00485 camera.set_camera_center(vgl_point_3d<double>(t[0],t[1],t[2]));
00486
00487
00488 vcl_vector<vgl_homg_point_3d<double> > h_world_pts;
00489 for (unsigned i = 0; i<num_pts; ++i) {
00490 h_world_pts.push_back(vgl_homg_point_3d<double>(ground_pts[i].x(),ground_pts[i].y(),0,1));
00491 if (camera.is_behind_camera(h_world_pts.back())) {
00492 vcl_cout << "behind camera" << vcl_endl;
00493 return false;
00494 }
00495 }
00496 camera = vpgl_optimize_camera::opt_orient_pos(camera, h_world_pts, image_pts);
00497
00498 return true;
00499 }
00500
00501 #endif // vpgl_camera_compute_cxx_