4、相机内参标定:针孔模型、畸变模型(径向/切向)、标定板设计、张正友标定法、OpenCV/Matlab标定工具实战

相机内参标定是视觉传感器与激光雷达、IMU等异构传感器进行外参联合标定的前置基础。如果内参不准,外参标定中的特征重投影误差会被系统性放大,导致融合系统在远距离目标上的定位精度急剧下降。本章从针孔成像的几何本质出发,深入剖析畸变来源与建模方式,并围绕张正友标定法给出从标定板设计到OpenCV/Matlab工具实战的完整闭环。

相机内参标定核心链路与畸变模型 世界坐标系 3D点 (X,Y,Z) 相机坐标系 刚体变换 R|t 针孔投影 归一化平面 (x',y') 畸变模型 径向/切向 k1,k2,p1,p2 像素坐标 (u,v) 内参矩阵K 标定板设计要点 • 棋盘格 10×7 或 12×9 • 方格尺寸 20-30mm • 平面度 < 0.1mm 张正友标定法流程 ① 采集≥15张不同位姿图像 ② 角点检测与亚像素细化 ③ 单应矩阵求解 → 内参初值 工具实战 OpenCV calibrateCamera Matlab Camera Calibrator 重投影误差 < 0.1px 标定输出 内参矩阵 K 畸变系数 D 重投影误差 畸变校正前后对比 原始图像(桶形畸变) → 校正后(直线恢复) 切向畸变(透镜与像面不平行) 径向畸变:k1(主导)、k2、k3(鱼眼/广角)

4.1 针孔模型与内参矩阵的几何本质

针孔模型是相机成像的理想化近似:三维空间中的点通过光心投影到像平面上。设世界坐标系下一点 \(P_w = (X_w, Y_w, Z_w)^T\),经外参(旋转矩阵 \(R\) 和平移向量 \(t\))变换到相机坐标系 \(P_c = R P_w + t\),再通过针孔投影得到归一化坐标 \(x' = X_c / Z_c\),\(y' = Y_c / Z_c\)。最终映射到像素坐标 \((u, v)\) 的完整公式为:

s * [u, v, 1]^T = K * [R | t] * [X_w, Y_w, Z_w, 1]^T
其中 K = [fx, 0, cx; 0, fy, cy; 0, 0, 1]

内参矩阵 \(K\) 中的 \(fx, fy\) 分别为 \(x\)、\(y\) 方向的等效焦距(单位像素),\(cx, cy\) 为主点坐标。需要特别强调的是,\(fx\) 与镜头物理焦距 \(f\)(毫米)的关系为 \(fx = f / dx\),其中 \(dx\) 为单个像素的物理宽度。在实际标定中,我们直接求解 \(fx, fy\),无需单独测量像素尺寸。

经验提醒:对于工业相机,若传感器靶面尺寸已知(如 1/1.8" CMOS,像元尺寸 2.4μm),可交叉验证标定出的 \(fx\) 是否合理。例如 12mm 镜头在 2.4μm 像元下,\(fx\) 理论值约为 5000 像素。若偏差超过 5%,需检查标定板尺寸或图像分辨率设置。

4.2 畸变模型:径向与切向的数学表达

实际镜头存在两类主要畸变:径向畸变源于透镜曲面形状误差,光线离光心越远弯曲越严重,表现为桶形(k1<0)或枕形(k1>0)失真;切向畸变源于透镜与成像平面不平行,产生梯形失真。OpenCV 采用 Brown-Conrady 模型,畸变系数向量 \(D = [k_1, k_2, p_1, p_2, k_3]\):

径向畸变:
x_distorted = x * (1 + k1*r^2 + k2*r^4 + k3*r^6)
y_distorted = y * (1 + k1*r^2 + k2*r^4 + k3*r^6)

切向畸变:
x_distorted = x + [2*p1*x*y + p2*(r^2 + 2*x^2)]
y_distorted = y + [p1*(r^2 + 2*y^2) + 2*p2*x*y]

其中 r^2 = x^2 + y^2,x、y 为归一化平面坐标

对于常规工业镜头,通常只需 \(k_1, k_2, p_1, p_2\) 四个系数;对于广角或鱼眼镜头,需引入 \(k_3\) 甚至更高阶项。标定工具会输出每个系数的标准差,若某个系数标准差过大(如超过系数本身),说明该系数不可靠,应将其置零重新标定。

畸变类型主导系数典型表现校正优先级
径向(桶形)k1 < 0直线向外弯曲高
径向(枕形)k1 > 0直线向内弯曲高
切向p1, p2梯形/平行四边形失真中
高阶径向k3画面边缘严重扭曲低(仅广角)

4.3 标定板设计与采集规范

标定板质量直接决定标定精度上限。推荐使用氧化铝基板+光刻工艺的陶瓷棋盘格,而非普通打印纸——后者在温湿度变化下热膨胀系数大,且表面不平整。设计要点如下:

  • 棋盘格尺寸:推荐 10×7 或 12×9 内角点(即 11×8 或 13×10 格),方格边长 20-30mm。过少角点导致单应矩阵求解不稳定,过多则增加角点检测计算量。
  • 平面度要求:标定板平面度误差应小于 0.1mm,否则在近距离标定时会引入系统性误差。
  • 表面处理:哑光涂层避免反光,黑白格对比度需大于 5:1,确保角点检测算法稳定提取。
  • 采集规范:至少 15-20 张图像,覆盖画面中心、四角、上下左右边缘;标定板倾斜角度控制在 15°-45° 之间,避免正对相机(退化位姿)。
风险提示:若标定板在画面中占比过小(<20%),角点亚像素定位精度会显著下降。建议标定板在图像中占比 30%-60%,并确保对焦清晰、无运动模糊。使用光圈优先模式,保证景深覆盖标定板平面。

4.4 张正友标定法核心流程

张正友标定法(Zhang's Method)利用平面标定板在不同位姿下的多张图像,通过单应矩阵约束求解内参。其核心步骤可归纳为:

  1. 角点检测:使用 OpenCV 的 findChessboardCorners 或 findCirclesGrid 提取角点,并用 cornerSubPix 进行亚像素细化(窗口 5×5,迭代 30 次)。
  2. 单应矩阵求解:每张图像建立 3×3 单应矩阵 \(H\),将标定板平面映射到图像平面。利用 \(H\) 的正交约束构建线性方程组,求解内参初值。
  3. 畸变系数估计:在最小二乘框架下,将畸变模型线性化,交替优化内参和畸变系数。
  4. 非线性优化:使用 Levenberg-Marquardt 算法最小化重投影误差,得到最终内参和畸变系数。
# OpenCV Python 标定核心代码
import cv2
import numpy as np

# 棋盘格内角点数
pattern_size = (10, 7)  # 10列7行
square_size = 0.025  # 方格边长25mm

# 准备对象点
objp = np.zeros((pattern_size[0]*pattern_size[1], 3), np.float32)
objp[:, :2] = np.mgrid[0:pattern_size[0], 0:pattern_size[1]].T.reshape(-1, 2)
objp *= square_size

obj_points = []  # 3D点
img_points = []  # 2D点

for img_path in image_paths:
    img = cv2.imread(img_path)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    ret, corners = cv2.findChessboardCorners(gray, pattern_size, None)
    if ret:
        corners_sub = cv2.cornerSubPix(gray, corners, (5,5), (-1,-1),
                                       (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001))
        obj_points.append(objp)
        img_points.append(corners_sub)

ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(
    obj_points, img_points, gray.shape[::-1], None, None)

# 评估重投影误差
total_error = 0
for i in range(len(obj_points)):
    imgpoints2, _ = cv2.projectPoints(obj_points[i], rvecs[i], tvecs[i], mtx, dist)
    error = cv2.norm(img_points[i], imgpoints2, cv2.NORM_L2) / len(imgpoints2)
    total_error += error
print(f"平均重投影误差: {total_error/len(obj_points):.4f} px")

4.5 实战案例:工业相机标定与精度验证

场景背景:某机器人抓取系统使用 Basler acA2440-75um 相机(2448×2048 分辨率,像元 3.45μm)搭配 16mm 镜头,工作距离 600mm,要求抓取定位精度 ±0.5mm。标定前发现机械臂视觉引导在视野边缘误差达 8mm。

初始现象:使用默认内参(厂家标称值)进行手眼标定后,在视野中心区域定位误差约 1.2mm,边缘区域误差急剧增大至 8mm,且呈明显桶形失真特征。

关键输入数据:采用 12×9 棋盘格(方格边长 25mm,平面度 0.05mm),采集 22 张图像,覆盖不同角度和位置。初始重投影误差 0.35px,其中 k1 = -0.082,p1 = 0.0012。

分析判断:重投影误差 0.35px 虽在可接受范围(<0.5px),但结合边缘误差 8mm 的表现,判断是畸变模型未充分拟合边缘区域。进一步检查发现,k3 系数标准差过大(0.015 vs 系数值 0.008),说明 k3 不可靠。

操作步骤:

  1. 将畸变模型从 5 参数(含 k3)降为 4 参数(去掉 k3),重新标定。
  2. 增加 5 张标定板靠近画面边缘的图像,提高边缘区域权重。
  3. 使用 cv2.getOptimalNewCameraMatrix 计算优化后的内参,并采用 cv2.undistort 校正图像。
  4. 校正后重新进行手眼标定,验证定位精度。

结果对比:重投影误差从 0.35px 降至 0.12px;视野边缘定位误差从 8mm 降至 0.8mm;中心区域误差从 1.2mm 降至 0.3mm。系统整体抓取成功率从 82% 提升至 97%。

风险与代价:增加边缘图像后,标定时间从 5 分钟延长至 8 分钟;但精度提升显著。复盘发现,初始标定失败的主因是图像采集时标定板始终位于画面中心区域,导致畸变模型对边缘拟合不足。

复盘经验:标定图像的空间分布比数量更重要。务必确保标定板覆盖画面四角和边缘,且倾斜角度多样化。建议使用标定辅助工具(如 OpenCV 的 calibrateCamera 返回的 per-view 误差)逐张检查,剔除重投影误差大于 0.5px 的异常图像。

4.6 常见误区与工程建议

误区后果正确做法
使用打印纸标定板平面度差,精度损失 30%+使用玻璃/陶瓷基板光刻标定板
图像数量不足 10 张内参过拟合,泛化差至少 15 张,覆盖全视野
忽略 k3 系数可靠性边缘畸变校正过度检查系数标准差,不可靠则置零
标定后不验证误差累积到外参标定用独立测试图验证重投影误差
固定焦距/光圈后重新标定内参失效变焦或调光圈后必须重新标定

最后强调,内参标定不是一次性工作。在车载、机器人等振动环境中,镜头固定螺丝松动或温度变化都会导致内参漂移。建议每 3-6 个月或每次拆装镜头后重新标定,并在外参标定前用 cv2.projectPoints 快速验证内参一致性。