做双目视觉这几年,我经常被问到同一个问题:是不是换个更长焦的镜头,深度估计就能更准?答案没有表面上那么简单。焦距确实会改变视差的大小,而视差又是双目深度估计唯一的"尺子",但它同时也在改变视场角、改变匹配难度、改变误差的分布方式。搞不清楚这层关系,很容易在选型阶段就走偏,或者在算法调试时被莫名其妙的误差来源折磨。
这篇文章不打算把公式堆一页PPT那么长,而是从几何直觉出发,把焦距、视差、深度估计三者之间的因果关系拆开揉碎,再结合我在实际项目里踩过的坑,把工程上真正需要关心的事情讲清楚。不管你是在做立体视觉标定、三维重建,还是刚入坑的双目测距,这篇文章都值得读完再动手。
1. 先搞清视差到底在"测量"什么
很多初学者把视差理解成"同一个点在不同相机里移动了多少像素",这个说法方向没错,但容易产生一个误解——以为视差是物体运动造成的。实际上在双目系统里,两个相机是固定的,物体也是静止的,是相机位置不同,导致同一个三维点投影到两个成像平面上的位置不一样。
1.1 用手指做一次最直观的视差实验
你把食指竖在眼前,先只用左眼看,再用右眼看,会发现手指相对于背景的位置跳了一下。这个"跳"就是视差。它的大小取决于两个因素:手指离你多远,以及你的两只眼睛相距多远。这里还没有焦距的事,因为人的眼球焦距基本固定。
在机器人或相机系统里,两台相机代替了双眼,它们之间的距离叫基线(baseline)。基线越长,同一个距离上的物体在两个画面里的位置差异越大,也就是视差越大。这也是为什么人们常说"基线越大,测距越准"——因为视差作为测量量,它变大就意味着测量分辨率变高。焦距的作用和基线类似,它把三维空间的角度差"放大"成成像面上的像素差,焦距越长,放大倍数越大。
1.2 对应点是视差计算的灵魂
要计算视差,首先得在左右两张图里找到"同一个三维点"的两个投影,这一对像素叫作对应点(correspondence)。块匹配、SGM、基于深度学习的匹配算法,本质上都在干这一件事。对应点找得准,视差才算得准;视差算得准,深度才有可能准。
在理想情况下,左右图像经过极线校正后,同一个三维点的两个投影一定处于同一行。这样就把二维搜索压缩成了一维搜索,匹配效率大幅提升,这也是为什么所有双目系统上线前都要做极线校正。但校正本身依赖高质量的标定参数,而标定参数里就包含焦距。换句话说,焦距不准,极线校正就不准,对应点匹配也就跟着崩。这里提前埋个伏笔,后面讲坑的时候会专门展开。
1.3 视差图与深度图的换算关系
当所有像素的匹配完成,会得到一张视差图(disparity map)。它和深度图不是一回事,深度是通过下面这个式子换算出来的:
深度 Z = 焦距 f × 基线 B / 视差 d
这个公式里,Z的单位是毫米或米,f 的单位是像素,B 的单位是毫米,d 的单位是像素。分子单位是"像素乘毫米",分母是"像素",正好约掉得到毫米。单看量纲就能记住这个式子。
这里最值得注意的点在于:深度和视差不是线性关系,而是反比关系。视差大,深度小(物体近);视差小,深度大(物体远)。这带来一个非常深刻的结果:同样的视差测量误差,在远处造成的深度误差比近处大得多,而且这个差距是按距离平方放大的。焦距的作用在这个误差放大机制里尤为关键,后面我会专门用一节来算。
2. 焦距是怎么"放大"视差的:一个完整的三角测量推导
想要真正理解焦距对视差的影响,最稳妥的方法是自己推一遍三角测量公式。网上很多资料直接抛出 Z = fB/d,但不讲几何过程,导致很多人误以为"焦距越大深度越准"是天然的真理。实际上,这个结论有严格的前提条件。
2.1 平行双目几何模型
假设两个相机光轴严格平行,像平面共面,对应像素行对齐。这是理想情况,实际系统都靠极线校正逼近这个状态。设三维空间中某点 P 的深度为 Z,它在左相机成像面上的水平坐标为 x_l,在右相机成像面上的水平坐标为 x_r,两个相机光心距离为 B。
从光心出发,P 点与左光心的连线会穿过左成像面上的一点,与右光心的连线穿过右成像面上的另一点。由于光轴平行,同一个点在两个成像面上的水平位置差异就构成视差 d = x_l - x_r。借助相似三角形:
在左相机一侧,三角形 P-左光心-左像点 和 三角形 Z-距-焦距 f 相似,可以得到 x_l = f × X / Z(X 是 P 点相对左光心的横向偏移)。同理 x_r = f × (X - B) / Z。两式相减,得到 d = f × B / Z。
从推导过程能清楚看到,视差 d 确实和焦距 f 成正比。焦距变成两倍,同一个距离上的视差像素数也变成两倍,这是纯粹的光学放大效果。
2.2 为什么像素焦距带单位
你可能已经注意到,我写公式时一直强调 f 的单位是像素,而不是镜头标牌上的 35mm、50mm 这类物理焦距。因为成像面是个传感器阵列,像素坐标的尺度由物理焦距和像元尺寸共同决定:
像素焦距 f = 物理焦距 F / 像元尺寸 p
比如一颗 8mm 物理焦距的镜头,配 2.0μm 像元的传感器,像素焦距就是 8mm ÷ 0.002mm = 4000 像素。同样的物理焦距,如果换一个像元更小的传感器,像素焦距会更大,视差也“显得”更大。但这里要小心——小像元只是把图像"切"得更细,并不会改变光的几何路径。像素焦距更大,带来的真正好处是像素级匹配的物理分辨率更高,这跟你用手机二倍数码变焦把图放大再匹配不是一个概念,后者只是插值,细节并没有真的增加。
2.3 视差像素数对深度分辨率的直接影响
假设基线 B = 120mm,像素焦距 f = 4000 像素,那么在 Z = 2m 处,视差 d = 4000 × 0.12 / 2 = 240 像素。如果匹配算法的精度是 0.1 像素,那么对应的深度分辨率大约是多少?把公式对 d 求导:
ΔZ ≈ Z² / (f × B) × Δd
代入数值:4 / (4000 × 0.12) × 0.1 ≈ 0.000833m,也就是不到 1mm。但如果把焦距换成 2000 像素,同样的距离和匹配精度下,深度分辨率就变成约 1.7mm,差了整整一倍。
焦距的作用在这里就变得非常具体了:它直接参与决定深度分辨率,而且是线性关系。这也是很多项目把长焦镜头当作"远程高精度测距"首选的原因。
3. 焦距变长,代价藏在视野里
既然长焦能得到更大的视差和更高的深度分辨率,那不是焦距越长越好吗?问题没这么简单。镜头不是只看一个方向的放大率,它的焦距和视场角是被同一个物理结构锁定的。焦距翻倍,视场角大约减半,你看到的世界"变窄"了。
3.1 长焦镜头丢了什么
对于特定的传感器尺寸,视场角 θ 和焦距 f 满足 tan(θ/2) = 传感器半宽 / f。焦距 12mm、传感器宽度 6mm 的相机,半个视场角约为 14 度;焦距换成 6mm,半个视场角就变成 26.5 度左右。对双目系统来说,这意味着两个相机的公共视场区变小了。公共视场是能同时被左右相机看到、可以计算视差的区域,它的大小直接决定了你"能测的范围有多大"。
在自动驾驶场景里,前视双目要覆盖整个车道宽度,如果焦距太长导致视野只有中间一条,两侧的来车和行人就完全进入不了公共视场。很多项目在路测阶段才发现这个问题,最后只能换短焦镜头,或者增加一组相机做拼接——成本和复杂度瞬间上去了。
3.2 短焦镜头近处分辨率不足
反过来,短焦看得广,但代价是远处的视差太小。还是按 B = 120mm、f = 2000 像素算,20m 处的视差只有 12 像素,如果匹配精度是 0.1 像素,深度分辨率是 1.67m左右。这个精度用于判断"前方有没有车"还行,用于判断"车距 19 米还是 21 米"就很吃力。
所以在短焦、大基线配置里,近处物体视差大、测距准,远处物体视差小、测距差。这正是很多双目方案的通病:近距离精度看起来很美,一旦目标超过二三十米,深度值就开始剧烈抖动。这不是算法不行,是几何条件决定的物理极限。
3.3 匹配窗口的"双重困境"
还有一个经常被忽视的问题:匹配窗口大小在像素层面是固定的,比如 7×7,但焦距改变后,同一个空间点在图像上的"大小"也变了。焦距越长,一个物体占用越多像素,物体表面在左右视图里的外观差异可能越大,尤其是倾斜表面或者有遮挡边缘时,匹配难度会增加。说白了,焦距不仅放大了视差,也放大了左右视角造成的差异,这让匹配算法更容易出错。
我做过一次对比实验:同一个场景,分别用 6mm 和 16mm 镜头采集双目图像,用同一套 SGM 参数跑匹配。6mm 镜头的匹配错误率大约 2.1%,16mm 镜头的错误率上升到 4.8%。虽然长焦的视差像素数变大,但错误匹配的数量也在增加,最终深度图质量并没有按理论计算的倍数提升。工程上必须把这一层损耗算进去。
4. 深度误差如何被焦距和视差"联手放大"
这一节是全文最值得反复咀嚼的部分。前面提到的 Z = fB/d 只是理想关系,实际测量中每一项都有误差,而误差从视差领域传播到深度领域时,会被几何结构放大。理解了这个放大机制,你才能对"焦距是不是越长越好"给出有依据的判断。
4.1 误差传播公式:从视差误差推导深度误差
设深度 Z = fB/d,对 d 求偏导,得到深度误差和视差误差的关系:
∂Z/∂d = -fB/d² = -Z²/(fB)
写成差分形式:ΔZ ≈ Z²/(fB) × Δd,绝对值表示是 ΔZ ≈ (Z²/(fB)) × Δd。
这个式子透露了三个关键信息:
- 深度误差与距离的平方成正比。目标越远,误差爆炸性增长。
- 深度误差与基线 B 成反比。基线越大,误差越小。
- 深度误差与焦距 f 成反比。焦距越大,误差越小。
焦距的作用再次出现,但它不是孤立起作用的。Z²/(fB) 是一个整体系统参数。同样的 50m 目标,f=4000px、B=1.2m 时,Δd=0.1px 对应的深度误差是 2500/(4000×1.2) × 0.1 ≈ 0.052m。如果把焦距提高到 8000px,误差降到 0.026m,效果非常可观。但如果把物体放到 100m,f=4000px 时误差已经变成约 0.21m,f=8000px 时也还有 0.1m。
4.2 距离平方效应是绕不开的物理墙
"误差随距离平方增长"是双目视觉里最让人头疼的规律。它意味着你在近处折腾得再好,远处该模糊还是模糊。焦距的作用只是在同一个平方曲线上改变斜率,不能改变平方增长的趋势。
有人会问:那我无限增大焦距,不就能把曲线压平了吗?理论上可以,但实际上镜头、结构件、装配误差、温度漂移都会限制可用的焦距上限。焦距越大,同样的机械形变在图像上造成的像素偏移也越大,标定参数越容易失配。我见过一个项目为了远距离精度换了 35mm 镜头,结果设备运行两个月后,因为温度变化导致左右相机相对位置发生了 0.02mm 级别的微变,远处的深度误差直接增加了一个数量级。焦距放大了视差,也放大了系统不稳定性。
4.3 像素量化:视差最小单位的"地板"
除了匹配算法的亚像素精度,还有一个物理层面绕不开的问题:数字图像的坐标是像素整数,视差的最小单位是 1 个像素。如果你不依赖亚像素插值,那么 Δd 的下限就是 1.0 像素。代入误差公式,100m 处,f=4000px、B=1.2m,单像素视差误差带来到约 0.52m 的深度误差。这个精度对大多数应用来说完全不够用。
所以你会看到,实际系统几乎都要做亚像素优化,常用的有抛物线插值、Lucas-Kanade 光流式优化,或者直接训练回归网络输出亚像素视差。但亚像素精度也不是天上掉的,它依赖纹理丰富度和图像信噪比。低照度、反光、无纹理墙面,都会让亚像素优化失效,深度图出现明显的"分层"现象。
5. 工程选型时,焦距和基线应该一起考虑
很多教程把焦距和基线拆开谈,但工程里它们是一个组合拳。设计一个双目系统的第一步,不是看焦距,而是先明确你到底要测多远、覆盖多大视野、允许多大的误差,然后反推焦距和基线。
5.1 先定最大测距和误差预算
假设项目要求在 30m 处深度误差不超过 0.15m,匹配精度能达到 0.1px。利用公式 ΔZ ≈ Z²/(fB) × Δd,反推 fB ≥ Z² × Δd / ΔZ = 900 × 0.1 / 0.15 = 600px·m。如果基线 B=0.5m,那 f ≥ 1200px;如果基线 B=1m,f ≥ 600px。
这个计算告诉我们,想提高测距能力,增加基线和增加焦距是等效的。但基线和焦距的工程代价不同:基线变大,设备体积变大,近处的公共视场会变小——太近距离的物体会因为两台相机"看不见同一个地方"而丢失;焦距变大,视野变窄。最终选型是在这两个约束之间找平衡点。
5.2 近距离高精度和中远距离覆盖的取舍
在室内机器人场景,一般测距范围就是 0.5m 到 8m,公共视场要覆盖机器人前臂作业区,所以通常选择焦距较短的广角镜头和中等基线。比如 2.8mm 镜头加 60mm 基线,配 640×480 分辨率传感器,就能在 2m 处获得约 0.5cm 的深度分辨率,足够避障和抓取。
在自动驾驶场景,感知范围要求 100m 甚至更远,那就需要更长焦距和更长基线。常见方案是中长焦镜头(6mm-12mm 物理焦距)配合 30cm-50cm 基线,同时牺牲部分近距视野,或者额外装一组近距广角双目做冗余覆盖。这里有个概念叫立体盲区(stereo blind zone):当物体比某距离更近时,它无法同时落在两个相机的视场里,视差无法计算。基线越长,这个盲区越大,系统设计时必须为盲区准备备用传感器。
我做过一个辅助驾驶项目,最初的方案选了 8mm 镜头、基线 45cm,结果发现车头前方 3m 以内的区域基本是盲区,超声波雷达和环视摄像头又看不远,最后只能把双目往后装一点,或者加一个短焦双目专门处理近场。这些教训,光看公式是想象不到的。
5.3 用一张决策表替代"越长越好"
我整理了一张选型参考表,供你粗估时使用。这里的焦距都是物理焦距(mm),实际计算还要换算成像素焦距。
| 应用方向 | 建议焦距 | 建议基线 | 主要权衡点 |
|---|---|---|---|
| 室内避障/近距抓取 | 2.8-4mm | 4-10cm | 盲区小,精度够用,成本低 |
| 服务机器人中远距 | 4-6mm | 10-20cm | 兼顾 0.5-8m 的公共视场 |
| 车载前视 | 6-12mm | 25-50cm | 远距优先,盲区靠补盲 |
| 无人机地形感知 | 4-6mm | 20-35cm | 重量受限,选大基线不现实 |
| 高端测绘 | 12-25mm | 50-200cm | 精度优先,体积和成本不敏感 |
注意表格只是参考,不同传感器的像元尺寸、分辨率和算法水平会大幅改变最终结果。真要定参,按 4.1 的公式做一次误差仿真,再带上真实场景数据测试,比任何经验法则都可靠。
6. 实际项目中焦距与视差关联的那些坑
文章最后,分享几个我在这条技术路线上真实踩过的坑。它们不是教科书里会写的知识点,但每一个都让项目组花了至少一两周才排查出来。
6.1 标定焦距和光学焦距不是一回事
标定得到的 fx、fy 是包含了镜头畸变修正后的等效像素焦距,它和镜头厂商标称的物理焦距一定存在偏差。原因是镜头的实际焦距会随对焦距离产生轻微变化,也就是呼吸效应。如果你的镜头对焦环被外力碰了一下,或者温度变化导致镜筒形变,标定参数立刻失配,视差就会出现系统性偏移。
我做过一个项目,开机后深度值整体偏了近 5%,排查了大半天才发现是三颗固定镜头的螺丝温度变化后轻微松动,光轴角度变了,但标定参数还是旧的。从那以后,我坚持在每轮实验前做一次快速自标定,至少要做焦距和外参的校验。
6.2 视差不变而深度变化:你必须知道的深度"量化台阶"
由于视差像素是最小离散单位,深度图上会出现一圈圈的等深度环带。距离越远,环带越宽,也就是深度"分层"。这个分层和焦距直接相关:焦距越大,每个视差台阶对应的深度范围越小,分层越细腻。但代价还是视野变窄。
解决分层问题常见做法是亚像素视差估计,但要注意,亚像素优化不能修复匹配错误的整数视差。如果整像素级别就匹配错了,插值只会把错误"匀"得更平滑,让深度图看起来还行、实际更假。调试时一定要保留视差图的可视化通道,逐帧检查整像素匹配质量,再谈亚像素。
从工程角度,我的建议是:在匹配质量稳定的前提下,优先保证视差图干净,然后再做亚像素增强;如果直接上亚像素,你会被"看起来很平滑但位置不对"的深度图误导很久。
6.3 温度漂移:被人忽视的"焦距杀手"
双目相机的两个镜头如果因为温度变化产生微小的相对位移,视差就会整体变化。这不是软件的锅,是物理结构在作祟。焦距越长,同样的机械微变在像素域里被放大得越厉害。
我处理过一个故障:一台户外设备上午深度正常,下午深度就开始跳。最后排查发现,阳光直射让相机支架温度从 20℃ 升到 50℃,金属支架热膨胀导致两个相机的相对位置变了大约 0.03mm,在长焦镜头下反映为好几像素的视差偏移。如果你用的是短焦,0.03mm 可能只对应不到 0.5 像素,系统还能扛住;一旦换成长焦,问题立刻暴露。
这个问题的工程解法有几个方向:选低热膨胀系数的结构材料,使用主动恒温,或者布设温度传感器然后对基线/旋转做温度补偿修正。其中补偿修正最实用,但前提是你的系统里有温度传感器,并且提前做了温漂标定实验。
6.4 最后一点:匹配算法的鲁棒性比焦距更影响真实精度
回到文章开头的那个问题:长焦是不是就意味着高精度?理论上没错,但实际系统里还有匹配算法这个变量。如果算法在长焦图像上频繁产生误匹配,视差错误带来的深度误差会完全掩盖焦距带来的分辨率增益。
我做过一个对比:同一个平台,分别用 4mm 镜头和 8mm 镜头,在同样的纹理丰富场景里,8mm 的深度图质量明显更好;在纹理稀疏的场景里,8mm 的误匹配区域比 4mm 大了将近一倍,最终深度图反而更差。焦距越长,左右视角差异越大,对匹配算法的鲁棒性要求也越高。
如果你的算法还停留在裸 SGM 阶段,先别急着换长焦。先把匹配的误匹配检测做扎实,比如加左右一致性检查、遮挡检测、边缘保护这些手段,再考虑用焦距提升精度。否则就是地基没打好,楼越高塌得越快。
做双目这么多年,我越来越倾向一个观点:焦距、基线、视差这三者不是孤立参数,它们是一个几何系统的三根支柱。选型时把它们放在一起权衡,调试时分清误差来自哪里,比盲目追求长焦或大基线有用得多。希望这篇文章能帮你在做深度估计时少走几步弯路。