Opencv(C++)学习系列---特征点检测和匹配

简介: Opencv(C++)学习系列---特征点检测和匹配

关于特征检测和匹配的具体原理会在后续的文章中具体讲解,本文主要介绍Opencv实现的简单过程:

第一步:定义特征检测器(SIFT,SURF,ORB等)。

第二步:对图像中特征点进行检测,并将特征点存储在Keypoints中。

第三步:提取特征点的描述信息。

第四步:定义特征匹配器(特征匹配的方法主要有两种分别为暴力匹配BFmatch和FlannBased)。

第五步:过滤掉较差的匹配点位(一般根据临近两点的距离进行过滤)

主要是根据DMatch中的distance进行过滤,对于distance可以抽象理解为匹配的分值,distance越小说明检测点的相似度越高,效果越好。

第六步:对匹配的特征点显示。

代码1(未滤波,只限制筛选点数为20)

#include <iostream>
#include <opencv2/opencv.hpp>  
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\imgproc\imgproc.hpp>
#include <opencv2/xfeatures2d.hpp>
using namespace cv;  //包含cv命名空间
using namespace std;
using namespace xfeatures2d;
int main() {
  system("color 2E");
  //载入图片
  Mat src1 = imread("E:\\乔大花进度\\11-18\\sift特征检测和匹配\\3.jpg",1);
  Mat src2 = imread("E:\\乔大花进度\\11-18\\sift特征检测和匹配\\4.jpg", 1);
  //显示原图
  imshow("原图1",src1);
  imshow("原图2", src2);
  //定义变量
  vector<KeyPoint> keypoints1, keypoints2;//定义检测的特征点存储容器
  Mat descriptors1,descriptors2;//定义特征点描述信息为Mat类型
  Mat result_img;//匹配结果图片
  //创建sift特征检测器实例
  //将SIFT可以换位SURF、ORB
  Ptr<SIFT>detector = SIFT::create();
  //提取特征点
  detector->detect(src1,keypoints1,noArray());
  detector->detect(src2, keypoints2, Mat());
  //获取特征点的描述信息=>特征向量
  detector->compute(src1,keypoints1,descriptors1);
  detector->compute(src2, keypoints2, descriptors2);
  //定义匹配器的实例化=>方法为暴力匹配法
  Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(DescriptorMatcher::BRUTEFORCE);//create中的参数可以填string FlannBased等匹配方法
  //第二种实例化方法
  //BFMatcher matcher;
  //进行暴力匹配
  vector<DMatch> matches;
  //第一个参数为queryDescription为目标,第二个参数为trainDescription模板
  matcher->match(descriptors1,descriptors2,matches);
  //限制特征点匹配数量=》只匹配前20个较好的特征点
  int num = 20;
  nth_element(matches.begin(), matches.begin()+num,matches.end());
  //vector去除20以后的元素
  matches.erase(matches.begin()+num,matches.end());
  
  //输出关键点和匹配结果
  //其中右侧图为trainDescription模板,左侧图为queryDescription目标
  //左图中的点与右图中进行匹配对应
  drawMatches(src1,keypoints1,src2,keypoints2, matches,result_img);
  drawKeypoints(src1,keypoints1,src1);
  drawKeypoints(src2,keypoints2,src2);
  
  imshow("匹配结果",result_img);
  imshow("特征点1",src1);
  imshow("特征点2",src2);
  waitKey(0);
  system("pause");
  return 0;
}

运行结果为:

代码2(通过距离进行滤波)

#include <iostream>
#include <opencv2/opencv.hpp>  
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\imgproc\imgproc.hpp>
#include <opencv2/xfeatures2d.hpp>
using namespace cv;  //包含cv命名空间
using namespace std;
using namespace xfeatures2d;
int main() {
  system("color 2E");
  //载入图片
  Mat src1 = imread("E:\\乔大花进度\\11-18\\sift特征检测和匹配\\3.jpg",1);
  Mat src2 = imread("E:\\乔大花进度\\11-18\\sift特征检测和匹配\\4.jpg", 1);
  //显示原图
  imshow("原图1",src1);
  imshow("原图2", src2);
  //定义变量
  vector<KeyPoint> keypoints1, keypoints2;//定义检测的特征点存储容器
  Mat descriptors1,descriptors2;//定义特征点描述信息为Mat类型
  Mat result_img;//匹配结果图片
  //创建sift特征检测器实例
  //将SIFT可以换位SURF、ORB
  Ptr<SIFT>detector = SIFT::create();
  //提取特征点
  detector->detect(src1,keypoints1,noArray());
  detector->detect(src2, keypoints2, Mat());
  //获取特征点的描述信息=>特征向量
  detector->compute(src1,keypoints1,descriptors1);
  detector->compute(src2, keypoints2, descriptors2);
  //定义匹配器的实例化=>方法为暴力匹配法
  Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(DescriptorMatcher::BRUTEFORCE);//create中的参数可以填string FlannBased等匹配方法
  //第二种实例化方法
  //BFMatcher matcher;
  //进行暴力匹配
  vector<DMatch> matches;
  //第一个参数为queryDescription为目标,第二个参数为trainDescription模板
  matcher->match(descriptors1,descriptors2,matches);
  //限制特征点匹配数量=》只匹配前20个较好的特征点
  int num = 20;
  nth_element(matches.begin(), matches.begin()+num,matches.end());
  //vector去除20以后的元素
  matches.erase(matches.begin()+num,matches.end());
  
  double Max_distance = matches[1].distance;
  double Min_distance = matches[1].distance;
  vector<DMatch> goodfeatrues;
  
  //根据特征点的距离去筛选
  for (int i = 0; i < matches.size(); i++)
  {
    double dist = matches[i].distance;
    if (dist>Max_distance)
    {
      Max_distance = dist;
    }
    if (dist<Min_distance)
    {
      Min_distance = dist;
    }
    
  }
  cout << "匹配点的最大距离:" << Max_distance << endl;
  cout << "匹配点的最小距离:" << Min_distance << endl;
  //M为距离阈值,M越大点数越多
  double M = 1.3;
  for (int  i = 0; i < matches.size(); i++)
  {
    double dist = matches[i].distance;
    if (dist<M*Min_distance)    {
      goodfeatrues.push_back(matches[i]);
    }
  }
  cout << "最终选取特征点的数量为:" << matches.size() << endl;
  //输出关键点和匹配结果
  //其中右侧图为trainDescription模板,左侧图为queryDescription目标
  //左图中的点与右图中进行匹配对应
  drawMatches(src1,keypoints1,src2,keypoints2, goodfeatrues,result_img);
  drawKeypoints(src1,keypoints1,src1);
  drawKeypoints(src2,keypoints2,src2);
  
  imshow("匹配结果",result_img);
  imshow("特征点1",src1);
  imshow("特征点2",src2);
  waitKey(0);
  system("pause");
  return 0;
}

运行结果为:

代码3(通过knnMatch匹配,可以通过对distance设置阈值进行滤波,效果最好)

#include <iostream>
#include <opencv2/opencv.hpp>  
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\imgproc\imgproc.hpp>
#include <opencv2/xfeatures2d.hpp>
using namespace cv;  //包含cv命名空间
using namespace std;
using namespace xfeatures2d;
int main() {
  system("color 2E");
  //载入图片
  Mat src1 = imread("E:\\乔大花进度\\11-18\\sift特征检测和匹配\\3.jpg",1);
  Mat src2 = imread("E:\\乔大花进度\\11-18\\sift特征检测和匹配\\4.jpg", 1);
  //显示原图
  imshow("原图1",src1);
  imshow("原图2", src2);
  //定义变量
  vector<KeyPoint> keypoints1, keypoints2;//定义检测的特征点存储容器
  Mat descriptors1,descriptors2;//定义特征点描述信息为Mat类型
  Mat result_img;//匹配结果图片
  //创建sift特征检测器实例
  //将SIFT可以换位SURF、ORB
  Ptr<SIFT>detector = SIFT::create();
  //提取特征点
  detector->detect(src1,keypoints1,noArray());
  detector->detect(src2, keypoints2, Mat());
  //获取特征点的描述信息=>特征向量
  detector->compute(src1,keypoints1,descriptors1);
  detector->compute(src2, keypoints2, descriptors2);
  //定义匹配器的实例化=>方法为暴力匹配法
  Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(DescriptorMatcher::BRUTEFORCE);//create中的参数可以填string FlannBased等匹配方法
  //第二种实例化方法
  //BFMatcher matcher;
  //进行暴力匹配
  vector<DMatch> matches;
  vector<Mat>train_desc(1, descriptors2);
  matcher->add(train_desc);
  matcher->train();
  vector<vector<DMatch>> matchpoints;
  matcher->knnMatch(descriptors1,matchpoints,2);
  vector<DMatch> goodfeatur;
  for (int i = 0; i < matchpoints.size(); i++)
  {
    if (matchpoints[i][0].distance<0.15*matchpoints[i][1].distance)
    {
      goodfeatur.push_back(matchpoints[i][0]);
    }
  }
  cout << "筛选后的特征点数量为: " << goodfeatur.size() << endl;
  //输出关键点和匹配结果
  //其中右侧图为trainDescription模板,左侧图为queryDescription目标
  //左图中的点与右图中进行匹配对应
  drawMatches(src1,keypoints1,src2,keypoints2, goodfeatur,result_img);
  drawKeypoints(src1,keypoints1,src1);
  drawKeypoints(src2,keypoints2,src2);
  
  namedWindow("匹配结果",WINDOW_NORMAL);
  resizeWindow("匹配结果",500,500);
  imshow("匹配结果",result_img);
  waitKey(0);
  system("pause");
  return 0;
}

运行结果为:

相关文章
|
2月前
|
计算机视觉
Opencv学习笔记(八):如何通过cv2读取视频和摄像头来进行人脸检测(jetson nano)
如何使用OpenCV库通过cv2模块读取视频和摄像头进行人脸检测,并提供了相应的代码示例。
119 1
|
1天前
|
算法 网络安全 区块链
2023/11/10学习记录-C/C++对称分组加密DES
本文介绍了对称分组加密的常见算法(如DES、3DES、AES和国密SM4)及其应用场景,包括文件和视频加密、比特币私钥加密、消息和配置项加密及SSL通信加密。文章还详细展示了如何使用异或实现一个简易的对称加密算法,并通过示例代码演示了DES算法在ECB和CBC模式下的加密和解密过程,以及如何封装DES实现CBC和ECB的PKCS7Padding分块填充。
13 4
2023/11/10学习记录-C/C++对称分组加密DES
|
4月前
|
算法 C语言 C++
C++语言学习指南:从新手到高手,一文带你领略系统编程的巅峰技艺!
【8月更文挑战第22天】C++由Bjarne Stroustrup于1985年创立,凭借卓越性能与灵活性,在系统编程、游戏开发等领域占据重要地位。它继承了C语言的高效性,并引入面向对象编程,使代码更模块化易管理。C++支持基本语法如变量声明与控制结构;通过`iostream`库实现输入输出;利用类与对象实现面向对象编程;提供模板增强代码复用性;具备异常处理机制确保程序健壮性;C++11引入现代化特性简化编程;标准模板库(STL)支持高效编程;多线程支持利用多核优势。虽然学习曲线陡峭,但掌握后可开启高性能编程大门。随着新标准如C++20的发展,C++持续演进,提供更多开发可能性。
89 0
|
2月前
|
机器学习/深度学习 计算机视觉
目标检测笔记(六):如何结合特定区域进行目标检测(基于OpenCV的人脸检测实例)
本文介绍了如何使用OpenCV进行特定区域的目标检测,包括人脸检测实例,展示了两种实现方法和相应的代码。
80 1
目标检测笔记(六):如何结合特定区域进行目标检测(基于OpenCV的人脸检测实例)
|
2月前
|
编译器 C语言 C++
配置C++的学习环境
【10月更文挑战第18天】如果想要学习C++语言,那就需要配置必要的环境和相关的软件,才可以帮助自己更好的掌握语法知识。 一、本地环境设置 如果您想要设置 C++ 语言环境,您需要确保电脑上有以下两款可用的软件,文本编辑器和 C++ 编译器。 二、文本编辑器 通过编辑器创建的文件通常称为源文件,源文件包含程序源代码。 C++ 程序的源文件通常使用扩展名 .cpp、.cp 或 .c。 在开始编程之前,请确保您有一个文本编辑器,且有足够的经验来编写一个计算机程序,然后把它保存在一个文件中,编译并执行它。 Visual Studio Code:虽然它是一个通用的文本编辑器,但它有很多插
|
2月前
|
Ubuntu Linux 编译器
Linux/Ubuntu下使用VS Code配置C/C++项目环境调用OpenCV
通过以上步骤,您已经成功在Ubuntu系统下的VS Code中配置了C/C++项目环境,并能够调用OpenCV库进行开发。请确保每一步都按照您的系统实际情况进行适当调整。
467 3
|
2月前
|
Java 编译器 C++
c++学习,和友元函数
本文讨论了C++中的友元函数、继承规则、运算符重载以及内存管理的重要性,并提到了指针在C++中的强大功能和使用时需要注意的问题。
27 1
|
3月前
|
存储 计算机视觉 C++
在C++中实现Armadillo库与OpenCV库之间的数据格式转换
在C++中实现Armadillo库与OpenCV库之间的数据格式转换是一项常见且实用的技能。上述步骤提供了一种标准的方法来进行这种转换,可以帮助开发者在两个库之间高效地转移和处理数据。虽然转换过程相对直接,但开发者应留意数据类型匹配和性能优化等关键细节。
66 11
|
2月前
|
算法 计算机视觉 Python
圆形检测算法-基于颜色和形状(opencv)
该代码实现了一个圆检测算法,用于识别视频中的红色、白色和蓝色圆形。通过将图像从RGB转换为HSV颜色空间,并设置对应颜色的阈值范围,提取出目标颜色的区域。接着对这些区域进行轮廓提取和面积筛选,使用霍夫圆变换检测圆形,并在原图上绘制检测结果。
90 0
|
3月前
|
存储 计算机视觉 C++
在C++中实现Armadillo库与OpenCV库之间的数据格式转换
在C++中实现Armadillo库与OpenCV库之间的数据格式转换是一项常见且实用的技能。上述步骤提供了一种标准的方法来进行这种转换,可以帮助开发者在两个库之间高效地转移和处理数据。虽然转换过程相对直接,但开发者应留意数据类型匹配和性能优化等关键细节。
31 3