3. 深度估计基础:三角测量原理与视差公式
深度估计,说白了就是让计算机知道物体离我们有多远。在3D显示里,这是最核心的一步。没有深度,就没有立体感。
我个人习惯把深度估计比作「人眼测距」。你想想看,我们两只眼睛看东西,为什么能判断远近?因为左右眼看到的画面不一样。这个「不一样」,就是视差。而视差和深度之间的关系,全靠三角测量来算。
3.1 三角测量:老祖宗的智慧
三角测量不是什么新鲜事。几百年前的测绘员就在用。原理很简单:已知两个点之间的距离,再测出两个角度,就能算出第三个点的位置。
在3D视觉里,两个点就是左右摄像头(或者你的左右眼),第三个点就是目标物体。我刚开始做双目视觉时,总觉得这原理太简单,能有多准?后来在项目里踩过坑才明白——原理简单,但工程实现全是细节。
核心思想:已知基线长度 B 和两个视角的夹角,通过相似三角形计算深度 Z。
来看一个标准模型。左右两个相机光心距离为 B(基线),目标点 P 在左相机成像点为 xL,在右相机成像点为 xR。焦距为 f。
3.2 深度与视差的数学推导
好,现在我们来推公式。别怕,就是初中几何。
从上面的图可以看出,两个三角形是相似的:
- 左相机光心、目标点 P、左成像点 xL 构成一个三角形
- 右相机光心、目标点 P、右成像点 xR 构成另一个三角形
根据相似三角形关系:
Z / f = B / (xL - xR)
这里 xL - xR 就是视差 d。所以:
深度公式:Z = (f × B) / d
这个公式太重要了。我建议你把它刻在脑子里。它告诉我们三件事:
- 深度与视差成反比——视差越大,物体越近
- 深度与基线成正比——两只眼分得越开,测距越准
- 深度与焦距成正比——长焦镜头看得更远,但视野窄
我的经验:实际项目中,基线 B 不是越大越好。基线太大,左右视图差异过大,匹配会失败。我做过一个户外测距项目,基线设了 30cm,结果近处物体匹配全崩了。后来改成 10cm,效果反而更好。
3.3 视差与深度的数值关系
我们来看一组典型数据。假设焦距 f = 1000 像素,基线 B = 10cm:
| 深度 Z (m) | 视差 d (像素) | 深度变化 1cm 对应的视差变化 |
|---|---|---|
| 0.5 | 200.0 | 3.92 像素 |
| 1.0 | 100.0 | 0.99 像素 |
| 2.0 | 50.0 | 0.25 像素 |
| 5.0 | 20.0 | 0.04 像素 |
| 10.0 | 10.0 | 0.01 像素 |
看到问题了吗?距离越远,视差越小。到了 10 米,深度变化 1cm 只带来 0.01 像素的视差变化。普通相机根本分辨不出来。
避坑指南:我曾经在一个自动驾驶项目里用双目测距,要求测到 100 米。算了一下,视差只有 1 个像素。1 个像素的误差,深度误差就是 100 米。这根本没法用。后来我们换成了激光雷达。记住:双目视觉的精度随距离平方衰减。
3.4 亚像素精度:突破像素限制
既然像素精度不够,怎么办?用亚像素。说白了,就是在一个像素内部再插值。
常用的方法有:
- 抛物线拟合:用匹配代价的峰值附近三个点拟合抛物线,找到亚像素极值点
- 二次曲线插值:类似,但用更多点做曲线拟合
- 相位相关:在频域做亚像素位移估计
我一般用抛物线拟合,简单够用。代码大概长这样:
// 抛物线拟合求亚像素视差
// c0, c1, c2 是三个相邻像素的匹配代价
float subpixel_disparity(float c0, float c1, float c2) {
float denom = c0 + c2 - 2.0f * c1;
if (fabs(denom) < 1e-6f) return 0.0f;
return (c0 - c2) / (2.0f * denom);
}
这个函数返回的是相对于中心像素的偏移量,范围在 [-0.5, 0.5] 之间。加上整数视差,就是亚像素视差。
我的建议:亚像素精度能做到 0.1 像素就不错了。别指望 0.01 像素,那需要信噪比极高的图像,现实中很难达到。
3.5 深度估计的误差来源
公式 Z = fB/d 看起来很完美,但实际用起来全是坑。我列几个最常见的:
| 误差来源 | 影响 | 缓解方法 |
|---|---|---|
| 相机标定误差 | f 和 B 不准,深度整体偏移 | 用棋盘格做高精度标定 |
| 匹配误差 | 视差 d 找错 | 用更鲁棒的匹配算法 |
| 量化误差 | 像素离散化导致精度损失 | 亚像素插值 |
| 镜头畸变 | 图像变形导致视差偏移 | 畸变校正 |
| 光照变化 | 左右图亮度不一致 | 直方图匹配或归一化 |
嗯,这里要注意。标定误差是系统性的,一旦标定好就固定了。匹配误差是随机的,每帧都可能不一样。我做过一个项目,标定完觉得精度还行,一换场景全废了。后来发现是温度变化导致相机光心偏移了。所以工业级应用要加温控。
3.6 本章小结
深度估计的核心就一句话:Z = fB/d。但这个公式背后,是三角测量的几何原理、亚像素的工程技巧、以及对各种误差的清醒认识。
我个人觉得,理解深度估计最好的方式就是动手算一遍。拿尺子量一下你的两眼距离(大概 6-7cm),再估算一下你看手机时的视差。你会发现,公式虽然简单,但每个参数的选择都有讲究。
记住三个关键点:
- 深度与视差成反比——近处物体视差大,远处视差小
- 精度随距离平方衰减——双目视觉不适合远距离测距
- 亚像素是工程必备——没有亚像素,深度图全是锯齿