4、点云坐标系与变换:世界坐标系、相机坐标系、物体坐标系,刚体变换(旋转、平移),齐次坐标与变换矩阵,使用Open3D实现点云变换

各位好,我是老张。今天我们来聊聊点云处理里最基础、也最容易踩坑的一个话题——坐标系与变换。

说实话,我刚开始做点云项目那会儿,觉得坐标系这东西有啥好讲的?不就是xyz嘛。结果呢?第一次做多传感器融合,激光雷达和相机对不上,折腾了两天才发现是坐标系定义搞反了。嗯,从那以后,我再也不敢小看坐标系了。

4.1 三个核心坐标系

点云数据本身只是一堆三维点,但每个点到底是在哪个坐标系下描述的?这很关键。我个人习惯把坐标系分成三类:

  • 世界坐标系:全局统一的参考系。比如你在一个房间里放了一台扫描仪,房间的某个墙角就是世界坐标系原点。所有物体的位置,最终都要映射到这个坐标系下。
  • 相机坐标系:以相机光心为原点,Z轴指向拍摄方向。你想想看,相机看到的点,天然就是在相机坐标系下的。但不同相机的坐标系定义可能不一样——有的Z轴朝前,有的Z轴朝后,这就是坑。
  • 物体坐标系:以物体自身为中心。比如你扫描一个杯子,杯底中心就是原点。物体坐标系的好处是:无论杯子怎么移动,它的几何描述不变。

我在项目中遇到过一个问题:用机械臂抓取零件,零件在传送带上移动。如果只用世界坐标系,每次都要重新计算抓取点。后来改用物体坐标系,把抓取点定义在零件上,世界坐标系只管零件的位置和姿态——简单多了。

4.2 刚体变换:旋转与平移

说白了,刚体变换就是“不改变物体形状的移动”。一个点云从坐标系A变到坐标系B,无非就是转一转、挪一挪。

旋转:绕X、Y、Z轴转。每个轴转一个角度,三个角度组合起来就是欧拉角。但欧拉角有个问题——万向锁。我建议你用旋转矩阵或者四元数,更稳定。

平移:就是沿着X、Y、Z方向挪动。简单,加个向量就行。

旋转矩阵R是3x3的,平移向量t是3x1的。组合起来:p' = R * p + t。这就是刚体变换的数学表达。

4.3 齐次坐标与变换矩阵

为什么要有齐次坐标?因为上面的公式写起来麻烦。每次都要先乘R再加t,代码里得写两行。用齐次坐标,把三维点变成四维:(x, y, z, 1)。然后变换矩阵T是4x4的:

T = | R  t |
    | 0  1 |

这样,一次矩阵乘法就搞定了:p' = T * p。干净利落。

我曾经在写点云配准代码时,忘了把齐次坐标的最后一维设成1,结果变换出来的点全飞到天上了。排查了半天才发现——嗯,细节决定成败。

4.4 使用Open3D实现点云变换

Open3D里做变换非常方便。我直接上代码:

import open3d as o3d
import numpy as np

# 读取点云
pcd = o3d.io.read_point_cloud("bunny.pcd")

# 定义变换矩阵(先绕Z轴转45度,再沿X轴平移0.5米)
theta = np.pi / 4
T = np.array([
    [np.cos(theta), -np.sin(theta), 0, 0.5],
    [np.sin(theta),  np.cos(theta), 0, 0.0],
    [0,              0,             1, 0.0],
    [0,              0,             0, 1]
])

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

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

你看,核心就一行:pcd.transform(T)。Open3D自动帮你把每个点都乘上T矩阵。

小技巧:如果你只想旋转不想平移,把平移部分设成0;只想平移不想旋转,把旋转部分设成单位矩阵。我经常用这个方法来调试——先测旋转对不对,再测平移。

4.5 知识体系总览

下面这张图,是我自己总结的坐标系与变换的核心逻辑。你一看就明白:

世界坐标系 全局统一参考 (房间墙角) 相机坐标系 以光心为原点 (Z轴朝前) 物体坐标系 以物体为中心 (杯底原点) 外参 位姿 刚体变换:p' = T * p 旋转 R (3x3) + 平移 t (3x1) 齐次坐标 → 4x4变换矩阵 Open3D: pcd.transform(T)
核心要点:坐标系变换的本质,就是用一个4x4矩阵把点从一个坐标系搬到另一个坐标系。记住这个,后面讲点云配准、SLAM、多传感器融合,全都要用到。

4.6 避坑指南

我曾经踩过的坑:
  • Open3D的坐标系是右手系,但有些传感器(比如某些深度相机)用的是左手系。不转换直接变换,结果全反。
  • 变换矩阵的顺序:先旋转后平移,还是先平移后旋转?Open3D的transform函数是先旋转后平移。如果你搞反了,点云会飞到莫名其妙的位置。
  • 单位问题:有的数据是毫米,有的是米。变换矩阵里的平移量,单位必须和点云一致。我见过有人把0.5米写成了0.5毫米,结果点云缩成一团。

好了,坐标系与变换就讲到这里。你回去可以拿自己的点云数据试试,先定义一个变换矩阵,看看点云怎么动。动手做一遍,比看十遍都管用。


专注资料整理