feature_matching.cpp
Go to the documentation of this file.
00001 //part of the source code of master thesis of Jiri Divis, source code written by Jiri Divis
00002 /*------------------------------------------------------------------------------------------*\
00003   This file contains RobustFeatureMatcherStats class, which contains heavily
00004   modyfied code that was taken from the supporting code for chapter 9 of the
00005   book:  
00006   Computer Vision Programming using the OpenCV Library. 
00007   by Robert Laganiere, Packt Publishing, 2011.
00008 
00009 
00010   Original license and copyright:
00011   This program is free software; permission is hereby granted to use, copy, modify, 
00012   and distribute this source code, or portions thereof, for any purpose, without fee, 
00013   subject to the restriction that the copyright notice may not be removed 
00014   or altered from any source or altered source distribution. 
00015   The software is released on an as-is basis and without any warranties of any kind. 
00016   In particular, the software is not guaranteed to be fault-tolerant or free from failure. 
00017   The author disclaims all warranties with regard to this software, any use, 
00018   and any consequent failure, is purely the responsibility of the user.
00019 
00020   Copyright (C) 2010-2011 Robert Laganiere, www.laganiere.name
00021 \*------------------------------------------------------------------------------------------*/
00031 #include "feature_matching.h"
00032 #include "error_func.h"
00033 #include "emat_estimation.h"
00034 #include <ros/console.h>
00035 
00036 
00037 using cv::Mat;
00038 using cv::KeyPoint;
00039 using cv::FeatureDetector;
00040 using cv::DMatch;
00041 using std::vector;
00042 using Eigen::Vector2f;
00043 
00044 void VirtualFeatureDetector::detectImpl(
00045         const Mat& image,
00046         vector<KeyPoint>& keypoints,
00047         const Mat& mask=Mat()) const {
00048     typedef pair<int, Vector2d> T;
00049     BOOST_FOREACH(T pt, points){
00050         keypoints.push_back(KeyPoint(
00051             (float)pt.second(0),
00052             (float)pt.second(1), 
00053             1.0, //size 
00054             -1.0, //angle
00055             0.0, //response
00056             0, //octave
00057             pt.first)); //class_id
00058     }
00059     removeInvalidPoints(mask, keypoints);
00060 }
00061 
00062 
00063 /*------------------------------------------------------------------------------------------*/
00064 
00065 void VirtualDescriptorExtractor::computeImpl(
00066         const Mat& image, vector<KeyPoint>& keypoints, Mat& descriptors ) const{
00067     //XXX not sure if it will work on border pixels
00068     removeBorderKeypoints(keypoints, image.size(), 2);
00069 
00070     descriptors.create(keypoints.size(), descriptorSize(), descriptorType());
00071     for(vector<KeyPoint>::size_type i = 0 ; i < keypoints.size(); i++){
00072         descriptors.at<int>(i, 0) = keypoints[i].class_id;
00073     }
00074 }
00075 
00076 /*------------------------------------------------------------------------------------------*/
00077 
00078 cv::Ptr<cv::DescriptorMatcher> VirtualDescriptorMatcher::clone( bool emptyTrainData ) const{
00079     VirtualDescriptorMatcher * tmp = new VirtualDescriptorMatcher(*this);
00080     tmp->clear();
00081     if(!emptyTrainData){
00082         BOOST_FOREACH(Mat m, trainDescCollection){
00083             tmp->trainDescCollection.push_back(m.clone());
00084         }
00085     }
00086     return tmp;
00087 }
00088 
00089 
00090 void VirtualDescriptorMatcher::knnMatchImpl(
00091         const Mat& queryDescriptors, vector<vector<DMatch> >& matches,
00092         int k, const vector<Mat>& masks, bool compactResult ){
00093     for(int i = 0; i < queryDescriptors.size().height; i++){
00094         vector<DMatch> tmpvec;
00095         assert(trainDescCollection.size() == 1);
00096         int z=k-1;
00097         for(int j = 0; j < trainDescCollection[0].size().height; j++){
00098             if(trainDescCollection[0].at<int>(j,0) == 
00099                     std::tr1::round(queryDescriptors.at<int>(i, 0))
00100                     && isPossibleMatch(masks[0], i, j)){
00101                 boost::uniform_real<> interval(0.0, 1.0);
00102                 double tmp = interval(rng_mt19937);
00103                 if(tmp > inlier_p){
00104                     int max = std::min(queryDescriptors.size().height, trainDescCollection[0].size().height) -1;
00105                     tmpvec.push_back(DMatch(std::min(j, max), std::min(i, max), 0));
00106                 } else{
00107                     tmpvec.push_back(DMatch(i, j, 0));
00108                 }
00109             }
00110             if(!tmpvec.empty() && z && isPossibleMatch(masks[0], i, j)){
00111                 tmpvec.push_back(DMatch(i, j, z));
00112                 z--;
00113             }
00114         }
00115         matches.push_back(tmpvec);
00116     }
00117 }
00118 
00119 void VirtualDescriptorMatcher::radiusMatchImpl(
00120         const Mat& queryDescriptors, vector<vector<DMatch> >& matches, float maxDistance, 
00121         const vector<Mat>& masks, bool compactResult){
00122     assert(false);
00123 }
00124 
00125 
00126 
00127 /*------------------------------------------------------------------------------------------*/
00128 
00129 void RobustFeatureMatcher::nonsymetricalMatch(
00130         const vector<cv::KeyPoint>& train_keypoints,
00131         const vector<cv::KeyPoint>& query_keypoints,
00132         const cv::Mat& train_descriptors,
00133         const cv::Mat& query_descriptors,
00134         RobustFeatureMatcherStats& stats,
00135         vector<cv::DMatch>& matches) {
00136     assert(matcher);
00137 
00138     // train->query match based on k nearest neighbours (with k=2)
00139     std::vector<std::vector<cv::DMatch> > matches0;
00140     matcher->knnMatch(query_descriptors, train_descriptors,
00141             matches0, // vector of matches (up to 2 per entry) 
00142             2);           // return 2 nearest neighbours
00143 
00144     stats.qt=matches0.size();
00145     //ROS_DEBUG_STREAM_NAMED("RobustMatcher", 
00146     //        "Number of non-symetrical feature matches before ratio filter: " << stats.qt);
00147 
00148     // clean image matches
00149     ratioTest(matches0, matches);
00150     stats.ratio_qt=matches.size();
00151     //ROS_DEBUG_STREAM_NAMED("RobustMatcher", 
00152     //        "Number of non-symetrical feature matches: " << stats.ratio_qt);
00153 }
00154 
00155 void RobustFeatureMatcher::symaetricalMatch(
00156         const std::vector<cv::KeyPoint>& keypoints_c1,
00157         const std::vector<cv::KeyPoint>& keypoints_c2,
00158         const cv::Mat& descriptors_c1,
00159         const cv::Mat& descriptors_c2,
00160         RobustFeatureMatcherStats& stats,
00161         std::vector<cv::DMatch>& sym_matches_c1c2){
00162     assert(matcher);
00163 
00164     // from image 1 to image 2.
00165     vector<cv::DMatch> matches_c1c2;
00166     nonsymetricalMatch(
00167             keypoints_c1, keypoints_c2, descriptors_c1, descriptors_c2, stats, matches_c1c2);
00168     stats.tq=stats.qt;
00169     // from image 2 to image 1.
00170     vector<cv::DMatch> matches_c2c1;
00171     nonsymetricalMatch(
00172             keypoints_c2, keypoints_c1, descriptors_c2, descriptors_c1, stats, matches_c2c1);
00173 
00174     // Remove non-symmetrical matches
00175     std::vector<cv::DMatch> symMatches;
00176     symmetryTest(matches_c1c2, matches_c2c1, keypoints_c2.size(), sym_matches_c1c2);
00177     stats.symetry=sym_matches_c1c2.size();
00178     //ROS_DEBUG_STREAM_NAMED("RobustMatcher", 
00179     //        "Number of symetrical feature matches: " << stats.symetry);
00180 }
00181 
00182 
00183 
00184 void RobustFeatureMatcher::ratioTest(
00185         std::vector<std::vector<cv::DMatch> > & matches0,
00186         std::vector<cv::DMatch> & matches) {
00187     assert(matches.size() == 0);
00188     for (std::vector<std::vector<cv::DMatch> >::iterator matchIterator= matches0.begin();
00189             matchIterator!= matches0.end(); ++matchIterator) {
00190         if (matchIterator->size() > 1) { // if 2 NN has been identified
00191             // check distance ratio
00192             if ((*matchIterator)[0].distance/(*matchIterator)[1].distance < ratio) {
00193                 matches.push_back((*matchIterator)[0]);
00194             }
00195         } else { // does not have 2 neighbours
00196             ;
00197         }
00198     }
00199 }
00200 
00201 
00202 
00203 void RobustFeatureMatcher::symmetryTest(
00204         const vector<cv::DMatch>& matches_c1c2,
00205         const vector<cv::DMatch>& matches_c2c1,
00206         int keypoints2_size,
00207         vector<cv::DMatch>& symMatches) {
00208     int BAD_INDEX = -1;
00209     vector<int> keypoint2i_to_match_c2c1i_map = vector<int>( keypoints2_size, BAD_INDEX);
00210     for(size_t i=0; i< matches_c2c1.size(); i++){
00211         keypoint2i_to_match_c2c1i_map[matches_c2c1[i].trainIdx] = i;
00212     }
00213 
00214     std::vector<cv::DMatch>::const_iterator match_c1c2_it = matches_c1c2.begin();
00215     while(match_c1c2_it != matches_c1c2.end()){
00216         int match_c2c1i = keypoint2i_to_match_c2c1i_map[match_c1c2_it->queryIdx];
00217         if(match_c2c1i!=BAD_INDEX){
00218             if(match_c1c2_it->trainIdx == matches_c2c1[match_c2c1i].queryIdx){
00219                 assert(matches_c2c1[match_c2c1i].trainIdx==match_c1c2_it->queryIdx);
00220                 symMatches.push_back(*match_c1c2_it);
00221             }
00222         }
00223         ++match_c1c2_it;
00224     }
00225 }
00226 
00227 
00228 bool RobustFeatureMatcher::ransacTest(
00229         const ImageMatchVec& matches_c1c2,
00230         const vector<cv::DMatch>& dmatches_c1c2,
00231         RobustFeatureMatcherStats& stats,
00232         vector<cv::DMatch>& filtered_matches_c1c2, 
00233         SE3& T_c1c2) {
00234 
00235     unsigned int min_inliers = std::max(
00236             (double)(mbuilder->getSize() + 1), 
00237             std::ceil(dmatches_c1c2.size() * ransac_model_min_inliers_ratio));
00238     if(min_inliers < mbuilder->getSize()){
00239         ROS_WARN_NAMED("RobustMatcher", "Aborting. min_inliers < model_size");
00240         return false;
00241     }
00242     //shared_ptr<EMatrixModel> model = ranSaC(mbuilder, matches_c1c2, ransac_iterations,
00243     //        min_inliers);
00244     typedef RealErrorMaxErrorAccumulator<AngleError> ErrorAccumT; 
00245     typedef EMatrixModel ModelT;
00246     shared_ptr<DataSelector<ModelT::DataVec> > selector(
00247             new RandomDataSelector<ModelT::DataVec>(
00248             matches_c1c2, mbuilder->getSize(), ransac_iterations));
00249     shared_ptr<ModelT> model = ranSaC<ErrorAccumT>(mbuilder, selector, matches_c1c2);
00250     //@todo check min inliers XXX.
00251 
00252     if(!model){
00253         ROS_WARN_NAMED("RobustMatcher", "Aborting. RanSaC could not find a fitting model.");
00254         return false;
00255     }
00256 
00257     MaskVec::const_iterator itIn= model->getInlierMask().begin();
00258     std::vector<cv::DMatch>::const_iterator itM= dmatches_c1c2.begin();
00259     while(itIn!= model->getInlierMask().end()) {
00260         if (*itIn) { // it is a valid match
00261             filtered_matches_c1c2.push_back(*itM);
00262         }
00263         ++itIn, ++itM;
00264     }
00265     stats.ransac=filtered_matches_c1c2.size();
00266 
00267     //TODO XXX
00268     /*if (maximal_data_mbuilder) {
00269         // The F matrix will be recomputed with all accepted matches
00270         // Compute 8-point F from all accepted matches
00271     }*/
00272 
00273     if(extractTransformFromE(model->getModelData(), model->getModel(), T_c1c2)){
00274         //ROS_DEBUG_STREAM_NAMED("RobustMatcher", 
00275         //        "Number of features that passed ransac test: " << stats.ransac);
00276         return true;
00277     } else{
00278         ROS_WARN_NAMED("RobustMatcher", "Aborting. Cannot extract transform.");
00279         return false;
00280     }
00281 }
00282 
00283 void RobustFeatureMatcher::outlierRemoval(
00284         const SE3& T_c1c2,
00285         const ImageMatchVec& matches_c1c2,
00286         const vector<cv::DMatch>& dmatches_c1c2,
00287         RobustFeatureMatcherStats& stats,
00288         vector<cv::DMatch>& filtered_matches_c1c2){ 
00289     Eigen::Matrix3d E = SO3::hat(T_c1c2.translation()) * T_c1c2.rotation_matrix();
00290     ALIGNED<Matrix3d>::vector Ematrices;
00291     Ematrices.push_back(E);
00292     shared_ptr<EMatrixModel> model = 
00293             DummyModelBuilderStd(Ematrices, max_outlier_removal_error)(ImageMatchVec());
00294     model->compute(matches_c1c2);
00295     MaskVec::const_iterator itIn= model->getInlierMask().begin();
00296     std::vector<cv::DMatch>::const_iterator itM= dmatches_c1c2.begin();
00297     while(itIn!= model->getInlierMask().end()) {
00298         if (*itIn) { // it is a valid match
00299             filtered_matches_c1c2.push_back(*itM);
00300         }
00301         ++itIn, ++itM;
00302     }
00303     stats.filter=filtered_matches_c1c2.size();
00304 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines


pose_estimation
Author(s): Jiri Divis/jiridivis@gmail.com
autogenerated on Wed Mar 27 2013 21:00:12