1. 简介
OpenCV是一个流行的开源计算机视觉库,它包含了各种图像处理和计算机视觉算法。本文将展示如何使用OpenCV来进行车道检测,并对其进行实时跟踪。车道检测是自动驾驶汽车中非常重要的一步,通过对车道的检测,我们可以确定车辆的位置和朝向,从而更好地进行导航。
2. 实现过程
2.1 准备工作
在开始编写代码之前,需要先安装OpenCV库,并准备好测试用的视频。在本文中,我将使用名为lanelines.mp4的测试视频。
2.2 视频读取与显示
首先,我们需要读取视频,并将其显示出来。下面是相关代码:
import cv2
video = cv2.VideoCapture('lanelines.mp4')
while True:
ret, frame = video.read()
if not ret:
break
cv2.imshow('Video', frame)
if cv2.waitKey(1) == ord('q'):
break
video.release()
cv2.destroyAllWindows()
上述代码中,我们使用了cv2.VideoCapture()函数来读取视频文件,这个函数会返回一个VideoCapture对象,我们可以使用该对象来读取视频的每一帧。在每一帧读取完成后,我们可以调用cv2.imshow()函数将其显示在屏幕上。如果用户输入了q键,则退出程序并关闭所有窗口。
需要注意的一点是,在使用cv2.imshow()之前,需要先使用cv2.namedWindow()函数来创建窗口,否则程序会无响应。
2.3 预处理
接下来,我们需要对每一帧进行预处理,以便于后续的车道检测。我们需要完成以下几个步骤:
将图像转换为灰度图像
应用高斯模糊
使用Canny算法检测边缘
选择感兴趣区域,并进行掩码操作,以便于仅保留车道线段
下面是完整代码:
import cv2
import numpy as np
video = cv2.VideoCapture('lanelines.mp4')
while True:
ret, frame = video.read()
if not ret:
break
# 将图像转换为灰度图像
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 应用高斯模糊
kernel_size = 5
blur_gray = cv2.GaussianBlur(gray, (kernel_size, kernel_size), 0)
# 使用Canny算法检测边缘
low_threshold = 50
high_threshold = 150
edges = cv2.Canny(blur_gray, low_threshold, high_threshold)
# 选择感兴趣区域,并进行掩码操作,以便于仅保留车道线段
mask = np.zeros_like(edges)
ignore_mask_color = 255
imshape = frame.shape
vertices = np.array([[(0, imshape[0]), (460, 320), (520, 320), (imshape[1], imshape[0])]], dtype=np.int32)
cv2.fillPoly(mask, vertices, ignore_mask_color)
masked_edges = cv2.bitwise_and(edges, mask)
cv2.imshow('Video', masked_edges)
if cv2.waitKey(1) == ord('q'):
break
video.release()
cv2.destroyAllWindows()
在以上代码中,我们使用cv2.cvtColor()函数将图像从BGR格式转换为灰度图像格式,使用cv2.GaussianBlur()函数对其进行高斯模糊处理,使用cv2.Canny()函数检测边缘。我们还定义了一个用于选择感兴趣区域的多边形,将图片分为了矩形区域和梯形区域两部分(mask可自由设置,位置应该包含车道线部分),并使用cv2.fillPoly()函数进行掩码操作,仅保留车道线段。
2.4 车道检测
在对每一帧图像进行预处理后,我们就可以进行车道检测了。我们将使用霍夫变换和二次函数拟合来检测车道线。下面是代码:
import cv2
import numpy as np
video = cv2.VideoCapture('lanelines.mp4')
while True:
ret, frame = video.read()
if not ret:
break
# 将图像转换为灰度图像
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 应用高斯模糊
kernel_size = 5
blur_gray = cv2.GaussianBlur(gray, (kernel_size, kernel_size), 0)
# 使用Canny算法检测边缘
low_threshold = 50
high_threshold = 150
edges = cv2.Canny(blur_gray, low_threshold, high_threshold)
# 选择感兴趣区域,并进行掩码操作,以便于仅保留车道线段
mask = np.zeros_like(edges)
ignore_mask_color = 255
imshape = frame.shape
vertices = np.array([[(0, imshape[0]), (460, 320), (520, 320), (imshape[1], imshape[0])]], dtype=np.int32)
cv2.fillPoly(mask, vertices, ignore_mask_color)
masked_edges = cv2.bitwise_and(edges, mask)
# 霍夫变换检测线段,并拟合二次函数
rho = 2
theta = np.pi/180
threshold = 40
min_line_length = 10
max_line_gap = 20
lines = cv2.HoughLinesP(masked_edges, rho, theta, threshold, np.array([]),
min_line_length, max_line_gap)
left_fit = []
right_fit = []
for line in lines:
for x1, y1, x2, y2 in line:
slope = (y2 - y1) / (x2 - x1)
if abs(slope) < 0.5:
continue
if slope < 0:
left_fit.append((x1, y1))
left_fit.append((x2, y2))
else:
right_fit.append((x1, y1))
right_fit.append((x2, y2))
if len(left_fit) > 0 and len(right_fit) > 0:
left_fit_x, left_fit_y = zip(*left_fit)
right_fit_x, right_fit_y = zip(*right_fit)
left_fit_curve = np.polyfit(left_fit_y, left_fit_x, 2)
right_fit_curve = np.polyfit(right_fit_y, right_fit_x, 2)
plot_y = np.linspace(0, frame.shape[0] - 1, frame.shape[0])
left_fit_x = left_fit_curve[0] * plot_y ** 2 + left_fit_curve[1] * plot_y + left_fit_curve[2]
right_fit_x = right_fit_curve[0] * plot_y ** 2 + right_fit_curve[1] * plot_y + right_fit_curve[2]
blank = np.zeros_like(frame)
color = [0, 255, 0]
thickness = 10
left_line = np.array(list(zip(left_fit_x, plot_y)), np.int32)
right_line = np.array(list(zip(right_fit_x, plot_y)), np.int32)
cv2.polylines(blank, [left_line], False, color, thickness)
cv2.polylines(blank, [right_line], False, color, thickness)
result = cv2.addWeighted(frame, 0.8, blank, 1, 0)
cv2.imshow('Video', result)
else:
cv2.imshow('Video', frame)
if cv2.waitKey(1) == ord('q'):
break
video.release()
cv2.destroyAllWindows()
在以上代码中,我们首先使用cv2.HoughLinesP()函数检测线段,然后筛选出斜率在0.5到正无穷之间的线段,分别存入左侧车道和右侧车道的列表中。接着,我们使用np.polyfit()函数对左侧车道和右侧车道的线段进行二次函数拟合,得到其拟合曲线。最后,我们使用cv2.polylines()函数将拟合曲线画在一张全黑的背景上。需要注意的是,在进行车道检测时,我们需要在相邻帧之间进行线段匹配,以便于产生平滑的车道线。
3. 结论
本文介绍了如何使用OpenCV来进行车道检测,其中包括视频读取与显示、预处理(灰度化、高斯模糊、Canny检测、掩码),以及车道检测(霍夫变换、二次函数拟合)。欢迎读者在自己的项目中尝试使用这些技术。