单目深度与几何估计


文档摘要

单目深度与几何估计 本节摘要:深度图是一张单通道图,每个像素是到相机的距离。从单张 RGB 帧预测它,过去没有双目或 LiDAR 几乎不可能;2026 年一个冻结的 ViT 编码器加一个轻量预测头,就能把误差压到几个百分点。本节区分相对深度与度量深度,讲清单目深度为何能从单图估出(透视、纹理梯度、遮挡、尺寸恒常、大气透视等线索)以及它恢复不了什么(绝对尺度、被遮几何);用 Depth Anything V3(DINOv2 主干)对任意单图免标定预测深度,认识 Marigold(条件扩散)与 ZoeDepth(真米制);并把 2D 检测经深度和针孔内参提升成 3D 点云。读完本节,你掌握了 AR 遮挡、避障、「拿杯子」机器人背后的同一座桥。

单目深度与几何估计

本节摘要:深度图是一张单通道图,每个像素是到相机的距离。从单张 RGB 帧预测它,过去没有双目或 LiDAR 几乎不可能;2026 年一个冻结的 ViT 编码器加一个轻量预测头,就能把误差压到几个百分点。本节区分相对深度与度量深度,讲清单目深度为何能从单图估出(透视、纹理梯度、遮挡、尺寸恒常、大气透视等线索)以及它恢复不了什么(绝对尺度、被遮几何);用 Depth Anything V3(DINOv2 主干)对任意单图免标定预测深度,认识 Marigold(条件扩散)与 ZoeDepth(真米制);并把 2D 检测经深度和针孔内参提升成 3D 点云。读完本节,你掌握了 AR 遮挡、避障、「拿杯子」机器人背后的同一座桥。

对应原课程:Phase 4 · Lesson 26 · monocular-depth(原英文 phases/04-computer-vision/26-monocular-depth/docs/en.md)。

学习目标

阅读完本节,你应当能够:

  1. 区分相对深度度量深度,说出各生产模型(MiDaS、Marigold、Depth Anything V3、ZoeDepth)各解哪一个。
  2. Depth Anything V3(DINOv2 主干)对任意单图免标定预测深度。
  3. 解释单目深度为何能从单图工作(透视线索、纹理梯度、学得先验),以及它恢复不了什么(绝对尺度、被遮几何)。
  4. 用深度图和针孔相机内参把 2D 检测提升成 3D 点

一、问题与直觉

深度是 2D 计算机视觉缺失的那根轴。给定 RGB,你知道物体在像平面哪里出现,不知道它多远。深度传感器(双目、LiDAR、飞行时间)直接解决,但昂贵、脆弱、量程有限。

单目深度估计——从单张 RGB 帧预测深度——过去产出模糊不可靠。到 2026 年大型预训练编码器改变了这点:Depth Anything V3 用冻结 DINOv2 主干,产出跨室内、户外、医学、卫星领域都泛化的深度图;Marigold 把深度重构成条件扩散问题;ZoeDepth 回归真实米制距离。

深度也是 2D 检测到 3D 理解的桥:把检测框的像素乘以深度,就把 2D 物体提升成了 3D 点云——这是每个 AR 遮障系统、每个避障流水线、每个「拿杯子」机器人的核心。

相对 vs 度量深度

  • 相对深度——有顺序的 z 值,无真实单位。「像素 A 比像素 B 近,但距离比不锚到米。」
  • 度量深度——到相机的绝对米制距离,要求模型学到图像线索与真实距离间的统计关系。

MiDaS、Depth Anything V3、Marigold 产相对深度;ZoeDepth、UniDepth、Metric3D 产度量深度。度量模型对相机内参敏感,相对模型不敏感。

编码器-解码器模式

Depth Anything V3 冻结编码器,只训 DPT 风格解码器。编码器提供丰富特征,解码器把它们插值回图像分辨率并回归深度。

单图为何能产出深度

2D 图像含许多与深度相关的单目线索:

  • 透视——3D 中的平行线在 2D 中汇聚。
  • 纹理梯度——远处表面纹理更小更密。
  • 遮挡顺序——近物遮远物。
  • 尺寸恒常——已知物体(车、人)给近似尺度。
  • 大气透视——户外远处物体更朦胧偏蓝。

在数十亿图上训过的 ViT 把这些线索内化了。足够数据加强主干,单目深度无需任何显式 3D 监督就能达到合理精度。

单目深度做不到的事

  • 绝对度量尺度——无内参或场景中已知物体,网络能预测「杯子比勺远两倍」,却不知杯子是 1 米还是 10 米远。
  • 被遮几何——椅子背面看不见,无法可靠推断。
  • 真正无纹理/反射面——镜面、玻璃、均色墙,网络给出看似合理却错误的深度。

2026 年的 Depth Anything V3

  • 原版 DINOv2 ViT-L/14 作编码器(冻结)。
  • DPT 解码器。
  • 在多源带位姿图像对上训练(除光度一致性外无需显式深度监督)。
  • 任意数量的视觉输入预测空间一致的几何,无论有无已知相机位姿。
  • 在单目深度、任意视角几何、视觉渲染、相机位姿估计上 SOTA。

这是 2026 你需要深度时的即插即用模型。

Marigold——为深度做扩散

Marigold(Ke 等,CVPR 2024)把深度估计重构成条件图到图扩散:条件是 RGB,目标是深度图,用预训练 Stable Diffusion 2 的 U-Net 作主干。输出深度图在物体边界处异常锐利。代价:比前馈模型慢(10~50 步去噪)。

内参与针孔相机

把像素 (u, v) 配深度 d 提升到相机坐标 3D 点 (X, Y, Z):

fx, fy, cx, cy = 相机内参 X = (u - cx) * d / fx Y = (v - cy) * d / fy Z = d

内参来自 EXIF 元数据、标定图案、或单目内参估计器(Perspective Fields、UniDepth)。无内参时,假设 60~70° 视场角和中等分辨率主点,仍可渲染点云——可用于可视化,不可用于测量。

评估

两个标准指标:

  • AbsRel(绝对相对误差):mean(|d_pred − d_gt| / d_gt),越低越好,生产模型 0.05~0.1。
  • delta < 1.25(阈值精度):max(d_pred/d_gt, d_gt/d_pred) < 1.25 的像素比例,越高越好,SOTA 0.9+。

对相对深度模型(Depth Anything V3、MiDaS),评估用两者的尺度-平移不变版本。

二、从零实现

步骤 1:深度指标

import torch def abs_rel_error(pred, target, mask=None): if mask is not None: pred = pred[mask] target = target[mask] return (torch.abs(pred - target) / target.clamp(min=1e-6)).mean().item() def delta_accuracy(pred, target, threshold=1.25, mask=None): if mask is not None: pred = pred[mask] target = target[mask] ratio = torch.maximum(pred / target.clamp(min=1e-6), target / pred.clamp(min=1e-6)) return (ratio < threshold).float().mean().item()

评估前永远先掩掉无效深度像素(零、NaN、饱和)。

步骤 2:尺度-平移对齐

对相对深度模型,算指标前先把预测对齐到真值,最小二乘拟合 a * pred + b = target:

def align_scale_shift(pred, target, mask=None): if mask is not None: p = pred[mask] t = target[mask] else: p = pred.flatten() t = target.flatten() A = torch.stack([p, torch.ones_like(p)], dim=1) coeffs, *_ = torch.linalg.lstsq(A, t.unsqueeze(-1)) a, b = coeffs[:2, 0] return a * pred + b

评估 MiDaS / Depth Anything 时,先跑 align_scale_shift 再算 abs_rel_error

步骤 3:把深度提升成点云

import numpy as np def depth_to_point_cloud(depth, intrinsics): H, W = depth.shape fx, fy, cx, cy = intrinsics v, u = np.meshgrid(np.arange(H), np.arange(W), indexing="ij") z = depth x = (u - cx) * z / fx y = (v - cy) * z / fy return np.stack([x, y, z], axis=-1) depth = np.random.uniform(0.5, 4.0, (240, 320)) intr = (320.0, 320.0, 160.0, 120.0) pc = depth_to_point_cloud(depth, intr) print(f"点云形状: {pc.shape} (H, W, 3)")

一个函数,每个 3D 提升应用都用。把点云导出 .ply,在 MeshLab 或 CloudCompare 打开。

步骤 4:合成深度场景冒烟测试

def synthetic_depth(size=96): yy, xx = np.meshgrid(np.arange(size), np.arange(size), indexing="ij") # 地面:从近(顶)到远(底)线性梯度 depth = 1.0 + (yy / size) * 4.0 # 中间方块:更近 mask = (np.abs(xx - size / 2) < size / 6) & (np.abs(yy - size * 0.6) < size / 6) depth[mask] = 2.0 return depth.astype(np.float32) gt = torch.from_numpy(synthetic_depth(96)) pred = gt + 0.3 * torch.randn_like(gt) # 模拟预测 aligned = align_scale_shift(pred, gt) print(f"对齐前 absRel = {abs_rel_error(pred, gt):.3f}") print(f"对齐后 absRel = {abs_rel_error(aligned, gt):.3f}")

步骤 5:Depth Anything V3 用法(参考)

import torch from transformers import pipeline from PIL import Image pipe = pipeline(task="depth-estimation", model="LiheYoung/depth-anything-v2-large") image = Image.open("street.jpg").convert("RGB") out = pipe(image) depth_np = np.array(out["depth"])

三行。out["depth"] 是 PIL 灰度图,转 numpy 做数学。Depth Anything V3 发布后换模型 id 即可,API 不变。

三、框架对比

  • Depth Anything V3(Meta AI / 字节,2024-2026)——相对深度默认,生产中最快的 ViT-large 主干模型。
  • Marigold(ETH,2024)——视觉质量最高,推理慢。
  • UniDepth(ETH,2024)——带相机内参估计的度量深度。
  • ZoeDepth(Intel,2023)——度量深度,较老仍可靠。
  • MiDaS v3.1——经典但稳定,好对比基线。

典型集成模式:

  1. RGB 帧到达。
  2. 深度模型产深度图。
  3. 检测器产框。
  4. 把框中心经深度提升到 3D,有现成点云就合并。
  5. 下游:AR 遮挡、路径规划、物体大小估计、双目替代。

实时场景,Depth Anything V2 Small(INT8 量化)在消费级 GPU 上 518×518 约 30 fps。

四、可复用产物

本节产出两个可复用文件(位于原课程 outputs/):

  • prompt-depth-model-picker.md:按延迟、度量 vs 相对需求、场景类型,在 Depth Anything V3、Marigold、UniDepth、MiDaS 间挑。
  • skill-depth-to-pointcloud.md:一个技能——正确处理内参、把深度图建成点云并导出 .ply

五、练习

  1. (简单) 在你桌面的任意 10 张图上跑 Depth Anything V2,存灰度 PNG 检查,找一个预测深度看着错的物体,解释单目线索为何失败。
  2. (中等) 给定 Depth Anything V2 的 RGB + 深度,提升成点云并用 open3d 渲染,对比室内/户外两场景哪个更可信。
  3. (困难) 取五对仅已知物体位置不同(如瓶子移近 30 cm)的图,用 UniDepth 预测两者度量深度,报告预测距离差与真实 30 cm 的对比。

本节要点回顾

  1. 深度是 2D 视觉缺失的轴——RGB 知在哪不知多远;单目深度从单帧预测,过去不行,2026 冻结 ViT+轻量头误差几个百分点。
  2. 相对 vs 度量:相对(有序 z 无单位,MiDaS/Depth Anything/Marigold)、度量(米制,需标定,ZoeDepth/UniDepth/Metric3D);度量对内参敏感。
  3. 编码器-解码器模式:冻结 ViT(DINOv2)产稠密特征,DPT 解码器上采样回归深度。
  4. 单图能估深度的原因:透视、纹理梯度、遮挡、尺寸恒常、大气透视等线索,数十亿图训练的 ViT 把它们内化。
  5. 恢复不了:绝对尺度(无内参/已知物)、被遮几何、无纹理/反射面(镜/玻璃/均色墙)。
  6. Depth Anything V3 是 2026 即插即用默认——DINOv2-L 冻结 + DPT,跨域 SOTA,免标定。
  7. Marigold = 条件扩散——SD2 U-Net 主干,边界锐利但慢(10~50 步)。
  8. 针孔提升:X=(u−cx)d/fx,Y=(v−cy)d/fy,Z=d;内参来自 EXIF/标定/UniDepth,无内参只能可视化不能测量。
  9. 评估两指标:AbsRel(生产<0.1)、delta<1.25(SOTA>0.9);相对深度用尺度-平移不变版,先最小二乘对齐。
  10. 实时:Depth Anything V2 Small INT8 在 518×518 约 30 fps。

下一节进入多目标跟踪——在视频里给每个目标一个稳定 ID,跨帧关联检测。


发布者: 作者: Rohit Gupta 转发
评论区 (0)
U