contrib/gel/mrc/vpgl/algo/vpgl_construct_cameras.cxx
Go to the documentation of this file.
00001 // This is gel/mrc/vpgl/algo/vpgl_construct_cameras.cxx
00002 #include "vpgl_construct_cameras.h"
00003 //:
00004 // \file
00005 
00006 #include <vcl_cmath.h> // for std::abs
00007 #include <vnl/vnl_inverse.h>
00008 #include <vnl/vnl_vector.h>
00009 #include <vnl/vnl_double_4.h>
00010 #include <vnl/algo/vnl_svd.h>
00011 #include <vgl/vgl_homg_point_2d.h>
00012 #include <vgl/vgl_homg_point_3d.h>
00013 #include <vgl/algo/vgl_rotation_3d.h>
00014 #include <vpgl/vpgl_fundamental_matrix.h>
00015 #include <vpgl/algo/vpgl_fm_compute_8_point.h>
00016 
00017 //: constructor
00018 vpgl_construct_cameras::vpgl_construct_cameras()
00019 {
00020 }
00021 
00022 //: constructor with initialization of corresponding points
00023 vpgl_construct_cameras::vpgl_construct_cameras(
00024     vcl_vector<vgl_point_2d<double> > p0,
00025     vcl_vector<vgl_point_2d<double> > p1,
00026     const vpgl_calibration_matrix<double>* K )
00027 {
00028     points0_=p0;
00029     points1_=p1;
00030 
00031     if ( p0.size() < 8 )
00032       vcl_cerr << "ERROR: vpgl_construct_cameras: need at least 7 correspondences.\n";
00033 
00034     if ( K == NULL ) {
00035       K_[0][0]=2000;K_[0][1]=0;K_[0][2]=512;
00036       K_[1][0]=0;K_[1][1]=2000;K_[1][2]=384;
00037       K_[2][0]=0;K_[2][1]=0;K_[2][2]=1;
00038     }
00039     else
00040       K_ = K->get_matrix();
00041 }
00042 
00043 vpgl_construct_cameras::~vpgl_construct_cameras()
00044 {
00045 }
00046 
00047 //: To construct the cameras according to the correspondence given
00048 //
00049 // - Computes fundamental matrix F using least squares solution (no RANSAC)
00050 // - Computes essential matrix E from F and supplied calibration matrix K
00051 // - Computes the camera pose such that all points are in front of the camera
00052 bool vpgl_construct_cameras::construct()
00053 {
00054     vcl_vector<vgl_homg_point_2d<double> > p0,p1;
00055 
00056     for (unsigned int i=0;i<points0_.size();i++)
00057     {
00058       vgl_homg_point_2d<double> p(points0_[i]);
00059       p0.push_back(p);
00060     }
00061     for (unsigned int i=0;i<points1_.size();i++)
00062     {
00063       vgl_homg_point_2d<double> p(points1_[i]);
00064       p1.push_back(p);
00065     }
00066 
00067     vpgl_fundamental_matrix<double> fm;
00068     vpgl_fm_compute_8_point fmcomp(false); // Set preconditioning false, otherwise breaks!!
00069     fmcomp.compute( p0, p1, fm );
00070 
00071     double fm_error = 0;
00072     for ( unsigned int i = 0; i < p0.size(); ++i ) {
00073       vnl_vector<double> pt0(3), pt1(3);
00074       pt0(0) = p0[i].x(); pt0(1) = p0[i].y(); pt0(2) = 1;
00075       pt1(0) = p1[i].x(); pt1(1) = p1[i].y(); pt1(2) = 1;
00076       vnl_vector<double> m = fm.get_matrix()*pt0;
00077       fm_error += vcl_abs( pt1(0)*m(0)+pt1(1)*m(1)+pt1(2)*m(2) );
00078     }
00079     if ( fm_error > .2 ) {
00080       vcl_cerr << "\nWARNING: vpgl_construct_cameras: fundamental matrix error is " <<
00081         fm_error << '\n';
00082     }
00083 
00084     vnl_double_3x3  Kt,Kinv;
00085     Kt=K_.transpose();
00086     Kinv=vnl_inverse(K_);
00087 
00088     //: computing the essential matrix
00089     E_=Kt*fm.get_matrix()*K_;
00090     vnl_double_3x3 U, V, W;
00091 
00092     W[0][0]=0;W[0][1]=-1;W[0][2]=0;
00093     W[1][0]=1;W[1][1]=0;W[1][2]=0;
00094     W[2][0]=0;W[2][1]=0;W[2][2]=1;
00095 
00096     vnl_svd<double> SVD(E_);
00097     U=SVD.U();
00098     V=SVD.V();
00099 
00100     // Get some image points to test possible cameras on.
00101     vnl_vector<double> point2d1(3);    vnl_vector<double> point2d2(3);
00102     point2d1[0]=points0_[0].x();       point2d2[0]=points1_[0].x();
00103     point2d1[1]=points0_[0].y();       point2d2[1]=points1_[0].y();
00104     point2d1[2]=1;                     point2d2[2]=1;
00105     point2d1=Kinv*point2d1;
00106     point2d2=Kinv*point2d2;
00107     vgl_point_2d<double> pnorm1(point2d1[0]/point2d1[2],point2d1[1]/point2d1[2]);
00108     vgl_point_2d<double> pnorm2(point2d2[0]/point2d2[2],point2d2[1]/point2d2[2]);
00109 
00110     // checking for the correct combination of cameras
00111     for ( int c = 0; c < 4; c++ )
00112     {
00113       vnl_double_3x3 R;
00114       vnl_vector<double> t;
00115       if ( c == 0 ) { //case 1
00116         R=U*W.transpose()*V.transpose();
00117         t=U.get_column(2);
00118       }
00119       if ( c == 1 ) { //case 2
00120         R=U*W*V.transpose();
00121         t=U.get_column(2);
00122       }
00123       if ( c == 2 ) { //case 3
00124         R=U*W.transpose()*V.transpose();
00125         t=-U.get_column(2);
00126       }
00127       if ( c == 3 ) { //case 4
00128         R=U*W*V.transpose();
00129         t=-U.get_column(2);
00130       }
00131       if ( vnl_det<double>( R ) < 0 ) R = -R;
00132       vnl_vector<double> cc = -R.transpose()*t;
00133       P2_.set_rotation( vgl_rotation_3d<double>(R) );
00134       P2_.set_camera_center( vgl_point_3d<double>( cc(0), cc(1), cc(2) ) );
00135       vgl_point_3d<double> p3d = triangulate_3d_point(
00136         pnorm1, P1_.get_matrix(), pnorm2, P2_.get_matrix() );
00137       vgl_homg_point_3d<double> ph3d(p3d);
00138       if (!P1_.is_behind_camera(ph3d) && !P2_.is_behind_camera(ph3d))
00139         break;
00140       if ( c == 3 ) {
00141         vcl_cerr << "ERROR: vpgl_construct_cameras failed.\n";
00142         return false;
00143       }
00144     }
00145 
00146     P1_.set_calibration( K_ );
00147     P2_.set_calibration( K_ );
00148     return true;
00149 }
00150 
00151 
00152 void
00153 vpgl_construct_cameras::get_world_points(
00154   vcl_vector< vgl_point_3d<double> >& world_points )
00155 {
00156   world_points.clear();
00157   for ( unsigned int p = 0; p < points0_.size(); ++p ) {
00158     world_points.push_back( triangulate_3d_point(
00159       points0_[p], P1_.get_matrix(), points1_[p], P2_.get_matrix() ) );
00160   }
00161 }
00162 
00163 
00164 vgl_point_3d<double>
00165 vpgl_construct_cameras::triangulate_3d_point(
00166   const vgl_point_2d<double>& x1,
00167   const vnl_double_3x4& P1,
00168   const vgl_point_2d<double>& x2,
00169   const vnl_double_3x4& P2 )
00170 {
00171   vnl_double_4x4 A;
00172 
00173   for (int i=0; i<4; i++) {
00174     A[0][i] = x1.x()*P1[2][i] - P1[0][i];
00175     A[1][i] = x1.y()*P1[2][i] - P1[1][i];
00176     A[2][i] = x2.x()*P2[2][i] - P2[0][i];
00177     A[3][i] = x2.y()*P2[2][i] - P2[1][i];
00178   }
00179 
00180   vnl_svd<double> svd_solver(A);
00181   vnl_double_4 p = svd_solver.nullvector();
00182   return vgl_homg_point_3d<double>(p[0],p[1],p[2],p[3]);
00183 }