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