第三章 张正友标定法:棋盘格检测、单应性矩阵与标定流程
张正友标定法,说白了就是用一个棋盘格照片,把相机的内参和外参算出来。这个方法在工业视觉里用得特别多,因为它操作简单,精度也够用。我最早接触这个方法是做手机摄像头标定的时候,那时候还不太理解背后的原理,后来做3D抓取项目,才发现这步要是没做好,后面全白搭。
3.1 棋盘格检测——标定的第一步
棋盘格检测是整个标定流程的入口。你想想看,如果连角点都找不准,后面算出来的参数能靠谱吗?
棋盘格检测的核心任务就是找到黑白格子相交的那些角点。OpenCV里提供了cv::findChessboardCorners这个函数,用起来很方便,但实际项目中坑不少。
棋盘格检测的关键步骤:
- 图像预处理——转灰度、直方图均衡化,让黑白格子对比更明显
- 粗定位——用图像梯度找到候选角点位置
- 亚像素精化——用
cv::cornerSubPix把精度推到亚像素级别 - 排序与验证——按行按列把角点排好,检查是否漏检或误检
我记得有一次在产线上做标定,光线条件很差,棋盘格反光严重,findChessboardCorners死活检测不出来。后来我加了一步自适应阈值处理,问题就解决了。嗯,这里要注意,棋盘格一定要是非对称的——比如9×6,而不是8×8,否则方向会搞混。
我的经验:标定用的棋盘格最好打印在平整的硬板上,不要贴在软布上。我见过有人用A4纸打印,结果纸一皱,标定出来的焦距偏差了5%以上。
3.2 单应性矩阵——从平面到平面的映射
单应性矩阵(Homography)是张正友标定法的数学核心。它描述的是两个平面之间的透视变换关系。在标定场景里,就是棋盘格平面和相机成像平面之间的映射。
数学上,单应性矩阵是一个3×3的矩阵,有8个自由度。为什么是8个?因为尺度归一化后,最后一个元素固定为1。我刚开始学的时候老搞混这个,后来自己推导了一遍才明白。
// 单应性矩阵的数学形式
// s * [u, v, 1]^T = H * [X, Y, 1]^T
// 其中 H = [h11, h12, h13; h21, h22, h23; h31, h32, 1]
// OpenCV中计算单应性矩阵
cv::Mat H = cv::findHomography(objectPoints, imagePoints, cv::RANSAC);
单应性矩阵的求解至少需要4对匹配点。但实际项目中,我建议用棋盘格上所有的角点来算,然后用RANSAC剔除异常点。这样做出来的H矩阵更稳定。
| 参数 | 含义 | 自由度 |
|---|---|---|
| h11, h12 | 旋转与缩放(x方向) | 2 |
| h21, h22 | 旋转与缩放(y方向) | 2 |
| h13, h23 | 平移量 | 2 |
| h31, h32 | 透视畸变 | 2 |
避坑指南:我曾经在计算单应性矩阵时,直接用DLT(直接线性变换)方法,结果遇到共线点的情况,矩阵奇异了。后来改用SVD分解加最小二乘,才稳定下来。记住,点不能共线,这是基本要求。
3.3 标定流程——从图像到参数
张正友标定法的完整流程,我把它总结成6个步骤。每一步都有它的物理意义,不是随便走个过场。
- 准备棋盘格——打印一张棋盘格,测量每个格子的实际尺寸(单位mm)
- 采集多张图像——从不同角度拍摄棋盘格,至少10-15张
- 检测角点——用
findChessboardCorners找到所有角点 - 计算单应性矩阵——对每张图像,计算棋盘格平面到成像平面的H矩阵
- 求解内参——利用多张图像的H矩阵,通过闭合解算出内参初值
- 非线性优化——用Levenberg-Marquardt算法对所有参数做全局优化
这里我特别想强调第2步。很多人随便拍几张就完事了,结果标定出来的参数偏差很大。我个人的习惯是:棋盘格要占图像面积的1/3以上,而且角度要覆盖俯仰、偏航、滚转三个方向。
采集图像的黄金法则:
- 至少15张图像,20张更保险
- 棋盘格在图像中心、左上、右上、左下、右下各拍几张
- 倾斜角度控制在30°到60°之间
- 确保棋盘格在景深范围内清晰
OpenCV里封装了完整的标定流程,核心函数就是cv::calibrateCamera。它会自动完成从单应性矩阵到内参求解,再到非线性优化的全过程。
// OpenCV标定核心代码
std::vector<cv::Mat> rvecs, tvecs;
cv::Mat cameraMatrix, distCoeffs;
double rms = cv::calibrateCamera(
objectPoints, // 世界坐标系中的棋盘格角点
imagePoints, // 图像坐标系中的角点
imageSize, // 图像尺寸
cameraMatrix, // 输出:内参矩阵
distCoeffs, // 输出:畸变系数
rvecs, tvecs, // 输出:每张图像的旋转和平移
cv::CALIB_FIX_ASPECT_RATIO // 标志位
);
标定完成后,一定要做重投影误差检查。这个值通常应该在0.1到0.5像素之间。如果超过1个像素,说明标定质量有问题,需要重新采集数据。
我的判断标准:重投影误差 < 0.3像素,标定质量优秀;0.3-0.8像素,可以接受;> 1像素,建议重做。我在一个3D抓取项目里,标定误差从0.8降到0.2后,抓取成功率从85%提升到了97%。
3.4 标定流程知识图谱
下面这张图把整个标定流程串起来了,从图像采集到参数输出,每一步的输入输出关系都画清楚了。
这张图把整个流程串成了一个闭环。从棋盘格准备开始,到非线性优化结束,中间每一步都环环相扣。我建议你在实际项目中,也按照这个流程来走,不要跳步。
最后提醒一句:标定不是一次性的事。相机在使用过程中,镜头松动、温度变化都可能导致参数漂移。我一般建议每3个月重新标定一次,或者在设备维修后立即标定。别等到抓取精度出问题了才想起来。