单目深度估计从单张 RGB 图像预测逐像素深度图。每个输出像素包含一个以米为单位的深度值表示从相机到该表面点的估计距离。深度模型的输出是一个与输入图像对齐的、形状为 (H, W) 的密集浮点地图。这种逐像素的表示方式使单目深度估计非常适合用于 3D 场景重建、机器人导航、AR/VR 内容创作以及任何需要从单个相机获取空间布局的应用。YOLO-Depth模型整体依旧沿用YOLO26的设计理念即用Backbone-Neck-Head三段式架构通过将最终的检测头替换为深度估计头将YOLO系列的高效特征提取能力迁移至深度估计任务。在特征提取阶段模型通过步长卷积与C3k2模块构建多级特征金字塔结合SPPF模块扩大感受野以捕获全局场景信息并引入C2PSA注意力机制强化对关键深度区域的感知最终输出P3、P4、P5三个尺度的特征图。在特征融合阶段Neck部分采用PAN/FPN结构通过上采样与特征拼接操作将深层语义信息与浅层细节信息进行双向融合生成兼具高分辨率与强语义的三尺度融合特征。在深度预测阶段多尺度Depth Head首先通过投影层统一特征通道再经Refine精炼层对各尺度特征进行独立优化随后通过Multi-scale Fusion模块融合三尺度精炼特征最后由Depth Head模块经上采样与卷积输出单通道无界对数深度图实现从RGB图像到稠密深度图的端到端映射单目深度估计数据集我们这里使用的是NYU Depth Dataset V2数据集其是计算机视觉领域中用于室内场景理解、深度估计和语义分割的一个经典基准数据集。该数据集由纽约大学NYU的 Nathan Silberman 等人发布其核心数据是使用 Microsoft Kinect 设备从多种室内场景中录制的视频序列。标注数据Labeled包含1449对经过密集标注且严格对齐的 RGB 图像与深度图像。这些图像涵盖了来自 3 个城市的 464 个室内场景每个像素都带有类别和实例编号标签。原始数据Raw包含 407,024 帧未标注的原始 RGB、深度及加速度计数据path:nyu-depth# dataset root dir (relative to Ultralytics settings datasets_dir)train:images/train# train images (relative to path) 795 imagesval:images/val# val images (relative to path) 654 images# Classesnc:1names:0:depthchannels:3# Download script/URL (optional)download:https://github.com/ultralytics/assets/releases/download/v0.0.0/nyu-depth.zipdataset/ ├── images/ │ ├── train/ │ └── val/ └── depth/ ├── train/ └── val/标注数据如下其为npy存储通过该方法读取出标签importnumpyasnpimportmatplotlib matplotlib.use(TkAgg)# 强制使用 TkAgg 后端必须在导入 pyplot 之前importmatplotlib.pyplotasplt# 1. 读取 .npy 文件npy_pathrD:\nyu-depth\nyu-depth\depth\train\nyu_0266.npy# 请替换为你的实际文件路径depth_mapnp.load(npy_path)# 2. 打印基础信息帮助确认数据是否正常加载print(f深度图形状 (Height, Width):{depth_map.shape})print(f数据类型:{depth_map.dtype})print(f深度范围:{np.nanmin(depth_map):.3f}m ~{np.nanmax(depth_map):.3f}m)# 3. 处理无效值深度图中通常用 NaN 或 0 表示无法测量的区域depth_map_cleannp.nan_to_num(depth_map,nan0.0)# 4. 可视化展示plt.figure(figsize(10,8))# 使用 plasma 或 jet colormap这两种配色在深度图中对比度较好implt.imshow(depth_map_clean,cmapplasma)plt.colorbar(im,labelDepth (meters))plt.title(Depth Map Visualization)plt.axis(off)# 隐藏坐标轴使图像更美观plt.tight_layout()plt.show()YOLO-Depth网络结构该模型整体依旧沿用YOLO26的设计理念即用Backbone-Neck-Head三段式架构通过将最终的检测头替换为深度估计头将YOLO系列的高效特征提取能力迁移至深度估计任务。在特征提取阶段模型通过步长卷积与C3k2模块构建多级特征金字塔结合SPPF模块扩大感受野以捕获全局场景信息并引入C2PSA注意力机制强化对关键深度区域的感知最终输出P3、P4、P5三个尺度的特征图。在特征融合阶段Neck部分采用PAN/FPN结构通过上采样与特征拼接操作将深层语义信息与浅层细节信息进行双向融合生成兼具高分辨率与强语义的三尺度融合特征。在深度预测阶段多尺度Depth Head首先通过投影层统一特征通道再经Refine精炼层对各尺度特征进行独立优化随后通过Multi-scale Fusion模块融合三尺度精炼特征最后由Depth Head模块经上采样与卷积输出单通道无界对数深度图实现从RGB图像到稠密深度图的端到端映射模型结构文件如下# YOLO26n backbonebackbone:# [from, repeats, module, args]-[-1,1,Conv,[64,3,2]]# 0-P1/2-[-1,1,Conv,[128,3,2]]# 1-P2/4-[-1,2,C3k2,[256,False,0.25]]-[-1,1,Conv,[256,3,2]]# 3-P3/8-[-1,2,C3k2,[512,False,0.25]]-[-1,1,Conv,[512,3,2]]# 5-P4/16-[-1,2,C3k2,[512,True]]-[-1,1,Conv,[1024,3,2]]# 7-P5/32-[-1,2,C3k2,[1024,True]]-[-1,1,SPPF,[1024,5,3,True]]# 9-[-1,2,C2PSA,[1024]]# 10# YOLO26n headhead:-[-1,1,nn.Upsample,[None,2,nearest]]-[[-1,6],1,Concat,[1]]# cat backbone P4-[-1,2,C3k2,[512,True]]# 13-[-1,1,nn.Upsample,[None,2,nearest]]-[[-1,4],1,Concat,[1]]# cat backbone P3-[-1,2,C3k2,[256,True]]# 16 (P3/8-small)-[-1,1,Conv,[256,3,2]]-[[-1,13],1,Concat,[1]]# cat head P4-[-1,2,C3k2,[512,True]]# 19 (P4/16-medium)-[-1,1,Conv,[512,3,2]]-[[-1,10],1,Concat,[1]]# cat head P5-[-1,1,C3k2,[1024,True,0.5,True]]# 22 (P5/32-large)-[[16,19,22],1,Depth,[256]]# Depth(P3, P4, P5) c_mid256; unbounded log-depth output模型结构如下Depth((proj):ModuleList((0):Conv((conv):Conv2d(64,256,kernel_size(1,1),stride(1,1))(act):SiLU(inplaceTrue) )(1):Conv((conv):Conv2d(128,256,kernel_size(1,1),stride(1,1))(act):SiLU(inplaceTrue) )(2):Conv((conv):Conv2d(256,256,kernel_size(1,1),stride(1,1))(act):SiLU(inplaceTrue) ) )(refine):ModuleList((0-2):3 x Sequential((0):Conv((conv):Conv2d(256,256,kernel_size(3,3),stride(1,1),padding(1,1))(act):SiLU(inplaceTrue) )(1):Conv((conv):Conv2d(256,256,kernel_size(3,3),stride(1,1),padding(1,1))(act):SiLU(inplaceTrue) ) ) )(head):Sequential((0):Conv((conv):Conv2d(256,128,kernel_size(3,3),stride(1,1),padding(1,1))(act):SiLU(inplaceTrue) )(1):ConvTranspose2d(128,128,kernel_size(2,2),stride(2,2))(2):Conv((conv):Conv2d(128,64,kernel_size(3,3),stride(1,1),padding(1,1))(act):SiLU(inplaceTrue) )(3):Conv2d(64,1,kernel_size(1,1),stride(1,1)) ) )1.proj(投影层): 统一多尺度特征(proj):ModuleList((0):Conv2d(64,256,kernel_size(1,1))(1):Conv2d(128,256,kernel_size(1,1))(2):Conv2d(256,256,kernel_size(1,1)))作用YOLO 的 Neck 通常会输出 3 个不同尺度的特征图例如 80×80、40×40、20×20对应的通道数通常是 64、128、256。由于通道数不一致无法直接进行特征融合。机制这里使用了 3 个1×1卷积逐点卷积将这三个不同尺度的特征图通道数全部统一映射到256。1×1卷积只改变通道维度不改变特征图的空间尺寸H, W起到了通道对齐的作用。2.refine(精炼层): 增强空间细节(refine):ModuleList((0-2):3x Sequential((0):Conv2d(256,256,kernel_size(3,3),padding(1,1))(1):Conv2d(256,256,kernel_size(3,3),padding(1,1))))作用深度估计对边缘和空间细节要求极高。在通道对齐后使用3×3卷积可以捕获局部的空间上下文信息。机制对 3 个尺度的特征图分别进行两次3×3卷积配合padding(1,1)保持尺寸不变。这相当于在每个尺度上进行了深度的特征提取让网络更好地学习物体的轮廓、纹理等与深度相关的几何特征。3.head(解码头): 特征融合与上采样这是深度估计头的核心输出部分负责将多尺度特征融合并恢复到原始分辨率(head):Sequential((0):Conv2d(256,128,kernel_size(3,3),padding(1,1))# 融合与降维(1):ConvTranspose2d(128,128,kerdefpostprocess(self,preds:torch.Tensor|tuple|list,img:torch.Tensor,orig_imgs:list[np.ndarray]|torch.Tensor)-list[Results]:Post-process depth predictions to Results objects.depth_mapspreds[0]ifisinstance(preds,(tuple,list))elsepreds# (B, 1, H, W)ifdepth_maps.ndim3:depth_mapsdepth_maps.unsqueeze(1)# (B, H, W) → (B, 1, H, W)# Restore model-input resolution so all backends crop letterbox padding before scaling to the original image.depth_mapsops.scale_masks(depth_maps,img.shape[2:],paddingFalse)ifnotisinstance(orig_imgs,list):# torch.Tensor source (B, 3, H, W)orig_imgsops.convert_torch2numpy_batch(orig_imgs)results[]fori,orig_imginenumerate(orig_imgs):img_pathself.batch[0][i]ifisinstance(self.batch[0],list)elseself.batch[0]depthops.scale_masks(depth_maps[i:i1].float(),orig_img.shape[:2])results.append(Results(orig_imgorig_img,pathimg_path,namesself.model.names,depthdepth.squeeze()))returnresultsnel_size(2,2),stride(2,2))# 2倍上采样(2):Conv2d(128,64,kernel_size(3,3),padding(1,1))# 进一步降维(3):Conv2d(64,1,kernel_size(1,1))# 输出单通道深度图)步骤 (0)首先通过3×3卷积将通道数从 256 降至 128。在实际代码中这里通常会在进入head之前将refine输出的 3 个特征图进行拼接Concat或相加Add然后送入这一层进行多尺度特征融合。步骤 (1)使用了转置卷积ConvTranspose2d。kernel_size(2,2), stride(2,2)是标准的 2 倍上采样操作将特征图的空间尺寸H, W放大一倍恢复空间分辨率。步骤 (2)上采样后再次使用3×3卷积将通道数从 128 降至 64消除上采样带来的棋盘效应Checkerboard Artifacts并平滑特征。步骤 (3)最终使用1×1卷积将通道数压缩为1。因为深度图本质上是一个单通道的灰度图每个像素点的值代表该位置距离相机的物理深度。后处理代码如下其将YOLO26-Depth模型输出的11144192的数据经过转换变为11480640的结构defpostprocess(self,preds:torch.Tensor|tuple|list,img:torch.Tensor,orig_imgs:list[np.ndarray]|torch.Tensor)-list[Results]:Post-process depth predictions to Results objects.depth_mapspreds[0]ifisinstance(preds,(tuple,list))elsepreds# (B, 1, H, W)ifdepth_maps.ndim3:depth_mapsdepth_maps.unsqueeze(1)# (B, H, W) → (B, 1, H, W)# Restore model-input resolution so all backends crop letterbox padding before scaling to the original image.depth_mapsops.scale_masks(depth_maps,img.shape[2:],paddingFalse)ifnotisinstance(orig_imgs,list):# torch.Tensor source (B, 3, H, W)orig_imgsops.convert_torch2numpy_batch(orig_imgs)results[]fori,orig_imginenumerate(orig_imgs):img_pathself.batch[0][i]ifisinstance(self.batch[0],list)elseself.batch[0]depthops.scale_masks(depth_maps[i:i1].float(),orig_img.shape[:2])results.append(Results(orig_imgorig_img,pathimg_path,namesself.model.names,depthdepth.squeeze()))returnresults模型性能YOLO-Depth在NYU Depth V2数据集上表现如下delta1NYU是在 NYU Depth V2 Eigen 测试集654 张图像上使用多尺度 水平翻转 TTA和对数最小二乘对齐后预测深度与真实值误差在 1.25 倍以内的像素百分比。在不使用 TTA 的情况下单尺度准确率可通过 yolo depth val modelyolo26n-depth.ptdatanyu-depth.yaml imgsz768 device0 进行复现该方法采用中位数仅尺度对齐得分较低delta1 0.783 (n)、0.793 (s)、0.840 (m)、0.853 (l)、0.860 (x)。abs_rel 是预测深度值与真实深度值之间的平均绝对相对误差。rmse 是以米为单位的均方根误差。速度是指在 imgsz768、batch1 下仅推理的延迟不含预处理/后处理以热身后的计时运行的均值 ± 标准差报告。CPU ONNX 是在 32 核 Intel Xeon (Skylake) 上运行的 ONNX Runtime fp32T4TensorRT10 是在 Tesla T4 上运行的 TensorRT fp16。params 和 FLOPs 是在 768×768 分辨率发布权重时的训练分辨率下测量的。与YOLO目标检测相结合YOLO-Depth模型直接输出与输入图像分辨率一致的稠密深度图图中每个像素值精确表征了该点到摄像头的物理距离。在实际应用中通过结合YOLO等目标检测算法获取检测框的中心坐标并索引深度图中对应位置的像素值即可实现对目标物体测距的精准量化。importcv2fromultralyticsimportYOLOfromultralytics.utils.plottingimportcolorize_depth# 1. 加载不同的模型model_depthYOLO(yolo26n-depth.pt)# 深度估计模型model_detectYOLO(rbest.pt)# 目标检测模型image_pathrimages\yique_0052.jpg# 2. 分别进行推理并将结果保存在不同的变量中depth_resultsmodel_depth(image_path)detect_resultsmodel_detect(image_path)# 3. 处理结果假设只有一张图片depth_resultdepth_results[0]detect_resultdetect_results[0]# 4. 获取并转换深度图depth_mapdepth_result.depth.data.cpu().numpy()color_depth_imgcolorize_depth(depth_map)# 5. 遍历【目标检测】结果在深度图上绘制边界框和深度值forboxindetect_result.boxes.xyxy.cpu().numpy():x1,y1,x2,y2map(int,box)# 计算检测框的中心点center_x(x1x2)//2center_y(y1y2)//2# 提取中心点的深度值注意边界保护if0center_ydepth_map.shape[0]and0center_xdepth_map.shape[1]:depth_valuedepth_map[center_y,center_x]# 在检测框上方显示深度textf{depth_value:.2f}mcv2.putText(color_depth_img,text,(x1,y1-10),cv2.FONT_HERSHEY_SIMPLEX,0.8,(0,255,255),1,cv2.LINE_AA)# 在中心点画个十字标记cv2.circle(color_depth_img,(center_x,center_y),2,(0,255,255),-1)# 6. 保存最终结果cv2.imwrite(depth_with_detections.jpg,color_depth_img)效果如下