OpenCV——SURF特征檢測、匹配與對象查找


SURF原理詳解:https://wenku.baidu.com/view/2f1e4d8ef705cc1754270945.html

SURF算法工作原理

 

  1. 選擇圖像中的POI(Points of interest) Hessian Matrix

  2. 在不同的尺度空間發現關鍵點,非最大信號壓制

  3. 發現特征點方法、旋轉不變性要求

  4. 生成特征向量

 SURF構造函數介紹

 

C++:  SURF::SURF(

      double hessianThreshold, --閾值檢測器使用Hessian的關鍵點,默認值在

                                                   300-500之間

      int nOctaves=4,                 -- 4表示在四個尺度空間

      int nOctaveLayers=2,        -- 表示每個尺度的層數

      bool extended=false, 

      bool upright=false              --表示計算旋轉不變性,不計算的速度更快

)

 

特征點繪制

 

特征點繪制是為了把檢測出來的Surf特征點在原圖上繪制出來,這一步是為了把特征點直觀的顯示出來給我們看,跟整個Surf算子的特征提取和匹配流程沒關系。

繪制使用drawKeypoints方法:

void drawKeypoints( const Mat& image,
            const vector<KeyPoint>& keypoints,
            CV_OUT Mat& outImage,
            const Scalar& color=Scalar::all(-1),
            int flags=DrawMatchesFlags::DEFAULT
);

第一個參數image:原始圖像,可以使三通道或單通道圖像;

第二個參數keypoints:特征點向量,向量內每一個元素是一個KeyPoint對象,包含了特征點的各種屬性信息;

第三個參數outImage:特征點繪制的畫布圖像,可以是原圖像;

第四個參數color:繪制的特征點的顏色信息,默認繪制的是隨機彩色;

第五個參數flags:特征點的繪制模式,其實就是設置特征點的那些信息需要繪制,那些不需要繪制,有以下幾種模式可選:

  DEFAULT:只繪制特征點的坐標點,顯示在圖像上就是一個個小圓點,每個小圓點的圓心坐標都是特征點的坐標。
  DRAW_OVER_OUTIMG:函數不創建輸出的圖像,而是直接在輸出圖像變量空間繪制,要求本身輸出圖像變量就是一個初始化好了的,size與type都是已經初始化好的變量
  NOT_DRAW_SINGLE_POINTS:單點的特征點不被繪制
  DRAW_RICH_KEYPOINTS:繪制特征點的時候繪制的是一個個帶有方向的圓,這種方法同時顯示圖像的坐標,size,和方向,是最能顯示特征信息的一種繪制方式。

 

 1 #include <opencv2/opencv.hpp>
 2 #include <opencv2/xfeatures2d.hpp>
 3 #include <iostream>
 4 
 5 using namespace cv;
 6 using namespace cv::xfeatures2d;
 7 using namespace std;
 8 
 9 int main(int argc, char** argv) {
10     Mat src = imread("test.jpg", IMREAD_GRAYSCALE);
11     if (src.empty()) {
12         printf("could not load image...\n");
13         return -1;
14     }
15     namedWindow("input image", CV_WINDOW_AUTOSIZE);
16     imshow("input image", src);
17 
18     // SURF特征點檢測
19     int minHessian = 100;
20     Ptr<SURF> detector = SURF::create(minHessian);//創建一個surf類對象並初始化
21     vector<KeyPoint> keypoints;
22     detector->detect(src, keypoints, Mat());//找出關鍵點
23 
24     // 繪制關鍵點
25     Mat keypoint_img;
26     drawKeypoints(src, keypoints, keypoint_img, Scalar::all(-1), DrawMatchesFlags::DEFAULT);
27     imshow("KeyPoints Image", keypoint_img);
28 
29     waitKey(0);
30     return 0;
31 }

繪制匹配點

 

drawMatches( const Mat& img1, const vector<KeyPoint>& keypoints1,
                             const Mat& img2, const vector<KeyPoint>& keypoints2,
                             const vector<DMatch>& matches1to2, Mat& outImg,
                             const Scalar& matchColor=Scalar::all(-1), const Scalar& singlePointColor=Scalar::all(-1),
                             const vector<char>& matchesMask=vector<char>(), int flags=DrawMatchesFlags::DEFAULT );

其中參數如下:

* img1 – 源圖像1

* keypoints1 –源圖像1的特征點.

* img2 – 源圖像2.

* keypoints2 – 源圖像2的特征點

* matches1to2 – 源圖像1的特征點匹配源圖像2的特征點[matches[i]] .

* outImg – 輸出圖像具體由flags決定.

* matchColor – 匹配的顏色(特征點和連線),若matchColor==Scalar::all(-1),顏色隨機.

* singlePointColor – 單個點的顏色,即未配對的特征點,若matchColor==Scalar::all(-1),顏色隨機.

*matchesMask – Mask決定哪些點將被畫出,若為空,則畫出所有匹配點. 

*flags—它跟drawKeypoints方法中flags的含義是一樣的。

當僅使用篩選出的最優匹配點進行匹配的時候,意味着會有很多非最優的特征點不會被匹配,這時候可以設置flags=DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS 

BF(暴力)匹配(src目標圖,temp需要查找的背景圖)

 1 #include <opencv2/opencv.hpp>
 2 #include <opencv2/xfeatures2d.hpp>
 3 #include <iostream>
 4 
 5 using namespace cv;
 6 using namespace cv::xfeatures2d;
 7 using namespace std;
 8 
 9 int main(int argc, char** argv) {
10     Mat src = imread("數字.jpg");
11     Mat temp = imread("2.png");
12     if (src.empty() || temp.empty()) {
13         printf("could not load image...\n");
14         return -1;
15     }
16     namedWindow("input image", CV_WINDOW_AUTOSIZE);
17     imshow("input image", src);
18 
19     // SURF特征點檢測
20     int minHessian = 400;
21     Ptr<SURF> detector = SURF::create(minHessian, 4, 3, true, true);//創建一個surf類檢測器對象並初始化
22     vector<KeyPoint> keypoints1, keypoints2;
23     Mat src_vector, temp_vector;//用來存放特征點的描述向量
24 
25     //detector->detect(src, keypoints1, Mat());//找出關鍵點
26     //detector->detect(temp, keypoints2, Mat());//找出關鍵點
27 
28     //找到特征點並計算特征描述子(向量)
29     detector->detectAndCompute(src, Mat(), keypoints1, src_vector);//輸入圖像,輸入掩碼,輸入特征點,輸出Mat,存放所有特征點的描述向量
30     detector->detectAndCompute(temp, Mat(), keypoints2, temp_vector);//這個Mat行數為特征點的個數,列數為每個特征向量的尺寸,SURF是64(維)
31 
32 
33     //匹配
34     BFMatcher matcher(NORM_L2);         //實例化一個暴力匹配器(括號里可以選擇匹配方法)
35     
36     vector<DMatch> matches;    //DMatch是用來描述匹配好的一對特征點的類,包含這兩個點之間的匹配信息
37                                //比如左圖有個特征m,它和右圖的特征點n最匹配,這個DMatch就記錄它倆最匹配,並且還記錄m和n的
38                                //特征向量的距離和其他信息,這個距離在后面用來做篩選    
39 
40     matcher.match(src_vector, temp_vector, matches);             //匹配,數據來源是特征向量,結果存放在DMatch類型里面  
41 
42     //匹配點篩選
43     //sort函數對數據進行升序排列
44     //篩選匹配點,根據match里面特征對的距離從小到大排序    
45     //篩選出最優的30個匹配點(可以不使用,會畫出所有特征點)
46 
47     sort(matches.begin(), matches.end());    
48     vector< DMatch > good_matches;
49     int ptsPairs = std::min(30, (int)(matches.size() * 0.15));//匹配點數量不大於50
50     cout << ptsPairs << endl;
51     for (int i = 0; i < ptsPairs; i++)
52     {
53         good_matches.push_back(matches[i]);//距離最小的50個壓入新的DMatch
54     }
55     
56 
57     Mat MatchesImage;                                //drawMatches這個函數直接畫出擺在一起的圖
58     drawMatches(src, keypoints1, temp, keypoints2, good_matches, MatchesImage, Scalar::all(-1), Scalar::all(-1), vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);  //繪制匹配點  
59     imshow("BFMatcher Image", MatchesImage);
60 
61     waitKey(0);
62     return 0;
63 }

 

FLANN匹配

 1 #include <opencv2/opencv.hpp>
 2 #include <opencv2/xfeatures2d.hpp>
 3 #include <iostream>
 4 #include <math.h>
 5 
 6 using namespace cv;
 7 using namespace cv::xfeatures2d;
 8 using namespace std;
 9 
10 int main(int argc, char** argv) {
11     Mat src = imread("數字.jpg",0);
12     Mat temp = imread("2.png",0);
13     if (src.empty() || temp.empty()) {
14         printf("could not load image...\n");
15         return -1;
16     }
17     namedWindow("input image", CV_WINDOW_AUTOSIZE);
18     imshow("input image", src);
19 
20     // SURF特征點檢測
21     int minHessian = 400;
22     Ptr<SURF> detector = SURF::create(minHessian, 4, 3, true, true);//創建一個surf類檢測器對象並初始化
23     vector<KeyPoint> keypoints1, keypoints2;
24     Mat src_vector, temp_vector;//用來存放特征點的描述向量
25 
26     //detector->detect(src, keypoints1, Mat());//找出關鍵點
27     //detector->detect(temp, keypoints2, Mat());//找出關鍵點
28 
29     //找到特征點並計算特征描述子(向量)
30     detector->detectAndCompute(src, Mat(), keypoints1, src_vector);//輸入圖像,輸入掩碼,輸入特征點,輸出Mat,存放所有特征點的描述向量
31     detector->detectAndCompute(temp, Mat(), keypoints2, temp_vector);//這個Mat行數為特征點的個數,列數為每個特征向量的尺寸,SURF是64(維)
32 
33 
34     //匹配
35     FlannBasedMatcher matcher;         //實例化一個FLANN匹配器(括號里可以選擇匹配方法)
36 
37     vector<DMatch> matches;    //DMatch是用來描述匹配好的一對特征點的類,包含這兩個點之間的匹配信息
38                                //比如左圖有個特征m,它和右圖的特征點n最匹配,這個DMatch就記錄它倆最匹配,並且還記錄m和n的
39                                //特征向量的距離和其他信息,這個距離在后面用來做篩選    
40 
41     matcher.match(src_vector, temp_vector, matches);             //匹配,數據來源是特征向量,結果存放在DMatch類型里面  
42 
43     //求最小最大距離
44     double minDistance = 1000;//反向逼近
45     double maxDistance = 0;
46     for (int i=0; i< src_vector.rows; i++) {
47         double distance = matches[i].distance;
48         if (distance > maxDistance)        {
49             maxDistance = distance;
50         }
51         if (distance < minDistance)        { 
52             minDistance = distance;
53         }
54     }
55     printf("max distance : %f\n", maxDistance);
56     printf("min distance : %f\n", minDistance);
57 
58     //篩選較好的匹配點
59     vector< DMatch > good_matches;
60     for (int i = 0; i < src_vector.rows; i++) {
61         double distance = matches[i].distance;
62         if (distance < max(minDistance * 2, 0.02)) {
63             good_matches.push_back(matches[i]);//距離小於范圍的壓入新的DMatch
64         }
65     }
66 
67     /*//sort函數對數據進行升序排列
68     //篩選匹配點,根據match里面特征對的距離從小到大排序
69     //篩選出最優的50個匹配點(可以不使用,會畫出所有特征點)
70 
71     sort(matches.begin(), matches.end());
72     vector< DMatch > good_matches;
73     int ptsPairs = std::min(50, (int)(matches.size() * 0.15));//匹配點數量不大於50
74     cout << ptsPairs << endl;
75     for (int i = 0; i < ptsPairs; i++)
76     {
77         good_matches.push_back(matches[i]);//距離最小的50個壓入新的DMatch
78     }
79     */
80 
81     Mat MatchesImage;                                //drawMatches這個函數直接畫出擺在一起的圖
82     drawMatches(src, keypoints1, temp, keypoints2, good_matches, MatchesImage, Scalar::all(-1), Scalar::all(-1), vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);  //繪制匹配點  
83     imshow("FLANN Image", MatchesImage);
84 
85     waitKey(0);
86     return 0;
87 }

 對象查找

 

 

 

  1 #include <opencv2/opencv.hpp>
  2 #include <opencv2/xfeatures2d.hpp>
  3 #include <iostream>
  4 #include <math.h>
  5 
  6 using namespace cv;
  7 using namespace cv::xfeatures2d;
  8 using namespace std;
  9 
 10 int main(int argc, char** argv) {
 11     Mat src = imread("fire_5.jpg");
 12     Mat temp = imread("數字.jpg");
 13     if (src.empty() || temp.empty()) {
 14         printf("could not load image...\n");
 15         return -1;
 16     }
 17     namedWindow("input image", CV_WINDOW_AUTOSIZE);
 18     imshow("input image", src);
 19 
 20     // SURF特征點檢測
 21     int minHessian = 400;
 22     Ptr<SURF> detector = SURF::create(minHessian, 4, 3, true, true);//創建一個surf類檢測器對象並初始化
 23     vector<KeyPoint> keypoints1, keypoints2;
 24     Mat src_vector, temp_vector;//用來存放特征點的描述向量
 25 
 26     //detector->detect(src, keypoints1, Mat());//找出關鍵點
 27     //detector->detect(temp, keypoints2, Mat());//找出關鍵點
 28 
 29     //找到特征點並計算特征描述子(向量)
 30     detector->detectAndCompute(src, Mat(), keypoints1, src_vector);//輸入圖像,輸入掩碼,輸入特征點,輸出Mat,存放所有特征點的描述向量
 31     detector->detectAndCompute(temp, Mat(), keypoints2, temp_vector);//這個Mat行數為特征點的個數,列數為每個特征向量的尺寸,SURF是64(維)
 32 
 33 
 34     //匹配
 35     FlannBasedMatcher matcher;         //實例化一個FLANN匹配器(括號里可以選擇匹配方法)
 36 
 37     vector<DMatch> matches;    //DMatch是用來描述匹配好的一對特征點的類,包含這兩個點之間的匹配信息
 38                                //比如左圖有個特征m,它和右圖的特征點n最匹配,這個DMatch就記錄它倆最匹配,並且還記錄m和n的
 39                                //特征向量的距離和其他信息,這個距離在后面用來做篩選    
 40 
 41     matcher.match(src_vector, temp_vector, matches);             //匹配,數據來源是特征向量,結果存放在DMatch類型里面  
 42 
 43     //求最小最大距離
 44     double minDistance = 1000;//反向逼近
 45     double maxDistance = 0;
 46     for (int i = 0; i < src_vector.rows; i++) {
 47         double distance = matches[i].distance;
 48         if (distance > maxDistance) {
 49             maxDistance = distance;
 50         }
 51         if (distance < minDistance) {
 52             minDistance = distance;
 53         }
 54     }
 55     printf("max distance : %f\n", maxDistance);
 56     printf("min distance : %f\n", minDistance);
 57 
 58     //篩選較好的匹配點
 59     vector< DMatch > good_matches;
 60     for (int i = 0; i < src_vector.rows; i++) {
 61         double distance = matches[i].distance;
 62         if (distance < max(minDistance * 3, 0.02)) {
 63             good_matches.push_back(matches[i]);//距離小於范圍的壓入新的DMatch
 64         }
 65     }
 66 
 67 
 68     Mat MatchesImage;                                //drawMatches這個函數直接畫出擺在一起的圖
 69     drawMatches(src, keypoints1, temp, keypoints2, good_matches, MatchesImage, Scalar::all(-1), Scalar::all(-1), vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);  //繪制匹配點  
 70     
 71 
 72     vector<Point2f> obj;
 73     vector<Point2f> objInScene;
 74     for (size_t t = 0; t < good_matches.size(); t++) {
 75         obj.push_back(keypoints1[good_matches[t].queryIdx].pt);//返回對象在模板圖特征點坐標
 76         objInScene.push_back(keypoints2[good_matches[t].trainIdx].pt);//返回對象在背景查找圖的坐標
 77     }
 78 
 79     Mat H = findHomography(obj,objInScene,RANSAC);//計算透視變換矩陣
 80 
 81     vector<Point2f> obj_corner(4);
 82     vector<Point2f> scene_corner(4);
 83     obj_corner[0] = Point(0, 0);
 84     obj_corner[1] = Point(src.cols, 0);
 85     obj_corner[2] = Point(src.cols,src.rows);
 86     obj_corner[3] = Point(0, src.rows);
 87 
 88     perspectiveTransform(obj_corner, scene_corner,H);//透視變換
 89 
 90     //畫出邊框線
 91     line(MatchesImage, scene_corner[0] + Point2f(src.cols, 0), scene_corner[1] + Point2f(src.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
 92     line(MatchesImage, scene_corner[1] + Point2f(src.cols, 0), scene_corner[2] + Point2f(src.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
 93     line(MatchesImage, scene_corner[2] + Point2f(src.cols, 0), scene_corner[3] + Point2f(src.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
 94     line(MatchesImage, scene_corner[3] + Point2f(src.cols, 0), scene_corner[0] + Point2f(src.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
 95     imshow("FLANN Image", MatchesImage);
 96 
 97     line(temp, scene_corner[0], scene_corner[1], Scalar(0, 0, 255), 2, 8, 0);
 98     line(temp, scene_corner[1], scene_corner[2], Scalar(0, 0, 255), 2, 8, 0);
 99     line(temp, scene_corner[2], scene_corner[3], Scalar(0, 0, 255), 2, 8, 0);
100     line(temp, scene_corner[3], scene_corner[0], Scalar(0, 0, 255), 2, 8, 0);
101     imshow("temp Image", temp);
102 
103     waitKey(0);
104     return 0;
105 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM