霍夫(Hough)直线变换(直线检测)
0 原理
霍夫变换在检测各种形状的的技术中非常流行,如果你要检测的形状可以用数学表达式写出,你就可以是使用霍夫变换检测它。及时要检测的形状存在一点破坏或者扭曲也可以使用。我们下面就看看如何使用霍夫变换检测直线。
首先将一条直线用一个点表示,这样用一个点表示直线上所有的点,一开始人们使用斜截式y=kx+q中的(k,q)来表示一条直线。
首先将一条直线用一个点表示,这样用一个点表示直线上所有的点,一开始人们使用斜截式y=kx+q中的(k,q)来表示一条直线。

变换后的空间成为霍夫空间。即:笛卡尔坐标系中一条直线,对应霍夫空间的一个点。
反过来同样成立(霍夫空间的一条直线,对应笛卡尔坐标系的一个点):

再来看看A、B两个点,对应霍夫空间的情形:

一步步来,再看一下三个点共线的情况:

可以看出如果笛卡尔坐标系的点共线,这些点在霍夫空间对应的直线交于一点:这也是必然,共线只有一种取值可能。
如果不止一条直线呢?再看看多个点的情况(有两条直线):

其实(3,2)与(4,1)也可以组成直线,只不过它有两个点确定,而图中A、B两点是由三条直线汇成,这也是霍夫变换的后处理的基本方式:选择由尽可能多直线汇成的点。
看看,霍夫空间:选择由三条交汇直线确定的点(中间图),对应的笛卡尔坐标系的直线(右图)。

到这里问题似乎解决了,已经完成了霍夫变换的求解,但是如果像下图这种情况呢?
但这样做会有一个弊端,那就是当直线趋近于垂直时,斜率a会趋近于无穷大。这一困难的解决方法之一就是使用法线来表示直线。

在极坐标系下,其实是一样的:极坐标的点→霍夫空间的正弦线,这条正弦线上的所有点都过极坐标中的那个点。


简单来说就是每个点在霍夫空间的弦线与其他点的弦线交一次,就会在累加器的ρθ平面中累加一次。下面的动画很好的演示了这个过程

1 OpenCV中的霍夫变换
上面介绍的整个过程在OpenCV中都被封装进了一个函数:cv2.HoughLines()。返回值就是极坐标表示的直线(ρ, θ)。ρ 的单位是像素,θ 的单位是弧度。
cv2.HoughLines(image, rho, theta, threshold, lines, sen, stn, min_theta, max_theta)
- image:输入图像,8-bit灰度图像
- rho:生成极坐标时候的像素扫描步长
- theta:生成极坐标时候的角度步长
- threshold:阈值,只有获得足够交点的极坐标点才被看成是直线
- lines:返回值,极坐标表示的直线(ρ, θ)
- sen:是否应用多尺度的霍夫变换,如果不是设置0表示经典霍夫变换
- stn:是否应用多尺度的霍夫变换,如果不是设置0表示经典霍夫变换
- min_theta:表示角度扫描范围最小值
- max_theta:表示角度扫描范围最大值
这种方法仅仅是一条直线都需要两个参数,这需要大量的计算。Probabilistic_Hough_Transform 是对霍夫变换的一种优化。它 不会对每一个点都进行计算,而是从一幅图像中随机选取(是不是也可以使用 图像金字塔呢?)一个点集进行计算,对于直线检测来说这已经足够了。但是 使用这种变换我们必须要降低阈值(总的点数都少了,阈值肯定也要小呀!)。
函数如下:
cv2.HoughLinesP(image, rho, theta, threshold, lines, minLineLength, maxLineGap)
- src:输入图像,必须8-bit的灰度图像
- rho:生成极坐标时候的像素扫描步长
- theta:生成极坐标时候的角度步长
- threshold:阈值,只有获得足够交点的极坐标点才被看成是直线
- lines:输出的极坐标来表示直线
- minLineLength:最小直线长度,比这个短的线都会被忽略。
- maxLineGap:最大间隔,如果小于此值,这两条直线 就被看成是一条直线。
举个例子:
import cv2
import numpy as np img = cv2.imread('test19.jpg')
img1 = img.copy()
img2 = img.copy()
img = cv2.GaussianBlur(img, (3, 3), 0)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
lines = cv2.HoughLines(edges, 1, np.pi/180, 110) for line in lines:
rho = line[0][0]
theta = line[0][1]
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = 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) lines = cv2.HoughLinesP(edges, 1, np.pi/180, 30, 300, 5) for line in lines:
x1 = line[0][0]
y1 = line[0][1]
x2 = line[0][2]
y2 = line[0][3]
cv2.line(img2, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imshow('houghlines3', img1)
cv2.imshow('edges', img2)
cv2.waitKey(0)
print(lines)
结果如下:

带有滑动条,用于调节HoughLines的参数
import cv2
import numpy as np
from matplotlib import pyplot as plt def nothing(x): # 滑动条的回调函数
pass src = cv2.imread('test19.jpg')
srcBlur = cv2.GaussianBlur(src, (3, 3), 0)
gray = cv2.cvtColor(srcBlur, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
WindowName = 'Approx' # 窗口名
cv2.namedWindow(WindowName, cv2.WINDOW_AUTOSIZE) # 建立空窗口 cv2.createTrackbar('threshold', WindowName, 0, 60, nothing) # 创建滑动条 while(1):
img = src.copy()
threshold = 100 + 2 * cv2.getTrackbarPos('threshold', WindowName) # 获取滑动条值 lines = cv2.HoughLines(edges, 1, np.pi/180, threshold) for line in lines:
rho = line[0][0]
theta = line[0][1]
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = 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.imshow(WindowName, img)
k = cv2.waitKey(1) & 0xFF
if k == 27:
break
cv2.destroyAllWindows()
结果如下:


带有滑动条,用于调节HoughLinesP的参数
import cv2
import numpy as np
from matplotlib import pyplot as plt def nothing(x): # 滑动条的回调函数
pass src = cv2.imread('test19.jpg')
srcBlur = cv2.GaussianBlur(src, (3, 3), 0)
gray = cv2.cvtColor(srcBlur, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
WindowName = 'Approx' # 窗口名
cv2.namedWindow(WindowName, cv2.WINDOW_AUTOSIZE) # 建立空窗口 cv2.createTrackbar('threshold', WindowName, 0, 100, nothing) # 创建滑动条
cv2.createTrackbar('minLineLength', WindowName, 0, 100, nothing) # 创建滑动条
cv2.createTrackbar('maxLineGap', WindowName, 0, 100, nothing) # 创建滑动条 while(1):
img = src.copy()
threshold = cv2.getTrackbarPos('threshold', WindowName) # 获取滑动条值
minLineLength = 2 * cv2.getTrackbarPos('minLineLength', WindowName) # 获取滑动条值
maxLineGap = cv2.getTrackbarPos('maxLineGap', WindowName) # 获取滑动条值 lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold, minLineLength, maxLineGap) for line in lines:
x1 = line[0][0]
y1 = line[0][1]
x2 = line[0][2]
y2 = line[0][3]
cv2.line(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imshow(WindowName, img)
k = cv2.waitKey(1) & 0xFF
if k == 27:
break
cv2.destroyAllWindows()
结果如下:


霍夫(Hough)直线变换(直线检测)的更多相关文章
- opencv —— HoughCircles 霍夫圆变换原理及圆检测
霍夫圆变换原理 霍夫圆变换的基本原理与霍夫线变换(https://www.cnblogs.com/bjxqmy/p/12331656.html)大体类似. 对直线来说,一条直线能由极径极角(r,θ)表 ...
- OpenCV 学习笔记03 直线和圆检测
检测边缘和轮廓不仅重要,还经常用到,它们也是构成其他复杂操作的基础. 直线和形状检测与边缘和轮廓检测有密切的关系. 霍夫hough 变换是直线和形状检测背后的理论基础.霍夫变化是基于极坐标和向量开展的 ...
- opencv —— HoughLines、HoughLinesP 霍夫线变换原理(标准霍夫线变换、多尺度霍夫线变换、累积概率霍夫线变换)及直线检测
霍夫线变换的原理 一条直线在图像二维空间可由两个变量表示,有以下两种情况: ① 在笛卡尔坐标系中:可由参数斜率和截距(k,b)表示. ② 在极坐标系中:可由参数极经和极角(r,θ)表示. 对于霍夫线变 ...
- Android开发中的OpenCV霍夫直线检测(Imgproc.HoughLines()&Imgproc.HoughLinesP())
本文为作者原创,转载请注明出处(http://www.cnblogs.com/mar-q/)by 负赑屃 //2017-04-21更新: 很多网友希望能得到源码,由于在公司做的,所以不太方便传出来 ...
- 霍夫直线检测 opencv
本次实验是检测图像中的直线,用到了HoughLines()和HoughLinesP()函数,其中HoughLinesP()称为累计概率霍夫变换,实验结果显示累计概率霍夫变换要比标准霍夫变换的效果好.具 ...
- opencv:霍夫直线检测
#include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace st ...
- opencv-霍夫直线变换与圆变换
转自:https://blog.csdn.net/poem_qianmo/article/details/26977557 一.引言 在图像处理和计算机视觉领域中,如何从当前的图像中提取所需要的特征信 ...
- Matlab 霍夫变换 ( Hough Transform) 直线检测
PS:好久没更新,因为期末到了,拼命复习中.复习久了觉得枯燥,玩玩儿霍夫变换直线检测 霍夫变换的基本原理不难,即便是初中生也很容易理解(至少在直线检测上是这样子的). 霍夫变换直线检测的基本原理:(不 ...
- Win8 Metro(C#)数字图像处理--2.38Hough变换直线检测
原文:Win8 Metro(C#)数字图像处理--2.38Hough变换直线检测 [函数名称] Hough 变换直线检测 HoughLineDetect(WriteableBit ...
- OpenCV2马拉松第22圈——Hough变换直线检測原理与实现
计算机视觉讨论群162501053 转载请注明:http://blog.csdn.net/abcd1992719g/article/details/27220445 收入囊中 Hough变换 概率Ho ...
随机推荐
- ubuntu22.04下安装nvidia-docker
首先需要保证docker engine已经安装成功,具体见: https://www.cnblogs.com/devilmaycry812839668/p/17269122.html ======== ...
- 如何关闭NVIDIA显卡的CUDA运算功能
基本很少有人会想到要关闭NVIDIA显卡的CUDA计算功能,这东西不想用就不跑cuda代码不就可以了吗,但是作为一个深度学习服务器集群的管理者来说,这个功能还是有用处的.前一阵使用实验室的一台服务器的 ...
- 7. 从0学ARM-GNU伪指令、代码编译,lds使用
<嵌入式工程师到底要不要学习ARM汇编指令?arm学习文章汇总> <到底什么是Cortex.ARMv8.arm架构.ARM指令集.soc?一文帮你梳理基础概念[科普]> 关于A ...
- 充分利用HarmonyOS NEXT:开发者的全功能指南
随着技术的不断进步,开发者们面临着如何在复杂的技术环境中创造出卓越应用的挑战.在当今的科技浪潮中,如何抓住创新的机遇?HarmonyOS NEXT的发布,带来了全新的机遇和功能.本文将探讨开发者如何充 ...
- Vue开发转到React开发,Prettier - Code formatter失效的问题
Vue转到React,Prettier - Code formatter失效,按下Ctrl+S无效,需要手动格式化一次 然后选择默认的格式化方式 之后按下Ctrl+S就可以进行格式化啦!!!
- springjdbc处理nvarchar
当我们使用spring-jdbc来做持久化时(注意不是spring-data-jbc),有时候一些特殊字符存入数据库时会用到nvarchar.nvarchar2这种类型(比如存放化学式,如CO₂等), ...
- office系列软件(word、ppt、excel)打不开的解决方案
前言 这里我遇到的情况是点击都没反应,而不像很多人那样有报错弹窗,费劲千辛万苦才最终解决,中间一度自暴自弃想着干脆用WPS得了(大可不必),中间我尝试了三种方法,不一定哪种有效,权当分享: 一.使 ...
- Typora mac激活
typora mac版本激活 我也是第一次使用mac电脑,在安装时基本上都是付费的,在mac下载使用typora是试用一段时间后是需要付费购买的,苦无能力有限只能绕一下,感谢网上的各位大佬的分享 来源 ...
- 【题目全解】ACGO排位赛#12
ACGO 排位赛#12 - 题目解析 别问为什么没有挑战赛#11,因为挑战赛#11被贪心的 Yuilice 吃掉了(不是). 本次挑战赛难度相比较前面几次有所提升. 爆料:小鱼现在已经入职了研发部门, ...
- 应聘软件测试 HR 会问到哪些问题?收藏这一篇就够了!
1.你还有收到其他offer吗? 其实hr问你offer情况,是对你感兴趣,想要进一步了解你,看下你的市场竞争力. 但注意不要太坦诚的说:我还没有offer或者收到两个offer还想对比对比:也不要撒 ...