contrib/rpl/rgrl/rgrl_trans_homography2d.cxx
Go to the documentation of this file.
00001 #include "rgrl_trans_homography2d.h"
00002 //:
00003 // \file
00004 #include <vcl_cassert.h>
00005 
00006 #include <vnl/algo/vnl_svd.h>
00007 #include <vnl/vnl_inverse.h>
00008 #include <vnl/vnl_vector_fixed.h>
00009 #include <vnl/vnl_math.h>
00010 #include <vnl/vnl_double_2.h>
00011 #include <vnl/vnl_double_3.h>
00012 
00013 #include <rgrl/rgrl_util.h>
00014 
00015 rgrl_trans_homography2d::
00016 rgrl_trans_homography2d()
00017   : H_( 0.0 ),
00018     from_centre_( 0.0, 0.0 ),
00019     to_centre_( 0.0, 0.0 )
00020 {}
00021 
00022 rgrl_trans_homography2d::
00023 rgrl_trans_homography2d( vnl_matrix<double> const& H,
00024                          vnl_matrix<double> const& covar )
00025   : rgrl_transformation( covar ),
00026     H_( H ),
00027     from_centre_( 0.0, 0.0 ),
00028     to_centre_( 0.0, 0.0 )
00029 {
00030   assert( H.rows() == 3 );
00031   assert( H.cols() == 3 );
00032   assert( covar_.rows() == covar_.cols() );
00033   // assert( covar_.rows() == 3 );
00034 }
00035 
00036 rgrl_trans_homography2d::
00037 rgrl_trans_homography2d( vnl_matrix<double> const& H )
00038   : H_( H ),
00039     from_centre_( 0.0, 0.0 ),
00040     to_centre_( 0.0, 0.0 )
00041 {}
00042 
00043 rgrl_trans_homography2d::
00044 rgrl_trans_homography2d( vnl_matrix<double> const& H,
00045                          vnl_matrix<double> const& covar,
00046                          vnl_vector<double> const& from_centre,
00047                          vnl_vector<double> const& to_centre )
00048   : rgrl_transformation( covar ),
00049     from_centre_( from_centre ),
00050     to_centre_( to_centre )
00051 {
00052   assert( to_centre.size() == 2 );
00053 
00054   //Uncenter the H_ = to_matrix^-1 * H * from_matrix
00055   //
00056   //vnl_matrix<double> to_inv(3,3, vnl_matrix_identity);
00057   //to_inv(0,2) = to_centre[0];
00058   //to_inv(1,2) = to_centre[1];
00059   //
00060   //vnl_matrix<double> from_matrix(3,3, vnl_matrix_identity);
00061   //from_matrix(0,2) = -from_centre[0];
00062   //from_matrix(1,2) = -from_centre[1];
00063   //
00064   //H_ = to_inv * H * from_matrix;
00065   //from_centre_ = from_centre;
00066 
00067   H_ = H;
00068 }
00069 
00070 vnl_matrix_fixed<double, 3, 3>
00071 rgrl_trans_homography2d::
00072 H() const
00073 {
00074   return uncenter_H_matrix();
00075 }
00076 
00077 vnl_matrix_fixed<double, 3, 3>
00078 rgrl_trans_homography2d::
00079 uncenter_H_matrix( ) const
00080 {
00081   vnl_matrix_fixed<double, 3, 3> H;
00082 
00083   // uncenter To image
00084   vnl_matrix_fixed<double, 3, 3> to_inv;
00085   to_inv.set_identity();
00086   to_inv(0,2) = to_centre_[0];
00087   to_inv(1,2) = to_centre_[1];
00088 
00089   // uncenter From image
00090   vnl_matrix_fixed<double, 3, 3> from_matrix;
00091   from_matrix.set_identity();
00092   from_matrix(0,2) = -from_centre_[0];
00093   from_matrix(1,2) = -from_centre_[1];
00094 
00095   H = to_inv * H_ * from_matrix;
00096 
00097   return H;
00098 }
00099 
00100 vnl_matrix<double>
00101 rgrl_trans_homography2d::
00102 transfer_error_covar( vnl_vector<double> const& from_loc ) const
00103 {
00104   assert ( is_covar_set() );
00105   assert ( from_loc.size() ==2 );
00106 
00107   vnl_matrix_fixed<double, 2, 9 > jac;
00108   vnl_matrix_fixed<double, 3, 9 > jf(0.0); // homogeneous coordinate
00109   vnl_matrix_fixed<double, 2, 3 > jg(0.0); // inhomo, [u/w, v/w]^T
00110   vnl_double_3 from_homo( from_loc[0]-from_centre_[0],
00111                           from_loc[1]-from_centre_[1],
00112                           1.0 );
00113   // transform coordinate
00114   vnl_double_3 mapped_homo = H_ * from_homo;
00115 
00116   // homogeneous coordinate w.r.t homography parameters
00117   jf(0,0) = jf(1,3) = jf(2,6) = from_homo[0]; // x
00118   jf(0,1) = jf(1,4) = jf(2,7) = from_homo[1]; // y
00119   jf(0,2) = jf(1,5) = jf(2,8) = 1.0;
00120 
00121   // derivatives w.r.t division
00122   jg(0,0) = 1.0/mapped_homo[2];
00123   jg(0,2) = -mapped_homo[0]/vnl_math_sqr(mapped_homo[2]);
00124   jg(1,1) = 1.0/mapped_homo[2];
00125   jg(1,2) = -mapped_homo[1]/vnl_math_sqr(mapped_homo[2]);
00126 
00127   // since Jab_g(f(p)) = Jac_g * Jac_f
00128   jac = jg * jf;
00129 
00130   return jac * covar_ * jac.transpose();
00131 }
00132 
00133 //: Inverse map using pseudo-inverse of H_.
00134 void
00135 rgrl_trans_homography2d::
00136 inv_map( const vnl_vector<double>& to,
00137          vnl_vector<double>& from ) const
00138 {
00139   vnl_double_3 homo_to(to[0], to[1], 1.0);
00140 
00141   // apply inverse homography
00142   vnl_double_3 homo_from = vnl_inverse(uncenter_H_matrix()) * homo_to;
00143 
00144   from[0] = homo_from[0]/homo_from[2];
00145   from[1] = homo_from[1]/homo_from[2];
00146 
00147   return;
00148 }
00149 
00150 //:  Inverse map with an initial guess
00151 void
00152 rgrl_trans_homography2d::
00153 inv_map( const vnl_vector<double>& to,
00154          bool initialize_next,
00155          const vnl_vector<double>& to_delta,
00156          vnl_vector<double>& from,
00157          vnl_vector<double>& from_next_est) const
00158 {
00159   vnl_double_3 homo_to(to[0]-to_centre_[0], to[1]-to_centre_[1], 1.0);
00160 
00161   // apply inverse homography
00162   vnl_matrix_fixed<double, 3, 3> Hinv = vnl_inverse(H_);
00163   vnl_double_3 homo_from = Hinv * homo_to;
00164 
00165   from[0] = homo_from[0]/homo_from[2]+from_centre_[0];
00166   from[1] = homo_from[1]/homo_from[2]+from_centre_[1];
00167 
00168   if ( initialize_next ) {
00169     homo_to[0] += to_delta[0];
00170     homo_to[1] += to_delta[1];
00171     homo_from = Hinv * homo_to;
00172     from_next_est[0] = homo_from[0]/homo_from[2]+from_centre_[0];
00173     from_next_est[1] = homo_from[1]/homo_from[2]+from_centre_[1];
00174   }
00175 }
00176 
00177 //: Return an inverse transformation of the uncentered transform
00178 rgrl_transformation_sptr
00179 rgrl_trans_homography2d::
00180 inverse_transform() const
00181 {
00182   vnl_matrix_fixed<double,3,3> H_inv = vnl_inverse(H_);
00183   rgrl_transformation_sptr result =
00184     new rgrl_trans_homography2d( H_inv.as_ref(), vnl_matrix<double>(), to_centre_.as_ref(), from_centre_.as_ref() );
00185 
00186   const unsigned m = scaling_factors_.size();
00187   if ( m > 0 ) {
00188     vnl_vector<double> scaling( m );
00189     for ( unsigned int i=0; i<m; ++i )
00190       scaling[i] = 1.0 / scaling_factors_[i];
00191     result->set_scaling_factors( scaling );
00192   }
00193 
00194   return result;
00195 }
00196 
00197 //: Return the jacobian of the transform.
00198 vnl_matrix_fixed<double,2,3>
00199 rgrl_trans_homography2d::
00200 homo_jacobian( vnl_vector_fixed<double,2> const& from_loc ) const
00201 {
00202   // Let h_i be the i_th row of H_, and p be the homogeneous vector of from_loc
00203   // f_0(p) = h_0.p/h_2.p
00204   // f_1(p) = h_1.p/h_2.p
00205   // The jacobian is a 2x3 matrix with entries
00206   // [d(f_0)/dx   d(f_0)/dy   d(f_0)/dw;
00207   //  d(f_1)/dx   d(f_1)/dy   d(f_1)/dw]
00208   //
00209 
00210   vnl_vector_fixed<double,3> p(from_loc[0]-from_centre_[0], from_loc[1]-from_centre_[1], 1.0);
00211   vnl_vector_fixed<double,3> h_0 = H_.get_row(0);
00212   vnl_vector_fixed<double,3> h_1 = H_.get_row(1);
00213   vnl_vector_fixed<double,3> h_2 = H_.get_row(2);
00214   double inv_mapped_w = 1.0/dot_product(h_2, p);
00215   double mapped_x = dot_product(h_0, p)*inv_mapped_w;
00216   double mapped_y = dot_product(h_1, p)*inv_mapped_w;
00217 
00218   vnl_matrix_fixed<double,2,3> jacobian;
00219   jacobian.set_row(0, h_0-mapped_x*h_2 );
00220   jacobian.set_row(1, h_1-mapped_y*h_2 );
00221 
00222   return inv_mapped_w*jacobian;
00223 }
00224 
00225 //: Return the jacobian of the transform.
00226 void
00227 rgrl_trans_homography2d::
00228 jacobian_wrt_loc( vnl_matrix<double>& jacobian, vnl_vector<double> const& from_loc ) const
00229 {
00230   // The jacobian is a 2x2 matrix with entries
00231   // [d(f_0)/dx   d(f_0)/dy;
00232   //  d(f_1)/dx   d(f_1)/dy]
00233   //
00234   vnl_double_2 centered_from = from_loc;
00235   centered_from -= from_centre_;
00236 
00237   double mapped_w = H_(2,0)*centered_from[0] + H_(2,1)*centered_from[1] + H_(2,2);
00238 
00239   jacobian.set_size(2, 2);
00240   // w/ respect to x
00241   jacobian(0,0) = H_(0,0)*( H_(2,1)*centered_from[1]+H_(2,2) ) - H_(2,0)*( H_(0,1)*centered_from[1] + H_(0,2) );
00242   jacobian(1,0) = H_(1,0)*( H_(2,1)*centered_from[1]+H_(2,2) ) - H_(2,0)*( H_(1,1)*centered_from[1] + H_(1,2) );
00243   // w/ respect to y
00244   jacobian(0,1) = H_(0,1)*( H_(2,0)*centered_from[0]+H_(2,2) ) - H_(2,1)*( H_(0,0)*centered_from[0] + H_(0,2) );
00245   jacobian(1,1) = H_(1,1)*( H_(2,0)*centered_from[0]+H_(2,2) ) - H_(2,1)*( H_(1,0)*centered_from[0] + H_(1,2) );
00246 
00247   jacobian *= (1/(mapped_w*mapped_w));
00248 }
00249 
00250 // for output CENTERED transformation
00251 void
00252 rgrl_trans_homography2d::
00253 write(vcl_ostream& os ) const
00254 {
00255   //vnl_vector<double> origin(from_centre_.size(), 0.0);
00256 
00257   // tag
00258   os << "HOMOGRAPHY2D\n"
00259   // parameters
00260      << 2 << vcl_endl
00261      << H_ << from_centre_ << "  " << to_centre_ << vcl_endl;
00262 
00263   // parent
00264   rgrl_transformation::write( os );
00265 }
00266 
00267 // for input
00268 bool
00269 rgrl_trans_homography2d::
00270 read(vcl_istream& is )
00271 {
00272   int dim;
00273 
00274   // skip empty lines
00275   rgrl_util_skip_empty_lines( is );
00276 
00277   vcl_string str;
00278   vcl_getline( is, str );
00279 
00280   // The token should appear at the beginning of line
00281   if ( str.find( "HOMOGRAPHY2D" ) != 0 ) {
00282     WarningMacro( "The tag is not HOMOGRAPHY2D. reading is aborted.\n" );
00283     return false;
00284   }
00285 
00286   // input global xform
00287   dim=-1;
00288   is >> dim;
00289   if ( dim > 0 ) {
00290     is >> H_ >> from_centre_ >> to_centre_;
00291   }
00292 
00293   // parent
00294   return is.good() && rgrl_transformation::read( is );
00295 }
00296 
00297 void
00298 rgrl_trans_homography2d::
00299 map_loc( vnl_vector<double> const& from,
00300          vnl_vector<double>      & to  ) const
00301 {
00302   to.set_size(2);
00303   // convert "from" to homogeneous co-cord
00304   vnl_vector_fixed<double,3> h_from(from[0]-from_centre_[0], from[1]-from_centre_[1], 1);
00305   vnl_vector_fixed<double,3> h_to = H_*h_from;
00306   to[0] = h_to[0]/h_to[2] + to_centre_[0];
00307   to[1] = h_to[1]/h_to[2] + to_centre_[1];
00308 }
00309 
00310 void
00311 rgrl_trans_homography2d::
00312 map_dir( vnl_vector<double> const& from_loc,
00313          vnl_vector<double> const& from_dir,
00314          vnl_vector<double>      & to_dir  ) const
00315 {
00316   assert ( from_loc.size() == 2 );
00317   assert ( from_dir.size() == 2 );
00318   vnl_vector<double> to_loc_begin, to_loc_end;
00319   this->map_loc(from_loc, to_loc_begin);
00320   this->map_loc(from_loc+from_dir, to_loc_end);
00321 
00322   to_dir = to_loc_end - to_loc_begin;
00323   to_dir.normalize();
00324 }
00325 
00326 rgrl_transformation_sptr
00327 rgrl_trans_homography2d::
00328 scale_by( double scale ) const
00329 {
00330   vnl_matrix_fixed<double,3,3> new_H( H_ );
00331 
00332   // scale
00333   new_H(0,2) *= scale;
00334   new_H(1,2) *= scale;
00335 
00336   // move the scale on the fixed coordinate,
00337   // and divide the 3rd row by this scale
00338   new_H(2,0) /= scale;
00339   new_H(2,1) /= scale;
00340 
00341   // normalize
00342   new_H /= new_H.fro_norm();
00343 
00344   // centers
00345   vnl_vector_fixed<double,2> from = from_centre_ * scale;
00346   vnl_vector_fixed<double,2> to = to_centre_ * scale;
00347 
00348   rgrl_transformation_sptr xform
00349     =  new rgrl_trans_homography2d( new_H.as_ref(),
00350                                     vnl_matrix<double>(),
00351                                     from.as_ref(), to.as_ref() );
00352   xform->set_scaling_factors( this->scaling_factors() );
00353   return xform;
00354 }
00355 
00356 //: make a clone copy
00357 rgrl_transformation_sptr
00358 rgrl_trans_homography2d::
00359 clone() const
00360 {
00361   return new rgrl_trans_homography2d( *this );
00362 }