3. 相机标定基础:内参矩阵、外参矩阵、畸变参数、张正友标定法原理

相机标定,说白了就是给相机做一次「视力矫正」。

你想想看,镜头不是完美的。它会把直线拍弯,把正方形拍成桶形。如果你要做运动对焦追踪,相机连世界坐标和像素坐标的对应关系都搞不清楚,那后面的算法全是白搭。

我个人习惯,拿到一个新相机,第一件事就是标定。不标定,心里没底。

3.1 四个核心概念:你必须要搞懂

相机标定到底在算什么东西?其实就四个:内参、外参、畸变参数,以及怎么算出来的——张正友标定法。

一句话总结:

  • 内参矩阵:相机自己的「基因」,焦距、光心位置,出厂就定了。
  • 外参矩阵:相机在空间里的「位置和朝向」,旋转加平移。
  • 畸变参数:镜头的光学缺陷,径向畸变和切向畸变。
  • 张正友标定法:用棋盘格照片,把上面三个东西一次性算出来。

3.2 内参矩阵:相机的「基因」

内参矩阵描述的是:三维空间里的点,是怎么投影到二维像素平面上的。

公式长这样:

     [ fx  0  cx ]
K =  [ 0  fy  cy ]
     [ 0   0   1 ]
  • fx, fy:焦距,单位是像素。注意,不是毫米,是像素。为什么?因为传感器像素大小不同,直接用像素更省事。
  • cx, cy:光心,理论上在图像正中心,实际上会有偏移。

我在项目中遇到过一件事:有个同事拿手机摄像头做AR,标定出来的cx偏了20个像素。他死活找不到原因,最后发现是手机摄像头模组装配公差。嗯,这就是内参的意义——告诉你相机真实的「出厂状态」。

我的习惯:内参矩阵一旦标定好,只要不换镜头、不调焦距,就不要动它。每次重新标定,结果都会有微小差异,选一组稳定的就好。

3.3 外参矩阵:相机在哪儿?在看哪儿?

外参矩阵描述的是:世界坐标系和相机坐标系之间的变换关系。

说白了,就是相机在世界里怎么摆的。

[R | t]
  • R:旋转矩阵,3x3,描述相机朝哪个方向看。
  • t:平移向量,3x1,描述相机在哪儿。

外参是动态的。运动对焦追踪里,相机在动,目标在动,外参每一帧都在变。这也是为什么我们要做实时追踪——外参变了,投影关系就变了。

注意:外参矩阵是「世界→相机」的变换。如果你搞反了方向,投影出来的点全错。我曾经在这个坑里爬了三天。

3.4 畸变参数:镜头的「原罪」

没有镜头是完美的。畸变主要分两种:

畸变类型 表现 数学参数
径向畸变 直线变弯,越靠近边缘越明显 k1, k2, k3
切向畸变 镜头和传感器不平行,画面倾斜 p1, p2

径向畸变最常见。广角镜头尤其严重。你拍一张棋盘格,边缘的格子都是弯的。

矫正公式大概是这样:

x_corrected = x * (1 + k1*r^2 + k2*r^4 + k3*r^6) + 2*p1*x*y + p2*(r^2 + 2*x^2)
y_corrected = y * (1 + k1*r^2 + k2*r^4 + k3*r^6) + p1*(r^2 + 2*y^2) + 2*p2*x*y

看着复杂?其实OpenCV一行代码就搞定了。但理解原理很重要——你至少要知道,畸变矫正是用多项式拟合出来的近似。

避坑指南:我曾经用鱼眼镜头做标定,只用了k1, k2两个参数,结果边缘矫正得一塌糊涂。后来加了k3,效果立竿见影。记住:畸变大的镜头,一定要用三个径向参数。

3.5 张正友标定法:为什么它是主流?

张正友标定法,1998年提出,到现在还是工业界的主流。为什么?

  • 只需要一张棋盘格,打印出来贴在平面上就行。
  • 不需要知道相机的位置,拍几张不同角度的照片就行。
  • 精度够用,对于大多数运动追踪场景,绰绰有余。

它的核心思想很简单:

  1. 拍一张棋盘格照片。
  2. 检测棋盘格的角点(亚像素精度)。
  3. 利用棋盘格是「平面」这个约束,建立单应性矩阵。
  4. 从多张照片的单应性矩阵中,解出内参和外参。
  5. 用最小二乘法优化所有参数,包括畸变参数。

下面这张图,就是整个流程的骨架:

张正友标定法流程 张正友标定法核心流程 拍摄多张棋盘格 亚像素角点检测 计算单应性矩阵 求解内参矩阵 求解外参矩阵 畸变参数优化 输出:内参 + 外参 + 畸变参数 核心思想:利用「棋盘格是平面」这个约束,从多张照片中联合求解所有参数

3.6 实战建议:标定到底怎么做?

给你一套我自己的标定流程:

  1. 打印棋盘格:格子大小要量准,误差不要超过0.1mm。
  2. 贴在一个平面上:最好是玻璃板或亚克力板,保证平整。
  3. 拍10-20张照片:角度要丰富,有俯仰、有旋转、有远近。
  4. 用OpenCV的calibrateCamera():一行代码搞定。
  5. 检查重投影误差:小于0.5像素就算合格。

重要提醒:标定板不要只拍正面的。我见过有人拍了20张全是正面,结果外参解不出来。一定要有角度变化,让棋盘格在画面里「动起来」。

3.7 标定结果怎么用?

标定完了,你得到的是:

  • 内参矩阵K:存好,以后每个项目都用它。
  • 畸变系数:用OpenCV的undistort()或initUndistortRectifyMap()做矫正。
  • 外参:每一帧重新算,或者用PnP算法实时解算。

在运动对焦追踪里,标定是第一步,也是最重要的一步。内参不准,后面的三角测量、位姿估计全是错的。别偷懒,好好标。

我的经验:标定一次大概花10分钟。但如果你换了一个镜头,或者调了焦距,一定要重新标。别想着「差不多能用」,差一点就是几个像素的误差,追踪算法直接崩。