4. 相机内参标定:张正友标定法原理、棋盘格角点检测、单应性矩阵求解、内参优化
相机内参标定,说白了就是搞清楚镜头和传感器之间的那点「小秘密」。
你想想看,一个三维世界里的点,怎么投影到二维图像上的?中间经历了哪些扭曲和缩放?这些参数,就是内参。我做了这么多年标定,见过太多因为内参不准导致车道线识别偏移的案例。嗯,今天我们就来聊聊最经典的张正友标定法。
4.1 张正友标定法原理
张正友法为什么经典?因为它只需要你打印一张棋盘格,拍几张不同角度的照片就行。不需要昂贵的三维标定块,也不需要精密的机械装置。
它的核心思想其实很简单:
- 我们知道棋盘格上每个角点的物理坐标(假设Z=0)
- 我们也知道这些角点在图像上的像素坐标
- 通过这两组对应关系,反推出相机的内参和外参
我个人习惯把张正友法理解成「两步走」:先线性求解一个初始值,再用非线性优化去微调。为什么需要两步?因为直接做非线性优化容易掉进局部最优,有个好初值就稳多了。
核心公式:
s * m = A * [R | t] * M
其中:
- m 是图像坐标
- M 是世界坐标
- A 是内参矩阵
- [R | t] 是外参矩阵
- s 是尺度因子
4.2 棋盘格角点检测
这一步是标定的基础。角点检测不准,后面算什么都白搭。
我记得有一次在项目现场,光线条件很差,棋盘格反光严重,角点检测总是跳点。后来我加了一个自适应阈值预处理,才把问题解决。
常用的检测方法:
- Harris角点检测:计算每个像素的梯度变化,找到响应值最大的点
- 亚像素精化:在整数像素位置附近做插值,把精度推到亚像素级别
- 棋盘格模式识别:利用棋盘格的黑白交替规律,排除误检
OpenCV里直接用 cv2.findChessboardCorners() 就能搞定。但我要提醒你,这个函数对图像质量很敏感。我建议你拍照时注意三点:
- 棋盘格要占画面1/4以上
- 光照均匀,不要有强反光
- 角度变化要丰富,别老拍正面
我的小技巧:
拍20张左右就够了。太多反而增加计算量,太少则参数不稳定。我一般拍15-25张,覆盖画面的各个角落。
4.3 单应性矩阵求解
单应性矩阵,说白了就是描述两个平面之间映射关系的矩阵。在张正友法里,它连接了棋盘格平面和图像平面。
为什么需要它?因为我们可以通过单应性矩阵,把外参消掉,直接得到内参的约束方程。
求解过程:
- 每张棋盘格照片,都能计算出一个单应性矩阵 H
- H 是 3x3 的矩阵,有8个自由度
- 通过至少4对匹配点,用DLT算法求解
你可能会问:为什么是4对?因为每对点提供两个方程,4对就是8个方程,刚好解8个未知数。当然,实际中我们会用更多点,用最小二乘法来降低噪声影响。
注意:
单应性矩阵求解时,一定要对数据进行归一化处理。我见过有人直接拿原始坐标去算,结果矩阵条件数很大,解出来的参数一塌糊涂。归一化后,数值稳定性会好很多。
4.4 内参优化
线性求解得到的内参,精度还不够。为什么?因为它没有考虑镜头畸变。
镜头畸变主要有两种:
- 径向畸变:图像边缘的直线会变弯,像鱼眼效果
- 切向畸变:镜头和传感器不平行导致的变形
优化的目标函数是重投影误差——就是把三维点投影到图像上,算算和实际检测到的角点差了多少像素。这个误差越小,标定结果越好。
我常用的优化方法:
- Levenberg-Marquardt算法:收敛快,适合这种小规模优化问题
- 先优化内参,再优化畸变参数:分开优化比一起优化更稳定
- 用多张图片联合优化:单张图片的信息量不够,多张才能把参数约束住
优化后的输出:
| 参数 | 含义 | 典型值(1280x720分辨率) |
|---|---|---|
| fx, fy | 焦距(像素单位) | ~800-1200 |
| cx, cy | 主点坐标 | ~640, 360 |
| k1, k2, k3 | 径向畸变系数 | ~0.1 ~ -0.5 |
| p1, p2 | 切向畸变系数 | ~0.001 |
优化完成后,我习惯做一件事:把标定结果应用到实际图像上,看看校正后的车道线是不是直的。如果直线变直了,说明标定没问题。如果还有弯曲,那就得回头检查角点检测或者优化过程了。
避坑指南:
我曾经遇到过一个问题:标定结果在实验室里完美,但上车后就跑偏。后来发现是温度变化导致镜头参数漂移了。所以,量产级的标定一定要考虑温度补偿,或者选用温漂小的镜头。
知识体系总览
好了,以上就是相机内参标定的核心内容。从原理到角点检测,从单应性矩阵到内参优化,每一步都有它的道理。做标定这件事,急不得,也马虎不得。参数差一点点,车道线识别就可能偏出去几十厘米。