core/vgl/algo/vgl_h_matrix_3d.txx
Go to the documentation of this file.
00001 // This is core/vgl/algo/vgl_h_matrix_3d.txx
00002 #ifndef vgl_h_matrix_3d_txx_
00003 #define vgl_h_matrix_3d_txx_
00004 //:
00005 // \file
00006 
00007 #include "vgl_h_matrix_3d.h"
00008 #include <vcl_iostream.h>
00009 #include <vcl_fstream.h>
00010 #include <vcl_cmath.h>
00011 #include <vcl_limits.h>
00012 #include <vcl_cassert.h>
00013 #include <vcl_cstdlib.h> // for exit()
00014 #include <vnl/vnl_inverse.h>
00015 #include <vnl/vnl_numeric_traits.h>
00016 #include <vnl/vnl_vector_fixed.h>
00017 #include <vnl/vnl_quaternion.h>
00018 #include <vnl/algo/vnl_svd.h>
00019 
00020 //--------------------------------------------------------------
00021 //
00022 //: Copy constructor
00023 template <class T>
00024 vgl_h_matrix_3d<T>::vgl_h_matrix_3d(vgl_h_matrix_3d<T> const& M)
00025 {
00026   t12_matrix_ = M.t12_matrix_;
00027 }
00028 
00029 //--------------------------------------------------------------
00030 //
00031 //: Constructor
00032 template <class T>
00033 vgl_h_matrix_3d<T>::vgl_h_matrix_3d(vnl_matrix_fixed<T, 4, 4> const& M)
00034 {
00035   t12_matrix_ = M;
00036 }
00037 
00038 //--------------------------------------------------------------
00039 //
00040 //: Constructor - calculate homography between two sets of 3D points (minimum 5)
00041 template <class T>
00042 vgl_h_matrix_3d<T>::vgl_h_matrix_3d(vcl_vector<vgl_homg_point_3d<T> > const& points1,
00043                                     vcl_vector<vgl_homg_point_3d<T> > const& points2)
00044 {
00045   vnl_matrix<T> W;
00046   assert(points1.size() == points2.size());
00047   unsigned int numpoints = points1.size();
00048   if (numpoints < 5)
00049   {
00050     vcl_cerr << "\nvhl_h_matrix_3d - minimum of 5 points required\n";
00051     vcl_exit(0);
00052   }
00053 
00054   W.set_size(3*numpoints, 16);
00055 
00056   for (unsigned int i = 0; i < numpoints; i++)
00057   {
00058     T x1 = points1[i].x(), y1 = points1[i].y(), z1 = points1[i].z(), w1 = points1[i].w();
00059     T x2 = points2[i].x(), y2 = points2[i].y(), z2 = points2[i].z(), w2 = points2[i].w();
00060 
00061     W[i*3][0]=x1*w2;     W[i*3][1]=y1*w2;     W[i*3][2]=z1*w2;     W[i*3][3]=w1*w2;
00062     W[i*3][4]=0.0;       W[i*3][5]=0.0;       W[i*3][6]=0.0;       W[i*3][7]=0.0;
00063     W[i*3][8]=0.0;       W[i*3][9]=0.0;       W[i*3][10]=0.0;      W[i*3][11]=0.0;
00064     W[i*3][12]=-x1*x2;   W[i*3][13]=-y1*x2;   W[i*3][14]=-z1*x2;   W[i*3][15]=-w1*x2;
00065 
00066     W[i*3+1][0]=0.0;     W[i*3+1][1]=0.0;     W[i*3+1][2]=0.0;     W[i*3+1][3]=0.0;
00067     W[i*3+1][4]=x1*w2;   W[i*3+1][5]=y1*w2;   W[i*3+1][6]=z1*w2;   W[i*3+1][7]=w1*w2;
00068     W[i*3+1][8]=0.0;     W[i*3+1][9]=0.0;     W[i*3+1][10]=0.0;    W[i*3+1][11]=0.0;
00069     W[i*3+1][12]=-x1*y2; W[i*3+1][13]=-y1*y2; W[i*3+1][14]=-z1*y2; W[i*3+1][15]=-w1*y2;
00070 
00071     W[i*3+2][0]=0.0;     W[i*3+2][1]=0.0;     W[i*3+2][2]=0.0;     W[i*3+2][3]=0.0;
00072     W[i*3+2][4]=0.0;     W[i*3+2][5]=0.0;     W[i*3+2][6]=0.0;     W[i*3+2][7]=0.0;
00073     W[i*3+2][8]=x1*w2;   W[i*3+2][9]=y1*w2;   W[i*3+2][10]=z1*w2;  W[i*3+2][11]=w1*w2;
00074     W[i*3+2][12]=-x1*z2; W[i*3+2][13]=-y1*z2; W[i*3+2][14]=-z1*z2; W[i*3+2][15]=-w1*z2;
00075   }
00076 
00077   vnl_svd<T> SVD(W);
00078   t12_matrix_ = vnl_matrix<T>(SVD.nullvector().data_block(), 4, 4);
00079 }
00080 
00081 //--------------------------------------------------------------
00082 //
00083 //: Load H from ASCII vcl_istream.
00084 template <class T>
00085 vgl_h_matrix_3d<T>::vgl_h_matrix_3d(vcl_istream& s)
00086 {
00087   read(s);
00088 }
00089 
00090 //--------------------------------------------------------------
00091 //
00092 //: Load from file
00093 template <class T>
00094 vgl_h_matrix_3d<T>::vgl_h_matrix_3d(char const* filename)
00095 {
00096   vcl_ifstream f(filename);
00097   if (!f.good())
00098     vcl_cerr << "vgl_h_matrix_3d::read: Error opening " << filename << vcl_endl;
00099   else
00100     t12_matrix_.read_ascii(f);
00101 }
00102 
00103 //--------------------------------------------------------------
00104 //
00105 //: Construct an affine vgl_h_matrix_3d from 3x3 M and 3x1 m.
00106 //
00107 template <class T>
00108 vgl_h_matrix_3d<T>::vgl_h_matrix_3d(vnl_matrix_fixed<T,3,3> const& M,
00109                                     vnl_vector_fixed<T,3> const& m)
00110 {
00111   for (int r = 0; r < 3; ++r) {
00112     for (int c = 0; c < 3; ++c)
00113       (t12_matrix_)(r, c) = M(r,c);
00114     (t12_matrix_)(r, 3) = m(r);
00115   }
00116   for (int c = 0; c < 3; ++c)
00117     (t12_matrix_)(3,c) = 0;
00118   (t12_matrix_)(3,3) = 1;
00119 }
00120 
00121 //--------------------------------------------------------------
00122 //
00123 //: Construct from a 16-element row-storage array of double.
00124 template <class T>
00125 vgl_h_matrix_3d<T>::vgl_h_matrix_3d (T const* t_matrix)
00126   : t12_matrix_ (t_matrix)
00127 {
00128 }
00129 
00130 // == OPERATIONS ==
00131 
00132 //-----------------------------------------------------------------------------
00133 //
00134 //:return the transformed point
00135 template <class T>
00136 vgl_homg_point_3d<T>
00137 vgl_h_matrix_3d<T>::operator()(vgl_homg_point_3d<T> const& x) const
00138 {
00139   vnl_vector_fixed<T, 4> v;
00140   v[0]=x.x();  v[1]=x.y();   v[2]=x.z();   v[3]=x.w();
00141   vnl_vector_fixed<T,4> v2 = t12_matrix_ * v;
00142   return vgl_homg_point_3d<T>(v2[0], v2[1], v2[2], v2[3]);
00143 }
00144 
00145 //-----------------------------------------------------------------------------
00146 //
00147 //: Return the preimage of a transformed plane
00148 template <class T>
00149 vgl_homg_plane_3d<T>
00150 vgl_h_matrix_3d<T>::preimage(vgl_homg_plane_3d<T> const& p)
00151 {
00152   vnl_vector_fixed<T, 4> v;
00153   v[0]=p.a();  v[1]=p.b();   v[2]=p.c();   v[3]=p.d();
00154   vnl_vector_fixed<T,4> v2 = (t12_matrix_.transpose()) * v;
00155   return vgl_homg_plane_3d<T>(v2[0], v2[1], v2[2], v2[3]);
00156 }
00157 
00158 //-----------------------------------------------------------------------------
00159 //
00160 //: Return the preimage of a transformed point (requires an inverse)
00161 template <class T>
00162 vgl_homg_point_3d<T>
00163 vgl_h_matrix_3d<T>::preimage(vgl_homg_point_3d<T> const& x) const
00164 {
00165   vnl_vector_fixed<T, 4> v;
00166   v[0]=x.x();  v[1]=x.y();   v[2]=x.z();   v[3]=x.w();
00167   v = vnl_inverse(t12_matrix_) * v;
00168   return vgl_homg_point_3d<T>(v[0], v[1], v[2], v[3]);
00169 }
00170 
00171 //-----------------------------------------------------------------------------
00172 //
00173 //: Transform a plane (requires an inverse)
00174 template <class T>
00175 vgl_homg_plane_3d<T>
00176 vgl_h_matrix_3d<T>::operator()(vgl_homg_plane_3d<T> const& p) const
00177 {
00178   vnl_vector_fixed<T, 4> v;
00179   v[0]=p.a();  v[1]=p.b();   v[2]=p.c();   v[3]=p.d();
00180   v = vnl_inverse_transpose(t12_matrix_) * v;
00181   return vgl_homg_plane_3d<T>(v[0], v[1], v[2], v[3]);
00182 }
00183 
00184 //-----------------------------------------------------------------------------
00185 //
00186 //: Print H on vcl_ostream
00187 template <class T>
00188 vcl_ostream& operator<<(vcl_ostream& s, vgl_h_matrix_3d<T> const& h)
00189 {
00190   return s << h.get_matrix();
00191 }
00192 
00193 //: Load H from ASCII file.
00194 template <class T>
00195 bool vgl_h_matrix_3d<T>::read(vcl_istream& s)
00196 {
00197   t12_matrix_.read_ascii(s);
00198   return s.good() || s.eof();
00199 }
00200 
00201 //: Load H from ASCII file.
00202 template <class T>
00203 vcl_istream& operator>>(vcl_istream& s, vgl_h_matrix_3d<T>& H)
00204 {
00205   H.read(s);
00206   return s;
00207 }
00208 
00209 // == DATA ACCESS ==
00210 
00211 //-----------------------------------------------------------------------------
00212 //
00213 //: Get matrix element at (row_index, col_index)
00214 template <class T>
00215 T vgl_h_matrix_3d<T>::get (unsigned int row_index, unsigned int col_index) const
00216 {
00217   return t12_matrix_.get(row_index, col_index);
00218 }
00219 
00220 //-----------------------------------------------------------------------------
00221 //
00222 //: Fill t_matrix with contents of H
00223 template <class T>
00224 void vgl_h_matrix_3d<T>::get (T* t_matrix) const
00225 {
00226   for (int row_index = 0; row_index < 4; row_index++)
00227     for (int col_index = 0; col_index < 4; col_index++)
00228       *t_matrix++ = t12_matrix_.get(row_index, col_index);
00229 }
00230 
00231 //-----------------------------------------------------------------------------
00232 //
00233 //: Fill t_matrix with contents of H
00234 template <class T>
00235 void vgl_h_matrix_3d<T>::get (vnl_matrix_fixed<T, 4, 4>* t_matrix) const
00236 {
00237   *t_matrix = t12_matrix_;
00238 }
00239 
00240 //-----------------------------------------------------------------------------
00241 //
00242 //: Return the inverse of this vgl_h_matrix_3d<T>.
00243 template <class T>
00244 vgl_h_matrix_3d<T> vgl_h_matrix_3d<T>::get_inverse() const
00245 {
00246   vnl_matrix_fixed<T, 4, 4> temp = vnl_inverse(t12_matrix_);
00247   return vgl_h_matrix_3d<T>(temp);
00248 }
00249 
00250 //: Set to 4x4 row-stored matrix
00251 //
00252 template <class T>
00253 void vgl_h_matrix_3d<T>::set (T const* H)
00254 {
00255   for (int row_index = 0; row_index < 4; row_index++)
00256     for (int col_index = 0; col_index < 4; col_index++)
00257       t12_matrix_. put (row_index, col_index, *H++);
00258 }
00259 
00260 //: Set to given vnl_matrix
00261 //
00262 template <class T>
00263 void vgl_h_matrix_3d<T>::set (vnl_matrix_fixed<T,4,4> const& H)
00264 {
00265   t12_matrix_ = H;
00266 }
00267 
00268 //: Compute transform to projective basis given five points, no 4 coplanar
00269 //
00270 template <class T>
00271 bool vgl_h_matrix_3d<T>::
00272 projective_basis(vcl_vector<vgl_homg_point_3d<T> > const& /*five_points*/)
00273 {
00274   vcl_cerr << "vgl_h_matrix_3d<T>::projective_basis(5pts) not yet implemented\n";
00275   return false;
00276 }
00277 
00278 //: Set to identity
00279 //
00280 template <class T>
00281 void vgl_h_matrix_3d<T>::set_identity ()
00282 {
00283   t12_matrix_.set_identity();
00284 }
00285 
00286 //: Set to translation
00287 //
00288 template <class T>
00289 void vgl_h_matrix_3d<T>::set_translation(T tx, T ty, T tz)
00290 {
00291   (t12_matrix_)(0, 3)  = tx;
00292   (t12_matrix_)(1, 3)  = ty;
00293   (t12_matrix_)(2, 3)  = tz;
00294 }
00295 
00296 //: Set to rotation about an axis
00297 //
00298 template <class T>
00299 void vgl_h_matrix_3d<T>::
00300 set_rotation_about_axis(vnl_vector_fixed<T,3> const& axis, T angle)
00301 {
00302   vnl_quaternion<T> q(axis, angle);
00303   //get the transpose of the rotation matrix
00304   vnl_matrix_fixed<T,3,3> R = q.rotation_matrix_transpose();
00305   //fill in with the transpose
00306   for (int c = 0; c<3; c++)
00307     for (int r = 0; r<3; r++)
00308       t12_matrix_[r][c]=R[c][r];
00309 }
00310 
00311 //: Set to roll, pitch and yaw specified rotation.
00312 // - roll is rotation about z
00313 // - pitch is rotation about y
00314 // - yaw is rotation about x
00315 //
00316 template <class T>
00317 void vgl_h_matrix_3d<T>::
00318 set_rotation_roll_pitch_yaw(T yaw, T pitch, T roll)
00319 {
00320   typedef typename vnl_numeric_traits<T>::real_t real_t;
00321   real_t ax = yaw/2, ay = pitch/2, az = roll/2;
00322 
00323   vnl_quaternion<T> qx((T)vcl_sin(ax),0,0,(T)vcl_cos(ax));
00324   vnl_quaternion<T> qy(0,(T)vcl_sin(ay),0,(T)vcl_cos(ay));
00325   vnl_quaternion<T> qz(0,0,(T)vcl_sin(az),(T)vcl_cos(az));
00326   vnl_quaternion<T> q = qz*qy*qx;
00327 
00328   vnl_matrix_fixed<T,3,3> R = q.rotation_matrix_transpose();
00329   //fill in with the transpose
00330   for (int c = 0; c<3; c++)
00331     for (int r = 0; r<3; r++)
00332       t12_matrix_[r][c]=R[c][r];
00333 }
00334 
00335 //: Set to rotation specified by Euler angles
00336 //
00337 template <class T>
00338 void vgl_h_matrix_3d<T>::
00339 set_rotation_euler(T rz1, T ry, T rz2)
00340 {
00341   typedef typename vnl_numeric_traits<T>::real_t real_t;
00342   real_t az1 = rz1/2, ay = ry/2, az2 = rz2/2;
00343 
00344   vnl_quaternion<T> qz1(0,0,T(vcl_sin(az1)),T(vcl_cos(az1)));
00345   vnl_quaternion<T> qy(0,T(vcl_sin(ay)),0,T(vcl_cos(ay)));
00346   vnl_quaternion<T> qz2(0,0,T(vcl_sin(az2)),T(vcl_cos(az2)));
00347   vnl_quaternion<T> q = qz2*qy*qz1;
00348 
00349   vnl_matrix_fixed<T,3,3> R = q.rotation_matrix_transpose();
00350   //fill in with the transpose
00351   for (int c = 0; c<3; c++)
00352     for (int r = 0; r<3; r++)
00353       t12_matrix_[r][c]=R[c][r];
00354 }
00355 
00356 template <class T>
00357 void 
00358 vgl_h_matrix_3d<T>::set_rotation_matrix(vnl_matrix_fixed<T, 3, 3> const& R)
00359 {
00360   for (unsigned r = 0; r<3; ++r)
00361     for (unsigned c = 0; c<3; ++c)
00362       t12_matrix_[r][c] = R[r][c];
00363 }
00364 
00365 template <class T>
00366 bool vgl_h_matrix_3d<T>::is_rotation() const
00367 {
00368   const vnl_matrix_fixed<T,4,4>& H = t12_matrix_;
00369   return H.get(0,3) == (T)0
00370       && H.get(1,3) == (T)0
00371       && H.get(2,3) == (T)0
00372       && this->is_euclidean();
00373 }
00374 
00375 
00376 template <class T>
00377 bool vgl_h_matrix_3d<T>::is_euclidean() const
00378 {
00379   const vnl_matrix_fixed<T,4,4>& H = t12_matrix_;
00380   if ( H.get(3,0) == (T)0 &&
00381        H.get(3,1) == (T)0 &&
00382        H.get(3,2) == (T)0 &&
00383        H.get(3,3) == (T)1 )
00384   {
00385     // use an error tolerance on the orthonormality constraint
00386     vnl_matrix_fixed<T, 3,3> R = get_upper_3x3_matrix();
00387     R *= R.transpose();
00388     R(0,0) -= T(1);
00389     R(1,1) -= T(1);
00390     R(2,2) -= T(1);
00391     double absolute_error = R.absolute_value_max();
00392     if ( absolute_error <= 10*vcl_numeric_limits<T>::epsilon() )
00393       return true;
00394   }
00395   return false;
00396 }
00397 
00398 
00399 template <class T>
00400 vgl_h_matrix_3d<T> 
00401 vgl_h_matrix_3d<T>::get_upper_3x3() const
00402 {
00403   //only sensible for affine transformations
00404   double u = (double)t12_matrix_[3][3];
00405   assert(vcl_fabs(u)>1e-9);
00406   T d = static_cast<T>(u);
00407   vnl_matrix_fixed<T,4,4> m(0.0);
00408   for (unsigned r = 0; r<3; r++)
00409     for (unsigned c = 0; c<3; c++)
00410       m[r][c] = t12_matrix_[r][c]/d;
00411   m[3][3]=1.0;
00412   return vgl_h_matrix_3d<T>(m);
00413 }
00414 
00415 template <class T>
00416 vnl_matrix_fixed<T, 3,3> vgl_h_matrix_3d<T>::get_upper_3x3_matrix() const
00417 {
00418   vnl_matrix_fixed<T,3,3> R;
00419   vgl_h_matrix_3d<T> m = this->get_upper_3x3();
00420   for (unsigned r = 0; r<3; r++)
00421     for (unsigned c = 0; c<3; c++)
00422       R[r][c] = m.get(r,c);
00423   return R;
00424 }
00425 
00426 template <class T>
00427 vgl_homg_point_3d<T>
00428 vgl_h_matrix_3d<T>::get_translation() const
00429 {
00430   //only sensible for affine transformations
00431   double u = (double)t12_matrix_[3][3];
00432   assert(vcl_fabs(u)>1e-9);
00433   T d = static_cast<T>(u);
00434   return vgl_homg_point_3d<T>(t12_matrix_[0][3]/d,
00435                               t12_matrix_[1][3]/d,
00436                               t12_matrix_[2][3]/d
00437                               ,(T)1.0);
00438 }
00439 
00440 template <class T>
00441 vnl_vector_fixed<T, 3>
00442 vgl_h_matrix_3d<T>::get_translation_vector() const
00443 {
00444   vgl_homg_point_3d<T> p = this->get_translation();
00445   return vnl_vector_fixed<T,3>(p.x(), p.y(), p.z());
00446 }
00447 
00448 //----------------------------------------------------------------------------
00449 #undef VGL_H_MATRIX_3D_INSTANTIATE
00450 #define VGL_H_MATRIX_3D_INSTANTIATE(T) \
00451 template class vgl_h_matrix_3d<T >; \
00452 template vcl_ostream& operator<<(vcl_ostream&, vgl_h_matrix_3d<T > const& ); \
00453 template vcl_istream& operator>>(vcl_istream&, vgl_h_matrix_3d<T >& )
00454 
00455 #endif // vgl_h_matrix_3d_txx_