3. 点云预处理

点云预处理,说白了就是给原始点云「洗个澡」。你想想看,不管是激光雷达扫出来的,还是深度相机拍出来的,原始数据里总带着一堆乱七八糟的东西——噪声点、离群点、还有那些根本不需要的背景点。我刚开始做无序分拣那会儿,就吃过这个亏:直接把原始点云丢给分割算法,结果程序跑了一分钟,最后抓了个寂寞。

所以这一章,咱们就把预处理这四板斧练熟。嗯,一个一个来。

3.1 体素滤波降采样

体素滤波,也叫Voxel Grid Filter。它的思路特别简单:把空间切成一个个小立方体(体素),每个立方体里只保留一个点。这个点通常是体素内所有点的重心,或者直接取中心点。

为什么要降采样?我遇到过一台老旧的工控机,处理10万点的点云还能凑合,但一旦上了50万点,帧率直接掉到2帧。体素滤波一上,点云缩到1万点,算法跑得飞起,精度还没怎么掉。

核心参数:体素大小(leaf size)。设得越小,保留的点越多;设得越大,点云越稀疏。一般无序分拣场景,我习惯设 0.01m ~ 0.02m。
// C++ PCL 示例
pcl::VoxelGrid<pcl::PointXYZ> vg;
vg.setInputCloud(cloud);
vg.setLeafSize(0.01f, 0.01f, 0.01f);
vg.filter(*cloud_filtered);
我的小技巧:体素大小不要一刀切。如果抓取目标是小零件(比如螺丝、螺母),体素设 0.005m;如果是大件(比如快递包裹),0.02m 起步。

3.2 统计滤波去噪

统计滤波,英文叫Statistical Outlier Removal,简称SOR。它的逻辑是:每个点周围都有邻居,如果某个点离邻居太远,那它大概率是个噪声点。

具体做法是:对每个点,计算它到所有邻居的平均距离。如果这个平均距离超出了全局均值加几倍标准差的范围,就把它干掉。

我曾经在一个仓库项目里,点云里总飘着几个「幽灵点」——离主物体老远,孤零零的。一开始以为是传感器坏了,后来发现是反光表面造成的。统计滤波一过,干干净净。

参数 含义 我常用的值
MeanK 邻居点数 50
StddevMulThresh 标准差倍数 1.0 ~ 2.0
// C++ PCL 示例
pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;
sor.setInputCloud(cloud_filtered);
sor.setMeanK(50);
sor.setStddevMulThresh(1.0);
sor.filter(*cloud_denoised);
注意:StddevMulThresh 设得太小(比如 0.5),会把正常点也误删;设得太大(比如 5.0),噪声点根本去不掉。我建议你先用 1.0 试跑,看效果再调。

3.3 直通滤波

直通滤波,PassThrough Filter,名字很直白——只让某个轴方向上的点通过。比如你只想要深度 0.5m 到 1.2m 之间的点,那就设一个范围,之外的统统砍掉。

这个滤波器在无序分拣里特别实用。你想啊,传送带上的工件只在某个高度范围内,背景的墙壁、地面、远处的架子,全都可以一刀切掉。我习惯先做直通滤波,再做降采样,这样计算量更小。

// C++ PCL 示例
pcl::PassThrough<pcl::PointXYZ> pass;
pass.setInputCloud(cloud_denoised);
pass.setFilterFieldName("z");
pass.setFilterLimits(0.5, 1.2);
pass.filter(*cloud_passed);
避坑指南:我曾经在一条产线上,直通滤波设了 x 轴范围,结果把工件的一部分切掉了。后来发现是工件摆放角度偏了,导致 x 坐标超出预期。所以,直通滤波的边界最好留 10%~20% 的余量。

3.4 点云法向量估计

法向量,就是点云表面每个点的朝向。它本身不是「滤波」,但它是后续分割、配准、抓取姿态估计的基础。没有法向量,你连物体是横着还是竖着都判断不了。

估计法向量的原理很简单:对每个点,找它的 k 个邻居,拟合一个平面,平面的法线就是该点的法向量。嗯,这里要注意:法向量的方向是二义性的,需要做定向处理。

我记得第一次做法向量估计时,没注意邻居数 k 的选择。k 设得太小,法向量全是噪声;k 设得太大,边缘细节全被磨平了。后来总结出一套经验:

场景 推荐 k 值 说明
高密度点云(>100点/cm²) 10 ~ 20 细节保留好
中等密度点云 20 ~ 50 平衡精度与平滑
稀疏点云(<10点/cm²) 50 ~ 100 防止法向量不稳定
// C++ PCL 示例
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
ne.setInputCloud(cloud_passed);
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
ne.setSearchMethod(tree);
ne.setKSearch(20);
ne.compute(*cloud_normals);
关键点:法向量估计前,一定要确保点云已经做过降采样和去噪。否则,噪声点的法向量会带偏周围一片。

3.5 本章知识体系

下面这张图,把四种预处理方法的流程和关系画清楚了。你可以把它当作一个检查清单:拿到原始点云后,按这个顺序走一遍,基本不会漏。

点云预处理流程 原始点云 ① 直通滤波 ② 体素滤波降采样 ③ 统计滤波去噪 ④ 法向量估计 顺序说明 1. 先直通滤波,砍掉背景 2. 再降采样,减少点数 3. 然后去噪,清理离群点 4. 最后估计法向量 参数调优建议 体素大小:0.01~0.02m 统计滤波:MeanK=50, Thresh=1.0