Opencv-C++笔记 (14) : 霍夫变换(直线、圆)

news2024/11/15 14:06:34

文章目录

  • 一、霍夫变换-直线
    • 1.1霍夫变换-直线 原理详解
  • 二、霍夫圆检测

一、霍夫变换-直线

Hough Line Transform用来做直线检测
前提条件 – 边缘检测已经完成

1、平面空间(x,y)到极坐标空间转换;
在这里插入图片描述

2、对极坐标进行变换,转化为θ与R的关系
在这里插入图片描述

1.1霍夫变换-直线 原理详解

对于任意一条直线上的所有点来说,变换到极坐标中,从[0~360]空间,可以得到r的大小,属于同一条直线上点在极坐标空 ( r , θ ) (r, \theta)(r,θ) 必然在一个点上有最强的信号出现,根据此反算到平面坐标中就可以得到直线上各点的像素坐标。从而得到直线。

标准的霍夫变换 cv::HoughLines 从平面坐标转换到霍夫空间,最终输出是 ( r , θ ) (r, \theta)(r,θ) 表示极坐标空间

void HoughLines(
InputArray image,     输入图像,必须8-bit的灰度图像
OutputArray lines,    输出的极坐标来表示直线
double rho,        极坐标素扫描步长
double theta,       极坐标角度步长,一般取值CV_PI/180
int threshold,       阈值,多少交点的极坐标点才被看成是直线
double srn = 0,       是否应用多尺度的霍夫变换,默认0表示经典霍夫变换
double stn = 0,       是否应用多尺度的霍夫变换,默认0表示经典霍夫变换 
double min_theta = 0,   表示角度扫描范围 0 ~180之间, 默认即可
double max_theta = CV_PI
);

霍夫变换直线概率 cv::HoughLinesP最终输出是直线的两个点 ( x 0 , y 0 , x 1 , y 1 )

void HoughLinesP(
InputArray image,      输入图像,必须8-bit的灰度图像
OutputArray lines,     输出的极坐标来表示直线
double rho,         极坐标像素扫描步长
double theta,        极坐标角度步长,一般取值CV_PI/180
int threshold,        阈值,多少交点的极坐标点才被看成是直线
double minLineLength = 0,  最小直线长度
double maxLineGap = 0 );  最大间隔
//头文件 quick_opencv.h:声明类与公共函数
#pragma once
#include <opencv2\opencv.hpp>
using namespace cv;

class QuickDemo {
public:
	...
	void hough_Demo(Mat& image1);
	void laplance_Demo(Mat& image1);
	void canny_Demo(Mat& image1);
};
//主函数调用该类的公共成员函数
#include <opencv2\opencv.hpp>
#include <quick_opencv.h>
#include <iostream>
using namespace cv;


int main(int argc, char** argv) {
	Mat src = imread("D:\\Desktop\\jianbian.png");
	if (src.empty()) {
		printf("Could not load images...\n");
		return -1;
	}
	QuickDemo qk;
	qk.hough_Demo(src1);
	qk.hough_Demo(src1);
	qk.canny_Demo(src1);
	waitKey(0);
	destroyAllWindows();
	return 0;
}
void QuickDemo::hough_Demo(Mat& image) {
	Mat image_line = image.clone();
	
	// 霍夫直线检测
	Mat gau_dst, gray_dst, grad_dst;
	GaussianBlur(image_line, gau_dst, Size(3, 3), 10);
	cvtColor(gau_dst, gray_dst, COLOR_BGR2GRAY);

	vector<Vec4f> plines;
	Canny(gray_dst, gray_dst, 100, 200);
	imshow("Canny", gray_dst);

	HoughLinesP(gray_dst, plines, 5, CV_PI/180, 10, 0, 10);// 斜线检测调整maxlineGap
	cout << "线条个数:" << plines.size() << endl;
	for (int i = 0; i < plines.size(); i++) {
		Vec4f hline = plines[i];
		line(image_line, Point(hline[0], hline[1]), Point(hline[2], hline[3]), Scalar(0, 0, 255), 1, 8, 0);
	}
	imshow("HoughLinesP", image_line);


	// 霍夫圆检测
	Mat median_dst, gray_median_dst;
	vector<Vec3f> pcircles;
	medianBlur(image, median_dst, 3);
	cvtColor(median_dst, gray_median_dst, COLOR_BGR2GRAY);
	HoughCircles(gray_median_dst, pcircles, HOUGH_GRADIENT, 1, 10, 100, 30, 5, 100);
	cout << "圆形个数:" << pcircles.size() << endl;

	for (int i = 0; i < pcircles.size(); i++) {
		Vec3f cc = pcircles[i];
		circle(image, Point(cc[0], cc[1]), cc[2], Scalar(255, 0, 0), 2, 8, 0);
		circle(image, Point(cc[0], cc[1]), 2, Scalar(255, 0, 0), 2, 8, 0); // 标注圆形
	}
	imshow("circle", image);
}

在这里插入图片描述

二、霍夫圆检测

算法详情见:霍夫圆检测 官方给出了好的示例。
对直线来说,一条直线能由极径极角 ( r , θ ) (r,θ)(r,θ) 表示,而对于圆来说,我们需要三个参数:圆心( a , b ) (a,b)(a,b),半径 r 。
笛卡尔坐标系中圆的方程为:
在这里插入图片描述
这就意味着每一组(a,b,r)代表一个通过点(x0,y0)的圆。

对于一个给定点(x0,y0),我们可以在三维直角坐标系中,绘出所有通过它的圆。最终我们将得到一条三维的曲线。
由于霍夫线变换圆检测对噪声比较敏感,所以首先要对图像做中值滤波,而且需要更多的检测计算消耗。OpenCV 霍夫圆变换对标准霍夫圆变换做了运算上的优化。它采用的是 “霍夫梯度法”。

基于效率考虑,Opencv中实现的霍夫变换圆检测是基于图像梯度的实现,分为两步:

  1. 检测边缘,发现可能的圆心
  2. 基于第一步的基础上从候选圆心开始计算最佳半径大小

霍夫梯度法的原理

估计圆心

1、把原图做一次 Canny 边缘检测,得到边缘检测的二值图。

对原始图像执行一次 Sobel 算子,计算出所有像素的邻域梯度值。

初始化圆心空间 N(a,b),令所有的 N(a,b)=0。

遍历 Canny 边缘二值图中的所有非零像素点,沿着梯度方向 ( 切线的垂直方向 )画线,将线段经过的所有累加器中的点 (a,b) 的 N(a,b)+=1。

void HoughCircles(
InputArray image,      输入图像 ,必须是8位的单通道灰度图像
OutputArray circles,    输出结果,发现的圆信息
int method,         HOUGH_GRADIENT
double dp,         dp = 1 累加器图像的反比分辨率
double minDist=src_gray.rows/8, 检测到圆心之间的最小距离,否则认为是同心圆-
double param1 = 100,    canny edge detection low threshold
double param2 = 100,   中心点累加器阈值 – 候选圆心
int minRadius = 0,      能检测到的最小圆半径, 默认为0
int maxRadius = 0      能检测到的最大圆半径, 默认为0
);
参数: 
第一个参数,InputArray类型的image,输入图像,即源图像,需为8位的灰度单通道图像。
第二个参数,InputArray类型的circles,经过调用HoughCircles函数后此参数存储了检测到的圆的输出矢量,每个矢量由包含了3个元素的浮点矢量(x, y, radius)表示。
第三个参数,int类型的method,即使用的检测方法,目前OpenCV中就霍夫梯度法一种可以使用,它的标识符为CV_HOUGH_GRADIENT,在此参数处填这个标识符即可。
第四个参数,double类型的dp,用来检测圆心的累加器图像的分辨率于输入图像之比的倒数,且此参数允许创建一个比输入图像分辨率低的累加器。上述文字不好理解的话,来看例子吧。例如,如果dp= 1时,累加器和输入图像具有相同的分辨率。如果dp=2,累加器便有输入图像一半那么大的宽度和高度。
第五个参数,double类型的minDist,为霍夫变换检测到的圆的圆心之间的最小距离,即让我们的算法能明显区分的两个不同圆之间的最小距离。这个参数如果太小的话,多个相邻的圆可能被错误地检测成了一个重合的圆。反之,这个参数设置太大的话,某些圆就不能被检测出来了。
第六个参数,double类型的param1,有默认值100。它是第三个参数method设置的检测方法的对应的参数。对当前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,它表示传递给canny边缘检测算子的高阈值,而低阈值为高阈值的一半。
第七个参数,double类型的param2,也有默认值100。它是第三个参数method设置的检测方法的对应的参数。对当前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,它表示在检测阶段圆心的累加器阈值。它越小的话,就可以检测到更多根本不存在的圆,而它越大的话,能通过检测的圆就更加接近完美的圆形了。
第八个参数,int类型的minRadius,有默认值0,表示圆半径的最小值。
第九个参数,int类型的maxRadius,也有默认值0,表示圆半径的最大值。

在这里插入图片描述

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

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

相关文章

作为软件工程师成为全职创作者:有争议的建议

我以写作为生&#xff0c;全职。我的通讯是Substack上排名第一的付费技术通讯&#xff0c;我是一个全职的创作者。 随着远程工作在科技领域变得越来越普遍&#xff0c;我收到越来越多的人发来同样的问题&#xff1a;他们怎么能像我一样&#xff1f; 尽管我被认为是一个成功的…

Linux 匿名页的生命周期

目录 匿名页的生成 匿名页生成时的状态 do_anonymous_page缺页中断源码 从匿名页加入Inactive lru引出 一个非常重要内核patch 匿名页何时回收 本文以Linux5.9源码讲述 匿名页的生成 用户空间malloc/mmap(非映射文件时&#xff09;来分配内存&#xff0c;在内核空间发生…

NodeJS原型链污染ctfshow_nodejs

文章目录 NodeJS原型链污染&ctfshow_nodejs前言0x01.原型与原型链0x02.prototype和__proto__分别是什么&#xff1f;0x03.原型链继承不同对象的原型链* 0x04.原型链污染原理0x05.merge()导致原型链污染0x06.ejs模板引擎RCEejs模板引擎另一处rce 0x07.jade模板引擎RCE【ctfs…

HCIP——STP

STP 一、STP概述二、二层环路带来的问题1、广播风暴问题2、MAC地址漂移问题3、多帧复制 三、802.1D生成树STP的BPDU1、配置BPDU2、RPC3、COST4、配置BPDU的工作过程5、TCN BPDU6、TCN BPDU的工作原理 四、STP的角色五、STP角色选举六、STP的接口状态七、接口状态的迁移八、STP的…

web集群学习:源码安装nginx配置启动服务脚本

1、源码安装nginx&#xff0c;并提供服务脚本。 1、源码安装会有一些软件依赖 &#xff08;1&#xff09;检查并安装 Nginx 基础依赖包 pcre-devel 、openssl-devel # rpm -qa | egrep pcre-devel | openssl-devel&#xff08;2&#xff09;安装 Nginx 所需的 pcre 库 正则支…

STM32入门学习之定时器中断

1.STM32的通用定时器是可编程预分频驱动的16位自动装载计数器。 STM32 的通用定时器可以被用于&#xff1a;测量输入信号的脉冲长度 ( 输入捕获 ) 或者产生输出波 形 ( 输出比较和 PWM) 等。 使用定时器预分频器和 RCC 时钟控制器预分频器&#xff0c;脉冲长度和波形 周…

分治法、回溯法与动态规划

算法思想比较 回溯法&#xff1a;有“通用解题法”之称&#xff0c;用它可以系统地搜索问题的所有解。回溯法是按照深度优先搜索(DFS)的策略&#xff0c;从根结点出发深度探索解空间树分治法&#xff1a;将一个难以直接解决的大问题&#xff0c;分割成一些规模较小的相同问题&…

PCIE链路信息

目录 简介&#xff1a; 目的&#xff1a; 详情&#xff1a; 简介&#xff1a; PCIe有很多寄存器&#xff0c;也有很多控制&#xff0c;包括链路状态信息&#xff0c;上一节我们讲到了PCie的链路训练&#xff0c;这节文章将继续学习PCIe相关知识。 目的&#xff1a; 从设计…

30岁程序员第一次失败的餐饮创业经历

背景介绍 我什么都比较晚&#xff0c;我比大多数人晚了两年毕业&#xff0c;事业稳定也比别人晚。直到去年&#xff0c;我才跳槽到一家外企外包工作获得相对满意的薪资。但即使如此&#xff0c;与更有经验的人相比&#xff0c;我仍然有很大的差距&#xff0c;自己也尚未积累足…

kubernetes集群日志管理系统部署方案

安装前请下载各种所需yaml文件 1、安装 elasticsearch 组件 1.1 创建名称空间 #elasticsearch、fluentd、kibana都会安装到此空间下 kubectl apply -f kube-logging.yaml1.2 查看 kube-logging 名称空间是否创建成功 kubectl get namespaces | grep kube-logging[rootk8s-…

一分钟学会JS获取当前年近五年的年份

先看效果图 上代码&#xff1a; 1、HTML <div><el-date-pickerv-model"queryYearXmgk.startYear"format"yyyy"value-format"yyyy"type"year"placeholder"开始"clearable:picker-options"pickerStartAuditYe…

EventBus 开源库学习(三)

源码细节阅读 上一节根据EventBus的使用流程把实现源码大体梳理了一遍&#xff0c;因为精力有限&#xff0c;所以看源码都是根据实现过程把基本流程看下&#xff0c;中间实现细节先忽略&#xff0c;否则越看越深不容易把握大体思路&#xff0c;这节把一些细节的部分再看看。 …

flutter开发实战-flutter_spinkit实现多种风格进度指示器

flutter开发实战-flutter_spinkit实现多种风格进度指示器 最近开发过程中flutter_spinkit&#xff0c;这个拥有多种种风格加载指示器 一、flutter_spinkit 引入flutter_spinkit # 多种风格的模糊进度指示器flutter_spinkit: ^5.1.0效果示例 const spinkit SpinKitRotatingC…

常见历史漏洞之Thinkphp

常见历史漏洞之Thinkphp 一、介绍二、Thinkphp历史漏洞三、Thinkphp特征发现四、批量漏洞检测五、漏洞总结六、5.0.23版本案例演示 一、介绍 Thinkphp是一种开源框架。是一个由国人开发的支持windows/Unix/Linux等服务器环境的轻量级PHP开发框架。很多cms就是基于thinkphp二次开…

动态规划01: 斐波那契数列模型

第 N 个泰波那契数&#xff08;easy&#xff09; 题目链接: 1137. 第 N 个泰波那契数 题目描述: 泰波那契序列 Tn 定义如下&#xff1a; T0 0, T1 1, T2 1, 且在 n > 0 的条件下 Tn3 Tn Tn1 Tn2 给你整数 n&#xff0c;请返回第 n 个泰波那契数 Tn 的值。 示例 1&…

Vue表格导出Excel数据,自定义表头,使用xlsx-style修饰

继续上篇文章封装导出方法: 效果图&#xff1a; 1、安装xlsx-style依赖&#xff1a; yarn add xlsx-style 2、安装node-polyfill-webpack-plugin依赖&#xff1a; yarn add node-polyfill-webpack-plugin -D 解决报错&#xff1a;jszip is not a constructor 3、配置vue.…

Cilium系列-13-启用XDP加速及Cilium性能调优总结

系列文章 Cilium 系列文章 前言 将 Kubernetes 的 CNI 从其他组件切换为 Cilium, 已经可以有效地提升网络的性能. 但是通过对 Cilium 不同模式的切换/功能的启用, 可以进一步提升 Cilium 的网络性能. 具体调优项包括不限于: 启用本地路由(Native Routing)完全替换 KubeProx…

广西茶叶元宇宙 武隆以茶为媒 推动茶文旅产业融合发展

8月4日&#xff0c;重庆市武隆区启动为期3天的“武隆首届玩茶荟”。本次活动以“中国最美玩茶地——武隆”为主题&#xff0c;吸引众多国内知名专家、茶企和茶馆相关负责人&#xff0c;共同探索武隆茶文旅融合发展新路径和新业态。 广西茶叶元宇宙&#xff1a;广西茶叶元宇宙 …

GD32F103的EXTI中断和EXTI事件

GD32F103的EXTI可以产生中断&#xff0c;也产生事件信号。 GD32F03的EXTI触发源: 1、I/O管脚的16根线&#xff1b; 2、内部模块的4根线(包括LVD、RTC闹钟、USB唤醒、以太网唤醒)。 通过配置GPIO模块的AFIO_EXTISSx寄存器&#xff0c;所有的GPIO管脚都可以被选作EXTI的触发源…

近阶段的一些思考

文章目录 近阶段&#xff08;大约一个多月&#xff09;一直在投入某个开发项目中&#xff0c;没有机会静下来思考一番。对于自己而言&#xff0c;忙碌是一种不好的现象&#xff0c;不应该认为是一件理所当然的事情&#xff0c;应该是一种危机的存在&#xff0c;这种状态持续两周…