4. 坐标系与变换基础:世界、相机、图像、像素坐标系;刚体变换与齐次矩阵
做手眼标定,说白了就是搞清楚「机器人的手」和「相机的眼」之间到底怎么个相对位置关系。而这一切的起点,就是坐标系和变换。我见过不少新手,一上来就急着跑标定程序,结果数据一团糟,最后发现连像素坐标和世界坐标都没分清楚。嗯,咱们先把地基打牢。
4.1 四个核心坐标系
在视觉引导机器人这个领域,我们打交道的主要是四个坐标系。它们就像不同语言,你得学会互相翻译。
| 坐标系 | 英文 | 单位 | 特点 |
|---|---|---|---|
| 世界坐标系 | World Coordinate System | mm / m | 描述物体在真实世界中的位置,是参考 |
| 相机坐标系 | Camera Coordinate System | mm | 以相机光心为原点,Z轴指向镜头前方 |
| 图像坐标系 | Image Coordinate System | mm | 在成像平面上,以光轴与平面交点为原点 |
| 像素坐标系 | Pixel Coordinate System | pixel | 图像左上角为原点,u向右,v向下 |
关键点:世界坐标是三维的,像素坐标是二维的。从三维到二维,我们损失了深度信息。标定的目的之一,就是找回这个映射关系。
4.2 坐标系之间的变换关系
这四个坐标系不是孤立的。它们通过一系列变换串联起来。我个人习惯把这个链条记作:
世界 → 相机 → 图像 → 像素
每一步都是一个数学变换。咱们拆开看。
4.2.1 从世界到相机:刚体变换
世界坐标系里的一个点,怎么变成相机坐标系里的点?答案是旋转加平移。这就是刚体变换。物体不会变形,只是位置和姿态变了。
数学上,一个三维点 Pw = (Xw, Yw, Zw) 变换到相机坐标系 Pc = (Xc, Yc, Zc):
Pc = R * Pw + T
其中 R 是 3x3 旋转矩阵,T 是 3x1 平移向量。这六个参数(三个旋转角 + 三个平移量)就是相机的外参。
我的经验:外参描述的是相机在世界中的位置。如果你把相机固定在一个机械臂末端,那外参就是变化的。手眼标定要解的,其实就是这个外参和机器人位姿之间的关系。
4.2.2 从相机到图像:透视投影
相机坐标系里的三维点,通过小孔成像模型投影到成像平面上。这一步是透视投影,用到了相机的内参。
x = f * Xc / Zc
y = f * Yc / Zc
这里 (x, y) 是图像坐标系下的坐标,单位是毫米。f 是焦距。注意,Zc 在分母上——这就是为什么物体离相机越远,成像越小。
4.2.3 从图像到像素:离散化
图像坐标是连续的物理尺寸,但计算机只能处理离散的像素。这一步就是离散化:
u = x / dx + u0
v = y / dy + v0
dx、dy 是每个像素的物理尺寸(mm/pixel),(u0, v0) 是图像坐标系原点在像素坐标系中的位置,也就是主点坐标。
注意:dx 和 dy 不一定相等,尤其是使用工业相机时,像素可能是矩形的。另外,镜头畸变也会让这个映射变得复杂。HALCON 的标定流程会自动处理畸变,但理解原理能帮你更好地诊断问题。
4.3 齐次矩阵:把变换统一起来
你想想看,上面这些变换有乘法、有加法,写起来挺麻烦。有没有一种方式能把旋转和平移统一成一次乘法?有,就是齐次坐标。
把一个三维点 (X, Y, Z) 扩展成四维 (X, Y, Z, 1),变换就可以写成:
| Xc | | R11 R12 R13 Tx | | Xw |
| Yc | = | R21 R22 R23 Ty | * | Yw |
| Zc | | R31 R32 R33 Tz | | Zw |
| 1 | | 0 0 0 1 | | 1 |
这个 4x4 矩阵就是齐次变换矩阵,通常记作 H。它把旋转和平移打包在一起,干净利落。
为什么用齐次矩阵?因为你可以把多个变换连乘起来。比如从世界到像素的完整变换:Hworld→pixel = Hintrinsic * Hextrinsic。一次矩阵乘法,搞定所有。
4.4 知识体系总览
下面这张图把四个坐标系和它们之间的变换关系串起来了。我建议你把它存下来,做标定的时候随时对照。
4.5 在 HALCON 中的实际应用
理论说完了,咱们看看在 HALCON 里怎么用。我个人最常用的几个算子:
- pose_to_hom_mat3d:把位姿(Pose)转换成齐次矩阵。标定结果通常以 Pose 形式给出,但做矩阵运算时得转成齐次矩阵。
- hom_mat3d_to_pose:反过来,从齐次矩阵提取位姿。
- affine_trans_point_3d:用齐次矩阵对三维点做变换。比如把世界坐标点转到相机坐标系。
- project_3d_point:把三维点投影到图像上,得到像素坐标。调试时很有用。
一个小技巧:我在项目中经常用 affine_trans_point_3d 来验证标定结果。标定完后,随便选一个已知世界坐标的点,投影到图像上,看看和实际像素位置差多少。如果偏差超过 1-2 个像素,说明标定质量有问题,得回头检查。
4.6 避坑指南
做手眼标定这些年,我踩过不少坑。分享几个最常见的:
- 坐标系方向搞反:HALCON 的相机坐标系 Z 轴指向镜头前方,而机器人坐标系可能不同。我曾经因为没注意这个,标定结果一直不对,折腾了两天。
- 齐次矩阵乘法顺序:矩阵乘法不满足交换律。先旋转再平移,和先平移再旋转,结果完全不同。HALCON 的算子默认是
P' = H * P,也就是先旋转后平移。 - 像素坐标的起点:HALCON 中像素坐标 (0,0) 在图像左上角,u 轴向右,v 轴向下。这和数学坐标系不同,做几何计算时要注意。
我曾经犯过的错:有一次做 eye-in-hand 标定,我直接把机器人位姿的平移向量当成相机外参的平移,忘了考虑旋转。结果标定出来的误差大得离谱。后来才意识到,外参的平移是在旋转之后的坐标系下定义的。记住:先旋转,再平移。
好了,坐标系和变换基础就讲到这里。这些概念会贯穿整个手眼标定流程,尤其是后面讲标定板设计、特征点提取、求解算法时,你会反复用到它们。建议你打开 HALCON,随便加载一张图,用 get_image_pointer1 看看像素数据,再用 camera_calibration 跑一遍标定,亲手验证一下这些变换关系。实践出真知。