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

来源:互联网 发布:魔兽世界月卡 知乎 编辑:程序博客网 时间:2024/04/28 06:53

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就是交叉匹配,剔除不好的匹配。有论文支撑,大家感兴趣可以去搜。

3 0
原创粉丝点击