vpgl_fundamental_matrix.hxx
Go to the documentation of this file.
1 // This is core/vpgl/vpgl_fundamental_matrix.hxx
2 #ifndef vpgl_fundamental_matrix_hxx_
3 #define vpgl_fundamental_matrix_hxx_
4 //:
5 // \file
6 
7 #include <iosfwd>
11 
12 //
13 #include <vnl/vnl_vector_fixed.h>
14 #include <vnl/vnl_matrix_fixed.h>
16 #include <vnl/vnl_inverse.h>
17 //#include <vnl/io/vnl_io_matrix_fixed.h>
18 #include <vnl/algo/vnl_svd.h>
19 #include <vnl/vnl_vector.h>
20 #include <vgl/vgl_point_2d.h>
21 #include <vgl/vgl_point_3d.h>
22 #include <vgl/vgl_homg_point_2d.h>
23 #include <vgl/vgl_homg_line_2d.h>
25 #ifdef _MSC_VER
26 # include <vcl_msvc_warnings.h>
27 #endif
28 #include <cassert>
29 
30 
31 //---------------------------------
32 template <class T>
34  : cached_svd_(nullptr)
35 {
36  vnl_matrix_fixed<T,3,3> default_matrix( (T)0 );
37  default_matrix(0,0) = default_matrix(1,1) = (T)1;
38  set_matrix( default_matrix );
39 }
40 
41 //---------------------------------
42 //: Copy Constructor
43 template <class T>
45  const vpgl_fundamental_matrix<T>& other)
46  : cached_svd_(nullptr)
47 {
48  set_matrix( other.F_ );
49 }
50 
51 //---------------------------------
52 //: From Essential Matrix.
53 // Since $E = Kl^T \times F \times Kr$, $F = Kl^{-T} \times E \times Kr^{-1}$
54 template <class T>
58  const vpgl_essential_matrix<T> &em)
59  : cached_svd_(nullptr)
60 {
63  this->set_matrix(kl_tinv * em.get_matrix() * kr_inv);
64 }
65 
66 
67 //---------------------------------
68 template <class T>
71 {
72  set_matrix( fm.F_ );
73  return *this;
74 }
75 
76 
77 //---------------------------------
78 //: Destructor
79 template <class T>
81 {
82  delete cached_svd_;
83 }
84 
85 
86 //---------------------------------
87 template <class T>
89  vgl_homg_point_2d<T>& el ) const
90 {
91  vnl_vector_fixed<T,3> v = cached_svd_->nullvector();
92  er.set( v[0], v[1], v[2] );
93  v = cached_svd_->left_nullvector();
94  el.set( v[0], v[1], v[2] );
95 }
96 
97 
98 //---------------------------------
99 template <class T>
101  const vgl_homg_point_2d<T>& pl ) const
102 {
103  vnl_vector_fixed<T,3> lr = F_.transpose() *
104  vnl_vector_fixed<T,3>( pl.x(), pl.y(), pl.w() );
105  return vgl_homg_line_2d<T>( lr(0), lr(1), lr(2) );
106 }
107 
108 
109 //---------------------------------
110 template <class T>
112  const vgl_homg_point_2d<T>& pr ) const
113 {
115  F_ * vnl_vector_fixed<T,3>( pr.x(), pr.y(), pr.w() );
116  return vgl_homg_line_2d<T>( ll(0), ll(1), ll(2) );
117 }
118 
119 
120 //---------------------------------
121 template <class T>
123  const vgl_homg_line_2d<T> &epiline_l) const
124 {
125  vgl_homg_point_2d<T> er, el;
126 
127  get_epipoles(er, el);
128 
129  vgl_homg_line_2d<T> el_as_line(el.x(), el.y(), el.w());
130 
131  vnl_vector_fixed<T,3> epiline_r =
132  get_matrix().transpose() *
134  vgl_homg_operators_2d<T>::intersection( el_as_line , epiline_l));
135 
136  return vgl_homg_line_2d<T>(epiline_r[0], epiline_r[1], epiline_r[2]);
137 }
138 
139 
140 //---------------------------------
141 template <class T>
143  const vgl_homg_line_2d<T> &epiline_r) const
144 {
145  vgl_homg_point_2d<T> er, el;
146 
147  get_epipoles(er, el);
148 
149  vgl_homg_line_2d<T> er_as_line(er.x(), er.y(), er.w());
150 
151  vnl_vector_fixed<T,3> epiline_l =
152  get_matrix() *
154  vgl_homg_operators_2d<T>::intersection( er_as_line , epiline_r));
155 
156  return vgl_homg_line_2d<T>(epiline_l[0], epiline_l[1], epiline_l[2]);
157 }
158 
159 
160 //---------------------------------
161 template <class T>
163  const vnl_vector_fixed<T,3>& v, T lambda ) const
164 {
165  vgl_homg_point_2d<T> er, el;
166  get_epipoles( er, el );
167  vnl_matrix_fixed<T,3,3> elx((T)0);
168  elx.put( 0, 1, -el.w() ); elx.put( 0, 2, el.y() );
169  elx.put( 1, 0, el.w() ); elx.put( 1, 2, -el.x() );
170  elx.put( 2, 0, -el.y() ); elx.put( 2, 1, el.x() );
171 
173  elvt(0,0) = el.x()*v[0]; elvt(1,0) = el.y()*v[0]; elvt(2,0) = el.w()*v[0];
174  elvt(0,1) = el.x()*v[1]; elvt(1,1) = el.y()*v[1]; elvt(2,1) = el.w()*v[1];
175  elvt(0,2) = el.x()*v[2]; elvt(1,2) = el.y()*v[2]; elvt(2,2) = el.w()*v[2];
176 
178  P.set_columns( 0, (elx*F_+elvt).as_ref() ); // size 3x3
179  P.set_column( 3, vnl_vector_fixed<T,3>( lambda*el.x(), lambda*el.y(), lambda*el.w() ) );
180  return P;
181 }
182 
183 
184 
185 //--------------------------------
186 template <class T>
188  const std::vector< vgl_point_3d<T> >& world_points,
189  const std::vector< vgl_point_2d<T> >& image_points ) const
190 {
191  assert( world_points.size() == image_points.size() );
192  assert( world_points.size() >= 2 );
193 
194  vgl_homg_point_2d<T> er, el;
195  get_epipoles( er, el );
196  vnl_matrix_fixed<T,3,3> elxF((T)0);
197  elxF.put( 0, 1, -el.w() ); elxF.put( 0, 2, el.y() );
198  elxF.put( 1, 0, el.w() ); elxF.put( 1, 2, -el.x() );
199  elxF.put( 2, 0, -el.y() ); elxF.put( 2, 1, el.x() );
200  elxF*=F_;
201 
202  vnl_matrix<T> A(static_cast<unsigned int>(3 * image_points.size()), 4 );
203  vnl_vector<T> y( 3*image_points.size() );
204  for ( unsigned p = 0; p < image_points.size(); p++ ) {
205  vnl_vector_fixed<T,3> wp_vnl(
206  world_points[p].x(), world_points[p].y(), world_points[p].z() );
207  vnl_vector_fixed<T,3> ip_vnl(
208  image_points[p].x(), image_points[p].y(), (T)1 );
209  vnl_vector_fixed<T,3> yp = ip_vnl - elxF * wp_vnl;
210  T ei;
211  for ( unsigned i = 0; i < 3; i++ ) {
212  y(3*p+i) = yp(i);
213  if ( i == 0 ) ei = el.x(); else if ( i == 1 ) ei = el.y(); else ei = el.w();
214  A(3*p+i,0) = ei*wp_vnl[0]; A(3*p+i,1) = ei*wp_vnl[1]; A(3*p+i,2) = ei*wp_vnl[2];
215  A(3*p+i,3) = ei;
216  }
217  }
218 
219  // Do least squares estimation of y=Ax
220  vnl_vector<T> x = vnl_svd<T>(A).solve(y);
221  vnl_vector_fixed<T,3> v( x(0), x(1), x(2) );
222  T lambda = x(3);
223  return extract_left_camera( v, lambda );
224 }
225 
226 //---------------------------------
227 template <class T>
229  const vpgl_proj_camera<T>& cl )
230 {
231  vnl_vector_fixed<T, 4> nv = cr.svd()->nullvector();
233  vnl_vector_fixed<T, 3> nvt = m * nv;
235  // unfortunately, vnl_cross_product_matrix is only defined for double
236  for (unsigned i = 0; i<3; ++i)
237  nvtd[i] = static_cast<double>(nvt[i]);
238  vnl_cross_product_matrix e2x( nvtd );
240  for (unsigned r = 0; r<3; ++r)
241  for (unsigned c = 0; c<3; ++c)
242  e2xt[r][c] = static_cast<T>(e2x[r][c]);
243  vnl_matrix_fixed<T, 3, 3> temp = e2xt * (cl.get_matrix() * cr.svd()->inverse());
244  set_matrix( temp );
245 }
246 
247 
248 //---------------------------------
249 template <class T>
251 {
252  F_ = vnl_svd<T>( F.as_ref() ).recompose(2);
253  if ( cached_svd_ != nullptr ) delete cached_svd_;
254  cached_svd_ = new vnl_svd<T>( F_.as_ref() );
255 }
256 
257 //: write vpgl_fundamental_matrix to stream
258 template <class T>
259 std::ostream& operator<<(std::ostream& s, vpgl_fundamental_matrix<T> const& p)
260 {
261  s << p.get_matrix();
262  return s;
263 }
264 
265 //: Read vpgl_perspective_camera from stream
266 template <class T>
267 std::istream& operator>>(std::istream& s, vpgl_fundamental_matrix<T>& p)
268 {
270  s >> m;
271  p.set_matrix(m);
272  return s;
273 }
274 
275 // Macro for easy instantiation.
276 #undef vpgl_FUNDAMENTAL_MATRIX_INSTANTIATE
277 #define vpgl_FUNDAMENTAL_MATRIX_INSTANTIATE(T) \
278 template class vpgl_fundamental_matrix<T >; \
279 template std::ostream& operator<<(std::ostream&, const vpgl_fundamental_matrix<T >&); \
280 template std::istream& operator>>(std::istream&, vpgl_fundamental_matrix<T >&)
281 
282 #endif // vpgl_fundamental_matrix_hxx_
A class for the essential matrix between two projective cameras.
vnl_matrix_ref< T > as_ref()
A class for the fundamental matrix between two projective cameras.
vnl_svd< T > * svd() const
Get a copy of the svd of the get_matrix.
vgl_homg_line_2d< T > l_epipolar_line(const vgl_homg_point_2d< T > &pr) const
std::istream & operator>>(std::istream &is, vpgl_local_rational_camera< T > &p)
Read from stream.
#define m
void get_epipoles(vgl_homg_point_2d< T > &er, vgl_homg_point_2d< T > &el) const
Put the coordinates of the epipoles in er, el.
A class representing the "K" matrix of a perspective camera matrix as described in.
void put(unsigned r, unsigned c, T const &v)
const vpgl_fundamental_matrix< T > & operator=(const vpgl_fundamental_matrix< T > &fm)
Assignment.
#define v
static vnl_vector_fixed< T, 3 > get_vector(vgl_homg_point_2d< T > const &p)
vnl_matrix< T > solve(vnl_matrix< T > const &B) const
vnl_matrix_fixed< T, 1, 1 > vnl_inverse(vnl_matrix_fixed< T, 1, 1 > const &m)
bool extract_left_camera(const vpgl_essential_matrix< T > &E, const vgl_point_2d< T > &left_corr, const vgl_point_2d< T > &right_corr, vpgl_perspective_camera< T > &p_left, const T translation_mag=(T) 1)
Left camera extractor. Normalized correspondence pair is needed to determine which of four solutions ...
vnl_matrix_fixed< T, num_cols, num_rows > transpose() const
vnl_matrix_fixed< T, 3, 3 > F_
Internal representation of the fundamental matrix.
vnl_matrix_fixed< T, 3, 3 > get_matrix() const
Get the calibration matrix.
vpgl_fundamental_matrix()
Default constructor creates dummy rank 2 matrix.
std::ostream & operator<<(std::ostream &s, const vpgl_local_rational_camera< T > &p)
Write to stream.
void set(T px, T py, T pw=(T) 1)
const vnl_matrix_fixed< T, 3, 4 > & get_matrix() const
Return a copy of the camera matrix.
vpgl_proj_camera< T > extract_left_camera(const vnl_vector_fixed< T, 3 > &v, T lambda) const
Gives the left camera matrix corresponding to the fundamental matrix.
virtual ~vpgl_fundamental_matrix()
Destructor.
vnl_matrix_fixed & set_column(unsigned i, T const *v)
vgl_homg_line_2d< T > r_epipolar_line(const vgl_homg_point_2d< T > &pl) const
Given a point in one image, find the corresponding epipolar line in the other image.
const vnl_matrix_fixed< T, 3, 3 > & get_matrix() const
Get a copy of the FM in vnl form.
vnl_matrix_fixed & set_columns(unsigned starting_column, vnl_matrix< T > const &M)
A class for the calibration matrix component of a perspective camera matrix.
void set_matrix(const vpgl_proj_camera< T > &cr, const vpgl_proj_camera< T > &cl)