NVIDIA AIBOX 实现单目深度估计
NVIDIA AIBOX 单目深度估计
深度感知是机器人定位、建图、避障以及自动驾驶环境感知的基础能力。常用深度获取方案对比如下:
| 方案 | 代表硬件 | 主要局限 |
|---|---|---|
| 机械式 LiDAR | 16/32 线雷达 | 千元级起步,体积与功耗较大,含旋转部件 |
| 结构光 / ToF | RealSense、Kinect | 有效距离约 10m 量级,强光与透明、反光物体失效 |
| 双目立体视觉 | 双目相机 | 依赖基线标定,长期使用存在标定漂移 |
| 单目深度估计 | 任意 USB / CSI 摄像头 | 输出为相对深度;单帧恢复绝对深度属病态问题,精度存在理论上限 |
单目深度估计不依赖几何约束,而是由卷积神经网络从单张 RGB 图像中学习单目线索——透视关系、遮挡、纹理梯度、物体先验尺寸——到深度的映射,以监督学习方式在大规模"图像-深度"配对数据集(如 NYU Depth v2)上训练。其硬件成本与部署门槛显著低于其他方案:无需专用传感器,无需标定,复用现有摄像头即可。

NVIDIA 系列 AIBOX
AIBOX 系列搭载 NVIDIA 原装 Jetson Orin 核心模组:
| AIBOX-OrinNX | AIBOX-OrinNano | |
|---|---|---|
| 模组 | Jetson Orin NX 16GB | Jetson Orin Nano 8GB |
| AI 性能 | 157 TOPS | 67 TOPS |
| GPU | 搭载 32 个 Tensor Core 的 1024 核 NVIDIA Ampere 架构 GPU | 搭载 32 个 Tensor Core 的 1024 核 NVIDIA Ampere 架构 GPU |
| CPU | 8 核 Arm Cortex - A78 64 位 CPU 2MB L2 + 4MB L3 | 6 核 Arm Cortex A78 64 位 CPU 1.5MB L2 + 4MB L3 |
| DDR | 16GB 128 位 LPDDR5 102.4GB/s | 8GB 128 位 LPDDR5 68 GB/s |
| HDMI | 4K@60Hz | 4K@30Hz |
针对深度估计任务,AIBOX 的架构优势有三点:
- 统一内存(Unified Memory)。CPU 与 GPU 共享同一物理内存,视频采集、解码与推理之间不存在跨总线数据拷贝。
jetson.utils.cudaToNumpy()可将 GPU 显存中的深度场直接映射为 numpy 数组供 CPU 侧业务逻辑读取,相比 x86 + 独立显卡架构省去了 CPU 与 GPU 之间的 PCIe 拷贝开销。 - 异构算力冗余充足。深度估计模型为纯卷积结构,可充分利用 GPU 的 CUDA 核心与 Tensor Core。AIBOX 算力显著高于 FastDepth 论文的实验平台 TX2(Ampere 架构在 FP16/INT8 推理上的吞吐优势尤为明显),运行该类模型后仍有充足算力并发承载检测、跟踪等其他视觉任务。
- 多路视频硬解码。AIBOX-OrinNX 的 NVDEC 支持同时硬解码 18 路 1080p30 视频,配合统一内存的零拷贝特性,可在单机上构建"多路解码 + 逐路单目深度估计"的处理管线。
FastDepth 算法原理
网络架构
FastDepth 采用编码器-解码器(encoder-decoder)结构,为全卷积网络(FCN),输入 224×224 RGB 图像,输出同尺寸的单通道深度图。

- 编码器(Encoder)采用 MobileNet:以 depthwise separable convolution(深度可分离卷积)替代标准卷积,将空间滤波与通道混合解耦为两步执行,计算量降至标准卷积的 1/8~1/9。
- 解码器(Decoder)为论文核心贡献。与分类任务仅依赖编码器不同,深度估计的解码器需逐级恢复空间分辨率并输出稠密深度图,其计算量无法像编码器那样通过逐层下采样压缩,因此解码器的低延迟设计是嵌入式实时化的关键难点。FastDepth 解码器采用最近邻上采样(nearest-neighbor interpolation)+ depthwise separable convolution的组合恢复分辨率:相比转置卷积(transposed convolution),该设计可避免棋盘伪影(checkerboard artifacts)并进一步压缩计算量;同时通过跳跃连接(skip connection)融合编码器各阶段的特征,保留高分辨率细节。
网络裁剪
在轻量架构的基础上,FastDepth 进一步采用 NetAdapt 进行通道级裁剪。NetAdapt 是平台感知(platform-aware)的裁剪算法:以目标平台实测的逐层延迟为依据,迭代削减各层通道数,在满足延迟约束的前提下尽可能保持精度。类比嵌入式开发中按 MIPS 预算逐级裁剪功能模块的做法:每层的裁剪比例不由人工设定,而是由平台实测延迟反馈迭代确定。

jetson-inference 中的实现
开源项目 jetson-inference 的 depthNet 类实现了 FastDepth 系列模型,内置两个预训练模型,以 ONNX 格式交付,首次运行时由 TensorRT 针对当前硬件编译优化引擎:
| 模型 | 启用参数 | 编码器 | 特点 |
|---|---|---|---|
| FCN-Mobilenet | --network=fcn-mobilenet(默认) | MobileNet | 推理速度快,适合实时流 |
| FCN-ResNet18 | --network=fcn-resnet18 | ResNet18 | 精度更高,速度略低 |
模型原始输出为 224×224 单通道浮点深度场(相对深度),可视化阶段经直方图均衡化与伪彩映射上采样至输入图像分辨率。
部署流程
以下步骤在 AIBOX 出厂系统上执行,无需刷机。
编译安装
sudo nvpmodel -m 0
sudo apt-get update
sudo apt-get install git cmake libpython3-dev python3-numpy
git clone --recursive --depth=1 https://github.com/dusty-nv/jetson-inference
cd jetson-inference
mkdir build
cd build
cmake ../
make -j$(nproc)
sudo make install
sudo ldconfig说明:
cmake阶段会运行CMakePreBuild.sh脚本,以交互方式下载预训练模型(含 DepthNet 系列),按提示选择所需模型即可;模型也可事后通过tools/download-models.sh补充下载。- 编译产物位于
jetson-inference/build/aarch64/,示例可执行文件在bin/子目录;Python 模块(jetson_inference、jetson_utils)随sudo make install安装至系统 Python 路径。 - 若不在本机构建,官方亦提供 Docker 容器方案(
docker/run.sh),详见官方文档。
参考:https://github.com/dusty-nv/jetson-inference/blob/master/docs/building-repo-2.md
运行示例
处理示例图片(%i 为通配符序号占位符):
# C++ 示例(位于 build/aarch64/bin)
$ ./depthnet "images/room_*.jpg" images/test/depth_room_%i.jpg
# Python 示例(位于 python/examples)
$ ./depthnet.py "images/room_*.jpg" images/test/depth_room_%i.jpg
处理视频流或摄像头(V4L2 设备或 MIPI CSI):
$ ./depthnet /dev/video0 # USB 摄像头
$ ./depthnet.py csi://0 # MIPI CSI 摄像头首次运行每个模型时,TensorRT 会针对当前硬件编译优化引擎,耗时数分钟属正常现象;引擎编译结果缓存至磁盘,后续运行恢复正常加载速度。
常用参数
| 参数 | 取值 | 说明 |
|---|---|---|
--network | fcn-mobilenet / fcn-resnet18 | 选用模型,默认 fcn-mobilenet |
--visualize | input / depth / input,depth | 显示内容组合 |
--depth-size | 浮点数(默认 1.0) | 深度图相对输入图像的缩放比例 |
--filter-mode | point / linear | 上采样插值方式 |
--colormap | viridis-inverted(默认)等 | 伪彩映射方案 |
原始深度场访问与尺度标定
伪彩可视化图仅供直观观察。工程应用中需通过 depthNet.GetDepthField() 获取原始深度场——GPU 上的 224×224 单通道浮点矩阵,经统一内存映射为 numpy 数组后可直接在 CPU 侧访问:
import jetson.inference
import jetson.utils
import numpy as np
# load mono depth network
net = jetson.inference.depthNet()
# depthNet re-uses the same memory for the depth field,
# so you only need to map it to numpy once (not every frame)
depth_field = net.GetDepthField()
depth_numpy = jetson.utils.cudaToNumpy(depth_field)
print(f"depth field resolution is {depth_field.width}x{depth_field.height}")
while True:
img = input.Capture() # assumes a videoSource stream was created
net.Process(img)
# wait for GPU to finish before touching the field from CPU
jetson.utils.cudaDeviceSynchronize()
# relative depth statistics of the current frame
min_depth = np.amin(depth_numpy)
max_depth = np.amax(depth_numpy)使用原始深度场需理解以下语义约束:
- 输出为相对深度。数值反映画面内各区域的深浅关系,数值范围随场景变化,不具跨场景可比性。伪彩图中的直方图均衡化会进一步拉伸色带,因此伪彩图的色标不可用于测距。
- 获取米制深度需尺度标定。常用方法:以场景中已知距离的参照物(人员、货架、地面标线)反解尺度因子;或与 IMU、双目基线等传感模态融合恢复尺度。这是单目方案相对双目/ToF/LiDAR 的本质边界。
- 分辨率与上采样伪影。原始深度场为 224×224,上采样至输入分辨率后存在平滑伪影;对空间分辨率有要求的应用应评估该指标是否满足需求。

