00001
00002 #ifndef vpgl_perspective_camera_txx_
00003 #define vpgl_perspective_camera_txx_
00004
00005
00006
00007 #include "vpgl_perspective_camera.h"
00008 #include <vcl_cassert.h>
00009 #include <vcl_iostream.h>
00010 #include <vgl/vgl_point_2d.h>
00011 #include <vgl/vgl_vector_3d.h>
00012 #include <vgl/vgl_homg_plane_3d.h>
00013 #include <vgl/vgl_line_3d_2_points.h>
00014 #include <vgl/algo/vgl_h_matrix_3d.h>
00015 #include <vnl/vnl_det.h>
00016 #include <vnl/algo/vnl_qr.h>
00017 #include <vnl/vnl_matrix_fixed.h>
00018
00019 #include <vgl/io/vgl_io_point_3d.h>
00020 #include <vnl/io/vnl_io_matrix_fixed.h>
00021 #include <vnl/io/vnl_io_vector_fixed.h>
00022
00023
00024 template <class T>
00025 vpgl_perspective_camera<T>::vpgl_perspective_camera()
00026 {
00027 R_.set_identity();
00028 camera_center_.set( (T)0, (T)0, (T)0 );
00029 recompute_matrix();
00030 }
00031
00032
00033
00034 template <class T>
00035 vpgl_perspective_camera<T>::vpgl_perspective_camera(
00036 const vpgl_calibration_matrix<T>& K,
00037 const vgl_point_3d<T>& camera_center,
00038 const vgl_rotation_3d<T>& R ) :
00039 K_( K ), camera_center_( camera_center ), R_( R )
00040 {
00041 recompute_matrix();
00042 }
00043
00044
00045 template <class T>
00046 vpgl_perspective_camera<T>::vpgl_perspective_camera(
00047 const vpgl_calibration_matrix<T>& K,
00048 const vgl_rotation_3d<T>& R,
00049 const vgl_vector_3d<T>& t) :
00050 K_( K ), R_( R )
00051 {
00052 this->set_translation(t);
00053 recompute_matrix();
00054 }
00055
00056
00057 template <class T>
00058 vpgl_perspective_camera<T>::vpgl_perspective_camera( const vpgl_perspective_camera& that)
00059 : vpgl_proj_camera<T>(that),
00060 K_(that.K_),
00061 camera_center_(that.camera_center_),
00062 R_(that.R_)
00063 {
00064 }
00065
00066
00067 template <class T>
00068 vpgl_proj_camera<T>* vpgl_perspective_camera<T>::clone(void) const
00069 {
00070 return new vpgl_perspective_camera<T>(*this);
00071 }
00072
00073
00074
00075 template <class T>
00076 vgl_line_3d_2_points<T> vpgl_perspective_camera<T>::backproject(
00077 const vgl_point_2d<T>& image_point ) const
00078 {
00079
00080 vnl_vector_fixed<T,4> vnl_wp = this->svd()->solve(
00081 vnl_vector_fixed<T,3>( image_point.x(), image_point.y(), 1.0 ) );
00082 vgl_homg_point_3d<T> wp_homg( vnl_wp[0], vnl_wp[1], vnl_wp[2], vnl_wp[3] );
00083 vgl_point_3d<T> wp;
00084 if ( !wp_homg.ideal() )
00085 wp.set( wp_homg.x()/wp_homg.w(), wp_homg.y()/wp_homg.w(), wp_homg.z()/wp_homg.w() );
00086 else
00087 wp.set( camera_center_.x()+wp_homg.x(),
00088 camera_center_.y()+wp_homg.y(),
00089 camera_center_.z()+wp_homg.z() );
00090 if ( is_behind_camera( vgl_homg_point_3d<T>( wp ) ) )
00091 wp = camera_center_ + ( camera_center_-wp );
00092
00093 return vgl_line_3d_2_points<T>( camera_center_, wp );
00094 }
00095
00096
00097
00098 template <class T>
00099 vgl_vector_3d<T> vpgl_perspective_camera<T>::principal_axis() const
00100 {
00101
00102
00103
00104 const vnl_matrix_fixed<T,3,4>& P = this->get_matrix();
00105 return normalized(vgl_vector_3d<T>(P(2,0),P(2,1),P(2,2)));
00106 }
00107
00108
00109
00110 template <class T>
00111 bool vpgl_perspective_camera<T>::is_behind_camera(
00112 const vgl_homg_point_3d<T>& world_point ) const
00113 {
00114 vgl_homg_plane_3d<T> l = this->principal_plane();
00115 T dot = world_point.x()*l.a() + world_point.y()*l.b() +
00116 world_point.z()*l.c() + world_point.w()*l.d();
00117 if (world_point.w() < (T)0) dot = ((T)(-1))*dot;
00118 return dot < 0;
00119 }
00120
00121
00122
00123 template <class T>
00124 void vpgl_perspective_camera<T>::set_calibration( const vpgl_calibration_matrix<T>& K)
00125 {
00126 K_ = K;
00127 recompute_matrix();
00128 }
00129
00130
00131
00132 template <class T>
00133 void vpgl_perspective_camera<T>::set_camera_center(
00134 const vgl_point_3d<T>& camera_center )
00135 {
00136 camera_center_ = camera_center;
00137 recompute_matrix();
00138 }
00139
00140
00141 template <class T>
00142 void vpgl_perspective_camera<T>::set_translation(const vgl_vector_3d<T>& t)
00143 {
00144 vgl_rotation_3d<T> Rt = R_.transpose();
00145 vgl_vector_3d<T> cv = -(Rt * t);
00146 camera_center_.set(cv.x(), cv.y(), cv.z());
00147 recompute_matrix();
00148 }
00149
00150
00151 template <class T>
00152 void vpgl_perspective_camera<T>::set_rotation( const vgl_rotation_3d<T>& R )
00153 {
00154 R_ = R;
00155 recompute_matrix();
00156 }
00157
00158
00159 template <class T>
00160 vgl_vector_3d<T> vpgl_perspective_camera<T>::get_translation() const
00161 {
00162 vgl_vector_3d<T> c(camera_center_.x(), camera_center_.y(),camera_center_.z());
00163 vgl_vector_3d<T> temp = R_*c;
00164 return -temp;
00165 }
00166
00167
00168
00169
00170 template <class T>
00171 void vpgl_perspective_camera<T>::look_at(const vgl_homg_point_3d<T>& point,
00172 const vgl_vector_3d<T>& up )
00173 {
00174 vgl_vector_3d<T> u = normalized(up);
00175 vgl_vector_3d<T> look = point - camera_center();
00176 normalize(look);
00177 T dp = dot_product(look, up);
00178
00179 #if 0
00180 bool singularity = vcl_fabs(vcl_fabs(static_cast<double>(dp))-1.0)<1e-08;
00181 assert(!singularity);
00182 #endif
00183 vgl_vector_3d<T> z = look;
00184
00185 if(vcl_fabs(dot_product<T>(u,z)-T(1))<1e-5)
00186 {
00187
00188 T r[] = { 1, 0, 0,
00189 0, 1, 0,
00190 0, 0, 1 };
00191
00192 vnl_matrix_fixed<T,3,3> R(r);
00193 set_rotation(vgl_rotation_3d<T>(R));
00194
00195 }
00196 else if(vcl_fabs(dot_product<T>(u,z)-T(-1))<1e-5)
00197 {
00198 T r[] = { 1, 0, 0,
00199 0, 1, 0,
00200 0, 0, -1 };
00201
00202 vnl_matrix_fixed<T,3,3> R(r);
00203 set_rotation(vgl_rotation_3d<T>(R));
00204
00205 }
00206 else
00207 {
00208 vgl_vector_3d<T> x = cross_product(-u,z);
00209 vgl_vector_3d<T> y = cross_product(z,x);
00210 normalize(x);
00211 normalize(y);
00212 normalize(z);
00213
00214 T r[] = { x.x(), x.y(), x.z(),
00215 y.x(), y.y(), y.z(),
00216 z.x(), z.y(), z.z() };
00217
00218 vnl_matrix_fixed<T,3,3> R(r);
00219 set_rotation(vgl_rotation_3d<T>(R));
00220 }
00221 }
00222
00223
00224
00225 template <class T>
00226 void vpgl_perspective_camera<T>::recompute_matrix()
00227 {
00228 vnl_matrix_fixed<T,3,4> Pnew( (T)0 );
00229
00230
00231 for ( int i = 0; i < 3; i++ )
00232 Pnew(i,i) = (T)1;
00233 Pnew(0,3) = -camera_center_.x();
00234 Pnew(1,3) = -camera_center_.y();
00235 Pnew(2,3) = -camera_center_.z();
00236
00237
00238 this->set_matrix(K_.get_matrix()*R_.as_matrix()*Pnew);
00239 }
00240
00241
00242
00243 template <class T>
00244 bool vpgl_perspective_decomposition( const vnl_matrix_fixed<T,3,4>& camera_matrix,
00245 vpgl_perspective_camera<T>& p_camera )
00246 {
00247
00248 vnl_matrix_fixed<T,3,3> H = camera_matrix.extract(3,3);
00249 vnl_vector_fixed<T,3> t = camera_matrix.get_column(3);
00250
00251 T det = vnl_det(H);
00252 if ( det == (T)0 ) return false;
00253
00254
00255 if ( det < (T)0 ){
00256 H *= (T)-1;
00257 t *= (T)-1;
00258 }
00259
00260
00261
00262
00263
00264
00265
00266
00267 vnl_matrix_fixed<T,3,3> Hf;
00268 for ( int i = 0; i < 3; i++ )
00269 for ( int j = 0; j < 3; j++ )
00270 Hf(i,j) = H(2-j,2-i);
00271 vnl_qr<T> QR( Hf );
00272 vnl_matrix_fixed<T,3,3> q,r,Qf,Rf;
00273 q = QR.Q();
00274 r = QR.R();
00275 for ( int i = 0; i < 3; i++ ){
00276 for ( int j = 0; j < 3; j++ ){
00277 Qf(i,j) = q(2-j,2-i);
00278 Rf(i,j) = r(2-j,2-i);
00279 }
00280 }
00281
00282
00283
00284 int r0pos = Rf(0,0) > 0 ? 1 : -1;
00285 int r1pos = Rf(1,1) > 0 ? 1 : -1;
00286 int r2pos = Rf(2,2) > 0 ? 1 : -1;
00287 int diag[3] = { r0pos, r1pos, r2pos };
00288 vnl_matrix_fixed<T,3,3> K1,R1;
00289 for ( int i = 0; i < 3; i++ ){
00290 for ( int j = 0; j < 3; j++ ){
00291 K1(i,j) = diag[j]*Rf(i,j);
00292 R1(i,j) = diag[i]*Qf(i,j);
00293 }
00294 }
00295 K1 = K1/K1(2,2);
00296
00297
00298 vpgl_calibration_matrix<T> new_K( K1 );
00299 p_camera.set_calibration( new_K );
00300
00301 vnl_qr<T> QRofH(H);
00302 vnl_vector<T> c1 = -QRofH.solve(t);
00303 vgl_point_3d<T> new_c( c1(0), c1(1), c1(2) );
00304 p_camera.set_camera_center( new_c );
00305
00306 p_camera.set_rotation( vgl_rotation_3d<T>(R1) );
00307
00308 return true;
00309 }
00310
00311
00312
00313 template <class T>
00314 vpgl_perspective_camera<T> vpgl_align_down(
00315 const vpgl_perspective_camera<T>& p0,
00316 const vpgl_perspective_camera<T>& p1 )
00317 {
00318 vpgl_perspective_camera<T> new_camera;
00319 new_camera.set_calibration( p0.get_calibration() );
00320 new_camera.set_rotation( p1.get_rotation()*p0.get_rotation().inverse() );
00321 vgl_point_3d<T> a0 = p0.get_rotation()*p0.get_camera_center();
00322 vgl_point_3d<T> a1 = p0.get_rotation()*p1.get_camera_center();
00323 vgl_point_3d<T> new_camera_center(a1.x() - a0.x(),
00324 a1.y() - a0.y(),
00325 a1.z() - a0.z() );
00326 new_camera.set_camera_center( new_camera_center );
00327 return new_camera;
00328 }
00329
00330
00331
00332 template <class T>
00333 vpgl_perspective_camera<T> vpgl_align_up(
00334 const vpgl_perspective_camera<T>& p0,
00335 const vpgl_perspective_camera<T>& p1 )
00336 {
00337 vpgl_perspective_camera<T> new_camera;
00338 new_camera.set_calibration( p0.get_calibration() );
00339 new_camera.set_rotation( p1.get_rotation()*p0.get_rotation() );
00340 vgl_point_3d<T> a = p0.get_rotation().inverse()*p1.get_camera_center();
00341 vgl_point_3d<T> new_camera_center( p0.get_camera_center().x() + a.x(),
00342 p0.get_camera_center().y() + a.y(),
00343 p0.get_camera_center().z() + a.z() );
00344 new_camera.set_camera_center( new_camera_center );
00345 return new_camera;
00346 }
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358 template <class T> vpgl_perspective_camera<T>
00359 vpgl_perspective_camera<T>::postmultiply( const vpgl_perspective_camera<T>& in_cam, const vgl_h_matrix_3d<T>& euclid_trans)
00360 {
00361 assert(euclid_trans.is_euclidean());
00362 const vpgl_calibration_matrix<T>& K = in_cam.get_calibration();
00363 const vgl_rotation_3d<T>& R = in_cam.get_rotation();
00364 const vgl_point_3d<T>& cc = in_cam.get_camera_center();
00365 vgl_rotation_3d<T> Re(euclid_trans.get_upper_3x3());
00366 vgl_homg_point_3d<T> t = euclid_trans.get_translation();
00367
00368
00369 vgl_rotation_3d<T> Rp(R*Re);
00370
00371
00372 assert(!t.ideal());
00373
00374
00375
00376 vgl_vector_3d<T> te(t.x()/t.w(), t.y()/t.w(), t.z()/t.w());
00377
00378
00379 vgl_point_3d<T> ccp = Re.inverse()*(cc-te);
00380
00381 return vpgl_perspective_camera<T>(K, ccp, Rp);
00382 }
00383
00384
00385
00386
00387 template <class Type>
00388 vcl_ostream& operator<<(vcl_ostream& s,
00389 vpgl_perspective_camera<Type> const& p)
00390 {
00391 vnl_matrix_fixed<Type, 3, 3> k = p.get_calibration().get_matrix();
00392 vgl_rotation_3d<Type> rot = p.get_rotation();
00393 vnl_matrix_fixed<Type, 3, 3> Rm = rot.as_matrix();
00394 vgl_vector_3d<Type> t = p.get_translation();
00395 s << k << '\n'
00396 << Rm << '\n'
00397 << t.x() << ' ' << t.y() << ' ' << t.z() << '\n';
00398 return s ;
00399 }
00400
00401
00402 template <class Type>
00403 vcl_istream& operator >>(vcl_istream& s,
00404 vpgl_perspective_camera<Type>& p)
00405 {
00406 vnl_matrix_fixed<Type, 3, 3> k, Rm;
00407 vnl_vector_fixed<Type, 3> tv;
00408 s >> k;
00409 s >> Rm;
00410 s >> tv;
00411 vpgl_calibration_matrix<Type> K(k);
00412 vgl_rotation_3d<Type> rot(Rm);
00413 vgl_vector_3d<Type> t(tv[0], tv[1], tv[2]);
00414 p.set_calibration(K);
00415 p.set_rotation(rot);
00416 p.set_translation(t);
00417 return s ;
00418 }
00419
00420
00421 template <class T> void vpgl_perspective_camera<T>::
00422 b_read(vsl_b_istream &is)
00423 {
00424 if (!is) return;
00425
00426 vnl_matrix_fixed<T,4,4> Rot;
00427 vnl_vector_fixed<T,4> q;
00428
00429 short ver;
00430 vsl_b_read(is, ver);
00431 switch (ver)
00432 {
00433 case 1:
00434 vpgl_proj_camera<T>::b_read(is);
00435 K_.b_read(is);
00436 vsl_b_read(is, camera_center_);
00437 vsl_b_read(is, Rot);
00438 R_ = vgl_rotation_3d<T>(vgl_h_matrix_3d<T>(Rot));
00439 break;
00440 case 2:
00441 vpgl_proj_camera<T>::b_read(is);
00442 K_.b_read(is);
00443 vsl_b_read(is, camera_center_);
00444 vsl_b_read(is, q);
00445 R_ = vgl_rotation_3d<T>(vnl_quaternion<T>(q));
00446 break;
00447 default:
00448 vcl_cerr << "I/O ERROR: vpgl_persperctive_camera::b_read(vsl_b_istream&)\n"
00449 << " Unknown version number "<< ver << '\n';
00450 is.is().clear(vcl_ios::badbit);
00451 return;
00452 }
00453 this->recompute_matrix();
00454 }
00455
00456
00457
00458
00459 template <class T> void vpgl_perspective_camera<T>::
00460 b_write(vsl_b_ostream &os) const
00461 {
00462 vsl_b_write(os, this->version());
00463 vpgl_proj_camera<T>::b_write(os);
00464 K_.b_write(os);
00465 vsl_b_write(os, camera_center_);
00466 vsl_b_write(os, static_cast<vnl_vector_fixed<T,4> >(R_.as_quaternion()));
00467 }
00468
00469
00470 template <class T> void
00471 vsl_b_write(vsl_b_ostream &os, const vpgl_perspective_camera<T> * p)
00472 {
00473 if (p==0) {
00474 vsl_b_write(os, false);
00475 }
00476 else{
00477 vsl_b_write(os,true);
00478 p->b_write(os);
00479 }
00480 }
00481
00482
00483
00484 template <class T> void
00485 vsl_b_read(vsl_b_istream &is, vpgl_perspective_camera<T>* &p)
00486 {
00487 delete p;
00488 bool not_null_ptr;
00489 vsl_b_read(is, not_null_ptr);
00490 if (not_null_ptr) {
00491 p = new vpgl_perspective_camera<T>();
00492 p->b_read(is);
00493 }
00494 else
00495 p = 0;
00496 }
00497
00498
00499
00500 #undef vpgl_PERSPECTIVE_CAMERA_INSTANTIATE
00501 #define vpgl_PERSPECTIVE_CAMERA_INSTANTIATE(T) \
00502 template class vpgl_perspective_camera<T >; \
00503 template bool vpgl_perspective_decomposition(const vnl_matrix_fixed<T,3,4>& camera_matrix, \
00504 vpgl_perspective_camera<T >& p_camera ); \
00505 template vpgl_perspective_camera<T > vpgl_align_down(const vpgl_perspective_camera<T >& p0, \
00506 const vpgl_perspective_camera<T >& p1 ); \
00507 template vpgl_perspective_camera<T > vpgl_align_up(const vpgl_perspective_camera<T >& p0, \
00508 const vpgl_perspective_camera<T >& p1 ); \
00509 template void vsl_b_read(vsl_b_istream &is, vpgl_perspective_camera<T >* &p); \
00510 template void vsl_b_write(vsl_b_ostream &os, const vpgl_perspective_camera<T > * p); \
00511 template vcl_ostream& operator<<(vcl_ostream&, const vpgl_perspective_camera<T >&); \
00512 template vcl_istream& operator>>(vcl_istream&, vpgl_perspective_camera<T >&)
00513
00514 #endif // vpgl_perspective_camera_txx_