core/vpgl/vpgl_fundamental_matrix.txx
Go to the documentation of this file.
00001 // This is core/vpgl/vpgl_fundamental_matrix.txx
00002 #ifndef vpgl_fundamental_matrix_txx_
00003 #define vpgl_fundamental_matrix_txx_
00004 //:
00005 // \file
00006 
00007 #include "vpgl_fundamental_matrix.h"
00008 #include "vpgl_essential_matrix.h"
00009 #include "vpgl_calibration_matrix.h"
00010 
00011 //
00012 #include <vnl/vnl_vector_fixed.h>
00013 #include <vnl/vnl_matrix_fixed.h>
00014 #include <vnl/vnl_cross_product_matrix.h>
00015 #include <vnl/vnl_inverse.h>
00016 //#include <vnl/io/vnl_io_matrix_fixed.h>
00017 #include <vnl/algo/vnl_svd.h>
00018 #include <vnl/vnl_vector.h>
00019 #include <vgl/vgl_point_2d.h>
00020 #include <vgl/vgl_point_3d.h>
00021 #include <vgl/vgl_homg_point_2d.h>
00022 #include <vgl/vgl_homg_line_2d.h>
00023 #include <vgl/algo/vgl_homg_operators_2d.h>
00024 #include <vcl_iosfwd.h>
00025 #include <vcl_cassert.h>
00026 
00027 
00028 //---------------------------------
00029 template <class T>
00030 vpgl_fundamental_matrix<T>::vpgl_fundamental_matrix()
00031   : cached_svd_(NULL)
00032 {
00033   vnl_matrix_fixed<T,3,3> default_matrix( (T)0 );
00034   default_matrix(0,0) = default_matrix(1,1) = (T)1;
00035   set_matrix( default_matrix );
00036 }
00037 
00038 //---------------------------------
00039 //: Copy Constructor
00040 template <class T>
00041 vpgl_fundamental_matrix<T>::vpgl_fundamental_matrix(
00042   const vpgl_fundamental_matrix<T>& other)
00043   : cached_svd_(NULL)
00044 {
00045   set_matrix( other.F_ );
00046 }
00047 
00048 //---------------------------------
00049 //: From Essential Matrix.
00050 //  Since $E = Kl^T \times F \times Kr$, $F = Kl^{-T} \times E \times Kr^{-1}$
00051 template <class T>
00052 vpgl_fundamental_matrix<T>::vpgl_fundamental_matrix(
00053     const vpgl_calibration_matrix<T> &kr,
00054     const vpgl_calibration_matrix<T> &kl,
00055     const vpgl_essential_matrix<T>   &em)
00056   : cached_svd_(NULL)
00057 {
00058   vnl_matrix_fixed<T, 3, 3> kl_tinv = vnl_inverse(kl.get_matrix().transpose());
00059   vnl_matrix_fixed<T, 3, 3> kr_inv = vnl_inverse(kr.get_matrix());
00060   this->set_matrix(kl_tinv * em.get_matrix() * kr_inv);
00061 }
00062 
00063 
00064 //---------------------------------
00065 template <class T>
00066 const vpgl_fundamental_matrix<T>&
00067 vpgl_fundamental_matrix<T>::operator=( const vpgl_fundamental_matrix<T>& fm )
00068 {
00069   set_matrix( fm.F_ );
00070   return *this;
00071 }
00072 
00073 
00074 //---------------------------------
00075 //: Destructor
00076 template <class T>
00077 vpgl_fundamental_matrix<T>::~vpgl_fundamental_matrix()
00078 {
00079   delete cached_svd_;
00080 }
00081 
00082 
00083 //---------------------------------
00084 template <class T>
00085 void vpgl_fundamental_matrix<T>::get_epipoles( vgl_homg_point_2d<T>& er,
00086                                                vgl_homg_point_2d<T>& el ) const
00087 {
00088   vnl_vector_fixed<T,3> v = cached_svd_->nullvector();
00089   er.set( v[0], v[1], v[2] );
00090   v = cached_svd_->left_nullvector();
00091   el.set( v[0], v[1], v[2] );
00092 }
00093 
00094 
00095 //---------------------------------
00096 template <class T>
00097 vgl_homg_line_2d<T> vpgl_fundamental_matrix<T>::r_epipolar_line(
00098   const vgl_homg_point_2d<T>& pl ) const
00099 {
00100   vnl_vector_fixed<T,3> lr = F_.transpose() *
00101     vnl_vector_fixed<T,3>( pl.x(), pl.y(), pl.w() );
00102   return vgl_homg_line_2d<T>( lr(0), lr(1), lr(2) );
00103 }
00104 
00105 
00106 //---------------------------------
00107 template <class T>
00108 vgl_homg_line_2d<T> vpgl_fundamental_matrix<T>::l_epipolar_line(
00109   const vgl_homg_point_2d<T>& pr ) const
00110 {
00111   vnl_vector_fixed<T,3> ll =
00112     F_ * vnl_vector_fixed<T,3>( pr.x(), pr.y(), pr.w() );
00113   return vgl_homg_line_2d<T>( ll(0), ll(1), ll(2) );
00114 }
00115 
00116 
00117 //---------------------------------
00118 template <class T>
00119 vgl_homg_line_2d<T> vpgl_fundamental_matrix<T>::r_epipolar_line(
00120     const vgl_homg_line_2d<T> &epiline_l) const
00121 {
00122   vgl_homg_point_2d<T> er, el;
00123 
00124   get_epipoles(er, el);
00125 
00126   vgl_homg_line_2d<T> el_as_line(el.x(), el.y(), el.w());
00127 
00128   vnl_vector_fixed<T,3> epiline_r =
00129     get_matrix().transpose() *
00130     vgl_homg_operators_2d<T>::get_vector(
00131         vgl_homg_operators_2d<T>::intersection( el_as_line , epiline_l));
00132 
00133   return vgl_homg_line_2d<T>(epiline_r[0], epiline_r[1], epiline_r[2]);
00134 }
00135 
00136 
00137 //---------------------------------
00138 template <class T>
00139 vgl_homg_line_2d<T> vpgl_fundamental_matrix<T>::l_epipolar_line(
00140     const vgl_homg_line_2d<T> &epiline_r) const
00141 {
00142   vgl_homg_point_2d<T> er, el;
00143 
00144   get_epipoles(er, el);
00145 
00146   vgl_homg_line_2d<T> er_as_line(er.x(), er.y(), er.w());
00147 
00148   vnl_vector_fixed<T,3> epiline_l =
00149     get_matrix() *
00150     vgl_homg_operators_2d<T>::get_vector(
00151         vgl_homg_operators_2d<T>::intersection( er_as_line , epiline_r));
00152 
00153   return vgl_homg_line_2d<T>(epiline_l[0], epiline_l[1], epiline_l[2]);
00154 }
00155 
00156 
00157 //---------------------------------
00158 template <class T>
00159 vpgl_proj_camera<T> vpgl_fundamental_matrix<T>::extract_left_camera(
00160   const vnl_vector_fixed<T,3>& v, T lambda ) const
00161 {
00162   vgl_homg_point_2d<T> er, el;
00163   get_epipoles( er, el );
00164   vnl_matrix_fixed<T,3,3> elx((T)0);
00165   elx.put( 0, 1, -el.w() ); elx.put( 0, 2, el.y() );
00166   elx.put( 1, 0, el.w() ); elx.put( 1, 2, -el.x() );
00167   elx.put( 2, 0, -el.y() ); elx.put( 2, 1, el.x() );
00168 
00169   vnl_matrix_fixed<T,3,3> elvt;
00170   elvt(0,0) = el.x()*v[0]; elvt(1,0) = el.y()*v[0]; elvt(2,0) = el.w()*v[0];
00171   elvt(0,1) = el.x()*v[1]; elvt(1,1) = el.y()*v[1]; elvt(2,1) = el.w()*v[1];
00172   elvt(0,2) = el.x()*v[2]; elvt(1,2) = el.y()*v[2]; elvt(2,2) = el.w()*v[2];
00173 
00174   vnl_matrix_fixed<T,3,4> P;
00175   P.set_columns( 0, (elx*F_+elvt).as_ref() ); // size 3x3
00176   P.set_column( 3, vnl_vector_fixed<T,3>( lambda*el.x(), lambda*el.y(), lambda*el.w() ) );
00177   return P;
00178 }
00179 
00180 
00181 
00182 //--------------------------------
00183 template <class T>
00184 vpgl_proj_camera<T> vpgl_fundamental_matrix<T>::extract_left_camera(
00185     const vcl_vector< vgl_point_3d<T> >& world_points,
00186     const vcl_vector< vgl_point_2d<T> >& image_points ) const
00187 {
00188   assert( world_points.size() == image_points.size() );
00189   assert( world_points.size() >= 2 );
00190 
00191   vgl_homg_point_2d<T> er, el;
00192   get_epipoles( er, el );
00193   vnl_matrix_fixed<T,3,3> elxF((T)0);
00194   elxF.put( 0, 1, -el.w() ); elxF.put( 0, 2, el.y() );
00195   elxF.put( 1, 0, el.w() ); elxF.put( 1, 2, -el.x() );
00196   elxF.put( 2, 0, -el.y() ); elxF.put( 2, 1, el.x() );
00197   elxF*=F_;
00198 
00199   vnl_matrix<T> A( 3*image_points.size(), 4 );
00200   vnl_vector<T> y( 3*image_points.size() );
00201   for ( unsigned p = 0; p < image_points.size(); p++ ) {
00202     vnl_vector_fixed<T,3> wp_vnl(
00203       world_points[p].x(), world_points[p].y(), world_points[p].z() );
00204     vnl_vector_fixed<T,3> ip_vnl(
00205       image_points[p].x(), image_points[p].y(), (T)1 );
00206     vnl_vector_fixed<T,3> yp = ip_vnl - elxF * wp_vnl;
00207     T ei;
00208     for ( unsigned i = 0; i < 3; i++ ) {
00209       y(3*p+i) = yp(i);
00210       if ( i == 0 ) ei = el.x(); else if ( i == 1 ) ei = el.y(); else ei = el.w();
00211       A(3*p+i,0) = ei*wp_vnl[0]; A(3*p+i,1) = ei*wp_vnl[1]; A(3*p+i,2) = ei*wp_vnl[2];
00212       A(3*p+i,3) = ei;
00213     }
00214   }
00215 
00216   // Do least squares estimation of y=Ax
00217   vnl_vector<T> x = vnl_svd<T>(A).solve(y);
00218   vnl_vector_fixed<T,3> v( x(0), x(1), x(2) );
00219   T lambda = x(3);
00220   return extract_left_camera( v, lambda );
00221 }
00222 
00223 //---------------------------------
00224 template <class T>
00225 void vpgl_fundamental_matrix<T>::set_matrix( const vpgl_proj_camera<T>& cr,
00226                                              const vpgl_proj_camera<T>& cl )
00227 {
00228   vnl_vector_fixed<T, 4> nv = cr.svd()->nullvector();
00229   vnl_matrix_fixed<T, 3, 4> m = cl.get_matrix();
00230   vnl_vector_fixed<T, 3> nvt =  m * nv;
00231   vnl_vector_fixed<double, 3> nvtd;
00232   // unfortunately, vnl_cross_product_matrix is only defined for double
00233   for (unsigned i = 0; i<3; ++i)
00234     nvtd[i] = static_cast<double>(nvt[i]);
00235   vnl_cross_product_matrix e2x( nvtd );
00236   vnl_matrix_fixed<T, 3, 3> e2xt;
00237    for (unsigned r = 0; r<3; ++r)
00238     for (unsigned c = 0; c<3; ++c)
00239       e2xt[r][c] = static_cast<T>(e2x[r][c]);
00240    vnl_matrix_fixed<T, 3, 3> temp = e2xt * (cl.get_matrix() * cr.svd()->inverse());
00241    set_matrix( temp );
00242 }
00243 
00244 
00245 //---------------------------------
00246 template <class T>
00247 void vpgl_fundamental_matrix<T>::set_matrix( const vnl_matrix_fixed<T,3,3>& F )
00248 {
00249   F_ = vnl_svd<T>( F.as_ref() ).recompose(2);
00250   if ( cached_svd_ != NULL ) delete cached_svd_;
00251   cached_svd_ = new vnl_svd<T>( F_.as_ref() );
00252 }
00253 
00254 //: write vpgl_fundamental_matrix to stream
00255 template <class T>
00256 vcl_ostream&  operator<<(vcl_ostream& s, vpgl_fundamental_matrix<T> const& p)
00257 {
00258   s << p.get_matrix();
00259   return s;
00260 }
00261 
00262 //: Read vpgl_perspective_camera from stream
00263 template <class T>
00264 vcl_istream&  operator>>(vcl_istream& s, vpgl_fundamental_matrix<T>& p)
00265 {
00266   vnl_matrix_fixed<T, 3, 3> m;
00267   s >> m;
00268   p.set_matrix(m);
00269   return s;
00270 }
00271 
00272 // Macro for easy instantiation.
00273 #undef vpgl_FUNDAMENTAL_MATRIX_INSTANTIATE
00274 #define vpgl_FUNDAMENTAL_MATRIX_INSTANTIATE(T) \
00275 template class vpgl_fundamental_matrix<T >; \
00276 template vcl_ostream& operator<<(vcl_ostream&, const vpgl_fundamental_matrix<T >&); \
00277 template vcl_istream& operator>>(vcl_istream&, vpgl_fundamental_matrix<T >&)
00278 
00279 #endif // vpgl_fundamental_matrix_txx_