4. 相机标定原理:张正友标定法

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

你想想看,相机镜头不是完美的。光线穿过透镜会发生折射,传感器也不一定完全平行。这些偏差会导致图像变形——直线变弯、矩形变鼓。做手眼标定之前,必须先把相机本身的「脾气」摸清楚。

我个人习惯把标定分成两步:先算内参(焦距、主点),再算畸变系数(径向、切向)。张正友标定法是目前最主流的做法,用棋盘格就能搞定。

4.1 棋盘格标定板

棋盘格长什么样?就是黑白相间的方格阵列。我刚开始做项目时,直接打印一张A4纸贴在硬纸板上。后来发现,打印精度和平面度都会影响结果。

我的经验: 标定板最好用玻璃或铝基板,热胀冷缩小。打印时用激光打印机,别用喷墨——墨水洇开会模糊角点检测。

棋盘格的关键参数:

  • 内角点数:比如 9×7 的棋盘,内角点是 8×6。注意是「内角」,不是格子数。
  • 方格尺寸:必须精确测量,单位毫米。我一般用游标卡尺量三次取平均。
  • 拍摄姿态:至少 10-20 张不同角度、不同距离的图片。倾斜、旋转、平移都要有。
避坑: 我曾经拍了一组全是正对相机的图片,结果标定出来的内参完全不对。因为缺少深度变化,方程解不稳定。记住:棋盘格平面和相机成像平面之间的夹角要变化丰富。

4.2 单应性矩阵

张正友标定法的核心,就是利用棋盘格平面到成像平面的单应性关系。

什么是单应性矩阵?简单说,它描述了两个平面之间的投影变换。在标定场景里,一个是棋盘格所在的物理平面(世界坐标系 Z=0),另一个是相机成像平面。

数学上,单应性矩阵 H 是一个 3×3 的矩阵:

s * [u, v, 1]^T = H * [X, Y, 1]^T

其中:

  • (u, v) 是图像坐标
  • (X, Y) 是棋盘格上的物理坐标
  • s 是尺度因子
  • H 包含内参和外参的混合信息

每张棋盘格图片,都能算出一个 H。我一般用 OpenCV 的 findHomography 函数,输入至少 4 个对应点就能解。但实际项目中,我会用所有内角点做最小二乘,精度更高。

关键点: 单应性矩阵 H 是内参矩阵 K 和外参矩阵 [R|t] 的乘积。通过多张图片的 H,我们可以把内参 K 单独剥离出来。

4.3 内参求解

内参矩阵 K 长这样:

K = [fx,  0, cx;
      0, fy, cy;
      0,  0,  1]

其中 fx、fy 是焦距(像素单位),cx、cy 是主点坐标(光轴与成像平面的交点)。

张正友的解法很巧妙。他从单应性矩阵 H 中提取约束方程,利用旋转矩阵的正交性,构建线性方程组。具体步骤:

  1. 对每张图片计算 H
  2. 从 H 中提取关于内参的约束
  3. 构建超定方程组,用最小二乘求解
  4. 得到内参的闭式解

我记得第一次手动推导这个流程时,被矩阵运算绕晕了。后来直接用 OpenCV 的 calibrateCamera,一行代码搞定。但理解原理很重要——遇到标定失败时,你知道该查哪里。

参数 含义 典型值(640×480)
fx x 方向焦距 ~500-600
fy y 方向焦距 ~500-600
cx 主点 x 坐标 ~320
cy 主点 y 坐标 ~240
经验值: 如果标定出来的 cx、cy 偏离图像中心太多(比如超过 20 像素),说明标定板图片质量有问题,或者相机传感器有偏移。我遇到过一台工业相机,cx 偏了 50 像素,后来发现是镜头安装歪了。

4.4 畸变系数求解

畸变主要分两类:

  • 径向畸变:光线通过透镜边缘时弯曲更严重,导致图像边缘向内(桶形)或向外(枕形)扭曲
  • 切向畸变:透镜和传感器不平行,导致图像倾斜

张正友标定法用多项式模型来拟合畸变:

x_distorted = x * (1 + k1*r^2 + k2*r^4 + k3*r^6) + [2*p1*x*y + p2*(r^2 + 2*x^2)]
y_distorted = y * (1 + k1*r^2 + k2*r^4 + k3*r^6) + [p1*(r^2 + 2*y^2) + 2*p2*x*y]

其中:

  • k1、k2、k3 是径向畸变系数
  • p1、p2 是切向畸变系数
  • r^2 = x^2 + y^2

求解过程是这样的:先用线性方法算出内参,然后固定内参,用非线性优化(比如 Levenberg-Marquardt)迭代求解畸变系数。

注意: k3 一般只用于鱼眼镜头或畸变很大的镜头。普通镜头用 k1、k2 就够了。我见过有人强行用 k3,结果标定出来的图像边缘反而更扭曲——过拟合了。

标定完成后,可以用 undistort 函数矫正图像。我习惯先看一眼矫正前后的对比图:棋盘格边缘的直线应该变直,否则标定参数有问题。

张正友标定法流程 拍摄棋盘格图片 检测角点坐标 计算单应性矩阵 H 求解内参矩阵 K 求解畸变系数 非线性优化 输出标定结果 说明: 1. 至少拍摄 10-20 张不同姿态的棋盘格图片 2. 角点检测使用亚像素精度,提高标定稳定性 3. 非线性优化同时优化内参和畸变系数,最小化重投影误差

4.5 标定质量评估

标定完了,怎么知道结果好不好?

我最常用的指标是重投影误差。就是把棋盘格上的物理点,用标定出的内参和畸变系数重新投影到图像上,算算和实际检测到的角点差多少像素。

经验阈值: 重投影误差 < 0.5 像素算优秀,< 1.0 像素算合格。如果超过 1.5 像素,我建议重新拍一组图片。

影响标定精度的常见因素:

  • 图片数量太少(< 10 张)
  • 棋盘格姿态变化不够(全是正面)
  • 棋盘格平面度差(纸板弯曲)
  • 光照不均匀导致角点检测偏移

嗯,标定这件事,看起来简单,做起来全是细节。我刚开始做的时候,标定了十几次才拿到满意的结果。后来总结出一套流程:先拍 20 张,跑一次标定,看重投影误差,剔除误差最大的几张,再跑一次。反复两三轮,基本就能稳定在 0.3 像素以内。