4、相机模型与标定:针孔相机模型、畸变模型(径向、切向)、张正友标定法、相机内参与外参

说到相机模型,我脑子里第一个蹦出来的就是针孔模型。说白了,这就是最朴素的成像原理——光线穿过一个小孔,在后面的感光平面上倒立成像。你想想看,我们平时用的手机、单反,本质上都在模拟这个过程。

但现实世界哪有那么完美。镜头不是针孔,是透镜组。透镜会带来各种畸变,就像哈哈镜一样。我当年第一次做视觉SLAM时,就被畸变坑过——明明特征点匹配上了,三角化出来的深度却乱七八糟。后来才发现,是没做畸变校正。

4.1 针孔相机模型

针孔模型的核心,就是四个坐标系之间的转换:世界坐标系 → 相机坐标系 → 图像坐标系 → 像素坐标系。嗯,这里要注意,很多人把图像坐标系和像素坐标系搞混。

数学上,一个三维点 \(P(X, Y, Z)\) 投影到像素坐标 \((u, v)\) 的过程可以写成:

Z * [u, v, 1]^T = K * [R | t] * [X, Y, Z, 1]^T

其中 \(K\) 是内参矩阵,\([R | t]\) 是外参矩阵。内参决定了相机本身的属性,外参决定了相机在空间中的位置和朝向。

内参矩阵 K 的标准形式:

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

fx, fy 是焦距(以像素为单位),cx, cy 是主点偏移。我习惯把 cx, cy 理解为光轴与成像平面的交点。

4.2 畸变模型

镜头畸变主要分两类:径向畸变和切向畸变。径向畸变是光线通过透镜边缘时弯曲造成的,说白了就是「桶形」或「枕形」效果。切向畸变则是透镜与成像平面不平行导致的。

我曾经在标定一个广角镜头时,径向畸变参数 k1 达到了 -0.35,图像边缘都快卷到中间了。校正后,整个画面舒展开来,那种感觉真的很爽。

4.2.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^2 = x^2 + y^2\),k1, k2, k3 是径向畸变系数。一般用 k1, k2 就够了,k3 是给鱼眼镜头准备的。

4.2.2 切向畸变

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 是切向畸变系数。实际项目中,切向畸变通常很小,但也不能忽略。我见过一个案例,因为切向畸变没校正,导致三维重建的平面出现了微小的弯曲。

我的经验:标定时至少拍 15-20 张不同角度的棋盘格照片。角度要覆盖各个方向,尤其是边缘。别偷懒,拍少了内参不稳定。

4.3 张正友标定法

张正友标定法,可以说是计算机视觉领域最经典的标定方法之一。它的核心思想是:用一张平面棋盘格,在不同角度下拍摄多张图像,然后通过单应性矩阵来求解内参和外参。

我记得第一次实现这个算法时,被单应性矩阵的分解卡了很久。后来才明白,张正友的巧妙之处在于利用了「平面」这个约束——棋盘格上的点都在同一个平面上,所以可以用单应性矩阵来描述从世界坐标到像素坐标的映射。

算法流程大致如下:

  1. 检测角点:在每张图像中提取棋盘格的角点坐标。
  2. 计算单应性矩阵:对每张图像,求解从棋盘格平面到图像平面的单应性矩阵 H。
  3. 求解内参:利用单应性矩阵的约束条件,建立线性方程组,求解内参矩阵 K。
  4. 求解外参:根据内参和单应性矩阵,计算每张图像的旋转矩阵 R 和平移向量 t。
  5. 非线性优化:用 Levenberg-Marquardt 算法对所有参数进行全局优化,最小化重投影误差。

避坑指南:我曾经在标定时发现重投影误差很大,检查后发现是棋盘格打印精度不够。建议用高精度打印机,或者直接买陶瓷棋盘格。另外,拍摄时保证光照均匀,避免反光。

4.4 相机内参与外参

内参和外参,说白了就是「你是谁」和「你在哪」的问题。

参数类型 包含内容 物理意义
内参 fx, fy, cx, cy, k1, k2, p1, p2, k3 焦距、主点、畸变系数
外参 R (3x3), t (3x1) 旋转矩阵、平移向量

内参是相机出厂后就固定的(除非你拆镜头)。外参则随着相机移动而变化。在SLAM中,我们每帧都在估计外参,而内参通常只标定一次。

你想想看,如果内参不准,外参估计就会跟着偏。就像你戴了一副度数不对的眼镜,看东西都是歪的。所以标定这一步,值得花时间做扎实。

核心公式总结:

// 世界坐标到像素坐标的完整流程
1. 世界坐标 P_w → 相机坐标 P_c = R * P_w + t
2. 相机坐标 P_c → 归一化坐标 p = (x/z, y/z)
3. 畸变校正 p_d = distort(p, k1, k2, p1, p2, k3)
4. 归一化坐标 → 像素坐标 u = fx * x_d + cx, v = fy * y_d + cy

4.5 知识体系总览

下面这张图,是我梳理的本章知识结构。你可以把它当作一个思维导图来看:

相机模型与标定 针孔相机模型 世界坐标系 相机坐标系 图像/像素坐标系 畸变模型 径向畸变 (k1,k2,k3) 切向畸变 (p1,p2) 张正友标定法 角点检测 单应性矩阵 非线性优化 内参与外参 内参:fx,fy,cx,cy,畸变 外参:R, t 标定精度直接影响SLAM和三维重建效果

这张图把四个核心模块串起来了。从针孔模型出发,理解成像几何;然后处理畸变,让图像变「正常」;再用张正友法标定出内参外参。每一步都环环相扣。

实用建议:如果你用 OpenCV 做标定,记得用 cv::calibrateCamera() 函数。输入棋盘格角点坐标和图像点坐标,输出内参、畸变系数和外参。我一般还会用 cv::initUndistortRectifyMap() 生成校正映射,然后一次性应用到所有图像上,效率高很多。

好了,相机模型和标定就聊到这儿。这些东西看着理论性强,但实际动手做一遍标定,你就能体会到其中的门道。尤其是当你看到校正后的图像变得横平竖直,那种成就感,嗯,值得。

可可精品资料库