4. 鱼眼相机标定原理
棋盘格角点检测,是相机标定里最基础也最关键的环节。说白了,就是让算法在图像里找到那些黑白格子相交的角点。你想想看,如果这一步不准,后面算出来的内参、畸变系数全是错的。我在项目里见过不少团队,标定板拍了一堆,结果角点检测不过,白白浪费采集时间。
4.1 标定板设计:别小看这张棋盘
先聊聊标定板怎么选。很多人觉得随便打印一张棋盘纸就行,其实坑不少。
| 参数 | 推荐值 | 我的经验 |
|---|---|---|
| 棋盘格数(内角点) | 9×6 或 11×8 | 奇数×偶数,避免对称歧义 |
| 方格尺寸 | 20mm ~ 40mm | 太大占画面,太小看不清 |
| 材质 | 亚光覆膜纸 / 铝板 | 反光板子会让角点检测崩溃 |
| 背景 | 纯色(黑/白/灰) | 不要有纹理干扰 |
4.2 采集规范:拍多少?怎么拍?
标定板采集不是随便拍几张就完事。我建议至少拍20~30张,覆盖以下姿态:
- 中心区域:标定板放在画面正中央,正对相机
- 边缘区域:标定板靠近画面四角,倾斜15°~30°
- 远近变化:从最近到最远,覆盖整个景深范围
- 旋转变化:绕X、Y、Z轴各旋转一些角度
为什么要这么多?因为鱼眼相机的畸变在边缘特别大,如果只拍中心区域,畸变参数根本算不准。我记得有一次,客户只给了8张图,结果标定出来的重投影误差0.8像素,怎么调都下不去。后来补拍到25张,误差直接降到0.15像素。
4.3 OpenCV 角点检测:findChessboardCorners
OpenCV 提供了现成的函数 cv::findChessboardCorners。它的核心逻辑是:先对图像做自适应阈值二值化,然后找四边形轮廓,再通过拓扑关系定位角点。
// C++ 示例
cv::Mat gray;
cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
cv::Size patternSize(9, 6); // 内角点数:9列×6行
std::vector<cv::Point2f> corners;
bool found = cv::findChessboardCorners(
gray,
patternSize,
corners,
cv::CALIB_CB_ADAPTIVE_THRESH |
cv::CALIB_CB_NORMALIZE_IMAGE |
cv::CALIB_CB_FAST_CHECK
);
if (found) {
cv::drawChessboardCorners(image, patternSize, corners, found);
}
这里有几个参数值得注意:
CALIB_CB_ADAPTIVE_THRESH:自适应阈值,应对光照不均CALIB_CB_NORMALIZE_IMAGE:直方图均衡化,提升对比度CALIB_CB_FAST_CHECK:快速预检,先判断有没有棋盘格,没有就跳过
我个人习惯把这三个标志位全开。虽然慢一点点,但鲁棒性高很多。特别是鱼眼图像边缘光照很差,不开自适应阈值经常检测不到。
4.4 亚像素精细化:从像素级到亚像素级
findChessboardCorners 返回的角点坐标是整数像素精度。对于标定来说,这远远不够。我们需要用 cv::cornerSubPix 做亚像素精细化。
cv::TermCriteria criteria(
cv::TermCriteria::EPS + cv::TermCriteria::MAX_ITER,
30, // 最大迭代次数
0.001 // 精度阈值
);
cv::cornerSubPix(
gray,
corners,
cv::Size(5, 5), // 搜索窗口半宽
cv::Size(-1, -1), // 死区,一般设为-1
criteria
);
它的原理是:在角点附近的小窗口内,利用梯度信息迭代优化,找到灰度变化最大的位置。说白了,就是让角点坐标从 (100, 200) 变成 (100.345, 200.678)。
4.5 检测失败怎么办?
我在项目中遇到过几次检测失败的情况,总结下来主要有三种:
- 光照太强或太暗:棋盘格边缘模糊,二值化后格子连成一片。解决方案:调整光源,或者用
cv::CLAHE做局部直方图均衡。 - 标定板倾斜过大:超过45°时,棋盘格变形严重,四边形检测失败。解决方案:控制倾斜角在30°以内。
- 图像分辨率太低:每个格子少于20个像素,角点定位不准。解决方案:换更高分辨率相机,或者靠近拍摄。
嗯,这里要注意:如果检测失败,不要硬调参数。先检查标定板本身——是不是脏了?是不是反光?是不是没贴平?这些物理因素比算法参数更重要。
4.6 知识体系图
下面这张图梳理了本章的核心流程,从标定板设计到角点输出,每一步都环环相扣。
4.7 实战建议
最后,给你几个我在项目中沉淀下来的建议:
- 先做一次完整流程:用一张图跑通检测+亚像素+可视化,确认参数没问题
- 批量检测时加日志:记录每张图的检测结果和角点数,方便排查问题
- 保存中间结果:把检测到的角点坐标存成文件,避免每次标定都重新检测
- 可视化检查:用
drawChessboardCorners画出角点,肉眼确认有没有错位