[OpenCV] 数字图像处理 C++ 学习——14霍夫变换直线、圆检测 附完整代码

news2024/9/21 6:56:09

文章目录

  • 前言
  • 1.霍夫变换原理
    • (1)霍夫变换检测直线的原理
    • (2)霍夫变换检测圆的原理
  • 2.代码实现
    • (1)霍夫直线检测
    • (2)霍夫圆检测
  • 3.完整代码

前言

霍夫变换是一种有效的检测图像中的几何形状(如直线、圆等)的算法。霍夫变换通过将几何形状的检测问题转化为参数空间的问题,能够在噪声较大的图像中有效地检测出目标。本文将详细介绍霍夫变换的原理,直线检测和圆检测的实现方法,并提供完整的 Opencv的C++ 代码示例。

1.霍夫变换原理

(1)霍夫变换检测直线的原理

霍夫变换用于检测直线的基本思想是将图像坐标空间中的点转换到参数空间。在二维图像空间中,直线可以表示为:
y = k x + b y = kx + b y=kx+b
然而,为了避免处理斜率无穷大的情况,霍夫变换使用极坐标表示直线方程:
ρ = x ⋅ cos ⁡ θ + y ⋅ sin ⁡ θ \rho = x \cdot \cos\theta + y \cdot \sin\theta ρ=xcosθ+ysinθ
其中, ρ \rho ρ是直线到图像原点的距离, θ \theta θ 是直线与 x 轴的夹角。在霍夫空间中,图像中的每个点都会在参数空间中形成一条正弦曲线,曲线的交点就代表图像中的一条直线。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图像中的多个点位于同一条直线上时,它们的曲线会在霍夫空间中相交,通过累加这些交点,可以检测出图像中的直线。

(2)霍夫变换检测圆的原理

对于圆的检测,圆的参数化方程为:
( x − a ) 2 + ( y − b ) 2 = R 2 (x - a)^2 + (y - b)^2 = R^2 (xa)2+(yb)2=R2
其中,(a, b) 是圆心的坐标,® 是圆的半径。霍夫变换通过检测图像中的边缘像素,确定这些像素点在参数空间中形成的圆。与直线检测不同的是,圆检测需要对三个参数(圆心 (a)、(b) 和半径 ®)进行霍夫变换。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 在输入图像中,每个检测到的边缘点(黑色小圆点)可能属于一个圆的一部分。根据圆的方程,每个边缘点可以对应无数个可能的圆。
  • 通过改变参数 θ 的值(即角度变化),可以绘制出多个可能的圆心位置 (a,b),这些可能的圆心会形成一系列圆的路径,如图中虚线圆所示。
  • 当多个边缘点都位于同一个圆上时,它们对应的多个圆心会在霍夫空间中相交(图中橙色点)。这些交点就代表了可能的圆心位置。
  • 在霍夫变换中,通过对霍夫空间进行累加操作,如果某个位置被多个边缘点的圆路径所覆盖,说明该位置有较大的概率是实际的圆心位置。每次累加器在这个位置增加计数,直到检测到符合圆的点。

2.代码实现

实验用到的图像road.png
OIP.jpg

(1)霍夫直线检测

HoughLines(); 一般不用,比较复杂,使用HoughLinesP完全可以实现直线检测。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

HoughLines()

/*************************HoughLines********************************/
	cv::Mat gray;
	cvtColor(image, gray, COLOR_BGR2GRAY);
	// 2.边缘检测
	cv::Mat edges;
	Canny(gray, edges, 50, 150);
	// 3.霍夫直线检测
	vector<Vec2f> lines;
	HoughLines(edges, lines, 1, CV_PI / 180, 150);
	// 4. 绘制检测到的直线
	for (size_t i = 0; i < lines.size(); i++) {
		float rho = lines[i][0], theta = lines[i][1];
		Point pt1, pt2;
		double a = cos(theta), b = sin(theta);
		double x0 = a * rho, y0 = b * rho;
		pt1.x = cvRound(x0 + 1000 * (-b));
		pt1.y = cvRound(y0 + 1000 * (a));
		pt2.x = cvRound(x0 - 1000 * (-b));
		pt2.y = cvRound(y0 - 1000 * (a));
		line(image, pt1, pt2, Scalar(0, 0, 255), 2, LINE_AA);
	}
	imshow("Detected Lines", image);

HoughLinesP()常用

/**********************HoughLinesP***************************************/
	vector<Vec4i> lines1; // 存储检测到的线段,每条线段有4个值(x1, y1, x2, y2)
	HoughLinesP(edges, lines1, 1, CV_PI / 180, 50, 50, 10); // 参数可以调整
	 // 4. 绘制检测到的直线
	for (size_t i = 0; i < lines.size(); i++) {
		Vec4i l = lines1[i];
		line(image, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 2, LINE_AA);
	}
	// 5. 显示结果
    imshow("Detected Lines_P", image);

结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(2)霍夫圆检测

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

HoughCircles()

/******************************HoughCircles***************************************/
	Mat gray1;
	cvtColor(inputimage, gray1, COLOR_BGR2GRAY);
	//medianBlur(gray1, gray1, 3);
	// 2. 使用高斯模糊减少噪声
	GaussianBlur(gray1, gray1, Size(9, 9), 2, 2);
	// 3. 霍夫圆检测
	vector<Vec3f> circles;
	HoughCircles(gray1, circles, HOUGH_GRADIENT, 1, gray1.rows / 8, 100, 25, 15, 38);
	// 4. 绘制检测到的圆
	for (size_t i = 0; i < circles.size(); i++) {
		Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
		int radius = cvRound(circles[i][2]);
		// 绘制圆心
		circle(inputimage, center, 3, Scalar(0, 255, 0), -1, 8, 0);
		// 绘制圆轮廓
		circle(inputimage, center, radius, Scalar(0, 0, 255), 3, 8, 0);

	}
	// 5. 显示结果
	cout << "Number of circles detected: " << circles.size() << endl;

	imshow("Detected Circles", inputimage);

结果:

HoughCircles(gray1, circles, HOUGH_GRADIENT, 1, gray1.rows / 8, 100, 25, 15, 38);

参数需要不断调整才能实现更好效果
在这里插入图片描述

3.完整代码

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

using namespace cv;
using namespace std;

void Hough_transform()
{
	cv::Mat image;
	image = imread("road.png");
	if (image.empty()) {
		printf("could not find the image...\n");
		return;
	}
	namedWindow("input image", cv::WINDOW_AUTOSIZE);
	cv::imshow("image", image);

	cv::Mat inputimage;
	inputimage = imread("OIP.jpg");
	if (inputimage.empty()) {
		printf("could not find the image...\n");
		return;
	}
	namedWindow("input image", cv::WINDOW_AUTOSIZE);
	cv::imshow("input image", inputimage);

	
	/*************************HoughLines********************************/
	cv::Mat gray;
	cvtColor(image, gray, COLOR_BGR2GRAY);
	// 2.边缘检测
	cv::Mat edges;
	Canny(gray, edges, 50, 150);
	// 3.霍夫直线检测
	vector<Vec2f> lines;
	HoughLines(edges, lines, 1, CV_PI / 180, 150);
	// 4. 绘制检测到的直线
	for (size_t i = 0; i < lines.size(); i++) {
		float rho = lines[i][0], theta = lines[i][1];
		Point pt1, pt2;
		double a = cos(theta), b = sin(theta);
		double x0 = a * rho, y0 = b * rho;
		pt1.x = cvRound(x0 + 1000 * (-b));
		pt1.y = cvRound(y0 + 1000 * (a));
		pt2.x = cvRound(x0 - 1000 * (-b));
		pt2.y = cvRound(y0 - 1000 * (a));
		line(image, pt1, pt2, Scalar(0, 0, 255), 2, LINE_AA);
	}
	imshow("Detected Lines", image);
	/**********************HoughLinesP***************************************/
	vector<Vec4i> lines1; // 存储检测到的线段,每条线段有4个值(x1, y1, x2, y2)
	HoughLinesP(edges, lines1, 1, CV_PI / 180, 50, 50, 10); // 参数可以调整
	 // 4. 绘制检测到的直线
	for (size_t i = 0; i < lines.size(); i++) {
		Vec4i l = lines1[i];
		line(image, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 2, LINE_AA);
	}
	// 5. 显示结果
    imshow("Detected Lines_P", image);
	/******************************HoughCircles***************************************/
	Mat gray1;
	cvtColor(inputimage, gray1, COLOR_BGR2GRAY);
	//medianBlur(gray1, gray1, 3);
	// 2. 使用高斯模糊减少噪声
	GaussianBlur(gray1, gray1, Size(9, 9), 2, 2);
	imshow("gray1", gray1);
	// 3. 霍夫圆检测
	vector<Vec3f> circles;
	HoughCircles(gray1, circles, HOUGH_GRADIENT, 1, gray1.rows / 8, 100, 25, 15, 38);
	// 4. 绘制检测到的圆
	for (size_t i = 0; i < circles.size(); i++) {
		Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
		int radius = cvRound(circles[i][2]);
		// 绘制圆心
		circle(inputimage, center, 3, Scalar(0, 255, 0), -1, 8, 0);
		// 绘制圆轮廓
		circle(inputimage, center, radius, Scalar(0, 0, 255), 3, 8, 0);
	}
	// 5. 显示结果
	cout << "Number of circles detected: " << circles.size() << endl;

	imshow("Detected Circles", inputimage);
	waitKey(0);
}
int main() 
{
	Hough_transform();
    return 0;
}

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

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

相关文章

微分方程学习笔记

文章目录 一、基础概念二、重要结论1、一阶可分离变量的微分方程求解思路2、一阶非齐次线性微分方程解的结构3、可降阶的高阶微分方程4、线性微分方程解的结构1. 二阶齐次线性微分方程解的结构2. 二阶非齐次线性微分方程解的结构 参考 之前大学的时候学微分方程有点云里雾里的&…

【2024】前端学习笔记7-颜色-位置-字体设置

学习笔记 1.定义&#xff1a;css2.颜色&#xff1a;color3.字体相关属性&#xff1a;font3.1.字体大小&#xff1a;font-size3.2.字体风格&#xff1a;font - style3.3.字体粗细&#xff1a;font - weight3.4.字体族&#xff1a;font - family 4.位置&#xff1a;text-align 1.…

CMA第三方软件测试报告获取指南

在当今竞争激烈的市场环境中&#xff0c;企业对于产品质量的重视程度不断提高。为了确保软件产品的性能和安全性&#xff0c;许多企业开始寻求专业的第三方测试服务来获取第三方软件测试报告&#xff0c;而有无CMA认证资质对于软件测试报告来说至关重要。 CMA认证是中国国家认…

Web 服务器介绍 | 通过 Tomcat 说明其作用

1. 什么是 Web 服务器&#xff1f; Web服务器是一种用于存储、处理和提供网页或Web应用程序的服务器。它通过HTTP&#xff08;超文本传输协议&#xff09;与客户端&#xff08;通常是浏览器&#xff09;进行通信&#xff0c;接收客户端的请求&#xff08;如网页请求&#xff0…

一个很强大的离线IP地址定位库和IP定位数据管理框架,支持亿级别的数据段(附源码)

前言 随着互联网的发展&#xff0c;IP地址定位成为了诸多应用中的重要一环。然而&#xff0c;现有的许多定位库在面对大规模数据时&#xff0c;往往会遇到查询速度慢、内存消耗大等问题。有没有一款工具能够处理这些问题&#xff0c;为开发者提供一个更为高效、灵活的定位库呢…

光伏储能直流监测系统的研发

摘要&#xff1a;在“双碳”战略背景下&#xff0c;光伏技术成为光伏与建筑两大行业关注的焦点。在建设中引入光电、储能、微网是目前的一个发展趋势&#xff0c;受接入资源的多样性和不连续的限制,合理控制、优化分配资源成为一项难题。研究建立一个智能微电网控制系统,利用集…

django数字化时代的新能源汽车供应链优化与可视化-计算机毕业设计源码91188

摘要 本研究旨在探讨利用Django框架进行新能源汽车供应链优化与可视化的应用。随着数字化时代的到来&#xff0c;新能源汽车产业迅速发展&#xff0c;供应链管理变得至关重要。通过结合Django框架的强大功能&#xff0c;我们可以优化新能源汽车供应链的各个环节&#xff0c;实现…

Python基础 | 在虚拟环境中安装并在指定文件夹中打开Jupyter notebook

在虚拟环境中安装并在指定文件夹中打开Jupyter notebook 前言一、在虚拟环境下安装Jupyter notebook二、在指定路径下打开Jupyter notebook 前言 Jupyter Notebook 是一个基于 Web 的交互式计算环境&#xff0c;主要功能是将代码、文本、数学方程式、可视化和其他相关元素组合…

线性规划------ + 案例 + Python源码求解(见文中)

目录 一、代数模型&#xff08;Algebraic Models&#xff09;详解1.1什么是代数模型&#xff1f;1.2代数模型的基本形式1.3 安装所需要的Python包--运行下述案例1.4代数模型的应用案例案例 1&#xff1a;市场供需平衡模型Python求解代码Python求解结果如下图&#xff1a; 案例 …

Android绘制靶面,初步点击位置区域划分取值测试

自定义View&#xff1a; public class TargetView extends View {private Paint paint;private int[] radii {100, 250, 400, 550, 700}; // 五个圆的半径private int numberOfSegments 8;private int[][] regionValues; // 存储每个区域的值public TargetView(Context cont…

单例模式(饿汉式-懒汉式)

我给面试官讲解了单例模式后&#xff0c;他对我竖起了大拇指&#xff01;https://blog.csdn.net/weixin_41949328/article/details/107296517?ops_request_misc%257B%2522request%255Fid%2522%253A%2522FAEE9ABD-432D-416C-98C6-9DD939138DEB%2522%252C%2522scm%2522%253A%252…

检查和测绘室内防撞无人机技术详解

随着无人机技术的飞速发展&#xff0c;其应用领域已从传统的航拍、农业扩展到更为精细化的室内空间测绘、巡检、物流等领域。在室内环境中&#xff0c;无人机面临着空间狭小、障碍物多、GPS信号弱等挑战&#xff0c;因此对防撞技术提出了更高的要求。室内防撞无人机技术的研发&…

JMeter 中使用 Gson 操作请求中的Boby参数

背景 使用org.json.JSONObject 转换&#xff0c;与原Body参数顺序发生变化&#xff0c;原因&#xff1a;JSONObject内部是用Hashmap来存储的&#xff0c;本质上是一个无序的键值对集合&#xff0c;不应依赖字段的添加顺序。 为解决org.json.JSONObject 输出顺序问题&#xff…

【virtuoso】AMS数模混合仿真

一、新建Verilog文件 1.1 新建functional 文件 1.2 编写Verilog文件 module phv (ckv ,rst_n ,phv_n );input ckv ;input rst_n ;output reg [10:0] phv_n;always (posedge ckv) beginif(rst_n)phv_n < 11b0;elsephv_n <…

PCIe扫盲(六)

系列文章目录 PCIe扫盲&#xff08;一&#xff09; PCIe扫盲&#xff08;二&#xff09; PCIe扫盲&#xff08;三&#xff09; PCIe扫盲&#xff08;四&#xff09; PCIe扫盲&#xff08;五&#xff09; PCIe扫盲&#xff08;六&#xff09; 文章目录 系列文章目录Flow Control…

io多路复用:epoll水平触发(LT)和边沿触发(ET)的区别和优缺点

在进行ET模式的正式分析之前&#xff0c;我们来举个例子简单地了解下ET和LT: 假设我们通过fork函数创建了父子两个进程&#xff0c;并通过匿名管道来通信&#xff0c;在子进程中&#xff0c;我们一次向管道写入10个字符数据&#xff0c;为"aaaa\nbbbb\n";每隔5s写入…

深入解析JSP会话跟踪:从原理到实践

什么是会话? 生活中:一次电话.一次取款过程Web应用一次会话:一个客户端浏览器与web服务器之间连续发生的一系列请求和相应的过程 什么是会话状态&#xff1f; 会话状态是指Web服务器与浏览器在会话过程中产生的状态信息。 什么是Cookie&#xff1f; 引言&#xff1a;浏览购…

windows使用tcpdump.exe工具进行抓包教程

windows主机安装一些抓包工具可能有些不方便&#xff0c;这里有一个tcpdump.exe工具直接免安装&#xff0c;可以直接使用进行抓包。&#xff08;工具下载见 附件&#xff09; tcpdump.exe使用教程 如下&#xff1a; 1&#xff1a;tcpdump -D 可查看网络适配器(注意前面的编号)…

htaccess转换nginx工具

115工具网为您提供htaccess与nginx在线转换,apache伪静态文件转为nginx重写规则,htaccess伪静态规则换nginx,apache RewriteRule转rewrite,apache伪静态文件转nginx重写,apache转nginx重写规则&#xff0c;本工具支持所有的htaccess伪静态、基本的配置规则、重定向等转换为ngin…

java多线程编程示例

程序功能 程序展示了 Java 中如何使用多线程来并行执行任务。具体功能如下&#xff1a; 程序创建了三个线程&#xff0c;每个线程执行相同的任务类 Task。 每个线程在运行时输出自身名称&#xff0c;并模拟执行五次任务&#xff0c;每次任务间隔 1 秒。 主线程在启动这三个线程…