3. 点云可视化入门:用Open3D和PCL让数据“活”起来

说实话,做点云处理这几年,我最大的感触就是——看不见的数据,等于没有数据

你辛辛苦苦滤波、分割、配准,最后输出一堆数字。但数字能告诉你什么?几乎什么也说不清。只有把点云画出来,你才能一眼看出问题在哪。

这一章,我们就来聊聊怎么用Open3D和PCL这两个库,把点云数据变成你能“看见”的东西。我会带上我踩过的坑,还有我个人的一些小习惯。

核心观点:可视化不是“锦上添花”,而是调试和验证的“刚需”。

点云可视化知识体系 可视化基础 Open3D / PCL 窗口 视角与渲染 旋转 / 缩放 / 背景 颜色编码 RGB / 高程 / 分类 强度显示 灰度映射 / 伪彩色

3.1 为什么可视化这么重要?

我刚开始做点云的时候,犯过一个低级错误。滤波参数设错了,结果把地面点全滤掉了,只剩下几根孤零零的电线杆。我盯着终端里的点数统计看了半天,愣是没发现问题。直到我把点云画出来——好家伙,地面没了,车都悬空了。

你想想看,如果当时我第一时间可视化,这个bug五分钟就能发现。所以我现在养成了一个习惯:每做一步处理,先看一眼可视化结果

我的小习惯:在代码里加一个 visualize() 函数,随时调用。别等到最后才看结果,那时候可能已经跑偏很远了。

3.2 Open3D 可视化:三行代码搞定

Open3D 是我个人最常用的库。为什么?因为它简单、快、交互好。你只需要三行代码,就能看到一个点云窗口。

import open3d as o3d

# 读取点云
pcd = o3d.io.read_point_cloud("data/room.pcd")

# 可视化
o3d.visualization.draw_geometries([pcd])

就这么简单。运行之后,你会看到一个窗口,可以用鼠标拖拽旋转、滚轮缩放。嗯,这里要注意:默认窗口是黑色的,如果你觉得不好看,可以改背景色。

调整视角与渲染参数

Open3D 的 draw_geometries 函数支持很多参数。我常用的几个:

  • window_name:窗口标题,方便区分多个窗口
  • width, height:窗口尺寸,我一般设 1280x720
  • point_show_normal:是否显示法向量,调试时有用
  • mesh_show_wireframe:显示网格线框
o3d.visualization.draw_geometries(
    [pcd],
    window_name="我的点云",
    width=1280,
    height=720,
    point_show_normal=True,
    background_color=[0.1, 0.1, 0.1]  # 深灰色背景
)

注意:背景颜色是 RGB 值,范围 0~1。不是 0~255。我刚开始就写错过,结果背景一片惨白。

3.3 PCL 可视化:更底层的控制

PCL(Point Cloud Library)是 C++ 的经典库。虽然 Open3D 更现代,但 PCL 在某些场景下依然不可替代——比如你需要精细控制渲染管线的时候。

PCL 的可视化核心是 pcl::visualization::PCLVisualizer。我一般这样用:

#include <pcl/visualization/pcl_visualizer.h>

pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("点云查看器"));
viewer->setBackgroundColor(0.1, 0.1, 0.1);
viewer->addPointCloud<pcl::PointXYZ>(cloud, "cloud");
viewer->setPointCloudRenderingProperties(
    pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "cloud");

while (!viewer->wasStopped()) {
    viewer->spinOnce(100);
}

这段代码会创建一个窗口,显示点云,点的大小设为3像素。你可以用鼠标旋转、缩放。PCL 的交互不如 Open3D 流畅,但胜在可控性强

视角控制:从不同角度看数据

有时候你需要从特定角度观察点云。比如,我想看建筑物的正面,而不是默认的俯视图。PCL 里可以这样设置:

viewer->setCameraPosition(
    pos_x, pos_y, pos_z,   // 相机位置
    view_x, view_y, view_z, // 观察目标点
    up_x, up_y, up_z        // 上方向
);

Open3D 更简单,你可以用 get_view_control() 获取当前视角参数,然后保存下来复用。

我的经验:调试时,我会先手动旋转到最佳视角,然后调用 view_control.convert_to_pinhole_camera_parameters() 保存参数。下次直接加载,省得每次都要手动调。

3.4 点云的颜色编码:让数据“说话”

默认情况下,点云是灰色的。但灰色能传递的信息太有限了。我们需要颜色编码——用颜色来表达数据的某个属性。

3.4.1 按高程着色

这是最常用的方式。把 Z 轴(高度)映射到颜色上,低处用蓝色,高处用红色。一眼就能看出地形起伏。

import numpy as np
import open3d as o3d

pcd = o3d.io.read_point_cloud("data/terrain.pcd")
points = np.asarray(pcd.points)

# 获取Z值
z = points[:, 2]
z_min, z_max = z.min(), z.max()

# 映射到颜色(蓝->绿->红)
colors = np.zeros((points.shape[0], 3))
colors[:, 0] = (z - z_min) / (z_max - z_min)  # R
colors[:, 2] = 1.0 - (z - z_min) / (z_max - z_min)  # B

pcd.colors = o3d.utility.Vector3dVector(colors)
o3d.visualization.draw_geometries([pcd])

这段代码把 Z 值归一化到 0~1,然后映射到红蓝通道。低处偏蓝,高处偏红。效果很直观。

3.4.2 按分类着色

如果你做语义分割,每个点有一个类别标签(比如 0=地面, 1=建筑, 2=树木)。这时候可以用固定颜色表来着色。

类别颜色RGB值
地面棕色(139, 69, 19)
建筑红色(255, 0, 0)
树木绿色(0, 255, 0)
车辆蓝色(0, 0, 255)
label_color_map = {
    0: [139/255, 69/255, 19/255],   # 地面
    1: [1.0, 0.0, 0.0],             # 建筑
    2: [0.0, 1.0, 0.0],             # 树木
    3: [0.0, 0.0, 1.0]              # 车辆
}

colors = np.array([label_color_map[label] for label in labels])
pcd.colors = o3d.utility.Vector3dVector(colors)

我曾经踩过的坑:颜色值忘记归一化到 0~1,直接用了 0~255。结果点云一片惨白。记住,Open3D 的颜色范围是 0~1,不是 0~255。

3.5 强度显示:LiDAR 的“灰度图”

如果你用的是激光雷达数据,每个点除了 XYZ 坐标,还有一个强度值(intensity)。强度值反映了目标表面对激光的反射能力。比如,路标反射强,沥青路面反射弱。

强度显示的本质,就是把强度值映射到灰度或伪彩色上。

灰度映射

intensity = np.asarray(pcd.intensity)
intensity_norm = (intensity - intensity.min()) / (intensity.max() - intensity.min())

# 灰度:R=G=B
gray = np.stack([intensity_norm, intensity_norm, intensity_norm], axis=1)
pcd.colors = o3d.utility.Vector3dVector(gray)

伪彩色映射

灰度图有时候不够明显。我更喜欢用热力图——低强度用蓝色,中强度用绿色,高强度用红色。

import matplotlib.cm as cm

# 使用matplotlib的jet色图
colors = cm.jet(intensity_norm)[:, :3]  # 去掉alpha通道
pcd.colors = o3d.utility.Vector3dVector(colors)

这样一看,路标、车牌这些高反射物体就“亮”起来了,路面、草地则偏暗。在夜间场景中,强度显示比 RGB 相机更可靠。

我的建议:如果你同时有 RGB 和强度数据,可以试试把强度作为亮度通道,叠加到 RGB 上。效果出奇的好,尤其在弱光环境下。

3.6 本章小结

可视化不是花架子,它是你调试和验证的第一道防线。Open3D 适合快速上手,PCL 适合深度控制。颜色编码和强度显示,能让你的数据“开口说话”。

我个人建议:把可视化写进你的处理流程里。每做一步,看一眼。你会发现,很多问题在数字里藏得很深,但在图像里一目了然。

专注资料整理