资讯动态

相机标定核心:四大坐标系与内参外参矩阵全解析

发布时间:2026/10/14 11:01:29 来源:尧图企业网站定制
做视觉项目的人无论你是在搞相机标定、AR叠加、三维重建还是最简单的单目测距第一天就会被四个名词糊脸世界坐标系、相机坐标系、成像平面坐标系、像素坐标系。很多人是这么过来的把教程里的矩阵公式抄下来代码跑通了就觉得自己会了。可一旦遇到几个实际问题就立刻露馅——主点cx、cy为什么不在图像中心fx和fy为什么不相等世界坐标的单位到底用米还是毫米投影公式里分母为什么是Zc而不是相机到点的距离我当年也在这个地方栽过跟头。做一个简单的测距Demo代码逻辑完全照抄算出来的距离就是不对。后来逐项排查才发现问题出在“坐标单位”上——我把棋盘格标定的世界坐标单位设成了毫米但用手动测量点时又用了米结果内参标定、外参求解全程都用错了尺度烂得悄无声息。所以这篇文章不打算只罗列公式而是把四个坐标系之间的来龙去脉彻底拆开讲。每走一步变换都告诉你它的物理含义是什么、为什么要这么写、实际项目里最容易错在哪。适合刚入门相机标定的人也适合那些公式能背、但遇到实际工程问题就犯迷糊的同学。先说清楚这四个坐标系各自站在哪里1.1 一个具体场景把四个坐标系拉到一起想象一下一个房间里放着一张桌子桌子上有一个杯子。你用手里的相机拍了一张照片。现在问题来了——照片上杯子的那个像素点是怎么从真实世界里的物理位置一步步变成图片上某个(u, v)坐标的真实世界里的位置用世界坐标系描述。你可以把世界坐标系的原点定在房间的某个墙角X轴指向东Y轴指向北Z轴竖直向上。杯子在那个坐标系里的坐标是(Xw, Yw, Zw)单位是米或者毫米。这个坐标系完全由你自己定义不需要对准任何相机只要保证整个场景里所有物体都可以用它描述就行。相机自己还有一套坐标系。相机坐标系的原点固定在相机的光心上Z轴指向相机正前方X轴朝右Y轴朝下不同定义习惯也有差异但这是最常见的约定。杯子相对于相机的空间位置用相机坐标系下的(Xc, Yc, Zc)来表示单位同样是你自己定的物理单位。光射进相机镜头打在感光芯片上就形成了一个物理图像点。这个图像点落在成像平面上用成像平面坐标系的(x, y)来描述。这个坐标系的原点在光轴与成像平面的交点也就是主点附近x轴、y轴分别和相机坐标系的X轴、Y轴平行单位是毫米。最后这个物理位置会被感光芯片上的像素网格“数字化”转成像素坐标系下的(u, v)。像素坐标系的原点在图像左上角u轴向右v轴向下单位是像素。四个坐标系的关系可以列成一张表坐标系原点坐标轴约定单位关键作用世界坐标系人为定义通常在场景某个角点按需定义米 / 毫米等描述物体的全局位置相机坐标系相机光心Z轴向前X轴向右Y轴向下米 / 毫米等描述物体相对相机的位置成像平面坐标系光轴与成像平面交点主点x、y轴平行于相机X、Y轴毫米物理图像上的位置像素坐标系图像左上角u向右v向下像素数字图像上的位置只要把这张表记牢后头的所有公式都不会跑偏。因为它们每一个都只是“从表格上一行跳到下一行”的转换。1.2 三步变换总览从世界到像素到底怎么走从3D世界点到2D像素点听起来很玄拆开了就三步。第一步世界坐标系到相机坐标系。这一步做的是刚体变换说白了就是旋转加平移。你要把整个世界搬到“以相机光心为原点”的角度去看首先得把坐标轴方向转过来再把原点移动到光心位置。这一步不改变物体之间的相对位置和形状所以叫刚体变换。第二步相机坐标系到成像平面坐标系。这一步做的是透视投影。简单点说就是利用针孔成像的相似三角形把相机前方的3D点压到相机后方的成像平面上。经过这一步点的深度信息会丢失掉或者说被“投影”掉了。三维世界的点开始变成二维图像上的物理坐标点。第三步成像平面坐标系到像素坐标系。这一步是数字化把物理尺寸的毫米坐标按像素网格的大小做一次缩放再平移一下原点位置变成像素坐标。你可以把这个过程理解成寄快递世界坐标系是收件人的家庭住址相机坐标系是快递员推着小推车站在小区门口成像平面坐标系是快递已经被放到包裹柜里的位置像素坐标系则是最后扫描枪打出来的那条取件码数字。路径一步一步走少一步都不行。世界坐标系到相机坐标系外参R和t究竟怎么理解2.1 世界坐标系是个“全局基准”我接触过的很多新手最看不上世界坐标系觉得它只不过是个形式上的东西——反正最后都要转到相机坐标系。但实际上它为整个系统提供了语义。比如在做AR的时候你希望虚拟物体稳定地“钉”在现实世界的某个桌角上。桌角的位置是用世界坐标系表达的。你每次拿到新的相机图像通过视觉算法估计出相机此时在世界坐标系里的位姿然后把虚拟物体从世界坐标投影到图像坐标。如果没有一个统一的世界坐标系虚拟物体和现实场景就连不到一起。世界坐标系怎么建完全看应用场景。做棋盘格标定时通常直接把世界坐标系原点定在棋盘格角点上Z轴垂直于棋盘格平面这样所有角点的Z坐标都是0处理起来非常方便。做固定相机的监控场景时可以在地上画一个原点用卷尺量几个标记点当作世界坐标。做SLAM时往往把第一帧相机的位置当作世界原点。没有哪一种定义绝对正确关键是全系统统一。2.2 旋转矩阵R为什么是3×3从世界坐标系转到相机坐标系坐标轴朝向不一样所以要先旋转。旋转用的矩阵R是3×3的。它的每一列可以理解为世界坐标系三个坐标轴在相机坐标系下的方向单位向量每一行则可以理解为相机坐标系的三个坐标轴在世界坐标系下的方向单位向量。这个矩阵是正交矩阵满足R的转置等于R的逆行列式等于1。很多人不理解三维旋转明明有三个自由度绕X轴、绕Y轴、绕Z轴各转一个角度为什么最后得到9个数的矩阵因为9个数之间不是独立的正交约束和行列式约束把它们限制住了。在实际工程里我们不会手写这个矩阵而是用欧拉角、旋转向量或者四元数来表示旋转再转换成矩阵去参与计算。但你要知道最终落到公式里的是这张3×3的矩阵。3×3的R本身也解释了刚体变换为什么“刚”——它只改变坐标轴方向不改变长度和角度所以物体不会因为旋转被拉伸或者扭曲。2.3 平移向量t的作用R解决“朝向”问题t则解决“原点”问题。相机坐标系的原点在光心世界坐标系的原点在墙角或棋盘格角点。光心相对于世界原点的位置偏移就是平移向量t它是3×1的列向量(tx, ty, tz)。先旋转再平移的顺序不能反。完整公式是Xc R * Xw t意思是先把世界坐标点旋转到相机坐标系的轴向上再整体平移到以光心为原点的坐标系里。如果你先平移再旋转因为坐标轴已经不同平移量也会被旋转结果就错了。2.4 外参矩阵的数据形式为了方便地把旋转和平移统一成一次矩阵乘法常见做法是引入齐次坐标。3维点的齐次坐标就是末尾补一个1变成4维向量。于是3×3的R和3×1的t可以拼成一张3×4的矩阵[R | t] [[r11, r12, r13, tx], [r21, r22, r23, ty], [r31, r32, r33, tz]]这个3×4的矩阵就是外参矩阵也常常写成4×4的齐次形式第三行第四列是0第四行是(0,0,0,1)方便后续链式相乘。外参只描述相机相对世界坐标系的位置和姿态。固定相机外参就是固定的移动相机外参就要实时更新。这也是为什么SLAM、AR这类系统每一帧都要做位姿估计——相机一晃外参全变。相机坐标系到成像平面透视投影是怎么推出来的3.1 针孔模型和相似三角形现在假设相机坐标系里有一个点P坐标是(Xc, Yc, Zc)。这个点在成像平面上会形成一个像点。要算这个像点的位置最经典的方法是针孔模型。把相机想象成一个不透光的盒子前面开一个小孔。光线从物体上某点出发穿过小孔打在盒子后壁的感光平面上形成一个倒立的像。小孔太小会导致成像过暗真实镜头用透镜代替但几何关系仍然可以用针孔模型近似。设焦距为f即光心到成像平面的距离。根据相似三角形可以得到成像平面上的物理坐标x、yx f * Xc / Zc y f * Yc / Zc这个推导过程在几何上是初中难度大三角形经过光心底边是Xc、高度是Zc小三角形底边是x、高度是f。两者相似于是Xc / Zc x / f。3.2 投影公式的分母是Zc而不是距离我发现这是最容易翻车的一个点。很多人在理解投影公式时会把分母Zc当作点到相机光心的距离。实际上不是。Zc是点在相机坐标系下沿光轴方向的那个深度分量不是欧式距离。打个比方你站在一条笔直的马路中间正前方远处有辆车。车距你的Z坐标可能是50米但如果车在你斜前方45度方向欧式距离约为70米而它沿光轴方向的深度依然是50米。投影公式用的永远是那个深度分量Zc因为只有它参与构成相似三角形的“高度”。这个值也可以是负的——如果点在相机正后方Zc为负投影结果会翻转。实际标定和测距时我们只关心相机前方的点所以Zc默认大于0。3.3 负号去哪了等效成像平面的讨巧处理真实的针孔成像倒像是在光心后面的成像平面上形成的。按照严格的坐标图像坐标应该是x -f * Xc / Zc y -f * Yc / Zc负号会让推导变得麻烦。于是几乎所有教材和视觉库都玩了一个小把戏把成像平面虚拟到光心前面去和真实的物理平面关于光心对称。这样一来图像坐标和相机坐标方向一致负号消失投影公式变成正号版本。这个虚拟的前置成像平面在物理上不存在但在数学上完全等价并且让所有公式清爽很多。你不需要在代码里处理倒像因为当你用的视觉库做标定和投影时它已经默认你采用了这个等价模型。焦距f在公式里是长度单位毫米。但在下一步转换到像素时它会被像素物理尺寸“吃掉”变成以像素为单位的尺度因子。成像平面到像素坐标系内参矩阵K的秘密4.1 像素坐标系的原点是左上角成像平面坐标系的原点在主点附近理论上光轴穿过的那个位置。但像素坐标系的原点永远在图像的左上角。为什么因为图像就是一行一行存储的第一行第一列就是左上角那个点。于是从物理坐标(x, y)到像素坐标(u, v)要先做一次平移。平移的量就是主点在像素坐标系里的位置用(cx, cy)表示。比如一张2048×1536的图像理论上主点应该在(1024, 768)附近但由于感光芯片安装精度的问题实际主点可能偏移到(1013.2, 765.8)之类的位置。这里的cx、cy不是整数而是浮点数因为它是标定出来的物理偏移映射到像素网格上的结果。4.2 从毫米到像素的缩放物理坐标的单位是毫米像素坐标的单位是像素这两个单位之间隔着一层“每个像素到底有多宽多高”。感光芯片上有一个一个的感光单元每个单元的物理尺寸记为dx和dy单位是毫米/像素。通常dx和dy差不多但未必完全相等。于是u x / dx cx v y / dy cy把之前投影公式里的x、y代进来就得到u f * Xc / (dx * Zc) cx fx * Xc / Zc cx v f * Yc / (dy * Zc) cy fy * Yc / Zc cy其中fx f / dxfy f / dy。注意fx和fy的单位是像素它们已经不是物理焦距了而是“以像素为单位的焦距”。4.3 内参矩阵K的完整形式把上面两行式子写成矩阵形式就是Zc * [u; v; 1] K * [Xc; Yc; Zc]其中K是K [[fx, s, cx], [0, fy, cy], [0, 0, 1]]这个K就是内参矩阵。s一般叫斜切参数默认接近0很多简化模型里直接写成0。它表示感光芯片的x轴和y轴是否严格垂直。正常工业相机这个角度偏差非常小可以忽略。内参矩阵只跟相机本身有关焦距、主点、像素尺寸。你把相机装在哪个位置、朝向哪里内参都保持不变。这也解释了为什么相机标定只需要标一次除非镜头被换过、焦距被调过否则内参可以直接复用。三步合一从3D点到2D像素的终极公式5.1 逐级代入得到完整投影方程现在把前面三步全部串起来。世界坐标点(Xw, Yw, Zw)先经过外参[Xc; Yc; Zc; 1] [R | t; 0 1] * [Xw; Yw; Zw; 1]得到相机坐标以后再乘内参矩阵KZc * [u; v; 1] K * [R | t] * [Xw; Yw; Zw; 1]这就是整个计算机视觉里最经典的单目成像方程。一张照片上的每个像素背后都是这个式子。用伪代码来写大致是这样一个过程# 内参矩阵 K K [[fx, 0, cx], [0, fy, cy], [0, 0, 1]] # 外参矩阵由旋转矩阵 R 和平移向量 t 组成 RT [[r11, r12, r13, tx], [r21, r22, r23, ty], [r31, r32, r33, tz]] # 世界坐标齐次形式 Xw [xw, yw, zw, 1] # 转到相机坐标 Xc RT * Xw # 归一化相机坐标除以深度 Zc x_norm Xc[0] / Xc[2] y_norm Xc[1] / Xc[2] # 再乘内参 K得到像素坐标 u fx * x_norm cx v fy * y_norm cy这里特别提醒归一化相机坐标是一个很常用的中间结果。x_norm、y_norm等于1的时候就是深度为1的平面上点的坐标。很多标定、姿态估计的算法都拿它当中间变量。5.2 内参与外参的分工边界搞清除内参和外参很多困惑会迎刃而解。内参是“相机自己的脾气”。同样一台相机不管怎么挪怎么转K永远是那张矩阵。所以在相机固定、镜头固定的工程里内参标定完就存起来之后所有帧都共用同一张K。外参是“相机在世界里的位置关系”。每动一次相机外参就变一次。比如AR系统每一帧都在估算外参因为头戴设备或者手机一直在移动。又比如机器人抓取固定相机装在工位上方只要相机没被碰过外参就不用重新算一旦机器人或相机位置变了外参就得重新标定。这种分工决定了工程架构。你可以把所有跟相机硬件有关的参数收敛到K里把所有跟位姿有关的参数收敛到外参里。代码里解耦清楚后期维护会很省心。5.3 反投影从像素到世界坐标的逆路径有了正投影自然有人会问已知图像上的像素点能不能反推出世界坐标答案是单目情况下不能唯一确定。把像素坐标(u, v)和深度Zc代入方程可以反推出Xc (u - cx) * Zc / fx Yc (v - cy) * Zc / fy Zc Zc你看Zc没有消失。像素坐标只给了你一条射线方向至于点在这条射线上多远完全未知。这条射线上的所有点都会投影到同一个像素。实际工程里如果你知道深度——比如深度相机给的深度图、双目标定得到的视差、或者激光雷达测距结果——就可以代入Zc恢复出完整的3D点。如果不知道深度就只能得到一条射线。用内参K的逆矩阵可以快速得到这条射线在相机坐标系下的方向向量direction K^(-1) * [u; v; 1]它表示的是相机坐标系下深度归一化后的方向。这个方法在三维重建、位姿求解、深度估计里无处不在。5.4 避坑畸变、单位、坐标轴顺序完整成像公式成立的前提是镜头满足理想的针孔模型。但真实镜头有畸变也就是光线经过镜头以后并不会严格汇聚到理想位置。畸变主要分两类。径向畸变是镜头形状引起的越靠近图像边缘越明显表现为直线变成弯曲的弧线切向畸变是镜头和感光芯片安装不平行导致的表现为图像上有微小的拉伸错位。常见的畸变模型会引入若干系数径向系数k1、k2、k3切向系数p1、p2。畸变处理应该在归一化坐标系下进行也就是在x_norm、y_norm阶段加补偿然后再乘内参K。实际标定库返回的畸变系数默认就作用在这个阶段。另外还有单位问题。外参t的单位和你定义世界坐标系的单位一致内参fx、fy是以像素为单位。你不能把以毫米为单位的世界坐标和以米为单位的平移向量混在一起用否则外参会标定出一些看似合理但完全错误的数值。这类错误很隐蔽特征点重投影误差看着不大但实际三维位置全偏了。常见问题与实操心得6.1 标定照片拍多少张才够用这个问题几乎每个做过标定的人都会问。我的个人经验是不要少于15张建议20到30张。拍的时候棋盘格要出现在画面不同位置——左上角、右上角、中央、左下角、右下角都要有。倾角要有变化远近要有变化。最忌讳的是所有照片都是正对着棋盘格拍的这样外参的约束不够标定出来的畸变系数容易过拟合。还有一个很容易忽视的细节标定板的角点检测数量要足够多。用7×10这种带内角点规格的棋盘格比4×5的稳得多。角点太少每张图提供的约束有限再多照片也难救。6.2 fx和fy为什么不相等很多人看到标定结果里fx和fy差了几个像素就怀疑自己标定出错。其实这非常正常。fx f / dxfy f / dy。如果感光芯片的像素单元不是严格正方形dx和dy略有差异fx和fy就会不相等。另外CMOS制造工艺、镜头畸变校正后的残差也会让两个值有细微差别。标定软件返回什么你就用什么。不要画蛇添足地把fx、fy强行设成同一个值。强行相等会让重投影误差变大尤其是图像靠边的位置误差会被放大。6.3 主点不在图像中心正常吗同样地cx、cy不等于图像尺寸的一半也完全正常。光轴穿过感光芯片的点跟芯片几何中心往往是两回事。镜头安装时有个微小的偏移、芯片封装有公差都会让主点偏离中心几个像素甚至几十个像素。除非偏离特别离谱——比如几百个像素那才需要怀疑标定样本出了问题或者镜头松了。6.4 一个完整的检查思路标定完不要只看重投影误差就完事。我习惯做一个“盲测”在标定场景里放一个已知世界坐标的物体用相机拍一张然后在图像里手动点出该物体的像素位置。把已知的世界坐标投影到图像上看看跟手动点选的像素差多少。如果误差在1、2个像素以内标定结果基本可靠。如果差很多先检查世界坐标单位再检查外参是否对应同一帧最后检查畸变模型是否用错。这个验证步骤成本很低但能拦住绝大多数标定“看起来成功、实际不可用”的坑。做视觉底层参数这块最大的教训就是不要相信任何一步变换的中间结果看上去合理就觉得万事大吉。坐标系之间的单位、符号、顺序任何一个环节出错最终表现都很可能只是“偏差一点点”。把每一步拆开验证把内参、外参、归一化坐标这些中间量打出来逐项检查才是最靠谱的调试方式。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑