4. 相机成像模型:针孔相机模型、内参矩阵、外参矩阵、畸变模型

做手眼标定,绕不开相机成像模型。说白了,你得知道相机是怎么「看」世界的。我刚开始接触这个领域时,总觉得公式太多、头大。后来踩了几个坑才明白——理解成像模型,是标定精度的根基。

这一节,我们聚焦四个核心概念:针孔模型、内参、外参、畸变。嗯,一个一个来。

4.1 针孔相机模型:最朴素的成像原理

针孔相机模型,是所有成像模型的起点。它假设光线沿直线传播,穿过一个小孔,在成像平面上形成倒立的像。你想想看,这其实跟初中物理的小孔成像实验一模一样。

数学上,我们用相似三角形来描述这个过程。假设世界坐标系中有一个点 P(X, Y, Z),它在图像平面上的投影点 p(u, v) 满足:

u = f * X / Z
v = f * Y / Z

其中 f 是焦距(小孔到成像平面的距离)。这个公式简单,但实际相机没那么理想。为什么?因为真实相机有镜头、有传感器偏移,还有各种制造误差。

核心要点:针孔模型是理想模型,实际相机需要在此基础上引入内参和畸变。

4.2 内参矩阵:从相机坐标到像素坐标

内参矩阵,描述的是相机内部的光学特性。它把相机坐标系下的三维点,映射到图像像素坐标系。我习惯把它拆成三部分:

  • 焦距 f:单位是像素,不是毫米。注意,x 和 y 方向的焦距可能不同(fx, fy)。
  • 主点 (cx, cy):光轴与成像平面的交点,理想情况下在图像中心,实际会有偏移。
  • 倾斜因子 s:传感器像素不是完美的正方形时引入的修正,通常很小,很多标定算法直接忽略。

内参矩阵 K 的数学形式:

K = [[fx,  s, cx],
     [ 0, fy, cy],
     [ 0,  0,  1]]

我在项目中遇到过一个问题:用 OpenCV 标定出来的 fx 和 fy 相差很大,检查后发现是相机传感器像素不是正方形。后来换了标定板,重新采集数据才搞定。所以,标定板的质量和采集姿势直接影响内参的准确性

个人经验:标定内参时,建议采集 20-30 张不同角度的棋盘格图像。太少,参数不稳定;太多,边际收益递减。

4.3 外参矩阵:从世界坐标到相机坐标

外参矩阵,描述的是相机在世界坐标系中的位置和朝向。它由旋转矩阵 R 和平移向量 t 组成。说白了,就是回答一个问题:相机放在哪里?朝哪个方向看?

数学上,外参矩阵是一个 4x4 的齐次变换矩阵:

[R | t]
[0 | 1]

其中 R 是 3x3 旋转矩阵,t 是 3x1 平移向量。注意,外参是相对于某个世界坐标系定义的。在手眼标定中,这个世界坐标系通常是机器人基座或标定板坐标系。

我曾经犯过一个低级错误:把外参矩阵的旋转和平移顺序搞反了。结果标定出来的手眼关系完全不对,机器人抓取偏差了 5 厘米。排查了两天才发现,是代码里矩阵乘法顺序错了。嗯,这里要提醒大家:变换矩阵的乘法顺序是右乘,先旋转后平移

避坑指南:外参矩阵的旋转矩阵 R 必须是正交矩阵(R^T * R = I)。如果标定出来的 R 不满足正交性,说明标定过程有误差,需要重新检查数据。

4.4 畸变模型:径向畸变与切向畸变

真实相机不是完美的针孔。镜头的光学特性会导致图像变形,这就是畸变。畸变主要分两类:

4.4.1 径向畸变

径向畸变,是光线通过镜头边缘时发生的弯曲。离光轴越远,畸变越明显。它有两种表现形式:

  • 桶形畸变:图像向外膨胀,常见于广角镜头。
  • 枕形畸变:图像向内收缩,常见于长焦镜头。

数学上,我们用多项式来建模径向畸变:

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

其中 r 是像素到光轴的距离,k1、k2、k3 是径向畸变系数。通常 k1 和 k2 就够了,k3 用于高畸变镜头(比如鱼眼)。

4.4.2 切向畸变

切向畸变,是镜头和传感器不平行导致的。说白了,就是镜头装歪了。它用两个参数 p1、p2 来描述:

x_distorted = x + [2 * p1 * x * y + p2 * (r^2 + 2 * x^2)]
y_distorted = y + [p1 * (r^2 + 2 * y^2) + 2 * p2 * x * y]

我在实际项目中,切向畸变通常很小(p1、p2 接近 0)。但如果相机受过撞击或镜头松动,切向畸变会突然变大。有一次,客户反馈标定精度突然下降,我远程检查发现是相机固定螺丝松了。重新拧紧后,切向畸变参数恢复正常。

关键点:畸变校正必须在图像去畸变后,再进行后续的坐标变换。顺序错了,精度全完蛋。

4.5 知识体系总览

为了让你更直观地理解这些概念的关系,我画了一张图:

相机成像模型知识体系 世界坐标系 (3D 点 P) 外参矩阵 [R | t] 相机坐标系 (3D 点 Pc) 内参矩阵 K = [fx, fy, cx, cy] 畸变模型 径向 k1,k2,k3 切向 p1,p2 像素坐标 (u, v) 乘以外参 得到 Pc 投影 得到 (u,v) 畸变校正 流程:世界坐标 → 外参变换 → 相机坐标 → 内参投影 → 畸变校正 → 像素坐标

从这张图你可以看到,整个成像流程是:世界坐标系下的点,先通过外参矩阵变换到相机坐标系,再通过内参矩阵投影到图像平面,最后用畸变模型修正镜头变形。每一步都环环相扣,任何一个环节出问题,都会影响最终的标定精度。

我的建议:在实际项目中,先用 OpenCV 的 cv2.calibrateCamera() 一次性标定内参和畸变系数。然后固定内参,再单独标定外参。这样能减少参数耦合带来的误差。

好了,这一节的内容就到这里。成像模型是手眼标定的数学基础,理解透了,后面的标定算法才能用得顺手。


公众号:蓝海资料掘金营,微信deep3321