3、单目标定基础:棋盘格标定板设计、角点检测原理、张正友标定法核心思想

好,咱们进入单目标定这个环节。说实话,这是整个多摄像头系统里最基础、也最容易被忽视的一步。很多人一上来就急着做双目标定、联合标定,结果发现数据对不上,回头一查——单目标定就没做扎实。

我个人习惯,做任何多传感器融合项目之前,先把每个传感器的内参和畸变系数标得清清楚楚。这就像盖房子打地基,地基歪了,上面再漂亮也没用。

3.1 棋盘格标定板设计——别小看这张格子纸

棋盘格,说白了就是一张黑白相间的格子图案。但这里面的门道,比你想象的多。

3.1.1 棋盘格的物理参数

设计棋盘格时,你需要明确两个关键参数:

  • 内角点数量:比如 9×6,指的是内部角点,不是格子数。我见过有人把格子数当角点数用,结果程序报错半天找不出原因。
  • 方格尺寸:单位通常是毫米。比如每个格子 30mm×30mm。

重要提醒:角点数量 = (列数-1) × (行数-1)。比如一张 10×7 的棋盘格,内角点是 9×6 = 54 个。

3.1.2 打印与使用建议

我在项目中遇到过最坑的事——用普通A4纸打印棋盘格,贴在纸板上。结果环境湿度一变,纸皱了,角点检测全偏了。

所以我的建议是:

  • 用铝塑板或亚克力板做底板,保证平整
  • 打印精度至少 600dpi,边缘要清晰
  • 棋盘格尺寸不要太小,否则远距离拍摄时角点看不清
  • 尺寸也不要太大,否则近距离拍摄时拍不全

我的经验:对于常见的工业相机(500万像素左右),棋盘格边长 25-40mm 比较合适。内角点数量推荐 9×6 或 11×8。

3.2 角点检测原理——计算机是怎么找到那些交叉点的?

你想想看,一张棋盘格图片里,计算机怎么知道哪些点是角点?

嗯,这里要讲一个经典算法——Harris 角点检测。不过 OpenCV 里用的其实是它的改进版,叫 findChessboardCorners

3.2.1 角点的数学定义

角点,就是图像中两个边缘方向都发生剧烈变化的点。说白了,你往上下左右移动一个小窗口,如果窗口内的像素变化都很大,那这个点就是角点。

数学上,Harris 用了一个矩阵来描述这种变化:

M = ∑ [ Ix²   IxIy ]
        [ IxIy  Iy²  ]

其中 Ix 和 Iy 是图像在 x 和 y 方向的梯度。然后计算响应值 R:

R = det(M) - k * trace(M)²

R 大于某个阈值,就是角点。

3.2.2 OpenCV 中的实现

实际用的时候,你不需要自己写 Harris。OpenCV 已经封装好了:

ret, corners = cv2.findChessboardCorners(gray, (9, 6), None)

这个函数会返回角点的像素坐标。但注意,它返回的坐标是亚像素级别的——什么意思?就是精度能达到小数点后几位。

我曾经踩过的坑:直接用 findChessboardCorners 返回的坐标做标定,结果重投影误差总是下不去。后来发现需要再用 cornerSubPix 做亚像素精细化。这一步不能省。

亚像素细化的代码:

criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
corners = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)

3.3 张正友标定法核心思想——为什么它成了行业标准?

张正友标定法,1998年提出的,到现在二十多年了,依然是单目标定的主流方法。为什么?因为它解决了两个核心问题:

  1. 不需要知道标定板的精确三维位置——你只需要拿着棋盘格在相机前晃一晃
  2. 精度足够高——对于绝大多数应用场景,重投影误差能控制在 0.1 像素以内

3.3.1 核心思想:从单应性矩阵出发

张正友的方法,说白了就是利用棋盘格是平面这个事实。因为棋盘格是平的,所以世界坐标系的 Z 坐标恒为 0。这样,投影方程就简化了。

投影方程简化后:

s * [u, v, 1]^T = K * [r1, r2, t] * [X, Y, 1]^T

其中 K 是内参矩阵,r1、r2 是旋转矩阵的前两列,t 是平移向量。

这个 3×3 的矩阵,就是单应性矩阵 H。每拍一张棋盘格图片,就能得到一个 H。

3.3.2 求解过程:两步走

张正友的方法分两步:

  • 第一步:线性求解——利用多张图片的单应性矩阵,构建超定方程组,用最小二乘法求出内参的初始值
  • 第二步:非线性优化——用最大似然估计,对所有参数(内参、畸变、外参)进行联合优化,最小化重投影误差

关键点:至少需要 3 张不同角度的棋盘格图片才能求解。我一般拍 15-20 张,覆盖视野的各个区域,尤其是边缘部分。

3.3.3 畸变模型

张正友方法还考虑了镜头畸变,主要是径向畸变和切向畸变:

x_distorted = x * (1 + k1*r² + k2*r⁴ + k3*r⁶) + 2*p1*x*y + p2*(r² + 2*x²)
y_distorted = y * (1 + k1*r² + k2*r⁴ + k3*r⁶) + p1*(r² + 2*y²) + 2*p2*x*y

其中 k1、k2、k3 是径向畸变系数,p1、p2 是切向畸变系数。

我的习惯:对于普通工业镜头,一般只标定 k1、k2 和 p1、p2 就够了。k3 通常用于鱼眼镜头。标定太多参数反而容易过拟合。

3.4 实战中的注意事项

最后,分享几个我在项目中积累的经验:

注意事项 说明
图片数量 至少 10 张,覆盖不同角度和距离。我一般拍 15-20 张
光照条件 避免反光和阴影。均匀光照最好
棋盘格姿态 要有倾斜、旋转、平移的变化。不要只拍正对着的
重投影误差 一般应小于 0.5 像素。如果大于 1 像素,说明标定有问题
标定板平整度 这是最容易忽略的。不平整的标定板,标定结果全是错的

嗯,单目标定这块内容就这些。下一章我们会讲双目标定,到时候你会看到,单目标定的结果会直接影响双目系统的精度。所以,这一章的内容,建议你动手实践一下,拍几张棋盘格跑一遍标定流程,感受一下。

记住一句话:标定不是一次性的工作。每次更换镜头、调整光圈、或者环境温度变化较大时,都建议重新标定一次。