opencv之特征描述子与匹配(暴力匹配与FLANN匹配)

什么叫特征描述子/匹配

什么是特征描述子
图片具有特有特征
匹配
提取一份图像中的特征,去训练集图像库寻找,寻找贴合区域


一些用到的API介绍

函数api

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

参数介绍
两个函数的区别仅在于DMatch数据接收的数据类型不同

  • img1:接收的第一幅源图像
  • keypoints1:KeyPoint类型的关键点(特征点),由第一幅图像检测得到
  • img2:接收的第二幅图像
  • keypoints2:KeyPoint类型的关键点(特征点),由第二幅图像检测得到
  • matches1to2:DMatch类型矢量,表示从第一幅到第二幅图像的匹配点,表示每一个图1中的特征点豆在图2中有一一对应的点
  • outImg:完成匹配后的输出图像,其内容取决于输出图像的标志位flags
  • matchColor:两个匹配点进行绘制匹配的颜色,即线和点的颜色,有默认值表示颜色随机生成
  • singlePointColor:对于没有匹配对的特征点绘制颜色
  • matchesMask:确定哪些是会绘制出来的掩膜,如果掩膜为空,表示所有匹配都进行绘制
  • flags:绘制匹配的标志位,有默认值DrawMatchesFlags::DEFAULT。其可选项如下:
enum  { 
          DEFAULT = 0,  //创建输出图像矩阵,对每一个特征点都只绘制其中间部分。
          DRAW_OVER_OUTIMG = 1,     //不创建输出图像矩阵,而是在输出图像上绘制匹配对
          NOT_DRAW_SINGLE_POINTS = 2,   //单点特征点不被绘制
          DRAW_RICH_KEYPOINTS = 4       //对每个特征点,绘制带大小和方向的关键点图像
      }

暴力匹配

循规蹈矩逐行逐列去匹配
例如下面的例子:使用SURF特征提取BF匹配方法进行匹配(暴力匹配)

#include 
#include 
#include 

using namespace std;
using namespace cv;
using namespace cv::xfeatures2d;

#define PIC_PATH "/work/opencv_pic/"
#define PIC_NAME "opencv.jpg"

#define PIC_PATH1 "/work/opencv_pic/"
#define PIC_NAME1 "opencvbkp.jpg"

int main(void)
{
    Mat src,src1;

    //获取完整的图片路径及名称
    string pic = string(PIC_PATH1)+string(PIC_NAME1);
    string pic1 = string(PIC_PATH)+string(PIC_NAME);

    //打印图片路径
    cout << "pic path is :"<<pic<<endl;
    cout << "pic1 path is :"<<pic1<<endl;
    //读取图片
    src = imread(pic,IMREAD_GRAYSCALE);
    src1 = imread(pic1,IMREAD_GRAYSCALE);
    //判断图片是否存在
    if(src.empty() || src1.empty())
    {
        cout<<"pic is not exist!!!!"<<endl;
        return -1;
    }

    //显示图片
    namedWindow("src pic",WINDOW_AUTOSIZE);
    imshow("src pic",src);
    namedWindow("src1 pic",WINDOW_AUTOSIZE);
    imshow("src1 pic",src1);


    int minHessian = 400;
    vector<KeyPoint> keypoint1,keypoint2;   //描述子
    Mat descriptor1,descriptor2;            //描述图像

    Ptr<SURF> detector = SURF::create(minHessian);   //创建SURF对象

    //计算特征值
    detector->detectAndCompute(src,Mat(),keypoint1,descriptor1);
    detector->detectAndCompute(src1,Mat(),keypoint2,descriptor2);


    BFMatcher matcher;
    vector<DMatch> matches;
    matcher.match(descriptor1,descriptor2,matches);

    Mat matchimages;
    drawMatches(src,keypoint1,src1,keypoint2,matches,matchimages);
    imshow("matchImages",matchimages);

    waitKey(0);
    destroyAllWindows();
    return 0;
}

代码运行效果

opencv之特征描述子与匹配(暴力匹配与FLANN匹配)_第1张图片

FLANN特征匹配

最近邻搜索的问题在图像识别、数据压缩、模式识别和分类、机器学习、文档检索系统、统计和数据分析等方面是一个重大问题,在高维空间中解决这个问题似乎是一个非常难以执行的任务,没有算法明显优于标准的蛮力搜索,因此越来越多的人把兴趣点转向执行最近邻搜索的一类算法。
FLANN(Fast Library for Approximate Nearest Neighbors)时目前最完整的近似近邻开源库,不但实现了一系列查找算法还包含了一种自动选取最快算法的机制。
opencv中提供了函数FlannBasedMatcher()函数


代码演示

#include 
#include 
#include 

using namespace std;
using namespace cv;
using namespace cv::xfeatures2d;

#define PIC_PATH "/work/opencv_pic/"
#define PIC_NAME "opencv.jpg"

#define PIC_PATH1 "/work/opencv_pic/"
#define PIC_NAME1 "opencvbkp.jpg"

int main(void)
{
    Mat src,src1;

    //获取完整的图片路径及名称
    string pic = string(PIC_PATH1)+string(PIC_NAME1);
    string pic1 = string(PIC_PATH)+string(PIC_NAME);

    //打印图片路径
    cout << "pic path is :"<<pic<<endl;
    cout << "pic1 path is :"<<pic1<<endl;
    //读取图片
    src = imread(pic,IMREAD_GRAYSCALE);
    src1 = imread(pic1,IMREAD_GRAYSCALE);
    //判断图片是否存在
    if(src.empty() || src1.empty())
    {
        cout<<"pic is not exist!!!!"<<endl;
        return -1;
    }

    //显示图片
    namedWindow("src pic",WINDOW_AUTOSIZE);
    imshow("src pic",src);
    namedWindow("src1 pic",WINDOW_AUTOSIZE);
    imshow("src1 pic",src1);


    int minHessian = 400;
    vector<KeyPoint> keypoint1,keypoint2;   //描述子
    Mat descriptor1,descriptor2;            //描述图像

    Ptr<SURF> detector = SURF::create(minHessian);   //创建SURF对象

    //计算特征值
    detector->detectAndCompute(src,Mat(),keypoint1,descriptor1);
    detector->detectAndCompute(src1,Mat(),keypoint2,descriptor2);

    //BFMatcher matcher;
    FlannBasedMatcher matcher;   //Flann匹配器
    vector<DMatch> matches;      //匹配数据
    matcher.match(descriptor1,descriptor2,matches);   //描述匹配 将匹配结果存放至matches
    
    //flann匹配基于距离匹配 进行最优距离查找
    float maxdist = 3;
    float mindist = 100;

    //通过逐步收敛的办法查找到最大值最小值
    for(int i=0;i<descriptor1.rows;i++)
    {
        float distance = matches[i].distance;
        distance*=100;
         cout<<"distance: "<<distance<<endl;
        if(distance>maxdist)
            maxdist = distance;
        if(distance<mindist)
            mindist = distance;
    }

    //将最大值 最小值打印出来
    cout<<"maxdist: "<<maxdist<<endl;
    cout<<"mindist: "<<mindist<<endl;

    vector<DMatch> goodmatches;   //定义最优的距离点集合
    for(int i=0;i<descriptor1.rows;i++)
    {
        float distance = matches[i].distance;
        if(distance*100<=2*mindist)
        {
            //将查找到的最小距离添加到goodmatches中
            goodmatches.push_back(matches[i]);
        }
    }
    Mat matchimages;
    //绘制匹配点 点数大大减少
    drawMatches(src,keypoint1,src1,keypoint2,goodmatches,matchimages);
    imshow("matchImages",matchimages);
    
    waitKey(0);
    destroyAllWindows();
    return 0;
}


代码运行效果

opencv之特征描述子与匹配(暴力匹配与FLANN匹配)_第2张图片

你可能感兴趣的:(opencv)