contrib/rpl/rgrl/rgrl_matcher_k_nearest_pick_one.cxx
Go to the documentation of this file.
00001 #include "rgrl_matcher_k_nearest_pick_one.h"
00002 //:
00003 // \file
00004 // \author Gehua Yang
00005 // \date   March 2005
00006 
00007 #include <rgrl/rgrl_feature.h>
00008 #include <rgrl/rgrl_feature_set.h>
00009 #include <rgrl/rgrl_transformation.h>
00010 #include <rgrl/rgrl_view.h>
00011 #include <rgrl/rgrl_match_set.h>
00012 #include <vcl_vector.h>
00013 #include <vcl_algorithm.h>
00014 
00015 
00016 rgrl_matcher_k_nearest_pick_one::
00017 rgrl_matcher_k_nearest_pick_one( unsigned int k )
00018   : rgrl_matcher_k_nearest_adv( k )
00019 {
00020 }
00021 
00022 
00023 rgrl_matcher_k_nearest_pick_one::
00024 rgrl_matcher_k_nearest_pick_one( unsigned int k, double dist_thres, double min_mapped_scale, double thres_reuse_match )
00025   : rgrl_matcher_k_nearest_adv(k, dist_thres, min_mapped_scale, thres_reuse_match)
00026 {
00027 }
00028 
00029 
00030 rgrl_match_set_sptr
00031 rgrl_matcher_k_nearest_pick_one::
00032 compute_matches( rgrl_feature_set const&       from_set,
00033                  rgrl_feature_set const&       to_set,
00034                  rgrl_view const&              current_view,
00035                  rgrl_transformation const&    current_xform,
00036                  rgrl_scale const&             /* current_scale */,
00037                  rgrl_match_set_sptr const&    old_matches )
00038 {
00039   typedef rgrl_view::feature_vector feat_vector;
00040   typedef feat_vector::const_iterator feat_iter;
00041 
00042   DebugMacro( 2, "Compute matches between features "
00043                  << from_set.label().name() << "-->"
00044                  << to_set.label().name() << vcl_endl; );
00045 
00046   // faster to check a boolean variable
00047   const bool allow_reuse_match = ( sqr_thres_for_reuse_match_ > 0) && (prev_xform_) && (old_matches);
00048 
00049   // create a map for from feature and the match iterator
00050   //
00051   typedef rgrl_match_set::const_from_iterator  from_feature_iterator;
00052   vcl_map< rgrl_feature_sptr, from_feature_iterator > feature_sptr_iterator_map;
00053   if ( allow_reuse_match )
00054   {
00055     for ( from_feature_iterator i=old_matches->from_begin(); i!=old_matches->from_end(); ++i )
00056       feature_sptr_iterator_map[ i.from_feature() ] = i;
00057   }
00058 
00059   // create the new match set
00060   //
00061   rgrl_match_set_sptr matches_sptr
00062     = new rgrl_match_set( from_set.type(), to_set.type(), from_set.label(), to_set.label() );
00063 
00064   //  get the features in the current view
00065   feat_vector from;
00066   if ( !current_view.features_in_region( from, from_set ) ) {
00067     DebugMacro( 1, "Cannot get features in current region!!!" << vcl_endl );
00068     return matches_sptr;
00069   }
00070 
00071   // reserve size
00072   feat_vector matching_features;
00073   matching_features.reserve( 10 );
00074 
00075   matches_sptr->reserve( from.size() );
00076 
00077   //  generate the matches for each feature of this feature type in the current region
00078   vnl_vector<double> prev_mapped;
00079   int reuse_match_count = 0;
00080   for ( feat_iter fitr = from.begin(); fitr != from.end(); ++fitr )
00081   {
00082     rgrl_feature_sptr mapped = (*fitr)->transform( current_xform );
00083     if ( !validate( mapped, current_view.to_image_roi() ) )
00084       continue;   // feature is invalid
00085 
00086     matching_features.clear();
00087 
00088     if ( allow_reuse_match )
00089     {
00090       prev_xform_->map_location( (*fitr)->location(), prev_mapped );
00091 
00092       // if the mapping difference is smaller than this threshold
00093       vcl_map< rgrl_feature_sptr, from_feature_iterator >::const_iterator map_itr;
00094       if ( vnl_vector_ssd( prev_mapped, mapped->location() ) < sqr_thres_for_reuse_match_  &&
00095           (map_itr=feature_sptr_iterator_map.find( *fitr )) != feature_sptr_iterator_map.end() )
00096       {
00097         // re-use the to features
00098         const from_feature_iterator& prev_from_iter = map_itr->second;
00099         for ( from_feature_iterator::to_iterator titr=prev_from_iter.begin(); titr!=prev_from_iter.end(); ++titr )
00100           matching_features.push_back( titr.to_feature() );
00101 
00102         // increament the count
00103         ++reuse_match_count;
00104       }
00105       else
00106         to_set.k_nearest_features( matching_features, mapped, k_ );
00107     }
00108     else
00109       to_set.k_nearest_features( matching_features, mapped, k_ );
00110 
00111     if ( debug_flag()>=4 )
00112     {
00113       vcl_cout << " From feature: ";
00114       (*fitr)->write( vcl_cout );
00115       vcl_cout << vcl_endl;
00116       for ( unsigned i=0; i<matching_features.size(); ++i ) {
00117         vcl_cout << " ###### " << i << " ###### " << vcl_endl;
00118         matching_features[i]->write(vcl_cout);
00119       }
00120     }
00121 
00122 
00123     // find the one most similar
00124     double max_weight = -1;
00125     double min_eucl_dist = 1e10;
00126     rgrl_feature_sptr max_feature;
00127     for ( feat_iter i = matching_features.begin(); i != matching_features.end(); ++i )
00128     {
00129       double eucl_dist = vnl_vector_ssd( (*i)->location(), mapped->location() );
00130       if ( thres_ > 0 && eucl_dist > thres_ )
00131          continue;
00132 
00133       double wgt = (*i)->absolute_signature_weight( mapped );
00134 
00135       if ( wgt > max_weight )
00136       {
00137         // more similar feature is always preferred.
00138         max_weight = wgt;
00139         min_eucl_dist = eucl_dist;
00140         max_feature = *i;
00141       }
00142       else if ( vcl_abs( wgt-max_weight) < 1e-12 && eucl_dist < min_eucl_dist )
00143       {
00144         // when the weights are approximately the same,
00145         // but one point is closer than the other,
00146         // use the closer point
00147         max_weight = wgt;
00148         min_eucl_dist = eucl_dist;
00149         max_feature = *i;
00150       }
00151     }
00152 
00153     // Add match
00154     // for consistent behavior, use
00155     // add_feature_and_matches() which computes the signature weight
00156     // We could also add one match with max_weight, which
00157     // should be identical action.
00158     //
00159 
00160     //feat_vector pruned_set;
00161     //if ( max_feature )
00162     //  pruned_set.push_back( max_feature );
00163     //
00164     //matches_sptr->add_feature_and_matches( *fitr, mapped, pruned_set );
00165 
00166     if ( max_feature )
00167     {
00168       matches_sptr->add_feature_and_match( *fitr, mapped, max_feature, max_weight );
00169       DebugMacro( 4, " ====== Final Choice ======\n" );
00170       if ( debug_flag() >=4 ) {
00171         max_feature->write(vcl_cout);
00172         vcl_cout << vcl_endl;
00173       }
00174     }
00175   }
00176 
00177   DebugMacro( 1, "There are " << reuse_match_count << " reuse of previous matches out of " << from.size() << vcl_endl );
00178 
00179   // store xform
00180   prev_xform_ = current_view.xform_estimate();
00181 
00182   return matches_sptr;
00183 }
00184 
00185 
00186 //  It is to restrict the number of nearest neighbors during the inversion.
00187 void
00188 rgrl_matcher_k_nearest_pick_one::
00189 add_one_flipped_match( rgrl_match_set_sptr&      inv_set,
00190                        rgrl_view          const& current_view,
00191                        nodes_vec_iterator const& begin_iter,
00192                        nodes_vec_iterator const& end_iter )
00193 {
00194   const unsigned int size = unsigned( end_iter - begin_iter );
00195   rgrl_transformation_sptr const& inverse_xform = current_view.inverse_xform_estimate();
00196 
00197   // create from feature and map it via inverse transformation
00198   rgrl_feature_sptr from = begin_iter->to_;
00199   rgrl_feature_sptr mapped = from->transform( *inverse_xform );
00200 
00201   // check mapped
00202   if ( !validate( mapped, current_view.from_image_roi() ) )
00203     return;
00204 
00205   // for consistent behavior,
00206   // pick the k nearest neighbor,
00207   // and then pick the one with highest similarity
00208   //
00209 
00210   // compute the distance
00211   // REMEMBER: the to is from, from is to. Everything is inversed
00212   //
00213   vcl_vector< internal_dist_node > dist_nodes;
00214   dist_nodes.reserve( size );
00215   for ( nodes_vec_iterator itr = begin_iter; itr!=end_iter; ++itr )
00216   {
00217     internal_dist_node tmp_node;
00218 
00219     // NOTE: should not use rgrl_feature::geometric_error() function,
00220     //       because it may compute normal distance, which is not desired
00221     //
00222     tmp_node.geo_err_ = vnl_vector_ssd( itr->from_->location(), mapped->location() );
00223     tmp_node.itr_ = itr;
00224 
00225     // push back
00226     dist_nodes.push_back( tmp_node );
00227   }
00228 
00229   // 1. Kth element based on distance
00230   //
00231   if ( size > k_ )
00232     vcl_nth_element( dist_nodes.begin(), dist_nodes.begin()+k_, dist_nodes.end() );
00233 
00234   // 2. Most similar feature
00235   //
00236   double max_weight = -1.0;
00237   double min_eucl_dist = 1e10;
00238   rgrl_feature_sptr max_feature;
00239   for ( unsigned i=0; i<k_ && i<size; ++i )
00240   {
00241     double eucl_dist = dist_nodes[i].geo_err_;
00242     if ( thres_ > 0 && eucl_dist > thres_ )
00243       continue;
00244 
00245     // one_fea is a feature on the "TO" image. Here the "TO" image
00246     // is the actual From image.
00247     rgrl_feature_sptr const& one_fea = dist_nodes[i].itr_->from_; // from is reversed as to
00248     double wgt = one_fea->absolute_signature_weight( mapped );
00249 
00250     if ( wgt > max_weight )
00251     {
00252       // more similar feature is always preferred.
00253       max_weight = wgt;
00254       min_eucl_dist = eucl_dist;
00255       max_feature = one_fea;
00256     }
00257     else if ( vcl_abs( wgt-max_weight) < 1e-12 && eucl_dist < min_eucl_dist )
00258     {
00259       // when the weights are approximately the same,
00260       // but one point is closer than the other,
00261       // use the closer point
00262       max_weight = wgt;
00263       min_eucl_dist = eucl_dist;
00264       max_feature = one_fea;
00265     }
00266   }
00267 
00268   // add matches
00269   if ( max_feature )
00270     inv_set->add_feature_and_match( from, mapped, max_feature, max_weight );
00271 }
00272 
00273 inline
00274 bool
00275 rgrl_matcher_k_nearest_pick_one::
00276 validate( rgrl_feature_sptr const& mapped, rgrl_mask_sptr const& roi_sptr ) const
00277 {
00278   // if the mapped point is not in the image
00279   if ( !roi_sptr->inside( mapped->location() ) )
00280     return false;
00281 
00282   // Suppose scale=1 is the lowest scale, or the finest resolution
00283   // Any mapped scale below 1 cannot find any correspondence
00284   // due to the pixel discretization.
00285   // In practice, the threshold is a number less than one,
00286   // as feature of real scale=0.9 is still likely to be detected.
00287 
00288   // if the scale is too small to be detected on the other image
00289   const double scale = mapped->scale();
00290   if ( scale!=0 && min_mapped_scale_>0 && scale<min_mapped_scale_ ) {
00291     return false;
00292   }
00293 
00294   // by default,
00295   return true;
00296 }