Go to the documentation of this file.00001
00002 #include "vpgl_construct_cameras.h"
00003
00004
00005
00006 #include <vcl_cmath.h>
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
00018 vpgl_construct_cameras::vpgl_construct_cameras()
00019 {
00020 }
00021
00022
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
00048
00049
00050
00051
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);
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
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
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
00111 for ( int c = 0; c < 4; c++ )
00112 {
00113 vnl_double_3x3 R;
00114 vnl_vector<double> t;
00115 if ( c == 0 ) {
00116 R=U*W.transpose()*V.transpose();
00117 t=U.get_column(2);
00118 }
00119 if ( c == 1 ) {
00120 R=U*W*V.transpose();
00121 t=U.get_column(2);
00122 }
00123 if ( c == 2 ) {
00124 R=U*W.transpose()*V.transpose();
00125 t=-U.get_column(2);
00126 }
00127 if ( c == 3 ) {
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 }