contrib/rpl/rgrl/rgrl_est_translation.cxx
Go to the documentation of this file.
00001 #include "rgrl_est_translation.h"
00002 //:
00003 // \file
00004 // \author Charlene Tsai
00005 // \date   Dec 2003
00006 
00007 #include <vcl_cassert.h>
00008 #include <vnl/algo/vnl_svd.h>
00009 #include "rgrl_trans_translation.h"
00010 #include "rgrl_match_set.h"
00011 
00012 rgrl_est_translation::
00013 rgrl_est_translation( unsigned int dimension )
00014 {
00015   // Derive the parameter_dof from the dimension
00016   //
00017   unsigned int param_dof = dimension;
00018 
00019   // Pass the two variable to the parent class, where they're stored
00020   //
00021   rgrl_estimator::set_param_dof( param_dof );
00022 }
00023 
00024 rgrl_transformation_sptr
00025 rgrl_est_translation::
00026 estimate( rgrl_set_of<rgrl_match_set_sptr> const& matches,
00027           rgrl_transformation const& /*cur_transform*/ ) const
00028 {
00029   // Iterators to go over the matches
00030   //
00031   typedef rgrl_match_set::const_from_iterator FIter;
00032   typedef FIter::to_iterator TIter;
00033 
00034   // The dimensionality of the space we are working in. Find it by
00035   // looking at the dimension of one of the data points.
00036   //
00037   unsigned ms = 0;
00038   while ( ms < matches.size() &&
00039           matches[ms]->from_begin() == matches[ms]->from_end() )
00040     ++ms;
00041   if ( ms == matches.size() ) {
00042     DebugMacro(0, "No data!\n");
00043     return 0; // no data!
00044   }
00045   const unsigned int m = matches[ms]->from_begin().from_feature()->location().size();
00046   assert ( m>=1 );
00047 
00048   // We use all the constraints from all the match sets to develop a
00049   // single linear system for the transformation.
00050   //
00051   vnl_matrix<double> XtWX( m, m );
00052   vnl_vector<double> XtWy( m );
00053   XtWX.fill( 0.0 );
00054   XtWy.fill( 0.0 );
00055 
00056   // Determine the weighted centres for the translation transformation. We
00057   // take the centres of all the points in all the match sets.
00058   //
00059   vnl_vector<double> from_centre( m, 0.0 );
00060   vnl_vector<double> to_centre( m, 0.0 );
00061   vnl_vector<double> from_pt( m );
00062   vnl_vector<double> to_pt( m );
00063   vnl_vector<double> Bq (m);
00064   vnl_matrix<double> wgtB( m, m );
00065   double sum_wgt = 0.0;
00066   unsigned count=0;  //for debugging
00067   for ( unsigned ms=0; ms < matches.size(); ++ms ) {
00068     rgrl_match_set const& match_set = *matches[ms];
00069     for ( FIter fi = match_set.from_begin(); fi != match_set.from_end(); ++fi ) {
00070       for ( TIter ti = fi.begin(); ti != fi.end(); ++ti ) {
00071         double const wgt = ti.cumulative_weight();
00072         from_pt = fi.from_feature()->location();
00073         from_pt *= wgt;
00074         from_centre += from_pt;
00075         to_pt = ti.to_feature()->location();
00076         to_pt *= wgt;
00077         to_centre   += to_pt;
00078         sum_wgt += wgt;
00079       }
00080     }
00081   }
00082   // if the weight is too small or zero,
00083   // that means there is no good match
00084   if( sum_wgt < 1e-13 ) {
00085     return 0;
00086   }
00087   
00088   from_centre /= sum_wgt;
00089   to_centre /= sum_wgt;
00090 
00091 
00092   // Since XtWX is symmetric, we only compute the upper triangle, and
00093   // copy it later into the lower triangle.
00094   for ( unsigned ms=0; ms < matches.size(); ++ms ) {
00095     rgrl_match_set const& match_set = *matches[ms];
00096     for ( FIter fi = match_set.from_begin(); fi != match_set.from_end(); ++fi ) {
00097       for ( TIter ti = fi.begin(); ti != fi.end(); ++ti ) {
00098         from_pt = fi.from_feature()->location();
00099         from_pt -= from_centre;
00100         to_pt = ti.to_feature()->location();
00101         to_pt -= to_centre;
00102         vnl_matrix<double> const& B = ti.to_feature()->error_projector();
00103         double const wgt = ti.cumulative_weight();
00104 
00105         assert ( from_pt.size() == m );
00106         assert ( to_pt.size() == m );
00107         assert ( B.cols() == m && B.rows() == m );
00108         ++count;
00109 
00110         // For each constraint, add w*DtBD to XtWX
00111         wgtB = B;
00112         wgtB *= wgt;
00113         XtWX += wgtB;
00114 
00115         // add w*Bq to XtWy
00116         Bq = to_pt.pre_multiply( B );
00117         for ( unsigned i = 0; i<m; ++i)
00118           XtWy[i] += wgt * Bq[i];
00119       }
00120     }
00121   }
00122 
00123   // ----------------------------
00124   // Compute the solution
00125 
00126   vnl_svd<double> svd( XtWX );
00127 
00128   // Due to floating point inaccuracies, some zero singular values may
00129   // look non-zero, so we correct for that.
00130   svd.zero_out_relative();
00131 
00132   // Use pseudo inverse
00133   if ( (unsigned)svd.rank() < m ) {
00134     DebugMacro(1, "rank ("<<svd.rank()<<") < "<<m<<"; no solution." );
00135     DebugMacro_abv(1,"  (used " << count << " correspondences)\n" );
00136     //DebugMacro_abv(1,"  use pseudo inverse instead\n" );
00137     return 0; //no solution
00138   }
00139 
00140   // Compute the solution into XtWy
00141   //
00142   vnl_matrix<double> covar = svd.inverse();
00143   XtWy.pre_multiply( covar );
00144 
00145   vnl_vector<double> trans = XtWy;
00146 
00147   DebugMacro(1,"T =\n" << trans-from_centre+to_centre << '\n' );
00148 
00149   return new rgrl_trans_translation( trans, covar, from_centre, to_centre );
00150 }
00151 
00152 
00153 rgrl_transformation_sptr
00154 rgrl_est_translation::
00155 estimate( rgrl_match_set_sptr matches,
00156           rgrl_transformation const& cur_transform ) const
00157 {
00158   // use base class implementation
00159   return rgrl_estimator::estimate( matches, cur_transform );
00160 }
00161 
00162 const vcl_type_info&
00163 rgrl_est_translation::
00164 transformation_type() const
00165 {
00166   return rgrl_trans_translation::type_id();
00167 }