core/vgl/algo/vgl_p_matrix.txx
Go to the documentation of this file.
00001 // This is core/vgl/algo/vgl_p_matrix.txx
00002 #ifndef vgl_p_matrix_txx_
00003 #define vgl_p_matrix_txx_
00004 //:
00005 // \file
00006 
00007 #include "vgl_p_matrix.h"
00008 
00009 #include <vcl_iostream.h>
00010 #include <vcl_fstream.h>
00011 #include <vcl_cmath.h>
00012 
00013 #include <vnl/vnl_matrix.h>
00014 #include <vnl/vnl_inverse.h>
00015 #include <vnl/algo/vnl_svd.h>
00016 #include <vnl/algo/vnl_qr.h>
00017 #include <vgl/vgl_homg_plane_3d.h>
00018 #include <vgl/vgl_point_3d.h>
00019 
00020 //--------------------------------------------------------------
00021 //
00022 template <class T>
00023 vgl_p_matrix<T>::vgl_p_matrix() :
00024   svd_(0)
00025 {
00026   for (int row_index = 0; row_index < 3; row_index++)
00027     for (int col_index = 0; col_index < 4; col_index++)
00028       if (row_index == col_index)
00029         p_matrix_. put(row_index, col_index, 1);
00030       else
00031         p_matrix_. put(row_index, col_index, 0);
00032 }
00033 
00034 //--------------------------------------------------------------
00035 //
00036 template <class T>
00037 vgl_p_matrix<T>::vgl_p_matrix(vcl_istream& i) :
00038   svd_(0)
00039 {
00040   read_ascii(i);
00041 }
00042 
00043 //--------------------------------------------------------------
00044 //
00045 template <class T>
00046 vgl_p_matrix<T>::vgl_p_matrix(vnl_matrix_fixed<T, 3, 4> const& pmatrix) :
00047   p_matrix_(pmatrix), svd_(0)
00048 {
00049 }
00050 
00051 //--------------------------------------------------------------
00052 //
00053 template <class T>
00054 vgl_p_matrix<T>::vgl_p_matrix(const vnl_matrix<T>& A, const vnl_vector<T>& a) :
00055   svd_(0)
00056 {
00057   set(A,a);
00058 }
00059 
00060 //--------------------------------------------------------------
00061 //
00062 template <class T>
00063 vgl_p_matrix<T>::vgl_p_matrix(const T *c_matrix) :
00064   p_matrix_(c_matrix), svd_(0)
00065 {
00066 }
00067 
00068 //--------------------------------------------------------------
00069 //
00070 // - Copy ctor
00071 template <class T>
00072 vgl_p_matrix<T>::vgl_p_matrix(const vgl_p_matrix& that) :
00073   p_matrix_(that.get_matrix()), svd_(0)
00074 {
00075 }
00076 
00077 // - Assignment
00078 template <class T>
00079 vgl_p_matrix<T>& vgl_p_matrix<T>::operator=(const vgl_p_matrix& that)
00080 {
00081   p_matrix_ = that.get_matrix();
00082   svd_ = 0;
00083   return *this;
00084 }
00085 
00086 //--------------------------------------------------------------
00087 //
00088 // - Destructor
00089 template <class T>
00090 vgl_p_matrix<T>::~vgl_p_matrix()
00091 {
00092   delete svd_; svd_ = 0;
00093 }
00094 
00095 // OPERATIONS
00096 
00097 
00098 //-----------------------------------------------------------------------------
00099 //
00100 template <class T>
00101 vgl_homg_line_2d<T> vgl_p_matrix<T>::operator()(const vgl_homg_line_3d_2_points<T>& L) const
00102 {
00103   return vgl_homg_line_2d<T>((*this)(L.point_finite()), (*this)(L.point_infinite()));
00104 }
00105 
00106 //-----------------------------------------------------------------------------
00107 //
00108 template <class T>
00109 vgl_line_segment_2d<T> vgl_p_matrix<T>::operator()(vgl_line_segment_3d<T> const& L) const
00110 {
00111   vgl_point_3d<T> p1 = L.point1(), p2 = L.point2();
00112   vgl_homg_point_3d<T> q1(p1.x(),p1.y(),p1.z()), q2(p2.x(),p2.y(),p2.z());
00113   return vgl_line_segment_2d<T>((*this)(q1), (*this)(q2));
00114 }
00115 
00116 //-----------------------------------------------------------------------------
00117 //
00118 template <class T>
00119 vgl_homg_point_3d<T> vgl_p_matrix<T>::backproject_pseudoinverse(const vgl_homg_point_2d<T>& x) const
00120 {
00121   //compute with double precision but cast back to type T
00122   vnl_vector_fixed<double,4> p = svd()->solve(vnl_vector_fixed<double,3>(x.x(),x.y(),x.w()));
00123   return vgl_homg_point_3d<T>(p[0],p[1],p[2],p[3]);
00124 }
00125 
00126 //-----------------------------------------------------------------------------
00127 //
00128 template <class T>
00129 vgl_homg_line_3d_2_points<T> vgl_p_matrix<T>::backproject(const vgl_homg_point_2d<T>& x) const
00130 {
00131   return vgl_homg_line_3d_2_points<T>(get_focal(), backproject_pseudoinverse(x));
00132 }
00133 
00134 //-----------------------------------------------------------------------------
00135 //
00136 template <class T>
00137 vgl_homg_plane_3d<T> vgl_p_matrix<T>::backproject(const vgl_homg_line_2d<T>& l) const
00138 {
00139   return p_matrix_.transpose() * l;
00140 }
00141 
00142 //-----------------------------------------------------------------------------
00143 template <class T>
00144 vcl_ostream& operator<<(vcl_ostream& s, const vgl_p_matrix<T>& p)
00145 {
00146   return s << p.get_matrix();
00147 }
00148 
00149 //-----------------------------------------------------------------------------
00150 template <class T>
00151 vcl_istream& operator>>(vcl_istream& i, vgl_p_matrix<T>& p)
00152 {
00153   p.read_ascii(i);
00154   return i;
00155 }
00156 
00157 static bool ok(vcl_istream& f) { return f.good() || f.eof(); }
00158 
00159 template <class T>
00160 bool vgl_p_matrix<T>::read_ascii(vcl_istream& f)
00161 {
00162   vnl_matrix_ref<T> ref = this->p_matrix_;
00163   f >> ref;
00164   clear_svd();
00165 
00166   if (!ok(f)) {
00167     vcl_cerr << "vgl_p_matrix::read_ascii: Failed to load P matrix\n";
00168     return false;
00169   }
00170   else
00171     return true;
00172 }
00173 
00174 template <class T>
00175 vgl_p_matrix<T> vgl_p_matrix<T>::read(const char* filename)
00176 {
00177   vcl_ifstream f(filename);
00178   if (!ok(f)) {
00179     vcl_cerr << "vgl_p_matrix::read: Failed to open P matrix file " << filename << vcl_endl;
00180     return vgl_p_matrix<T>();
00181   }
00182 
00183   vgl_p_matrix<T> P;
00184   if (!P.read_ascii(f))
00185     vcl_cerr << "vgl_p_matrix::read: Failed to read P matrix file " << filename << vcl_endl;
00186 
00187   return P;
00188 }
00189 
00190 template <class T>
00191 vgl_p_matrix<T> vgl_p_matrix<T>::read(vcl_istream& s)
00192 {
00193   vgl_p_matrix<T> P;
00194   s >> P;
00195   return P;
00196 }
00197 
00198 // COMPUTATIONS
00199 
00200 //-----------------------------------------------------------------------------
00201 //
00202 template <class T>
00203 vnl_svd<T>* vgl_p_matrix<T>::svd() const
00204 {
00205   if (svd_ == 0) {
00206     // Need to make svd_ volatile for SGI g++ 2.7.2 optimizer bug.
00207     svd_ = new vnl_svd<T>(p_matrix_); // mutable const
00208   }
00209   return svd_;
00210 }
00211 
00212 template <class T>
00213 void vgl_p_matrix<T>::clear_svd() const
00214 {
00215   delete svd_; svd_ = 0;
00216 }
00217 
00218 //-----------------------------------------------------------------------------
00219 //
00220 template <class T>
00221 vgl_homg_point_3d<T> vgl_p_matrix<T>::get_focal() const
00222 {
00223   if (svd()->singularities() > 1) {
00224     vcl_cerr << "vgl_p_matrix::get_focal:\n"
00225              << "  Nullspace dimension is " << svd()->singularities()
00226              << "\n  Returning an invalid point (a vector of zeros)\n";
00227     return vgl_homg_point_3d<T>(0,0,0,0);
00228   }
00229 
00230   vnl_matrix<double> ns = svd()->nullspace();
00231 
00232   return vgl_homg_point_3d<T>(ns(0,0), ns(1,0), ns(2,0), ns(3,0));
00233 }
00234 
00235 template <class T>
00236 vgl_h_matrix_3d<T> vgl_p_matrix<T>::get_canonical_H() const
00237 {
00238   vnl_matrix_fixed<T,3,3> A;
00239   vnl_vector_fixed<T,3> a;
00240   this->get(&A, &a);
00241   return vgl_h_matrix_3d<T>(vnl_inverse(A), -vnl_inverse(A)*a);
00242 }
00243 
00244 template <class T>
00245 bool vgl_p_matrix<T>::is_canonical(T tol) const
00246 {
00247   for (int r = 0; r < 3; ++r)
00248     for (int c = 0; c < 4; ++c) {
00249       double d = r==c ? p_matrix_(r,c)-1 : p_matrix_(r,c);
00250       if (vcl_fabs(d) > tol)
00251         return false;
00252     }
00253   return true;
00254 }
00255 
00256 template <class T>
00257 vgl_p_matrix<T> operator*(const vgl_p_matrix<T>& P, const vgl_h_matrix_3d<T>& H)
00258 {
00259   vnl_matrix_fixed<T, 3, 4> M = P.get_matrix()*H.get_matrix();
00260   return vgl_p_matrix<T>(M);
00261 }
00262 
00263 // DATA ACCESS
00264 
00265 //-----------------------------------------------------------------------------
00266 //
00267 template <class T>
00268 T vgl_p_matrix<T>::get(unsigned int row_index, unsigned int col_index) const
00269 {
00270   return p_matrix_. get(row_index, col_index);
00271 }
00272 
00273 //-----------------------------------------------------------------------------
00274 //
00275 template <class T>
00276 void vgl_p_matrix<T>::get(T* c_matrix) const
00277 {
00278   for (int row_index = 0; row_index < 3; row_index++)
00279     for (int col_index = 0; col_index < 4; col_index++)
00280       *c_matrix++ = p_matrix_. get(row_index, col_index);
00281 }
00282 
00283 //----------------------------------------------------------------
00284 //
00285 template <class T>
00286 void
00287 vgl_p_matrix<T>::get(vnl_matrix<T>* A, vnl_vector<T>* a) const
00288 {
00289   A->put(0,0, p_matrix_(0,0));
00290   A->put(1,0, p_matrix_(1,0));
00291   A->put(2,0, p_matrix_(2,0));
00292 
00293   A->put(0,1, p_matrix_(0,1));
00294   A->put(1,1, p_matrix_(1,1));
00295   A->put(2,1, p_matrix_(2,1));
00296 
00297   A->put(0,2, p_matrix_(0,2));
00298   A->put(1,2, p_matrix_(1,2));
00299   A->put(2,2, p_matrix_(2,2));
00300 
00301   a->put(0, p_matrix_(0,3));
00302   a->put(1, p_matrix_(1,3));
00303   a->put(2, p_matrix_(2,3));
00304 }
00305 
00306 //----------------------------------------------------------------
00307 //
00308 template <class T>
00309 void
00310 vgl_p_matrix<T>::get(vnl_matrix_fixed<T,3,3>* A, vnl_vector_fixed<T,3>* a) const
00311 {
00312   A->put(0,0, p_matrix_(0,0));
00313   A->put(1,0, p_matrix_(1,0));
00314   A->put(2,0, p_matrix_(2,0));
00315 
00316   A->put(0,1, p_matrix_(0,1));
00317   A->put(1,1, p_matrix_(1,1));
00318   A->put(2,1, p_matrix_(2,1));
00319 
00320   A->put(0,2, p_matrix_(0,2));
00321   A->put(1,2, p_matrix_(1,2));
00322   A->put(2,2, p_matrix_(2,2));
00323 
00324   a->put(0, p_matrix_(0,3));
00325   a->put(1, p_matrix_(1,3));
00326   a->put(2, p_matrix_(2,3));
00327 }
00328 
00329 //----------------------------------------------------------------
00330 //
00331 template <class T>
00332 void
00333 vgl_p_matrix<T>::get_rows(vnl_vector<T>* a, vnl_vector<T>* b, vnl_vector<T>* c) const
00334 {
00335   if (a->size() < 4) a->set_size(4);
00336   a->put(0, p_matrix_(0, 0));
00337   a->put(1, p_matrix_(0, 1));
00338   a->put(2, p_matrix_(0, 2));
00339   a->put(3, p_matrix_(0, 3));
00340 
00341   if (b->size() < 4) b->set_size(4);
00342   b->put(0, p_matrix_(1, 0));
00343   b->put(1, p_matrix_(1, 1));
00344   b->put(2, p_matrix_(1, 2));
00345   b->put(3, p_matrix_(1, 3));
00346 
00347   if (c->size() < 4) c->set_size(4);
00348   c->put(0, p_matrix_(2, 0));
00349   c->put(1, p_matrix_(2, 1));
00350   c->put(2, p_matrix_(2, 2));
00351   c->put(3, p_matrix_(2, 3));
00352 }
00353 
00354 //----------------------------------------------------------------
00355 //
00356 template <class T>
00357 void
00358 vgl_p_matrix<T>::get_rows(vnl_vector_fixed<T,4>* a,
00359                           vnl_vector_fixed<T,4>* b,
00360                           vnl_vector_fixed<T,4>* c) const
00361 {
00362   a->put(0, p_matrix_(0, 0));
00363   a->put(1, p_matrix_(0, 1));
00364   a->put(2, p_matrix_(0, 2));
00365   a->put(3, p_matrix_(0, 3));
00366 
00367   b->put(0, p_matrix_(1, 0));
00368   b->put(1, p_matrix_(1, 1));
00369   b->put(2, p_matrix_(1, 2));
00370   b->put(3, p_matrix_(1, 3));
00371 
00372   c->put(0, p_matrix_(2, 0));
00373   c->put(1, p_matrix_(2, 1));
00374   c->put(2, p_matrix_(2, 2));
00375   c->put(3, p_matrix_(2, 3));
00376 }
00377 
00378 //----------------------------------------------------------------
00379 //
00380 template <class T>
00381 void
00382 vgl_p_matrix<T>::set_rows(vnl_vector_fixed<T,4> const& a, vnl_vector_fixed<T,4> const& b, vnl_vector_fixed<T,4> const& c)
00383 {
00384   p_matrix_.put(0, 0, a(0));
00385   p_matrix_.put(0, 1, a(1));
00386   p_matrix_.put(0, 2, a(2));
00387   p_matrix_.put(0, 3, a(3));
00388 
00389   p_matrix_.put(1, 0, b(0));
00390   p_matrix_.put(1, 1, b(1));
00391   p_matrix_.put(1, 2, b(2));
00392   p_matrix_.put(1, 3, b(3));
00393 
00394   p_matrix_.put(2, 0, c(0));
00395   p_matrix_.put(2, 1, c(1));
00396   p_matrix_.put(2, 2, c(2));
00397   p_matrix_.put(2, 3, c(3));
00398 }
00399 
00400 //-----------------------------------------------------------------------------
00401 //
00402 template <class T>
00403 void
00404 vgl_p_matrix<T>::set(const T p_matrix [3][4])
00405 {
00406   for (int row_index = 0; row_index < 3; row_index++)
00407     for (int col_index = 0; col_index < 4; col_index++)
00408       p_matrix_. put(row_index, col_index, p_matrix [row_index][col_index]);
00409   clear_svd();
00410 }
00411 
00412 //-----------------------------------------------------------------------------
00413 //
00414 template <class T>
00415 void
00416 vgl_p_matrix<T>::set(const T *p)
00417 {
00418   for (int row_index = 0; row_index < 3; row_index++)
00419     for (int col_index = 0; col_index < 4; col_index++)
00420       p_matrix_. put(row_index, col_index, *p++);
00421   clear_svd();
00422 }
00423 
00424 
00425 //----------------------------------------------------------------
00426 //
00427 template <class T>
00428 void
00429 vgl_p_matrix<T>::set(const vnl_matrix<T>& A, const vnl_vector<T>& a)
00430 {
00431   p_matrix_(0,0) = A(0,0);
00432   p_matrix_(1,0) = A(1,0);
00433   p_matrix_(2,0) = A(2,0);
00434 
00435   p_matrix_(0,1) = A(0,1);
00436   p_matrix_(1,1) = A(1,1);
00437   p_matrix_(2,1) = A(2,1);
00438 
00439   p_matrix_(0,2) = A(0,2);
00440   p_matrix_(1,2) = A(1,2);
00441   p_matrix_(2,2) = A(2,2);
00442 
00443   p_matrix_(0,3) = a[0];
00444   p_matrix_(1,3) = a[1];
00445   p_matrix_(2,3) = a[2];
00446 }
00447 
00448 //----------------------------------------------------------------
00449 //
00450 template <class T>
00451 void vgl_p_matrix<T>::set_identity()
00452 {
00453   p_matrix_(0,0) = 1;
00454   p_matrix_(1,0) = 0;
00455   p_matrix_(2,0) = 0;
00456 
00457   p_matrix_(0,1) = 0;
00458   p_matrix_(1,1) = 1;
00459   p_matrix_(2,1) = 0;
00460 
00461   p_matrix_(0,2) = 0;
00462   p_matrix_(1,2) = 0;
00463   p_matrix_(2,2) = 1;
00464 
00465   p_matrix_(0,3) = 0;
00466   p_matrix_(1,3) = 0;
00467   p_matrix_(2,3) = 0;
00468 }
00469 
00470 template <class T>
00471 void
00472 vgl_p_matrix<T>::fix_cheirality()
00473 {
00474   vnl_matrix_fixed<T,3,3> A;
00475   vnl_vector_fixed<T,3> a;
00476   this->get(&A, &a);
00477   double det = vnl_qr<double>(A).determinant();
00478 
00479   double scale = 1;
00480 #if 0 // Used to scale by 1/det, but it's a bad idea if det is small
00481   if (vcl_fabs(det - 1) > 1e-8) {
00482     vcl_cerr << "vgl_p_matrix::fix_cheirality: Flipping, determinant is " << det << vcl_endl;
00483   }
00484 
00485   scale = 1/det;
00486 #endif // 0
00487   if (det < 0)
00488     scale = -scale;
00489 
00490   p_matrix_ *= scale;
00491   if (svd_)
00492     svd_->W() *= scale;
00493 }
00494 
00495 template <class T>
00496 bool vgl_p_matrix<T>::is_behind_camera(const vgl_homg_point_3d<T>& hX)
00497 {
00498   vnl_vector_fixed<T,4> p = p_matrix_.get_row(2);
00499   double dot = hX.x()*p[0]+hX.y()*p[1]+hX.z()*p[2]+hX.w()*p[3];
00500   if (hX.w() < 0) dot = -dot;
00501 
00502   return dot < 0;
00503 }
00504 
00505 template <class T>
00506 void vgl_p_matrix<T>::flip_sign()
00507 {
00508   p_matrix_ *= -1;
00509   if (svd_)
00510     svd_->W() *= -1;
00511 }
00512 
00513 template <class T>
00514 bool vgl_p_matrix<T>::looks_conditioned()
00515 {
00516   double cond = svd()->W(0) / svd()->W(2);
00517 #ifdef DEBUG
00518   vcl_cerr << "vgl_p_matrix::looks_conditioned: cond = " << cond << '\n';
00519 #endif
00520   return cond < 100;
00521 }
00522 
00523 template <class T>
00524 vgl_p_matrix<T> vgl_p_matrix<T>::postmultiply(vnl_matrix_fixed<T,4,4> const& H) const
00525 {
00526   return vgl_p_matrix<T>(p_matrix_ * H);
00527 }
00528 
00529 template <class T>
00530 vgl_p_matrix<T> vgl_p_matrix<T>::premultiply(vnl_matrix_fixed<T,3,3> const& H) const
00531 {
00532   return vgl_p_matrix<T>(H * p_matrix_);
00533 }
00534 
00535 
00536 //----------------------------------------------------------------------------
00537 #undef VGL_P_MATRIX_INSTANTIATE
00538 #define VGL_P_MATRIX_INSTANTIATE(T) \
00539 template class vgl_p_matrix<T >; \
00540 template vgl_p_matrix<T > operator*(const vgl_p_matrix<T >& P, const vgl_h_matrix_3d<T >& H); \
00541 template vcl_ostream& operator<<(vcl_ostream& s, const vgl_p_matrix<T >& h); \
00542 template vcl_istream& operator>>(vcl_istream& s, vgl_p_matrix<T >& h)
00543 
00544 #endif // vgl_p_matrix_txx_