OpenCV:深入Feature2D组件——角点检测

角点检测

  • 1 Harris角点检测
    • 1.1 兴趣点与角点
    • 1.2 角点检测
    • 1.3 harris角点检测
    • 1.4 实现harris角点检测:cornerHarris()函数
    • 1.5 综合案例:harris角点检测与测绘
  • 2. Shi—Tomasi角点检测
    • 2.1Shi—Tomasi角点检测概述
    • 2.2 确定图像强角点:goodFeaturesToTrack()函数
    • 2.3 综合示例:Shi—Tomasi角点检测
  • 3. 亚像素级角点检测
    • 3.1 背景概述
    • 3.2 寻找亚像素角点:cornerSubPix()函数

1 Harris角点检测

1.1 兴趣点与角点

在图像处理和计算机视觉领域,兴趣点,也被成作关键点、特征点。它被大量用于解决物体识别、图像识别、图像匹配、视觉跟踪、三维重建等一系列的问题。我们不再观察整幅图,而是选择某些特殊的点,然后对他们进行局部有的放矢地分析。如果能检测到足够多的这种点,同时它们的区分度很高,并且可以精确定位稳定的特征,那么这个方法就具有实用价值。
图像特征类型可以被分为如下三种:

  • 边缘
  • 角点(感兴趣关键点)
  • 斑点(感兴趣区域)

其中,角点是个很特殊的存在。如果某一点在任意方向的一个微小变化都会引起灰度很大的变化,那么我们就把它称之为角点。角点作为图像上的特征点,包含有重要的信息,在图像融合和目标跟踪以及三维重建中有重要的应用价值。他们在图像中可以轻易地定位,同时,在人造物体场景,比如门、窗、桌等处也随处可见。因为角点位于两条边缘交点处,代表了两个边缘变化的方向上的点,所以他们是可以精确定位的而为特征,甚至可以达到亚像素的精度。又由于其图像梯度有很高的变化,这种变化是可以用来帮助检测角点的。需要注意的是,角点位于相同强度区域上的点不同,与物体轮廓上的点也不同,因为轮廓点难以在相同的其物体上精确定位。

另外,关于角点的具体描述可以有如下几种:

  • 一阶导数(即灰度的梯度)的局部最大所对应的像素点;
  • 两条及两条以上边缘的交点;
  • 图像中梯度值和梯度方向的变化速率都很高的
  • 角点处的一阶导数最大,二阶导数为零,它指示了物体边缘变化不连续的方向。

1.2 角点检测

现有的角点检测算法并不是都十分的健壮。很多方法都要求有大量的训练集和冗余数据来防止或减少错误特征的出现。另外,角点检测方法的一个很重要的评价标准是其对多幅图像中相同或相似特征的检测能力,并且能够应对光照变化、图像旋转等图像变化。

在当前的图像处理领域,角点检测算法可归纳为一下三类。

  • 基于灰度图像的角点检测
  • 基于二值图像的角点检测
  • 基于轮廓曲线的角点检测

1.3 harris角点检测

harris角点检测是一种直接基于灰度图像的角点提取算法,稳定性高,尤其对L型角点检测精度高但由于采用了高斯滤波,运算速度相对较慢,角点信息有丢失和位置偏移的现象,而且角点提取有聚簇的现象。

1.4 实现harris角点检测:cornerHarris()函数

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

  • 第一个参数:输入单通道8位或浮点图像。
  • 第二个参数:用于存储Harris检测器响应的图像。它的类型为CV_32FC1,大小与src相同。
  • 第三个参数:邻域大小
  • 第四个参数:表示Sobel()算子的孔径大小
  • 第五个参数:Harris检测器的自由参数,见上述公式

1.5 综合案例:harris角点检测与测绘

#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;

#define WINDOW_NAME1 "程序窗口1"
#define WINDOW_NAME2 "程序窗口2"

Mat g_srcImage, g_srcImage1, g_grayImage;
int thresh = 30; //当前阈值
int max_thresh = 175; //最大阈值


//回调函数
void on_ConerHarris(int, void*) {
	Mat dstImage;
	Mat normImage; //归一化之后
	Mat scaledImage; //线性变换后的八位无符号整型的图

	dstImage = Mat::zeros(g_srcImage.size(), CV_32FC1);
	g_srcImage1 = g_srcImage.clone();

	//进行角点检测
	cornerHarris(g_grayImage, dstImage, 2, 3, 0.04, BORDER_DEFAULT);
	//归一化
	normalize(dstImage, normImage, 0, 255, NORM_MINMAX, CV_32FC1, Mat());
	convertScaleAbs(normImage, scaledImage);//将归一化后的图线性变化为无符号整型	

	//进行绘制
	for (int j = 0; j < normImage.rows; j++) {
		for (int i = 0; i < normImage.cols; i++) {
			if ((int)normImage.at<float>(j, i) > thresh + 80) {
				circle(g_srcImage1, Point(i, j), 5, Scalar(10, 10, 255), 2, 0);
				circle(scaledImage, Point(i, j), 5, Scalar(0, 10, 255), 2, 0);
			}
		}
	}
	imshow(WINDOW_NAME1, g_srcImage1);
	imshow(WINDOW_NAME2, scaledImage);
}

int main() {
	g_srcImage = imread("1.jpg", 1);
	imshow("原始图", g_srcImage);
	g_srcImage1 = g_srcImage.clone();
	
	//存留一张灰度图
	cvtColor(g_srcImage1, g_grayImage, COLOR_BGR2GRAY);

	//创建窗口和滚动条
	namedWindow(WINDOW_NAME1, 0);
	createTrackbar("阈值", WINDOW_NAME1, &thresh, max_thresh, on_ConerHarris);

	//对回调函数进行初始化
	on_ConerHarris(0, 0);

	waitKey();
	return 0;
}

在这里插入图片描述

2. Shi—Tomasi角点检测

2.1Shi—Tomasi角点检测概述

除了利用Harris进行角点检测之外,我们通常还可以利用Shi-Tomasi方法进行角点检测。Shi-Tomasi算法是 Harris算法的改进,此算法最原始的定义是将矩阵M的行列式值与M的迹相减,再将差值同预先给定的阈值进行比较。后来Shi和 Tomasi提出改进了方法,若两个特征值中较小的一个大于最小阈值,则会得到强角点。

2.2 确定图像强角点:goodFeaturesToTrack()函数

goodFeaturesToTrack()函数结合了Shi-Tomasi算子,用于确定图像的墙角点。
在这里插入图片描述

  • 第一个参数:输入8位或浮点32位的单通道图像。
  • 第二个参数:检测到的角的输出向量。
  • 第三个参数:要返回的角的最大数量。maxCorners <= 0意味着没有设置最大数量的限制,所有检测到的角都被返回。
  • 第四个参数:表征图像角落的最小接受质量的参数。参数值乘以最佳角部质量度量,即最小特征值(见cornerMinEigenVal)或Harris函数响应(见cornerHarris)。质量度量小于乘积的角被拒绝。例如,如果最佳角的质量度量=1500,并且qualityLevel=0.01,那么所有质量度量小于15的角都被拒绝。
  • 第五个参数:角点之间的最小距离,此参数用于保证返回的角点之间的距离不小于minDistance个像素。
  • 第六个参数:可选的兴趣区域。如果图像不是空的(它需要有CV_8UC1的类型和与图像相同的大小),它指定了检测角的区域。
  • 第七个参数:计算导数自相关矩阵时指定的邻域范围。
  • 第八个参数:表示是否使用Harris检测器(见cornerHarris)或cornerMinEigenVal的参数。
  • 第九个参数:设置Hessian自相关矩阵行列式的权重系数。

2.3 综合示例:Shi—Tomasi角点检测

#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;

#define WINDOW_NAME "Shi-Tomasi角点检测"

Mat g_srcImage, g_grayImage;
int g_maxCornerNumber = 33;
int g_maxTarckbar = 500;
RNG g_rng(12345);

void on_GoodFeaturesToTrack(int, void*) {
	if (g_maxCornerNumber <= 1) g_maxCornerNumber = 1;
	
	//Shi-Tomasi算法参数准备
	vector<Point2f> corners;
	double qualityLevel = 0.01;
	double minDistance = 10;
	int blockSize = 3;
	double k = 0.04;
	Mat copy = g_srcImage.clone();

	goodFeaturesToTrack(g_grayImage,
		corners,
		g_maxCornerNumber,
		qualityLevel,
		minDistance,
		Mat(),
		blockSize,
		false,
		k
		);

	cout << "此次检测到的角点数量为:" << corners.size() << endl;

	//绘制检测到的角点
	for (int i = 0; i < corners.size(); i++) {
		circle(copy, corners[i], 4, Scalar(0, 0, 255), 1, 8, 0);
	}
	imshow(WINDOW_NAME, copy);
}

int main() {
	g_srcImage = imread("1.jpg", 1);
	cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);

	namedWindow(WINDOW_NAME);
	createTrackbar("最大角点数", WINDOW_NAME, &g_maxCornerNumber,g_maxTarckbar, on_GoodFeaturesToTrack);
	imshow("源图像", g_srcImage);
	on_GoodFeaturesToTrack(0, 0);
	waitKey();
}

在这里插入图片描述

3. 亚像素级角点检测

3.1 背景概述

若我们进行图像处理的目的不是提取用于识别的特征点而是进行几何测量,这通常需要更高的精度,而函数 goodFeaturesToTrack()只能提供简单的像素的坐标值,也就是说,有时候会需要实数坐标值而不是整数坐标值。
亚像素级角点检测的位置在摄像机标定、跟踪并重建摄像机的轨迹,或者重建被跟踪目标的三维结构时,是一个基本的测量值。
在这里插入图片描述
亚像素精确的角定位器是基于这样的观察:从中心q到位于q的邻域内的点p的每个矢量都是与p处的图像梯度正交的,并受到图像和测量噪声的影响。考虑一下这个表达式:
在这里插入图片描述
其中DIpi是q附近的一个点pi的图像梯度。要找到q的值,使ϵi达到最小。可以建立一个方程组,将ϵi设为零:
在这里插入图片描述
其中梯度是在q的邻域(“搜索窗口”)内求和。将第一个梯度项称为G,第二个梯度项称为b,就可以得到:
在这里插入图片描述
该算法将邻域窗口的中心设置在这个新的中心q,然后进行迭代,直到该中心保持在一个设定的阈值之内。

3.2 寻找亚像素角点:cornerSubPix()函数

在这里插入图片描述

  • 第一个参数:输入的图像
  • 第二个参数:InputOutputArray类型的corners,提供输入角点的初始坐标和精确地输出坐标
  • 第三个参数:搜索窗口边长的一半。例如,如果winSize=Size(5,5) ,则使用(5∗2+1)×(5∗2+1)=11×11的搜索窗口。
  • 第四个参数:Size类型的zeroZone,表示死区的一半尺寸。而死区为不对搜索区的中央位置做求和运算的区域,用来避免自相关矩阵出现的某些可能的奇异性。值为(-1,-1)表示没有死区。
  • 第五个参数:角部细化迭代过程的终止标准。也就是说,角位置的细化过程要么在 criteria.maxCount 迭代之后停止,要么在某个迭代中角位置的移动小于 criteria.epsilon时停止。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/34811.html

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

相关文章

实时包裹信息同步:WebSocket 在 Mendix 中的应用

场景介绍 在现代物流中&#xff0c;能够实时跟踪包裹信息&#xff0c;尤其是包裹重量&#xff0c;是非常重要的。在这种场景中&#xff0c;我们可以使用称重设备获取包裹的信息&#xff0c;然后实时将这些信息同步给 Mendix 开发的 App&#xff0c;并在 App 的页面上实时显示包…

用git下载gitee上的项目资源

目录 用git下载gitee上的项目资源 用git 的clone 命令 然后到gitee上复制相关的下载地址&#xff1a; 粘贴到clone后面即可&#xff08;注意地址与clone之间有空格&#xff01;&#xff01;&#xff01;&#xff09; 运行结果&#xff1a; 用git下载gitee上的项目资源 用git…

MySQL安装与部署

第一种方法&#xff1a;在线安装 配置一个安装yum源 Adding the MySQL Yum Repository 可以手动配置yum源&#xff0c;baseurl指向国内镜像源地址&#xff0c;比如清华、中科大。 Installing MySQL Starting the MySQL Server&#xff1a; 查询临时登录密码 修改数据库密码…

golang 结构体struct转map实践

1、反射 type sign struct { Name string json:"name,omitempty" Age int json:"age,omitempty" } var s sign s.Name "csdn" s.Age 18 //方式1 反射 var data make(map[string]interface{}) t : reflect.TypeOf(s) v : …

Spring Bean的实例化过程

一、前言 对于写Java的程序员来说&#xff0c;Spring已经成为了目前最流行的第三方开源框架之一&#xff0c;在我们充分享受Spring IOC容器带来的红利的同时&#xff0c;我们也应该考虑一下Spring这个大工厂是如何将一个个的Bean生产出来的&#xff0c;本期我们就一起来讨论一…

2023年第三届工业自动化、机器人与控制工程国际会议

会议简介 Brief Introduction 2023年第三届工业自动化、机器人与控制工程国际会议&#xff08;IARCE 2023&#xff09; 会议时间&#xff1a;2023年10月27 -30日 召开地点&#xff1a;中国成都 大会官网&#xff1a;www.iarce.org 2023年第三届工业自动化、机器人与控制工程国际…

Redis通信协议

RESP协议 Redis是一个CS架构的软件&#xff0c;通信一般分两步&#xff08;不包括pipeline和PubSub&#xff09;&#xff1a; ① 客户端&#xff08;client&#xff09;向服务端&#xff08;server&#xff09;发送一条命令 ② 服务端解析并执行命令&#xff0c;返回响应结果…

Spring MVC各种参数进行封装

目录 一、简单数据类型 1.1 控制器方法 1.2 测试结果 二、对象类型 2.1 单个对象 2.1.1 控制器方法 2.1.2 测试结果 2.2 关联对象 2.2.1 控制器方法 2.2.2 测试结果 三、集合类型 3.1 简单数据类型集合 3.1.1 控制方法 3.1.2 测试结果 3.2 对象数据类型集合 3.…

使用MQL4编写自己的交易策略:技巧与经验分享

随着技术的发展&#xff0c;越来越多的投资者开始使用程序化交易系统进行交易&#xff0c;其中MQL4语言是广泛应用于MetaTrader 4平台上编写交易策略的一种语言。本文将分享一些技巧和经验&#xff0c;帮助读者利用MQL4编写自己的交易策略。 策略开发流程 首先&#xff0c;我…

传输控制协议 TCP

文章目录 一、TCP报文格式1.报头格式2.TCP最大段长度 MSS 二、TCP连接建立与释放1.连接建立&#xff1a;三次握手2.报文传输3.连接释放&#xff1a;四次挥手4.保持定时器与时间等待定时器 三、TCP差错重传1.字节流状态分类与滑动窗口&#xff08;发送&#xff09;① 滑动窗口两…

Android Studio实现内容丰富的安卓博客发布平台

如需源码可以添加q-------3290510686&#xff0c;也有演示视频演示具体功能&#xff0c;源码不免费&#xff0c;尊重创作&#xff0c;尊重劳动。 项目编号078 1.开发环境 android stuido jdk1.8 eclipse mysql tomcat 2.功能介绍 安卓端&#xff1a; 1.注册登录 2.查看博客列表…

[AJAX]原生AJAX——自定义请求头

客户端 <script>// 1、创建对象const xhr new XMLHttpRequest();// 2、初始化&#xff1a;设置请求类型和urlxhr.open(POST, http://127.0.0.1:8000/server);// 设置请求头// Content-Type&#xff1a;设置请求体内容类型// application/x-www-form-urlencoded&#xf…

2022(二等奖)C2464植物保护管理系统

作品介绍 一、需求分析 1. 应用背景 森林是陆地生态系统的主体&#xff0c;是人类生存与发展的物质基础。以森林为主要经营对象的林业&#xff0c;不仅承担着生态建设的主要任务&#xff0c;而且承担着提供多种林产品的重大使命。进入21世纪&#xff0c;人类正在继农业文明和…

二进制、十进制相互转换

二进制转十进制&#xff1a; 1100 0000转为十进制的数值为&#xff1a;12864192 十进制转二进制&#xff1a; 列如&#xff1a;十进制数为202 1286432168421二进制11001010 解析&#xff1a; 202>128&#xff0c;第一个二进制数为&#xff1a;1 202-128>64&#xf…

Spring 事务管理方案和事务管理器及事务控制的API

目录 一、事务管理方案 1. 修改业务层代码 2. 测试 二、事务管理器 1. 简介 2. 在配置文件中引入约束 3. 进行事务配置 三、事务控制的API 1. PlatformTransactionManager接口 2. TransactionDefinition接口 3. TransactionStatus接口 往期专栏&文章相关导读 …

【Lua】ZeroBrane Studio免费专业IDE使用详解

▒ 目录 ▒ &#x1f6eb; 问题描述环境 1️⃣ IDE界面说明项目目录编辑器控制台窗口输出窗口选择解释器堆栈窗口监视窗口大纲窗口 2️⃣ 调试程序3️⃣ 自定义lua解释器编译自己的lua解释器增加interpreters配置文件重启IDE 4️⃣ 其它IDE比较Lua EditorVSCode &#x1f6ec; …

Redis:redis基于各大实战场景下的基本使用

文章目录 前言String 命令实战1.业务缓存对应redis中的指令伪代码 2.分布式锁对应redis中的指令伪代码 3.限流对应redis中的指令伪代码 List 命令实战1.提醒功能对应Redis中的指令伪代码 2.热点列表对应Redis中的指令伪代码 Hash 命令实战1.用户资料缓存对应redis中的指令伪代码…

算法设计与分析 课程期末复习简记

目录 网络流 线性规划 回溯算法 分支限界 贪心算法 动态规划 分治算法 算法复杂度分析 相关概念 网络流 下面是本章需要掌握的知识 • 流量⽹络的相关概念 • 最⼤流的概念 • 最⼩割集合的概念 • Dinic有效算法的步骤 • 会⼿推⼀个流量⽹络的最⼤流 下面对此依次进行复…

数据结构--串的定义和基本操作

数据结构–串的定义和基本操作 注:数据结构三要素――逻辑结构、数据的运算、存储结构&#xff08;物理结构) 存储结构不同&#xff0c;运算的实现方式不同 \color{pink}存储结构不同&#xff0c;运算的实现方式不同 存储结构不同&#xff0c;运算的实现方式不同 串的定义 串 …

suse ha for sap scale-up性能优化场景安装配置

1. 安装SUSE操作系统 在官网下载SUSE Linux Enterprise Server for SAP Applications安装介质&#xff0c;在安装操作系统过程中&#xff0c;选择SUSE Linux Enterprise Server for SAP Applications操作系统。 在软件选择界面&#xff0c;根据需要选择SAP HANA Server Base…