3. 点云生成与聚类
各位同学,今天我们来聊聊点云处理这个核心环节。说实话,点云这东西,刚接触时觉得挺简单——不就是一堆三维坐标点嘛?但真正做项目时才发现,这里面的门道可不少。
我最早做雷达融合时,拿到点云数据直接往上堆算法,结果系统跑起来卡得要命。后来才明白,点云处理的关键不在于算法多花哨,而在于数据结构选得对不对、预处理做没做到位。
点云数据结构:选对容器很重要
点云本质上是一组三维空间中的点,每个点通常包含(x, y, z)坐标,还可能带有强度、速度、时间戳等信息。但怎么组织这些数据,直接影响后续处理的效率。
我个人习惯用两种结构:
- 无序点云:就是一个点列表,简单直接。适合小规模数据(几千点以内)。
- 有序点云:按扫描线或帧结构组织,类似图像。毫米波雷达通常输出这种结构,因为每个chirp对应一条扫描线。
嗯,这里要注意:毫米波雷达的点云密度远低于激光雷达。我见过有人直接把激光雷达的PCL库搬过来用,结果发现KD-Tree建树的时间比处理点云本身还长。说白了,选数据结构要跟数据规模匹配。
// 一个简单的毫米波点云结构体
typedef struct {
float x; // 横向距离 (m)
float y; // 纵向距离 (m)
float z; // 高度 (m)
float velocity; // 径向速度 (m/s)
float snr; // 信噪比 (dB)
uint32_t timestamp; // 时间戳 (us)
} MMWavePoint;
// 点云帧结构
typedef struct {
uint32_t point_num;
MMWavePoint points[MAX_POINTS];
uint64_t frame_id;
} PointCloudFrame;
点云滤波:先把垃圾扔掉
雷达原始点云里,噪声点、杂散点特别多。我做过统计,某些场景下有效点可能只占30%。所以滤波是第一步,也是最重要的一步。
常用的滤波方法:
- 直通滤波:按距离、速度范围直接切掉。比如我只关心0-50米内的目标,超出的一律丢弃。
- 统计滤波:计算每个点邻域内的平均距离,离群太远的点去掉。这个对去除随机噪声很有效。
- 半径滤波:如果一个点周围指定半径内点数太少,就认为是孤立噪声点。
DBSCAN聚类:密度相连的才是兄弟
DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是我最常用的聚类算法。为什么?因为它不需要预先指定聚类数量,而且能很好地处理噪声点。
核心思想很简单:
- 如果一个点周围半径ε内有至少MinPts个点,它就是核心点
- 核心点之间密度相连的归为一类
- 剩下的就是噪声点
参数选择上,我一般这样设:
- ε(邻域半径):毫米波雷达我常用0.5-1.5米。太小会把一个目标拆成好几块,太大又会把相邻目标合并。
- MinPts(最小点数):3-5个。行人可能只有2-3个点,车辆可能有10-20个点。
// DBSCAN核心逻辑(简化版)
void dbscan_cluster(PointCloud* cloud, float eps, int min_pts) {
int cluster_id = 0;
for (int i = 0; i < cloud->size(); i++) {
if (cloud->points[i].visited) continue;
cloud->points[i].visited = true;
// 找邻域内的点
std::vector<int> neighbors = range_query(cloud, i, eps);
if (neighbors.size() < min_pts) {
cloud->points[i].label = NOISE; // 标记为噪声
} else {
cluster_id++;
expand_cluster(cloud, i, neighbors, cluster_id, eps, min_pts);
}
}
}
欧式聚类:距离近的就是一家人
欧式聚类(Euclidean Clustering)比DBSCAN更直观——就是按欧氏距离把相近的点归到一起。它其实可以看作是DBSCAN的一个特例,当MinPts=1时,两者等价。
实现步骤:
- 建KD-Tree加速近邻搜索
- 选一个未处理的点作为种子
- 找距离小于阈值的所有点,加入当前簇
- 对簇内新加入的点重复步骤3,直到没有新点加入
- 重复步骤2-4,直到所有点都被处理
欧式聚类的优点是速度快、实现简单。缺点是对密度变化敏感——稀疏区域和密集区域用同一个距离阈值效果不好。
实际项目中的选择:
- 场景简单、点云均匀 → 用欧式聚类,速度快
- 场景复杂、噪声多、密度变化大 → 用DBSCAN,鲁棒性好
- 实时性要求极高 → 欧式聚类+适当下采样
知识体系总览
下面这张图概括了本章的核心逻辑,从原始点云到最终聚类结果的完整流程:
实际项目中的避坑指南
最后分享几个我踩过的坑:
- 坐标系统一:雷达坐标系和车体坐标系往往有偏移,聚类前一定要做好坐标变换。我见过有人忘了做这个,结果聚类出来的目标位置全偏了。
- 速度信息别浪费:毫米波雷达有速度测量能力,聚类时把速度作为一个维度加入距离计算,能更好地区分相邻但运动方向不同的目标。
- 实时性优化:如果每帧点云超过2000个点,建议先做下采样。我一般用体素滤波,把0.2m立方体内的点合并成一个,既保留形状又减少数据量。
好了,点云生成与聚类这部分就讲到这里。记住:数据结构选对、滤波做到位、聚类参数调好,这三步走稳了,后面的目标跟踪和融合才能做好。