4、双目相机标定:棋盘格标定法、立体标定、极线校正原理与OpenCV实现
双目立体视觉的核心任务是利用左右两台相机对同一场景成像的视差(Disparity)来恢复深度信息。然而,视差计算的精度完全依赖于两台相机之间的几何关系是否被精确建模。如果左右图像对没有经过严格的标定与校正,即使匹配算法再优秀,得到的深度图也会出现严重的畸变和误差。本章将系统讲解双目相机标定的完整技术链路:从单目棋盘格标定的内参解算,到双目立体标定的外参(旋转矩阵与平移向量)求解,再到极线校正(Stereo Rectification)的数学原理与OpenCV工程实现。我们将深入剖析每一步的物理意义、代码实现细节以及工程中常见的坑点,帮助读者构建一套可落地的双目相机标定与校正方案。
4.1 棋盘格标定法:单目内参与畸变解算
棋盘格标定法(Zhang's Method)是当前工业界与学术界最主流的相机标定方法。其核心思想是:通过拍摄不同姿态下的平面棋盘格,利用角点检测获取图像坐标,结合已知的棋盘格物理尺寸(方格边长),建立从三维世界坐标到二维像素坐标的投影关系,从而求解相机的内参矩阵(焦距、主点)和畸变系数(径向畸变与切向畸变)。
4.1.1 核心原理:从世界坐标到像素坐标的映射
相机成像模型可简化为四个坐标系的变换:世界坐标系 → 相机坐标系 → 图像物理坐标系 → 像素坐标系。其数学表达式为:
s * [u, v, 1]^T = K * [R | t] * [X, Y, Z, 1]^T
其中,K为内参矩阵(包含fx, fy, cx, cy),R和t为相机相对于标定板的外参。棋盘格标定法利用至少3个不同姿态的标定板图像(通常建议10-20张),通过最小化重投影误差(Reprojection Error)来优化内参、外参和畸变系数。畸变模型通常采用Brown-Conrady模型,包含径向畸变(k1, k2, k3)和切向畸变(p1, p2)。
4.1.2 操作流程:OpenCV单目标定步骤
- 图像采集:使用双目相机同步拍摄棋盘格,确保棋盘格在视场中占据约1/3至1/2面积,且姿态多样(倾斜、旋转、远近)。
- 角点检测:使用
cv2.findChessboardCorners()提取亚像素级角点,并用cv2.cornerSubPix()细化。 - 参数初始化:生成棋盘格的世界坐标(假设Z=0平面),例如7×9的棋盘格,方格边长30mm。
- 标定求解:调用
cv2.calibrateCamera()得到内参矩阵K、畸变系数D、每张图的旋转向量rvec和平移向量tvec。 - 精度评估:计算重投影误差,通常要求小于0.1像素;若误差过大,需剔除异常图像或重新采集。
4.1.3 案例拆解:单目标定的工程实践
假设我们使用分辨率为1280×720的双目相机,棋盘格为9×6内角点,方格边长25mm。采集20张图像后,OpenCV返回的重投影误差为0.08像素,内参矩阵为:
K = [fx, 0, cx;
0, fy, cy;
0, 0, 1]
fx = 820.35, fy = 821.10, cx = 639.50, cy = 359.80
畸变系数: k1=-0.045, k2=0.012, p1=0.001, p2=-0.002, k3=0.000
从结果看,主点cx接近图像中心640,说明镜头安装较正;fx与fy差异小于1像素,表明像素单元近似正方形。若重投影误差大于0.3像素,应检查标定板是否平整、图像是否模糊、角点检测是否准确。
4.1.4 常见误区与总结
- 误区一:标定板图像越多越好。实际上,超过20张后精度提升有限,且过多相似姿态的图像反而可能引入冗余误差。
- 误区二:忽略标定板平整度。打印的棋盘格应贴在刚性平板上,否则角点坐标存在系统性偏差。
- 误区三:只标定一次。镜头松动、温度变化、焦距调整后必须重新标定。
4.2 立体标定:求解左右相机的相对位姿
单目标定解决了单台相机的内参问题,但双目系统还需要知道左右相机之间的空间变换关系,即旋转矩阵R和平移向量T。立体标定(Stereo Calibration)正是利用同一时刻拍摄的左右图像对,联合优化两相机的内参、畸变以及外参(R, T),使得左右相机对同一世界点的投影误差最小。
4.2.1 核心原理:本质矩阵与基础矩阵
立体标定的输出包括:
- 旋转矩阵R:将左相机坐标系变换到右相机坐标系的旋转。
- 平移向量T:左相机原点在右相机坐标系下的平移量。
- 本质矩阵E:E = [T]× R,描述了两相机坐标系下的对极几何约束。
- 基础矩阵F:F = K_R^{-T} E K_L^{-1},描述了像素坐标系下的对极约束。
OpenCV的 cv2.stereoCalibrate() 函数接受左右相机的内参、畸变系数以及对应的角点对,输出R、T、E、F。该函数内部使用Levenberg-Marquardt优化算法,最小化所有角点的重投影误差之和。
4.2.2 操作流程:立体标定的关键步骤
- 数据准备:使用双目相机同步采集10-20组棋盘格图像对,确保左右图像均能完整看到棋盘格。
- 角点提取:分别对左右图像提取角点,并确保左右角点一一对应(使用相同的棋盘格尺寸)。
- 立体标定:调用
cv2.stereoCalibrate(),传入左右内参、畸变、角点世界坐标和图像坐标。 - 结果验证:输出R、T后,检查平移向量的模长是否与基线距离(两相机光心间距)大致相符。例如,若基线为120mm,则||T||应接近120mm。
stereoCalibrate()。如果直接使用默认内参,可能导致优化陷入局部极小值,输出错误的R和T。
4.2.3 案例拆解:立体标定的精度验证
某双目相机基线为100mm,标定后得到:
R = [ 0.9999, -0.0012, 0.0008;
0.0012, 0.9999, 0.0005;
-0.0008, -0.0005, 1.0000 ]
T = [ -99.85, 0.12, -0.08 ] (单位mm)
旋转矩阵接近单位阵,说明两相机光轴几乎平行;平移向量x分量约-100mm,与基线长度吻合。若T的y或z分量过大(如超过5mm),说明两相机存在明显的安装倾斜,需要检查机械结构。
4.2.4 常见误区与总结
- 误区一:忽略同步触发。如果左右相机不是硬件同步,棋盘格在移动时会产生运动模糊或位置偏差,导致角点对不齐。
- 误区二:标定板姿态单一。如果所有图像中棋盘格都正对相机,无法准确估计旋转矩阵,应增加倾斜和旋转姿态。
- 误区三:不检查重投影误差。立体标定的重投影误差应小于0.2像素,否则需要剔除误差较大的图像对。
4.3 极线校正原理:将双目几何转换为标准形式
极线校正(Stereo Rectification)是双目视觉中承上启下的关键步骤。其目的是通过重投影(Reprojection),将左右图像变换为“行对齐”的标准形式:即左右图像中同一空间点的投影位于同一水平线上。这样,立体匹配的搜索空间从二维降为一维,大幅提升计算效率与匹配精度。
4.3.1 核心原理:对极几何与校正目标
在未校正的双目系统中,左图像上的一个点p_L,其在右图像上的对应点p_R必然位于一条极线(Epipolar Line)上。极线校正通过计算两个单应性矩阵(Homography),将左右图像分别投影到共同的平面上,使得极线变为水平且平行。校正后的图像满足:
- 左右图像的行坐标(v)完全一致。
- 视差仅存在于列坐标(u)方向。
- 深度Z与视差d成反比:Z = f * B / d,其中f为焦距(像素),B为基线长度。
4.3.2 操作流程:OpenCV极线校正实现
- 调用stereoRectify:输入立体标定得到的R、T以及左右内参、畸变,输出左右校正旋转矩阵R1、R2,投影矩阵P1、P2,以及视差到深度映射矩阵Q。
- 计算校正映射:使用
cv2.initUndistortRectifyMap()分别计算左右图像的映射表(map1, map2)。 - 应用重映射:使用
cv2.remap()对原始图像进行重采样,得到校正后的图像对。 - 验证校正效果:在左右校正图像上绘制水平线,检查对应特征点是否位于同一行。
# 核心代码示例
R1, R2, P1, P2, Q, _, _ = cv2.stereoRectify(
K_L, D_L, K_R, D_R, (width, height), R, T,
alpha=0, newImageSize=(width, height))
map1_L, map2_L = cv2.initUndistortRectifyMap(
K_L, D_L, R1, P1, (width, height), cv2.CV_32FC1)
map1_R, map2_R = cv2.initUndistortRectifyMap(
K_R, D_R, R2, P2, (width, height), cv2.CV_32FC1)
rectified_L = cv2.remap(img_L, map1_L, map2_L, cv2.INTER_LINEAR)
rectified_R = cv2.remap(img_R, map1_R, map2_R, cv2.INTER_LINEAR)
4.3.3 案例拆解:校正效果评估与调优
某项目使用双目相机采集室内场景,校正前左右图像中同一物体的投影点行坐标相差约15像素。经过stereoRectify校正后,行坐标差降至0.5像素以内。进一步使用 cv2.computeCorrespondEpilines() 计算极线,发现极线斜率从0.3降至0.01,验证了校正效果。若校正后仍存在较大行差,可尝试调整 alpha 参数(0表示裁剪最少,1表示保留所有像素),或增大校正图像的尺寸以减少边缘畸变。
4.3.4 常见误区与总结
- 误区一:校正后图像出现黑色边框。这是因为校正变换导致图像边缘被裁剪,可通过设置
alpha=1保留全部像素,但会引入无效区域。 - 误区二:忽略畸变校正。如果输入stereoRectify的畸变系数不准确,校正后的图像仍会有残余畸变。
- 误区三:校正后不验证。必须通过绘制水平线或计算极线误差来确认校正质量,否则后续深度估计将产生系统性偏差。
4.4 实战案例:双目相机标定全流程闭环
为帮助读者建立完整的工程认知,我们以一个实际项目为例,展示从图像采集到深度图生成的全流程。
4.4.1 项目背景与约束
某移动机器人平台搭载双目相机,基线120mm,分辨率1280×720,视场角约90°。要求深度测量范围0.5m-5m,精度优于2%。项目约束:标定时间有限(不超过30分钟),且现场无法使用高精度标定板,只能使用A4纸打印的棋盘格(方格边长25mm)。
4.4.2 初始现象与问题
初次使用OpenCV默认参数标定后,重投影误差为0.35像素,生成的深度图在边缘区域出现明显的“拉丝”现象,且远处物体的深度值波动超过5%。初步判断是标定精度不足导致极线校正不彻底。
4.4.3 分析与优化过程
- 检查标定板质量:发现A4纸存在轻微弯曲,导致角点坐标偏差。改用硬纸板衬底,并确保表面平整。
- 增加图像数量与姿态:从12张增加到18张,并增加棋盘格倾斜45°和旋转30°的姿态。
- 优化角点检测:使用
cv2.cornerSubPix()时,设置窗口大小为11×11,迭代终止条件为0.001像素。 - 重新标定:重投影误差降至0.08像素,立体标定的T向量x分量为-119.8mm,与基线吻合。
- 校正验证:绘制水平线检查,行坐标差从3像素降至0.3像素。
4.4.4 结果对比与复盘
| 指标 | 优化前 | 优化后 | 提升幅度 |
|---|---|---|---|
| 重投影误差 (像素) | 0.35 | 0.08 | 77% |
| 极线行差 (像素) | 3.0 | 0.3 | 90% |
| 深度误差 (5m处) | 5.2% | 1.8% | 65% |
| 边缘拉丝现象 | 明显 | 消失 | — |
复盘经验:标定精度对深度估计的影响是决定性的。在资源受限的情况下,优先保证标定板平整、图像清晰、姿态多样,比单纯增加图像数量更有效。此外,校正后的验证环节不可省略,它是发现标定问题的最后一道防线。
4.5 本章总结与工程建议
双目相机标定与极线校正是立体视觉系统的“地基工程”。本章从单目棋盘格标定出发,逐步深入到立体标定和极线校正,并给出了完整的OpenCV实现路径。在实际工程中,建议遵循以下原则:
- 标定频率:每次拆装镜头、碰撞或温度剧烈变化后,必须重新标定。
- 精度指标:单目重投影误差 < 0.1像素,立体重投影误差 < 0.2像素,极线行差 < 1像素。
- 工具链:使用OpenCV的
calibrateCamera、stereoCalibrate、stereoRectify三件套,配合remap完成校正。 - 验证闭环:校正后必须通过绘制水平线或计算极线误差来验证,确保后续深度估计的输入数据可靠。
掌握本章内容后,读者应能独立完成一套双目相机的标定与校正流程,为后续的立体匹配与深度估计打下坚实基础。