霍夫变换原理

news2025/1/11 19:54:25

文章目录

  • 霍夫变换原理
    • 当点都在y轴上时,用y=kx+b形式是无法求出参数空间中的交点,也就是累计都一样。所以就用极坐标来表示参数空间。
    • 公式求证
    • 过程


霍夫变换原理

在这里插入图片描述

当点都在y轴上时,用y=kx+b形式是无法求出参数空间中的交点,也就是累计都一样。所以就用极坐标来表示参数空间。

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

公式求证

cosθ = x / r
sinθ = y / r
而蓝色线的斜率为:y/x
sinθ / cosθ = y / r /(x/r)
		= y / x

又因为蓝色线和红色线垂直,
所以他们的斜率相乘为-1,
求红色线的斜率:
即:k = - x/y = -cosθ/sinθ

r /b = sinθ
即:b=r/sinθ

即红色线方程式:
y = (-cosθ/sinθ)x + (r/sinθ)

在这里插入图片描述

过程

霍夫变换是一种图像处理技术,可以用来检测出图像中的直线、圆等形状。

霍夫变换找直线的原理如下:

  1. 在笛卡尔坐标系中,一条直线可以用 y = mx + b 的形式表示,其中 m 是斜率,b 是截距。将直线用极坐标表示,可以得到:

    rho = x * cos(theta) + y * sin(theta)

    其中,rho 表示直线到坐标原点的距离,theta 表示直线与 x 轴的夹角。

  2. 对于图像中的每个点,遍历所有可能的 rho 和 theta 组合,并在霍夫空间中进行累加。

  3. 在霍夫空间中,如果有多个点在同一直线上,那么它们对应的 rho 和 theta 组合的累加值会比较高,可以通过设置一个阈值来确定直线。

  4. 在霍夫空间中,每个点对应的 rho 和 theta 组合对应着一条直线,可以通过取出累加值最高的几个点来确定图像中的直线。

  5. 霍夫直线检测的优缺点
    优点:霍夫变换找直线的优点是能够检测出图像中的所有直线,不需要预先知道直线的位置和方向。Hough直线检测的优点是抗干扰能力强,对图像中直线的殘缺部分、噪声以及其它共存的非直线结构不敏感,能容忍特征边界描述中的间隙,并且相对不受图像噪声的影响。

缺点:Hough变换算法的特点导致其时间复杂度和空间复杂度都很高,并且在检测过程中只能确定直线方向,丢失了线段的长度信息。由于霍夫检测过程中进行了离散化,因此检测精度受参数离散间隔制约

以下是C++代码实现霍夫变换找直线的示例:

void HoughTransform(Mat& img, Mat& dst)
{
	// 定义图像的宽和高
	int width = img.cols;
	int height = img.rows;
	double rhoMax = sqrt(pow(width, 2) + pow(height, 2)); // 最大极径
	int thetaMax = 180; // 最大极角
	int accumHeight = (int)(rhoMax * 2 + 1); // 累加器高度
	int accumWidth = thetaMax;// 累加器宽度
	// 定义霍夫变换的参数空间的大小
	Mat accum(accumHeight, accumWidth, CV_32SC1, Scalar(0)); // 累加器
	int centerX = width / 2;
	int centerY = height / 2;
	for (int y = 0; y < height; ++y)
	{
		for (int x = 0; x < width; ++x)
		{
			if (img.at<uchar>(y, x) == 255)
			{
				for (int theta = 0; theta < thetaMax; ++theta)
				{
					double rho = (x - centerX) * cos(theta * CV_PI / 180) + (y - centerY) * sin(theta * CV_PI / 180); // 极径
					int rhoIndex = (int)cvRound(rho + rhoMax);
					accum.at<int>(rhoIndex, theta)++;
				}
			}
		}
	}
	dst = Mat::zeros(height, width, CV_8UC1);
	// 对每个参数进行遍历  找到霍夫变换参数空间中的峰值
	for (int rhoIndex = 0; rhoIndex < accumHeight; ++rhoIndex)
	{
		for (int theta = 0; theta < thetaMax; ++theta)
		{
			// 如果当前参数对应的计数值大于等于阈值
			if (accum.at<int>(rhoIndex, theta) > 150)
			{
				/*首先,我们将rhoIndex从数组索引值转换回霍夫空间中的极径rho。
					这里需要注意,由于我们之前对rho进行了平移,所以在转换回来时,
					我们需要将rhoMax再次减去以得到正确的极径值。*/
				double rho = rhoIndex - rhoMax;

				double a = cos(theta * CV_PI / 180);
				double b = sin(theta * CV_PI / 180);
				//转换原来x和y的实际像素坐标
				double x = a * rho + centerX;
				double y = b * rho + centerY;
                //当一个直线角度不变的情况下,x 移动(-b),y也跟着移动a
                 //-b = sin() = x/r      a = cos() = y/r      当r=1000  r*x/r =x   r*y/r = y (x和-y的关系:比率不变)  也就是角度不变,坐标沿着同一角度的直线变化
				Point pt1(cvRound(x + 1000 * (-b)), cvRound(y + 1000 * a));
				Point pt2(cvRound(x - 1000 * (-b)), cvRound(y - 1000 * a));

                //Point pt1(cvRound(x + 1000 * (b)), cvRound(y + 1000 * -a));
				//Point pt2(cvRound(x - 1000 * (b)), cvRound(y - 1000 * -a));
				line(dst, pt1, pt2, Scalar(255), 1, LINE_8);


			}
		}
	}
}

上面代码centerX 有什么用意?

在霍夫变换中,我们需要将每个像素点的坐标转换为极坐标系下的极径和极角。由于极径的范围通常是从原点到图像边缘的最大距离,因此在计算极径时,我们需要将每个像素的坐标平移使其相对于图像中心而非左上角。

在代码中,centerX是图像宽度的一半,即图像中心点的x坐标。我们将每个像素的x坐标减去centerX,以将坐标系统平移到图像中心。

同样,centerY是图像高度的一半,即图像中心点的y坐标。我们将每个像素的y坐标减去centerY,以将坐标系统平移到图像中心。

这样做的目的是确保极径的计算基于图像中心而非左上角,从而使算法更加准确。

int rhoIndex = (int)(rho + rhoMax + 0.5); 这段代码什么意思

这段代码是将当前直线在霍夫空间中的极径rho转换为在accum数组中的索引值rhoIndex。

在霍夫空间中,极径的值通常是一个浮点数。为了在数组中保存极径的计数值,我们需要将它们转换为整数类型。因此,我们使用(int)将rho强制转换为整数类型。此外,我们需要将所有的极径值移动到正数范围内,以便在数组中使用。因此,我们添加一个常数rhoMax,该常数等于极径的最大值加上1,以将所有极径值移动到正数范围内。

最后,我们使用0.5来进行四舍五入,以确保将rho值正确地映射到rhoIndex上。这样可以避免由于浮点数的舍入误差而导致的不准确的索引值。

        double rho = rhoIndex - rhoMax;
        double a = cos(theta * CV_PI / 180);
        double b = sin(theta * CV_PI / 180);
        double x0 = a * rho + centerX;
        double y0 = b * rho + centerY;

这段代码是将accum数组中的索引值转换回霍夫空间中的极坐标。

首先,我们将rhoIndex从数组索引值转换回霍夫空间中的极径rho。这里需要注意,由于我们之前对rho进行了平移,所以在转换回来时,我们需要将rhoMax再次减去以得到正确的极径值。

然后,我们将极角theta转换为弧度制,并计算出直线的参数a和b。这里需要注意,OpenCV中的三角函数接受的是弧度制而非角度制的参数,所以我们需要将theta转换为弧度制。

接下来,我们计算直线在笛卡尔坐标系下的截距x0和y0。这里的计算公式来自于霍夫变换中的极坐标到笛卡尔坐标的转换公式:

x = r cos(theta) + x0
y = r sin(theta) + y0

其中,x0和y0是直线在笛卡尔坐标系下的截距,theta是直线在霍夫空间中的极角,r是直线在霍夫空间中的极径。通过将r替换为计算得到的rho,我们可以将直线的极坐标转换为笛卡尔坐标。由于之前我们对坐标进行了平移,所以在计算x0和y0时,我们需要将它们还原回原始坐标系。

    Point pt1(cvRound(x + 1000 * (-b)), cvRound(y + 1000 * a));
    Point pt2(cvRound(x - 1000 * (-b)), cvRound(y - 1000 * a));

这段代码是用来在图像上绘制检测到的直线。

由于在霍夫空间中,直线的表示形式是(rho, theta),其中rho表示直线到图像中心的距离,theta表示直线与x轴的夹角,因此我们需要将它们转换为笛卡尔坐标系下的表示形式,即直线的两个端点坐标(x1, y1)和(x2, y2)。

对于一条直线,我们可以根据它在霍夫空间中的参数rho和theta,以及一个固定长度的线段来计算它在图像上的两个端点坐标。

具体地,我们首先计算线段的一个端点(x1, y1),其中x1和y1分别等于直线在笛卡尔坐标系下的截距(x0, y0)加上一个向量(-b, a),该向量的长度为1000。向量(-b, a)的长度可以控制我们在图像上绘制直线的长度。

然后,我们计算线段的另一个端点(x2, y2),其中x2和y2分别等于直线在笛卡尔坐标系下的截距(x0, y0)加上一个向量-(-b, a),该向量的长度同样为1000。注意,在计算x2和y2时,我们将向量-(-b, a)写成了(b, -a),因为-(-b, a)等于(b, -a)。

最后,我们使用OpenCV的cvRound函数将x1、y1、x2和y2四个值分别四舍五入为整数,以便在图像上绘制直线。然后,我们将x1和y1作为直线的起点,将x2和y2作为直线的终点,在图像上绘制一条直线。

为什么(-b, a)是向量?

(-b, a)是一个向量,它可以表示为一个有向线段,其起点为原点(0, 0),终点为点(-b, a)。

在这个问题中,(-b, a)被用来表示垂直于直线的向量。我们可以将这个向量添加到直线在笛卡尔坐标系下的截距点(x0, y0)上,从而得到直线上的另一个点(x2, y2)。

这个向量的长度为1000,可以用来控制绘制的直线的长度。在具体实现时,我们将这个向量的长度设置为1000个像素,因此直线的长度为1000个像素。

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

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

相关文章

linux服务器安装nodejs

注意&#xff1a; 本文针对的是有linux操作基础&#xff0c; 会使用vim的基本操作的同学。故有些很基础的东西没有赘述&#xff0c;如果是纯小白的同学&#xff0c;看起来可能会感觉缺失一些东西。 1.nodejs官网下载自己需要的版本的node node版本选择下载地址 我使用的是14.…

图像边缘检测原理

文章目录 图像边缘检测原理1:2:3:基本边缘检测算子 图像边缘检测原理 1: 图像的边缘指的是图像中像素灰度值突然发生变化的区域&#xff0c;如果将图像的每一行像素和每一列像素都描述成一个关于灰度值的函数&#xff0c;那么图像的边缘对应在灰度值函数中是函数值突然变大的…

Autoware 安装(踩坑指南)

Autoware 安装&#xff08;踩坑指南&#xff09; 【Autoware】2小时安装Autoware1.13&#xff08;保姆级教程&#xff09; Autoware入门学习&#xff08;二&#xff09;——Ubuntu18.04下的源码安装和配置 上面的两篇博客安装都异常顺利&#xff0c;甚至没有一点报错&#xff0…

AMEYA360代理线:艾睿红外热成像仪数据机房监测应用

数据信息时代&#xff0c;数据机房是企业重要的区域。近日某购物平台发生的数据机房宕机事故&#xff0c;引发关注。机房设备温度异常&#xff0c;使得系统崩溃&#xff0c;经济损失超亿元。红外热成像仪作为一种非接触式、精准度高、可视化的温度测量工具&#xff0c;为数据机…

【MyBatis 神级框架】从入门到进阶

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 1. 什么是 MyBatis 1.1 为什么要学MaBatis&am…

TikTok正测试AI聊天机器人Tako

该功能可以“从根本上改变应用程序中的搜索和导航” 原文链接&#xff1a;TikTok tests AI chatbot called Tako – The Verge TikTok正在测试一个名为Tako的AI聊天机器人&#xff0c;根据与The Verge共享的功能截图&#xff0c;它可以根据人们的问题推荐视频。 如果TikTok最…

总结:公有云产品之CDN

一、介绍 由于公司经常提供CDN相关概念&#xff0c;本文特地总结下。 二、产品说明 百度云的内容分发网络CDN是一款基于互联网的分布式服务平台&#xff0c;可以加速网络上的内容分发和传输&#xff0c;提高网络的稳定性和访问速度。 CDN主要通过将网站的静态和动态资源缓存…

读书笔记-《ON JAVA 中文版》-摘要17[第十七章 文件]

文章目录 第十七章 文件1. 文件和目录路径1.1 选取路径部分片段1.2 路径分析1.3 Paths的增减修改 2. 目录3. 文件系统4. 路径监听5. 文件查找6. 文件读写7. 本章小结 第十七章 文件 在丑陋的 Java I/O 编程方式诞生多年以后&#xff0c;Java终于简化了文件读写的基本操作。 在 …

手机APP测试流程规范模板

一、流程图 二、测试周期 9.25-10.5 1、测试资源 测试任务开始前&#xff0c;检查各项测试资源。 1.1、产品功能需求文档 1&#xff09;产品原型图 2&#xff09;产品效果图 3&#xff09;行为统计分析定义文档 4&#xff09;测试设备&#xff08;Android4.1-Android4.…

OWASP 之跨站脚本xss基础技能

OWASP 之跨站脚本xss基础技能 一.XSS概述二.漏洞危害三.XSS漏洞绕过方法1.手工测试XSS步骤2.常见xss3.绕过方法 四.xss防御方法a.CSP内容安全策略b.HttpOnlyc.输入输出检查d.使用防御函数 五.pikachu靶场1.反射型XSS&#xff08;get&#xff09;2.反射型XSS&#xff08;post&am…

PS如何把多张图片拼接到一张?

现在有多张图片如下 &#xff0c;如何拼接成为1张呢&#xff1f; 打开ps&#xff0c;在ps里面点击文件->自动->联系表。 在弹出来的联系表对话框中&#xff0c;点击选取&#xff0c;选择要拼接的图片。 选择好图片之后&#xff0c;设置宽度高度&#xff0c;宽度的话&…

List Label 28.003 2023 Crack

列表和标签 28.003 在 Web 报表设计器中添加新的图表类型&#xff0c;并支持 Embarcadero RAD Studio 11.3。 6月 16&#xff0c; 2023 - 16&#xff1a;38 新版本 特征 .NET 所有可用的 NuGet 包现在都有一个特殊的企业包和 ID&#xff0c;以确保包都来自一个包源&#xff0c;…

GeneGPT:用领域工具增强大型语言模型,以改善对生物医学信息的访问

文章目录 一、论文关键信息二、主要内容1. Motivations2. 解决方案关键3. 实验和结果 三、总结与讨论 &#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 一、论文关键信息 论文标题&#xff1a;GeneGPT: Augmenting Large Language Models with Domain …

代码审计——垂直越权详解

为方便您的阅读&#xff0c;可点击下方蓝色字体&#xff0c;进行跳转↓↓↓ 01 漏洞描述02 审计要点03 漏洞特征04 漏洞案例05 修复方案 01 漏洞描述 垂直越权&#xff0c;也称权限提升&#xff0c;是一种“基于URL的访问控制”设计缺陷引起的漏洞。 由于Web应用程序没有做权…

2023开放原子全球开源峰会——Intel专题探访

浩瀚宇宙&#xff0c;有光&#xff0c;朝着未来之境&#xff1b;万物之始&#xff0c;有道&#xff0c;启示智慧共荣&#xff1b;在多维赋能的时空里&#xff0c;见微知著&#xff0c;开放共享 &#xff0c;包罗万象&#xff1b;在抵达终点的路途中&#xff0c;彼此陪伴&#x…

《Java核心卷1》怎么样?读1,2章草记 | 第12版

文章目录 《Java核心技术卷 一》第一章 概述第二章 Java编程环境 图书推荐 《Java核心技术卷 一》 第一章 概述 前言&#xff1a;本书与一些”0基础入门“的书定位感觉是不太一样的&#xff0c;可能就像书名所说&#xff0c;是”核心技术“叭。书中经常将Java语言与 c 进行对比…

基于Java电子竞技管理平台设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a; ✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精…

详解c++---红黑二叉树的原理和实现

什么是红黑二叉树树 avl树是通过控制平衡因子来控制二叉搜索树的平衡&#xff0c;当某个节点的平衡因子等于2或者-2的话我们就根据他所在的位置来进行旋转&#xff0c;如果这个节点位于右右的话就对其进行向左旋转&#xff0c;如果这个节点位于左左的话就对其进行向右旋转&…

【Android复习笔记】OkHttp核心原理

使用方法 调用流程 0kHttp请求过程中最少只需要接触OkHttpClient、Request、Call、 Response,但是框架内部进行大量的逻辑处理。 所有的逻辑大部分集中在拦截器中,但是在进入拦截器之前还需要依靠分发器来调配请求任务。 分发器:内部维护队列与线程池,完成请求调配;拦截…

chatgpt赋能python:Python中嵌套列表的访问方法

Python中嵌套列表的访问方法 在Python编程中&#xff0c;嵌套列表是一种很常见的数据类型。它可以存储多个列表&#xff0c;使得数据结构更加复杂灵活。然而&#xff0c;如何访问嵌套列表中的元素呢&#xff1f;本文将详细介绍Python中嵌套列表的访问方法。 嵌套列表的定义 …