作者:Dt Pham编译:McGL
在这个项目中,我使用 Python 和 OpenCV 构建了一个 pipeline 来检测车道线。这个 pipeline 包含以下步骤:
- 摄像头校准(Camera calibration)
- 透视变换(Perspective transformation)
- 颜色阈值和区域掩码(Color thresholding and Region masking)
- 寻找车道像素(Finding lane pixels)
- 测量车道曲线和曲率(Measuring lane curves and curvatures)
- 将结果显示回原始图像(Display the result back to original image)
1. 摄像头校准
当摄像头观察现实世界中的 3D 物体并将其转换成 2D 图像时,就会发生畸变; 这种转换并不完美。畸变实际上改变了这些 3D 物体的形状和大小。所以,分析摄像头图像的第一步,就是消除这种失真,这样你就可以从中得到有用的信息。
我们感兴趣的畸变有两种类型: 径向畸变(radial distortion)和切向畸变(tangential distortion)。
为了校准摄像头,我们可以拍摄已知形状的照片,并纠正任何畸变的错误。这项任务最常见的目标是棋盘,因为它的高对比度模式。
首先,我们需要用我们的摄像头拍摄大量的棋盘图像,并检测这些图像所有的角。这可以通过 OpenCV 中的函数 cv2.findchesspardcorners() 来实现。
之后,我们将使用 cv2.calibrateCamera()来求解畸变系数。修正径向畸变需要三个系数: k1,k2,k3;而修正切向畸变需要两个系数: p1,p2。计算畸变点坐标的公式如下所示,其中 r 是未畸变图像中某点与图像畸变中心之间的已知距离,而该中心通常就是图像的中心 (x_c,y_c)
2. 透视变换
在这一步中,我们将把图像转换为鸟瞰图。这将使以后的步骤,如测量车道曲率更容易。要对图像进行变换,首先需要从源图像取4个点,并从目标图像取4个点,然后使用函数 cv2.getPerspectiveTransform() 进行变换。这个函数计算一个 3x3 变换矩阵,当我们想要通过 cv2.warpPerspective() 函数对图像进行变换时,这个函数是必需的。
3. 色彩阈值和区域掩码
HLS (色相,明度,饱和度)是 RGB 模型的一种替代表示。HLS 是圆柱形几何体,色相(维的角度)是实际的色彩。明度是指颜色中混合了多少白色(或黑色) ,而饱和度值是指颜色中有多少灰色。饱和度值为0表示大部分为灰色,100%亮 (L=255)为白色。
车道线的颜色是白色和黄色,并且两者都有特定范围内的饱和度值。因此,我只选择饱和度值在这个范围之间的像素。通过过滤掉明度值较小的像素点,可以在明度信道中检测出白色。
区域掩码是消除图像中不太可能包含车道线的部分的过程。我们可以看到,车道线大多出现在图像的下半部分,因此在图像的上半部分屏蔽像素将提高我们检测车道线的准确率,因为图像现在只包含更有可能是车道线的一部分的像素。
4. 寻找车道像素
下一步,我们需要分类哪些像素位于左车道、右车道或两者都不是。之后,我们将找到最适合所有左车道像素的多项式方程和最适合所有右车道像素的另一个方程。
首先,我对图像下半部分的所有列都做了一个直方图。在我们的阈值化二值图像中,像素要么是0,要么是1,所以这个直方图中最突出的两个峰值将很好地指示车道线基线的 x 位置。
我们可以用它作为搜索线条的起点。然后,在图像上我们可以使用一个滑动窗口向上移动(进一步沿着道路) ,以确定在车道线走向。
5. 寻找车道曲线并测量曲率
我们已经估计了哪些像素属于左线和右线(分别以蓝色和红色显示) ,并且我们已经拟合了这些像素位置的多项式。我们可以用这个多项式来计算车道曲率的半径以及车辆离车道中心的距离。
回忆一下,我们找车道线的方程式:
这是 y 而不是 x 的函数的原因是,因为在转换后的图像中,车道线是近乎垂直的,可能多个 y 值具有相同的 x 值。
这里 x 和 y 的单位是像素,但是我们想把它转换成米来计算车道曲率和车辆的位置。假设两条车道线之间的距离(像素坐标)为700像素。在现实生活中,这个距离大约是12英尺或3.7米。因此,水平方向上的每个像素相当于现实生活中的3.7/700米。我们把这个值称为 mx = 3.7/700。在垂直方向上做同样的操作,我们得到 my = 30/720,每720个垂直像素表示30米。转换过程是这样的:
函数 x=f(y) 任意点的曲率半径如下得出:
这很容易计算,因为我们只需要计算我们的函数的一阶和二阶导数。
接下来,我们要计算我们的车离车道中心有多远。这可以通过计算车道中心和图像中心之间的水平距离(以像素为单位)来实现。之后,我们可以乘以常量 mx 来转换为现实中的距离。
6. 将结果显示回原始图像
最后一步是将前一步的结果与原始图像结合起来。
要做到这一点,我们需要恢复前面所做的透视变换,并将输出图像置于原始图像之上。
总结
这个特殊的 pipeline 在正常和阴暗(这时车道线很难看见)的条件下工作良好。然而,由于这个 pipeline 的参数数量有限,它不够鲁邦,无法在雨雪等极端条件下表现良好。
总而言之,只要把几个算法放在一起,我们就可以创建一个能够检测车道线的 pipeline。首先,我们对摄像头失真进行了校正。然后,我们将其转换为鸟瞰图,过滤掉图像中不相关的部分,并使用“滑动窗口”找到车道像素。最后,计算车道线方程并测量车道曲率。详细的实现,请查看我 Github 上的项目:https://github.com/Dt-Pham/Advanced-Lane-Lines
来源:https://medium.com/@dt99.pham/self-driving-car-finding-lane-lines-7f7312997a6f