core/vgl/algo/vgl_h_matrix_2d.txx
Go to the documentation of this file.
00001 // This is core/vgl/algo/vgl_h_matrix_2d.txx
00002 #ifndef vgl_h_matrix_2d_txx_
00003 #define vgl_h_matrix_2d_txx_
00004 
00005 #include "vgl_h_matrix_2d.h"
00006 #include <vnl/vnl_inverse.h>
00007 #include <vnl/vnl_vector_fixed.h>
00008 #include <vnl/algo/vnl_svd.h>
00009 #include <vcl_limits.h>
00010 #include <vcl_cstdlib.h> // for exit()
00011 #include <vcl_fstream.h>
00012 #include <vcl_cassert.h>
00013 # include <vcl_deprecated.h>
00014 
00015 template <class T>
00016 vgl_h_matrix_2d<T>::vgl_h_matrix_2d(vcl_istream& s)
00017 {
00018   t12_matrix_.read_ascii(s);
00019 }
00020 
00021 template <class T>
00022 vgl_h_matrix_2d<T>::vgl_h_matrix_2d(char const* filename)
00023 {
00024   vcl_ifstream f(filename);
00025   if (!f.good())
00026     vcl_cerr << "vgl_h_matrix_2d::read: Error opening " << filename << vcl_endl;
00027   else
00028     t12_matrix_.read_ascii(f);
00029 }
00030 
00031 template <class T>
00032 vgl_h_matrix_2d<T>::vgl_h_matrix_2d(vcl_vector<vgl_homg_point_2d<T> > const& points1,
00033                                     vcl_vector<vgl_homg_point_2d<T> > const& points2)
00034 {
00035   vnl_matrix<T> W;
00036   assert(points1.size() == points2.size());
00037   unsigned int numpoints = points1.size();
00038   if (numpoints < 4)
00039   {
00040     vcl_cerr << "\nvhl_h_matrix_2d - minimum of 4 points required\n";
00041     vcl_exit(0);
00042   }
00043 
00044   W.set_size(2*numpoints, 9);
00045 
00046   for (unsigned int i = 0; i < numpoints; ++i)
00047   {
00048     T x1 = points1[i].x(), y1 = points1[i].y(), w1 = points1[i].w();
00049     T x2 = points2[i].x(), y2 = points2[i].y(), w2 = points2[i].w();
00050 
00051     W[i*2][0]=x1*w2;    W[i*2][1]=y1*w2;    W[i*2][2]=w1*w2;
00052     W[i*2][3]=0.0;      W[i*2][4]=0.0;      W[i*2][5]=0.0;
00053     W[i*2][6]=-x1*x2;   W[i*2][7]=-y1*x2;   W[i*2][8]=-w1*x2;
00054 
00055     W[i*2+1][0]=0.0;    W[i*2+1][1]=0.0;    W[i*2+1][2]=0.0;
00056     W[i*2+1][3]=x1*w2;  W[i*2+1][4]=y1*w2;  W[i*2+1][5]=w1*w2;
00057     W[i*2+1][6]=-x1*y2; W[i*2+1][7]=-y1*y2; W[i*2+1][8]=-w1*y2;
00058   }
00059 
00060   vnl_svd<T> SVD(W);
00061   t12_matrix_ = vnl_matrix_fixed<T,3,3>(SVD.nullvector().data_block()); // 9-dim. nullvector
00062 }
00063 
00064 template <class T>
00065 vgl_h_matrix_2d<T>::vgl_h_matrix_2d(vnl_matrix_fixed<T,2,2> const& M,
00066                                     vnl_vector_fixed<T,2> const& m)
00067 {
00068   for (int r = 0; r < 2; ++r) {
00069     for (int c = 0; c < 2; ++c)
00070       (t12_matrix_)(r, c) = M(r,c);
00071     (t12_matrix_)(r, 2) = m(r);
00072   }
00073   for (int c = 0; c < 2; ++c)
00074     (t12_matrix_)(2,c) = 0;
00075   (t12_matrix_)(2,2) = 1;
00076 }
00077 
00078 
00079 // == OPERATIONS ==
00080 
00081 template <class T>
00082 vgl_homg_point_2d<T>
00083 vgl_h_matrix_2d<T>::operator()(vgl_homg_point_2d<T> const& p) const
00084 {
00085   vnl_vector_fixed<T,3> v2 = t12_matrix_ * vnl_vector_fixed<T,3>(p.x(), p.y(), p.w());
00086   return vgl_homg_point_2d<T>(v2[0], v2[1], v2[2]);
00087 }
00088 
00089 template <class T>
00090 vgl_homg_line_2d<T>
00091 vgl_h_matrix_2d<T>::correlation(vgl_homg_point_2d<T> const& p) const
00092 {
00093   vnl_vector_fixed<T,3> v2 = t12_matrix_ * vnl_vector_fixed<T,3>(p.x(), p.y(), p.w());
00094   return vgl_homg_line_2d<T>(v2[0], v2[1], v2[2]);
00095 }
00096 
00097 template <class T>
00098 vgl_homg_line_2d<T>
00099 vgl_h_matrix_2d<T>::preimage(vgl_homg_line_2d<T> const& l) const
00100 {
00101   vnl_vector_fixed<T,3> v2 = t12_matrix_.transpose() * vnl_vector_fixed<T,3>(l.a(), l.b(), l.c());
00102   return vgl_homg_line_2d<T>(v2[0], v2[1], v2[2]);
00103 }
00104 
00105 template <class T>
00106 vgl_homg_point_2d<T>
00107 vgl_h_matrix_2d<T>::correlation(vgl_homg_line_2d<T> const& l) const
00108 {
00109   vnl_vector_fixed<T,3> v2 = t12_matrix_ * vnl_vector_fixed<T,3>(l.a(), l.b(), l.c());
00110   return vgl_homg_point_2d<T>(v2[0], v2[1], v2[2]);
00111 }
00112 
00113 template <class T>
00114 vgl_conic<T>
00115 vgl_h_matrix_2d<T>::operator() (vgl_conic<T> const& C) const
00116 {
00117   T a=C.a(), b=C.b()/2, c = C.c(), d = C.d()/2, e = C.e()/2, f = C.f();
00118   vnl_matrix_fixed<T,3,3> M, Mp;
00119   M(0,0) = a;  M(0,1) = b;  M(0,2) = d;
00120   M(1,0) = b;  M(1,1) = c;  M(1,2) = e;
00121   M(2,0) = d;  M(2,1) = e;  M(2,2) = f;
00122   Mp = (t12_matrix_.transpose())*M*t12_matrix_;
00123   return   vgl_conic<T>(Mp(0,0),(Mp(0,1)+Mp(1,0)),Mp(1,1),(Mp(0,2)+Mp(2,0)),
00124                         (Mp(1,2)+Mp(2,1)), Mp(2,2));
00125 }
00126 
00127 template <class T>
00128 vgl_conic<T>
00129 vgl_h_matrix_2d<T>::preimage(vgl_conic<T> const& C) const
00130 {
00131   T a=C.a(), b=C.b()/2, c = C.c(), d = C.d()/2, e = C.e()/2, f = C.f();
00132   vnl_matrix_fixed<T,3,3> M, Mp;
00133   M(0,0) = a;  M(0,1) = b;  M(0,2) = d;
00134   M(1,0) = b;  M(1,1) = c;  M(1,2) = e;
00135   M(2,0) = d;  M(2,1) = e;  M(2,2) = f;
00136   Mp = vnl_inverse_transpose(t12_matrix_)*M*vnl_inverse(t12_matrix_);
00137   return   vgl_conic<T>(Mp(0,0),(Mp(0,1)+Mp(1,0)),Mp(1,1),(Mp(0,2)+Mp(2,0)),
00138                         (Mp(1,2)+Mp(2,1)), Mp(2,2));
00139 }
00140 
00141 
00142 template <class T>
00143 vgl_homg_point_2d<T>
00144 vgl_h_matrix_2d<T>::preimage(vgl_homg_point_2d<T> const& p) const
00145 {
00146   vnl_vector_fixed<T,3> v = vnl_inverse(t12_matrix_) * vnl_vector_fixed<T,3>(p.x(), p.y(), p.w());
00147   return vgl_homg_point_2d<T>(v[0], v[1], v[2]);
00148 }
00149 
00150 template <class T>
00151 vgl_homg_line_2d<T>
00152 vgl_h_matrix_2d<T>::operator()(vgl_homg_line_2d<T> const& l) const
00153 {
00154   vnl_vector_fixed<T,3> v = vnl_inverse_transpose(t12_matrix_) * vnl_vector_fixed<T,3>(l.a(), l.b(), l.c());
00155   return vgl_homg_line_2d<T>(v[0], v[1], v[2]);
00156 }
00157 
00158 template <class T>
00159 vcl_ostream& operator<<(vcl_ostream& s, vgl_h_matrix_2d<T> const& h)
00160 {
00161   return s << h.get_matrix();
00162 }
00163 
00164 template <class T>
00165 bool vgl_h_matrix_2d<T>::read(vcl_istream& s)
00166 {
00167   t12_matrix_.read_ascii(s);
00168   return s.good() || s.eof();
00169 }
00170 
00171 template <class T>
00172 bool vgl_h_matrix_2d<T>::read(char const* filename)
00173 {
00174   vcl_ifstream f(filename);
00175   if (!f.good())
00176     vcl_cerr << "vgl_h_matrix_2d::read: Error opening " << filename << vcl_endl;
00177   return read(f);
00178 }
00179 
00180 // == DATA ACCESS ==
00181 
00182 template <class T>
00183 T vgl_h_matrix_2d<T>::get(unsigned int row_index, unsigned int col_index) const
00184 {
00185   return t12_matrix_. get(row_index, col_index);
00186 }
00187 
00188 template <class T>
00189 void vgl_h_matrix_2d<T>::get(T* H) const
00190 {
00191   for (T const* iter = t12_matrix_.begin(); iter < t12_matrix_.end(); ++iter)
00192     *H++ = *iter;
00193 }
00194 
00195 template <class T>
00196 void vgl_h_matrix_2d<T>::get(vnl_matrix_fixed<T,3,3>* H) const
00197 {
00198   *H = t12_matrix_;
00199 }
00200 
00201 template <class T>
00202 void vgl_h_matrix_2d<T>::get(vnl_matrix<T>* H) const
00203 {
00204   VXL_DEPRECATED("vgl_h_matrix_2d<T>::get(vnl_matrix<T>*) const"); 
00205   *H = t12_matrix_.as_ref(); // size 3x3
00206 }
00207 
00208 template <class T>
00209 vgl_h_matrix_2d<T>&
00210 vgl_h_matrix_2d<T>::set_identity()
00211 {
00212   t12_matrix_.set_identity();
00213   return *this;
00214 }
00215 
00216 template <class T>
00217 vgl_h_matrix_2d<T>&
00218 vgl_h_matrix_2d<T>::set(const T* H)
00219 {
00220   for (T* iter = t12_matrix_.begin(); iter < t12_matrix_.end(); ++iter)
00221     *iter = *H++;
00222   return *this;
00223 }
00224 
00225 template <class T>
00226 vgl_h_matrix_2d<T>&
00227 vgl_h_matrix_2d<T>::set(vnl_matrix_fixed<T,3,3> const& H)
00228 {
00229   t12_matrix_ = H;
00230   return *this;
00231 }
00232 
00233 //-------------------------------------------------------------------
00234 template <class T>
00235 bool vgl_h_matrix_2d<T>::
00236 projective_basis(vcl_vector<vgl_homg_point_2d<T> > const& points)
00237 {
00238   if (points.size()!=4)
00239     return false;
00240   vnl_vector_fixed<T,3> p0(points[0].x(), points[0].y(), points[0].w());
00241   vnl_vector_fixed<T,3> p1(points[1].x(), points[1].y(), points[1].w());
00242   vnl_vector_fixed<T,3> p2(points[2].x(), points[2].y(), points[2].w());
00243   vnl_vector_fixed<T,3> p3(points[3].x(), points[3].y(), points[3].w());
00244   vnl_matrix_fixed<T,3,4> point_matrix;
00245   point_matrix.set_column(0, p0);
00246   point_matrix.set_column(1, p1);
00247   point_matrix.set_column(2, p2);
00248   point_matrix.set_column(3, p3);
00249 
00250   if (! point_matrix.is_finite() || point_matrix.has_nans())
00251   {
00252     vcl_cerr << "vgl_h_matrix_2d<T>::projective_basis():\n"
00253              << " given points have infinite or NaN values\n";
00254     this->set_identity();
00255     return false;
00256   }
00257   vnl_svd<T> svd1(point_matrix.as_ref(), 1e-8); // size 3x4
00258   if (svd1.rank() < 3)
00259   {
00260     vcl_cerr << "vgl_h_matrix_2d<T>::projective_basis():\n"
00261              << " At least three out of the four points are nearly collinear\n";
00262     this->set_identity();
00263     return false;
00264   }
00265 
00266   vnl_matrix_fixed<T,3,3> back_matrix;
00267   back_matrix.set_column(0, p0);
00268   back_matrix.set_column(1, p1);
00269   back_matrix.set_column(2, p2);
00270 
00271   vnl_vector_fixed<T,3> scales_vector = vnl_inverse(back_matrix) * p3;
00272 
00273   back_matrix.set_column(0, scales_vector[0] * p0);
00274   back_matrix.set_column(1, scales_vector[1] * p1);
00275   back_matrix.set_column(2, scales_vector[2] * p2);
00276 
00277   if (! back_matrix.is_finite() || back_matrix.has_nans())
00278   {
00279     vcl_cerr << "vgl_h_matrix_2d<T>::projective_basis():\n"
00280              << " back matrix has infinite or NaN values\n";
00281     this->set_identity();
00282     return false;
00283   }
00284   this->set(vnl_inverse(back_matrix));
00285   return true;
00286 }
00287 
00288 template <class T>
00289 bool vgl_h_matrix_2d<T>::is_rotation() const
00290 {
00291   return t12_matrix_.get(0,2) == (T)0
00292       && t12_matrix_.get(1,2) == (T)0
00293       && this->is_euclidean();
00294 }
00295 
00296 template <class T>
00297 bool vgl_h_matrix_2d<T>::is_euclidean() const
00298 {
00299   if ( t12_matrix_.get(2,0) != (T)0 ||
00300        t12_matrix_.get(2,1) != (T)0 ||
00301        t12_matrix_.get(2,2) != (T)1 )
00302     return false; // should not have a translation part
00303 
00304   // use an error tolerance on the orthonormality constraint
00305   vnl_matrix_fixed<T,2,2> R = get_upper_2x2_matrix();
00306   R *= R.transpose();
00307   R(0,0) -= T(1);
00308   R(1,1) -= T(1);
00309   return R.absolute_value_max() <= 10*vcl_numeric_limits<T>::epsilon();
00310 }
00311 
00312 template <class T>
00313 bool vgl_h_matrix_2d<T>::is_identity() const
00314 {
00315   return t12_matrix_.is_identity();
00316 }
00317 
00318 //-------------------------------------------------------------------
00319 template <class T>
00320 bool vgl_h_matrix_2d<T>::projective_basis(vcl_vector<vgl_homg_line_2d<T> > const& lines
00321 #ifdef VCL_VC_6
00322                                          ,int dummy // parameter to help useless compiler disambiguate different functions
00323 #endif
00324                                          )
00325 {
00326   if (lines.size()!=4)
00327     return false;
00328   vnl_vector_fixed<T,3> l0(lines[0].a(), lines[0].b(), lines[0].c());
00329   vnl_vector_fixed<T,3> l1(lines[1].a(), lines[1].b(), lines[1].c());
00330   vnl_vector_fixed<T,3> l2(lines[2].a(), lines[2].b(), lines[2].c());
00331   vnl_vector_fixed<T,3> l3(lines[3].a(), lines[3].b(), lines[3].c());
00332   vnl_matrix_fixed<T,3,4> line_matrix;
00333   line_matrix.set_column(0, l0);
00334   line_matrix.set_column(1, l1);
00335   line_matrix.set_column(2, l2);
00336   line_matrix.set_column(3, l3);
00337 
00338   if (! line_matrix.is_finite() || line_matrix.has_nans())
00339   {
00340     vcl_cerr << "vgl_h_matrix_2d<T>::projective_basis():\n"
00341              << " given lines have infinite or NaN values\n";
00342     this->set_identity();
00343     return false;
00344   }
00345   vnl_svd<T> svd1(line_matrix.as_ref(), 1e-8); // size 3x4
00346   if (svd1.rank() < 3)
00347   {
00348     vcl_cerr << "vgl_h_matrix_2d<T>::projective_basis():\n"
00349              << " At least three out of the four lines are nearly concurrent\n";
00350     this->set_identity();
00351     return false;
00352   }
00353 
00354   vnl_matrix_fixed<T,3,3> back_matrix;
00355   back_matrix.set_column(0, l0);
00356   back_matrix.set_column(1, l1);
00357   back_matrix.set_column(2, l2);
00358   vnl_vector_fixed<T,3> scales_vector = vnl_inverse(back_matrix) * l3;
00359   back_matrix.set_row(0, scales_vector[0] * l0);
00360   back_matrix.set_row(1, scales_vector[1] * l1);
00361   back_matrix.set_row(2, scales_vector[2] * l2);
00362 
00363   if (! back_matrix.is_finite() || back_matrix.has_nans())
00364   {
00365     vcl_cerr << "vgl_h_matrix_2d<T>::projective_basis():\n"
00366              << " back matrix has infinite or NaN values\n";
00367     this->set_identity();
00368     return false;
00369   }
00370   this->set(back_matrix);
00371   return true;
00372 }
00373 
00374 template <class T>
00375 vgl_h_matrix_2d<T>
00376 vgl_h_matrix_2d<T>::get_inverse() const
00377 {
00378   return vgl_h_matrix_2d<T>(vnl_inverse(t12_matrix_));
00379 }
00380 
00381 
00382 template <class T>
00383 vgl_h_matrix_2d<T>&
00384 vgl_h_matrix_2d<T>::set_translation(T tx, T ty)
00385 {
00386   t12_matrix_[0][2] = tx;   t12_matrix_[1][2] = ty;
00387   return *this;
00388 }
00389 
00390 template <class T>
00391 vgl_h_matrix_2d<T>&
00392 vgl_h_matrix_2d<T>::set_rotation(T theta)
00393 {
00394   double theta_d = (double)theta;
00395   double c = vcl_cos(theta_d), s = vcl_sin(theta_d);
00396   t12_matrix_[0][0] = (T)c;   t12_matrix_[0][1] = -(T)s;
00397   t12_matrix_[1][0] = (T)s;   t12_matrix_[1][1] = (T)c;
00398   return *this;
00399 }
00400 
00401 template <class T>
00402 vgl_h_matrix_2d<T>&
00403 vgl_h_matrix_2d<T>::set_scale(T scale)
00404 {
00405   for (unsigned r = 0; r<2; ++r)
00406     for (unsigned c = 0; c<3; ++c)
00407       t12_matrix_[r][c]*=scale;
00408   return *this;
00409 }
00410 
00411 template <class T>
00412 vgl_h_matrix_2d<T>&
00413 vgl_h_matrix_2d<T>::set_similarity(T s, T theta,
00414                                    T tx, T ty)
00415 {
00416   T a=s*vcl_cos(theta);
00417   T b=s*vcl_sin(theta);
00418   t12_matrix_[0][0] = a; t12_matrix_[0][1] = -b; t12_matrix_[0][2] = tx;
00419   t12_matrix_[1][0] = b; t12_matrix_[1][1] =  a; t12_matrix_[1][2] = ty;
00420   t12_matrix_[2][0]=T(0); t12_matrix_[2][1]=T(0); t12_matrix_[2][2] = T(1);
00421   return *this;
00422 }
00423 
00424 template <class T>
00425 vgl_h_matrix_2d<T>&
00426 vgl_h_matrix_2d<T>::set_aspect_ratio(T aspect_ratio)
00427 {
00428   for (unsigned c = 0; c<3; ++c)
00429     t12_matrix_[1][c]*=aspect_ratio;
00430   return *this;
00431 }
00432 
00433 
00434 template <class T>
00435 vgl_h_matrix_2d<T>&
00436 vgl_h_matrix_2d<T>::set_affine(vnl_matrix_fixed<T,2,3> const& M23)
00437 {
00438   for (unsigned r = 0; r<2; ++r)
00439     for (unsigned c = 0; c<3; ++c)
00440       t12_matrix_[r][c] = M23[r][c];
00441   t12_matrix_[2][0] = T(0); t12_matrix_[2][1] = T(0);  t12_matrix_[2][2] = T(1);
00442   return *this;
00443 }
00444 
00445 template <class T>
00446 vgl_h_matrix_2d<T>&
00447 vgl_h_matrix_2d<T>::set_affine(vnl_matrix<T> const& M23)
00448 {
00449   VXL_DEPRECATED("vgl_h_matrix_2d<T>::set_affine(vnl_matrix<T> const&)"); 
00450   assert (M23.rows()==2 && M23.columns()==3);
00451   for (unsigned r = 0; r<2; ++r)
00452     for (unsigned c = 0; c<3; ++c)
00453       t12_matrix_[r][c] = M23[r][c];
00454   t12_matrix_[2][0] = T(0); t12_matrix_[2][1] = T(0);  t12_matrix_[2][2] = T(1);
00455   return *this;
00456 }
00457 
00458 template <class T>
00459 vgl_h_matrix_2d<T>
00460 vgl_h_matrix_2d<T>::get_upper_2x2() const
00461 {
00462   //only sensible for affine transformations
00463   T d = t12_matrix_[2][2];
00464   assert(d<-1e-9 || d>1e-9);
00465   vnl_matrix_fixed<T,3,3> m(0.0);
00466   for (unsigned r = 0; r<2; ++r)
00467     for (unsigned c = 0; c<2; ++c)
00468       m[r][c] = t12_matrix_[r][c]/d;
00469   m[2][2]=1.0;
00470   return vgl_h_matrix_2d<T>(m);
00471 }
00472 
00473 template <class T>
00474 vnl_matrix_fixed<T,2,2>
00475 vgl_h_matrix_2d<T>::get_upper_2x2_matrix() const
00476 {
00477   vnl_matrix_fixed<T,2,2> R;
00478   vgl_h_matrix_2d<T> m = this->get_upper_2x2();
00479   for (unsigned r = 0; r<3; ++r)
00480     for (unsigned c = 0; c<3; ++c)
00481       R[r][c] = m.get(r,c);
00482   return R;
00483 }
00484 
00485 template <class T>
00486 vgl_homg_point_2d<T>
00487 vgl_h_matrix_2d<T>::get_translation() const
00488 {
00489   //only sensible for affine transformations
00490   T d = t12_matrix_[2][2];
00491   assert(d<-1e-9 || d>1e-9);
00492   return vgl_homg_point_2d<T>(t12_matrix_[0][2]/d,
00493                               t12_matrix_[1][2]/d,
00494                               (T)1);
00495 }
00496 
00497 template <class T>
00498 vnl_vector_fixed<T,2>
00499 vgl_h_matrix_2d<T>::get_translation_vector() const
00500 {
00501   vgl_homg_point_2d<T> p = this->get_translation();
00502   return vnl_vector_fixed<T,2>(p.x(), p.y());
00503 }
00504 
00505 //----------------------------------------------------------------------------
00506 #undef VGL_H_MATRIX_2D_INSTANTIATE
00507 #define VGL_H_MATRIX_2D_INSTANTIATE(T) \
00508 template class vgl_h_matrix_2d<T >; \
00509 template vcl_ostream& operator << (vcl_ostream& s, vgl_h_matrix_2d<T > const& h); \
00510 template vcl_istream& operator >> (vcl_istream& s, vgl_h_matrix_2d<T >& h)
00511 
00512 #endif // vgl_h_matrix_2d_txx_