第4章 点云可视化:让数据“说话”
点云可视化,说白了就是给你的激光雷达数据装上一双眼睛。我刚开始做感知时,总觉得算法跑通了就行,直到有一次调试地面分割,死活找不到参数问题——后来可视化一看,原来是坐标系搞反了。嗯,从那以后我再也不敢跳过可视化这一步了。
4.1 用PCL可视化点云——基础操作
PCL里最常用的可视化工具就是 pcl::visualization::PCLVisualizer。我个人习惯把它封装成一个函数,方便反复调用。
#include <pcl/visualization/pcl_visualizer.h>
void visualizePointCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud) {
pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("点云显示"));
viewer->setBackgroundColor(0, 0, 0); // 黑色背景
viewer->addPointCloud<pcl::PointXYZ>(cloud, "sample cloud");
viewer->setPointCloudRenderingProperties(
pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "sample cloud");
while (!viewer->wasStopped()) {
viewer->spinOnce(100);
}
}
这里有个小坑:spinOnce 和 spin 的区别。我曾在项目里用 spin 导致界面卡死,后来改成 spinOnce 配合循环就解决了。
pcl::VoxelGrid 下采样后再可视化,速度能快好几倍。
4.2 调整视角与颜色——让数据更直观
默认的灰色点云看久了容易疲劳。我建议根据点云属性上色,比如高度、强度或者距离。
4.2.1 按高度上色
pcl::visualization::PointCloudColorHandlerGenericField<pcl::PointXYZ> color_handler(cloud, "z");
viewer->addPointCloud<pcl::PointXYZ>(cloud, color_handler, "colored cloud");
这样地面是蓝色,高处是红色,一眼就能看出结构。我在做路沿检测时,就靠这个快速定位了误分割的区域。
4.2.2 调整视角
PCL 默认视角是从 Z 轴正方向看。你可以用鼠标拖拽旋转,也可以用代码设置固定视角:
viewer->setCameraPosition(0, 0, 10, // 相机位置
0, 0, 0, // 焦点位置
0, 1, 0); // 上方向
4.3 多窗口显示——对比分析利器
做地面分割时,我经常需要同时看原始点云和分割后的结果。多窗口显示就派上用场了。
pcl::visualization::PCLVisualizer::Ptr viewer1(new pcl::visualization::PCLVisualizer("原始点云"));
pcl::visualization::PCLVisualizer::Ptr viewer2(new pcl::visualization::PCLVisualizer("地面分割结果"));
// 设置窗口位置
viewer1->setPosition(0, 0);
viewer1->setSize(640, 480);
viewer2->setPosition(640, 0);
viewer2->setSize(640, 480);
// 分别添加点云
viewer1->addPointCloud(original_cloud, "original");
viewer2->addPointCloud(ground_cloud, "ground");
while (!viewer1->wasStopped() && !viewer2->wasStopped()) {
viewer1->spinOnce(100);
viewer2->spinOnce(100);
}
你想想看,左边是原始数据,右边是处理结果,参数调没调对一目了然。我有个同事甚至用四个窗口同时对比不同算法的效果。
| 窗口数量 | 适用场景 | 建议布局 |
|---|---|---|
| 2个 | 原始 vs 处理结果 | 左右并排 |
| 3个 | 原始 + 地面 + 障碍物 | 上1下2 |
| 4个 | 多算法对比 | 2x2网格 |
4.4 交互式选取点云——调试的“手术刀”
有时候你需要精确知道某个区域的点云信息。PCL 提供了交互式选取功能,说白了就是让你用鼠标框选点云。
4.4.1 点选模式
class PointPickingCallback : public pcl::visualization::PCLVisualizer::PointPickingCallback {
void pointPickingEvent(const pcl::visualization::PointPickingEvent& event) override {
float x, y, z;
if (event.getPointIndex() != -1) {
event.getPoint(x, y, z);
std::cout << "选中点坐标: " << x << ", " << y << ", " << z << std::endl;
}
}
};
viewer->registerPointPickingCallback(new PointPickingCallback());
按下 Shift + 鼠标左键就能选中一个点。我在标定激光雷达和相机时,就靠这个功能手动选取对应点。
4.4.2 区域选取
框选区域需要用到 AreaPickingEvent。嗯,这个稍微复杂一点,但很实用:
viewer->registerAreaPickingCallback([](const pcl::visualization::AreaPickingEvent& event) {
std::vector<int> indices;
event.getPointsIndices(indices);
std::cout << "选中了 " << indices.size() << " 个点" << std::endl;
});
4.5 实战经验总结
做点云可视化这么多年,我总结了几条铁律:
- 颜色就是信息——别用默认灰色,按高度或强度上色能发现很多隐藏问题
- 多窗口是调试利器——同时看原始数据和处理结果,对比效率翻倍
- 交互式选取是最后的手段——自动算法搞不定时,手动选点分析往往能救命
- 性能优化不能忘——点云太大时先下采样,不然可视化会卡成PPT
我记得有一次,客户反馈我们的地面分割在某个场景下效果差。我打开可视化一看,发现是地面坡度太大导致算法误判。用交互式选取工具量了几个点的高度差,很快就定位了问题——阈值设得太死了。
所以说,可视化不只是“看看而已”。它是你调试算法的眼睛,是发现问题的手电筒。把这章的内容练熟了,后面的地面分割实战你会轻松很多。