读取图像或视频帧
下面,有 3 个加载图像的示例。稍后,在每个步骤之后,将显示这些样本图像的中间结果。第三张图像对处理要求最高,因为黄线和道路之间的阴影和对比度非常小。
过滤白色和黄色
对于前两个更简单的图像,此步骤不是必需的。然而,在第三个示例中,直接进行下一步(灰度转换)会为黄色车道和明亮的道路产生非常相似的灰色。我们想以某种方式区分这两个对象。因此,初始过滤作为道路车道主要组成部分的 2 个关键颜色的想法。首先,将图像转换为HSL 颜色空间。HSL(色相、饱和度、亮度)色彩空间概念是基于人类视觉的色彩感知。这就是为什么即使图像上有阴影,也比在 RGB 空间中更容易区分所需颜色(黄色和白色)。
为了提取白色,我只过滤了 HSL 颜色空间的“L”分量中的高亮度。对于黄色通道,我选择色调等于或多或少 30 以选择黄色,并且 Ii 过滤饱和度非常高。下面是经过这种过滤的测试图像。
转换为灰度
与许多计算机视觉应用程序一样,图像被转换为灰度。这主要是为了进一步操作的简单性和速度。例如,边缘检测器会发现相邻像素之间的大梯度。因此,与 RGB 或 HSL 颜色空间相比,仅比较一维(灰度)像素会更容易。
高斯模糊
为了抑制噪声和杂散梯度,应用了高斯平滑。在这里,它再次为边缘检测步骤做准备。车道和道路之间的边界不能那么平滑,因此我们不希望边缘检测器将此类区域分类为附加线。平滑内核的大小定义了输出的模糊程度以及这种操作需要多少时间。
边缘检测
为了检测边缘,让我们使用流行的Canny方法。它使用 2 个参数调用:低阈值和高阈值,应通过反复试验找到。根据 OpenCV 文档:
- 如果像素梯度高于上限阈值,则该像素被接受为边缘
- 如果像素梯度值低于下阈值,则将其拒绝。
- 如果像素梯度在两个阈值之间,那么只有当它连接到高于上限阈值的像素时才会被接受。
Canny 推荐了 2:1 和 3:1 之间的上下比例。我选择了 80 和 40 的值。下面是这个操作的输出。
感兴趣区域定义
为了过滤掉图像中不必要的对象,定义了感兴趣区域。然后将这样的蒙版(这里是梯形)应用于工作图像。
这是这种掩蔽的结果:
霍夫线检测
现在,在我们感兴趣的区域中检测到边缘后,需要识别所有直线。这是通过此处另一篇文章中解释的霍夫变换完成的。这个操作有很多参数需要通过实验来调整。从高层次上讲,它们定义了像素序列应该被分类为一条线的长度或“直线”程度。OpenCV文档中有一个很好的例子,关于特征提取,显示了示例图像上的霍夫线变换的结果。
下面是我们测试过的图像,其中发现的霍夫线以绿色绘制。
过滤霍夫线
正如我们在上面看到的,有些线段是不需要的。例如,在感兴趣区域内的汽车上出现的小水平线或一些线。因此,对于每条霍夫线,我们计算一个斜率参数。经过一些实验,只留下了坡度在 17 到 56 度之间的线,以供进一步分析。
下面,只有过滤的霍夫线。
平均线段
所有找到的霍夫线现在应该被平均/外推以仅产生两条代表车道的线。第一个任务是将线分成两组(左和右——从斜率符号推导出来)。然后,可以对表示线段的点使用最佳线性拟合或从这些线中取平均值。我决定应用加权平均来计算得到的斜率和截距。在这里,线段的长度用作权重。段越长,对结果的影响越大。此外,为了放大片段长度的重要性,权重计算为长度参数的平方。
在最终行上应用移动平均线
在视频流上运行管道时,我们可以观察到线条在闪烁。为避免这种情况,我们可以应用线参数的累积移动平均线。对于每一帧,它平均最后n 个结果,包括当前结果。此方法的累积版本对最近的结果应用更大的权重。通过将最后一个平均帧保存在内存中,我们也可以在帧中因某些错误而找不到行的情况下使用它。
结果和可能的改进
然而,它只检测直线,这些直线可能可以通过使用某种高阶多项式拟合来处理弯曲车道来克服。另外,当另一辆车出现在我们感兴趣的区域时会发生什么?它可以产生一些可以被识别为车道的线。我们可能应该同时检测到这样的汽车,以确保这样的物体绝对不是车道。如果我们从/上坡开车怎么办?然后,预定义的感兴趣区域可能不再有效。我还想知道当道路上标记一些白色/黄色平面标志时会发生什么。应测试此类特殊情况以及夜间驾驶,并应应用一些附加功能以避免错误的车道线检测。