contrib/rpl/rgrl/rgrl_weighter_m_est.cxx
Go to the documentation of this file.
00001 #include "rgrl_weighter_m_est.h"
00002 //:
00003 // \file
00004 // \author Chuck Stewart
00005 // \date   Feb 2003
00006 
00007 #include <vcl_cmath.h>
00008 #include <vcl_cassert.h>
00009 #include <vnl/vnl_matrix.h>
00010 #include <vnl/vnl_math.h>
00011 #include <rrel/rrel_m_est_obj.h>
00012 
00013 #include "rgrl_match_set.h"
00014 #include "rgrl_scale.h"
00015 #include "rgrl_transformation.h"
00016 
00017 rgrl_weighter_m_est::
00018 rgrl_weighter_m_est( vcl_auto_ptr<rrel_m_est_obj>  m_est,
00019                      bool                          use_signature_error,
00020                      bool                          use_precomputed_signature_wgt )
00021   : m_est_( m_est ),
00022     use_signature_error_( use_signature_error ),
00023     signature_precomputed_( use_precomputed_signature_wgt ),
00024     weight_more_on_distinct_match_( true )
00025 {
00026 }
00027 
00028 
00029 rgrl_weighter_m_est::
00030 ~rgrl_weighter_m_est()
00031 {
00032 }
00033 
00034 
00035 void
00036 rgrl_weighter_m_est::
00037 compute_weights( rgrl_scale const&  scales,
00038                  rgrl_match_set&    match_set ) const
00039 {
00040   //  Cache the inverse covariance of the signature error if signature
00041   //  errors are used.  Be careful of null entries.
00042 
00043   vnl_matrix<double> signature_inv_covar;
00044   if ( use_signature_error_ && !signature_precomputed_ ) {
00045     assert ( scales.has_signature_inv_covar() );
00046     signature_inv_covar = scales.signature_inv_covar();
00047   }
00048 
00049   //  cache the geometric scale.
00050   assert ( scales.has_geometric_scale() );
00051   double geometric_scale = scales.geometric_scale();
00052 
00053   typedef rgrl_match_set::from_iterator from_iter;
00054   typedef from_iter::to_iterator        to_iter;
00055 
00056   DebugMacro(1,'\n');
00057   DebugMacro_abv(1, "Matched points : from\t to\t geo_err\t geo_wgt\t cum_wgt:\n" );
00058 
00059   //  for each from image feature being matched
00060   for ( from_iter fitr = match_set.from_begin();
00061        fitr != match_set.from_end(); ++fitr ) {
00062 
00063     DebugMacro_abv(1, fitr.from_feature()->location() << '\t');
00064     if ( fitr.empty() ) DebugMacro_abv(2, '\n' );
00065 
00066     if ( fitr.size() == 0 )  continue;
00067 
00068     double sum_weights = 0; // for normalizing, later
00069     rgrl_feature_sptr mapped_from = fitr.mapped_from_feature();
00070 
00071     for ( to_iter titr = fitr.begin(); titr != fitr.end(); ++titr )
00072     {
00073       DebugMacro_abv( 1, titr.to_feature()->location() << "\t " );
00074 
00075       //  for each match with a "to" image feature
00076       rgrl_feature_sptr to_feature = titr.to_feature();
00077       //double geometric_err = mapped_from->geometric_error( *to_feature );
00078       double geometric_err = to_feature->geometric_error( *mapped_from );
00079       double geometric_wgt = m_est_->wgt( geometric_err, geometric_scale );
00080 
00081       DebugMacro_abv(1, geometric_err << "\t " << geometric_wgt << "\t " );
00082 
00083       double signature_wgt = 1.0;
00084       if ( signature_precomputed_ ) {
00085         signature_wgt = titr . signature_weight( );
00086       }
00087       else if ( use_signature_error_ ) {
00088         vnl_vector<double> error_vector = to_feature->signature_error_vector( *mapped_from );
00089         assert ( error_vector.size() > 0 && 
00090                  error_vector.size() == signature_inv_covar.rows() &&
00091                  error_vector.size() == signature_inv_covar.cols());
00092         double signature_err = vcl_sqrt( dot_product( error_vector * signature_inv_covar, error_vector ) );
00093         // CS: we may need to add some chi-squared normalization
00094         // here for large signature vectors.
00095         signature_wgt = m_est_->wgt( signature_err );  // already normalized at this point
00096       }
00097 
00098       double cumul_wgt = geometric_wgt * signature_wgt;
00099 
00100       DebugMacro_abv(1, cumul_wgt << vcl_endl );
00101 
00102       titr.set_geometric_weight( geometric_wgt );
00103       if ( !signature_precomputed_ ) titr.set_signature_weight( signature_wgt );
00104       titr.set_cumulative_weight( cumul_wgt );
00105       sum_weights += cumul_wgt;
00106     }
00107 
00108     // Now, assign the cumulative weights for each match by scaling
00109     // the initial cumulative weight by the fraction of the total
00110     // cumulative weight.
00111     // If weight_more_on_distinct_match_ is set,
00112     // a feature with more matches will be penalized for the
00113     // ambiguity, and a feature with a unique match will not be
00114     // affected at all.
00115 
00116     if ( sum_weights > 1e-16 ) { //sum_weights not approaching 0
00117       if( weight_more_on_distinct_match_ )
00118         for ( to_iter titr = fitr.begin(); titr != fitr.end(); ++titr ) {
00119           double wgt = titr.cumulative_weight();
00120             titr.set_cumulative_weight( wgt*wgt / sum_weights );
00121         }
00122       else
00123         for ( to_iter titr = fitr.begin(); titr != fitr.end(); ++titr ) {
00124           double wgt = titr.cumulative_weight();
00125             titr.set_cumulative_weight( wgt / sum_weights );
00126         }
00127     }
00128   }
00129 }
00130 
00131 double 
00132 rgrl_weighter_m_est::
00133 aux_sum_weighted_residuals( rgrl_scale const&  scale,
00134                             rgrl_match_set&    match_set,
00135                             rgrl_transformation const&  xform )
00136 {
00137   typedef rgrl_match_set::from_iterator  from_iter;
00138   typedef from_iter::to_iterator         to_iter;
00139 
00140   if ( match_set.from_size() > 0) {
00141     match_set.remap_from_features( xform );
00142     compute_weights( scale, match_set );
00143   }
00144   
00145   double weighted_sum = 0;
00146   
00147   // As the objective function is formulated as weighted Least-Square problem,
00148   // the obj function value is indeed weighted sum of SQUARED residuals
00149   //
00150   for ( from_iter fitr = match_set.from_begin(); fitr != match_set.from_end(); ++fitr ){
00151       if ( fitr.size() == 0 )  continue;
00152       
00153       rgrl_feature_sptr mapped_from = fitr.mapped_from_feature();
00154       for ( to_iter titr = fitr.begin(); titr != fitr.end(); ++titr ) {
00155         //  for each match with a "to" image feature
00156         rgrl_feature_sptr to_feature = titr.to_feature();
00157         double geometric_err = to_feature->geometric_error( *mapped_from );
00158         
00159         weighted_sum += vnl_math_sqr(geometric_err) * titr.geometric_weight();
00160       }
00161   }
00162   
00163   return weighted_sum;
00164 }
00165 
00166 // It is unclear how to handle multiple matches. 
00167 // The current method is to pick the one with minimum distance
00168 // and evaluate the likelihood based on that. 
00169 //
00170 double
00171 rgrl_weighter_m_est::
00172 aux_sum_rho_values( rgrl_scale const&  scale,
00173                     rgrl_match_set&    match_set,
00174                     rgrl_transformation const&  xform )
00175 {
00176   typedef rgrl_match_set::from_iterator  from_iter;
00177   typedef from_iter::to_iterator         to_iter;
00178 
00179   if ( match_set.from_size() == 0 ) return 0;
00180 
00181   double sum_rho = 0;
00182 
00183   for ( from_iter fitr = match_set.from_begin(); fitr != match_set.from_end(); ++fitr ){
00184       if ( fitr.size() == 0 )  continue;
00185       
00186       rgrl_feature_sptr mapped_from = fitr.from_feature()->transform( xform );
00187       to_iter titr = fitr.begin();
00188       double min_val = titr.to_feature()->geometric_error( *mapped_from );
00189       
00190       for ( ++titr; titr != fitr.end(); ++titr ) {
00191         //  for each match with a "to" image feature
00192         rgrl_feature_sptr to_feature = titr.to_feature();
00193         double geometric_err = to_feature->geometric_error( *mapped_from );
00194 
00195         // signature weight
00196         //
00197         //GY: don't know how to handle this in a correct way
00198         // double signature_wgt = 1.0;
00199         //if ( signature_precomputed_ ) {
00200         //  signature_wgt = titr . signature_weight( );
00201         //}
00202         
00203         if( min_val > geometric_err )
00204           min_val = geometric_err;
00205       }
00206       // sum of rho is weighted by signature??
00207       sum_rho += m_est_->rho(min_val, scale.geometric_scale());
00208   }
00209   
00210   return sum_rho;
00211 }
00212 
00213 double 
00214 rgrl_weighter_m_est::
00215 aux_neg_log_likelihood( rgrl_scale const&  scale,
00216                         rgrl_match_set&    match_set,
00217                         rgrl_transformation const&  xform )
00218 {
00219   typedef rgrl_match_set::from_iterator  from_iter;
00220   typedef from_iter::to_iterator         to_iter;
00221 
00222   int n = 0;
00223 
00224   for ( from_iter fitr = match_set.from_begin(); fitr != match_set.from_end(); ++fitr )
00225     if( fitr.size() > 0 ) {
00226       // multi-match counts as one constraint
00227       n ++;
00228     }
00229 
00230   double sum_rho_values = aux_sum_rho_values(scale, match_set, xform);
00231   const double geometric_scale = scale.geometric_scale();
00232   //vcl_cout << "    rho_value: " << sum_rho_values << vcl_endl;
00233   return n*vcl_log(geometric_scale) + sum_rho_values;
00234 }
00235 
00236 double 
00237 rgrl_weighter_m_est::
00238 aux_avg_neg_log_likelihood( rgrl_scale const&  scale,
00239                             rgrl_match_set&    match_set,
00240                             rgrl_transformation const&  xform )
00241 {
00242   typedef rgrl_match_set::from_iterator  from_iter;
00243   typedef from_iter::to_iterator         to_iter;
00244 
00245   int n = 0;
00246 
00247   for ( from_iter fitr = match_set.from_begin(); fitr != match_set.from_end(); ++fitr )
00248     if( fitr.size() > 0 ) {
00249       // multi-match counts as one constraint
00250       n ++;
00251     }
00252 
00253   if( !n ) 
00254     return 0;
00255     
00256   double sum_rho_values = aux_sum_rho_values(scale, match_set, xform);
00257   const double geometric_scale = scale.geometric_scale();
00258   //vcl_cout << "    rho_value: " << sum_rho_values << vcl_endl;
00259   return vcl_log(geometric_scale) + sum_rho_values/double(n);
00260 }