00001
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005
00006
00007
00008 #include "PMatrix.h"
00009
00010 #include <vcl_iostream.h>
00011 #include <vcl_fstream.h>
00012 #include <vcl_cmath.h>
00013 #include <vcl_cassert.h>
00014
00015 #include <vnl/vnl_matrix.h>
00016 #include <vnl/vnl_transpose.h>
00017 #include <vnl/vnl_matlab_print.h>
00018 #include <vnl/algo/vnl_svd.h>
00019 #include <vnl/algo/vnl_qr.h>
00020 #include <vgl/vgl_homg_plane_3d.h>
00021 #include <vgl/vgl_point_3d.h>
00022
00023 #include <mvl/HomgPrettyPrint.h>
00024 #include <mvl/HomgLine2D.h>
00025 #include <mvl/HomgLineSeg2D.h>
00026 #include <mvl/HomgPoint2D.h>
00027 #include <mvl/HomgLine3D.h>
00028 #include <mvl/HomgLineSeg3D.h>
00029 #include <mvl/HomgPoint3D.h>
00030 #include <mvl/HomgPlane3D.h>
00031 #include <mvl/HomgOperator2D.h>
00032 #include <mvl/PMatrixDecompAa.h>
00033 #include <mvl/HMatrix3D.h>
00034 #include <mvl/HMatrix2D.h>
00035
00036
00037
00038
00039
00040
00041 PMatrix::PMatrix ()
00042 : svd_(0)
00043 {
00044 for (int row_index = 0; row_index < 3; row_index++)
00045 for (int col_index = 0; col_index < 4; col_index++)
00046 if (row_index == col_index)
00047 p_matrix_. put (row_index, col_index, 1);
00048 else
00049 p_matrix_. put (row_index, col_index, 0);
00050 }
00051
00052
00053
00054
00055
00056
00057
00058 PMatrix::PMatrix (vcl_istream& i)
00059 : svd_(0)
00060 {
00061 read_ascii(i);
00062 }
00063
00064
00065
00066
00067
00068 PMatrix::PMatrix (vnl_double_3x4 const& pmatrix)
00069 : p_matrix_ (pmatrix),
00070 svd_(0)
00071 {
00072 }
00073
00074
00075
00076
00077
00078 PMatrix::PMatrix (const vnl_matrix<double>& A, const vnl_vector<double>& a)
00079 : svd_(0)
00080 {
00081 set(A,a);
00082 }
00083
00084
00085
00086
00087
00088 PMatrix::PMatrix (const double *c_matrix)
00089 : p_matrix_ (c_matrix),
00090 svd_(0)
00091 {
00092 }
00093
00094
00095
00096
00097
00098 PMatrix::PMatrix (const PMatrix& that)
00099 : vbl_ref_count(), p_matrix_(that.get_matrix()), svd_(0)
00100 {
00101 }
00102
00103
00104 PMatrix& PMatrix::operator=(const PMatrix& that)
00105 {
00106 p_matrix_ = that.get_matrix();
00107 svd_ = 0;
00108 return *this;
00109 }
00110
00111
00112
00113
00114 PMatrix::~PMatrix()
00115 {
00116 delete svd_; svd_ = 0;
00117 }
00118
00119
00120
00121
00122
00123
00124 HomgPoint2D PMatrix::project (const HomgPoint3D& X) const
00125 {
00126 vnl_double_3 x = p_matrix_ * X.get_vector();
00127 return HomgPoint2D(x);
00128 }
00129
00130
00131
00132
00133
00134 vgl_homg_line_2d<double> PMatrix::project (const vgl_homg_line_3d_2_points<double>& L) const
00135 {
00136 return vgl_homg_line_2d<double>(project(L.point_finite()), project(L.point_infinite()));
00137 }
00138
00139 HomgLine2D PMatrix::project (const HomgLine3D& L) const
00140 {
00141 return HomgOperator2D::join(project(L.get_point_finite()), project(L.get_point_infinite()));
00142 }
00143
00144
00145
00146
00147
00148 vgl_line_segment_2d<double> PMatrix::project(vgl_line_segment_3d<double> const& L) const
00149 {
00150 vgl_point_3d<double> p1 = L.point1(), p2 = L.point2();
00151 vgl_homg_point_3d<double> q1 (p1.x(),p1.y(),p1.z()), q2 (p2.x(),p2.y(),p2.z());
00152 return vgl_line_segment_2d<double>(project(q1), project(q2));
00153 }
00154
00155 HomgLineSeg2D PMatrix::project (const HomgLineSeg3D& L) const
00156 {
00157 return HomgLineSeg2D(project(L.get_point1()), project(L.get_point2()));
00158 }
00159
00160
00161
00162
00163
00164
00165 vgl_homg_point_3d<double> PMatrix::backproject_pseudoinverse (const vgl_homg_point_2d<double>& x) const
00166 {
00167 vnl_double_4 p = svd()->solve(vnl_double_3(x.x(),x.y(),x.w()));
00168 return vgl_homg_point_3d<double>(p[0],p[1],p[2],p[3]);
00169 }
00170
00171 HomgPoint3D PMatrix::backproject_pseudoinverse (const HomgPoint2D& x) const
00172 {
00173 return svd()->solve(x.get_vector());
00174 }
00175
00176
00177
00178
00179
00180 vgl_homg_line_3d_2_points<double> PMatrix::backproject (const vgl_homg_point_2d<double>& x) const
00181 {
00182 return vgl_homg_line_3d_2_points<double>(get_focal(), backproject_pseudoinverse(x));
00183 }
00184
00185 HomgLine3D PMatrix::backproject (const HomgPoint2D& x) const
00186 {
00187 return HomgLine3D(get_focal_point(), backproject_pseudoinverse(x));
00188 }
00189
00190
00191
00192
00193 vgl_homg_plane_3d<double> PMatrix::backproject (const vgl_homg_line_2d<double>& l) const
00194 {
00195 return p_matrix_.transpose() * l;
00196 }
00197
00198 HomgPlane3D PMatrix::backproject (const HomgLine2D& l) const
00199 {
00200 return HomgPlane3D(vnl_transpose(p_matrix_) * l.get_vector());
00201 }
00202
00203
00204
00205 vcl_ostream& operator<<(vcl_ostream& s, const PMatrix& p)
00206 {
00207 if (HomgPrettyPrint::pretty)
00208 return vnl_matlab_print(s, p.get_matrix(), "");
00209 else
00210 return s << p.get_matrix();
00211 }
00212
00213
00214
00215 vcl_istream& operator>>(vcl_istream& i, PMatrix& p)
00216 {
00217 p.read_ascii(i);
00218 return i;
00219 }
00220
00221 static bool ok(vcl_istream& f) { return f.good() || f.eof(); }
00222
00223
00224
00225
00226
00227 bool PMatrix::read_ascii(vcl_istream& f)
00228 {
00229 vnl_matrix<double> hold(3,4);
00230 f >> hold;
00231
00232 for (int i=0;i<3;i++)
00233 for (int j=0;j<4;j++)
00234 p_matrix_(i,j) = hold(i,j);
00235
00236 clear_svd();
00237
00238 if (!ok(f)) {
00239 vcl_cerr << "PMatrix::read_ascii: Failed to load P matrix from stream\n";
00240 return false;
00241 }
00242
00243 return true;
00244 }
00245
00246
00247
00248
00249
00250
00251 PMatrix PMatrix::read(const char* filename)
00252 {
00253 vcl_ifstream f(filename);
00254 if (!ok(f)) {
00255 vcl_cerr << "PMatrix::read: Failed to open P matrix file " << filename << vcl_endl;
00256 return PMatrix();
00257 }
00258
00259 PMatrix P;
00260 if (!P.read_ascii(f))
00261 vcl_cerr << "PMatrix::read: Failed to read P matrix file " << filename << vcl_endl;
00262
00263 return P;
00264 }
00265
00266
00267 PMatrix PMatrix::read(vcl_istream& s)
00268 {
00269 PMatrix P;
00270 s >> P;
00271 return P;
00272 }
00273
00274
00275
00276
00277
00278
00279 vnl_svd<double>* PMatrix::svd() const
00280 {
00281 if (svd_ == 0) {
00282
00283 svd_ = new vnl_svd<double>(p_matrix_);
00284 }
00285 return svd_;
00286 }
00287
00288
00289
00290 void PMatrix::clear_svd() const
00291 {
00292 delete svd_; svd_ = 0;
00293 }
00294
00295
00296
00297
00298
00299 vgl_homg_point_3d<double> PMatrix::get_focal() const
00300 {
00301 if (svd()->singularities() > 1) {
00302 vcl_cerr << "PMatrix::get_focal:\n"
00303 << " Nullspace dimension is " << svd()->singularities()
00304 << "\n Returning an invalid point (a vector of zeros)\n";
00305 return vgl_homg_point_3d<double>(0,0,0,0);
00306 }
00307
00308 vnl_matrix<double> ns = svd()->nullspace();
00309
00310 return vgl_homg_point_3d<double>(ns(0,0), ns(1,0), ns(2,0), ns(3,0));
00311 }
00312
00313 HomgPoint3D PMatrix::get_focal_point() const
00314 {
00315
00316 if (svd()->singularities() > 1) {
00317 vcl_cerr << "PMatrix::get_focal_point:\n"
00318 << " Nullspace dimension is " << svd()->singularities()
00319 << "\n Returning a vector of zeros\n";
00320 return HomgPoint3D(0,0,0,0);
00321 }
00322
00323 vnl_matrix<double> nullspace = svd()->nullspace();
00324
00325 if (nullspace(3,0) == 0)
00326 vcl_cerr << "PMatrix::get_focal_point: Focal point at infinity";
00327
00328 return HomgPoint3D(nullspace(0,0),
00329 nullspace(1,0),
00330 nullspace(2,0),
00331 nullspace(3,0));
00332 }
00333
00334
00335
00336 HMatrix3D PMatrix::get_canonical_H() const
00337 {
00338
00339
00340
00341
00342
00343 PMatrixDecompAa p(*this);
00344 vnl_svd<double> svd(p.A);
00345 return HMatrix3D(svd.inverse(), -svd.solve(p.a));
00346 }
00347
00348
00349
00350 bool PMatrix::is_canonical(double tol) const
00351 {
00352 for (int r = 0; r < 3; ++r)
00353 for (int c = 0; c < 4; ++c) {
00354 double d = (r == c) ? (p_matrix_(r,c) - 1) : p_matrix_(r,c);
00355 if (vcl_fabs(d) > tol)
00356 return false;
00357 }
00358 return true;
00359 }
00360
00361
00362 PMatrix operator*(const PMatrix& P, const HMatrix3D& H)
00363 {
00364 return PMatrix(P.get_matrix() * H);
00365 }
00366
00367
00368
00369
00370
00371
00372 double
00373 PMatrix::get (unsigned int row_index, unsigned int col_index) const
00374 {
00375 return p_matrix_. get (row_index, col_index);
00376 }
00377
00378
00379
00380
00381 void
00382 PMatrix::get (double* c_matrix) const
00383 {
00384 for (int row_index = 0; row_index < 3; row_index++)
00385 for (int col_index = 0; col_index < 4; col_index++)
00386 *c_matrix++ = p_matrix_. get (row_index, col_index);
00387 }
00388
00389
00390
00391
00392 void
00393 PMatrix::get(vnl_double_3x4* p_matrix) const
00394 {
00395 *p_matrix = p_matrix_;
00396 }
00397
00398
00399
00400
00401 void
00402 PMatrix::get(vnl_matrix<double>* A, vnl_vector<double>* a) const
00403 {
00404 A->put(0,0, p_matrix_(0,0));
00405 A->put(1,0, p_matrix_(1,0));
00406 A->put(2,0, p_matrix_(2,0));
00407
00408 A->put(0,1, p_matrix_(0,1));
00409 A->put(1,1, p_matrix_(1,1));
00410 A->put(2,1, p_matrix_(2,1));
00411
00412 A->put(0,2, p_matrix_(0,2));
00413 A->put(1,2, p_matrix_(1,2));
00414 A->put(2,2, p_matrix_(2,2));
00415
00416 a->put(0, p_matrix_(0,3));
00417 a->put(1, p_matrix_(1,3));
00418 a->put(2, p_matrix_(2,3));
00419 }
00420
00421
00422
00423
00424 void
00425 PMatrix::get (vnl_double_3x3* A, vnl_double_3* a) const
00426 {
00427 A->put(0,0, p_matrix_(0,0));
00428 A->put(1,0, p_matrix_(1,0));
00429 A->put(2,0, p_matrix_(2,0));
00430
00431 A->put(0,1, p_matrix_(0,1));
00432 A->put(1,1, p_matrix_(1,1));
00433 A->put(2,1, p_matrix_(2,1));
00434
00435 A->put(0,2, p_matrix_(0,2));
00436 A->put(1,2, p_matrix_(1,2));
00437 A->put(2,2, p_matrix_(2,2));
00438
00439 a->put(0, p_matrix_(0,3));
00440 a->put(1, p_matrix_(1,3));
00441 a->put(2, p_matrix_(2,3));
00442 }
00443
00444
00445
00446
00447 void
00448 PMatrix::get_rows (vnl_vector<double>* a, vnl_vector<double>* b, vnl_vector<double>* c) const
00449 {
00450 a->put(0, p_matrix_(0, 0));
00451 a->put(1, p_matrix_(0, 1));
00452 a->put(2, p_matrix_(0, 2));
00453 a->put(3, p_matrix_(0, 3));
00454
00455 b->put(0, p_matrix_(1, 0));
00456 b->put(1, p_matrix_(1, 1));
00457 b->put(2, p_matrix_(1, 2));
00458 b->put(3, p_matrix_(1, 3));
00459
00460 c->put(0, p_matrix_(2, 0));
00461 c->put(1, p_matrix_(2, 1));
00462 c->put(2, p_matrix_(2, 2));
00463 c->put(3, p_matrix_(2, 3));
00464 }
00465
00466
00467
00468
00469 void
00470 PMatrix::get_rows(vnl_vector_fixed<double,4>* a,
00471 vnl_vector_fixed<double,4>* b,
00472 vnl_vector_fixed<double,4>* c) const
00473 {
00474 a->put(0, p_matrix_(0, 0));
00475 a->put(1, p_matrix_(0, 1));
00476 a->put(2, p_matrix_(0, 2));
00477 a->put(3, p_matrix_(0, 3));
00478
00479 b->put(0, p_matrix_(1, 0));
00480 b->put(1, p_matrix_(1, 1));
00481 b->put(2, p_matrix_(1, 2));
00482 b->put(3, p_matrix_(1, 3));
00483
00484 c->put(0, p_matrix_(2, 0));
00485 c->put(1, p_matrix_(2, 1));
00486 c->put(2, p_matrix_(2, 2));
00487 c->put(3, p_matrix_(2, 3));
00488 }
00489
00490
00491
00492
00493 void
00494 PMatrix::set (const double p_matrix [3][4])
00495 {
00496 for (int row_index = 0; row_index < 3; row_index++)
00497 for (int col_index = 0; col_index < 4; col_index++)
00498 p_matrix_. put (row_index, col_index, p_matrix [row_index][col_index]);
00499 clear_svd();
00500 }
00501
00502
00503
00504 void
00505 PMatrix::set (const vnl_matrix<double>& p_matrix)
00506 {
00507 assert(p_matrix.rows()==3 && p_matrix.cols()==4);
00508
00509 for (int row_index = 0; row_index < 3; row_index++)
00510 for (int col_index = 0; col_index < 4; col_index++)
00511 p_matrix_. put (row_index, col_index, p_matrix (row_index,col_index));
00512 clear_svd();
00513 }
00514
00515
00516
00517
00518 void
00519 PMatrix::set (const double *p)
00520 {
00521 for (int row_index = 0; row_index < 3; row_index++)
00522 for (int col_index = 0; col_index < 4; col_index++)
00523 p_matrix_. put (row_index, col_index, *p++);
00524 clear_svd();
00525 }
00526
00527
00528
00529
00530
00531 void
00532 PMatrix::set (vnl_double_3x4 const& p_matrix)
00533 {
00534 p_matrix_ = p_matrix;
00535 clear_svd();
00536 }
00537
00538
00539
00540
00541
00542 void
00543 PMatrix::set (const vnl_matrix<double>& A, const vnl_vector<double>& a)
00544 {
00545 p_matrix_(0,0) = A(0,0);
00546 p_matrix_(1,0) = A(1,0);
00547 p_matrix_(2,0) = A(2,0);
00548
00549 p_matrix_(0,1) = A(0,1);
00550 p_matrix_(1,1) = A(1,1);
00551 p_matrix_(2,1) = A(2,1);
00552
00553 p_matrix_(0,2) = A(0,2);
00554 p_matrix_(1,2) = A(1,2);
00555 p_matrix_(2,2) = A(2,2);
00556
00557 p_matrix_(0,3) = a[0];
00558 p_matrix_(1,3) = a[1];
00559 p_matrix_(2,3) = a[2];
00560 }
00561
00562
00563 void
00564 PMatrix::fix_cheirality()
00565 {
00566 PMatrixDecompAa p(*this);
00567 double det = vnl_qr<double>(p.A).determinant();
00568
00569 double scale = 1;
00570 #if 0 // Used to scale by 1/det, but it's a bad idea if det is small
00571 if (vcl_fabs(det - 1) > 1e-8)
00572 vcl_cerr << "PMatrix::fix_cheirality: Flipping, determinant is " << det << vcl_endl;
00573 scale = 1/det;
00574 #else
00575 if (det < 0)
00576 scale = -1;
00577 #endif // 0
00578
00579 p_matrix_ *= scale;
00580 if (svd_)
00581 svd_->W() *= scale;
00582 }
00583
00584
00585
00586
00587 bool
00588 PMatrix::is_behind_camera(const vgl_homg_point_3d<double>& hX)
00589 {
00590 vnl_double_4 p = p_matrix_.get_row(2);
00591 double dot = hX.x()*p[0]+hX.y()*p[1]+hX.z()*p[2]+hX.w()*p[3];
00592 if (hX.w() < 0) dot = -dot;
00593
00594 return dot < 0;
00595 }
00596
00597 bool
00598 PMatrix::is_behind_camera(const HomgPoint3D& hX)
00599 {
00600 vnl_double_4 X = hX.get_vector();
00601
00602 int sign = +1;
00603 if (X[3] < 0)
00604 sign = -1;
00605
00606 vnl_double_4 plane = p_matrix_.get_row(2);
00607
00608 return sign * dot_product(plane, X) < 0;
00609 }
00610
00611
00612 void
00613 PMatrix::flip_sign()
00614 {
00615 p_matrix_ *= -1;
00616 if (svd_)
00617 svd_->W() *= -1;
00618 }
00619
00620
00621 bool
00622 PMatrix::looks_conditioned()
00623 {
00624 double cond = svd()->W(0) / svd()->W(2);
00625
00626 return cond < 100;
00627 }
00628
00629
00630 PMatrix PMatrix::postmultiply(vnl_double_4x4 const& H) const
00631 {
00632 return PMatrix(p_matrix_ * H);
00633 }
00634
00635
00636 PMatrix PMatrix::premultiply(vnl_double_3x3 const& H) const
00637 {
00638 return PMatrix(H * p_matrix_);
00639 }
00640