【计算机视觉系列实战教程 (实战02)】:基于特征点匹配的图像配准

news/2024/7/8 9:55:45 标签: 计算机视觉

这里写目录标题

  • 1、特征点提取
    • (1)GFTT算法提取特征点
      • A.What(什么是GFTT)
      • B.GFTT的优势
      • C.How(如何使用GFTT算法提取图像特征点)
    • (2)FAST算法提取特征点
      • A.What(什么是FAST角点)
      • B.FAST角点的强度值
      • C.How(如何使用FAST算法提取图像特征点)
    • (3)BRISK算法提取特征点
      • A.What
      • B.How(如何使用BRISK算法提取特征点)
    • (4)ORB算法提取特征点
      • A.What
      • B.How(如何使用ORB算法提取特征点)
  • 2、描述子
    • (1)What
    • (2)How(如何衡量两个特征点相似性)
      • A.周围像素的特征
      • B.周围像素的描述子
      • C.基于深度学习的方法
    • (3)SIFT描述子实现关键点匹配
      • A.原理
      • B.How(如何得到SIFT特征点和描述子)
    • (4)ORB描述子实现关键点匹配
      • A.原理
      • B.BRIEF算法计算描述子
      • C.How(如何得到ORB特征点描述子)
  • 3、图像匹配
  • 4、图像配准

1、特征点提取

(1)GFTT算法提取特征点

A.What(什么是GFTT)

GFTT算法是对Harris的改进:一是针对特征点聚集问题,使用局部区域最大值解决;二是针对不均匀分布问题,使用限制两个特征点之间最短具体解决

B.GFTT的优势

  • 稳定性好:GTFF 算法检测到的角点相对更加稳定,不容易出现聚簇现象,且角点信息的丢失和位置偏移也相对较少
  • 参数可调节:通过设置相关参数,如最大角点数目、角点可接受的最小特征值、角点之间的最小距离等,可以根据具体需求和图像特点来优化特征点的提取效果

C.How(如何使用GFTT算法提取图像特征点)

int GetKpsByGTFF(const cv::Mat& imSrcGray, std::vector<cv::KeyPoint>& vkps)
{
	//对参数进行检测
	if(imSrcGray.empty() )
	{	
		return -1; 
	}
	if(imSrcGray.channels()!=1)
	{	
		return -2; 
	}
	if(!vkps.empty())
	{	
		vkps.clear(); 
	}
	//提取图像特征点
	cv::Ptr<cv::GFTTDetector> ptrGFTT = 
				cv::GFTTDetector::create(500, //关键点的最大数量
										 0.01, //角点的最小特征值
										 15); //角点之间允许的最短距离
	ptrGFTT->detect(imSrcGray, vkps); //调用算法探测图像上的特征点
	if(vkps.size()==0)
	{	return -3; }
	else
	{	return 1;	}
											
}

(2)FAST算法提取特征点

A.What(什么是FAST角点)

以某个点为中心做一个圆,根据圆上的像素值判断该 点是否为关键点。由于不需要作复杂的梯度计算,该方法提取关键点的效率很高,在实时性要求高的条件下使用很广

B.FAST角点的强度值

计算中心点像素与 认定的连续圆弧上的像素的差值,然后将这些差值的绝对值累加,就能得到角点强度

C.How(如何使用FAST算法提取图像特征点)

int GetKpsByFAST(const cv::Mat& imSrcGray, std::vector<cv::KeyPoint>& vkps)
{
	//对参数进行检测
	if(imSrcGray.empty() )
	{	
		return -1; 
	}
	if(imSrcGray.channels()!=1)
	{	
		return -2; 
	}
	if(!vkps.empty())
	{	
		vkps.clear(); 
	}
	//使用FAST算法提取特征点
	cv::Ptr<cv::FastFeatureDetector> ptrFAST = 
		cv::FastFeatureDetector::create(65);//65表关键点强度,即FAST角点的强度值(response)
	ptrFAST->detect(imgSrcGray, vkps);
	if(vkps.size()==0)
	{
		return -3;
	}
	else
	{
		return 1;
	}
}

(3)BRISK算法提取特征点

A.What

基于FAST的多尺度快速检测器。首先下采样构建图像金字塔,然后对金字塔所有图像应用FAST特征检测。只有是局部最大值的像素才可能成 为关键点。这个条件满足后,比较这个点与上下两层的相邻像素的评分;如果它的评分在尺度上 也更高,那么就认为它是一个兴趣点。

B.How(如何使用BRISK算法提取特征点)

int GetKpsByBRISK(const cv::Mat& imSrcGray, std::vector<cv::KeyPoint>& vkps)
{
	//对参数进行检测
	if(imSrcGray.empty() )
	{	
		return -1; 
	}
	if(imSrcGray.channels()!=1)
	{	
		return -2; 
	}
	if(!vkps.empty())
	{	
		vkps.clear(); 
	}
	//使用BRISK算法提取图像特征点
	cv::Ptr<cv::BRISK> ptrBRISK = 
		cv::BRISK::create(60, 5); //60表示FAST角点的强度值必须达到60,才有可能被认为是关键点;5表示金字塔层数
	ptrBRISK->detect(imSrcGray, vkps);
	if (vkps.size() == 0)
	{
		return -3;
	}
	else
	{
		return 1;
	}
}

(4)ORB算法提取特征点

A.What

基于FAST的多尺度带方向的特征检测算法。

  • 特征点方向:每个被检测的兴趣点总是关联了一个方向。在FAST的中心点的圆形区域内计算重心,中心与重心的组成的向量即为该关键电的方向。

B.How(如何使用ORB算法提取特征点)

int GetKpsByORB(const cv::Mat& imSrcGray, std::vector<cv::KeyPoint>& vkps)
{
	//对参数进行检测
	if(imSrcGray.empty() )
	{	
		return -1; 
	}
	if(imSrcGray.channels()!=1)
	{	
		return -2; 
	}
	if(!vkps.empty())
	{	
		vkps.clear(); 
	}
	//使用ORB算法对图像进行特征点提取
	cv::Ptr<cv::ORB> ptrORB = 
		cv::ORB::create(500, 1.2, 8);//500:特征点数量;1.2:金字塔的缩放尺度;8:金字塔层数
	ptrORB->detect(imSrcGray, vkps);
	if (vkps.size() == 0)
	{
		return -3;
	}
	else
	{
		return 1;
	}
}

2、描述子

(1)What

A图像的某一点和B图像的某一点如果对应现实世界的同一点,那么它们就应该是匹配的。这也是特征点匹配的目的

从数学的角度分析:要进行特征点的匹配,就应该考虑两个关键点的相似性,因此,如何衡量两个关键点的相似性成为了我们要考虑的首要问题

(2)How(如何衡量两个特征点相似性)

A.周围像素的特征

计算该特征点指定区域的均值、方差、梯度等,用作衡量标准。但单个的值很容易受到环境的印象,具有不稳定性,在工程实践中不会采用这些特征

B.周围像素的描述子

使用一些专门为特征点设计的描述子(可以理解为一个向量),这些描述子能够捕捉到角点的独特特性,通过比较描述子的差异来衡量相似性。在工程实践中一般采用特征点的描述子来进行特征点的匹配

C.基于深度学习的方法

利用训练好的卷积神经网络模型提取角点的深层特征,然后比较这些特征的相似度

(3)SIFT描述子实现关键点匹配

A.原理

step01:首先选取关键点周围16×16像素点,将其分为4×4大小的子区域,总共16个子区域。
step02:然后对每个子区域统计八个方向的梯度方向直方图,每个子区域用这8个统计结果进行描述。
step03:最后得到8×16 = 128 个数据作为描述符向量。

B.How(如何得到SIFT特征点和描述子)

#include <opencv2/features2d/features2d.hpp>
int GetKpsAndDescriptorBySIFT(const cv::Mat& imSrc,
	std::vector<cv::KeyPoint>& vkps,
	cv::Mat& matDescriptor)
{
	//对输入的参数进行检查
	if (imSrc.empty())
	{
		return -1;
	}
	if (imSrc.channels() != 1)
	{
		return - 2;
	}
	if (!vkps.empty())
	{
		vkps.clear();
	}
	//提取关键点
	cv::Ptr<cv::SIFT> ptrSIFT = cv::SIFT::create(500, 3);
	ptrSIFT->detect(imSrc, vkps);
	if (vkps.size() == 0)
	{
		return -3;
	}
		//计算关键点的描述子
	ptrSIFT->compute(imSrc, vkps, matDescriptor);
	if (matDescriptor.empty())
	{
		return -4;
	}
	return 1;
}

(4)ORB描述子实现关键点匹配

A.原理

采用BRIEF算法提取关键点的描述子

B.BRIEF算法计算描述子

  • 为减少噪声干扰,先对图像进行高斯滤波(方差为2,高斯窗口为9x9)
  • 以特征点为中心,取s×s的邻域窗口,在窗口内随机选取一对点,比较二者像素的大小,进行二进制赋值:若p(x) > p(y),则赋值为1;若p(x) ≤ p(y),则赋值为0,其中p(x)、p(y)分别是随机点x=(u1,v1)、y=(u2,v2)的像素值。
  • 在窗口中随机选取n对随机点(一般n=256),重复步骤2的二进制赋值,形成一个二进制编码,即特征描述子。

C.How(如何得到ORB特征点描述子)

int GetKpsAndDescriptorByORB(const cv::Mat& imSrc,
	std::vector<cv::KeyPoint>& vkps,
	cv::Mat& matDescriptor)
{
	//对输入的参数进行检查
	if (imSrc.empty())
	{
		return -1;
	}
	if (imSrc.channels() != 1)
	{
		return - 2;
	}
	if (!vkps.empty())
	{
		vkps.clear();
	}
		//提取ORB关键点
	cv::Ptr<cv::Feature2D> ptrORB = cv::ORB::create(500, 1.2, 8);
	ptrORB->detect(imSrc, vkps);
	if (vkps.size() == 0)
	{
		return -3;
	}
	//计算关键点的描述子
	ptrORB->compute(imSrc, vkps, matDescriptor);
	if (matDescriptor.empty())
	{
		return -4;
	}
	return 1;
}

3、图像匹配

4、图像配准


http://www.niftyadmin.cn/n/5536896.html

相关文章

elementPlus表格二次封装

为何要对element-plus表格进行二次封装&#xff1f; 我们正常在开发项目中&#xff0c;表格的风格是一致的&#xff0c;但是表格或多或少会有些不同&#xff0c;有些是需要分页&#xff0c;有些是按钮功能不同&#xff0c;有些又需要加Tag&#xff0c;或者对时间进行格式化等。…

学会python——用python制作一个登录和注册窗口(python实例十八)

目录 1.认识Python 2.环境与工具 2.1 python环境 2.2 Visual Studio Code编译 3.登录和注册窗口 3.1 代码构思 3.2 代码实例 3.3 运行结果 4.总结 1.认识Python Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的可读…

Rust简明教程第四章-其他类型泛型

观看B站软件工艺师杨旭的rust教程学习记录&#xff0c;有删减有补充 枚举 枚举类型可以让我们的程序使用一些固定长度和固定数值的变量值范围 enum 枚举 枚举类型中的值被称为变体 enum IpAddrKind{V4,//变体V6,//变体 } fn main(){let four IpAddrKind::V4;let six IpA…

django admin添加自己的页面

建立模型 如果要单独建一个页面&#xff0c;用于展示model的数据&#xff0c;可以新建一个model&#xff0c;继承自要展示的那个类 class ViewsByDayModel(ViewsByDay): # 父类为要展示的model类class Meta:proxy True # 使用代理verbose_name 每日浏览次数统计verbose_nam…

ChatGPT在Java后端开发中的应用与影响

随着人工智能技术的发展&#xff0c;尤其是OpenAI推出的聊天机器人模型ChatGPT&#xff0c;其强大的自然语言理解和生成能力正在改变着我们的生活和工作方式。在Java后端开发领域&#xff0c;ChatGPT同样有着广泛的应用前景&#xff0c;并且能够为Java后端开发者带来诸多好处。…

Android高级——智能指针

智能指针 智能指针是一种能够自动维护对象引用计数的技术 引用了一个实际使用的对象&#xff0c;而不是一个指针智能指针构造时&#xff0c;增加它所引用的对象的引用计数智能指针析构时&#xff0c;减少它所引用的对象的引用计数 但智能指针无法解决循环引用问题&#xff0…

【项目管理】项目风险管理(Word原件)

风险和机会管理就是在一个项目开发过程中对风险进行识别、跟踪、控制的手段。风险和机会管理提供了对可能出现的风险进行持续评估&#xff0c;确定重要的风险机会以及实施处理的策略的一种规范化的环境。包括识别、分析、制定处理和减缓行动、跟踪 。合理的风险和机会管理应尽力…

三菱PLC 6行程序实现8电机顺序启动逆序停止

目录 概要指令概述顺序启动梯形图逆序停止梯形图 概要 这里主要用到的是三菱的位左移&#xff08;SFTL&#xff09;和右移&#xff08;SFTR&#xff09;指令来实现顺序启动和逆序停止&#xff0c;时间可自由设置&#xff0c;除了应用在电机上&#xff0c;也可以用来做跑马灯。…