OpenCV HoughLine()函数与HoughlinesP()函数及HoughCircles()函数详解及用法示例

news2024/10/11 22:55:02

        OpenCV HoughLine()函数与HoughlinesP()函数都用于图像中的直线检测,但二者是有区别的。

        HoughLine()函数

        HoughLines()基于霍夫变换的原理,通过投票机制来确定图像中直线的存在及其参数。该函数返回检测到的直线的极坐标参数。它是一个 cv::Vec2f 类型元素组成的向量,每个元素是一对浮点数,表示检测到的直线的参数,即(ρ, θ)ρ是原点到直线的距离,θ是原点到直线垂线与x轴的夹角。由于无法直接确定检测到直线的起始及终位置,只能通过直线上的两个点来画直线。将画出来的直线显示出来,就可看到直线检测结果。OpenCV HoughLine()函数的原型如下:

        OpenCV HoughLine()函数参数:

        image:待检测直线的原图像。该图像必须是CV_8U的单通道二值图像,即边缘检测后的图像。

        lines:存储检测到的直线的参数对的容器。每一条直线都由两个参数表示,分别是直线距离坐标原点的距离rho和坐标原点到直线的垂线与x轴的夹角theta

        rho:以像素为单位的距离分辨率,即距离r离散化时的单位长度。这个参数决定了霍夫空间中r坐标轴的分辨率。

        theta:以弧度为单位的角度分辨率,即夹角theta离散化时的单位角度。这个参数决定了霍夫空间中theta坐标轴的分辨率。

        threshold:累加器的阈值。参数空间中离散化后的每个方格被通过的累计次数大于该阈值时,将被识别为直线,否则不被识别为直线。这个参数决定了检测直线的灵敏度。

        srn = 0(可选):对于多尺度霍夫变换算法,该参数表示距离分辨率的除数。粗略的累加器距离分辨率是第三个参数rho,精确的累加器分辨率是rho/srn。这个参数必须是非负数,默认参数是0

        stn = 0(可选):对于多尺度霍夫变换算法,该参数表示角度分辨率的除数。粗略的累加器角度分辨率是第四个参数theta,精确的累加器分辨率是theta/stn。这个参数必须是非负数,默认参数为0。当这个参数与第六个参数srn同时为0时,此函数表示的是标准霍夫变换。

        min_theta = 0(可选):检测直线的最小角度,默认参数为0

        max_theta = CV_PI(可选):检测直线的最大角度,默认参数为CV_PI,即圆周率。这个参数限定了检测直线的角度范围。

        示例:

        在完成具体代码之前,先讨论一下如何画出检测到的直线。如上图,这里用P1P2两点来画直线,P1P2是直线上以垂足P为对称中心的两个点,为保证画的直线会落在被检测图像内,这里d取图像长、宽中的最大值。P点的坐标为:(ρ*cosθ ρ*sinθ),P1的坐标为:(ρ*cosθ-d*sinθρ*sinθ+d*cosθ),P2的坐标为(ρ*cosθ+d*sinθρ*sinθ-d*cosθ)。有了两个点P1P2的坐标就可以画出直线了。

        新建一个控制台应用程序,在源程序中加入如下代码:

#include <iostream>
#include <opencv2/opencv.hpp>
#include <math.h>

using namespace cv;
using namespace std;

void DrawLine(Mat& dst, vector<Vec2f> lines, Scalar scalar, int n);

int main()
{
    Mat src = imread(".\\pic\\1.png");
	if (src.empty())
	{
		cout << "Cann't Open Image!" << endl;
		return -1;
	}
	imshow("Src", src);

	Mat dst;
	cvtColor(src, dst, COLOR_BGR2GRAY);
	GaussianBlur(dst, dst, Size(9, 9), 0);
	//imshow("Dst", dst);

	Mat m_Edges;
	Canny(dst, m_Edges, 75, 150);
	imshow("Edges", m_Edges);

	vector<Vec2f> lines;
	HoughLines(m_Edges, lines, 1, CV_PI / 180, 100);
	DrawLine(src, lines, Scalar(0, 0, 255), 1);
	imshow("Result", src);


	waitKey(0);
}

void DrawLine(Mat& dst, vector<Vec2f> lines, Scalar scalar, int n)
{
	Point2f p, p1, p2;
	float rho, theta;
	int d = MAX(dst.rows, dst.cols);
	int sizeofLines = lines.size();
	for (size_t i = 0; i < sizeofLines; i++)
	{
		rho = lines[i][0];
		theta = lines[i][1];
		p.x = rho * cos(theta);
		p.y = rho * sin(theta);
		p1.x = p.x - d * sin(theta);
		p2.x = p.x + d * sin(theta);
		p1.y = p.y + d * cos(theta);
		p2.y = p.y - d * cos(theta);
		line(dst, p1, p2, scalar, n);
	}

}

试运行, 结果如下:

        HoughLinesP()函数

        HoughLinesP()函数基于霍夫变换(Hough Transform)的原理,通过检测图像中的边缘来识别线段。它主要用于在二值图像中检测直线段,并返回这些线段的端点坐标。HoughLinesP()函数的原型如下:

        HoughLinesP()函数参数:

        image:输入的8位单通道二值图像,通常是由边缘检测算法(如Canny算法)得到的图像。

       lines:输出的直线向量Vector<Vec4i>,每条线用4个元素表示,即直线的两个端点的4个坐标值(x1, y1, x2, y2)。

        rho:霍夫空间中坐标的分辨率,以像素为单位。它决定了霍夫空间中r坐标轴的分辨率。通常设置为1

        theta:角度的分辨率,以弧度为单位。它决定了霍夫空间中θ坐标轴的分辨率。通常设置为π/180,即1度。

        threshold:判定直线点数量的阈值。累加器中的票数大于该阈值的线段才会被检测出来。阈值越高,检测到的线段越少。

        minLineLength(可选):线段的最小长度。小于此值的线段将被拒绝。默认值为0,表示不进行此检查。

        maxLineGap(可选):最大允许的线段间距,以使它们被视为单一线段。如果两条线段在同一直线上且它们之间的间隙小于此值,则它们将被视为一条线段。默认值为0,表示不进行此检查。

        HoughLinesP()函数工作原理

        1 边缘检测:首先对图像进行边缘检测,以获取所有可能形成直线的像素点。边缘检测可以通过各种算法(如Canny算法)来实现。边缘检测并不是在HoughLinesP()函数的内部完成,而是将边缘检测的输出结果作为HoughLinesP()函数的输入源。

       2  霍夫变换:然后对这些边缘像素点进行霍夫变换。霍夫变换的基本思想是将每个边缘像素点的梯度和角度映射到霍夫空间中。在霍夫空间中,每个可能的直线参数(斜率和截距,但在这里用极坐标ρθ表示)对应一个投票桶。如果一个边缘像素点对应的梯度和角度落在两个投票桶的边界上,则该像素点会给两个投票桶各投一票。

        3 检测线段:最后,通过查找投票数最多的投票桶来确定检测到的线段。根据设置的阈值、最小线段长度和最大线段间距等参数,筛选出符合条件的线段。

        HoughLinesP()函数示例:

        屏蔽掉HoughLines的部分代码,加入新代码如下:

//HoughLinesP
	
	Mat src = imread(".\\pic\\1.png");
	if (src.empty())
	{
		cout << "Cann't Open Image!" << endl;
		return -1;
	}
	imshow("Src", src);

	Mat dst;
	cvtColor(src, dst, COLOR_BGR2GRAY);
	GaussianBlur(dst, dst, Size(9, 9), 0);
	//imshow("Dst", dst);

	Mat m_Edges;
	Canny(dst, m_Edges, 75, 150);
	//imshow("Edges", m_Edges);

	vector<Vec4i> lines;
	HoughLinesP(m_Edges, lines, 1, CV_PI / 180, 60);
	int sizeofLines = lines.size();

	for (size_t i = 0; i < sizeofLines; i++)
	{
		line(src,Point(lines[i][0], lines[i][1]), Point(lines[i][2], lines[i][3]),Scalar(0,0,255),2);
	}
	imshow("Result", src);


	waitKey(0);
	
}

试运行结果如下:

        HoughCircles()函数

        HoughCircles()函数用于在灰度图中检测圆。其原型如下:

        HoughCircles()函数参数:

        image 输入图像,即源图像,应为8位单通道图像。如果使用彩色图像,需要先转换成灰度图像。

        circles 用来存储HoughCircles的结果,类型为listlist中对象格式为(x, y, r),分别表示圆心的x坐标、y坐标和圆的半径。

        method 定义检测图像中圆的方法。目前唯一实现的方法是cv::HOUGH_GRADIENT

        dp 图像像素分辨率与参数空间分辨率的比值(官方文档上写的是图像分辨率与累加器分辨率的比值)。dp=1时,参数空间与图像像素空间(分辨率)一样大;dp=2时,参数空间的分辨率只有像素空间的一半大。通过设置dp可以减少计算量。

        minDist 检测到的圆中心(x, y)坐标之间的最小距离。如果minDist太小,会保留大部分圆心相近的圆;如果minDist太大,则可能会将圆心相近的圆合并(若两圆心距离小于minDist,则认为是同一个圆)。

        param1 Canny边缘检测的高阈值,低阈值被自动置为高阈值的一半,默认为100

        param2 累加平面某点是否是圆心的判定阈值。只有当累加值大于该阈值时,才判断为圆。param2值设置得越小,检测到的圆越多;设置得越大,检测到的圆越接近完美的圆形。

        minRadius 半径的最小大小(以像素为单位),默认为0

        maxRadius 半径的最大大小(以像素为单位),默认为0。如果maxRadius小于等于0,则使用最大图像尺寸。如果maxRadius小于0HOUGH_GRADIENT返回中心而不查找半径,此时可以使用其他过程来找到正确的半径。

        HoughCircles()函数示例:

        屏蔽掉上面程序的部分代码,加入新代码,如下:

//HoughCircles
	Mat src = imread(".\\pic\\2.png");
	if (src.empty())
	{
		cout << "Cann't Open Image!" << endl;
		return -1;
	}
	imshow("Src", src);

	Mat dst;
	cvtColor(src, dst, COLOR_BGR2GRAY);
	GaussianBlur(dst, dst, Size(7, 7), 0);
	
	vector<Vec3f> circles;
	HoughCircles(dst, circles, HOUGH_GRADIENT, 1, 5,100);
	int sizeofLines = circles.size();

	for (size_t i = 0; i < sizeofLines; i++)
	{
		circle(src, Point(circles[i][0], circles[i][1]),circles[i][2], Scalar(0, 0, 255), 2);
	}
	imshow("Result", src);


	waitKey(0);
	
}

试运行,结果如下:

本博文到此结束,本博文示例程序的源代码已上传到CSDN。下载链接为:https://mp.csdn.net/mp_download/manage/download/UpDetailed

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

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

相关文章

【多线程】CAS原理

文章目录 为什么会出现CAS思想?CAS概念CAS自旋概念CAS的简单使用CAS源码解析 UnSafe类CAS底层原理CAS的硬件保证CAS自旋锁的实现前置知识----原子引用AtomicReference实现自旋锁 CAS缺点ABA问题什么是ABA问题如何解决ABA问题简单案例AtomicStampedReference的源码分析 为什么会…

leetcode链表(二)-两两交换链表中的节点

题目 . - 力扣&#xff08;LeetCode&#xff09; 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 思路 一定要使用虚拟头节点…

电子学报期刊投稿过程记录

电子学报的编辑老师确实人非常好&#xff0c;专业知识过硬&#xff0c;文章内容审核仔细&#xff0c;对格式的要求相对严格&#xff0c;并且打电话或者邮箱询问都很和善&#xff0c;也很温柔&#xff0c;同时也愿意配合再缴费后提前发送录用证明&#xff0c;但是见刊和网络首发…

单点登录Apereo CAS 7.1客户端集成教程

从上一篇部署并成功运行CAS服务端后,我们已经能通过默认的账号密码进行登录。 上篇地址:单点登录Apereo CAS 7.1安装配置教程-CSDN博客 本篇我们将开始对客户端进行集成。 CAS中的客户端,就是指我们实际开发的各个需要登录认证的应用。现在,跟着笔者的步伐,一起探索如何…

共识算法Raft

引入 在分布式系统中&#xff0c;为了消除单点提高系统可用性&#xff0c;通常会创建副本来进行容错&#xff0c;但这会带来另一个问题就是&#xff0c;如何保证多个副本之间的数据一致性。 为了解决这个问题&#xff0c;计算机行内就提出了共识算法&#xff0c;它允许多个分…

git gui基本使用

一、图形化界面 二、创建新项目 创建文件&#xff0c;加入暂存区&#xff0c;提交到版本库 三、创建分支 四、合并分支 1.切换至master 五、更新分支 六、解决冲突 修改冲突&#xff0c;加入暂存区&#xff0c;提交到版本库 七、远程创建库 Gitee - 基于 Git 的代码托管和研…

低功耗

低功耗 目录 低功耗 STM32中的电源系统 STM32 中的低功耗 相关代码 -- 首先我们先看我们做的项目如何降低功耗 -- 对于设备&#xff0c;功耗怎么降低&#xff1f;把设备上所有的电子模块&#xff0c;都进入低功耗模式。 对于空气质量检测仪&#xff0c;如何降低功耗&…

修改armbian DNS服务器地址(永久修改DNS配置)

linux dns服务器地址的配置文件在/etc/resolv.conf 但系统可能设置的是默认值&#xff0c;也就是192.168.1.1。导致系统无法正常解析域名&#xff0c;进而导致有一些接口无法调用或下载失败。 最直接的思路就是修改/etc/resolv.conf&#xff0c;将其中的nameserver修改为正确的…

必看系列:面试官通过一个问题考查了网络编程所有知识点!

一、写在开头 本文的主题是和大家一起探讨学习:“在浏览器中输入URL开始后,计算机所做的几件事”,这个问题是好几年前自己面试的时候,面试官考问过的,当时准备十分不充分,回答的一塌糊涂,今天拿出来再整理学习一遍,一同进步! 其实这个问题本身倒是不难,但它巧妙的是…

节假日提醒,节假日任务,节假日判断如何做?这篇文章教会你!

你是否有这样的需求&#xff0c;有一个任务需要在大家都休息的时候处理&#xff0c;你肯定会想到周六周日了&#xff0c;那不好意思&#xff0c;遇到调休怎么办呢&#xff1f;遇到国假怎么办呢&#xff1f;我这里所说的节假日和工作日不仅仅指正常的周一至周日&#xff0c;还包…

浙江省发规院产业发展研究所调研组莅临迪捷软件考察调研

2024年10月10日下午&#xff0c;浙江省发展与规划院产业发展研究所调研组一行莅临迪捷软件考察调研&#xff0c;绍兴市府办、区发改、区经信、迪荡街道等相关领导陪同。 调研组一行参观了迪捷软件的展厅与办公区&#xff0c;深入了解了迪捷软件的公司发展历程、运营状况、产品…

Python 如何使用 Bert 进行中文情感分析

前言 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;情感分析是一个非常常见且重要的应用。情感分析通常用于识别文本中的情感&#xff0c;例如判断一条微博或评论是正面、负面还是中性。在过去的几年中&#xff0c;随着深度学习的发展&#xff0c;BERT&#xff…

MySQL表的基本操作和数据类型

MySQL表的基本操作和数据类型 表的操作创建表修改表删除表 数据类型数值类型整型浮点型 文本、二进制类型日期时间类型ENUM类型和SET类型 表的操作 创建表 语法&#xff1a; CREATE TABLE table_name(field1 datatype,field2 datatype,field3 datatype )character set 字符集…

Python的matplotlib可视化工具基本操作(数据分析生成图表)

一、安装导入 1、使用包管理器安装matplotlib pip3 install matplotlib 2、导入plt工具 import matplotlib.pyplot as plt 二、基本函数 1、创建图表 使用pyplot工具打点调用创建图表函数 例如创建直方图&#xff1a; import matplotlib.pyplot as plt import pandas…

【unity框架开发9】序列化字典,场景,vector,color,Quaternion

文章目录 前言一、可序列化字典类普通字典简单的使用可序列化字典简单的使用 二、序列化场景三、序列化vector四、序列化color五、序列化旋转Quaternion完结 前言 自定义序列化的主要原因&#xff1a; 可读性&#xff1a;使数据结构更清晰&#xff0c;便于理解和维护。优化 I…

Android Framework默认授予app通知使用权限

安卓通知使用权限 在安卓系统中&#xff0c;应用程序需要获取通知使用权限才能向用户发送通知。以下是关于安卓通知使用权限的一些信息&#xff1a; 权限获取方式 当用户安装应用时&#xff0c;系统可能会在安装过程中提示用户授予应用通知权限。用户可以选择允许或拒绝。 应…

记录一些yolo-world训练数据集的报错

参考的这个文章 https://blog.csdn.net/ITdaka/article/details/138863017?spm1001.2014.3001.5501 openai快捷下载&#xff1a;https://download.csdn.net/download/qq_43767886/89876720 然后我打算训练coco数据集&#xff0c;遇到了以下的问题 问题一 原因&#xff1a;…

智慧农田新篇章:高标准农田灌区信息化的创新实践

在新时代的农业发展蓝图中&#xff0c;智慧农田已成为推动农业现代化、实现可持续发展目标的关键一环。高标准农田灌区信息化作为智慧农业的重要组成部分&#xff0c;正引领着一场深刻的农业技术革命&#xff0c;它不仅关乎粮食安全与资源高效利用&#xff0c;还深刻影响着农村…

writehelpAI论文写作,专业毕业论文救星

撰写专业毕业论文是每位学生学术旅程中的一个重要里程碑&#xff0c;它不仅检验了你对专业知识的掌握程度&#xff0c;还考验着研究能力、批判性思维以及书面表达技巧。在这个过程中&#xff0c;writehelpAI这样的智能写作助手可以成为你的得力伙伴&#xff0c;帮助解决从选题到…

功率检测和语音功能

INA226 INA226 High-Side or Low-Side Measurement, Bi-Directional Current and Power Monitor with I2C Compatible Interface datasheet (Rev. A) INA226功率监测模块原理 7.5 编程 INA226 器件的一个重要方面是它不一定测量电流或功率。该器件可测量施加在 IN 和 IN- 输入…