接下来进入代码环节,这里详细给大家解释一下 HoughLinesP 参数的含义以及如何使用。
lines = cv2.HoughLinesP(cropped_image,2,np.pi/180,100,np.array([]),minLineLength=40,maxLineGap=5)
第一参数是我们要检查的图片
Hough accumulator 数组
第二个和第三个参数用于定义我们 Hough 坐标如何划分 bin,也就是小格的精度。我们通过曲线穿过 bin 格子来进行投票,我们根据投票数量来决定 p 和 theta 的值。2 表示我们小格宽度以像素为单位 。
我们可以通过下图划分小格,只要曲线穿过就会对小格进行投票,我们记录投票数量,记录最多的作为参数
如果定义尺寸过大也就失去精度,如果定义格子尺寸过小虽然精度上来了,这样也会打来增长计算时间。
接下来参数 100 表示我们投票为 100 以上的线才是符合要求是我们要找的线。也就是在 bin 小格子需要有 100 以上线相交于此才是我们要找的参数。
minLineLength 给 40 表示我们检查线长度不能小于 40 pixel
maxLineGap=5 作为线间断不能大于 5 pixel
定义显示车道线方法
def disply_lines(image,lines):
pass
通过定义函数将找到的车道线显示出来。
line_image = disply_lines(lane_image,lines)
查看探测车道线数据结构
def disply_lines(image,lines):
line_image = np.zeros_like(image)
if lines is not None:
for line in lines:
print(line)
先定义一个尺寸大小和原图一样的矩阵用于绘制查找到车道线,我们先判断一下是否已经找到车道线,lines 返回值应该不为 None 是一个矩阵,我们可以简单地打印一下看一下效果
[[704 418 927 641]]
[[704 426 791 516]]
[[320 703 445 494]]
[[585 301 663 381]]
[[630 341 670 383]]
探测车道线
看数据结构[[x1,y1,x2,y2]] 的二维数组,这就需要我们转换一下为一维数据[x1,y1,x2,y2]
def disply_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_image
line_image = disply_lines(lane_image,lines)
cv2.imshow('result',line_image)
合成影响
combo_image = cv2.addWeighted(lane_image,0.8, line_image, 1, 1,1)
有关合成图片我们是将两张图片通过给一定权重进行叠加合成。
优化
我们通过学习霍夫变换探测到的车道线还是不够平滑,我们需要优化,基本思路就是对这些直线的斜率和截距取平均值然后将所有探测出点绘制到一条直线上。
averaged_lines = average_slope_intercept(lane_image,lines);
首先定义我们的函数,接收道路图片和探测点做为参数。
def average_slope_intercept(image,lines):
left_fit = []
right_fit = []
for line in lines:
x1, y1, x2, y2 = line.reshape(4)
parameters = np.polyfit((x1,x2),(y1,y2),1)
print(parameters)
这里定义两个数组 left_fit 和 right_fit 分别用于存放左右两侧车道线的点,我们打印一下 lines 的斜率和截距,通过 numpy 提供 polyfit 方法输入两个点我们就可以得到通过这些点的直线的斜率和截距。
[ 1. -286.]
[ 1.03448276 -302.27586207]
[ -1.672 1238.04 ]
[ 1.02564103 -299.
def average_slope_intercept(image,lines):
left_fit = []
right_fit = []
for line in lines:
x1, y1, x2, y2 = line.reshape(4)
parameters = np.polyfit((x1,x2),(y1,y2),1)
# print(parameters)
slope = parameters[0]
intercept = parameters[1]
if slope < 0:
left_fit.append((slope,intercept))
else:
right_fit.append((slope,intercept))
print(left_fit)
print(right_fit)
由于左侧和右侧线的斜率不同,我们根据斜率可以划分点到左右两侧的直线矩阵上。
left_fit_average = np.average(left_fit,axis=0)
right_fit_average = np.average(right_fit,axis=0)
然后通过取平局值来得到他们平均斜率和截距。
[ -1.61019355 1201.00387097]
[ 1.0243751 -298.80648538]
def make_coordinates(image, line_parameters):
slope, intercept = line_parameters
print(image.shape)
return
我们输出一下图片大小,我们图片是以其左上角作为原点 0 ,0 来开始计算的,所以我们直线从图片底部 700 多向上绘制我们无需绘制全部可以截距一部分即可。
![图(https://upload-images.jianshu.io/upload_images/8207483-367e149bfb5a5165.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
(704, 1279, 3)
(704, 1279, 3)
left_line = make_coordinates(image, left_fit_average)
right_line = make_coordinates(image, right_fit_average)
def make_coordinates(image, line_parameters):
slope, intercept = line_parameters
y1 = image.shape[0]
y2 = int(y1*(3/5))
x1 = int((y1 - intercept)/slope)
x2 = int((y2 - intercept)/slope)
# print(image.shape)
return np.array([x1,y1,x2,y2])
所以直线开始和终止我们给定 y1,y2 然后通过方程的斜率和截距根据y 算出 x。
averaged_lines = average_slope_intercept(lane_image,lines);
line_image = disply_lines(lane_image,averaged_lines)
combo_image = cv2.addWeighted(lane_image,0.8, line_image, 1, 1,1)
cv2.imshow('result',combo_image)