00001
00002 #ifndef vgl_p_matrix_txx_
00003 #define vgl_p_matrix_txx_
00004
00005
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
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
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
00089 template <class T>
00090 vgl_p_matrix<T>::~vgl_p_matrix()
00091 {
00092 delete svd_; svd_ = 0;
00093 }
00094
00095
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
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
00199
00200
00201
00202 template <class T>
00203 vnl_svd<T>* vgl_p_matrix<T>::svd() const
00204 {
00205 if (svd_ == 0) {
00206
00207 svd_ = new vnl_svd<T>(p_matrix_);
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
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_