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