4、地面与非地面分割:三种主流方法深度解析
地面分割这件事,说实话,是激光雷达感知里最基础但也最容易被忽视的一环。我刚开始做自动驾驶时,总觉得地面分割嘛,随便找个平面拟合就完事了。结果呢?车在坡道上直接漏检了一根车道线,差点出事。从那以后,我再也不敢小看这个模块了。
今天咱们就聊聊三种主流的地面分割方法。每种方法都有自己的脾气,你得根据场景来选。
4.1 基于RANSAC的平面拟合
RANSAC,全称是Random Sample Consensus。说白了,就是在一堆点里,反复随机挑几个点去拟合一个平面,然后看看有多少点支持这个平面。支持最多的那个,就是地面。
我个人习惯用RANSAC做快速验证。代码写起来简单,效果也还行。
// 伪代码示例
int maxIterations = 100;
double distanceThreshold = 0.1; // 单位:米
for (int i = 0; i < maxIterations; i++) {
// 随机选3个点
Point p1 = points[rand() % N];
Point p2 = points[rand() % N];
Point p3 = points[rand() % N];
// 计算平面方程 ax + by + cz + d = 0
Plane plane = fitPlane(p1, p2, p3);
// 统计内点数量
int inliers = 0;
for (auto& p : points) {
double dist = distanceToPlane(p, plane);
if (dist < distanceThreshold) inliers++;
}
// 记录最优平面
if (inliers > bestInliers) {
bestPlane = plane;
bestInliers = inliers;
}
}
注意:RANSAC有个致命问题——它假设地面是平的。你想想看,真实道路哪有那么平?遇到坡道、减速带,RANSAC直接就懵了。我曾经在高速匝道上吃过这个亏,地面分割后车道线全断了。
我的建议:RANSAC适合做预处理,比如快速剔除大部分地面点。但别指望它搞定复杂场景。迭代次数设到100-200次就够了,再多就是浪费算力。
4.2 基于射线坡度的地面分割
这个方法就聪明多了。它把激光雷达的扫描线想象成一条条射线,从中心往外发射。每条射线上,相邻点之间的坡度变化,就是判断地面的关键。
为什么会这样?因为地面上的点,坡度变化是连续的、缓慢的。而障碍物上的点,坡度会突然跳变。
具体做法是这样的:
- 把点云按角度分到不同的射线(bin)里
- 对每条射线,按距离排序
- 计算相邻点的坡度(高度差 / 水平距离)
- 坡度小于阈值的,认为是地面点
// 射线坡度分割核心逻辑
double slopeThreshold = 0.1; // 坡度阈值,约5.7度
for (auto& ray : rays) {
sortByDistance(ray.points);
for (int i = 1; i < ray.points.size(); i++) {
double dz = ray.points[i].z - ray.points[i-1].z;
double dr = hypot(
ray.points[i].x - ray.points[i-1].x,
ray.points[i].y - ray.points[i-1].y
);
double slope = dz / dr;
if (abs(slope) < slopeThreshold) {
markAsGround(ray.points[i]);
} else {
markAsObstacle(ray.points[i]);
}
}
}
核心优势:射线坡度法天然适应坡道。因为它是局部比较,不是全局拟合。上坡、下坡都能处理。我在城市道路场景里,基本都用这个方法。
不过,它也有弱点。如果地面有坑洼或者小石子,坡度会剧烈变化,容易误判。嗯,这里要注意,阈值不能设得太死。
4.3 基于Patchwork的地面分割
Patchwork是近两年比较火的方法。它把点云分成一个个小网格(patch),每个网格独立判断是不是地面。最后再把这些小网格拼起来,形成完整的地面。
我个人觉得,Patchwork是这三种方法里最鲁棒的。它结合了局部信息和全局信息。
具体流程:
- 把点云投影到二维网格(比如50x50的网格)
- 每个网格内,计算最低点、最高点、平均高度
- 用这些特征判断网格是不是地面
- 相邻地面网格合并,形成完整地面
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| RANSAC | 简单、快速 | 假设地面平坦 | 停车场、高速公路 |
| 射线坡度 | 适应坡道 | 对噪声敏感 | 城市道路、乡村路 |
| Patchwork | 鲁棒性高 | 计算量大 | 复杂场景、越野 |
避坑指南:我曾经在雨雪天用Patchwork,发现地面分割效果变差。后来排查发现,是雨滴和雪花被当成了地面点。解决办法是加一个高度滤波,把离群点先滤掉。
4.4 三种方法的对比与选择
你可能会问,到底该用哪个?我的经验是这样的:
- 如果只是做Demo,RANSAC就够了,5分钟搞定
- 如果是量产项目,建议用射线坡度法,效率高、效果好
- 如果场景特别复杂(比如越野、矿区),上Patchwork
其实,很多量产方案是混合使用的。先用RANSAC粗分割,再用射线坡度法精调。这样既快又准。
一句话总结:地面分割没有银弹。你得根据传感器安装高度、道路类型、计算资源来选。我建议你把这三种方法都实现一遍,跑跑自己的数据,自然就知道哪个适合你了。
这张图很直观。原始点云进来,三条路都能走。但最终目的都一样——把地面和非地面分开,然后只对非地面点做车道线检测。你想想看,如果地面点不滤掉,车道线检测算法会疯掉的,到处都是干扰。
我的小技巧:实际部署时,我习惯把三种方法的结果做个投票。两个方法都认为是地面的点,才标记为地面。这样误检率能降低不少。当然,计算量会大一些,但现在的硬件完全扛得住。
好了,地面分割就聊到这儿。这三种方法你都可以试试,跑跑自己的数据,看看哪个效果最好。记住,没有最好的方法,只有最适合你场景的方法。