4、车道线检测基础:传统图像处理方法
各位同学好,今天我们来聊聊车道线检测中最基础、也最经典的一套组合拳——边缘检测、霍夫变换、RANSAC拟合。说实话,虽然现在深度学习很火,但传统方法在嵌入式平台、低算力场景下依然有不可替代的优势。我自己在早期做量产项目时,就是靠这套方法撑过了大半年。
4.1 边缘检测:找到图像中的“突变”
车道线在图像里是什么?说白了,就是路面上一道颜色突变的边界。边缘检测的任务,就是把这些突变点找出来。
我个人最常用的是 Canny 边缘检测。它比单纯的 Sobel 算子要稳定得多。为什么?因为它做了“非极大值抑制”和“双阈值滞后处理”。
核心流程:
- 高斯滤波去噪(先模糊,再求导,避免噪声干扰)
- 计算梯度幅值和方向(Sobel 算子)
- 非极大值抑制(只保留梯度方向上的局部最大值)
- 双阈值检测(高阈值确定强边缘,低阈值连接弱边缘)
嗯,这里要注意:双阈值的设置很关键。我见过不少新手把高阈值设得太高,结果车道线断成一段一段的。我的经验是,高阈值取 150-200,低阈值取 50-80,具体要看你的图像对比度。
// C++ 示例:Canny 边缘检测
cv::Mat gray, edges;
cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);
cv::GaussianBlur(gray, gray, cv::Size(5, 5), 1.5);
cv::Canny(gray, edges, 50, 150); // 低阈值50,高阈值150
我的小技巧: 在项目里,我习惯先对图像做 ROI 裁剪,只保留车道线可能出现的区域(比如下半部分)。这样能减少大量无关边缘,提升后续处理速度。
4.2 霍夫变换:从边缘点到直线
边缘检测完,你得到的是一个个离散的像素点。怎么把这些点变成一条完整的车道线?霍夫变换就是干这个的。
它的思想很巧妙:把图像空间中的点,映射到参数空间中的曲线。在参数空间中找交点,交点对应的就是图像空间中的直线。
常用的有两种:
- 标准霍夫变换:用 (ρ, θ) 参数空间,检测直线
- 概率霍夫变换:只随机采样部分点,效率更高
我在项目中几乎只用概率霍夫变换。为什么?因为标准霍夫变换会把所有可能的直线都找出来,包括那些只有两三个点组成的“伪直线”。概率霍夫变换可以设置最小线段长度和最大间隔,过滤掉这些噪声。
// C++ 示例:概率霍夫变换
std::vector<cv::Vec4i> lines;
cv::HoughLinesP(edges, lines, 1, CV_PI/180, 50, 30, 10);
// 参数:rho=1, theta=1度, 阈值=50, 最小线段长度=30, 最大间隔=10
我曾经踩过的坑: 霍夫变换的阈值设得太低,结果把路边的护栏、阴影都当成车道线了。后来我加了一个角度约束——只保留角度在 30°~150° 之间的线段。因为车道线在图像中基本是斜的,不会出现水平或垂直的线。
4.3 RANSAC 拟合:对抗噪声的利器
霍夫变换出来的线段,往往还是断断续续的。而且受路面纹理、光照变化影响,会有不少离群点。这时候就需要 RANSAC 出场了。
RANSAC 的全称是 Random Sample Consensus,随机抽样一致。它的核心思想是:从数据中随机选一小部分点拟合模型,然后看其他点对这个模型的“支持度”。支持度高的模型,就是我们要的。
你想想看,如果直接用最小二乘法拟合,离群点会把结果拉偏。但 RANSAC 只信任“内点”,所以鲁棒性很强。
| 方法 | 优点 | 缺点 |
|---|---|---|
| 最小二乘法 | 计算快,数学形式简单 | 对离群点敏感,一个坏点就能毁掉结果 |
| RANSAC | 抗离群点能力强,鲁棒性好 | 需要迭代,计算量稍大;需要设置阈值 |
// 伪代码:RANSAC 直线拟合
for (int i = 0; i < maxIterations; i++) {
// 1. 随机选两个点
Point p1 = randomPoint(points);
Point p2 = randomPoint(points);
// 2. 由这两个点确定一条直线
Line model = fitLine(p1, p2);
// 3. 计算所有点到这条直线的距离
int inliers = 0;
for (auto& pt : points) {
if (distance(pt, model) < threshold) {
inliers++;
}
}
// 4. 如果内点数量超过当前最优,更新模型
if (inliers > bestInliers) {
bestModel = model;
bestInliers = inliers;
}
}
我的经验: RANSAC 的迭代次数和距离阈值怎么设?我一般先设 100 次迭代,阈值 3-5 个像素。如果场景噪声大(比如雨天、夜晚),我会把迭代次数提到 200,阈值放宽到 8 个像素。另外,记得在拟合完后再用所有内点做一次最小二乘优化,这样精度更高。
4.4 三者如何配合?
这三步是串行工作的:
- 边缘检测:把彩色图像变成二值边缘图
- 霍夫变换:从边缘图中提取候选线段
- RANSAC 拟合:从候选线段中拟合出最终的车道线模型
我画了一张流程图,帮你理清这个流程:
这个流程看起来简单,但实际工程中坑不少。我举个例子:在隧道里,光照变化剧烈,Canny 的边缘检测结果会很不稳定。我的做法是动态调整 Canny 的阈值——根据图像的平均亮度,自动把阈值调高或调低。
总结一下这套方法的优缺点:
- 优点:计算量小,实时性好;不需要训练数据;在结构化道路上表现稳定
- 缺点:对光照、阴影、磨损的车道线敏感;无法处理弯道(只能拟合直线);需要手动调参
好了,这就是传统车道线检测的三大法宝。下一章我们会聊怎么把这些方法跟定位系统融合起来。嗯,先消化一下今天的内容,有问题随时问我。