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

news2024/11/13 12:54:58

角点检测

  • 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时停止。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

硬件基本常识杂记1

文章目录 电感&#xff08;RL电路&#xff09;&#xff0c;电容&#xff08;RC电路&#xff09;&#xff0c;(LRC电路)谐振&#xff08;串联、并联&#xff09;滤波器&#xff08;高通RC、低通RC、高通RL、低通RL、带通、Π型&#xff09;积分电路、微分电路截至频率w信号传输、…

Docker迁移与备份

容器保存为镜像 语法: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]] 为nginx创建镜像: docker commit -a "leq" -m "nginx的镜像" 10053cd47ebf nginx:v1.0 -a 提交的镜像作者 -m 提交时的说明文字 镜像备份 语法: docker save…

深入理解C语言对文件的包装与缓冲区

内存级文件操作的运用 1.模拟实现文件分装2. 深入理解缓冲区的概念 1.模拟实现文件分装 【目标】 以最简单的方式&#xff0c;理解FILE结构体的原理。 头文件&#xff1a;mystdio.h&#xff08;定义了MY_FILE结构体&#xff0c;声明fopen&#xff0c;fwrite&#xff0c;fclos…

『手撕 Mybatis 源码』10 - 一级缓存

一级缓存 概述 一级缓存是 SqlSession 级别的缓存。在操作数据库时需要构造 SqlSession 对象&#xff0c;在对象中有一个数据结构&#xff08;HashMap&#xff09;用于存储缓存数据。不同的 SqlSession 之间的缓存数据区域&#xff08;HashMap&#xff09;是互相不影响的二级缓…

hive基于新浪微博的日志数据分析——项目及源码

有需要本项目的全套资源资源以及部署服务可以私信博主&#xff01;&#xff01;&#xff01; 本系统旨在对新浪微博日志进行大数据分析&#xff0c;探究用户行为、内容传播、移动设备等多个方面的特征和趋势&#xff0c;为企业和个人的营销策略、产品设计、用户服务等提供有益的…

PN结、二极管、三极管、三极管放大电路、上拉电路/下拉电路

1、N型参杂 与 P型参杂 B站 视频地址 &#xff1a;https://www.bilibili.com/video/BV1fB4y147Gn 1&#xff09;N型参杂 &#xff08;N型半导体&#xff09; &#xff1a; 4价硅 参杂 5价麟&#xff0c;多一个自由负电子&#xff08;带负电&#xff09; 2&#xff09;P型参杂…

Linux性能学习(4.2):网络_为什么MTU是1500

文章目录 1 基本概念2 为什么MTU是15003 有效载荷最大是1500吗4 Linux下如何修改MTU 参考资料&#xff1a; 1. RFC894 2. 什么是MTU&#xff08;Maximum Transmission Unit&#xff09;&#xff1f; 1 基本概念 Maximum Transmission Unit&#xff0c;缩写MTU&#xff0c;即…

Python爬虫:Scrapy框架

&#x1f680;Python爬虫&#xff1a;Scrapy框架 &#x1f577;️ Scrapy介绍&#x1f4e6; Scrapy框架&#x1f4c1; Scrapy项目&#x1f50d; 创建爬虫过程&#x1f578;️ 页面分析&#x1f4d1; 提取信息&#x1f389; 完整代码&#x1f4dd; 结语 在本篇博文中&#xff0c…

C++6.29思维,作业

有以下类定义&#xff0c;按要求实现剩余功能 #include <iostream> using namespace std;class Person { private:int age;int *p; public://无参构造Person():p(new int(89)){age 18;cout << "无参构造" << endl;}//有参构造Person(int age,int …

docker的容器

首先要关闭防火墙,不然会阻止连接 查询防火墙状态 systemctl status firewalld 如果是running的状态要关闭一下 关闭防火墙 systemctl stop firewalld 禁用防火墙(禁止开机启动) systemctl disable firewalld 容器的创建语句: docker run …

第11节 跟上板块轮动的节奏

板块 文章目录 板块什么是板块板块的分类板块的轮动 板块相关接口本节课任务 什么是板块 股票板块是一些具有相同特征的股票的集合&#xff0c;命名通常也会简单明了的直接按照特征命名。例如沪深300板块&#xff0c;蓝筹板块。对上市公司进行“分班”不论是对于企业还是对于投…

Leetcode-每日一题【148.排序链表】

题目 给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3]输出&#xff1a;[1,2,3,4] 示例 2&#xff1a; 输入&#xff1a;head [-1,5,3,4,0]输出&#xff1a;[-1,0,3,4,5] 示例 3&#xff1…

VC++多文档项目同时显示多个文本文件

VC6新建一个多文档工程&#xff1b;工程名为txt&#xff1b;生成的类如下&#xff1b;与单文档项目相比多了一个ChildFrm&#xff1b; 在类向导为Doc类添加OnOpenDocument函数&#xff1b; 此时生成的OnOpenDocument()函数如下&#xff1b; BOOL CTxtDoc::OnOpenDocument(LPCT…

Python基础 —— 条件语句

考虑了好久&#xff0c;不知道是先写条件循环&#xff0c;还是先写数据类型,因为如果先写条件循环的话&#xff0c;要涉及到数据类型的内容&#xff1b;先写数据类型的话&#xff0c;又要设计到条件循环的内容…纠结一番后&#xff0c;决定还是先说条件循环&#xff0c;再在数据…

chatgpt赋能python:用Python抓取数据:提高SEO的关键

用Python抓取数据&#xff1a;提高SEO的关键 在数字化时代&#xff0c;数据已经变成了最宝贵的财富之一。然而&#xff0c;对于企业和网站管理者来说&#xff0c;数据仅仅是有价值的当它被收集和转化成行动中存在的信息。这时&#xff0c;Python成为了一个有用的工具&#xff…

基于VORS、CCDM模型、GeoDetector、GWR模型集成技术在城镇化与生态系统健康空间关系分析及影响效应中的应用

城市群是一国经济发展水平的象征&#xff0c;也是一国经济发展到一定阶段的标志&#xff0c;我国城市群建设体量不断增加&#xff0c;将成为全球经济的核心&#xff0c;中国城市群的建设逐步引领全球进入到了21世纪的中国新时代。然而&#xff0c;高速的城镇化发展&#xff0c;…

leetcode题集训 sql

目录 背景步骤175组合两个表&#xff08;多表联查&#xff09;176 177 第n高的薪水&#xff08;Distinct关键字 排序&#xff09;178分数排名 &#xff08;排序 order over关键字&#xff09;179 连续出现的数字 &#xff08;模拟多张表联查&#xff09;181. 超过经理收入的员工…

学号编码:TooY0ung的学院(结构体)

根据66十二位编码规则&#xff0c;用城市代码和出生年编制学号。 【本笔记适合初通算法的 coder 翻阅】 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”教程《 python 完全自学教程》&#xff0c;不仅仅是基础…

Web-文件上传漏洞总结

目录 1、常规前端绕过 2、修改文件类型 3、使用 .user.ini 或 .htaccess&#xff08;可能还存在大小写绕过&#xff09; 4、使用字典爆破可行后缀 5、结合文件包含漏洞使用图片马 6、条件竞争 1、常规前端绕过 如下图&#xff0c;在前端存在限制&#xff0c;只能上传图片…

springboot校园点餐小程序

校园点餐系统 springboot校园点餐系统小程序 java校园点餐小程序 技术&#xff1a; 基于springbootvue小程序校园点餐系统的设计与实现 运行环境&#xff1a; JAVA版本&#xff1a;JDK1.8 IDE类型&#xff1a;IDEA、Eclipse都可运行 数据库类型&#xff1a;MySql&#xff08;…