00001
00002 #ifndef vpgl_proj_camera_txx_
00003 #define vpgl_proj_camera_txx_
00004
00005
00006
00007 #include "vpgl_proj_camera.h"
00008 #include <vcl_iostream.h>
00009 #include <vgl/vgl_point_2d.h>
00010 #include <vgl/vgl_point_3d.h>
00011 #include <vnl/vnl_vector_fixed.h>
00012 #include <vnl/io/vnl_io_matrix_fixed.h>
00013 #include <vsl/vsl_binary_loader.h>
00014
00015
00016
00017
00018
00019 template <class T>
00020 vpgl_proj_camera<T>::vpgl_proj_camera() :
00021 cached_svd_(NULL)
00022 {
00023 P_ = vnl_matrix_fixed<T,3,4>( (T)0 );
00024 P_(0,0) = P_(1,1) = P_(2,2) = (T)1;
00025 }
00026
00027
00028 template <class T>
00029 vpgl_proj_camera<T>::vpgl_proj_camera( const vnl_matrix_fixed<T,3,4>& camera_matrix ) :
00030 P_( camera_matrix ),
00031 cached_svd_(NULL)
00032 {
00033 }
00034
00035
00036 template <class T>
00037 vpgl_proj_camera<T>::vpgl_proj_camera( const T* camera_matrix ) :
00038 P_( camera_matrix ),
00039 cached_svd_(NULL)
00040 {
00041 }
00042
00043
00044 template <class T>
00045 vpgl_proj_camera<T>::vpgl_proj_camera( const vpgl_proj_camera& cam ) :
00046 vpgl_camera<T>(),
00047 P_( cam.get_matrix() ),
00048 cached_svd_(NULL)
00049 {
00050 }
00051
00052
00053 template <class T>
00054 const vpgl_proj_camera<T>& vpgl_proj_camera<T>::operator=( const vpgl_proj_camera& cam )
00055 {
00056 P_ = cam.get_matrix();
00057 if ( cached_svd_ != NULL ) delete cached_svd_;
00058 cached_svd_ = NULL;
00059 return *this;
00060 }
00061
00062
00063 template <class T>
00064 vpgl_proj_camera<T>::~vpgl_proj_camera()
00065 {
00066 if ( cached_svd_ != NULL ) delete cached_svd_;
00067 cached_svd_ = NULL;
00068 }
00069
00070 template <class T>
00071 vpgl_proj_camera<T>* vpgl_proj_camera<T>::clone(void) const
00072 {
00073 return new vpgl_proj_camera<T>(*this);
00074 }
00075
00076
00077
00078
00079
00080 template <class T>
00081 vgl_homg_point_2d<T> vpgl_proj_camera<T>::project( const vgl_homg_point_3d<T>& world_point ) const
00082 {
00083
00084
00085 vgl_homg_point_2d<T> image_point(
00086 P_(0,0)*world_point.x() + P_(0,1)*world_point.y() +
00087 P_(0,2)*world_point.z() + P_(0,3)*world_point.w(),
00088
00089 P_(1,0)*world_point.x() + P_(1,1)*world_point.y() +
00090 P_(1,2)*world_point.z() + P_(1,3)*world_point.w(),
00091
00092 P_(2,0)*world_point.x() + P_(2,1)*world_point.y() +
00093 P_(2,2)*world_point.z() + P_(2,3)*world_point.w() );
00094 return image_point;
00095 }
00096
00097
00098 template <class T>
00099 void
00100 vpgl_proj_camera<T>::project(const T x, const T y, const T z, T& u, T& v) const
00101 {
00102 vgl_homg_point_3d<T> world_point(x, y, z);
00103 vgl_homg_point_2d<T> image_point = this->project(world_point);
00104 if (image_point.ideal(static_cast<T>(1.0e-10)))
00105 {
00106 u = 0; v = 0;
00107 vcl_cerr << "Warning: projection to ideal image point in vpgl_proj_camera -"
00108 << " result not valid\n";
00109 return;
00110 }
00111 u = image_point.x()/image_point.w();
00112 v = image_point.y()/image_point.w();
00113 }
00114
00115
00116 template <class T>
00117 vgl_line_segment_2d<T> vpgl_proj_camera<T>::project(
00118 const vgl_line_segment_3d<T>& world_line ) const
00119 {
00120 vgl_homg_point_3d<T> point1_w( world_line.point1() );
00121 vgl_homg_point_3d<T> point2_w( world_line.point2() );
00122 vgl_point_2d<T> point1_im( project( point1_w ) );
00123 vgl_point_2d<T> point2_im( project( point2_w ) );
00124 vgl_line_segment_2d<T> image_line( point1_im, point2_im );
00125 return image_line;
00126 }
00127
00128 template <class T>
00129 vgl_line_2d<T> vpgl_proj_camera<T>::project( const vgl_infinite_line_3d<T>& world_line ) const
00130 {
00131 vgl_homg_point_3d<T> point1_w( world_line.point() );
00132 vgl_homg_point_3d<T> point2_w( world_line.point_t(T(1)) );
00133 vgl_point_2d<T> point1_im( project( point1_w ) );
00134 vgl_point_2d<T> point2_im( project( point2_w ) );
00135 vgl_line_2d<T> image_line( point1_im, point2_im );
00136 return image_line;
00137 }
00138
00139 template <class T>
00140 vgl_homg_line_3d_2_points<T> vpgl_proj_camera<T>::backproject(
00141 const vgl_homg_point_2d<T>& image_point ) const
00142 {
00143
00144 vnl_vector_fixed<T,4> vnl_wp = svd()->solve(
00145 vnl_vector_fixed<T,3>( image_point.x(), image_point.y(), image_point.w() ) );
00146 vgl_homg_point_3d<T> wp( vnl_wp[0], vnl_wp[1], vnl_wp[2], vnl_wp[3] );
00147
00148
00149 if ( wp.ideal(.000001) )
00150 return vgl_homg_line_3d_2_points<T>( camera_center(), wp );
00151 return vgl_homg_line_3d_2_points<T>( wp, camera_center() );
00152 }
00153
00154
00155
00156 template <class T>
00157 vgl_homg_plane_3d<T> vpgl_proj_camera<T>::backproject(
00158 const vgl_homg_line_2d<T>& image_line ) const
00159 {
00160 vnl_vector_fixed<T,3> image_line_vnl(image_line.a(),image_line.b(),image_line.c());
00161 vnl_vector_fixed<T,4> world_plane = P_.transpose() * image_line_vnl;
00162 return vgl_homg_plane_3d<T>( world_plane(0), world_plane(1),
00163 world_plane(2), world_plane(3) );
00164 }
00165
00166
00167
00168
00169
00170 template <class T>
00171 vgl_homg_point_3d<T> vpgl_proj_camera<T>::camera_center() const
00172 {
00173 vnl_matrix<T> ns = svd()->nullspace();
00174 return vgl_homg_point_3d<T>(ns(0,0), ns(1,0), ns(2,0), ns(3,0));
00175 }
00176
00177
00178
00179
00180
00181 template <class T>
00182 vnl_svd<T>* vpgl_proj_camera<T>::svd() const
00183 {
00184
00185 if ( cached_svd_ == NULL )
00186 {
00187 cached_svd_ = new vnl_svd<T>(P_);
00188
00189
00190 if ( cached_svd_->rank() != 3 )
00191 vcl_cerr << "vpgl_proj_camera::svd()\n"
00192 << " Warning: Projection matrix is not rank 3, errors may occur.\n";
00193 }
00194 return cached_svd_;
00195 }
00196
00197
00198 template <class T>
00199 bool vpgl_proj_camera<T>::set_matrix( const vnl_matrix_fixed<T,3,4>& new_camera_matrix )
00200 {
00201 P_ = new_camera_matrix;
00202 if ( cached_svd_ != NULL ) delete cached_svd_;
00203 cached_svd_ = NULL;
00204 return true;
00205 }
00206
00207
00208 template <class T>
00209 bool vpgl_proj_camera<T>::set_matrix( const T* new_camera_matrix )
00210 {
00211 P_ = vnl_matrix_fixed<T,3,4>( new_camera_matrix );
00212 if ( cached_svd_ != NULL ) delete cached_svd_;
00213 cached_svd_ = NULL;
00214 return true;
00215 }
00216
00217
00218
00219
00220
00221 template <class T> void vpgl_proj_camera<T>::
00222 b_read(vsl_b_istream &is)
00223 {
00224 if (!is) return;
00225
00226 short ver;
00227 vsl_b_read(is, ver);
00228 vnl_matrix_fixed<T,3,4> Pnew;
00229 switch (ver)
00230 {
00231 case 1:
00232 vsl_b_read(is, Pnew);
00233 set_matrix(Pnew);
00234 break;
00235 default:
00236 vcl_cerr << "I/O ERROR: vpgl_proj_camera::b_read(vsl_b_istream&)\n"
00237 << " Unknown version number "<< ver << '\n';
00238 is.is().clear(vcl_ios::badbit);
00239 return;
00240 }
00241 }
00242
00243
00244
00245
00246 template <class T> void vpgl_proj_camera<T>::
00247 b_write(vsl_b_ostream &os) const
00248 {
00249 vsl_b_write(os, this->version());
00250 vsl_b_write(os, this->P_);
00251 }
00252
00253
00254
00255
00256
00257 template <class Type>
00258 vcl_ostream& operator<<(vcl_ostream& s,
00259 vpgl_proj_camera<Type> const& p)
00260 {
00261 s << "projective:"
00262 << "\nP\n" << p.get_matrix() << vcl_endl;
00263
00264 return s ;
00265 }
00266
00267
00268 template <class Type>
00269 vcl_istream& operator>>(vcl_istream& s,
00270 vpgl_proj_camera<Type>& p)
00271 {
00272 vnl_matrix_fixed<Type,3,4> new_matrix;
00273 s >> new_matrix;
00274 p.set_matrix( new_matrix );
00275
00276 return s ;
00277 }
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288 template <class T>
00289 void vsl_add_to_binary_loader(vpgl_proj_camera<T> const& b)
00290 {
00291 vsl_binary_loader<vpgl_proj_camera<T> >::instance().add(b);
00292 }
00293
00294
00295 template <class T>
00296 vgl_h_matrix_3d<T> get_canonical_h( vpgl_proj_camera<T>& camera )
00297 {
00298
00299
00300 vnl_matrix_fixed<T,4,3> Pinv = camera.svd()->pinverse();
00301 vnl_vector<T> l = camera.svd()->solve( vnl_vector<T>(3,(T)0) );
00302
00303 vnl_matrix_fixed<T,4,4> H;
00304 for ( int i = 0; i < 4; i++ ){
00305 for ( int j = 0; j < 3; j++ )
00306 H(i,j) = Pinv(i,j);
00307 H(i,3) = l(i);
00308 }
00309 return vgl_h_matrix_3d<T>( H );
00310 }
00311
00312
00313 template <class T>
00314 void fix_cheirality( vpgl_proj_camera<T>& )
00315 {
00316 vcl_cerr << "fix_cheirality( vpgl_proj_camera<T>& ) not implemented\n";
00317 }
00318
00319
00320 template <class T>
00321 void make_cannonical( vpgl_proj_camera<T>& camera )
00322 {
00323 vnl_matrix_fixed<T,3,4> can_cam( (T)0 );
00324 can_cam(0,0) = can_cam(1,1) = can_cam(2,2) = (T)1;
00325 camera.set_matrix( can_cam );
00326 }
00327
00328
00329 template <class T>
00330 vpgl_proj_camera<T> premultiply( const vpgl_proj_camera<T>& in_camera,
00331 const vnl_matrix_fixed<T,3,3>& transform )
00332 {
00333 return vpgl_proj_camera<T>( transform*in_camera.get_matrix() );
00334 }
00335
00336
00337 template <class T>
00338 vpgl_proj_camera<T> postmultiply( const vpgl_proj_camera<T>& in_camera,
00339 const vnl_matrix_fixed<T,4,4>& transform )
00340 {
00341 return vpgl_proj_camera<T>( in_camera.get_matrix()*transform );
00342 }
00343
00344
00345 template <class T>
00346 vgl_point_3d<T> triangulate_3d_point(const vpgl_proj_camera<T>& c1,
00347 const vgl_point_2d<T>& x1,
00348 const vpgl_proj_camera<T>& c2,
00349 const vgl_point_2d<T>& x2)
00350 {
00351 vnl_matrix_fixed<T,4,4> A;
00352 vnl_matrix_fixed<T,3,4> P1 = c1.get_matrix();
00353 vnl_matrix_fixed<T,3,4> P2 = c2.get_matrix();
00354 for (int i=0; i<4; i++) {
00355 A[0][i] = x1.x()*P1[2][i] - P1[0][i];
00356 A[1][i] = x1.y()*P1[2][i] - P1[1][i];
00357 A[2][i] = x2.x()*P2[2][i] - P2[0][i];
00358 A[3][i] = x2.y()*P2[2][i] - P2[1][i];
00359 }
00360 vnl_svd<T> svd_solver(A);
00361 vnl_vector_fixed<T, 4> p = svd_solver.nullvector();
00362 vgl_homg_point_3d<T> hp(p[0],p[1],p[2],p[3]);
00363 return vgl_point_3d<T>(hp);
00364 }
00365
00366
00367
00368
00369
00370 template <class T>
00371 vcl_vector<vnl_matrix_fixed<T,2,3> >
00372 image_jacobians(const vpgl_proj_camera<T>& camera,
00373 const vcl_vector<vgl_point_3d<T> >& pts)
00374 {
00375 const vnl_matrix_fixed<T,3,4>& P = camera.get_matrix();
00376 vnl_vector_fixed<T,4> denom = P.get_row(2);
00377
00378 vnl_matrix_fixed<T,3,4> Du;
00379 Du(0,0) = Du(1,1) = Du(2,2) = 0.0;
00380 Du(0,1) = P(0,0)*P(2,1) - P(0,1)*P(2,0);
00381 Du(0,2) = P(0,0)*P(2,2) - P(0,2)*P(2,0);
00382 Du(1,2) = P(0,1)*P(2,2) - P(0,2)*P(2,1);
00383 Du(0,3) = P(0,0)*P(2,3) - P(0,3)*P(2,0);
00384 Du(1,3) = P(0,1)*P(2,3) - P(0,3)*P(2,1);
00385 Du(2,3) = P(0,2)*P(2,3) - P(0,3)*P(2,2);
00386 Du(1,0) = -Du(0,1);
00387 Du(2,0) = -Du(0,2);
00388 Du(2,1) = -Du(1,2);
00389
00390 vnl_matrix_fixed<T,3,4> Dv;
00391 Dv(0,0) = Dv(1,1) = Dv(2,2) = 0.0;
00392 Dv(0,1) = P(1,0)*P(2,1) - P(1,1)*P(2,0);
00393 Dv(0,2) = P(1,0)*P(2,2) - P(1,2)*P(2,0);
00394 Dv(1,2) = P(1,1)*P(2,2) - P(1,2)*P(2,1);
00395 Dv(0,3) = P(1,0)*P(2,3) - P(1,3)*P(2,0);
00396 Dv(1,3) = P(1,1)*P(2,3) - P(1,3)*P(2,1);
00397 Dv(2,3) = P(1,2)*P(2,3) - P(1,3)*P(2,2);
00398 Dv(1,0) = -Dv(0,1);
00399 Dv(2,0) = -Dv(0,2);
00400 Dv(2,1) = -Dv(1,2);
00401
00402
00403 const unsigned int num_pts = pts.size();
00404 vcl_vector<vnl_matrix_fixed<T,2,3> > img_jac(num_pts);
00405
00406 for (unsigned int i=0; i<num_pts; ++i)
00407 {
00408 const vgl_point_3d<T>& pt = pts[i];
00409 vnl_matrix_fixed<double,2,3>& J = img_jac[i];
00410 vnl_vector_fixed<T,4> hpt(pt.x(),pt.y(),pt.z(),1.0);
00411
00412 double d = dot_product(denom,hpt);
00413 d *= d;
00414 J.set_row(0,Du*hpt);
00415 J.set_row(1,Dv*hpt);
00416 J /= d;
00417 }
00418
00419 return img_jac;
00420 }
00421
00422
00423
00424 #undef vpgl_PROJ_CAMERA_INSTANTIATE
00425 #define vpgl_PROJ_CAMERA_INSTANTIATE(T) \
00426 template class vpgl_proj_camera<T >; \
00427 template vgl_h_matrix_3d<T > get_canonical_h( vpgl_proj_camera<T >& camera ); \
00428 template void fix_cheirality( vpgl_proj_camera<T >& camera ); \
00429 template void make_cannonical( vpgl_proj_camera<T >& camera ); \
00430 template vpgl_proj_camera<T > premultiply( const vpgl_proj_camera<T >& in_camera, \
00431 const vnl_matrix_fixed<T,3,3>& transform ); \
00432 template vpgl_proj_camera<T > postmultiply(const vpgl_proj_camera<T >& in_camera, \
00433 const vnl_matrix_fixed<T,4,4>& transform ); \
00434 template vgl_point_3d<T > triangulate_3d_point(const vpgl_proj_camera<T >& c1, \
00435 const vgl_point_2d<T >& x1, \
00436 const vpgl_proj_camera<T >& c2, \
00437 const vgl_point_2d<T >& x2); \
00438 template vcl_vector<vnl_matrix_fixed<T,2,3> > \
00439 image_jacobians(const vpgl_proj_camera<T >& camera, \
00440 const vcl_vector<vgl_point_3d<T > >& pts); \
00441 template void vsl_add_to_binary_loader(vpgl_proj_camera<T > const& b); \
00442 template vcl_ostream& operator<<(vcl_ostream&, const vpgl_proj_camera<T >&); \
00443 template vcl_istream& operator>>(vcl_istream&, vpgl_proj_camera<T >&)
00444
00445 #endif // vpgl_proj_camera_txx_