1. 相机标定到底是什么?为什么你的照片会“变形”?
如果你玩过单反,或者用手机拍过建筑,可能会发现一个有趣的现象:照片里的直线,尤其是靠近边缘的部分,有时候会莫名其妙地“弯”了。比如,你拍一个方方正正的窗户,照片里窗户的边缘却像被吸进去了一样,变成了弧形。这可不是你的手抖了,也不是镜头脏了,而是镜头本身存在的一种光学缺陷,我们称之为“畸变”。
相机标定,简单来说,就是给相机做一次“体检”和“身份认证”。通过这次“体检”,我们可以精确地知道相机的“内在特性”(内参)和它看世界时的“姿势”(外参),并且能测量出它“看东西变形”的程度(畸变参数)。有了这些数据,我们就能像给照片戴上一副“矫正眼镜”一样,把变形的图像拉直、还原,让照片里的世界和真实世界在几何关系上对得上号。
这听起来可能有点学术,但它的应用无处不在。从手机拍照的自动矫正、全景拼接,到自动驾驶汽车用摄像头感知距离,再到工业机器人用视觉精准抓取零件,背后都离不开相机标定。没有准确的标定,机器“看”到的世界就是扭曲的,做出的判断自然也是错的。所以,无论你是摄影爱好者想提升画质,还是计算机视觉的初学者想踏入这个领域,掌握相机标定都是非常关键的第一步。
在众多标定方法中,张正友教授于1998年提出的方法,堪称经典中的经典。它不需要昂贵、精密的标定设备,只需要你打印一张棋盘格图案,用待标定的相机从不同角度拍几张照片,就能算出所有需要的参数。这种方法巧妙、实用、精度高,几乎成了业界和学术界的标准流程。今天,我们就用Python和OpenCV这个强大的工具库,手把手带你走一遍完整的张正友标定流程,从生成棋盘格开始,一直到在图像上画出三维坐标轴。我会把原理掰开揉碎了讲,把代码一行行解释清楚,保证你跟着做一遍,就能彻底搞懂。
2. 动手之前:理解原理,告别“调包侠”
在急着敲代码之前,我们花点时间聊聊背后的原理。知其然更要知其所以然,这样出了问题你才知道往哪儿找,而不是只会对着报错发呆。张正友标定的核心思想,是建立“真实世界点”到“照片像素点”之间的数学关系。
想象一下,你面前有一个真实的棋盘格,每个黑白格的交点(我们叫它“角点”)在三维空间里都有一个精确的坐标 (X, Y, Z)。你用相机拍下它,在二维的照片上,这些角点变成了一个个像素点 (u, v)。相机标定要解的,就是这个从 (X, Y, Z) 到 (u, v) 的映射方程。
这个过程可以拆解成三步走:
2.1 从世界到相机:换个视角看问题
首先,世界坐标系是固定的,比如我们把棋盘格的一个角点设为原点。但相机可以到处移动、旋转。所以第一步,我们需要用一个旋转矩阵 R 和一个平移向量 t,把棋盘格上所有角点的世界坐标,统一转换到以相机镜头中心为原点的“相机坐标系”下。这一步决定了相机“站在哪儿、脸朝哪边”看棋盘格。
公式很简单:[X_camera; Y_camera; Z_camera] = R * [X_world; Y_world; Z_world] + t。R 和 t 就是我们要求解的外参数,每一张照片都对应一组不同的外参,因为每拍一张,相机的位置和角度都可能变了。
2.2 从相机到图像:透视投影的魔法
接下来,相机坐标系是三维的,但我们的照片是二维的。这就需要透视投影。你可以把它想象成相机背后有一个小孔(针孔相机模型),光线穿过小孔在底片上成像。这里会引入相机的内参数矩阵 K。
这个 K 矩阵长这样:
[ fx, 0, cx ]
[ 0, fy, cy ]
[ 0, 0, 1 ]
它包含了相机的核心身份信息:
- fx, fy:分别是x轴和y轴方向的焦距(以像素为单位)。它决定了成像的放大倍数,为什么手机变焦拍远景更清楚?本质上就是焦距变大了。
- cx, cy:主点坐标,通常是图像的中心点。理论上光线应该穿过图像正中心,但镜头组装可能有细微偏差,这个参数就是用来修正这个偏差的。
通过内参矩阵 K,我们可以把相机坐标系下的三维点 (X_c, Y_c, Z_c),投影到图像平面上的二维点 (x, y)。公式是:[x; y; 1] 等价于 (1/Z_c) * K * [X_c; Y_c; Z_c]。注意这里的 1/Z_c,这就是透视效果的关键:离相机越远的物体,成像越小。
2.3 从图像到像素:最后一步量化
上一步得到的 (x, y) 还是连续的图像坐标(单位可能是毫米)。但我们的照片是由一个个离散的像素组成的。所以最后一步,需要根据传感器的尺寸和分辨率,把 (x, y) 换算成具体的像素坐标 (u, v)。不过幸运的是,在OpenCV的模型中,内参矩阵 K 已经直接包含了这个换算关系,fx, fy, cx, cy 本身就已经是像素值了。所以我们通常把上一步直接得到的结果就当作像素坐标。
2.4 畸变:让直线变弯的“元凶”
上面说的都是理想情况。现实中的镜头,尤其是为了获得更大视野而采用的广角镜头,会因为透镜的形状和组装工艺,引入两种主要的畸变:
- 径向畸变:像鱼眼效果,直线会向内(枕形畸变)或向外(桶形畸变)弯曲。这是最主要、最需要矫正的畸变。
- 切向畸变:由于镜头和成像平面不平行导致,有点像“剪切”变形。
张正友标定法在求解时,会一并估计出刻画这些畸变的系数(通常是k1, k2, k3, p1, p2),有了它们,我们就能把照片上弯曲的点,反向推回它原本应该在的直线位置。
总结一下,标定就是通过多张已知物体(棋盘格)的图片,反推出 K、畸变系数 以及每张图片对应的 R 和 t。OpenCV的 cv2.calibrateCamera 函数,就是帮我们完成这个复杂的反向求解过程的。
3. 实战第一步:制作你的专属标定板
理论有点烧脑,现在我们开始动手。第一步,你需要一个标定板。张正友法推荐使用黑白棋盘格,因为它的角点(黑白方格相交的点)非常容易通过计算机算法精确检测。
你可以从网上下载,但我强烈建议自己用代码生成。好处有两个:一是尺寸和格子数量完全可控;二是你可以用高分辨率打印,获得更清晰的边缘,这对后续角点检测的精度至关重要。
下面是我常用的一个生成脚本,比原始文章里的更灵活一些:
import cv2
import numpy as np
def generate_chessboard(squares_x=9, squares_y=6, square_size_px=100, margin_px=50, filename='


7890

被折叠的 条评论
为什么被折叠?



