Hough 变换是图像处理中,检测直线最基本,也是应用最广泛的一种传统方法。虽然现在是深度学习大行其道的时代,但是很多传统的算法,依然有其参考的价值所在,至少从数学表达上来看,是更加的简洁,有理有据。
在介绍 Hough 变换之前,我们先回顾一下中学时代学的一些知识,我们学过直角坐标系,也就是常说的 X-Y 坐标系,我们知道在直角坐标系里,一条直线可以简单的用两个参数来表示 ,同时我们学过极坐标系,一条直线可以由法向半径 和 表示, ,所以一条直线可以有两种参数形式来表示:
所以一条直线可以由直角坐标系下的
来决定,也可以由极坐标系下的 KaTeX parse error: Expected 'EOF', got '\thea' at position 7: \rho, \̲t̲h̲e̲a̲ 来表示,给定一条直线,其对应的参数就是确定的,那么,我们知道过一个点的直线有无数条,那么过这个点就会生成很多的 KaTeX parse error: Expected 'EOF', got '\thea' at position 7: \rho, \̲t̲h̲e̲a̲
一组 在直角坐标系下可以决定一条直线,反过来,直角坐标系下的一个点 在极坐标系下可以决定一条曲线,这个时候的变量就是 ,如下图所示,选择直线上的三个点,每个点在极坐标系下都形成了不同的曲线
在图像中,一条直线有很多离散的点,每个点都会产生很多的
,而有一组
是这条直线上的所有点都会产生的,如果看投票的话,就会看到这组
被命中的次数最多,如上图所示,所有极坐标系的下的曲线都会相交于某一个
而这个
其实就对应直角坐标下的一条直线。
hough 变换就是利用这样的关系,来找直线。
简单来说,就是先构造一个离散的 空间,比如在图像域的话,一般可以假设 的范围是 -R ~ R,R 表示图像的长或者宽的一半, 可以取 ,然后把这些参数离散化成 个区间,比如 20 或者 30 等,对应图像上的每一个像素坐标,都可以在这个 表上生成一系列的点,每个图像的像素点都能生成一系列的点,然后统计哪个 上命中的点多,那就有可能是一条直线,实际判断的时候,也会考虑设置一个阈值。
当然,如果对图像每个像素坐标都做这样的统计,显然计算量太大了,所以一般在做 hough 变换之前,会先做一个边缘检测,将明显不符合要求的点去掉,一般都做 canny 边缘检测。
OpenCV 有封装好的边缘检测与 hough 变换的函数:
# Read image
img = cv2.imread('lanes.jpg', cv2.IMREAD_COLOR) # road.png is the filename
# Convert the image to gray-scale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Find the edges in the image using canny detector
edges = cv2.Canny(gray, 50, 200)
# Detect points that form a line
lines = cv2.HoughLinesP(edges, 1, np.pi/180, max_slider, minLineLength=10, maxLineGap=250)
# Draw lines on the image
for line in lines:
x1, y1, x2, y2 = line[0]
cv2.line(img, (x1, y1), (x2, y2), (255, 0, 0), 3)
# Show result
cv2.imshow("Result Image", img)
参考来源:
https://www.learnopencv.com/hough-transform-with-opencv-c-python/