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

文章目录

  • 前言
  • 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.rhkb.cn/news/426417.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python学习第十节:爬虫基于requests库的方法

python学习第十节&#xff1a;爬虫基于requests库的方法 requests模块的作用&#xff1a; 发送http请求&#xff0c;获取响应数据&#xff0c;requests 库是一个原生的 HTTP 库&#xff0c;比 urllib 库更为容易使用。requests 库发送原生的 HTTP 1.1 请求&#xff0c;无需手动…

引领智能家居新风尚,WTN6040F门铃解决方案——让家的呼唤更动听

在追求高效与便捷的智能家居时代&#xff0c;每一个细节都承载着我们对美好生活的向往。WTN6040F&#xff0c;作为一款专为现代家庭设计的低成本、高性能门铃解决方案&#xff0c;正以其独特的魅力&#xff0c;悄然改变着我们的居家生活体验。 芯片功能特点&#xff1a; 1.2.4…

关于订单信息的Excel数据分析报告

提升自己&#xff0c;掌握数据分析的能力&#xff0c;最快的方式就是实践&#xff01; 这里又是一个Excel数据分析项目的分析报告&#xff0c;有需要项目配套数据集的可以关注私信我免费获取(●◡●)

Skytower

一、安装配置靶机 下载地址: SkyTower: 1 ~ VulnHub 下载之后解压发现是VirtualBox格式的 我们下载一个VirtualBox&#xff0c;这是官网 Downloads – Oracle VirtualBox 安装到默认路径就 打开后点击注册 选择解压后的vbox文件 然后点击左上角管理 点击导出虚拟电脑&…

MUNIK谈ASPICE系列专题分享(十)ASPICE配置管理如何做

前言&#xff1a; ASPICE&#xff08;Automotive Software Process Improvement and Capability dEtermination&#xff09;是一种用于评估汽车行业软件开发过程成熟度的模型。配置管理是ASPICE中的一个关键过程领域&#xff08;KPA&#xff09;&#xff0c;它涉及到对软件项目…

【Linux篇】Http协议(1)(笔记)

目录 一、http基本认识 1. Web客户端和服务器 2. 资源 3. URI 4. URL 5. 事务 6. 方法 7. 状态码 二、HTTP报文 1. 报文的流动 &#xff08;1&#xff09;流入源端服务器 &#xff08;2&#xff09;向下游流动 2. 报文语法 三、TCP连接 1. TCP传输方式 2. TCP连…

Vue3.0组合式API:使用defineEmits()实现子组件向父组件传递数据

1、使用 defineEmits() 函数 父组件通过使用 Prop 为子组件传递数据&#xff0c;但如果子组件要把数据传递回去&#xff0c;就需要使用自定义事件来实现。父组件可以通过 v-on 指令&#xff08;简写形式“”&#xff09;监听子组件实例的自定义事件&#xff0c;而子组件可以通…

高密原型验证系统解决方案(下篇)

0 引言 我们在上篇中和大家探讨了用户在进行大规模 复杂 SoC 设计原型验证时在全局时钟及复位同步&#xff0c; 大规模设计分割以及高速接口与先进 Memory 控制 器 IP 验证等方面遇到的关键困难&#xff0c;并提出了相应的 解决方案帮助用户来克服这些困难。接下来我们会 和用户…

PDF扫描版文字识别OCR

PDF扫描版文字识别OCR 最近需要有对PDF扫描版进行文字可识别的需求&#xff0c;这里介绍一款工具挺好用的 这是一款开源的OCR工具 github地址 https://github.com/hiroi-sora/Umi-OCR 主要功能及特点 免费&#xff1a;本项目所有代码开源&#xff0c;完全免费。方便&#…

二叉树的广度优先遍历和题目

二叉树广度优先遍历利用队列 。 typedef char BTDataType; typedef struct BinaryTreeNode {BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right; }BTNode; typedef BTNode* QDataType;// 链式结构&#xff1a;表示队列 typedef struct QueueNode {…

如何使用宝塔面板安装中间件

如何快速安装中间件&#xff0c;宝塔镇河妖非常简单。 使用 SSH 连接工具&#xff0c;如堡塔SSH终端连接到您的 Linux 服务器后&#xff0c;挂载磁盘&#xff0c;根据系统执行相应命令开始安装&#xff08;大约2分钟完成面板安装&#xff09;&#xff1a; Centos安装脚本 yum…

视频去重剪辑软件哪个好用?这3款工具值得一试!

很多人都喜欢在视频平台上分享自己的剪辑作品。随着视频数量的激增&#xff0c;视频去重成为了一个不可忽视的问题。无论是为了遵守版权法规&#xff0c;还是为了提升内容的独特性和吸引力&#xff0c;选择一款好用的视频去重剪辑软件都显得尤为重要。本文将推荐几款优秀的视频…

YOLOv8 OBB win10+ visual 2022移植部署

前言 想做一个目标旋转角度检测的工程&#xff0c;但是网上多少python的&#xff0c;或者linux的。在win10 visual 2022移植部署&#xff0c;记录一下。 参考 这篇文章没有C win10 环境下的部署教程&#xff0c;我相对于是对此做了补充。 1、下载工程 https://github.com/sh…

21章 规则集和映射

1.同20章 线性表、栈、队列和优先队列的第10题。 2.同20章 线性表、栈、队列和优先队列的第1题。 3.修改程序清单21-7中的程序。如果关键字在注释或者字符串中&#xff0c;则不进行统计。将Java文件名从命令行传递。 import java.io.*; import java.util.Arrays; import jav…

DeDeCMS靶场漏洞复现

打开靶场地址 姿势一&#xff1a;通过文件管理器上传webshell 1.登录后台 dedecms默认的后台登录地址为/dede 2.在附加管理里的文件式管理器中有文件上传 3.上传木马文件 4.访问木马文件 并连接 姿势二&#xff1a;修改模板文件获取webshell 1.点击模板里面的默认模板管理 …

SHL笔试测评系统题库考什么?如何通过综合测评|附性格测试104道

嘿&#xff0c;各位求职小伙伴们&#xff01;我是职小豚&#xff0c;今天就来带大家深入了解神秘又充满挑战的 SHL 笔试测评系统。 一、SHL 人才测评系统介绍 SHL 呀&#xff0c;那可是人才测评领域的超级大明星&#xff01;就像一个智慧的魔法师&#xff0c;用各种神奇的题目…

c++11标准(2)右值引用的衍生产物

欢迎来到博主的专栏&#xff1a;c杂谈 博主ID&#xff1a;代码小豪 文章目录 万能引用模板右值引用到底是左值还是右值完美转发 万能引用模板 当c11推出右值引用之后&#xff0c;我们所写的模板函数可以写成这样&#xff1a; template<class T> T&& Universal_…

[000-01-008].第08节:Sentinel 环境搭建

1.Sentinel的构成&#xff1a; 核心库-后台默认的端口是8719控制台-前台默认的是8080端口 2.2.搭建Sentinel环境&#xff1a; a.下载Sentinel&#xff1a; 1.sentinel官方提供了UI控制台&#xff0c;方便我们对系统做限流设置。可以在GitHub下载 b.下载后运行Sentinel&#…

【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 <…

【C++】多态的认识和理解

个人主页 文章目录 ⭐一、多态的概念&#x1f384;二、多态的定义及实现1.多态的构成2.实现多态的条件3.虚函数的概念4.虚函数的重写和覆盖5.析构函数的重写6.协变7.override和 final关键字8.重载、重写/覆盖、隐藏这三者的区别 &#x1f3e0;三、纯虚函数和抽象类的关系&#…