• 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...
    ");
    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...
    ");
    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...
    ");
    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
    ", maxDistance);
    56     printf("min distance : %f
    ", 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...
    ");
     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
    ", maxDistance);
     56     printf("min distance : %f
    ", 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 }
  • 相关阅读:
    POJ 2778(自动机+矩阵幂乘(字符串果然是个坑爹玩应!))
    CF357D(规律题,不好想出来!)
    HDU 4107(线段树 特殊懒惰标记)g++ TLE,c++才过(呜呜呜呜)
    hdu 3954(线段树的特殊lazy操作-更新时才遍历!)
    CF354C(思路+(左区间++,1+右区间--思想))
    hdu3851(dp+区间范围很大且有循环的处理方法)
    CF119D(字符串-哈希求解(KMP求了半天,结果哈希更简单!))
    CF 353D
    HDU 4760 字典树(题意比较难理解)
    hdu3649(取石子博弈+dp)
  • 原文地址:https://www.cnblogs.com/long5683/p/9692987.html
Copyright © 2020-2023  润新知