contrib/rpl/rgrl/rgrl_trans_rad_dis_homo2d.cxx
Go to the documentation of this file.
00001 // This is rpl/rgrl/rgrl_trans_rad_dis_homo2d.cxx
00002 #include "rgrl_trans_rad_dis_homo2d.h"
00003 //:
00004 // \file
00005 
00006 #include <vcl_cassert.h>
00007 #include <vnl/vnl_vector_fixed.h>
00008 #include <vnl/vnl_math.h>
00009 #include <vnl/vnl_double_2.h>
00010 #include <vnl/vnl_double_3.h>
00011 #include <vnl/vnl_double_2x2.h>
00012 #include <vnl/vnl_transpose.h>
00013 
00014 #include "rgrl_util.h"
00015 
00016 // NOTE: the first parameters of all functions in this file
00017 // are the target/return value, i.e., return value by references
00018 //
00019 
00020 // map homography
00021 static
00022 inline
00023 void
00024 map_inhomo_point( vnl_double_2& mapped, vnl_matrix_fixed<double, 3, 3> const& H, vnl_vector<double> const& loc )
00025 {
00026   vnl_double_3 homo_from( loc[0], loc[1], 1 );
00027   vnl_double_3 homo_to = H * homo_from;
00028   mapped[0] = homo_to[0]/homo_to[2];
00029   mapped[1] = homo_to[1]/homo_to[2];
00030 }
00031 
00032 //: Return the jacobian of the transform.
00033 static
00034 void
00035 homo_wrt_loc( vnl_matrix_fixed<double, 2, 2>&        jac_loc,
00036               vnl_matrix_fixed<double, 3, 3> const&  H,
00037               vnl_vector_fixed<double, 2>    const&  from_loc )
00038 {
00039   // The jacobian is a 2x2 matrix with entries
00040   // [d(f_0)/dx   d(f_0)/dy;
00041   //  d(f_1)/dx   d(f_1)/dy]
00042   //
00043   const double mapped_w = H(2,0)*from_loc[0] + H(2,1)*from_loc[1] + H(2,2);
00044 
00045   // w/ respect to x
00046   jac_loc(0,0) = H(0,0)*( H(2,1)*from_loc[1]+H(2,2) ) - H(2,0)*( H(0,1)*from_loc[1] + H(0,2) );
00047   jac_loc(1,0) = H(1,0)*( H(2,1)*from_loc[1]+H(2,2) ) - H(2,0)*( H(1,1)*from_loc[1] + H(1,2) );
00048   // w/ respect to y
00049   jac_loc(0,1) = H(0,1)*( H(2,0)*from_loc[0]+H(2,2) ) - H(2,1)*( H(0,0)*from_loc[0] + H(0,2) );
00050   jac_loc(1,1) = H(1,1)*( H(2,0)*from_loc[0]+H(2,2) ) - H(2,1)*( H(1,0)*from_loc[0] + H(1,2) );
00051 
00052   jac_loc *= (1/(mapped_w*mapped_w));
00053 }
00054 
00055 
00056 static
00057 void
00058 homo_wrt_h( vnl_matrix_fixed<double, 2, 9>&        jac_h,
00059             vnl_matrix_fixed<double, 3, 3> const&  H,
00060             vnl_vector_fixed<double, 2>    const&  from_loc )
00061 {
00062   vnl_matrix_fixed<double, 3, 9 > jf(0.0); // homogeneous coordinate
00063   vnl_matrix_fixed<double, 2, 3 > jg(0.0); // inhomo, [u/w, v/w]^T
00064 
00065   // transform coordinate
00066   vnl_double_3 from_homo( from_loc[0], from_loc[1], 1 );
00067   vnl_double_3 mapped_homo = H * from_homo;
00068 
00069   // homogeneous coordinate w.r.t homography parameters
00070   jf(0,0) = jf(1,3) = jf(2,6) = from_homo[0]; // x
00071   jf(0,1) = jf(1,4) = jf(2,7) = from_homo[1]; // y
00072   jf(0,2) = jf(1,5) = jf(2,8) = 1.0;
00073 
00074   // derivatives w.r.t division
00075   jg(0,0) = 1.0/mapped_homo[2];
00076   jg(0,2) = -mapped_homo[0]/vnl_math_sqr(mapped_homo[2]);
00077   jg(1,1) = 1.0/mapped_homo[2];
00078   jg(1,2) = -mapped_homo[1]/vnl_math_sqr(mapped_homo[2]);
00079 
00080   // Apply chain rule: Jab_g(f(p)) = Jac_g * Jac_f
00081   jac_h = jg * jf;
00082 }
00083 
00084 // distort image coordinate
00085 static
00086 inline
00087 void
00088 distort( vnl_double_2& dis_loc, vnl_double_2 const& true_loc, double k1 )
00089 {
00090   const double c = 1 + k1 * true_loc.squared_magnitude();
00091   dis_loc = c * true_loc;
00092 }
00093 
00094 #if 0 // ***This is incorrect implementation***
00095 // undistort image coordinate
00096 static
00097 inline
00098 void
00099 undistort( vnl_double_2& true_loc, vnl_double_2 const& dis_loc, double k1 )
00100 {
00101   const double c = 1 + k1 * dis_loc.squared_magnitude();
00102   true_loc = dis_loc;
00103 }
00104 #endif // 0
00105 
00106 // jacobian w.r.t k1 parameter
00107 static
00108 inline
00109 void
00110 distort_wrt_k1( vnl_double_2& jac_k1, vnl_double_2 const& true_loc )
00111 {
00112   const double c = true_loc.squared_magnitude();
00113   jac_k1 = c * true_loc;
00114 }
00115 
00116 
00117 // jacobian w.r.t location
00118 static
00119 inline
00120 void
00121 distort_wrt_loc( vnl_double_2x2& jac_loc, vnl_double_2 const& true_loc, double k1 )
00122 {
00123   const double c = 1 + k1 * true_loc.squared_magnitude();
00124 
00125   jac_loc(0,0) = c + 2*k1*vnl_math_sqr(true_loc[0]);
00126   jac_loc(1,1) = c + 2*k1*vnl_math_sqr(true_loc[1]);
00127   jac_loc(0,1) = jac_loc(1,0) = 2 * k1 * true_loc[0] * true_loc[1];
00128 }
00129 
00130 
00131 rgrl_trans_rad_dis_homo2d::
00132 rgrl_trans_rad_dis_homo2d()
00133   : H_( 0.0 ),
00134     from_centre_( 0.0, 0.0 ),
00135     to_centre_( 0.0, 0.0 ),
00136     k1_from_( 0.0 ),
00137     k1_to_( 0.0 )
00138 {}
00139 
00140 rgrl_trans_rad_dis_homo2d::
00141 rgrl_trans_rad_dis_homo2d( vnl_matrix<double> const& H,
00142                            double k1_from,
00143                            double k1_to,
00144                            vnl_vector<double> const& from_centre,
00145                            vnl_vector<double> const& to_centre )
00146  :  H_( H ),
00147     from_centre_( from_centre ),
00148     to_centre_( to_centre ),
00149     k1_from_( k1_from ),
00150     k1_to_( k1_to )
00151 {}
00152 
00153 rgrl_trans_rad_dis_homo2d::
00154 rgrl_trans_rad_dis_homo2d( vnl_matrix<double> const& H,
00155                            double k1_from,
00156                            double k1_to,
00157                            vnl_matrix<double> const& covar,
00158                            vnl_vector<double> const& from_centre,
00159                            vnl_vector<double> const& to_centre )
00160  :  rgrl_transformation( covar ),
00161     H_( H ),
00162     from_centre_( from_centre ),
00163     to_centre_( to_centre ),
00164     k1_from_( k1_from ),
00165     k1_to_( k1_to )
00166 {
00167   assert( to_centre.size() == 2 );
00168 
00169   //Uncenter the H_ = to_matrix^-1 * H * from_matrix
00170   //
00171   //vnl_matrix<double> to_inv(3,3, vnl_matrix_identity);
00172   //to_inv(0,2) = to_centre[0];
00173   //to_inv(1,2) = to_centre[1];
00174   //
00175   //vnl_matrix<double> from_matrix(3,3, vnl_matrix_identity);
00176   //from_matrix(0,2) = -from_centre[0];
00177   //from_matrix(1,2) = -from_centre[1];
00178   //
00179   //H_ = to_inv * H * from_matrix;
00180   //from_centre_ = from_centre;
00181 }
00182 
00183 vnl_matrix<double>
00184 rgrl_trans_rad_dis_homo2d::
00185 transfer_error_covar( vnl_vector<double> const& from  ) const
00186 {
00187   assert ( is_covar_set() );
00188   assert ( from.size() ==2 );
00189 
00190   // Step 1. undistorted from coordinate and compute apu/apd
00191   vnl_double_2 dis_from_loc( from[0]-from_centre_[0], from[1]-from_centre_[1] );
00192   vnl_double_2 true_from_loc;
00193   // make the trick: *distort*
00194   distort( true_from_loc, dis_from_loc, k1_from_ );
00195   vnl_double_2x2 pu_pd;
00196   distort_wrt_loc( pu_pd, dis_from_loc, k1_from_ );
00197   vnl_double_2 pu_k1_from;
00198   distort_wrt_k1( pu_k1_from, dis_from_loc );
00199 
00200   // Step 2. homography transformation
00201   vnl_double_2 true_to_loc;
00202   map_inhomo_point( true_to_loc, H_, true_from_loc.as_ref() );
00203   vnl_double_2x2 qu_pu;
00204   homo_wrt_loc( qu_pu, H_, true_from_loc );
00205   vnl_matrix_fixed<double, 2, 9> qu_h;
00206   homo_wrt_h( qu_h, H_, true_from_loc );
00207 
00208   // Step 3. distorted To coodinates
00209   vnl_double_2x2 qd_qu;
00210   distort_wrt_loc( qd_qu, true_to_loc, k1_to_ );
00211   vnl_double_2 qd_k1_to;
00212   distort_wrt_k1( qd_k1_to, true_to_loc );
00213 
00214   // Steop 4. apply chain rule
00215   vnl_matrix_fixed<double, 2, 9> qd_h = qd_qu * qu_h;
00216   vnl_double_2  qd_k1_from = qd_qu * qu_pu * pu_k1_from;
00217 
00218   // assemble jacobian matrix
00219   vnl_matrix<double> jac(2, 11, 0.0);
00220   // wrt. k1_from
00221   jac(0,9) = qd_k1_from[0];
00222   jac(1,9) = qd_k1_from[1];
00223 
00224   // wrt. k1_to
00225   jac(0,10) = qd_k1_to[0];
00226   jac(1,10) = qd_k1_to[1];
00227 
00228   // wrt. H
00229   for ( unsigned i=0; i<2; ++i )
00230     for ( unsigned j=0; j<9; ++j )
00231       jac(i, j) = qd_h(i,j);
00232 
00233   return jac * covar_ * vnl_transpose( jac );
00234 }
00235 
00236 //: Inverse map using pseudo-inverse of H_.
00237 void
00238 rgrl_trans_rad_dis_homo2d::
00239 inv_map( const vnl_vector<double>& /*to*/,
00240          vnl_vector<double>& /*from*/ ) const
00241 {
00242   assert( ! "rgrl_trans_rad_dis_homo2d::inv_map( to, from ) is not implemented!!!" );
00243 }
00244 
00245 //: Return the jacobian of the transform.
00246 void
00247 rgrl_trans_rad_dis_homo2d::
00248 jacobian_wrt_loc( vnl_matrix<double>& jac, vnl_vector<double> const& from ) const
00249 {
00250   // using chain rule:
00251   // aqd/apd = aqd/aqu * aqu/apu * apu/apd
00252   //
00253 
00254   jac.set_size(2, 2);
00255 
00256   // Step 1. undistorted from coordinate and compute apu/apd
00257   vnl_double_2 dis_from_loc( from[0]-from_centre_[0], from[1]-from_centre_[1] );
00258   vnl_double_2 true_from_loc;
00259   // make the trick: *distort*
00260   distort( true_from_loc, dis_from_loc, k1_from_ );
00261   vnl_double_2x2 pu_pd;
00262   distort_wrt_loc( pu_pd, dis_from_loc, k1_from_ );
00263 
00264 
00265   // Step 2. homography transformation
00266   vnl_double_2 true_to_loc;
00267   map_inhomo_point( true_to_loc, H_, true_from_loc.as_ref() );
00268   vnl_double_2x2 qu_pu;
00269   homo_wrt_loc( qu_pu, H_, true_from_loc );
00270 
00271   // Step 3. distorted To coodinates
00272   vnl_double_2x2 qd_qu;
00273   distort_wrt_loc( qd_qu, true_to_loc, k1_to_ );
00274 
00275   // Steop 4. put them together
00276   jac = (qd_qu * qu_pu * pu_pd).as_ref();
00277 }
00278 
00279 void
00280 rgrl_trans_rad_dis_homo2d::
00281 map_loc( vnl_vector<double> const& from,
00282          vnl_vector<double>      & to ) const
00283 {
00284   to.set_size(2);
00285 
00286   // Step 1. undistorted from coordinate
00287   vnl_double_2 dis_from_loc( from[0]-from_centre_[0], from[1]-from_centre_[1] );
00288   vnl_double_2 true_from_loc;
00289   // make the trick: *distort*
00290   distort( true_from_loc, dis_from_loc, k1_from_ );
00291 
00292   // Step 2. homography transformation
00293   vnl_double_2 true_to_loc;
00294   map_inhomo_point( true_to_loc, H_, true_from_loc.as_ref() );
00295 
00296   // Step 3. distorted To coodinates
00297   vnl_double_2 dis_to_loc;
00298   distort( dis_to_loc, true_to_loc, k1_to_ );
00299 
00300   // add center back
00301   to = (dis_to_loc + to_centre_).as_ref();
00302 }
00303 
00304 void
00305 rgrl_trans_rad_dis_homo2d::
00306 map_dir( vnl_vector<double> const& from_loc,
00307          vnl_vector<double> const& from_dir,
00308          vnl_vector<double>      & to_dir    ) const
00309 {
00310   assert ( from_loc.size() == 2 );
00311   assert ( from_dir.size() == 2 );
00312   vnl_vector<double> to_loc_begin, to_loc_end;
00313   this->map_loc(from_loc, to_loc_begin);
00314   this->map_loc(from_loc+from_dir, to_loc_end);
00315 
00316   to_dir = to_loc_end - to_loc_begin;
00317   to_dir.normalize();
00318 }
00319 
00320 rgrl_transformation_sptr
00321 rgrl_trans_rad_dis_homo2d::
00322 scale_by( double scale ) const
00323 {
00324   vnl_matrix_fixed<double,3,3> new_H( H_ );
00325 
00326   // scale
00327   new_H(0,2) *= scale;
00328   new_H(1,2) *= scale;
00329 
00330   // move the scale on the fixed coordinate,
00331   // and divide the 3rd row by this scale
00332   new_H(2,0) /= scale;
00333   new_H(2,1) /= scale;
00334 
00335   // normalize
00336   new_H /= new_H.fro_norm();
00337 
00338   // centers
00339   vnl_vector_fixed<double,2> from = from_centre_ * scale;
00340   vnl_vector_fixed<double,2> to = to_centre_ * scale;
00341 
00342   // radial terms
00343   const double sq_scale = scale*scale;
00344   double k1_from = k1_from_ / sq_scale;
00345   double k1_to = k1_to_ / sq_scale;
00346 
00347   rgrl_transformation_sptr xform
00348     =  new rgrl_trans_rad_dis_homo2d( new_H.as_ref(),
00349                                       k1_from, k1_to,
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 vnl_matrix_fixed<double, 3, 3>
00357 rgrl_trans_rad_dis_homo2d::
00358 uncenter_H_matrix( ) const
00359 {
00360   vnl_matrix_fixed<double, 3, 3> H;
00361 
00362   // uncenter To image
00363   vnl_matrix_fixed<double, 3, 3> to_inv;
00364   to_inv.set_identity();
00365   to_inv(0,2) = to_centre_[0];
00366   to_inv(1,2) = to_centre_[1];
00367 
00368   // uncenter From image
00369   vnl_matrix_fixed<double, 3, 3> from_matrix;
00370   from_matrix.set_identity();
00371   from_matrix(0,2) = -from_centre_[0];
00372   from_matrix(1,2) = -from_centre_[1];
00373 
00374   H = to_inv * H_ * from_matrix;
00375 
00376   return H;
00377 }
00378 
00379 rgrl_transformation_sptr
00380 rgrl_trans_rad_dis_homo2d::
00381 inverse_transform( ) const
00382 {
00383   assert ( ! "rgrl_trans_quadratic::inverse_transform() is not defined" );
00384   return 0;
00385 }
00386 
00387 // for output CENTERED transformation,
00388 void
00389 rgrl_trans_rad_dis_homo2d::
00390 write(vcl_ostream& os ) const
00391 {
00392   //vnl_vector<double> origin(from_centre_.size(), 0.0);
00393 
00394   // tag
00395   os << "HOMOGRAPHY2D_WITH_RADIAL_DISTORTION\n"
00396   // parameters
00397      << 2 << vcl_endl
00398      << H_
00399      << from_centre_ << "  " << to_centre_ << '\n'
00400      << k1_from_ << "  " <<  k1_to_
00401      << vcl_endl;
00402 
00403   // parent
00404   rgrl_transformation::write( os );
00405 }
00406 
00407 // for input
00408 bool
00409 rgrl_trans_rad_dis_homo2d::
00410 read(vcl_istream& is )
00411 {
00412   int dim;
00413 
00414   // skip empty lines
00415   rgrl_util_skip_empty_lines( is );
00416 
00417   vcl_string str;
00418   vcl_getline( is, str );
00419 
00420   // The token should appear at the beginning of line
00421   if ( str.find( "HOMOGRAPHY2D_WITH_RADIAL_DISTORTION" ) != 0 ) {
00422     WarningMacro( "The tag is not HOMOGRAPHY2D. reading is aborted.\n" );
00423     return false;
00424   }
00425 
00426   // input global xform
00427   dim=-1;
00428   is >> dim;
00429   if ( dim > 0 ) {
00430     is >> H_ >> from_centre_ >> to_centre_ >> k1_from_ >> k1_to_;
00431   }
00432 
00433   // parent
00434   return is.good() && rgrl_transformation::read( is );
00435 }
00436 
00437 //: make a clone copy
00438 rgrl_transformation_sptr
00439 rgrl_trans_rad_dis_homo2d::
00440 clone() const
00441 {
00442   return new rgrl_trans_rad_dis_homo2d( *this );
00443 }