[图解]cv2.HoughLines() 和 cv2.HoughLinesP()原理和代码

2024-05-05 14:32

本文主要是介绍[图解]cv2.HoughLines() 和 cv2.HoughLinesP()原理和代码,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

理论

如上图,左边a,b固定可以确定一条直线,线是(x_i,y_j) 组成的集合.

下面从xy空间变化到ab空间,此时给定一个绿点(x_i,y_j)可以确定一条绿色的线,给定一个蓝点 

(x_i,y_j)可以确定一条蓝色的线,绿线和蓝线相交的点就是左边确定红线的参数a和b.此时xy空间里红线上的其他点,变换到ab空间必过蓝绿线相交点.

下面把ab换成rho和theta.

rho = x cos (theta) + y sin (theta)  这里面rho 是原点到直线的垂直距离,和 theta是由这条垂直线和逆时针测量的水平轴形成的角度(该方向因您表示坐标系的方式而异。OpenCV 中使用了这种表示)。检查下面的图像:

所以如果线在原点以下通过,它会有一个正的 rho 并且角度小于 180。如果它在原点之上,而不是取大于 180 的角度,而是取小于 180 的角度,并且 rho被取为阴性。任何垂直线将具有 0 度,水平线将具有 90 度。

现在让我们看看霍夫变换如何处理线条。任何线都可以用这两个术语表示,(rho, theta). 因此,首先创建一个二维数组或累加器(以保存两个参数的值),并且最初设置为 0。让行表示(rho) 和列表示 (theta). 数组的大小取决于您需要的精度。假设您希望角度精度为 1 度,您将需要 180 列。对于(rho),可能的最大距离是图像的对角线长度。所以取一像素精度,行数可以是图像的对角线长度。

考虑一个 100x100 的图像,取一个点。你知道它的 (x,y) 值。现在在线方程中,输入值(theta = 0,1,2,....,180) 并检查 (rho)你得到。对于每(rho,theta) 对,您在相应的累加器中将值增加 1 ,所以现在在累加器中,单元格 (50,90) = 1 以及其他一些单元格。

现在取直线上的第二个点。执行与上述相同的操作。增加与您获得的单元格相对应的值。这样,最后,(rho,theta) 单元格累积数越多,说明过这条线的点越多,当大于某一阈值的时候,我们说这是我们要找的一条直线.

OpenCV 中的霍夫变换

上面解释的所有内容都封装在 OpenCV 函数cv2.HoughLines() 中。它只是返回一组(rho, theta)列表。rho以像素为单位测量,并且theta以弧度为单位。第一个参数,输入图像应该是一个二值图像,所以在应用霍夫变换之前应用阈值或使用精明的边缘检测。第二个和第三个参数分别是rho 和theta的精度。第四个参数是阈值,这意味着它应该被视为一条线的最低投票数。请记住,投票数取决于线上的点数。所以它可能代表了应该检测的最小线长。

Python:
cv.HoughLines(image, rho, theta, threshold[, lines[, srn[, stn[, min_theta[, max_theta]]]]]) ->lines

例子代码:

import cv2
import numpy as npimg = cv2.imread('../data/sudoku.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,50,150,apertureSize = 3)lines = cv2.HoughLines(edges,1,np.pi/180,200)
for line in lines:rho,theta = line[0]a = np.cos(theta)b = np.sin(theta)x0 = a*rhoy0 = b*rhox1 = int(x0 + 1000*(-b))y1 = int(y0 + 1000*(a))x2 = int(x0 - 1000*(-b))y2 = int(y0 - 1000*(a))cv2.line(img,(x1,y1),(x2,y2),(0,0,255),2)cv2.imwrite('houghlines3.jpg',img)

image

 概率霍夫变换

在霍夫变换中,您可以看到,即使对于具有两个参数的行,也需要进行大量计算。概率霍夫变换是我们看到的霍夫变换的优化。它没有考虑所有要点。相反,它只需要一个足以进行线检测的随机点子集。只是我们必须降低阈值。请参见下图,它比较了霍夫空间中的霍夫变换和概率霍夫变换。

图片

OpenCV 实现基于 Matas, J. 和 Galambos, C. 和 Kittler, JV [55]使用渐进式概率霍夫变换对线条进行鲁棒检测。使用的函数是cv2.HoughLinesP()。它有两个新参数。

  • minLineLength - 线的最小长度。比这短的线段被拒绝。
  • maxLineGap - 线段之间的最大允许间隙,将它们视为一条线。

好处是,它直接返回线的两个端点。在前面的例子中,你只得到线的参数,你必须找到所有的点。在这里,一切都是直接而简单的。

示例代码:

import cv2
import numpy as npimg = cv2.imread('../data/sudoku.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,50,150,apertureSize = 3)
lines = cv2.HoughLinesP(edges,1,np.pi/180,100,minLineLength=100,maxLineGap=10)
for line in lines:x1,y1,x2,y2 = line[0]cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2)cv2.imwrite('houghlines5.jpg',img)

image

参考英文链接:

https://vovkos.github.io/doxyrest-showcase/opencv/sphinxdoc/page_tutorial_py_houghlines.html

这篇关于[图解]cv2.HoughLines() 和 cv2.HoughLinesP()原理和代码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/961940

相关文章

Java的栈与队列实现代码解析

《Java的栈与队列实现代码解析》栈是常见的线性数据结构,栈的特点是以先进后出的形式,后进先出,先进后出,分为栈底和栈顶,栈应用于内存的分配,表达式求值,存储临时的数据和方法的调用等,本文给大家介绍J... 目录栈的概念(Stack)栈的实现代码队列(Queue)模拟实现队列(双链表实现)循环队列(循环数组

使用Java将DOCX文档解析为Markdown文档的代码实现

《使用Java将DOCX文档解析为Markdown文档的代码实现》在现代文档处理中,Markdown(MD)因其简洁的语法和良好的可读性,逐渐成为开发者、技术写作者和内容创作者的首选格式,然而,许多文... 目录引言1. 工具和库介绍2. 安装依赖库3. 使用Apache POI解析DOCX文档4. 将解析

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

Spring Boot循环依赖原理、解决方案与最佳实践(全解析)

《SpringBoot循环依赖原理、解决方案与最佳实践(全解析)》循环依赖指两个或多个Bean相互直接或间接引用,形成闭环依赖关系,:本文主要介绍SpringBoot循环依赖原理、解决方案与最... 目录一、循环依赖的本质与危害1.1 什么是循环依赖?1.2 核心危害二、Spring的三级缓存机制2.1 三

C#中async await异步关键字用法和异步的底层原理全解析

《C#中asyncawait异步关键字用法和异步的底层原理全解析》:本文主要介绍C#中asyncawait异步关键字用法和异步的底层原理全解析,本文给大家介绍的非常详细,对大家的学习或工作具有一... 目录C#异步编程一、异步编程基础二、异步方法的工作原理三、代码示例四、编译后的底层实现五、总结C#异步编程

使用Python实现全能手机虚拟键盘的示例代码

《使用Python实现全能手机虚拟键盘的示例代码》在数字化办公时代,你是否遇到过这样的场景:会议室投影电脑突然键盘失灵、躺在沙发上想远程控制书房电脑、或者需要给长辈远程协助操作?今天我要分享的Pyth... 目录一、项目概述:不止于键盘的远程控制方案1.1 创新价值1.2 技术栈全景二、需求实现步骤一、需求

Java中Date、LocalDate、LocalDateTime、LocalTime、时间戳之间的相互转换代码

《Java中Date、LocalDate、LocalDateTime、LocalTime、时间戳之间的相互转换代码》:本文主要介绍Java中日期时间转换的多种方法,包括将Date转换为LocalD... 目录一、Date转LocalDateTime二、Date转LocalDate三、LocalDateTim

Go 语言中的select语句详解及工作原理

《Go语言中的select语句详解及工作原理》在Go语言中,select语句是用于处理多个通道(channel)操作的一种控制结构,它类似于switch语句,本文给大家介绍Go语言中的select语... 目录Go 语言中的 select 是做什么的基本功能语法工作原理示例示例 1:监听多个通道示例 2:带

鸿蒙中@State的原理使用详解(HarmonyOS 5)

《鸿蒙中@State的原理使用详解(HarmonyOS5)》@State是HarmonyOSArkTS框架中用于管理组件状态的核心装饰器,其核心作用是实现数据驱动UI的响应式编程模式,本文给大家介绍... 目录一、@State在鸿蒙中是做什么的?二、@Spythontate的基本原理1. 依赖关系的收集2.

jupyter代码块没有运行图标的解决方案

《jupyter代码块没有运行图标的解决方案》:本文主要介绍jupyter代码块没有运行图标的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录jupyter代码块没有运行图标的解决1.找到Jupyter notebook的系统配置文件2.这时候一般会搜索到