目标

在这一章当中,将学习

  • 了解霍夫变换的概念
  • 使用它来检测图像中的线条
  • 函数:cv2.HoughLines()cv2.HoughLinesP()

理论

如果可以用数学形式表示形状,则霍夫变换是检测任何形状的一种比较流行的技术。即使形状有些破损或变形,也可以检测出形状。本文将讲解如何将它何作用于一条线。

一条线可以表示为y=mx+cy = mx+cy=mx+c或以参数形式表示为ρ=xcosθ+ysinθρ = xcosθ+ysinθρ=xcosθ+ysinθ $,其中ρ是从原点到该线的垂直距离,而θ是由该垂直线和水平轴形成的角度以逆时针方向测量(该方向随如何表示坐标系而变化。此表示形式在OpenCV中使用)。如下图所示:


因此,如果线在原点下方通过,则它将具有正的ρ且角度小于180。如果线在原点上方,则将角度取为小于180,而不是大于180的角度。ρ取负值。任何垂直线将具有0度,水平线将具有90度

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

考虑一个100x100的图像,中间有一条水平线。取直线的第一点。此时知道它的(x,y)值。现在在线性方程式中,将值θ= 0,1,2,… 180放进去,然后检查得到ρ。对于每对( ρ, θ ),在累加器中对应的(ρ,θ )单元格将值增加1。假设此点是(50,90),则该点的值加1,其它点依此类推。

现在,对行的第二个点。执行与上述相同的操作。递增( ρ , θ ) 对应的单元格中的值。这次,单元格(50,90)=2。实际上,正在对( ρ, θ )值进行投票。对线路上的每个点都继续执行此过程。在每个点上,单元格(50,90)都会增加或投票,而其他单元格可能会或可能不会投票。这样一来,**最后,单元格(50,90)的投票数将最高。**因此,如果在累加器中搜索最大票数,则将获得(50,90)值,该值表示该图像中的一条线与原点的距离为50,角度为90度

这就是霍夫变换对线条的工作方式,原理很简单。输入的图片中有两条粗直线,经过霍夫变换后的结果得到accumaltor矩阵,右图就是把accumaltor矩阵画出来,越亮值越大,越黑值越小。在右图中,有两个很明显的亮点, 这两个亮点分别代表两条不同参数的直线,与输入的图片(左图)吻合。然后读取矩阵的两个最大值就可以得出这两条线距画面中心距离以及角度。

OpenCV中的霍夫曼变换

上面说明的所有内容都封装在OpenCV函数cv2.HoughLines()中。

lines=cv2.HoughLines(image,rho,theta,threshold)
返回的lines:表示的是一个具有两个或三个元素的数组,math:(rho,theta), 其中ρ 以像素为单位,θ以弧度为单位
第一个参数,输入图像应该是二进制图像,因此在应用霍夫变换之前,请应用阈值或使用Canny边缘检测
第二和第三参数分别是ρθ精度
第四个参数是阈值,这意味着应该将其视为行的最低投票。请记住,票数取决于线上的点数。因此,它表示应检测到的最小线长。

import cv2
import numpy as npimg = cv2.imread('sudo.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150, apertureSize=3)lines = cv2.HoughLines(edges, 1, np.pi/180, 100)  # 最后一个数是阈值控制,不同的值效果不一样
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))  # 以(x0, y0)为起点,将线段延长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.imshow('houglines', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

OpenCV HoughLines 中,它是定义线条的端点,以便它们在绘制线条时到达(并经过)图像的侧面。您使用的霍夫变换仅返回线与原始线的角度和距离。所以额外的计算是从原点垂直于这条线找到一条线的交点,这样它就可以识别这条线上的某个点。但它不知道这条线应该有多长。所以它沿着这条线从那个点延伸了这条线。由于它知道直线的角度和直线上的一个点,它只提供两个端点到直线上给定点的距离。如果您的图像尺寸大于约 21000 像素,那么如果您希望线条到达图像的两侧,则可能需要增加 1000 值。减号 (-b) 出现如下:
从原点到垂直于直线的方向由它的斜率给出b/a = sin(theta)/cos(theta)=tan(theta)。请参阅https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_houghlines/py_houghlines.html 上的图表。但是线本身的方向与该方向成 90 度,其角度由 给出-1/tan(theta) = -cos(theta)/sin(theta) = -a/b or a/-b。即它的斜率是 (a/-b)=(y-yo)/(x-xo)=delY/delX。请参阅https://byjus.com/maths/slope-of-line/。因此,要获得两个端点,您可以从 xo, yo 给定的任意点开始,然后沿线向任一方向移动,这样端点 X 分量为 xo ± 1000 delX = xo ± 1000 cos(perp_angle) = xo ± 1000
(-b) 终点 Y 分量是 yo ± 1000 delY = yo ± 1000sin(perp_angle) = yo ± 1000*a。其中 perp_angle 是沿实际线的方向。

分享

检查下面的结果

概率霍夫变换

在霍夫变换中,可以看到,即使对于带有两个参数的行,也需要大量计算。概率霍夫变换是霍夫变换的优化。它没有考虑所有要点。取而代之的是,它仅采用随机的点子集,足以进行直线检测。只是必须降低阈值。

OpenCV的实现基于Matas,J.和Galambos,C.和Kittler, J.V.使用渐进概率霍夫变换对行进行的稳健检测 。使用的函数是cv2.HoughLinesP()。它有两个新的论点。

lines = cv.HoughLines( image, rho, theta, threshold[, lines[, srn[, stn[, min_theta[, max_theta]]]]] )

  • minLineLength - 最小行长。小于此长度的线段将被拒绝。如果有超过阈值个数的像素点构成了一条直线,但是这条直线很短,那么就不会接受该直线作为判断结果,而认为这条直线仅仅是图像中的若干个像素点恰好随机构成了一种算法上的直线关系而已,实际上原图中并不存在这条直线。
  • maxLineGap - 线段之间允许将它们视为一条线的最大间隙。如果有超过阈值个数的像素点构成了一条直线,但是这组像素点之间的距离都很远,就不会接受该直线作为判断结果,而认为这条直线仅仅是图像中的若干个像素点恰好随机构成了一种算法上的直线关系而已,实际上原始图像中并不存在这条直线。

最好的是,它直接返回行的两个端点。在以前的情况下,仅获得线的参数,并且必须找到所有点。在这里,一切都是直接而简单的。

参见下图,比较了霍夫空间中的霍夫变换和概率霍夫变换。

实现

# p 霍夫变换
import cv2
import numpy as npimg = cv2.imread('sudo.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.imshow('houghlinep', img)
cv2.waitKey()
cv2.destroyAllWindows()

看到如下结果:

可以看到在这张图上,cv2.HoughLines效果比cv2.HoughLinesP要好,但是不一定一直好,比如下面一张

# compare
# p 霍夫变换
import cv2
import numpy as np
from matplotlib import pyplot as pltimg = cv2.imread('building.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 200, 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)img1= cv2.imread('building.png')
gray1= cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
edges1 = cv2.Canny(gray1, 50, 150, apertureSize=3)
lines1 = cv2.HoughLines(edges1, 1, np.pi/180, 200)
for line in lines1: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(img1, (x1, y1), (x2, y2), (0,0,255), 2)plt.subplot(121)
plt.imshow(img1_rgb)
plt.title('HoughLines')
plt.xticks([])
plt.yticks([])img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img1_rgb = cv2.cvtColor(img1, cv2.COLOR_BGR2RGB)
plt.subplot(122)
plt.imshow(img_rgb)
plt.title('HoughLinesP')
plt.xticks([])
plt.yticks([])plt.show()

实际上,主要是HoughLines是一条直线而非线段,而那些小树叶又容易被误检测成图片,所以才会画的面目。

附加资源

  • https://docs.opencv.org/4.1.2/d6/d10/tutorial_py_houghlines.html

  • Hough Transform on Wikipedia

  • https://docs.opencv.org/4.1.2/dd/d1a/group__imgproc__feature.html#ga46b4e588934f6c8dfd509cc6e0e4545a

  • https://docs.opencv.org/4.1.2/dd/d1a/group__imgproc__feature.html#ga8618180a5948286384e3b7ca02f6feeb

  • https://blog.csdn.net/ftimes/article/details/106816736

  • https://stackoverflow.com/questions/62585845/why-add-and-subtract-1000-for-hough-line-transformation

  • https://www.cnblogs.com/kk17/p/9693132.html

opencv26:霍夫直线变换相关推荐

  1. OpenCV中霍夫直线变换

    OpenCV中霍夫直线变换 首先要知道,一条直线的通用表达式为y=ax+b\color{#F00}y=ax+by=ax+b,a为直线的斜率,b为直线的截距,知道这两个参数可以唯一确定一条直线.通常我们 ...

  2. 使用霍夫直线变换做直线检测

    霍夫直线变换 cv2.HoughLines(image, rho, theta, threshold, lines, sen, stn, min_theta, max_theta) cv2.Hough ...

  3. python 霍夫直线变换_OpenCV-Python 霍夫线变换 | 三十二

    目标 在这一章当中, 我们将了解霍夫变换的概念. 我们将看到如何使用它来检测图像中的线条. 我们将看到以下函数:cv.HoughLines(),cv.HoughLinesP() 理论 如果可以用数学形 ...

  4. python 霍夫直线变换_霍夫线变换

    目录:一.引入极坐标 二.霍夫线变换实现原理 三.图像中的霍夫线变换 四.概率霍夫变换 五.Python 例子 六.参考 Hough线变换是一种用于检测直线的变换.它最大的优点是,即使是虚线(dash ...

  5. halcon hough_lines 霍夫直线变换

    目录 hough_lines(算子) 描述 参数 hough_lines(算子) hough_lines - 借助Hough变换检测边缘图像中的线条并将其返回到HNF中. hough_lines(Re ...

  6. OpenCV标准霍夫直线检测详解

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 本文转载自:OpenCV学堂 霍夫直线检测 对于图像来说可以从笛卡 ...

  7. 霍夫圈变换——Hough circle

    草鸡详细的hough.circle介绍 一个电脑编程小白的自我成长之路(&_&)嘿嘿. CvSeq* cvHoughCircles( CvArr* image, void* circl ...

  8. 【OpenCV-Python】——边缘和轮廓Laplacian/Sobel/Canny边缘检测查找/绘制轮廓及轮廓特征霍夫直线/圆变换

    目录 前言: 1.边缘检测 1.1 Laplacian边缘检测 1.2 Sobel边缘检测 1.3 Canny边缘检测 2.图像轮廓 2.1 查找轮廓 2.2 绘制轮廓 2.3 轮廓特征 3.霍夫变换 ...

  9. LSD直线检测和霍夫线变换的学习建议

    最近笔者学习霍夫线变换和LSD直线检测算法,有一些学习建议,希望可以给予大家一些帮助.  学习霍夫变换的感想 每个人理解的霍夫变换或许略有差异,但是最主要的是笛卡尔坐标系跟极坐标系的相互转换. 霍夫变 ...

最新文章

  1. 有关eigen库的一些基本使用方法
  2. DynaSLAM跑通的辛酸之路
  3. Homework 1_SQL Server中由于外键约束而删除数据失败
  4. tf.concat用法总结
  5. 课堂小结:返回一个整数数组所有子数和的最大值
  6. 小D课堂 - 零基础入门SpringBoot2.X到实战_第2节 SpringBoot接口Http协议开发实战_13、jar包方式运行web项目文件上传和访问...
  7. javascript 同时下载多个文件
  8. 【二分法】凸多边形外接圆的半径
  9. 接口测试是什么接口测试文档规范
  10. 用大数据文本挖掘来看“共享单车”的行业现状及走势
  11. 【python】画玫瑰花喽!!!
  12. 蚂蚁金服区块链创新大赛
  13. hadoop大数据生态集群
  14. Linux MTD是什么??
  15. SVM(支持向量机)
  16. 支持手机,滑动拖动验证
  17. 【SW系列】计算机案例之草图文字
  18. Android逆向之八门神器原理解析(主要分析其修改内存原理)
  19. php 正则验证手机号和电话
  20. python远程文件管理系统_python 读取远程服务器文件

热门文章

  1. 深耕“有效私域”,雀巢集团携手腾讯重塑零售数字化体验
  2. 2019河南对口升学高考试卷计算机专业课,2019河南对口升学高考试卷计算机专业课-9页word资料...
  3. 设计模式【5】-- 原型模式
  4. 原生JS实现飞机大战游戏 超详细解析 快来做一个自己玩吧
  5. java订单到期自动取消_订单自动过期实现方案
  6. 微信开发网页授权获取用户信息
  7. Linux系统运维与架构设计之Linux概述
  8. 家族谱树形数据结构实现
  9. 《软技能-代码之外的生存能力》第四篇——生产力
  10. Unity 程序升级(PC版非热更新)