原理链接如下:陌归:霍夫(Hough)变换之直线检测
代码链接:Ganso:Fundamentals——从车道线检测谈到霍夫变换
同样是一篇讲解原理的番外,这一篇主要讲解CV中常用的霍夫变换的数学原理。
霍夫变换的由来
“霍夫变换于1962年由Paul Hough首次提出,最初的Hough变换是设计用来检测直线和曲线,起初的方法要求知道物体边界线的解析方程,但不需要有关区域位置的先验知识。后于1972年由Richard Duda & Peter Hart推广使用。”
其实,霍夫变换的中心思想就是通过坐标变换来检测直线,后来经过改进,就可以检测椭圆等。
霍夫线变换
坐标系的角度:
说起直线,我们会想到笛卡尔坐标系(即x-y坐标系)下的直线方程,细分之则有点斜式、截距式等,
这时极坐标就carry全场了,它与笛卡尔坐标系的转换关系:
由此极坐标下,直线可用
统计学的角度:
内容出自:Opencv学习笔记-----霍夫变换直线检测及原理理解 - CSDN博客
如上图,假定在一个8*8的平面像素中有一条直线,并且从左上角
霍夫圆变换
霍夫圆变换使用的算法叫霍夫梯度法,对应的函数为HoughCircles,这个函数实际上是对常规找圆算法的一种改进,这里不展开讲,想学习这个原理的同学请参考找圆算法((HoughCircles)总结与优化 - CSDN博客
1. base
导入必要的包,顺便写一个打印图像的函数,cv2与plt颜色通道不一致(所以为什么不用plt导入呢)。
import numpy as np
import matplotlib.pyplot as plt
import cv2# opencv的颜色通道顺序为[B,G,R],而matplotlib的颜色通道顺序为[R,G,B]。
def plotImg(img):if len(img.shape)==3:img = img[:,:,(2,1,0)]plt.imshow(img)else:plt.imshow(img, cmap='gray')plt.show()
导入图片,感觉如果干扰很多效果也不会太好。
image = cv2.imread('test_image.jpg')
plotImg(image)
canny
灰度,模糊,canny三连击。
canny输入需求如此。
def canny(image):gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)blur = cv2.GaussianBlur(gray,(5,5),0)canny = cv2.Canny(blur, 50, 150)return cannylane_image = np.copy(image)
canny = canny(lane_image)
plotImg(canny)
region_of_interest
手工特征区域?作者的思路也是蛮清奇的。
简单来说就是对于视角前面的三角形区域做了一个mask,全部填充255,与原图像bitwise。
def region_of_interest(image):height = image.shape[0]polygons = np.array([[(200,height), (1100,height), (550,250)]])mask = np.zeros_like(image)cv2.fillPoly(mask, polygons, 255)masked_image= cv2.bitwise_and(image,mask)return masked_imagecropped_image = region_of_interest(canny)
plotImg(cropped_image)
2. Hough Transform
将图像提取边缘之后获得了很多杂乱的点,而我们需要做的就是找到过这些点的公共直线。
点斜式方程
点斜式方程是
极坐标方程
在极坐标空间中,对于过固定点的直线,过原点做垂线,记距离为
也就是说过固定点的直线簇
霍夫变换
我们将过每个点的直线簇映射到极坐标空间,基本都由一条曲线表示,比如图示的三个点,这样。曲线的交点对应的坐标就是过所有点的直线的极坐标参数。
投票机制
当图片上的点非常多时,所有曲线并不期望相交于一点。我们可以将霍夫空间划分为一个个patch,当一个patch上面的交点满足大于某个threshold时,我们视为这些点有它们的公共直线。
3. cv2实现
cv.2HoughLinesP(image, rho, theta, threshold[, lines[, minLineLength[, maxLineGap]]])
参数
image 图像。
rho、theta:分辨率。(分别率就是指同一个角度,如果计算出两点的rio值小于2,则认为是同一直线。)
threshold:投票阈值。
lines:没有查到。
minLineLength:最小线条长度。
maxLineGap:最大线条间隔。
def display_lines(image,lines):line_image = np.zeros_like(image)if lines is not None:for line in lines:x1, y1, x2, y2 = line.reshape(4)cv2.line(line_image, (x1,y1), (x2,y2),(255,0,0),10)return line_imagelines = cv2.HoughLinesP(cropped_image, 2, np.pi/180, 100, np.array([133,2]), minLineLength=40, maxLineGap=5)
line_image = display_lines(image,lines)
plotImg(line_image)combo_image = cv2.addWeighted(lane_image,0.8, line_image,1,1)
plotImg(combo_image)
霍夫变换求直线