第3章:点云坐标系与变换

做点云处理,坐标系绕不开。

我刚开始接触点云时,就被各种坐标系搞晕过。世界坐标系、相机坐标系、还有后面要讲的局部坐标系……说白了,它们就是给三维空间里的点一个「身份地址」。地址不同,同一个点的坐标值就不同。

3.1 世界坐标系与相机坐标系

先讲世界坐标系。你可以把它想象成一个「绝对参考系」。不管你的传感器怎么动,世界坐标系是固定不变的。在自动驾驶里,它通常以车辆启动位置为原点;在三维重建里,它往往以场景中心为原点。

相机坐标系呢?它跟着相机走。相机在哪儿,原点就在哪儿。Z轴指向相机前方,X轴向右,Y轴向下——嗯,这是OpenCV的习惯。

我遇到过不少新手,直接把相机坐标系下的点当成世界坐标来用。结果呢?点云全歪了。你想想看,相机转了个角度,点云也跟着转,这显然不对。

核心关系:世界坐标系是固定的,相机坐标系是动态的。两者通过刚体变换相互转换。

为什么需要区分它们?因为传感器采集的数据天然在相机坐标系下。你要做全局建图、多传感器融合,就必须统一到世界坐标系。

3.2 刚体变换:旋转矩阵与平移向量

刚体变换,说白了就是「旋转+平移」。物体形状不变,只是位置和朝向变了。

旋转矩阵是个3x3的方阵。它描述了一个坐标系相对于另一个坐标系的朝向关系。我习惯用R表示。平移向量是个3x1的列向量,用t表示。

公式很简单:

P_world = R * P_camera + t

其中P_camera是相机坐标系下的点,P_world是世界坐标系下的点。

反过来呢?

P_camera = R^T * (P_world - t)

注意,旋转矩阵的逆等于它的转置。这个性质在代码里很实用。

我的习惯:写代码时,我会把旋转矩阵和平移向量打包成一个4x4的齐次变换矩阵。这样一次矩阵乘法就能搞定变换,代码更简洁。

齐次变换矩阵长这样:

T = [[R, t],
     [0, 1]]

用Open3D的话,你可以这样构建:

import numpy as np
import open3d as o3d

# 定义旋转矩阵(绕Z轴旋转45度)
theta = np.pi / 4
R = np.array([
    [np.cos(theta), -np.sin(theta), 0],
    [np.sin(theta),  np.cos(theta), 0],
    [0,              0,             1]
])

# 定义平移向量
t = np.array([1.0, 2.0, 0.5])

# 构建齐次变换矩阵
T = np.eye(4)
T[:3, :3] = R
T[:3, 3] = t

3.3 使用Open3D进行点云旋转与平移

Open3D处理变换非常方便。它内置了transform()方法,直接传入4x4矩阵就行。

来看个完整例子:

import open3d as o3d
import numpy as np

# 生成一个随机点云
pcd = o3d.geometry.PointCloud()
points = np.random.rand(100, 3)  # 100个随机点
pcd.points = o3d.utility.Vector3dVector(points)

# 定义变换矩阵
theta = np.pi / 6  # 30度
R = np.array([
    [np.cos(theta), -np.sin(theta), 0],
    [np.sin(theta),  np.cos(theta), 0],
    [0,              0,             1]
])
t = np.array([0.5, 0.0, 0.0])

T = np.eye(4)
T[:3, :3] = R
T[:3, 3] = t

# 应用变换
pcd_transformed = pcd.transform(T)

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

运行这段代码,你会看到原始点云(白色)和变换后的点云(红色)同时显示。旋转加平移,一步到位。

我曾经踩过的坑:Open3D的transform()是原地操作。如果你不想修改原始点云,记得先copy()一份。

另外,Open3D也支持单独设置旋转和平移:

# 单独旋转
pcd.rotate(R, center=(0, 0, 0))

# 单独平移
pcd.translate(t)

rotate()center参数指定旋转中心。默认是原点。如果你想绕点云中心旋转,先计算质心:

center = pcd.get_center()
pcd.rotate(R, center=center)

这个技巧在配准和拼接时特别有用。

3.4 知识体系总览

下面这张图帮你理清本章的核心逻辑:

点云坐标系与变换知识体系 世界坐标系 固定参考系 相机坐标系 动态传感器系 R, t 刚体变换 旋转矩阵 R (3x3) + 平移向量 t (3x1) 齐次变换矩阵 T (4x4) Open3D实现 transform() / rotate() / translate()

从图中可以看出,世界坐标系和相机坐标系通过刚体变换(R和t)相互转换。而Open3D提供了现成的API来实现这些变换。

实用建议:在实际项目中,我习惯把所有点云统一到世界坐标系后再处理。这样后续的滤波、分割、配准都会简单很多。

好了,坐标系和变换就讲到这里。记住一句话:坐标系是点云的「身份证」,变换是点云的「搬家工具」。掌握好它们,后面的课程你会走得很顺。


公众号:蓝海资料掘金营,微信deep3321