霍夫变换常用来在图像中提取直线和圆等几何形状,如下图所示:
在这里我使用霍夫变换主要是想来提取图像中的直线.
一条直线可由两个点A=(X1,Y1)和B=(X2,Y2)确定(笛卡尔坐标)
另一方面 y=kx+q也可以写成关于(k,q)的函数表达式(霍夫空间):
对应的变换可以通过图形直观表示:
变换后的空间成为霍夫空间。即:笛卡尔坐标系中一条直线,对应霍夫空间的一个点。
注意
当以下情况
k=∞是不方便表示的,而且q怎么取值呢,这样不是办法。因此考虑将笛卡尔坐标系换为:极坐标表示。
上面的公式有一处错误,应该是
x cos θ + y sin θ = ρ x \cos \theta+y \sin \theta=\rho xcosθ+ysinθ=ρ
在极坐标系下,其实是一样的:极坐标的点→霍夫空间的直线,只不过霍夫空间不再是[k,q]的参数,而是的参数,给出对比图:
在实现的图像处理领域,图像的像素坐标P(x, y)是已知的,而r, theta则是我们要寻找的变量。如果我们能绘制每个(r, theta)值根据像素点坐标P(x, y)值的话,那么就从图像笛卡尔坐标系统转换到极坐标霍夫空间系统,这种从点到曲线的变换称为直线的霍夫变换。变换通过量化霍夫参数空间为有限个值间隔等分或者累加格子
首先创建一个2D数组(累加器),初始化累加器,所有的值都为0。
行表示 ρ,列表示 θ。
这个数组的大小决定了最后结果的准确性。
如果你希望角度精确到1°,你就需要180列。对于 ρ,最大值为图片对角线距离。
想象一下我们有一个大小为100x100的直线位于图像中央。
OpenCV中首先计算(r,θ) 累加数,累加数超过一定值后就认为在同一直线上(有一个阈值)。
# coding:utf8
import cv2
import numpy as np
# 读入图像
img = cv2.imread("/home/cheng/Pictures/cangchu.png")
# 转为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Canny边缘检测
edges = cv2.Canny(gray, 50, 100)
"""
canny边缘检测:
有五个步骤:
1 高斯滤波器降噪
2 计算梯度
3 边缘上使用非最大抑制 nms
4 边缘上使用双阈值去除假阳性
5 分析所有边缘连接 消除不明显的边缘
"""
minLineLength = 100
maxLineGap = 10
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 100, minLineLength, maxLineGap)
"""
cv2.HoughLinesP
作用:标准霍夫线变换, 找到图像中的所有直线
参数:
1 二值图
2 半径精度
3 角度精度
4 最短检测长度
5 允许的最大缺口
返回:
一个列表,每一项是一个四元组,分别是直线两个端点的坐标
"""
for line in lines:
for x1, y1, x2, y2 in line:
# 在图片上画直线
cv2.line(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
cv2.imshow("edges", edges)
cv2.imshow("lines", img)
cv2.waitKey()
cv2.destroyAllWindows()