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

这里写目录标题

  • 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.mfbz.cn/a/772927.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring框架的学习前言

1.注意事项 1.在接下来的学习中我们会将jdk的版本升级到17。 2.引入maven仓库用来存储依赖 3.在后面的javaSpring框架中要第一个项目的创建要选javaweb和lombook这两个依赖 2.Maven的主要功能 &#xff08;1&#xff09;maven的主要功能是引入依赖和管理依赖&#xff0c;在…

基于SpringCloud的分布式架构网上商城

基于SpringCloud的分布式架构网上商城的主要使用者管理员功能&#xff1a;首页、个人中心、用户管理、商品信息管理、商品分类管理、系统管理、订单管理等功能。 &#x1f495;&#x1f495;作者&#xff1a;Weirdo &#x1f495;&#x1f495;个人简介&#xff1a;擅长Java、C…

【SkiaSharp绘图15】SKPath属性详解:边界、填充、凹凸、类型判断、坐标、路径类型

文章目录 SKPath 构造函数SKPath 属性Bounds 边界(宽边界)TightBounds紧边界FillType填充方式IsConcave 是否凹/ IsConvex 是否凸IsEmpty是否为空IsLine是否为线段IsRect是否为矩形IsOval是否为椭圆或圆IsRoundRect是否为圆角矩形Item[] 获取路径的坐标LastPoint最后点的坐标Po…

基于香橙派AIpro搭建的车牌识别系统

引言 本人正有学习嵌入式的想法&#xff0c;正好碰到机会让我搞了块OrangePi AIpro&#xff08;香橙派AIpro&#xff09;开发板&#xff0c;正合我意&#xff0c;直接上手进行体验&#xff0c;顺便给大家分享下我的实践过程。 开发板介绍与初次启动 OrangePiAIPro开发板是香…

WPF UI InkCanvas 导师演示画板 演示 笔记 画笔 识别

<Grid><InkCanvas Name"inkCanvas"/><Button Content"识别" Click"Button_Click" VerticalAlignment"Bottom"/></Grid> 引用内库 Ink ink new Ink(); private void Button_Click(object sender, RoutedEvent…

基于STM32F103C8T6的同步电机驱动-CubeMX配置与IQmath调用

基于STM32F103C8T6的同步电机驱动-CubeMX配置与IQmath调用 一、功能描述: 上位机通过CAN总线实现对电机的运动控制,主要包含三种模式:位置模式、速度模式以及力矩模式。驱动器硬件核心为STM32F103C8T6,带相电压采集电路以及母线电压采集电路。其中供电电压12V。 PWM中心对…

Android-卷积神经网络(Convolutional Neural Network, CNN)

一个复杂且在Android开发中常见的算法是图像处理中的卷积神经网络(Convolutional Neural Network, CNN)。CNN被广泛用于图像识别、物体检测和图像分割等任务,其复杂性在于需要处理大量的图像数据、复杂的神经网络结构和高效的计算。 1. 卷积操作(Convolution) 数学原理:…

企业级监控系统Zabbix

文章目录 Zabbix介绍Zabbix架构Zabbix serverZabbix agentZabbix proxy Zabbix Server的安装Zabbix Agent的安装监控主机流程zabbix_get自定义模板和监控项实战用户登录数监控1.指定监控项命令2.重启Agent服务3.在Server上创建监控项4.测试监控项5.查看监控项图形 触发器定义触…

字符设备驱动程序

简单做个模板框架 字符设备开发流程 确定设备号dev_t&#xff0c;动态分配 alloc_chrdev_region() 或静态分配 register_chrdev_region()定义file_opeartion 结构体*fops *&#xff0c;在结构体成员中实现对应的 *open()、read()*等函数。cdev_init() 将 fops 与 cdev 绑定&…

STM32学习历程(day2)

GPIO解释 GPIO(General-purpose input/output) 可以配置为八种输入输出模式 引脚电平 0V-3.3V 部分引脚可容忍5v 输出模式可控制端口输出高低电平 用以驱动LED、控制蜂鸣器、模拟通信协议输出时序 输入模式可读取端口的高低电平或电压&#xff0c;用于读取按键输入、外界…

firefly rk3588 sdk安装问题记录

目录 一、python版本不对 1.1 下载python2.6 1.2 安装python2.6 1.3 安装遇到问题 二、安装hashlib 三、更新3588 SDK代码 一、python版本不对 我的环境的python版本是python3.7。初次安装的时候执行命令报错&#xff0c;说是版本不对导致 fuhdell:rk3588_sdk$ .repo/rep…

centos通过官网下载安装最新版mysql方案

官网下载步骤&#xff1a; 点击DOCUMENTATION mysql的yum仓库Using the MySQL Yum Repository 向下翻&#xff0c;查看安装命令 点击下载mysql安装包 下载对应的版本 不注册&#xff0c;直接下载社区版 下载好的安装包 安装步骤&#xff1a; 把rpm包导入到服务器…

AI 驱动的数据中心变革与前景

文章主要探讨了AI计算时代数据中心的转型&#xff0c;涉及计算技术的多样性、规格尺寸和加速器的发展、大型语言模型&#xff08;LLM&#xff09;的发展、功耗和冷却趋势、基准测试的重要性以及数据中心的发展等方面。为大家提供深入了解AI基础设施发展的视角。 计算技术的多样…

​浅谈 Linux 中的 core dump 分析方法

在 Linux 系统开发领域中&#xff0c;core dump&#xff08;核心转储&#xff09;是一个不可或缺的工具&#xff0c;它为我们提供了在程序崩溃时分析程序状态的重要线索。当程序因为某种原因&#xff08;如段错误、非法指令等&#xff09;异常终止时&#xff0c;Linux 系统会尝…

spring boot + vue3+element plus 项目搭建

一、vue 项目搭建 1、创建 vue 项目 vue create vue-element说明:创建过程中可以选择路由,也可也可以不选择,可以通过 npm install 安装 vue 项目目录结构 说明:api 为自己创建的文件夹,router 选择路由模块会自动创建 router下的index.js文件(配置路由的文件) im…

泰国内部安全行动司令部数据泄露

BreachForums 论坛的一名成员宣布发生一起重大数据泄露事件&#xff0c;涉及泰国内部安全行动司令部 (ISOC)&#xff0c;该机构被称为泰国皇家武装部队的政治部门。 目前&#xff0c;我们无法准确确认此次泄露的真实性&#xff0c;因为该组织尚未在其网站上发布有关该事件的任…

微信开发者工具报错 Error: module ‘xxx.js‘ is not defined, require args is ‘xxx.js‘

背景 报错如下 检查 代码逻辑和写法都是ok的重新打开项目又是可以的 解决方案 先确保微信开发者工具和uniapp的将js编译成es5都开着&#xff08;这个是默认开的&#xff09; 然后把微信开发者工具关了重开 一般做这一步就会好了&#xff0c;但是只是临时解决 &#xff08…

如何使用 3D 建模库在 C# 中将 3DS 转换为 USDZ?

USDZ/USD是一种 3D 文件格式&#xff0c;被广泛用于跨平台共享 3D 资产。另一方面&#xff0c;3DS是另一种以块形式存储数据的 3D 文件格式。在某些情况下&#xff0c;您需要将3DS 文件转换为 USDZ/USD文件格式。因此&#xff0c;本篇博文介绍了一个功能丰富的3D 建模库&#x…

记录一下简单导入导出excel二级表头

数据库导入导出表头 之前的工具类GenerateExcelToFile新增两个导出这种二级表头方法 package com.njry.utils;import cn.hutool.core.util.IdUtil; import com.njry.config.FileProperties; import com.njry.exception.BadRequestException; import org.apache.poi.hssf.user…

《Winodws API每日一练》8.2 static控件

在 Windows 编程中&#xff0c;"Static" 控件是一种常见的用户界面元素&#xff0c;用于显示静态文本或图像&#xff0c;而无法进行用户交互。它通常用于显示标签、标题、说明文本或静态图像等信息。Static 控件是一种静态的、只读的显示元素&#xff0c;不接受用户的…