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_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
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
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
00080 template <class T>
00081 vgl_p_matrix<T>::~vgl_p_matrix()
00082 {
00083 delete svd_; svd_ = 0;
00084 }
00085
00086
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
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());
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
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_