vgl_p_matrix.hxx
Go to the documentation of this file.
1 // This is core/vgl/algo/vgl_p_matrix.hxx
2 #ifndef vgl_p_matrix_hxx_
3 #define vgl_p_matrix_hxx_
4 //:
5 // \file
6 
7 #include <iostream>
8 #include <fstream>
9 #include <cmath>
10 #include "vgl_p_matrix.h"
11 
12 #ifdef _MSC_VER
13 # include <vcl_msvc_warnings.h>
14 #endif
15 
16 #include <vnl/vnl_matrix.h>
17 #include <vnl/vnl_inverse.h>
18 #include <vnl/algo/vnl_svd.h>
19 #include <vnl/algo/vnl_determinant.h>
20 #include <vgl/vgl_homg_plane_3d.h>
21 #include <vgl/vgl_point_3d.h>
22 
23 //--------------------------------------------------------------
24 //
25 template <class T>
27  svd_(nullptr)
28 {
29  for (int row_index = 0; row_index < 3; row_index++)
30  for (int col_index = 0; col_index < 4; col_index++)
31  if (row_index == col_index)
32  p_matrix_. put(row_index, col_index, 1);
33  else
34  p_matrix_. put(row_index, col_index, 0);
35 }
36 
37 //--------------------------------------------------------------
38 //
39 template <class T>
41  svd_(nullptr)
42 {
43  read_ascii(i);
44 }
45 
46 //--------------------------------------------------------------
47 //
48 template <class T>
49 vgl_p_matrix<T>::vgl_p_matrix(vnl_matrix_fixed<T, 3, 4> const& pmatrix) :
50  p_matrix_(pmatrix), svd_(nullptr)
51 {
52 }
53 
54 //--------------------------------------------------------------
55 //
56 template <class T>
57 vgl_p_matrix<T>::vgl_p_matrix(const T *c_matrix) :
58  p_matrix_(c_matrix), svd_(nullptr)
59 {
60 }
61 
62 //--------------------------------------------------------------
63 //
64 // - Copy ctor
65 template <class T>
67  p_matrix_(that.get_matrix()), svd_(nullptr)
68 {
69 }
70 
71 // - Assignment
72 template <class T>
74 {
75  p_matrix_ = that.get_matrix();
76  svd_ = nullptr;
77  return *this;
78 }
79 
80 //--------------------------------------------------------------
81 //
82 // - Destructor
83 template <class T>
85 {
86  delete svd_; svd_ = nullptr;
87 }
88 
89 // OPERATIONS
90 
91 
92 //-----------------------------------------------------------------------------
93 //
94 template <class T>
96 {
97  return vgl_homg_line_2d<T>((*this)(L.point_finite()), (*this)(L.point_infinite()));
98 }
99 
100 //-----------------------------------------------------------------------------
101 //
102 template <class T>
104 {
105  vgl_point_3d<T> p1 = L.point1(), p2 = L.point2();
106  vgl_homg_point_3d<T> q1(p1.x(),p1.y(),p1.z()), q2(p2.x(),p2.y(),p2.z());
107  return vgl_line_segment_2d<T>((*this)(q1), (*this)(q2));
108 }
109 
110 //-----------------------------------------------------------------------------
111 //
112 template <class T>
114 {
115  vnl_vector_fixed<T,4> p = svd()->solve(vnl_vector_fixed<T,3>(x.x(),x.y(),x.w()).as_ref());
116  return vgl_homg_point_3d<T>(p[0],p[1],p[2],p[3]);
117 }
118 
119 //-----------------------------------------------------------------------------
120 //
121 template <class T>
123 {
124  return vgl_homg_line_3d_2_points<T>(get_focal(), backproject_pseudoinverse(x));
125 }
126 
127 //-----------------------------------------------------------------------------
128 //
129 template <class T>
131 {
132  return p_matrix_.transpose() * l;
133 }
134 
135 //-----------------------------------------------------------------------------
136 template <class T>
137 std::ostream& operator<<(std::ostream& s, const vgl_p_matrix<T>& p)
138 {
139  return s << p.get_matrix();
140 }
141 
142 //-----------------------------------------------------------------------------
143 template <class T>
144 std::istream& operator>>(std::istream& i, vgl_p_matrix<T>& p)
145 {
146  p.read_ascii(i);
147  return i;
148 }
149 
150 static inline bool ok(std::istream& f) { return f.good() || f.eof(); }
151 
152 template <class T>
153 bool vgl_p_matrix<T>::read_ascii(std::istream& f)
154 {
155  vnl_matrix_ref<T> ref = this->p_matrix_.as_ref();
156  f >> ref;
157  clear_svd();
158 
159  if (!ok(f)) {
160  std::cerr << "vgl_p_matrix::read_ascii: Failed to load P matrix\n";
161  return false;
162  }
163  else
164  return true;
165 }
166 
167 template <class T>
169 {
170  std::ifstream f(filename);
171  if (!ok(f)) {
172  std::cerr << "vgl_p_matrix::read: Failed to open P matrix file " << filename << std::endl;
173  return vgl_p_matrix<T>();
174  }
175 
176  vgl_p_matrix<T> P;
177  if (!P.read_ascii(f))
178  std::cerr << "vgl_p_matrix::read: Failed to read P matrix file " << filename << std::endl;
179 
180  return P;
181 }
182 
183 template <class T>
185 {
186  vgl_p_matrix<T> P;
187  s >> P;
188  return P;
189 }
190 
191 // COMPUTATIONS
192 
193 //-----------------------------------------------------------------------------
194 //
195 template <class T>
196 vnl_svd<T>* vgl_p_matrix<T>::svd() const
197 {
198  if (svd_ == nullptr) {
199  svd_ = new vnl_svd<T>(p_matrix_.as_ref()); // size 3x4; mutable const
200  }
201  return svd_;
202 }
203 
204 template <class T>
206 {
207  delete svd_; svd_ = nullptr;
208 }
209 
210 //-----------------------------------------------------------------------------
211 //
212 template <class T>
214 {
215  if (svd()->singularities() > 1) {
216  std::cerr << "vgl_p_matrix::get_focal:\n"
217  << " Nullspace dimension is " << svd()->singularities()
218  << "\n Returning an invalid point (a vector of zeros)\n";
219  return vgl_homg_point_3d<T>(0,0,0,0);
220  }
221 
222  vnl_matrix<T> ns = svd()->nullspace();
223 
224  return vgl_homg_point_3d<T>(ns(0,0), ns(1,0), ns(2,0), ns(3,0));
225 }
226 
227 template <class T>
229 {
230  vnl_matrix_fixed<T,3,3> A;
231  vnl_vector_fixed<T,3> a;
232  this->get(&A, &a);
233  return vgl_h_matrix_3d<T>(vnl_inverse(A), -vnl_inverse(A)*a);
234 }
235 
236 template <class T>
238 {
239  for (int r = 0; r < 3; ++r)
240  for (int c = 0; c < 4; ++c) {
241  T d = r==c ? p_matrix_(r,c)-1 : p_matrix_(r,c);
242  if (std::fabs(d) > tol)
243  return false;
244  }
245  return true;
246 }
247 
248 template <class T>
250 {
251  vnl_matrix_fixed<T, 3, 4> M = P.get_matrix()*H.get_matrix();
252  return vgl_p_matrix<T>(M);
253 }
254 
255 // DATA ACCESS
256 
257 //-----------------------------------------------------------------------------
258 //
259 template <class T>
260 T vgl_p_matrix<T>::get(unsigned int row_index, unsigned int col_index) const
261 {
262  return p_matrix_. get(row_index, col_index);
263 }
264 
265 //-----------------------------------------------------------------------------
266 //
267 template <class T>
268 void vgl_p_matrix<T>::get(T* c_matrix) const
269 {
270  for (int row_index = 0; row_index < 3; row_index++)
271  for (int col_index = 0; col_index < 4; col_index++)
272  *c_matrix++ = p_matrix_. get(row_index, col_index);
273 }
274 
275 //----------------------------------------------------------------
276 //
277 template <class T>
278 void
279 vgl_p_matrix<T>::get(vnl_matrix<T>* A, vnl_vector<T>* a) const
280 {
281  A->put(0,0, p_matrix_(0,0));
282  A->put(1,0, p_matrix_(1,0));
283  A->put(2,0, p_matrix_(2,0));
284 
285  A->put(0,1, p_matrix_(0,1));
286  A->put(1,1, p_matrix_(1,1));
287  A->put(2,1, p_matrix_(2,1));
288 
289  A->put(0,2, p_matrix_(0,2));
290  A->put(1,2, p_matrix_(1,2));
291  A->put(2,2, p_matrix_(2,2));
292 
293  a->put(0, p_matrix_(0,3));
294  a->put(1, p_matrix_(1,3));
295  a->put(2, p_matrix_(2,3));
296 }
297 
298 //----------------------------------------------------------------
299 //
300 template <class T>
301 void
302 vgl_p_matrix<T>::get(vnl_matrix_fixed<T,3,3>* A, vnl_vector_fixed<T,3>* a) const
303 {
304  A->put(0,0, p_matrix_(0,0));
305  A->put(1,0, p_matrix_(1,0));
306  A->put(2,0, p_matrix_(2,0));
307 
308  A->put(0,1, p_matrix_(0,1));
309  A->put(1,1, p_matrix_(1,1));
310  A->put(2,1, p_matrix_(2,1));
311 
312  A->put(0,2, p_matrix_(0,2));
313  A->put(1,2, p_matrix_(1,2));
314  A->put(2,2, p_matrix_(2,2));
315 
316  a->put(0, p_matrix_(0,3));
317  a->put(1, p_matrix_(1,3));
318  a->put(2, p_matrix_(2,3));
319 }
320 
321 //----------------------------------------------------------------
322 //
323 template <class T>
324 void
325 vgl_p_matrix<T>::get_rows(vnl_vector<T>* a, vnl_vector<T>* b, vnl_vector<T>* c) const
326 {
327  if (a->size() < 4) a->set_size(4);
328  a->put(0, p_matrix_(0, 0));
329  a->put(1, p_matrix_(0, 1));
330  a->put(2, p_matrix_(0, 2));
331  a->put(3, p_matrix_(0, 3));
332 
333  if (b->size() < 4) b->set_size(4);
334  b->put(0, p_matrix_(1, 0));
335  b->put(1, p_matrix_(1, 1));
336  b->put(2, p_matrix_(1, 2));
337  b->put(3, p_matrix_(1, 3));
338 
339  if (c->size() < 4) c->set_size(4);
340  c->put(0, p_matrix_(2, 0));
341  c->put(1, p_matrix_(2, 1));
342  c->put(2, p_matrix_(2, 2));
343  c->put(3, p_matrix_(2, 3));
344 }
345 
346 //----------------------------------------------------------------
347 //
348 template <class T>
349 void
350 vgl_p_matrix<T>::get_rows(vnl_vector_fixed<T,4>* a,
351  vnl_vector_fixed<T,4>* b,
352  vnl_vector_fixed<T,4>* c) const
353 {
354  a->put(0, p_matrix_(0, 0));
355  a->put(1, p_matrix_(0, 1));
356  a->put(2, p_matrix_(0, 2));
357  a->put(3, p_matrix_(0, 3));
358 
359  b->put(0, p_matrix_(1, 0));
360  b->put(1, p_matrix_(1, 1));
361  b->put(2, p_matrix_(1, 2));
362  b->put(3, p_matrix_(1, 3));
363 
364  c->put(0, p_matrix_(2, 0));
365  c->put(1, p_matrix_(2, 1));
366  c->put(2, p_matrix_(2, 2));
367  c->put(3, p_matrix_(2, 3));
368 }
369 
370 //----------------------------------------------------------------
371 //
372 template <class T>
374 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)
375 {
376  p_matrix_.put(0, 0, a(0));
377  p_matrix_.put(0, 1, a(1));
378  p_matrix_.put(0, 2, a(2));
379  p_matrix_.put(0, 3, a(3));
380 
381  p_matrix_.put(1, 0, b(0));
382  p_matrix_.put(1, 1, b(1));
383  p_matrix_.put(1, 2, b(2));
384  p_matrix_.put(1, 3, b(3));
385 
386  p_matrix_.put(2, 0, c(0));
387  p_matrix_.put(2, 1, c(1));
388  p_matrix_.put(2, 2, c(2));
389  p_matrix_.put(2, 3, c(3));
390 
391  return *this;
392 }
393 
394 //-----------------------------------------------------------------------------
395 //
396 template <class T>
398 vgl_p_matrix<T>::set(const T p_matrix [3][4])
399 {
400  for (int row_index = 0; row_index < 3; row_index++)
401  for (int col_index = 0; col_index < 4; col_index++)
402  p_matrix_. put(row_index, col_index, p_matrix [row_index][col_index]);
403  clear_svd();
404  return *this;
405 }
406 
407 //-----------------------------------------------------------------------------
408 //
409 template <class T>
412 {
413  for (int row_index = 0; row_index < 3; row_index++)
414  for (int col_index = 0; col_index < 4; col_index++)
415  p_matrix_. put(row_index, col_index, *p++);
416  clear_svd();
417  return *this;
418 }
419 
420 
421 //----------------------------------------------------------------
422 //
423 template <class T>
425 vgl_p_matrix<T>::set(vnl_matrix_fixed<T,3,3> const& A, vnl_vector_fixed<T,3> const& a)
426 {
427  p_matrix_(0,0) = A(0,0);
428  p_matrix_(1,0) = A(1,0);
429  p_matrix_(2,0) = A(2,0);
430 
431  p_matrix_(0,1) = A(0,1);
432  p_matrix_(1,1) = A(1,1);
433  p_matrix_(2,1) = A(2,1);
434 
435  p_matrix_(0,2) = A(0,2);
436  p_matrix_(1,2) = A(1,2);
437  p_matrix_(2,2) = A(2,2);
438 
439  p_matrix_(0,3) = a[0];
440  p_matrix_(1,3) = a[1];
441  p_matrix_(2,3) = a[2];
442 
443  return *this;
444 }
445 
446 //----------------------------------------------------------------
447 //
448 template <class T>
450 vgl_p_matrix<T>::set(vnl_matrix<T> const& A, vnl_vector<T> const& a)
451 {
452  p_matrix_(0,0) = A(0,0);
453  p_matrix_(1,0) = A(1,0);
454  p_matrix_(2,0) = A(2,0);
455 
456  p_matrix_(0,1) = A(0,1);
457  p_matrix_(1,1) = A(1,1);
458  p_matrix_(2,1) = A(2,1);
459 
460  p_matrix_(0,2) = A(0,2);
461  p_matrix_(1,2) = A(1,2);
462  p_matrix_(2,2) = A(2,2);
463 
464  p_matrix_(0,3) = a[0];
465  p_matrix_(1,3) = a[1];
466  p_matrix_(2,3) = a[2];
467 
468  return *this;
469 }
470 
471 //----------------------------------------------------------------
472 //
473 template <class T>
475 {
476  p_matrix_.set_identity();
477  return *this;
478 }
479 
480 template <class T>
483 {
484  vnl_matrix_fixed<T,3,3> A;
485  vnl_vector_fixed<T,3> a;
486  this->get(&A, &a);
487  T det = vnl_determinant(A);
488 
489  T scale = 1;
490 #if 0 // Used to scale by 1/det, but it's a bad idea if det is small
491  if (std::fabs(det - 1) > 1e-8) {
492  std::cerr << "vgl_p_matrix::fix_cheirality: Flipping, determinant is " << det << std::endl;
493  }
494 
495  scale = 1/det;
496 #endif // 0
497  if (det < 0)
498  scale = -scale;
499 
500  p_matrix_ *= scale;
501  if (svd_)
502  svd_->W() *= scale;
503 
504  return *this;
505 }
506 
507 template <class T>
509 {
510  vnl_vector_fixed<T,4> p = p_matrix_.get_row(2);
511  T dot = hX.x()*p[0]+hX.y()*p[1]+hX.z()*p[2]+hX.w()*p[3];
512  if (hX.w() < 0) dot = -dot;
513 
514  return dot < 0;
515 }
516 
517 template <class T>
520 {
521  p_matrix_ *= -1;
522  if (svd_)
523  svd_->W() *= -1;
524  return *this;
525 }
526 
527 template <class T>
529 {
530  T cond = svd()->W(0) / svd()->W(2);
531 #ifdef DEBUG
532  std::cerr << "vgl_p_matrix::looks_conditioned: cond = " << cond << '\n';
533 #endif
534  return cond < 100;
535 }
536 
537 template <class T>
538 vgl_p_matrix<T> vgl_p_matrix<T>::postmultiply(vnl_matrix_fixed<T,4,4> const& H) const
539 {
540  return vgl_p_matrix<T>(p_matrix_ * H);
541 }
542 
543 template <class T>
544 vgl_p_matrix<T> vgl_p_matrix<T>::premultiply(vnl_matrix_fixed<T,3,3> const& H) const
545 {
546  return vgl_p_matrix<T>(H * p_matrix_);
547 }
548 
549 
550 //----------------------------------------------------------------------------
551 #undef VGL_P_MATRIX_INSTANTIATE
552 #define VGL_P_MATRIX_INSTANTIATE(T) \
553 template class vgl_p_matrix<T >; \
554 template vgl_p_matrix<T > operator*(const vgl_p_matrix<T >& P, const vgl_h_matrix_3d<T >& H); \
555 template std::ostream& operator<<(std::ostream& s, const vgl_p_matrix<T >& h); \
556 template std::istream& operator>>(std::istream& s, vgl_p_matrix<T >& h)
557 
558 #endif // vgl_p_matrix_hxx_
homogeneous plane in 3D projective space
const vnl_matrix_fixed< T, 3, 4 > & get_matrix() const
Definition: vgl_p_matrix.h:184
General 3x4 perspective projection matrix.
vgl_point_3d< Type > point1() const
vgl_p_matrix & flip_sign()
Change the overall sign of the P matrix.
Represents a homogeneous 2D line.
Definition: vgl_fwd.h:14
bool is_behind_camera(vgl_homg_point_3d< T > const &)
Return true if the 3D point X is behind the camera represented by this P.
vgl_point_3d< Type > point2() const
void get(vnl_matrix_fixed< T, 3, 3 > *A, vnl_vector_fixed< T, 3 > *a) const
Return the 3x3 matrix and 3x1 column vector of P = [A a].
bool read_ascii(std::istream &f)
Load from file.
vgl_homg_point_3d< T > get_focal() const
Return the 3D point representing the focal point of the camera.
std::ostream & operator<<(std::ostream &s, vgl_orient_box_3d< Type > const &p)
Write box to stream.
vgl_h_matrix_3d< T > get_canonical_H() const
Return the 3D H-matrix s.t. P * H = [I 0].
bool is_canonical(T tol=0) const
Return true iff P is [I 0].
Represents a homogeneous 3D point.
Definition: vgl_fwd.h:9
Type & z()
Definition: vgl_point_3d.h:73
void clear_svd() const
Discredit the cached svd.
#define dot(p, q)
static vgl_p_matrix read(const char *filename)
Load from file.
a point in 3D nonhomogeneous space
vnl_matrix_fixed< T, 3, 4 > p_matrix_
Definition: vgl_p_matrix.h:199
A class to hold a 3-d projective transformation matrix and to perform common operations using it e....
Definition: vgl_algo_fwd.h:12
vgl_p_matrix & operator=(const vgl_p_matrix &)
Represents a 3D line segment using two points.
Definition: vgl_fwd.h:19
vgl_p_matrix()
Constructor. Set up a canonical P matrix.
vgl_p_matrix & set_identity()
Set the camera to an identity projection. X->u, Y->v.
vgl_p_matrix & set(vnl_matrix_fixed< T, 3, 4 > const &p_matrix)
Set the internal matrix using the 3x4 p_matrix.
Definition: vgl_p_matrix.h:172
vgl_homg_line_3d_2_points< T > backproject(vgl_homg_point_2d< T > const &x) const
Return the 3D line which is the backprojection of the specified image point, x.
vgl_p_matrix & set_rows(const vnl_vector_fixed< T, 4 > &a, const vnl_vector_fixed< T, 4 > &b, const vnl_vector_fixed< T, 4 > &c)
Set P = [a b c]' from its rows a, b, c.
Type & x()
Definition: vgl_point_3d.h:71
vnl_matrix_fixed< T, 4, 4 > const & get_matrix() const
Return the 4x4 homography matrix.
std::istream & operator>>(std::istream &is, vgl_orient_box_3d< Type > &p)
Read box from stream.
vgl_homg_point_3d< T > backproject_pseudoinverse(vgl_homg_point_2d< T > const &x) const
Return the 3D point $\vec X$ which is $\vec X = P^+ \vec x$.
#define l
vgl_homg_point_1d< T > operator *(vnl_matrix_fixed< T, 2, 2 > const &m, vgl_homg_point_1d< T > const &p)
Transform a point through a 2x2 projective transformation matrix.
Represents a homogeneous 2D point.
Definition: vgl_fwd.h:8
vgl_p_matrix< T > postmultiply(vnl_matrix_fixed< T, 4, 4 > const &H) const
post-multiply this projection matrix with a 3-d projective transform.
vgl_homg_point_3d< Type > point_finite() const
Finite point (Could be an ideal point, if the whole line is at infinity.).
bool looks_conditioned()
Splendid hack that tries to detect if the P is an image-coords P or a normalized P.
void get_rows(vnl_vector< T > *a, vnl_vector< T > *b, vnl_vector< T > *c) const
Return the rows of P = [a b c]'.
vgl_p_matrix & fix_cheirality()
Scale P so determinant of first 3x3 is 1.
vgl_homg_point_2d< T > operator()(vgl_homg_point_3d< T > const &X) const
Return the image point which is the projection of the specified 3D point X.
Definition: vgl_p_matrix.h:86
Type & y()
Definition: vgl_point_3d.h:72
vgl_p_matrix< T > premultiply(vnl_matrix_fixed< T, 3, 3 > const &H) const
pre-multiply this projection matrix with a 2-d projective transform.
vgl_homg_point_3d< Type > point_infinite() const
Infinite point: the intersection of the line with the plane at infinity.
Represents a homogeneous 3D line using two points.
Definition: vgl_fwd.h:15
vnl_svd< T > * svd() const
Compute the svd of this P and cache it, so that future operations that require it need not recompute ...