使用 OpenCV 进行相机校准
相机已经存在了很长时间。然而,随着 20 世纪后期廉价针孔相机的推出,它们在我们的日常生活中变得司空见惯。不幸的是,这种廉价是有代价的:严重的失真。幸运的是,这些失真是常数,通过校准和一些重新映射,我们可以纠正这一点。此外,通过校准,您还可以确定相机的自然单位(像素)与现实世界单位(例如毫米)之间的关系。
理论
对于畸变,OpenCV 考虑了径向和切向因素。理解这些数学模型是进行准确校准的基础。
径向畸变
径向畸变是由于透镜形状引起的,光线在远离光轴的地方弯曲得更厉害。它通常表现为'桶形'或'枕形'畸变。OpenCV 使用以下多项式公式来描述径向畸变:
x_distorted = x * (1 + k1r^2 + k2r^4 + k3r^6) y_distored = y * (1 + k1r^2 + k2r^4 + k3r^6)
其中 (x, y) 是归一化坐标,r^2 = x^2 + y^2,k1, k2, k3 是径向畸变系数。
切向畸变
切向畸变的发生是因为拍摄图像的镜头与成像平面不完全平行。这可以通过以下公式表示:
x_distorted = x + [2p1xy + p2(r^2 + 2x^2)] y_distorted = y + [p1(r^2 + 2y^2) + 2p2xy]
其中 p1, p2 是切向畸变系数。
因此,我们有五个失真参数,在 OpenCV 中,这些参数通常表示为具有 5 列的一行矩阵(或者根据模型不同为 8 列)。
相机矩阵与单位转换
为了将像素坐标转换为物理坐标,我们使用相机内参矩阵。公式如下:
u = fx * (X/Z) + cx v = fy * (Y/Z) + cy
在这里,fx 和 fy 是相机焦距(以像素为单位),(cx, cy) 是以像素坐标表示的光学中心。如果对于两个轴,使用具有给定纵横比的公共焦距,则 fy = fx * a。包含这四个参数的矩阵称为相机矩阵。
虽然无论使用何种相机分辨率,失真系数都是相同的,但这些失真系数应与校准分辨率的当前分辨率一起缩放。确定这两个矩阵的过程就是校准。这些参数的计算是通过基本的几何方程完成的。
校准对象
使用的方程式取决于所选的校准对象。目前 OpenCV 支持三种类型的对象进行校准:
- 经典黑白棋盘格
- ChArUco 板图案
- 对称圆形图案
- 不对称圆形图案
基本上,您需要用相机拍摄这些模式的快照,并让 OpenCV 找到它们。每个找到的模式都会产生一个新方程。要求解方程,您至少需要预定数量的模式快照来形成一个适配方程组。这个数字对于棋盘模式来说较高,而对于圆盘模式来说,这个数字较小。例如,从理论上讲,棋盘模式至少需要两个快照。然而,在实践中,我们的输入图像中存在大量的噪点,因此为了获得良好的效果,您可能需要至少 10 张不同位置的输入模式的良好快照。
目标示例应用
本教程将构建一个示例应用程序,该程序能够:
- 确定失真矩阵
- 确定相机矩阵
- 从相机、视频和图像文件列表中获取输入
- 从 XML/YAML 文件读取配置
- 将结果保存到 XML/YAML 文件中
- 计算重投影误差
源代码实现逻辑
您可以在 OpenCV 源代码库的文件夹中找到参考源代码。对于程序的用法,请使用参数运行它。该程序有一个基本参数:其配置文件的名称。如果没有给出,那么它将尝试打开名为'default.xml'的那个。
在配置文件中,您可以选择使用相机作为输入、视频文件或图像列表。如果选择最后一个,则需要创建一个配置文件,在其中枚举要使用的图像。要记住的重要部分是,需要使用应用程序工作目录中的绝对路径或相对路径来指定图像。
配置读取
应用程序从配置文件中读取设置后启动。虽然这是其中的一个重要部分,但它与本教程的主题无关:相机校准。因此,我选择不在此处发布该部分的代码。有关如何执行此操作的技术背景,请参阅官方文档。
// 读取设置
const string inputSettingsFile = parser.();
;
(!fs.()) {
cout << << inputSettingsFile << endl;
parser.();
;
}
Settings s;
fs[] >> s;
fs.();


