4. 相机内参标定原理:针孔模型、畸变模型与标定流程

相机内参标定,说白了就是搞清楚你的眼睛(镜头)到底是怎么看世界的。我刚开始接触3D视觉时,总觉得标定是个“玄学”——明明棋盘格摆得端端正正,结果就是不对。后来踩的坑多了,才明白这背后其实就两件事:针孔模型和畸变模型。

这一章,咱们就把这两个模型掰开揉碎,再聊聊标定的完整流程。你想想看,如果连相机怎么看世界都不清楚,后面的3D测量和抓取怎么可能准?

4.1 针孔模型——相机成像的“理想国”

针孔模型是最简单的成像模型。它假设光线从物体出发,穿过一个小孔,在后面的成像平面上形成倒像。这个模型虽然理想化,但它是所有标定算法的基础。

核心公式其实就一个投影关系:

// 世界坐标系到像素坐标系的映射
// [u, v, 1]^T = K * [R|t] * [X, Y, Z, 1]^T

// 其中 K 是内参矩阵:
// K = [fx,  0, cx;
//       0, fy, cy;
//       0,  0,  1]

这里 fx、fy 是焦距(以像素为单位),cx、cy 是主点坐标。说白了,内参矩阵就是描述“从相机坐标系到像素坐标系”的映射关系。

关键点:针孔模型假设镜头是完美的,光线沿直线传播。但现实中没有完美的镜头,所以我们需要畸变模型来修正。

4.2 畸变模型——现实世界的“不完美”

我在项目中遇到过最头疼的问题,就是标定完发现边缘的测量误差特别大。后来一查,原来是畸变参数没调好。畸变主要分两类:径向畸变和切向畸变。

4.2.1 径向畸变

径向畸变是镜头曲率造成的。离光心越远,畸变越明显。它分为两种:

  • 桶形畸变:图像边缘向外凸出,像桶一样。常见于广角镜头。
  • 枕形畸变:图像边缘向内凹陷。常见于长焦镜头。

数学模型用泰勒级数展开:

x_corrected = x * (1 + k1 * r^2 + k2 * r^4 + k3 * r^6)
y_corrected = y * (1 + k1 * r^2 + k2 * r^4 + k3 * r^6)

其中 r 是像素到光心的距离,k1、k2、k3 是径向畸变系数。一般只用 k1 和 k2 就够了,k3 只在鱼眼镜头等极端情况下才用。

4.2.2 切向畸变

切向畸变是镜头和成像平面不平行造成的。说白了就是镜头装歪了。它的模型是:

x_corrected = x + [2 * p1 * x * y + p2 * (r^2 + 2 * x^2)]
y_corrected = y + [p1 * (r^2 + 2 * y^2) + 2 * p2 * x * y]

p1、p2 是切向畸变系数。我建议你在标定时,先只标径向畸变,如果残差还大,再考虑切向。因为切向畸变参数多了,容易过拟合。

个人经验:我曾经在一个项目中,标定结果总是差那么0.1像素。折腾了两天,最后发现是镜头没拧紧,产生了微小的切向畸变。拧紧后重新标定,残差直接降到0.05像素以下。所以,硬件稳定性比算法更重要。

4.3 标定流程——从采集到优化

标定流程就三步:采集 → 提取 → 优化。听起来简单,但每一步都有坑。

4.3.1 采集——标定板图像

采集标定板图像时,要注意几点:

  • 数量:至少15-20张。太少的话,优化容易陷入局部最优。
  • 姿态:标定板要覆盖视场的各个区域——左上、右下、中间、倾斜、旋转。我习惯让标定板占画面1/3到1/2,不要太满。
  • 光照:均匀光照,避免反光。反光会导致角点提取不准。

避坑指南:我曾经为了省事,只拍了10张标定板图像,结果标定出来的内参在边缘区域误差很大。后来补到20张,效果明显改善。记住:宁多勿少。

4.3.2 提取——角点检测

提取角点是标定的关键步骤。Halcon 提供了 find_caltab 和 find_marks_and_pose 算子。我个人习惯用 find_caltab 先定位标定板,再用 find_marks_and_pose 提取角点。

* Halcon 标定板角点提取示例
read_image (Image, 'calibration_image_01')
find_caltab (Image, CaltabRegion, 'caltab_30mm.descr', 3, 112, 5)
find_marks_and_pose (Image, CaltabRegion, 'caltab_30mm.descr', 3, 112, 5, [], [], RCoord, CCoord, StartPose)

提取完成后,检查角点是否准确。如果角点偏移超过0.5像素,这张图就不要用了。

4.3.3 优化——最小化重投影误差

优化的目标是最小化重投影误差——也就是把3D点投影到图像上,和实际提取的2D点之间的像素距离。Halcon 使用 camera_calibration 算子进行优化。

* Halcon 相机标定优化
camera_calibration (CalibDataID, 'all', 'pose', Errors, 'calibration_object', 'caltab_30mm.descr')

优化完成后,检查 Errors 输出。一般平均重投影误差应小于0.1像素。如果大于0.3像素,说明标定质量有问题,需要重新采集或检查标定板。

核心指标:重投影误差 < 0.1 像素 → 优秀;0.1-0.3 像素 → 可接受;> 0.3 像素 → 需要重新标定。

4.4 知识结构总览

下面这张图,把相机内参标定的核心逻辑串起来了。你可以把它当作一个快速参考。

相机内参标定知识结构 针孔模型 理想成像映射 畸变模型 现实偏差修正 标定流程 采集→提取→优化 径向畸变 (k1, k2, k3) 桶形/枕形 切向畸变 (p1, p2) 镜头倾斜 内参矩阵 K fx, fy, cx, cy 核心目标:最小化重投影误差 理想 < 0.1 像素 | 可接受 0.1-0.3 像素 | 需重标 > 0.3 像素

4.5 标定参数对比表

为了方便你快速查阅,我把标定涉及的主要参数整理成了表格:

参数 符号 说明 典型范围
焦距(x方向) fx 以像素为单位的x方向焦距 500-5000
焦距(y方向) fy 以像素为单位的y方向焦距 500-5000
主点(x方向) cx 光心在x方向的像素坐标 图像宽度/2 ± 50
主点(y方向) cy 光心在y方向的像素坐标 图像高度/2 ± 50
径向畸变系数1 k1 二阶径向畸变 -0.5 ~ 0.5
径向畸变系数2 k2 四阶径向畸变 -0.5 ~ 0.5
径向畸变系数3 k3 六阶径向畸变(鱼眼用) -0.5 ~ 0.5
切向畸变系数1 p1 切向畸变 -0.1 ~ 0.1
切向畸变系数2 p2 切向畸变 -0.1 ~ 0.1

小技巧:标定完成后,可以用 gen_caltab 生成一个虚拟标定板,然后用标定好的内参去投影,看看和实际图像是否吻合。如果偏差大,说明标定有问题。