2. 深度估计基础
聊到人像模式的散景效果,核心其实就两个字——深度。你想想看,手机怎么知道哪个人是前景、哪块背景该虚化?靠的就是深度估计。这一章,咱们把地基打牢。
什么是深度图?一张“灰度地图”
深度图,说白了就是一张灰度图。每个像素的值代表场景中那个点到相机的距离。值越大(越亮),物体越远;值越小(越暗),物体越近。
深度图 ≠ 视差图 ≠ 视差图 很多人刚入门容易搞混。深度图是物理距离(单位毫米/米),视差图是左右视图的像素偏移量(单位像素)。两者可以通过相机参数互相转换,但概念上别混为一谈。
举个例子。一张 640×480 的 RGB 图,对应一张同样分辨率的深度图。像素 (200, 300) 的深度值是 1200mm,说明那个点离相机 1.2 米。整张图就是场景的“距离快照”。
我早期做双目深度估计时,第一次看到生成的深度图——人脸区域一片漆黑,背景墙壁灰白,边缘还有毛刺。嗯,那质量确实惨不忍睹。但也正是那张图让我意识到:深度估计的精度,直接决定了后续散景渲染的成败。
深度估计的应用场景:不止是虚化
很多人以为深度估计只用来做背景虚化。其实它的应用范围广得多。我列几个常见的:
- 人像模式 / 背景虚化:手机摄影的招牌功能。通过深度图区分前景人物和背景,对背景做高斯模糊或光学模拟模糊。
- AR / VR 交互:虚拟物体要“贴”在真实场景中,必须知道每个平面的深度。否则虚拟杯子会飘在空中,穿帮。
- 自动驾驶:车辆需要知道前方障碍物的距离。深度估计是感知模块的标配。
- 3D 重建:多视角深度图融合,可以生成场景的三维点云模型。
- 机器人抓取:机械臂要抓取物体,得知道物体在空间中的精确位置和姿态。
我的经验:在手机人像模式中,深度图的分辨率往往不需要太高。320×240 的深度图配合边缘细化,就能做出不错的虚化效果。但自动驾驶场景就不行——低分辨率深度图会导致障碍物测距误差过大,直接威胁安全。
传统方法与深度学习方法对比
深度估计不是新概念。早些年没有深度学习的时候,大家也做了很多尝试。我简单梳理一下两者的核心差异。
| 对比维度 | 传统方法 | 深度学习方法 |
|---|---|---|
| 核心原理 | 几何约束、手工特征 | 端到端学习、数据驱动 |
| 输入要求 | 通常需要双目/多视图 | 单目即可(单张 RGB) |
| 计算速度 | 较慢(全局优化耗时) | 快(前向推理,可 GPU 加速) |
| 精度 | 纹理丰富区域尚可,弱纹理区域差 | 整体精度高,泛化能力强 |
| 鲁棒性 | 对光照、遮挡敏感 | 对光照、遮挡有一定容忍度 |
| 代表方法 | SGM、PatchMatch、MRF | MiDaS、DPT、BTS、AdaBins |
传统方法里,我印象最深的是 SGM(半全局匹配)。它通过多个方向的动态规划来近似全局优化,效果比局部匹配好不少。但有个致命问题——计算量太大。我在一个嵌入式项目里试过,640×480 的图,SGM 跑了将近 2 秒。这速度,做实时人像模式?想都别想。
深度学习方法就不一样了。以 MiDaS 为例,它用混合数据集训练,输入单张 RGB 图,直接输出深度图。前向推理在手机上也能跑到 30fps 以上。精度嘛,比传统方法高出一大截。
注意:深度学习方法的深度估计是“相对深度”,不是物理距离。它只能告诉你 A 点比 B 点近,但不知道具体近多少毫米。要得到深度,需要额外的标定或后处理。我在项目中踩过这个坑——直接用相对深度做虚化,结果背景模糊程度忽大忽小,很不自然。
知识结构总览
下面这张图,把本章的核心知识点串起来了。你可以把它当作一个快速索引。
传统方法:SGM 的“挣扎”
传统方法里,SGM 算是经典中的经典。它的思路是:把深度估计看作一个能量函数最小化问题。能量函数包含数据项(匹配代价)和平滑项(相邻像素深度应相近)。
但 SGM 有个硬伤——弱纹理区域。一面白墙,左右视图看起来一模一样,匹配代价算出来全是平的。SGM 只能靠平滑项“硬猜”,结果就是深度图上一片模糊。
我曾在某个安防监控项目里用 SGM 做行人深度估计。白天光线好还行,一到晚上,画面噪点一多,深度图直接崩了——行人轮廓和背景糊在一起,根本分不清。
深度学习方法:MiDaS 的“降维打击”
深度学习方法,尤其是 MiDaS,彻底改变了游戏规则。它用混合数据集训练(包含室内、室外、立体、激光扫描等多种来源),学会了从单张 RGB 图推断深度的能力。
MiDaS 的核心是编码器-解码器结构。编码器提取多尺度特征,解码器逐步恢复分辨率,最后输出深度图。它还用了一个技巧——多尺度融合,把不同尺度的特征拼接起来,保留细节和全局结构。
实用建议:如果你要在手机上部署深度估计模型,别直接用 MiDaS 原版(太大)。可以试试轻量化的版本,或者用知识蒸馏压缩模型。我在一个项目中把 MiDaS 从 200MB 压缩到 15MB,精度只掉了 3%,但推理速度从 200ms 降到了 30ms。
传统 vs 深度学习:怎么选?
这个问题没有标准答案。我个人的经验是:
- 有双目/多视图输入,且计算资源有限:传统方法还能一战。比如嵌入式设备上的双目深度估计,SGM 优化后也能跑到实时。
- 只有单张 RGB 图,且对精度要求高:无脑选深度学习方法。MiDaS、DPT、BTS 都是好选择。
- 需要深度:传统方法更容易得到深度(通过三角测量)。深度学习方法需要额外标定或后处理。
- 需要实时性:深度学习方法经过优化后,在 GPU/NPU 上可以跑得很快。传统方法在 CPU 上也能优化,但上限有限。
避坑提醒:我曾经在一个项目里试图用传统方法做单目深度估计——用了各种手工特征(SIFT、LBP、HOG),结果精度惨不忍睹。单目深度估计本身是病态问题(一张图丢失了深度信息),传统方法没有数据支撑,根本解不了。别在这上面浪费时间。