Freak特征描述+BruteForceMatcher匹配+RANSAC剔除误匹配

Freak特征描述+BruteForceMatcher匹配+RANSAC剔除误匹配

时间一晃飞快,前几日的广州之行让人难忘,置身炎热的户外仿佛蒸桑拿一样。这一段时间一直在研究一种从一幅图片中找到给定目标的方法,而基于局部特征提取并且进行特征的匹配可以实现。
目前局部特征描述子有以下几种,

  1. 2004年发展成熟的SIFT
  2. 后来改进的SURF,它们的描述符是高维度整型的数字。
  3. 2010年出现的BRIEF是一种二进制的描述符,这种描述符在提高计算速度方面给出了不错的思路,但是不具备旋转不变,尺度不变,对噪声也比较敏感(虽然它采用了高斯平滑来抗噪声)
  4. 2011年出现的ORB算法同样是二进制,但是解决了旋转不变和噪声敏感的问题,但是不具备尺度不变性。
  5. 2011年同时出现了BRISK算法,解决旋转不变,尺度不变和抗噪声问题,网上有视频,实时性也不错,先有个直观认识,爽死。链接[(http://v.youku.com/v_show/id_XMTI5MzI3Mzk0OA==.html)]
  6. 2012年提出FREAK算法,其实是在BRISK上的改进。具备BRISK的优点。这篇论文中作者表示FREAK算法可以outperform以前所有的描述子。(注意:这里是特征描述子,因为论文中没有给出特征点检测方法,只有特征点的描述子)
    看完了综述,我决定用FREAK来实现。足足耗了我15天,今天我这一段所得写下,勉励自己,服务他人。
    先贴上代码
/************************************************************************
* Copyright(c) 2016  唯疯
* All rights reserved.
*
* Brief: FAST特征点提取以及FREAK描述子的图像匹配,基于OpenCV2.4.8
* Version: 1.0
* Author: 唯疯
* Date: 2016/07/21
* Address: 广州&北京
************************************************************************/
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/nonfree/features2d.hpp>
#include <opencv2/legacy/legacy.hpp>
#include <iostream>
#include <vector>

using namespace std;
using namespace cv;

int main()
{
    Mat img1_src = imread("im5.jpg",0);
    Mat img2_src = imread("im6.jpg",0);
    //FastFeatureDetector fast(40);
    SurfFeatureDetector fast(2000,4);
    FREAK extractor;
    vector<KeyPoint> keypoints1,keypoints2;
    Mat descriptor1,descriptor2;
    vector<DMatch> final_matches; 
    vector<DMatch> matches;

    double t = (double)getTickCount();
    fast.detect(img1_src,keypoints1);
    fast.detect(img2_src,keypoints2);
    //drawKeypoints(img1_src,keypoints1,img1_src,Scalar(0,255,0));
    //drawKeypoints(img2_src,keypoints2,img2_src,Scalar(0,255,0));//问题在这里!!!醉了,这里的问题,浪费了我5天,欧耶,就是整整5天,由于我想在这里看一看检测出来的特征点是啥样的,就跟父母想第一眼就立刻看到刚出生的婴儿是一个心情的。结果,后来特征匹配就几乎没有什么正确匹配,害我还以为是FREAK这个描述子有问题呢。于是就各种找问题,看论文,翻墙逛论坛。最后一个不经意间发现了。问题就是:这俩个语句是把特征点又原封不动的画到了img1_src中,也就是原图像里面,而后来我进行特征点描述的时候,就直接在画满了特征点的图片下进行描述,而不是原图!不是原图啊!是充满了特征点的图片!所以后期再进行匹配的时候,显然,各种乱匹配,就跟隔壁家小狗似的,见了猫都想干坏事。于是乎,我直接注释掉了这两句!
    extractor.compute(img1_src,keypoints1,descriptor1);
    extractor.compute(img2_src,keypoints2,descriptor2);
    BFMatcher matcher(NORM_HAMMING,true);//暴力匹配,并且进行crosscheck,就是说第二个参数选择true。
    matcher.match(descriptor1,descriptor2,matches);
    final_matches=matches;
    cout<<"number of total_matches : "<<final_matches.size()<<endl;

//接下来是RANSAC剔除误匹配
    vector<Point2f> querymatches, trainmatches;
    vector<KeyPoint> p1,p2;
    for(int i=0;i<final_matches.size();i++)
    {
        p1.push_back(keypoints1[final_matches[i].queryIdx]);
        p2.push_back(keypoints2[final_matches[i].trainIdx]);
    }
    for(int i=0;i<p1.size();i++)
    {
        querymatches.push_back(p1[i].pt);
        trainmatches.push_back(p2[i].pt);
    }
    cout<<querymatches[1]<<" and "<<trainmatches[1]<<endl;
    vector<uchar> status;
    Mat h = findHomography(querymatches,trainmatches,status,CV_FM_RANSAC,10);
    int index=0;
    vector<DMatch> super_final_matches;
    for (int i=0;i<final_matches.size();i++)
    {
        cout<<status[i];
        if (status[i] != 0)
        {
        super_final_matches.push_back(final_matches[i]);
            index++;
        }
    }
    cout<<"number of inlier_matches : "<<index<<endl;

    Mat imgMatch;
    drawMatches(img1_src,keypoints1,img2_src,keypoints2,super_final_matches,imgMatch);
    imshow("imgMatch",imgMatch);

    t = ((double)getTickCount()-t)/getTickFrequency();
    cout<<" total time [s] : "<<t<<endl;
    waitKey(0);
    return 0;
}

看看简单的效果
一:
首先说说特征点检测,为什么我用surf,而不用速度很快的fast或者Brisk,我自己做了测试,发现用fast和brisk的话,再用freak描述,最终匹配效果并不好,比sift要差…我其实不太明白为什么,因为有一些后期的论文对比效果说freak综合效果最好,然而我却得不到这样的结果。要继续钻研了,大家有想法欢迎交流,哦不,欢迎指点!
二:
RANSAC的这个算法,请用opencv库中的cvFindHomography,不要用cvFindFundamentalMat,因为这两个是不一样的,字面上简单看一个是找到单应性矩阵,一个是找到基础矩阵,这两个到底有神马区别???
《计算机视觉中的多视图几何》中这样描述:

  1. 2D单应:一幅2D图像中点集到另一幅图像中点集的射影变换。
  2. 基本矩阵:它使一个队所有的点都是的x`Fx=0成立的奇异矩阵F。这是一个3*3的奇异矩阵,而且秩为2,不可逆。它是2维图像上的点通过对极线束约束的映射,是2维到1维的映射。

具体的大家可以看书或者百度,或者等以后我有空了,再具体描述。其实我也没有太懂哈哈哈!还要再看看!慎言慎言!
之前,我曾经自己编写过一个RANSAC的算法啊,但是效果不是特别理想,由于RANSAC算法本身也比较耗时,各路大神们也都提出了很多改进方法,不知道opencv跟进这些改进算法没有?推荐综述型文章《A Universal Framework for Random
Sample Consensus》,里面提到的prosac,lo-ransac速度提升很多!大家自行汲取,我想以后再写一些关于RANSAC的博文。
三:
代码中用到BFMatcher这个类,对象的参数有两个BFMatcher::BFMatcher(int normType=NORM_L2, bool crossCheck=false )。第一个指的是距离,如果是sift或者surf描述的话,就选择NORM_L2和NORM_L2;ORB,BRISK,FREAK这种二进制的描述子就用汉明距离,也就是NORM_HAMMING;NORM_HAMMING2是用作ORB的。第二个参数是是否crossCheck,最好选择true,这个也经过我实验验证,选择true相当于knn匹配中将k置1,也就是只返回最好的那一组匹配,而不是多个近邻。(注意:如果要用knnmatch的话,这个crossCheck的参数就选择false)。这种只返回最好的一组匹配的方式可以作为ratio test的一种替代选择。实验证明,如果选择false,那么将会返回一对多匹配,和多对一的匹配,后期用ransac的效果可能非常不理想。crossCheck就是交叉匹配,剔除不好的匹配。有论文支撑,大家感兴趣可以去搜。

  • 10
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值