3. 视差的计算公式:d = x_left - x_right,深度 Z = (f × B) / d
好,咱们进入正题。前面两章我们聊了人眼怎么感知深度,也看了双目相机的基本结构。这一章,我要把最核心的数学公式摆出来。
别怕,真的就两个公式。我当年刚接触双目视觉时,也觉得公式肯定很复杂。结果一看,就两行。说白了,整个双目测距的底层逻辑,就藏在这两个式子里。
3.1 视差 d 到底是个啥?
先看第一个公式:
d = x_left - x_right
这里的 d 就是视差(Disparity)。x_left 是同一个物理点在左相机成像平面上的列坐标(像素位置),x_right 是它在右相机上的列坐标。
你想想看,一个物体离相机越近,它在左右两张照片上的位置差异就越大。反过来,物体在无穷远处,左右眼看到的几乎一样,视差就趋近于 0。
核心直觉:视差大 → 物体近;视差小 → 物体远。就这么简单。
我在项目中遇到过一个问题:有人把 x_left 和 x_right 搞反了,结果算出来的深度全是负数。嗯,这里要注意,我们通常约定左图坐标减右图坐标,而且两个相机是严格水平对齐的。如果相机没对齐,那就要先做立体校正,这个后面会讲。
3.2 深度 Z 怎么算?
第二个公式,也是整个双目视觉的基石:
Z = (f × B) / d
其中:
- Z — 物体到相机平面的深度距离(单位:毫米或米)
- f — 焦距(单位:像素)
- B — 基线长度(单位:毫米)
- d — 视差(单位:像素)
这个公式其实是从相似三角形推导出来的。我习惯这样理解:焦距 f 和基线 B 是相机的固定参数,出厂就定了。视差 d 是实时算出来的。所以深度 Z 和视差 d 成反比。
我的小技巧:如果你记不住公式,就记住「视差越大,深度越小」。反比例关系,永远不会错。
3.3 焦距 f 的含义
焦距 f,说白了就是镜头中心到成像传感器的距离。但在双目视觉里,我们通常用像素单位来表示焦距,而不是毫米。
为什么会这样?因为我们的图像坐标 x_left 和 x_right 都是用像素来量的。如果焦距用毫米,单位就不统一了。所以相机标定的时候,会把焦距从毫米换算成像素。
| 参数 | 物理含义 | 常用单位 |
|---|---|---|
| 焦距 f | 镜头中心到成像面的距离 | 像素(pixel) |
| 基线 B | 左右相机光心之间的距离 | 毫米(mm) |
| 视差 d | 同名点在左右图上的列坐标差 | 像素(pixel) |
| 深度 Z | 物体到相机平面的距离 | 毫米(mm) |
我曾经踩过一个坑:用 OpenCV 标定完相机,直接拿标定出来的焦距(单位是像素)去算深度,结果发现 Z 的单位对不上。后来才意识到,基线 B 是毫米,焦距 f 是像素,算出来的 Z 也是像素,需要再乘上像素尺寸才能转成毫米。嗯,这个细节很容易忽略。
3.4 基线 B 的含义
基线 B,就是左右两个相机光心之间的直线距离。你可以把它想象成你两只眼睛之间的距离。成年人的瞳距大约是 60-70 毫米。
基线越长,视差效果越明显,深度测量精度越高。但代价是相机体积变大,而且近距离物体的视差可能超出搜索范围。
反过来,基线越短,相机可以做得很紧凑,适合手机、小型设备。但视差变小了,远距离物体的深度精度就会下降。
注意:基线不是越长越好。我见过有人为了追求精度,把两个相机拉得很开,结果近距离物体的左右图完全对不上,匹配失败。选基线要看你实际的应用场景。
3.5 知识结构图
下面这张图把视差和深度的关系梳理清楚了:
3.6 实际计算示例
光讲理论不过瘾,咱们来算一个实际的例子。假设:
- 焦距 f = 800 像素
- 基线 B = 120 毫米
- 某点在左右图上的视差 d = 40 像素
那么深度:
Z = (800 × 120) / 40 = 96000 / 40 = 2400 毫米 = 2.4 米
如果同一个点,视差变成 d = 80 像素:
Z = (800 × 120) / 80 = 96000 / 80 = 1200 毫米 = 1.2 米
你看,视差翻了一倍,深度减半。这就是反比例关系。
我的建议:刚开始做双目项目时,先用 Excel 或者 Python 写个小脚本,把不同视差对应的深度列个表。这样你能直观感受到,视差变化对深度的影响有多大。尤其是在近距离(视差大)时,视差变化一点点,深度变化就很剧烈。
3.7 精度与视差的关系
这里有个重要的点:视差是整数像素还是浮点数?
实际匹配算法算出来的视差通常是浮点数,但有些低成本方案只输出整数视差。整数视差会导致深度值出现阶梯状跳变,尤其是远距离物体。
我习惯把这个问题叫做「量化误差」。举个例子,视差从 1 像素变成 2 像素,深度可能从 100 米跳到了 50 米。这个误差在远距离上非常明显。
解决办法?用亚像素精度匹配,或者用更高分辨率的相机。当然,成本也会上去。
避坑指南:我曾经在一个项目中,为了省计算资源,把视差输出从浮点数截断成整数。结果远距离物体的深度完全没法用,跳变太严重。后来老老实实改回浮点数,问题才解决。所以,能保留浮点就别用整数。
3.8 本章小结
两个公式,一张图,一个例子。这就是视差和深度的全部关系。
- 视差 d = 左图坐标 − 右图坐标
- 深度 Z = (焦距 f × 基线 B) / 视差 d
- 焦距 f 和基线 B 是相机固定参数,需要提前标定
- 视差越大,物体越近;视差越小,物体越远
记住这些,后面的立体匹配、深度图生成,都是在这个基础上展开的。