OpenCV中特徵檢測,提取與匹配使用方法學習

最近在學習OpenCV,一般看官方一邊看書,發現自己原來用的很多接口早已被更新,分享一下學習心得體會,也希望大家可以不吝賜教!
        首先看到在Mastering OpenCV with Practical Computer Vision Projects書中,特徵點檢測,特徵點描述(特徵提取),特徵點匹配用了以下代碼:

  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 plaincopy
  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二值化方法也是類似的調用方法:

  1. cv::Ptr<cv::CLAHE> cl = createCLAHE(80, Size(4, 4))  
  2. cl->apply(imSrc, ImDst);  
       特徵提取好了以後,OpenCV也提供了非常方便的特徵匹配函數,繼承於DescriptorMatcher類,包括BFMatcher,FlannBasedMatcher。這部分文檔還沒細看……歡迎大家指導!
CV自帶的特徵匹配和特徵匹配結果繪製函數簡直易用的令人髮指……請看:
[html] view plaincopy
  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方法計算透視變換矩陣來篩選符合相同透視的特徵點,這樣做可以去除很多錯誤的匹配。
  1. std::vector<unsigned char> inliersMask(srcPoints.size());  
  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版本以後檢測,特徵提取與匹配方法。如果調用遇到困難,還是可以直接查看源碼來的更快捷。

  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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章