00001
00002 #ifndef vpgl_perspective_camera_txx_
00003 #define vpgl_perspective_camera_txx_
00004
00005
00006
00007 #include "vpgl_perspective_camera.h"
00008
00009 #include <vgl/vgl_point_2d.h>
00010 #include <vgl/vgl_vector_3d.h>
00011 #include <vgl/vgl_homg_plane_3d.h>
00012 #include <vgl/vgl_line_3d_2_points.h>
00013 #include <vgl/algo/vgl_h_matrix_3d.h>
00014 #include <vnl/vnl_det.h>
00015 #include <vnl/algo/vnl_qr.h>
00016 #include <vnl/vnl_matrix_fixed.h>
00017 #if 0
00018 #include <vgl/io/vgl_io_point_3d.h>
00019 #include <vnl/io/vnl_io_matrix_fixed.h>
00020 #include <vnl/io/vnl_io_vector_fixed.h>
00021 #endif
00022 #include <vul/vul_file.h>
00023 #include <vul/vul_file_iterator.h>
00024
00025 #include <vcl_cassert.h>
00026 #include <vcl_iostream.h>
00027 #include <vcl_fstream.h>
00028 #include <vcl_algorithm.h>
00029
00030 #include <vnl/vnl_trace.h>
00031
00032
00033 template <class T>
00034 vpgl_perspective_camera<T>::vpgl_perspective_camera()
00035 {
00036 R_.set_identity();
00037 camera_center_.set( (T)0, (T)0, (T)0 );
00038 recompute_matrix();
00039 }
00040
00041
00042
00043 template <class T>
00044 vpgl_perspective_camera<T>::vpgl_perspective_camera(
00045 const vpgl_calibration_matrix<T>& K,
00046 const vgl_point_3d<T>& camera_center,
00047 const vgl_rotation_3d<T>& R ) :
00048 K_( K ), camera_center_( camera_center ), R_( R )
00049 {
00050 recompute_matrix();
00051 }
00052
00053
00054 template <class T>
00055 vpgl_perspective_camera<T>::vpgl_perspective_camera(
00056 const vpgl_calibration_matrix<T>& K,
00057 const vgl_rotation_3d<T>& R,
00058 const vgl_vector_3d<T>& t) :
00059 K_( K ), R_( R )
00060 {
00061 this->set_translation(t);
00062 recompute_matrix();
00063 }
00064
00065
00066 template <class T>
00067 vpgl_perspective_camera<T>::vpgl_perspective_camera( const vpgl_perspective_camera& that)
00068 : vpgl_proj_camera<T>(that),
00069 K_(that.K_),
00070 camera_center_(that.camera_center_),
00071 R_(that.R_)
00072 {
00073 }
00074
00075
00076 template <class T>
00077 vpgl_proj_camera<T>* vpgl_perspective_camera<T>::clone(void) const
00078 {
00079 return new vpgl_perspective_camera<T>(*this);
00080 }
00081
00082
00083 template <class T>
00084 vgl_homg_line_3d_2_points<T> vpgl_perspective_camera<T>::backproject(
00085 const vgl_homg_point_2d<T>& image_point ) const
00086 {
00087
00088 vnl_vector_fixed<T,4> vnl_wp = this->svd()->solve(
00089 vnl_vector_fixed<T,3>( image_point.x(), image_point.y(), image_point.w() ).as_ref() );
00090 vgl_homg_point_3d<T> wp( vnl_wp[0], vnl_wp[1], vnl_wp[2], vnl_wp[3] );
00091
00092 return vgl_homg_line_3d_2_points<T>( vgl_homg_point_3d<T>(camera_center_), wp );
00093 }
00094
00095
00096 template <class T>
00097 vgl_line_3d_2_points<T> vpgl_perspective_camera<T>::backproject(
00098 const vgl_point_2d<T>& image_point ) const
00099 {
00100
00101 vnl_vector_fixed<T,4> vnl_wp = this->svd()->solve(
00102 vnl_vector_fixed<T,3>( image_point.x(), image_point.y(), 1.0 ).as_ref() );
00103 vgl_homg_point_3d<T> wp_homg( vnl_wp[0], vnl_wp[1], vnl_wp[2], vnl_wp[3] );
00104 vgl_point_3d<T> wp;
00105 if ( !wp_homg.ideal() )
00106 wp.set( wp_homg.x()/wp_homg.w(), wp_homg.y()/wp_homg.w(), wp_homg.z()/wp_homg.w() );
00107 else
00108 wp.set( camera_center_.x()+wp_homg.x(),
00109 camera_center_.y()+wp_homg.y(),
00110 camera_center_.z()+wp_homg.z() );
00111 if ( is_behind_camera( vgl_homg_point_3d<T>( wp ) ) )
00112 wp = camera_center_ + ( camera_center_-wp );
00113
00114 return vgl_line_3d_2_points<T>( camera_center_, wp );
00115 }
00116
00117 template <class T>
00118 vgl_ray_3d<T> vpgl_perspective_camera<T>::
00119 backproject_ray( const vgl_point_2d<T>& image_point ) const
00120 {
00121 vgl_line_3d_2_points<T> l2 = this->backproject(image_point);
00122 return vgl_ray_3d<T>(l2.point1(), l2.direction());
00123 }
00124
00125
00126 template <class T>
00127 vgl_vector_3d<T> vpgl_perspective_camera<T>::principal_axis() const
00128 {
00129
00130
00131
00132 const vnl_matrix_fixed<T,3,4>& P = this->get_matrix();
00133 return normalized(vgl_vector_3d<T>(P(2,0),P(2,1),P(2,2)));
00134 }
00135
00136
00137 template <class T>
00138 bool vpgl_perspective_camera<T>::is_behind_camera(
00139 const vgl_homg_point_3d<T>& world_point ) const
00140 {
00141 vgl_homg_plane_3d<T> l = this->principal_plane();
00142 T dot = world_point.x()*l.a() + world_point.y()*l.b() +
00143 world_point.z()*l.c() + world_point.w()*l.d();
00144 if (world_point.w() < (T)0) dot = ((T)(-1))*dot;
00145 return dot < 0;
00146 }
00147
00148
00149 template <class T>
00150 void vpgl_perspective_camera<T>::set_calibration( const vpgl_calibration_matrix<T>& K)
00151 {
00152 K_ = K;
00153 recompute_matrix();
00154 }
00155
00156
00157 template <class T>
00158 void vpgl_perspective_camera<T>::set_camera_center(
00159 const vgl_point_3d<T>& camera_center )
00160 {
00161 camera_center_ = camera_center;
00162 recompute_matrix();
00163 }
00164
00165
00166 template <class T>
00167 void vpgl_perspective_camera<T>::set_translation(const vgl_vector_3d<T>& t)
00168 {
00169 vgl_rotation_3d<T> Rt = R_.transpose();
00170 vgl_vector_3d<T> cv = -(Rt * t);
00171 camera_center_.set(cv.x(), cv.y(), cv.z());
00172 recompute_matrix();
00173 }
00174
00175
00176 template <class T>
00177 void vpgl_perspective_camera<T>::set_rotation( const vgl_rotation_3d<T>& R )
00178 {
00179 R_ = R;
00180 recompute_matrix();
00181 }
00182
00183
00184 template <class T>
00185 vgl_vector_3d<T> vpgl_perspective_camera<T>::get_translation() const
00186 {
00187 vgl_vector_3d<T> c(camera_center_.x(), camera_center_.y(),camera_center_.z());
00188 vgl_vector_3d<T> temp = R_*c;
00189 return -temp;
00190 }
00191
00192
00193
00194
00195 template <class T>
00196 void vpgl_perspective_camera<T>::look_at(const vgl_homg_point_3d<T>& point,
00197 const vgl_vector_3d<T>& up )
00198 {
00199 vgl_vector_3d<T> u = normalized(up);
00200 vgl_vector_3d<T> look = point - camera_center();
00201 normalize(look);
00202 vcl_cout << "look at vector: " << look << vcl_endl;
00203
00204 #if 0
00205 T dp = dot_product(look, up);
00206 bool singularity = vcl_fabs(vcl_fabs(static_cast<double>(dp))-1.0)<1e-08;
00207 assert(!singularity);
00208 #endif
00209 vgl_vector_3d<T> z = look;
00210
00211 if (vcl_fabs(dot_product<T>(u,z)-T(1))<1e-5)
00212 {
00213 T r[] = { 1, 0, 0,
00214 0, 1, 0,
00215 0, 0, 1 };
00216
00217 vnl_matrix_fixed<T,3,3> R(r);
00218 set_rotation(vgl_rotation_3d<T>(R));
00219 }
00220 else if (vcl_fabs(dot_product<T>(u,z)-T(-1))<1e-5)
00221 {
00222 T r[] = { 1, 0, 0,
00223 0, 1, 0,
00224 0, 0, -1 };
00225
00226 vnl_matrix_fixed<T,3,3> R(r);
00227 set_rotation(vgl_rotation_3d<T>(R));
00228 }
00229 else
00230 {
00231 vgl_vector_3d<T> x = cross_product(-u,z);
00232 vgl_vector_3d<T> y = cross_product(z,x);
00233 normalize(x);
00234 normalize(y);
00235 normalize(z);
00236
00237 T r[] = { x.x(), x.y(), x.z(),
00238 y.x(), y.y(), y.z(),
00239 z.x(), z.y(), z.z() };
00240
00241 vnl_matrix_fixed<T,3,3> R(r);
00242 set_rotation(vgl_rotation_3d<T>(R));
00243 }
00244 }
00245
00246
00247
00248 template <class T>
00249 void vpgl_perspective_camera<T>::recompute_matrix()
00250 {
00251 vnl_matrix_fixed<T,3,4> Pnew( (T)0 );
00252
00253
00254 for ( int i = 0; i < 3; i++ )
00255 Pnew(i,i) = (T)1;
00256 Pnew(0,3) = -camera_center_.x();
00257 Pnew(1,3) = -camera_center_.y();
00258 Pnew(2,3) = -camera_center_.z();
00259
00260
00261 this->set_matrix(K_.get_matrix()*R_.as_matrix()*Pnew);
00262 }
00263
00264
00265
00266 template <class T>
00267 bool vpgl_perspective_decomposition( const vnl_matrix_fixed<T,3,4>& camera_matrix,
00268 vpgl_perspective_camera<T>& p_camera )
00269 {
00270
00271 vnl_matrix_fixed<T,3,3> H = camera_matrix.extract(3,3);
00272 vnl_vector_fixed<T,3> t = camera_matrix.get_column(3);
00273
00274 T det = vnl_det(H);
00275 if ( det == (T)0 ) return false;
00276
00277
00278 if ( det < (T)0 ) {
00279 H *= (T)-1;
00280 t *= (T)-1;
00281 }
00282
00283
00284
00285
00286
00287
00288
00289
00290 vnl_matrix_fixed<T,3,3> Hf;
00291 for ( int i = 0; i < 3; i++ )
00292 for ( int j = 0; j < 3; j++ )
00293 Hf(i,j) = H(2-j,2-i);
00294 vnl_qr<T> QR( Hf.as_ref() );
00295 vnl_matrix_fixed<T,3,3> q,r,Qf,Rf;
00296 q = QR.Q();
00297 r = QR.R();
00298 for ( int i = 0; i < 3; i++ ) {
00299 for ( int j = 0; j < 3; j++ ) {
00300 Qf(i,j) = q(2-j,2-i);
00301 Rf(i,j) = r(2-j,2-i);
00302 }
00303 }
00304
00305
00306
00307 int r0pos = Rf(0,0) > 0 ? 1 : -1;
00308 int r1pos = Rf(1,1) > 0 ? 1 : -1;
00309 int r2pos = Rf(2,2) > 0 ? 1 : -1;
00310 int diag[3] = { r0pos, r1pos, r2pos };
00311 vnl_matrix_fixed<T,3,3> K1,R1;
00312 for ( int i = 0; i < 3; i++ ) {
00313 for ( int j = 0; j < 3; j++ ) {
00314 K1(i,j) = diag[j]*Rf(i,j);
00315 R1(i,j) = diag[i]*Qf(i,j);
00316 }
00317 }
00318 K1 = K1/K1(2,2);
00319
00320
00321 vpgl_calibration_matrix<T> new_K( K1 );
00322 p_camera.set_calibration( new_K );
00323
00324 vnl_qr<T> QRofH(H.as_ref());
00325 vnl_vector<T> c1 = -QRofH.solve(t.as_ref());
00326 vgl_point_3d<T> new_c( c1(0), c1(1), c1(2) );
00327 p_camera.set_camera_center( new_c );
00328
00329 p_camera.set_rotation( vgl_rotation_3d<T>(R1) );
00330
00331 return true;
00332 }
00333
00334
00335
00336 template <class T>
00337 vpgl_perspective_camera<T> vpgl_align_down(
00338 const vpgl_perspective_camera<T>& p0,
00339 const vpgl_perspective_camera<T>& p1 )
00340 {
00341 vpgl_perspective_camera<T> new_camera;
00342 new_camera.set_calibration( p0.get_calibration() );
00343 new_camera.set_rotation( p1.get_rotation()*p0.get_rotation().inverse() );
00344 vgl_point_3d<T> a0 = p0.get_rotation()*p0.get_camera_center();
00345 vgl_point_3d<T> a1 = p0.get_rotation()*p1.get_camera_center();
00346 vgl_point_3d<T> new_camera_center(a1.x() - a0.x(),
00347 a1.y() - a0.y(),
00348 a1.z() - a0.z() );
00349 new_camera.set_camera_center( new_camera_center );
00350 return new_camera;
00351 }
00352
00353
00354
00355 template <class T>
00356 vpgl_perspective_camera<T> vpgl_align_up(
00357 const vpgl_perspective_camera<T>& p0,
00358 const vpgl_perspective_camera<T>& p1 )
00359 {
00360 vpgl_perspective_camera<T> new_camera;
00361 new_camera.set_calibration( p0.get_calibration() );
00362 new_camera.set_rotation( p1.get_rotation()*p0.get_rotation() );
00363 vgl_point_3d<T> a = p0.get_rotation().inverse()*p1.get_camera_center();
00364 vgl_point_3d<T> new_camera_center( p0.get_camera_center().x() + a.x(),
00365 p0.get_camera_center().y() + a.y(),
00366 p0.get_camera_center().z() + a.z() );
00367 new_camera.set_camera_center( new_camera_center );
00368 return new_camera;
00369 }
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381 template <class T> vpgl_perspective_camera<T>
00382 vpgl_perspective_camera<T>::postmultiply( const vpgl_perspective_camera<T>& in_cam, const vgl_h_matrix_3d<T>& euclid_trans)
00383 {
00384 assert(euclid_trans.is_euclidean());
00385 const vpgl_calibration_matrix<T>& K = in_cam.get_calibration();
00386 const vgl_rotation_3d<T>& R = in_cam.get_rotation();
00387 const vgl_point_3d<T>& cc = in_cam.get_camera_center();
00388 vgl_rotation_3d<T> Re(euclid_trans.get_upper_3x3());
00389 vgl_homg_point_3d<T> t = euclid_trans.get_translation();
00390
00391
00392 vgl_rotation_3d<T> Rp(R*Re);
00393
00394
00395 assert(!t.ideal());
00396
00397
00398
00399 vgl_vector_3d<T> te(t.x()/t.w(), t.y()/t.w(), t.z()/t.w());
00400
00401
00402 vgl_point_3d<T> ccp = Re.inverse()*(cc-te);
00403
00404 return vpgl_perspective_camera<T>(K, ccp, Rp);
00405 }
00406
00407 template <class T>
00408 vpgl_perspective_camera<T> vpgl_perspective_camera<T>::
00409 postmultiply(const vpgl_perspective_camera<T>& camera,
00410 const vgl_rotation_3d<T>& rot, const vgl_vector_3d<T>& trans)
00411 {
00412 vgl_h_matrix_3d<T> H;
00413 H.set_identity();
00414 H.set_rotation_matrix(rot.as_matrix());
00415 H.set_translation(trans.x(), trans.y(), trans.z());
00416 return vpgl_perspective_camera<T>::postmultiply(camera, H);
00417 }
00418
00419
00420
00421
00422 template <class Type>
00423 vcl_ostream& operator<<(vcl_ostream& s,
00424 vpgl_perspective_camera<Type> const& p)
00425 {
00426 vnl_matrix_fixed<Type, 3, 3> k = p.get_calibration().get_matrix();
00427 vgl_rotation_3d<Type> rot = p.get_rotation();
00428 vnl_matrix_fixed<Type, 3, 3> Rm = rot.as_matrix();
00429 vgl_vector_3d<Type> t = p.get_translation();
00430 s << k << '\n'
00431 << Rm << '\n'
00432 << t.x() << ' ' << t.y() << ' ' << t.z() << '\n';
00433 return s ;
00434 }
00435
00436
00437 template <class Type>
00438 vcl_istream& operator >>(vcl_istream& s,
00439 vpgl_perspective_camera<Type>& p)
00440 {
00441 vnl_matrix_fixed<Type, 3, 3> k, Rm;
00442 vnl_vector_fixed<Type, 3> tv;
00443 s >> k;
00444 s >> Rm;
00445 s >> tv;
00446 vpgl_calibration_matrix<Type> K(k);
00447 vgl_rotation_3d<Type> rot(Rm);
00448 vgl_vector_3d<Type> t(tv[0], tv[1], tv[2]);
00449 p.set_calibration(K);
00450 p.set_rotation(rot);
00451 p.set_translation(t);
00452 return s ;
00453 }
00454
00455
00456 template <class Type>
00457 void vpgl_perspective_camera<Type>::save(vcl_string cam_path)
00458 {
00459 vcl_ofstream os(cam_path.c_str());
00460 if (!os.is_open()) {
00461 vcl_cout << "unable to open output stream in vpgl_proj_camera<T>::save(.)\n";
00462 return;
00463 }
00464 os << *this << '\n';
00465 os.close();
00466 }
00467
00468
00469 template <class Type>
00470 void vrml_write(vcl_ostream& str, vpgl_perspective_camera<Type> const& p, double rad)
00471 {
00472 vgl_point_3d<Type> cent = p.get_camera_center();
00473 str << "Transform {\n"
00474 << "translation " << cent.x() << ' ' << cent.y() << ' '
00475 << ' ' << cent.z() << '\n'
00476 << "children [\n"
00477 << "Shape {\n"
00478 << " appearance Appearance{\n"
00479 << " material Material\n"
00480 << " {\n"
00481 << " diffuseColor " << 1 << ' ' << 1.0 << ' ' << 0.0 << '\n'
00482 << " transparency " << 0.0 << '\n'
00483 << " }\n"
00484 << " }\n"
00485 << " geometry Sphere\n"
00486 << "{\n"
00487 << " radius " << rad << '\n'
00488 << " }\n"
00489 << " }\n"
00490 << " ]\n"
00491 << "}\n";
00492 vgl_vector_3d<Type> r = p.principal_axis();
00493 vcl_cout<<"principal axis :" <<r<<vcl_endl;
00494 vnl_vector_fixed<Type,3> yaxis(0.0, 1.0, 0.0), pvec(r.x(), r.y(), r.z());
00495 vgl_rotation_3d<Type> rot(yaxis, pvec);
00496 vnl_quaternion<Type> q = rot.as_quaternion();
00497
00498
00499 vnl_vector_fixed<Type,3> axis = q.axis();
00500 vcl_cout<<"quaternion "<<axis<< " angle "<<q.angle()<<"\n\n";
00501 double ang = q.angle();
00502 str << "Transform {\n"
00503 << " translation " << cent.x()+6*rad*r.x() << ' ' << cent.y()+6*rad*r.y()
00504 << ' ' << cent.z()+6*rad*r.z() << '\n'
00505 << " rotation " << axis[0] << ' ' << axis[1] << ' ' << axis[2] << ' ' << ang << '\n'
00506 << "children [\n"
00507 << " Shape {\n"
00508 << " appearance Appearance{\n"
00509 << " material Material\n"
00510 << " {\n"
00511 << " diffuseColor 1 0 0\n"
00512 << " transparency 0\n"
00513 << " }\n"
00514 << " }\n"
00515 << " geometry Cylinder\n"
00516 << "{\n"
00517 << " radius "<<rad/3<<'\n'
00518 << " height " << 12*rad << '\n'
00519 << " }\n"
00520 << " }\n"
00521 << "]\n"
00522 << "}\n";
00523 }
00524
00525
00526
00527 template <class T>
00528 vcl_vector<vpgl_perspective_camera<T> > cameras_from_directory(vcl_string dir, T)
00529 {
00530 vcl_vector<vpgl_perspective_camera<T> > camlist;
00531 if (!vul_file::is_directory(dir.c_str()) ) {
00532 vcl_cerr << "cameras_from_directory: " << dir << " is not a directory\n";
00533 return camlist;
00534 }
00535
00536
00537 vcl_string camglob=dir+"/*";
00538 vul_file_iterator file_it(camglob.c_str());
00539 vcl_vector<vcl_string> cam_files;
00540 while (file_it) {
00541 vcl_string camName(file_it());
00542 cam_files.push_back(camName);
00543 ++file_it;
00544 }
00545 vcl_sort(cam_files.begin(), cam_files.end());
00546
00547
00548 for (vcl_vector<vcl_string>::iterator iter = cam_files.begin();
00549 iter != cam_files.end(); ++iter)
00550 {
00551 vcl_ifstream ifs(iter->c_str());
00552 vpgl_perspective_camera<T> pcam;
00553 if (!ifs.is_open()) {
00554 vcl_cerr << "Failed to open file " << *iter << '\n';
00555 }
00556 else {
00557 ifs >> pcam;
00558 camlist.push_back(pcam);
00559 }
00560 }
00561 return camlist;
00562 }
00563
00564 template <class T>
00565 double vpgl_persp_cam_distance( const vpgl_perspective_camera<T>& cam1, const vpgl_perspective_camera<T>& cam2)
00566 {
00567 vgl_vector_3d<T> ray1 = cam1.principal_axis();
00568 vgl_vector_3d<T> ray2 = cam2.principal_axis();
00569
00570 vgl_rotation_3d<T> R(ray1, ray2);
00571 double trace = vnl_trace(R.as_matrix());
00572 return vcl_acos((trace-1.0)/2.0);
00573 }
00574
00575
00576
00577 #undef vpgl_PERSPECTIVE_CAMERA_INSTANTIATE
00578 #define vpgl_PERSPECTIVE_CAMERA_INSTANTIATE(T) \
00579 template class vpgl_perspective_camera<T >; \
00580 template bool vpgl_perspective_decomposition(const vnl_matrix_fixed<T,3,4>& camera_matrix, \
00581 vpgl_perspective_camera<T >& p_camera ); \
00582 template vpgl_perspective_camera<T > vpgl_align_down(const vpgl_perspective_camera<T >& p0, \
00583 const vpgl_perspective_camera<T >& p1 ); \
00584 template vpgl_perspective_camera<T > vpgl_align_up(const vpgl_perspective_camera<T >& p0, \
00585 const vpgl_perspective_camera<T >& p1 ); \
00586 template vpgl_perspective_camera<T > postmultiply(const vpgl_perspective_camera<T >& in_cam, \
00587 const vgl_h_matrix_3d<T >& euclid_trans); \
00588 template double vpgl_persp_cam_distance(const vpgl_perspective_camera<T >& cam1, \
00589 const vpgl_perspective_camera<T >& cam2); \
00590 template void vrml_write(vcl_ostream &s, const vpgl_perspective_camera<T >&, double rad); \
00591 template vcl_vector<vpgl_perspective_camera<T > > cameras_from_directory(vcl_string dir, T); \
00592 template vcl_ostream& operator<<(vcl_ostream&, const vpgl_perspective_camera<T >&); \
00593 template vcl_istream& operator>>(vcl_istream&, vpgl_perspective_camera<T >&)
00594
00595 #endif // vpgl_perspective_camera_txx_