contrib/rpl/rgrl/rgrl_matcher_k_nearest.cxx
Go to the documentation of this file.
00001 #include "rgrl_matcher_k_nearest.h"
00002 //:
00003 // \file
00004 // \author Amitha Perera
00005 // \date   Feb 2003
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 bool
00017 rgrl_matcher_k_nearest::internal_dist_node::
00018 operator<( internal_dist_node const& rhs ) const
00019 {
00020   return this->geo_err_ < rhs.geo_err_;
00021 }
00022 
00023 rgrl_matcher_k_nearest::
00024 rgrl_matcher_k_nearest( unsigned int k )
00025   : k_( k ),
00026     thres_( -1.0 )
00027 {
00028 }
00029 
00030 
00031 rgrl_matcher_k_nearest::
00032 rgrl_matcher_k_nearest( unsigned int k, double dist_thres )
00033   : k_( k ),
00034     thres_( dist_thres )
00035 {
00036   if ( thres_ > 0.0 )  thres_ = thres_*thres_;
00037 }
00038 
00039 
00040 rgrl_match_set_sptr
00041 rgrl_matcher_k_nearest::
00042 compute_matches( rgrl_feature_set const&       from_set,
00043                  rgrl_feature_set const&       to_set,
00044                  rgrl_view const&              current_view,
00045                  rgrl_transformation const&    current_xform,
00046                  rgrl_scale const&             /* current_scale */,
00047                  rgrl_match_set_sptr const&    /*old_matches*/ )
00048 {
00049   typedef rgrl_view::feature_vector feat_vector;
00050   typedef feat_vector::const_iterator feat_iter;
00051 
00052   rgrl_match_set_sptr matches_sptr
00053     = new rgrl_match_set( from_set.type(), to_set.type(), from_set.label(), to_set.label() );
00054 
00055   //  get the features in the current view
00056   feat_vector from;
00057   if( !current_view.features_in_region( from, from_set ) ) {
00058     DebugMacro( 1, "Cannot get features in current region!!!" << vcl_endl );
00059     return matches_sptr;
00060   }
00061 
00062   // reserve size
00063   feat_vector matching_features, pruned_set;
00064   matching_features.reserve( 10 );
00065   pruned_set.reserve( 10 );
00066   
00067   matches_sptr->reserve( from.size() );
00068 
00069   //  generate the matches for each feature of this feature type in the current region
00070   for ( feat_iter fitr = from.begin(); fitr != from.end(); ++fitr )
00071   {
00072     rgrl_feature_sptr mapped = (*fitr)->transform( current_xform );
00073     if ( !validate( mapped, current_view.to_image_roi() ) )
00074       continue;   // feature is invalid
00075 
00076     matching_features.clear();
00077     to_set.k_nearest_features( matching_features, mapped, k_ );
00078 
00079     // prune the matches to satisfy the threshold
00080     //
00081     if ( thres_ > 0 ) {
00082       pruned_set.clear();
00083       for ( feat_iter i = matching_features.begin(); i != matching_features.end(); ++i ) {
00084         if ( vnl_vector_ssd( (*i)->location(), mapped->location() ) < thres_ ) {
00085           pruned_set.push_back( *i );
00086         }
00087       }
00088       if ( !pruned_set.empty() ) {
00089         matches_sptr->add_feature_and_matches( *fitr, mapped,
00090                                                pruned_set );
00091       }
00092     } else {
00093       matches_sptr->add_feature_and_matches( *fitr, mapped,
00094                                              matching_features );
00095     }
00096   }
00097 
00098   return matches_sptr;
00099 }
00100 
00101 
00102 //  It is to restrict the number of nearest neighbors during the inversion.
00103 void
00104 rgrl_matcher_k_nearest::
00105 add_one_flipped_match( rgrl_match_set_sptr&      inv_set,
00106                        rgrl_view          const& current_view,
00107                        nodes_vec_iterator const& begin_iter,
00108                        nodes_vec_iterator const& end_iter )
00109 {
00110   const unsigned int size = unsigned( end_iter - begin_iter );
00111   rgrl_transformation_sptr const& inverse_xform = current_view.inverse_xform_estimate();
00112 
00113   // create from feature and map it via inverse transformation
00114   rgrl_feature_sptr from = begin_iter->to_;
00115   rgrl_feature_sptr mapped = from->transform( *inverse_xform );
00116 
00117   if ( !validate( mapped, current_view.from_image_roi() ) )
00118     return;
00119 
00120   // compute the distance
00121   // REMEMBER: the to is from, from is to. Everything is inversed
00122   //
00123   vcl_vector< internal_dist_node > dist_nodes;
00124   dist_nodes.reserve( size );
00125   for ( nodes_vec_iterator itr = begin_iter; itr!=end_iter; ++itr )
00126   {
00127     internal_dist_node tmp_node;
00128 
00129     // NOTE: should not use rgrl_feature::geometric_error() function,
00130     //       because it may compute normal distance, which is not desired
00131     //
00132     tmp_node.geo_err_ = vnl_vector_ssd( itr->from_->location(), mapped->location() );
00133     tmp_node.itr_ = itr;
00134 
00135     // push back
00136     dist_nodes.push_back( tmp_node );
00137   }
00138 
00139   // Kth element based on distance
00140   if ( size > k_ )
00141     vcl_nth_element( dist_nodes.begin(), dist_nodes.begin()+k_, dist_nodes.end() );
00142 
00143   // setup structure
00144   vcl_vector< rgrl_feature_sptr > matching_tos;
00145   vcl_vector< double >            sig_wgts;
00146   matching_tos.reserve( k_ );
00147   sig_wgts.reserve( k_ );
00148 
00149   for ( unsigned i=0; i<k_ && i<size; ++i )
00150   {
00151     if ( thres_ > 0 && dist_nodes[i].geo_err_ > thres_ )
00152       continue;
00153 
00154     nodes_vec_iterator const& current_node = dist_nodes[i].itr_;
00155     matching_tos.push_back( current_node->from_ );
00156 
00157     // recompute the signature weight
00158     //
00159     // double wgt = current_node->sig_wgt_;
00160     double wgt = current_node->from_->absolute_signature_weight( mapped );
00161     sig_wgts.push_back( wgt );
00162     //sig_wgts.push_back( current_node.itr_->sig_wgt_ );
00163   }
00164 
00165   // add matches
00166   if ( ! matching_tos.empty() )
00167     inv_set->add_feature_matches_and_weights( from, mapped, matching_tos, sig_wgts );
00168 }
00169 
00170 bool
00171 rgrl_matcher_k_nearest::
00172 validate( rgrl_feature_sptr const& mapped, rgrl_mask_sptr const& roi_sptr ) const
00173 {
00174   // if the mapped point is not in the image
00175   if ( !roi_sptr->inside( mapped->location() ) )
00176     return false;
00177 
00178   // Suppose scale=1 is the lowest scale, or the finest resolution
00179   // Any mapped scale below 1 cannot find any correspondence
00180   // due to the pixel discretization.
00181   // In practice, the threshold is a number less than one,
00182   // as feature of real scale=0.9 is still likely to be detected.
00183 
00184 #if 0
00185   // if the scale is too small to be detected on the other image
00186   const double scale = mapped->scale();
00187   if ( scale!=0 && scale<0.4 ) {
00188     return false;
00189   }
00190 #endif // 0
00191 
00192   // by default,
00193   return true;
00194 }