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