OpenCV中特征检测,提取与匹配使用方法学习

最近在学习OpenCV,一般看官方一边看书,发现自己原来用的很多接口早已被更新,分享一下学习心得体会,也希望大家可以不吝赐教!
        首先看到在Mastering OpenCV with Practical Computer Vision Projects书中,特征点检测,特征点描述(特征提取),特征点匹配用了以下代码:

[cpp]  view plain copy
  1. cv::Ptr<cv::FeatureDetector> detector = new cv::ORB(1000);            // 创建orb特征点检测  
  2. cv::Ptr<cv::DescriptorExtractor> extractor = new cv::FREAK(truetrue);       // 用Freak特征来描述特征点  
  3. cv::Ptr<cv::DescriptorMatcher> matcher = new cv::BFMatcher(cv::NORM_HAMMING,  // 特征匹配,计算Hamming距离  
 看到这段代码的时候很疑惑,为什么可以这么写呢?跟到feature2D.hpp中看了看,发现:

[html]  view plain copy
  1. class CV_EXPORTS_W ORB : public Feature2D  
  2.   
  3. class CV_EXPORTS_W Feature2D : public FeatureDetector, public DescriptorExtractor  

        原来ORB,Feature2D,FeatureDetecter以及DescriptorExtractor之间是这样的继承关系,所以我们可以new一个ORB对象给FeatureDetecter指针了。再搜索一下文档和头文件,还有更多的检测方法,特征描述可以使用。其中ORB既可以作为检测器,也可以作特征提取。
        可以作为检测器的还有BRISK,MSER(特征区域),FastFeatureDetector(应该就是Orb吧?),StarDetector等等。
        可以作特征提取的描述器包括BriefDescriptorExtractor(应该就是Orb吧?)Freak,OpponentColorDescriptorExtractor等等。
        原来OpenCV提供了好多现成的方法,好方便……感叹一下,以前辛辛苦苦码的代码很多就浪费了,用好工具还是很重要那!>_< 顺带一提的是,2.4.5中新增的CLAHE二值化方法也是类似的调用方法:

[cpp]  view plain copy
  1. cv::Ptr<cv::CLAHE> cl = createCLAHE(80, Size(4, 4))  
  2. cl->apply(imSrc, ImDst);  
       特征提取好了以后,OpenCV也提供了非常方便的特征匹配函数,继承于DescriptorMatcher类,包括BFMatcher,FlannBasedMatcher。这部分文档还没细看……欢迎大家指导!
CV自带的特征匹配和特征匹配结果绘制函数简直易用的令人发指……请看:
[html]  view plain copy
  1. vector<DMatch> matches;  
  2. matcher->match(descriptors1, descriptors2, matches);  
  3. Mat imResultOri;  
  4. drawMatches(img1, keypoints1, img2, keypoints2, matches, imResultOri, CV_RGB(0,255,0), CV_RGB(0,255,0));  
        我和我的小伙伴都惊呆了……
        当然啦,做完特征点匹配,我们还可以通过RANSAC方法计算透视变换矩阵来筛选符合相同透视的特征点,这样做可以去除很多错误的匹配。
[cpp]  view plain copy
  1. std::vector<unsigned char> inliersMask(srcPoints.size());  
[cpp]  view plain copy
  1. <span style="font-family: Arial, Helvetica, sans-serif;">homography = cv::findHomography(srcPoints, dstPoints, CV_FM_RANSAC, reprojectionThreshold, inliersMask);</span>  

        到此,一个简单的匹配任务就算是完成啦。
        看完这部分内容最大的心得体会就是,作为一个写工程代码的人来说,要好好的去学习和掌握工具,可以避免好多没有意义的重复劳动。
        跑了一个例子:

运行结果:

特征匹配:


一致的透视变换:


光流:


        以上使用的代码是Mastering OpenCV with Practical Computer Vision Projects书上的源码经整理以后的代码,顺便尝试了一下光流算法的调用。通过对这段源码的学习,基本能够掌握OpenCV2.4版本以后检测,特征提取与匹配方法。如果调用遇到困难,还是可以直接查看源码来的更快捷。

[cpp]  view plain copy
  1. #include <iostream>  
  2. #include <fstream>  
  3. #include <sstream>  
  4.   
  5. #include "opencv2/opencv.hpp"  
  6.   
  7. using namespace cv;  
  8. using namespace std;  
  9.   
  10. void KeyPointsToPoints(vector<KeyPoint> kpts, vector<Point2f> &pts);  
  11.   
  12. bool refineMatchesWithHomography(  
  13.         const std::vector<cv::KeyPoint>& queryKeypoints,  
  14.         const std::vector<cv::KeyPoint>& trainKeypoints,  
  15.         float reprojectionThreshold, std::vector<cv::DMatch>& matches,  
  16.         cv::Mat& homography);  
  17.   
  18. /** @function main */  
  19. int main(int argc, char* argv[]) {  
  20.   
  21.     /************************************************************************/  
  22.     /* 特征点检测,特征提取,特征匹配,计算投影变换                            */  
  23.     /************************************************************************/  
  24.   
  25.     // 读取图片  
  26.     Mat img1Ori = imread("1.jpg", 0);  
  27.     Mat img2Ori = imread("2.jpg", 0);  
  28.   
  29.     // 缩小尺度  
  30.     Mat img1, img2;  
  31.     resize(img1Ori, img1, Size(img1Ori.cols / 4, img1Ori.cols / 4));  
  32.     resize(img2Ori, img2, Size(img2Ori.cols / 4, img2Ori.cols / 4));  
  33.   
  34.     cv::Ptr<cv::FeatureDetector> detector = new cv::ORB(1000);                        // 创建orb特征点检测  
  35.     cv::Ptr<cv::DescriptorExtractor> extractor = new cv::FREAK(truetrue);           // 用Freak特征来描述特征点  
  36.     cv::Ptr<cv::DescriptorMatcher> matcher = new cv::BFMatcher(cv::NORM_HAMMING,  // 特征匹配,计算Hamming距离  
  37.             true);  
  38.   
  39.     vector<KeyPoint> keypoints1;  // 用于保存图中的特征点     
  40.     vector<KeyPoint> keypoints2;    
  41.     Mat descriptors1;               // 用于保存图中的特征点的特征描述  
  42.     Mat descriptors2;                 
  43.   
  44.     detector->detect(img1, keypoints1);      // 检测第一张图中的特征点  
  45.     detector->detect(img2, keypoints2);        
  46.       
  47.     extractor->compute(img1, keypoints1, descriptors1);      // 计算图中特征点位置的特征描述  
  48.     extractor->compute(img2, keypoints2, descriptors2);  
  49.   
  50.     vector<DMatch> matches;  
  51.     matcher->match(descriptors1, descriptors2, matches);  
  52.   
  53.     Mat imResultOri;  
  54.     drawMatches(img1, keypoints1, img2, keypoints2, matches, imResultOri,  
  55.             CV_RGB(0,255,0), CV_RGB(0,255,0));  
  56.     cout << "[Info] # of matches : " << matches.size() << endl;  
  57.   
  58.     Mat matHomo;  
  59.     refineMatchesWithHomography(keypoints1, keypoints2, 3, matches, matHomo);  
  60.     cout << "[Info] Homography T : " << matHomo << endl;  
  61.     cout << "[Info] # of matches : " << matches.size() << endl;  
  62.   
  63.     Mat imResult;  
  64.     drawMatches(img1, keypoints1, img2, keypoints2, matches, imResult,  
  65.             CV_RGB(0,255,0), CV_RGB(0,255,0));  
  66.   
  67.     // 计算光流  
  68.     vector<uchar> vstatus;  
  69.     vector<float> verrs;  
  70.     vector<Point2f> points1;  
  71.     vector<Point2f> points2;  
  72.     KeyPointsToPoints(keypoints1, points1);  
  73.   
  74.     calcOpticalFlowPyrLK(img1, img2, points1, points2, vstatus, verrs);  
  75.   
  76.     Mat imOFKL = img1.clone();  
  77.     for (int i = 0; i < vstatus.size(); i++) {  
  78.         if (vstatus[i] && verrs[i] < 15) {  
  79.             line(imOFKL, points1[i], points2[i], CV_RGB(255,255,255), 1, 8, 0);  
  80.             circle(imOFKL, points2[i], 3, CV_RGB(255,255,255), 1, 8, 0);  
  81.         }  
  82.     }  
  83.   
  84.   
  85.     imwrite("opt.jpg", imOFKL);  
  86.     imwrite("re1.jpg", imResultOri);  
  87.     imwrite("re2.jpg", imResult);  
  88.   
  89.     imshow("Optical Flow", imOFKL);  
  90.     imshow("origin matches", imResultOri);  
  91.     imshow("refined matches", imResult);  
  92.     waitKey();  
  93.   
  94.     return -1;  
  95. }  
  96.   
  97. bool refineMatchesWithHomography(  
  98.         const std::vector<cv::KeyPoint>& queryKeypoints,  
  99.         const std::vector<cv::KeyPoint>& trainKeypoints,  
  100.         float reprojectionThreshold, std::vector<cv::DMatch>& matches,  
  101.         cv::Mat& homography) {  
  102.     const int minNumberMatchesAllowed = 8;  
  103.   
  104.     if (matches.size() < minNumberMatchesAllowed)  
  105.         return false;  
  106.   
  107.     // Prepare data for cv::findHomography  
  108.     std::vector<cv::Point2f> srcPoints(matches.size());  
  109.     std::vector<cv::Point2f> dstPoints(matches.size());  
  110.   
  111.     for (size_t i = 0; i < matches.size(); i++) {  
  112.         srcPoints[i] = trainKeypoints[matches[i].trainIdx].pt;  
  113.         dstPoints[i] = queryKeypoints[matches[i].queryIdx].pt;  
  114.     }  
  115.   
  116.     // Find homography matrix and get inliers mask  
  117.     std::vector<unsigned char> inliersMask(srcPoints.size());  
  118.     homography = cv::findHomography(srcPoints, dstPoints, CV_FM_RANSAC,  
  119.             reprojectionThreshold, inliersMask);  
  120.   
  121.     std::vector<cv::DMatch> inliers;  
  122.     for (size_t i = 0; i < inliersMask.size(); i++) {  
  123.         if (inliersMask[i])  
  124.             inliers.push_back(matches[i]);  
  125.     }  
  126.   
  127.     matches.swap(inliers);  
  128.     return matches.size() > minNumberMatchesAllowed;  
  129. }  
  130.   
  131. void KeyPointsToPoints(vector<KeyPoint> kpts, vector<Point2f> &pts) {  
  132.     for (int i = 0; i < kpts.size(); i++) {  
  133.         pts.push_back(kpts[i].pt);  
  134.     }  
  135.   
  136.     return;  
  137. }  

原文地址:http://blog.csdn.net/u010141147/article/details/9464571

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值