从零开始详解OpenCV车道线检测

前言

车道线检测是智能驾驶和智能交通系统中的重要组成部分,对于提高道路安全、交通效率和驾驶舒适性具有重要意义。在本篇文章中将介绍使用OpenCV进行车道线的检测

详解

导入包

python 复制代码
import cv2
import matplotlib.pyplot as plt
import numpy as np

读入图像并灰度化

python 复制代码
img = cv2.imread('road.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
plt.imshow(gray, cmap='gray')
plt.show()

二值化

python 复制代码
thresh, im = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY)
plt.imshow(im, cmap=plt.cm.gray)
plt.show()

边缘检测

python 复制代码
output = cv2.Canny(im, 180, 255)
plt.imshow(output, cmap='gray')
plt.show()

cv2.Canny()函数的语法和参数说明:

python 复制代码
语法:
	edges = cv2.Canny(image, threshold1, threshold2[, apertureSize[, L2gradient]])
参数:
	image:输入图像,通常是8位灰度图像。
	threshold1:第一个阈值。边缘梯度值高于这个阈值的像素被视为边缘。
	threshold2:第二个阈值。在这两个阈值之间的边缘会被认为是强边缘,而低于threshold1但高于threshold2的边缘被认为是弱边缘。只有与强边缘相连的弱边缘才会被认为是真正的边缘。
	apertureSize(可选):Sobel算子的孔径大小,用于计算梯度。默认是3。
	L2gradient(可选):一个布尔值,指定是否使用L2范数来计算梯度幅度。如果为True,则使用L2范数;否则,使用L1范数(这更快)。默认是False。
返回值:
	edges:输出图像,包含检测到的边缘。

掩码操作

从边缘检测的结果看,仍然存在很多干扰区域,我们可以通过掩码操作除去这一部分的干扰。

在获取掩码的步骤中,首先构建一个全为0的掩码,即黑色部分。然后使用cv2,fillPoly来绘制掩码中值为255的白色部分。

python 复制代码
polygons = np.array([[(0, output.shape[0]), (0, 400), (output.shape[1]//2, 100), (output.shape[1], 400), (output.shape[1], output.shape[0])]])
mask = np.zeros_like(output)
cv2.fillPoly(mask, polygons, 255)

cv2.fillPoly用于在图像上绘制并填充多边形

python 复制代码
语法:
	cv2.fillPoly(img, pts, color[, lineType[, shift[, offset]]])
参数:
	img:原图像。
	pts:多边形的顶点坐标列表。其中每个元素是一个二维坐标点(即顶点的坐标)。
	color:填充颜色。这是一个三元组,表示 BGR 颜色。
	lineType:线条类型。默认值为 cv2.LINE_8, 可选参数:
		cv2.LINE_8(8-连通)
		cv2.LINE_4(4-连通)
		cv2.LINE_AA(反锯齿线条)。
	shift:点的精度。这是一个整数值,表示每个坐标点 (x,y) 的偏移量。默认值为 0。
	offset:绘制多边形的偏移量。这是一个元组,表示在 x 和 y 方向上的偏移量。默认值为 (0,0)。

获取到的掩码如下图

随后可以通过按位与运算对图像进行掩码操作

python 复制代码
masked_image = cv2.bitwise_and(output, mask)

操作后的结果

我们将以上两个步骤写成一个函数

python 复制代码
def mask_of_image(image):
    polygons = np.array([[(0, image.shape[0]), (0, 400), (image.shape[1]//2, 100), (image.shape[1], 400), (image.shape[1], image.shape[0])]])
    mask = np.zeros_like(image)
    cv2.fillPoly(mask, polygons, 255)
    masked_image = cv2.bitwise_and(image, mask)
    return masked_image

绘制到原图像

在这一步可以先获取车道线的直线部分,再将获取到的直线线段绘制到原图像

python 复制代码
mask_img = mask_of_image(output)

img = cv2.imread('road.png')
lines = cv2.HoughLinesP(mask_img, 1, np.pi/180, 5)
for line in lines:
    x1, y1, x2, y2 = line[0]
    cv2.line(img, (x1, y1), (x2, y2), (0, 255, 0), 4)

plt.imshow(img)

cv2.HoughLinesP 用于在二值图像中执行概率霍夫线变换(Probabilistic Hough Transform)以检测直线,能够返回检测到的直线的起点和终点的坐标。

以下是 cv2.HoughLinesP 的函数原型和参数说明:

python 复制代码
语法
	cv2.HoughLinesP(image, rho, theta, threshold, lines=None, minLineLength=None, maxLineGap=None)
参数:
	image:是通过边缘检测(如 Canny 边缘检测)处理后的图像。
	rho:参数 ρ 的步长(分辨率)。ρ 是从原点到直线的垂直距离(以像素为单位)。
	theta:参数 θ 的步长(分辨率)。θ 是直线的角度(以弧度为单位)。
		通常,可以使用较小的角度步长来提高角度的精度。
	threshold:累加器阈值。只有那些累加器值大于阈值的直线才会被返回。
		这个值越高,检测到的直线就越强。
	lines:一个可选参数,用于存储检测到的直线的端点坐标。
		它是一个 NumPy 数组,每行包含四个元素 [x1, y1, x2, y2],
		分别表示直线的起点和终点的坐标。
	minLineLength:可选参数,表示检测到的直线的最小长度。
		小于此长度的直线将被忽略。默认值为 None。
	maxLineGap:可选参数,表示在检测到的直线上被认为是同一部分的两个线段之间的最大距离。
		如果两个线段之间的间隔小于此值,则它们将被视为同一条直线。默认值为 None。
相关推荐
AI的探索之旅16 小时前
97 个 OpenCV 实例(十九):视频写入,VideoWriter 与 FourCC 编码
人工智能·opencv·音视频
码农刚子2 天前
告别影楼和付费 App,5 分钟本地搭一个证件照自由平台|HivisionIDPhotos 开箱实测
python·图像识别
这个人懒得名字都没写2 天前
OpenCV 官方教程中的测试图片Can’t find required data file
python·opencv
AI的探索之旅2 天前
97 个 OpenCV 实例(十七):图片读写,FileStorage 与 JPEG 采样
人工智能·opencv·计算机视觉
牧羊人.3332 天前
计算机视觉基础第15章|DNN实现图像风格迁移
图像处理·人工智能·深度学习·opencv·计算机视觉
欧特克_Glodon2 天前
OpenCV计算机视觉开发入门与实践<二十九>:grabCut算法分割图像
opencv·算法·计算机视觉·图像分割·grabcut 算法
leoZ2312 天前
AI+前端提效-09 AI赋能前端测试:单元测试、E2E测试自动生成,提升覆盖率
前端·人工智能·opencv·目标检测·数据挖掘·单元测试·语音识别
别动我齐刘海3 天前
从0到1独立搭建机器人软件系统
c++·人工智能·神经网络·opencv·目标检测·机器学习·机器人
AI的探索之旅3 天前
97 个 OpenCV 实例(十五):几何校正,透视变换 + ECC 对齐
人工智能·opencv·计算机视觉
欧特克_Glodon4 天前
OpenCV计算机视觉开发入门与实践<二十七>:图像分割概述
c++·人工智能·opencv·计算机视觉