PCL去离群点 之SOR和ROR详解
在 Point Cloud Library 里,去离群点最经典的就是:
- SOR:StatisticalOutlierRemoval(统计滤波)
- ROR:RadiusOutlierRemoval(半径滤波)
- SOR:用“统计分布”找异常点(全局思维)
- ROR:用“局部密度”找孤立点(局部思维)
一、SOR(统计离群点)详解
核心思想(本质)
用统计学判断“谁不合群” SOR = 看每个点“和邻居的平均距离”,太远的就是离群点
步骤:
- 对每个点 pi,找 K 个邻居
- 计算这些邻居的平均距离
- 得到所有点的距离分布(近似高斯)
- 超过阈值的点 → 删除
数学直觉
这就是StddevMulThresh
特点总结
自适应(自动根据数据分布)
对随机噪声非常鲁棒
在边缘容易误删
典型效果
- 去掉“漂浮噪声”
- 点云整体更干净
- 保持结构
举例说明
假设有一段 1D 点(为了简单):
正常点: 0.0, 0.1, 0.2, 0.15, 0.18 离群点: 5.0步骤1:对每个点找邻居(假设 K=3)
比如:
点 0.1:
邻居:0.0, 0.2, 0.15
平均距离:
点 5.0(离群点):
步骤2:统计所有点的“平均距离分布”
| 点 | 平均距离 |
|---|---|
| 正常点 | ~0.08 |
| 离群点 | ~4.82 |
步骤3:计算均值 + 标准差
步骤4:设阈值(StddevMulThresh = 1)
| 值 | 效果 |
|---|---|
| 小(10) | 不稳定 |
| 中(30~50) | 推荐 |
| 大(100) | 平滑但慢 |
| 值 | 效果 |
|---|---|
| 0.5 | 删很多(激进) |
| 1.0 | 常用 |
| 2.0 | 保守 |
pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor; sor.setInputCloud(cloud); // 每个点找50个邻居 sor.setMeanK(50); // 标准差倍数(越小越严格) sor.setStddevMulThresh(1.0); sor.filter(*cloud_filtered);二、ROR(半径离群点)详解
核心思想
用“邻居数量”判断是否孤立
步骤:
- 对每个点画一个半径 rrr
- 统计邻居数量 NNN
- 如果:
本质理解
空间密度约束
- 正常区域:点密集
- 离群点:孤零零
特点总结
直观、可控
对“孤立点”非常有效
对密度变化敏感(致命点)
| r | 效果 |
|---|---|
| 小 | 删得多(容易误删) |
| 中 | 推荐 |
| 大 | 几乎不删 |
| 值 | 效果 |
|---|---|
| 小(2~5) | 宽松 |
| 中(5~20) | 常用 |
| 大(50+) | 严格 |
pcl::RadiusOutlierRemoval<pcl::PointXYZ> ror; ror.setInputCloud(cloud); // 搜索半径(单位:米) ror.setRadiusSearch(0.05); // 最少邻居数 ror.setMinNeighborsInRadius(10); ror.filter(*cloud_filtered);三、SOR vs ROR 本质区别(重点)
| 维度 | SOR | ROR |
|---|---|---|
| 判断依据 | 距离统计 | 邻居数量 |
| 是否自适应 | ✅ 是 | ❌ 否 |
| 对密度变化 | 稳定 | 敏感 |
| 对孤立点 | 一般 | 很强 |
| 对边缘 | 易误删 | 保留好 |
| 参数难度 | 中等 | 高(依赖尺度) |
