单目与多目深度估计的区别¶
“单目”指的是使用单张图像(即只有一个视角或镜头)来获取深度信息。与之相对的是双目或多目深度估计,后者使用两个或多个摄像头来获取深度信息,这个表格能帮助你更好地理解和对比单目深度估计与双目或多目深度估计的特点和应用场景。
| 特征 | 单目深度估计 | 双目或多目深度估计 |
|---|---|---|
| 输入 | 单张图像 | 多张图像(通常从不同视角拍摄) |
| 挑战 | - 尺度模糊性:无法直接提供绝对深度信息 - 光照影响:光照变化影响估计准确性 - 遮挡和反射:遮挡物和反射表面干扰深度信息提取 |
- 设备复杂性:需要多个摄像头 - 计算复杂性:处理多张图像需要更多的计算资源 |
| 优势 | - 设备简单:只需一个摄像头 - 适用范围广:适合资源受限的设备,如智能手机、无人机等 |
- 直接计算深度:通过视差直接计算深度,准确性高 |
| 工作原理 | - 利用纹理、颜色、阴影、几何结构和上下文等视觉线索 - 通过学习和模型训练来估计深度 |
- 通过视差(不同视角下的位置差异)直接计算深度 |
| 应用 | - 3D 重建 - 增强现实 - 自动驾驶辅助系统 - 机器人导航(资源受限环境) |
- 自动驾驶汽车 - 机器人导航(高精度要求) - 工业检测和测量 |
| 典型模型 | - Depth Anything V2 - ZoeDepth |
- Stereo Matching - Structure from Motion (SfM) |
单目深度估计¶
单目深度估计是一项计算机视觉任务,涉及从单个图像中预测场景的深度信息。换句话说,它是从单个摄像头视角估计场景中物体距离的过程。
单目深度估计有多种应用,包括 3D 重建、增强现实、自动驾驶和机器人技术。这是一项具有挑战性的任务,因为它需要模型理解场景中物体之间的复杂关系以及相应的深度信息,这些信息可能会受到光照条件、遮挡和纹理等因素的影响。
深度估计主要分为两类:
- 绝对深度估计:这种任务变体旨在提供从摄像头到物体的确切深度测量值。这个术语通常与度量深度估计互换使用,其中深度以米或英尺等精确单位表示。绝对深度估计模型输出的深度图包含代表真实距离的数值。
- 相对深度估计:相对深度估计旨在预测场景中物体或点的深度顺序,而不提供精确的测量值。这些模型输出的深度图显示哪些部分更靠近或远离,但不提供实际的距离。
在本指南中,我们将介绍如何使用 Depth Anything V2(一种最先进的零样本相对深度估计模型)和 ZoeDepth(一种绝对深度估计模型)进行推断。
查看 深度估计任务页面,以查看所有兼容的架构和检查点。
在开始之前,我们需要安装最新版本的 Transformers:
pip install -q -U transformers
深度估计管道¶
使用支持深度估计的模型进行推断的最简单方法是使用相应的 pipeline()。从 Hugging Face Hub 上的检查点实例化一个管道:
from transformers import pipeline
import torch
device = "cuda" if torch.cuda.is_available() else "cpu"
checkpoint = "depth-anything/Depth-Anything-V2-base-hf"
pipe = pipeline("depth-estimation", model=checkpoint, device=device)
接下来,选择一张图像进行分析:
from PIL import Image
import requests
url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg"
image = Image.open(requests.get(url, stream=True).raw)
image

将图像传递给管道:
predictions = pipe(image)
管道返回一个包含两个条目的字典。第一个条目称为 predicted_depth,是一个张量,其中每个像素的值表示深度(以米为单位)。第二个条目 depth 是一个 PIL 图像,可视化了深度估计结果。
让我们看一下可视化的结果:
predictions["depth"]

手动进行深度估计推断¶
现在你已经看到了如何使用深度估计管道,接下来我们来看看如何手动复制相同的结果。
首先,从 Hugging Face Hub 上的检查点加载模型及其相关处理器。这里我们使用与之前相同的检查点:
from transformers import AutoImageProcessor, AutoModelForDepthEstimation
checkpoint = "Intel/zoedepth-nyu-kitti"
image_processor = AutoImageProcessor.from_pretrained(checkpoint)
model = AutoModelForDepthEstimation.from_pretrained(checkpoint).to(device)
使用 image_processor 准备图像输入,它将处理必要的图像变换,如调整大小和归一化:
pixel_values = image_processor(image, return_tensors="pt").pixel_values.to(device)
将准备好的输入传递给模型:
with torch.no_grad():
outputs = model(pixel_values)
接下来,对结果进行后处理,以去除任何填充并调整深度图的大小以匹配原始图像的尺寸。post_process_depth_estimation 函数输出一个包含 "predicted_depth" 的字典列表。
# ZoeDepth 动态填充输入图像。因此,我们在调用 `post_process_depth_estimation` 时传递原始图像的尺寸,以去除填充并调整到原始尺寸。
post_processed_output = image_processor.post_process_depth_estimation(
outputs,
source_sizes=[(image.height, image.width)],
)
predicted_depth = post_processed_output[0]["predicted_depth"]
depth = (predicted_depth - predicted_depth.min()) / (predicted_depth.max() - predicted_depth.min())
depth = depth.detach().cpu().numpy() * 255
depth = Image.fromarray(depth.astype("uint8"))
在 原始实现 中,ZoeDepth 模型会对原始图像和翻转后的图像进行推断,并取平均结果。post_process_depth_estimation 函数可以通过传递翻转后的输出到可选参数 outputs_flipped 来处理这一点:
with torch.no_grad():
outputs = model(pixel_values)
outputs_flipped = model(pixel_values=torch.flip(inputs.pixel_values, dims=[3]))
post_processed_output = image_processor.post_process_depth_estimation(
outputs,
source_sizes=[(image.height, image.width)],
outputs_flipped=outputs_flipped,
)
