特征检测与匹配笔记(OpenCV3编程入门--毛星云--基于特征的局部匹配算法)

本文深入探讨了立体匹配算法的分类,包括全局匹配与局部匹配算法的特点及应用场景,重点介绍了SURF、SIFT等特征检测算法的原理与OpenCV实现。通过多个示例演示了特征点检测、描述子计算及匹配过程,对比了不同算法的性能。

立体匹配算法分类

1、OpenCV实现的立体匹配算法:可以分为2类:全局匹配算法与局部匹配算法。全局匹配算法精度高,缺点是计算速度慢,实时性差;局部匹配算法分为基于区域的匹配,基于特征的匹配;局部匹配计算速度快,可以满足实时性要求,但是精度较全局匹配差;基于特征的匹配只能得到稀疏的视差,需要靠插值完成视差图的重建;
2、全局匹配算法:OpenCV实现了SGBM(半全局块匹配算法),GC算法(OpenCV3.0以后版本没有实现);
3、基于区域的局部匹配算法:OpenCV实现了BM(块匹配算法);
4、基于特征的局部匹配算法:OpenCV实现了10种特征检测匹配方法:

1. FAST  --FastFeatureDetector;
2. STAR --StarFeatureDetector;
3. SIFT --尺度不变特征变换;
4. SURF --加速鲁棒特征;
5. ORB
6. MSER
7. GFTT
8. HARRIS
9. Dense
10.SimpleBlob 

SURF特征点检测原理

1、SURF : SpeededUp Robust Features , 直译“加速版的具有鲁棒性的特征算法” , SURF是尺度不变特征变换算法(SIFT)的加速版,计算速度更快,在多幅图片下具有更好的稳定性;SURF最大的特征在于采用了Harr特征以及积分图像的概念,大大加快了程序的运行时间;
2、SURF算法原理:
①构建Hessian矩阵,构建高斯金字塔尺度空间;
②利用非极大值抑制初步确定特征点;
③精确定位极值点(采用三维线性插值法得到亚像素级的特征点)
④选取特征点的主方向:
Sift选取特征点主方向是采用在特征点领域内统计其梯度直方图,取直方图bin值最大的以及超过bin值80%的哪些方向作为特征点的主方向;
Surf则是不统计其梯度直方图,而是统计特征点领域内的harr小波特征,取最大值那个扇形的方向作为特征点的主方向;
⑤构造surf特征点描述子(Descriptor):
Sift算法是在特征点周围取1616的领域,将该领域化为44个小区域,每个小区域统计8个方向梯度,最后得到448 = 128维的向量,作为该点的Sift描述子
Surf算法中,在特征点周围取20s(s是所检测到该特征点所在的尺度),然后将该框分为16个子区域,每个区域计算harr小波特征的4个值,所以每个特征点就是16*4=64维的向量,相比Sift,特征点描述子少了一半,特征匹配速度大大加快;

3、OpenCV3.0以后版本中,SURF、SurfFeatureDetector、SurfDescriptorExtractor代表相同含义(typedef定义的别名);(类继承关系)

在这里插入图片描述
在这里插入图片描述
4、SurfFeatureDetector类常用的方法:detect()(寻找特征点)、compute()(计算特征点的描述子);

绘制关键点与KeyPoint类

1、drawKeyPoints()函数:第5个参数flag : 绘制关键点的特征标识符(注意不同参数效果)
在这里插入图片描述
(Google翻译:)
在这里插入图片描述

2、KeyPoint关键点:(使用描述符描述其特征信息)
关键点是角点概念的扩展,对来自图像的小的局部像斑的信息进行编码,使关键点具有高度可辨别性,关键点的描述性信息被概括成描述符的形式,其描述符的维度通常比形成关键点的像素像斑低得多。(摘自Learning OpenCV3)
在这里插入图片描述
在这里插入图片描述

_size : 特征点领域直径
_angle : 特征点方向(0-360),(-1表示不使用)
_response : 关键点强度;
_octave : 关键点所在的图像金字塔的组;
_class_id : 用于聚类的id;

3、Surf、Sift是OpenCV的nofree模块,需要安装opencv_contrib附加库;(CMake编译时需要选择编译平台为x64!)
在这里插入图片描述

Surf特征点检测demo1

#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>   //添加Surf
#include <iostream>

using namespace std;
using namespace cv;
using namespace cv::xfeatures2d;     //添加命名空间

int main(int argc, char** argv)
{
	Mat src = imread("00.jpg", IMREAD_COLOR);
	imshow("input", src);

	int minHessian = 1000;  
	Ptr<SURF> detector = SURF::create(minHessian);
	vector<KeyPoint> keypoint_1;
	detector->detect(src, keypoint_1);			//检测SURF特征关键点

	//绘制KeyPoints
	Mat img_keypoint_1;
	drawKeypoints(src, keypoint_1, img_keypoint_1, Scalar::all(-1), DrawMatchesFlags::DEFAULT);
	//显示KeyPoints
	imshow("detect", img_keypoint_1);

	waitKey(0);
	return 0;
}

在这里插入图片描述
在这里插入图片描述

Surf特征描述子计算与特征匹配(暴力匹配BFMatch)

1、Surf算法为每个检测到的特征定义了位置与尺度,尺度值可用于定义围绕特征点的窗口大小,不论物体的尺度在窗口是什么样的,都将包含相同的视觉信息,这些信息用于表示特征点以使得它们与众不同;
2、OpenCV中,使用Surf进行特征点描述与匹配主要是drawMatches()方法与BruteForceMatcher类使用;
3、drawMatcher() : 绘制两幅图像中的匹配点
在这里插入图片描述
在这里插入图片描述
matchMask : 确定哪些匹配是会绘制出来的掩膜,如果掩膜为空,表示所有匹配都进行绘制;

4、BFMatcher类常用方法:
train() :
训练一个描述符匹配器(例如,flann索引)。在所有要匹配的方法中,方法train()每次在匹配之前都会运行。一些描述符匹配器(例如,BruteForceMatcher)具有此方法的空实现。其他的描述符匹配器真的训练他们的内部结构(例如,FlannBasedMatcher训练flann::Index)。
match() : 查询列表,并与训练好的字典中的描述符进行比较,查询列表上每个关键点与列表中的“最佳匹配”匹配;
knnMatch() : k-最邻近匹配;
radiusMatch() : 半径匹配,返回与查询描述符特定距离内的所有匹配;
在这里插入图片描述

5、特征点匹配步骤:
①Surf算子计算特征点;
②Surf算子计算特征点描述子;
③BruteForceMatcher中的函数match()强行匹配两幅图像的特征向量;

Surf特征点暴力匹配demo2

#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>   //添加Surf
#include <iostream>

using namespace std;
using namespace cv;
using namespace cv::xfeatures2d;     //添加命名空间

int main(int argc, char** argv)
{
   
   
	Mat src1 = imread("1.jpg");
	Mat src2 = imread("2.jpg");

	Ptr<SURF> surfdect = SURF::create(1500);
	//计算Surf特征点
	vector<KeyPoint> keypoint_src1;
	vector<KeyPoint> keypoint_src2;
	surfdect->detect(src1, keypoint_src1);
	surfdect->detect(src2, keypoint_src2);
	//计算描述符(特征向量)
	Mat descriptor_src1;
	Mat descriptor_src2;
	surfdect->compute(src1, keypoint_src1, descriptor_src1);
	surfdect->compute(src2, keypoint_src2, descriptor_src2);
	//匹配两幅图像中的描述子
	vector<DMatch> dMatch;
	Ptr<BFMatcher> bfMatch = BFMatcher::create(NORM_L2, false);
	bfMatch->match(descriptor_src1,descriptor_src2,dMatch);
	//绘制匹配点
	Mat imgMatches;
	drawMatches(src1, keypoint_src1, src2, keypoint_src2, dMatch, imgMatches);

	imshow("BF Match", imgMatches);

	waitKey(0);
	return 0;
}

暴力匹配结果:(许多误匹配点)
在这里插入图片描述

快速近似最近邻逼近搜索函数库(FLANN)

1、FLANN : Fast Library for Approximate Nearest Neighbors;
2、FlannBasedMatcher类继承DescriptorMatcher类;使用match()方法匹配;
在这里插入图片描述
3、match()方法:
在这里插入图片描述
4、DMatch类的四个主要属性:用来存储描述符匹配结果
在这里插入图片描述

FLANN匹配demo3

在这里插入图片描述

#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>   //添加Surf
#include <iostream>

using namespace std;
using namespace cv;
using namespace cv::xfeatures2d;     //添加命名空间

int main(int argc, char** argv)
{
   
   
	Mat src1 = imread("1.jpg");
	Mat src2 = imread("2.jpg");
	//计算Surf特征点
	Ptr<SURF> surfdect = SURF::create(1000);
	vector<KeyPoint> keypoint_src1;
	vector<KeyPoint> keypoint_src2;
	surfdect->detect(src1, keypoint_src1);
	surfdect->detect(src2, keypoint_src2);
	//计算描述符(特征向量)
	Mat descriptor_src1;
	Mat descriptor_src2;
	surfdect->compute(src1, keypoint_src1, descriptor_src1);
	surfdect->compute(src2, keypoint_src2, descriptor_src2);
	//使用FLANN算法匹配描述符向量
	vector<DMatch> dMatch;
	Ptr<FlannBasedMatcher> flannMatcher = FlannBasedMatcher::create();
	flannMatcher->match(descriptor_src1, descriptor_src2, dMatch);
	double max_dist = 0, min_dist = 100;
	//快速计算关键点之间的最大和最小距离
	for (int i = 0; i < descriptor_src1.rows; i++)
	{
   
   
		double dist = dMatch[i].distance;
		if (dist < min_dist) min_dist = dist
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值