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