FunnyWii
FunnyWii
Published on 2023-11-14 / 50 Visits
0
0

车道线检测功能综述【传统方法】

车道线检测技术

车道线检测技术是计算机视觉和自动驾驶领域中的关键技术之一,它能够帮助车辆在道路上准确识别和跟踪车道线,从而实现自动驾驶、车道保持等功能。

车道线检测方法总体上可以分为 传统方法基于深度学习的方法

车道线数据集

数据集 数量(张) 尺寸 场景 特点
TuSimple 72k 1280x720 高速路,天气晴朗,车道线清晰 车道线以点来标注
CULane 98k 1640x590 多种难以检测的情况; 场景复杂,很多位于北京城区 最多标记4条车道线
Caltech 1.2k 640x480 场景比较简单,且视角较好
VPGNet 20k 白天(非雨天、雨天、大雨天)、夜晚 包含各种车道线类型,以及不同类型的车道标识(左转箭头、直行箭头、斑马线等等)
BDD100k 120M 1280x720 包含美国4个区的白天、黑夜各种天气状况 二维8类别车道线
ApolloScape 140k 3384x2710 车道线以掩码的形式标注,包含2维或3维28个类别
CurveLanes 135k 2650x144 包括复杂的场景,如S路,Y车道,夜间和多车道的场景 采用三次样条曲线手动标注所有车道线,分为训练集100k,验证集20k,测试集30k
Comma2k19 LD 2k 1164x874 手动注释。场景是从Comma2k19数据集中时速超过48km/h的场景中随机选择
OpenLane: 3D 200k 第一个真实世界和最大比例的3D lane数据集

传统方法

传统图像方法通过边缘检测滤波等方式分割出车道线区域,然后结合霍夫变换、RANSAC等算法进行车道线检测。这类算法需要人工手动去调滤波算子,根据算法所针对的街道场景特点手动调节参数曲线,工作量大且鲁棒性较差,当行车环境出现明显变化时,车道线的检测效果不佳。主

滑动窗口法

滑动窗口法是一种传统的方法,它在图像中使用滑动窗口逐步搜索可能包含车道线的区域。

相关源代码:
Advanced Lane Detection
Advanced Lane Finding Using Sliding Window Search

相机校准

不同于一般的检测算法,涉及到像素坐标系->世界坐标系变换的,都需要先进行相机校准,得到相机的内参和畸变参数。

图像灰度化

若对原始彩色图像进行直接处理,由于图片信息过多,算法难以提取到有效信息,故首先对于原图像进行灰度化处理。

G(x,y) = 0.2989 \times R(x,y) + 0.5870 \times G(x,y) + 0.1140 \times B(x,y)

图像滤波

通过高斯滤波进行图像的降噪处理,可以有效降低图片的噪声干扰。高斯滤波器的模板矩阵大小设为5×5,标准偏差sigma为1。

图像二值化

图像二值化处理是分割图像的首要步骤。通过原图像像素灰度值与预定的阈值S进行比对,将所有像素值分为两类,大于阈值的置为1,小于阈值的置为0。

通过加入OTSU算法对灰度值进行自适应二值化可以提高对光照变化的鲁棒性。

图像二值化.png

透视变换

透视变换是将当前视角转换为BEV视角来可视化前方道路。可以减少非车道线信息,且车道线形状近似平行。

透视变换本质上是将输入图像中车道区域边界的四个点映射到所需的点集,从而生成所需的BEV。

查找车道线像素

在图像中定位车道线像素点的方法是绘制非零像素的直方图。由于像素值已经二值化,再加上透视变换,峰值可以代表大部分非零像素的位置。直方图中峰值的x坐标可作为搜索车道线的起点(左右车道各一个)。滑动窗口的框围绕车道线的中心点放置。

查找车道线像素.png

滑动窗口能够估计每个车道线区域的中心点,中心点的xy坐标。可以使用search_around_poly()函数拟合一个多项式曲线。要注意这个函数拟合的结果是f(y)而非f(x),因为车道线在图像中是竖直的。

边缘检测

Canny边缘检测是一种经典的边缘检测算法,由John Canny于1986年提出,它能够有效地检测图像中的边缘,并且对噪声具有一定的抵抗能力。

高斯滤波

为了降低图像中的噪声,首先对原始图像进行高斯滤波。高斯滤波通过卷积原始图像和一个高斯核来平滑图像,减小图像中的高频噪声。

梯度计算

使用 Roberts,Prewitt,Sobel 等算子计算图像的梯度,分别得到图像在水平和垂直方向上的梯度值。梯度的方向通常用于确定边缘的方向。G 表示梯度强度,G_x&G_y表示水平&垂直方向的一阶导数值\theta 表示梯度方向:

G = \sqrt{G_x^2+G_y^2}
\theta = arctan({G_y}/{G_x})

NMS非极大值抑制

计算出像素点 p 的梯度和方向后,对梯度幅值图进行非极大值抑制,去除非边缘像素。具体做法是,在梯度方向上,比较每个像素的梯度幅值与其相邻两个像素的梯度幅值,如果不是极大值,将其置0,否则置为某一不大于255的数,非最大值抑制能帮助保留局部最大梯度而抑制所有其他梯度值。这意味着只保留了梯度变化中最锐利的位置。

NMS非极大值抑制.png

边缘跟踪

这个阶段可以加入双阈值处理的方法,即设置两个阈值,一个高阈值和一个低阈值。根据梯度幅值,将像素分为强边缘、弱边缘和非边缘三类。高阈值用于标记强边缘,低阈值用于标记弱边缘。

然后设置两个阈值minVal和maxVal。强度梯度大于maxVal的任何边缘肯定是边缘,低于minVal的边缘肯定是非边缘,因此被丢弃。那些位于这两个阈值之间的点,则基于这些点是否与真正的边缘部分相连接。如果它们连接“真正边缘”像素,则它们被认为是边缘的一部分,否则也被丢弃。

边缘跟踪.png

分割

使用Mask蒙版的方法,认为包含车道线的区域(一般在画面下方)的值为1,其它区域的值为0。将Mask与当前frame叠加便可得出主要车道区域。

霍夫变换

霍夫变换是一种常用的计算机视觉技术,用于在图像中检测几何形状,如直线、圆和椭圆。

霍夫变换的基本思想是通过将图像中的几何形状 y=mx+b的一条线 表示为参数空间中的点 (m,b),并通过对参数空间(累加空间)中的点进行累积投票来检测这些几何形状。可以总结为:从图像空间到霍夫空间的转换。

霍夫变换1.png

空间坐标系的直线转换到霍夫空间是点,因为直线的参数确定,确定的参数在霍夫空间里面就是点。空间坐标系的点转换到霍夫空间是直线,因为经过这个点有无穷个直线,每个直线对应的(m,b)不同。

因此,若要在图像空间中寻找一条线,那么在霍夫空间中,要寻找的应是相交的线

将边缘检测图像中的每个点,都视为霍夫空间中的一条线。在霍夫空间中有很多条线相交的地方,可以认为找到了一组连续的点。

霍夫变换2.png

为了避免出现垂直线的线,也就是斜率无限大的情况,可以使用极坐标的方式重新定义直线。

p表示直线到原点的垂直距离,\theta表示实现的垂直线与横轴的夹角。

也就是x_0=p_0cos\theta_0y_0=p_0sin\theta_0,由此可以得到:

p_0 = x_0cos\theta_0 + y_0sin\theta_0

霍夫变换3.png

假设x_0y_0均为1,那么 p_0 = x_0cos\theta_0 + y_0sin\theta_0 的图像如下图所示,也是一个三角函数。

霍夫变换4.jpg

因此如果取直线上的 (x_1,y_1)......(x_n,y_n) 那么则会转化为霍夫空间中的 n 条正弦曲线,这些正弦曲线在霍夫空间中的交点,即图像空间中直线的参数。

霍夫变换5.png

RGB -> GRAY

首先将 RGB 格式的图像(三通道)转换为 GRAY (单通道)。

void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0);

    src:输入RGB图像。
    dst:输出灰度图像。
    code:颜色空间转换代码,CV_BGR2GRAY或CV_RGB2GRAY。
    dstCn:输出图像的通道数,默认为0,表示与输入图像的通道数相同。

高斯滤波

去除高频噪声。

void GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY=0, int borderType=BORDER_DEFAULT);

    src:输入图像。
    dst:输出图像,用于存储滤波结果。
    ksize:高斯内核的大小,指定滤波器的尺寸。可以使用Size(width, height)来指定内核的宽度和高度。
    sigmaX:X方向的高斯核标准差。
    sigmaY:可选,Y方向的高斯核标准差。如未指定,默认为0,表示与sigmaX相同。
    borderType:可选,指定边界像素的处理方式。默认为 BORDER_DEFAULT。

Canny边缘检测

Canny 边缘检测算法可以用来寻找与图像中的边缘相关的点。将原本复制的灰度图最大限度保留信息的情况下转换为二值图像。

void Canny(InputArray image, OutputArray edges, double threshold1, double threshold2, int apertureSize=3, bool L2gradient=false);

MASK掩码

可以降低计算代价,只在ROI进行运算。下图中的 height 和 width 分别代表图像的高与宽。

MASK掩码.png

霍夫变换

void HoughLinesP(InputArray image, OutputArray lines, double rho, double theta, int threshold, double minLineLength=0, double maxLineGap=0);

    image:输入图像,可以是Canny算法输出的边缘检测结果。
    lines:输出参数,检测到的直线的线段集。
    rho:极坐标中的距离分辨率。
    theta:极坐标中的角度分辨率。
    threshold:直线检测的阈值,只有当累加器中的值大于等于阈值时,才会被认为是一条直线。
    minLineLength:最小线段长度,小于此长度的线段将被忽略。
    maxLineGap:最大线段间隙,如果两条线段之间的间隙小于此值,则将它们视为一条线段。

Lane绘制

直接使用霍夫变换得到的车道线结果,一般会包含多条相邻的线段,但是不是一条完整的车道线。因此还需要进行如下处理:

  • 对每条直线求取斜率,
  • 分别归为左右列表中对得到的列表进行斜率平均值m_0的计算和最高点A的计算
  • 根据平均斜率m_0与最高点计算线段与图像下方的交点B坐标
  • 连接最高点A与交点B

Lane和原始图像的融合

参考文章

[1] https://zhuanlan.zhihu.com/p/580523473
[2] https://blog.csdn.net/u012932320/article/details/125379388
[3] https://kushalbkusram.medium.com/advanced-lane-detection-fd39572cfe91
[4] 万斌, 童亮, 魏双叶 and 任子豪, 2021. 基于自适应滑动窗口检测的车道线识别. 北京信息科技大学学报 (自然科学版).
[5] https://zhuanlan.zhihu.com/p/60190848
[5] https://www.cnblogs.com/minyshi/p/8573685.html
[6] https://zhuanlan.zhihu.com/p/60891432
[7]


Comment