00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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,
00054 -1.0,
00055 0.0,
00056 0,
00057 pt.first));
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
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
00139 std::vector<std::vector<cv::DMatch> > matches0;
00140 matcher->knnMatch(query_descriptors, train_descriptors,
00141 matches0,
00142 2);
00143
00144 stats.qt=matches0.size();
00145
00146
00147
00148
00149 ratioTest(matches0, matches);
00150 stats.ratio_qt=matches.size();
00151
00152
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
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
00170 vector<cv::DMatch> matches_c2c1;
00171 nonsymetricalMatch(
00172 keypoints_c2, keypoints_c1, descriptors_c2, descriptors_c1, stats, matches_c2c1);
00173
00174
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
00179
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) {
00191
00192 if ((*matchIterator)[0].distance/(*matchIterator)[1].distance < ratio) {
00193 matches.push_back((*matchIterator)[0]);
00194 }
00195 } else {
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
00243
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
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) {
00261 filtered_matches_c1c2.push_back(*itM);
00262 }
00263 ++itIn, ++itM;
00264 }
00265 stats.ransac=filtered_matches_c1c2.size();
00266
00267
00268
00269
00270
00271
00272
00273 if(extractTransformFromE(model->getModelData(), model->getModel(), T_c1c2)){
00274
00275
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) {
00299 filtered_matches_c1c2.push_back(*itM);
00300 }
00301 ++itIn, ++itM;
00302 }
00303 stats.filter=filtered_matches_c1c2.size();
00304 }