3、内参矩阵与外参矩阵:内参矩阵K的构成(fx, fy, cx, cy)、外参矩阵(旋转R与平移t)、投影方程
好,咱们接着往下聊。前面我们把相机模型和坐标系的关系理清了,现在该动真格的了——把数学公式请出来。
说白了,相机标定要解决的核心问题就一个:世界坐标系里的一个点,是怎么跑到图像像素坐标系里去的? 这个映射过程,全靠内参矩阵和外参矩阵来搭桥。
3.1 内参矩阵K:相机的“内部基因”
内参矩阵,我习惯叫它K矩阵。它描述的是相机本身的固有属性,跟相机放哪儿、朝哪拍没关系。你换个场景拍,K矩阵不变。
K矩阵长这样:
K = | fx 0 cx |
| 0 fy cy |
| 0 0 1 |
这里面四个参数,每个都有物理意义:
- fx, fy:焦距参数。单位是像素。fx = F / dx,F是物理焦距(毫米),dx是每个像素的物理宽度(毫米/像素)。说白了,fx告诉你物体在图像上横向能放多大。
- cx, cy:主点坐标。就是光轴穿过图像平面的那个点,单位也是像素。理想情况下它在图像正中心,但实际总有偏差。
我个人的经验: 很多初学者以为cx、cy就是图像宽高的一半。我刚开始也这么想,结果标定出来的结果总差那么一点。后来才发现,镜头装配时主点偏移个几十个像素太正常了。千万别偷懒,老老实实标定。
内参矩阵的作用,是把相机坐标系下的三维点映射到图像物理坐标系,再转到像素坐标系。公式如下:
| u | | fx 0 cx | | Xc |
| v | = | 0 fy cy | * | Yc |
| 1 | | 0 0 1 | | Zc |
这里 (Xc, Yc, Zc) 是相机坐标系下的坐标,(u, v) 是像素坐标。注意,这个公式里Zc还没归一化,实际用的时候要除以Zc。
小技巧: 如果你拿到一个标定结果,fx和fy相差很大(比如超过5%),那大概率是标定板没放平,或者图像有畸变没处理好。我曾经遇到过fx=1200、fy=800的情况,查了半天发现是标定图片里有一张模糊的混进去了。
3.2 外参矩阵:相机在“世界”中的位置
外参矩阵描述的是世界坐标系和相机坐标系之间的变换关系。说白了,就是相机在世界里怎么摆的——朝哪看、站多远。
外参矩阵由两部分组成:
- 旋转矩阵R:3x3的正交矩阵,描述相机的朝向。说白了就是相机绕三个轴转了多少。
- 平移向量t:3x1的向量,描述相机在世界坐标系中的位置。
外参矩阵通常写成4x4的齐次形式:
[R | t] = | r11 r12 r13 t1 |
| r21 r22 r23 t2 |
| r31 r32 r33 t3 |
| 0 0 0 1 |
它的作用是把世界坐标系下的点,变换到相机坐标系下:
| Xc | | r11 r12 r13 t1 | | Xw |
| Yc | = | r21 r22 r23 t2 | * | Yw |
| Zc | | r31 r32 r33 t3 | | Zw |
| 1 | | 0 0 0 1 | | 1 |
注意: 旋转矩阵R必须是正交矩阵,也就是说R的逆等于R的转置。如果你标定出来的R不满足这个性质(比如行列式不是1),那说明标定过程有问题。我曾经见过一个案例,标定出来的R行列式是0.97,结果重建出来的三维点全歪了。
3.3 投影方程:从世界到像素的“完整路线”
好了,现在把内参和外参串起来,就是完整的投影方程:
| u | | fx 0 cx 0 | | R t | | Xw |
| v | = | 0 fy cy 0 | * | 0 1 | * | Yw |
| 1 | | 0 0 1 0 | | | | Zw |
| 1 |
简化一下:
s * [u, v, 1]^T = K * [R | t] * [Xw, Yw, Zw, 1]^T
这里s是个尺度因子,就是前面说的Zc。为什么要有s?因为从三维到二维,深度信息丢失了,我们只能知道方向,不知道具体多远。
你想想看,这个公式其实就干了三件事:
- 外参变换:把世界坐标点转到相机坐标系下
- 内参映射:把相机坐标点投影到图像平面上
- 尺度归一化:除以深度,得到最终的像素坐标
避坑指南: 我曾经在项目里犯过一个低级错误——把外参矩阵的平移向量t理解反了。记住,[R | t] 是把世界坐标转到相机坐标,不是反过来。如果你要算相机在世界里的位置,得用 -R^T * t。这个坑我踩过,后来每次写代码都先画个坐标系确认一下。
3.4 一个完整的例子
假设我们有一个标定好的相机,内参如下:
fx = 800, fy = 800, cx = 640, cy = 480
外参:相机在世界坐标系原点,朝Z轴正方向看(即R为单位矩阵,t为零向量)。
现在世界坐标系下有一个点 P = (100, 200, 500) 毫米。它在图像上的像素坐标是多少?
计算过程:
1. 外参变换:因为R=I, t=0,所以相机坐标 = (100, 200, 500)
2. 内参映射:
u' = 800 * 100 / 500 + 640 = 160 + 640 = 800
v' = 800 * 200 / 500 + 480 = 320 + 480 = 800
3. 所以像素坐标是 (800, 800)
嗯,这个点正好落在图像中心偏右下的位置,符合直觉。
个人习惯: 我每次标定完,都会拿几个已知坐标的点手动算一遍投影,验证标定结果对不对。虽然麻烦,但能避免很多后期调试的麻烦。你想想看,如果标定错了,后面做三维重建、SLAM全白搭。
好了,内参矩阵和外参矩阵就讲到这里。下一节我们聊聊畸变参数——镜头不是完美的,总有点歪歪扭扭的地方需要校正。