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