3. 传感器数据处理:激光雷达点云滤波、聚类与特征提取

大家好,我是你们的老朋友。今天咱们聊聊激光雷达的数据处理。说实话,很多新手一上来就急着跑算法,结果点云数据乱七八糟,后面决策全崩了。我当年也踩过这个坑——有一次在园区测试,车突然对着一个垃圾桶急刹,后来发现是点云没滤干净,把垃圾桶当成了行人。嗯,从那以后,我养成了一个习惯:先花 70% 的精力把数据洗干净,再谈后面的决策。

这一章,我们就聚焦在三个核心环节:滤波、聚类、特征提取。说白了,就是把原始点云变成机器人能理解的障碍物信息。

3.1 点云滤波:去噪与下采样

激光雷达扫出来的原始点云,其实挺脏的。有飘在空中的噪点,有地面反射的杂波,还有远处的稀疏点。你想想看,如果把这些都喂给聚类算法,结果会怎样?

我个人习惯,先做两步滤波:

  • 直通滤波(PassThrough):直接砍掉距离太远或太近的点。比如我只保留 0.5m 到 50m 范围内的点,超出这个范围的,要么是车身上的点,要么是噪声。
  • 体素滤波(VoxelGrid):把空间切成小立方体,每个立方体只保留一个代表点。这样点云数量能减少 80% 以上,但形状特征基本保留。

重要经验:体素滤波的格子大小很关键。设太大,障碍物细节丢失;设太小,计算量降不下来。我在项目中一般设 0.1m 到 0.2m,具体看激光雷达的线束密度。

下面是我常用的滤波代码片段:

# 直通滤波
pass_through = cloud_filtered.passthrough(filter_axis='z', 
                                         min_range=-0.5, 
                                         max_range=2.0)

# 体素滤波
voxel_filter = cloud_filtered.voxel_grid_filter(leaf_size=0.15)

小技巧:如果你用的是 16 线雷达,体素大小建议 0.2m;如果是 64 线或 128 线,可以缩到 0.1m。线束越多,点越密,格子就可以设小一点。

3.2 点云聚类:把点变成块

滤波之后,我们得到了一堆干净的点。但机器人需要知道:哪些点属于同一个障碍物?这就靠聚类了。

最常用的方法是 欧几里得聚类(Euclidean Clustering)。它的逻辑很简单:如果两个点之间的距离小于某个阈值,就认为它们属于同一个物体。

我记得有一次在雨雾天气测试,点云变得特别稀疏,聚类阈值设小了,一个行人被分成了三块;设大了,又把旁边的树和行人粘在一起。后来我总结了一个经验:

  • 聚类半径:一般设 0.3m 到 0.5m。室内场景可以小一点,室外大一点。
  • 最小点数:少于 5 个点的簇直接丢弃,大概率是噪声。
  • 最大点数:超过 5000 个点的簇,可能是墙面或大型车辆,需要单独处理。

避坑指南:我曾经在高速场景下,把路边的护栏和一辆静止的轿车聚在了一起。原因是护栏的点太密,聚类半径覆盖了车。后来我加了距离自适应——近处用大半径,远处用小半径,效果好了很多。

聚类后的效果,可以用下面这张图来理解:

点云聚类前后对比 原始点云(散乱) 聚类后(分块) 行人 车辆 噪声(丢弃)

3.3 特征提取:从块到属性

聚类之后,我们有了一个个障碍物点云块。但机器人还需要知道:这个块是什么?它有多大?它朝哪个方向运动?

特征提取就是干这个的。我一般提取以下几类特征:

特征类别 具体特征 计算方法 用途
几何特征 中心点、长宽高、体积 计算点云的最小包围盒 判断障碍物大小
形状特征 线性度、平面度、散度 PCA 分解点云协方差矩阵 区分行人(散状)vs 车辆(平面状)
运动特征 速度、加速度、运动方向 多帧跟踪 + 卡尔曼滤波 预测障碍物未来位置
统计特征 点云数量、密度、强度均值 直接统计 辅助分类(如金属反射强度高)

这里重点说一下形状特征。为什么它重要?你想想看,一个行人和一根电线杆,在点云里可能大小差不多,但形状完全不同。行人点云比较散乱,而电线杆的点云呈细长条状。

我常用的方法是 PCA(主成分分析)。简单来说,就是计算点云的三个主方向,然后看它们的比值:

  • 线性度(Linearity):如果点云主要沿一个方向分布,说明是细长物体(如电线杆、树干)。
  • 平面度(Planarity):如果点云主要分布在两个方向上,说明是平面物体(如墙面、车辆侧面)。
  • 散度(Scatter):如果三个方向分布均匀,说明是散乱物体(如行人、灌木丛)。

实战经验:我在做行人检测时,发现单纯靠几何大小(比如宽度 0.5m)会误检很多。后来加了散度特征,行人的散度一般在 0.3 以上,而车辆在 0.1 以下。这个阈值帮我过滤掉了 90% 的误检。

特征提取的代码示例:

# 计算点云协方差矩阵
cov_matrix = np.cov(points.T)

# PCA 分解
eigenvalues, eigenvectors = np.linalg.eig(cov_matrix)

# 归一化特征值
eigenvalues = np.sort(eigenvalues)[::-1]
linearity = (eigenvalues[0] - eigenvalues[1]) / eigenvalues[0]
planarity = (eigenvalues[1] - eigenvalues[2]) / eigenvalues[0]
scatter = eigenvalues[2] / eigenvalues[0]

小提示:如果你用的是 ROS,PCL 库里有现成的 MomentOfInertiaEstimation 类,可以直接算包围盒和特征值。但建议自己手写一遍 PCA,理解原理后调参才不慌。

3.4 本章小结

好了,这一章的内容就这些。总结一下核心要点:

  1. 滤波:直通滤波砍范围,体素滤波降密度。别偷懒,这一步做不好,后面全是白费。
  2. 聚类:欧几里得聚类最常用,注意半径和点数阈值。雨雾天气记得调参。
  3. 特征提取:几何特征看大小,形状特征看 PCA,运动特征靠跟踪。三者结合才能准确判断障碍物类型。

说实话,传感器数据处理这部分,看起来基础,但真正做好的工程师不多。我见过太多人直接拿开源代码跑,结果在真实场景里各种翻车。嗯,希望你能沉下心来,把每一步都吃透。

下一章,我们会把这些处理好的障碍物信息,用到决策规划里去。到时候你就知道,今天花的时间,绝对值。

可可精品资料库