ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

YOLO与单目深度估计融合实战:从2D图像到3D感知

YOLO与单目深度估计融合实战:从2D图像到3D感知 在计算机视觉项目中我们常常需要同时理解场景中的“是什么”和“在哪里”。目标检测YOLO能告诉我们物体是什么、在哪里而单目深度估计则能告诉我们物体离我们有多远。将两者结合就能从一张普通的2D图片中构建出带有深度信息的3D感知场景。本文将手把手带你完成一个“YOLO-DEPTH”单目深度测试项目从环境搭建、模型推理到结果可视化提供完整的代码和避坑指南让你能快速复现并应用到自己的项目中。1. 项目背景与核心概念1.1 什么是YOLO与单目深度估计YOLOYou Only Look Once是一种先进的目标检测算法。它的核心思想是将目标检测任务视为一个回归问题只需“看”一次图像就能直接预测出图像中所有目标的边界框和类别概率。YOLO以其速度快、精度高而闻名非常适合实时应用如视频监控、自动驾驶和机器人导航。目前主流版本已发展到YOLOv8、YOLOv9等。单目深度估计Monocular Depth Estimation是指仅使用一张RGB图像单个摄像头视角来估计场景中每个像素点到相机的距离深度。这与需要两个摄像头的立体视觉不同更具挑战性但也更灵活、成本更低。近年来基于深度学习的单目深度估计模型如MiDaS、Depth Anything取得了巨大进展能够从单张图片中恢复出相对准确的深度图。1.2 为什么需要YOLO-DEPTH结合单独的目标检测或深度估计都有其局限性仅有YOLO我们知道“图片里有一只猫在左上角”但不知道这只猫离我们是1米还是10米。这对于需要空间交互的应用如机器人抓取、AR/VR是致命的。仅有深度图我们知道场景中每个点的远近关系但不知道哪些点属于同一个物体猫、桌子、人。深度图是稠密的几何信息缺乏语义。YOLO-DEPTH的结合完美地解决了上述问题语义几何YOLO提供物体的语义标签和精确的2D边界框深度图提供每个像素的3D位置信息。实例级深度分析我们可以根据YOLO检测到的边界框从深度图中裁剪出对应区域计算该物体的平均深度、最近点、最远点等实现“对每个物体进行测距”。3D感知结合相机内参可以将2D检测框和深度信息反投影到3D空间估算物体在真实世界中的大致尺寸和位置。应用场景自动驾驶感知车辆、行人距离、机器人导航与抓取、增强现实将虚拟物体放置在真实场景的正确深度、智能监控判断入侵者的距离、无人机避障等。2. 环境准备与版本说明本项目将使用Python作为开发语言主要依赖PyTorch深度学习框架并选用YOLOv8进行目标检测选用轻量且强大的Depth Anything模型进行深度估计。2.1 基础环境操作系统Windows 10/11, Linux (Ubuntu 20.04), 或 macOS。本文示例在Ubuntu 22.04上完成。Python 3.8 (推荐3.8或3.9)包管理工具pip 或 conda2.2 核心依赖库创建一个新的Python虚拟环境是良好的实践。以下是项目所需的依赖请将其保存到requirements.txt文件中。# requirements.txt torch1.10.0 # PyTorch深度学习框架 torchvision0.11.0 opencv-python4.5.0 # 图像处理 ultralytics8.0.0 # YOLOv8官方库 numpy1.20.0 # 数值计算 matplotlib3.3.0 # 结果可视化 Pillow8.0.0 # 图像处理 # Depth Anything 官方库 (通过git安装)版本说明ultralytics库封装了YOLOv8提供了极其简便的训练和推理接口。Depth Anything是一个独立的仓库我们需要克隆它并安装其依赖。2.3 环境搭建步骤步骤1创建并激活虚拟环境# 使用 conda conda create -n yolo-depth python3.9 conda activate yolo-depth # 或使用 venv python -m venv yolo-depth-env # Linux/macOS source yolo-depth-env/bin/activate # Windows yolo-depth-env\Scripts\activate步骤2安装PyTorch请根据你的CUDA版本如果有GPU前往 PyTorch官网 获取正确的安装命令。例如对于CUDA 11.8pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118如果没有GPU则安装CPU版本pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu步骤3安装其他依赖和YOLOv8pip install ultralytics opencv-python numpy matplotlib Pillow步骤4克隆并安装Depth Anythinggit clone https://github.com/LiheYoung/Depth-Anything.git cd Depth-Anything pip install -r requirements.txt # 安装Depth Anything包本身 pip install -e . cd .. # 返回项目根目录现在你的环境已经准备好了。项目目录结构建议如下yolo_depth_project/ ├── requirements.txt ├── main.py # 主程序 ├── utils.py # 工具函数 ├── test_images/ # 存放测试图片 │ ├── street.jpg │ └── indoor.jpg ├── results/ # 存放输出结果 └── Depth-Anything/ # 克隆的Depth Anything仓库3. 核心原理与模型加载3.1 YOLOv8推理流程YOLOv8将检测任务简化为一个高效的卷积神经网络。输入图像被划分为网格每个网格预测多个边界框及其置信度和类别概率。ultralytics库的YOLO类封装了从加载模型、预处理图像、推理到后处理非极大值抑制的全过程我们只需几行代码即可调用。3.2 Depth Anything模型简介Depth Anything采用了大规模无标注数据预训练的策略学习到了强大的深度先验。它提供了一个统一的编码器-解码器架构可以输出与输入图像同分辨率的深度图深度值经过归一化处理通常0代表最近1代表最远。我们主要使用其DepthAnythingV2模型它比V1版本更轻量、更准确。3.3 模型初始化代码让我们创建一个utils.py文件来封装模型加载函数。# utils.py import torch import cv2 from ultralytics import YOLO from depth_anything.dpt import DepthAnything def load_yolo_model(model_pathyolov8n.pt): 加载YOLOv8模型。 参数: model_path: 模型权重文件路径。可以是官方模型名如‘yolov8n.pt’或自定义训练权重。 返回: YOLO模型实例。 # 首次运行会自动从Ultralytics服务器下载预训练权重 model YOLO(model_path) # 设置为推理模式 model.to(cuda if torch.cuda.is_available() else cpu) print(fYOLO模型加载成功设备: {next(model.model.parameters()).device}) return model def load_depth_anything_model(encodervits, devicecuda): 加载Depth Anything模型。 参数: encoder: 编码器类型可选 ‘vits’, ‘vitb’, ‘vitl’。越小越快精度可能略低。 device: 运行设备‘cuda’ 或 ‘cpu’。 返回: DepthAnything模型实例。 model DepthAnything.from_pretrained(fLiheYoung/depth_anything_{encoder}14) model.to(device) model.eval() # 设置为评估模式 print(fDepth Anything模型加载成功编码器: {encoder}, 设备: {device}) return model def preprocess_image_for_depth(image_rgb): 将图像预处理为Depth Anything模型所需的格式。 参数: image_rgb: RGB格式的numpy数组 (H, W, 3)。 返回: 预处理后的张量 (1, 3, H, W)。 import torchvision.transforms as T transform T.Compose([ T.ToTensor(), ]) image_tensor transform(image_rgb).unsqueeze(0) # 增加batch维度 return image_tensor4. 完整实战单张图片推理与可视化我们将编写一个main.py实现读取图片、分别用YOLO和Depth Anything推理、融合结果并可视化的完整流程。4.1 主程序框架# main.py import cv2 import numpy as np import matplotlib.pyplot as plt from utils import load_yolo_model, load_depth_anything_model, preprocess_image_for_depth def main(): # 1. 初始化模型 print(正在加载模型...) yolo_model load_yolo_model(yolov8n.pt) # 使用nano版本速度快 depth_model load_depth_anything_model(encodervits, devicecuda if torch.cuda.is_available() else cpu) # 2. 读取图像 image_path test_images/street.jpg image_bgr cv2.imread(image_path) if image_bgr is None: print(f错误无法读取图像 {image_path}) return image_rgb cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB) original_h, original_w image_rgb.shape[:2] print(f图像加载成功: {image_path}, 尺寸: ({original_w}, {original_h})) # 3. YOLO目标检测 print(正在进行YOLO目标检测...) yolo_results yolo_model(image_rgb, verboseFalse) # verboseFalse关闭冗余日志 # 提取检测结果 detections yolo_results[0].boxes # 获取边界框、置信度、类别ID boxes detections.xyxy.cpu().numpy() if detections is not None else [] # [x1, y1, x2, y2] confs detections.conf.cpu().numpy() if detections is not None else [] class_ids detections.cls.cpu().numpy().astype(int) if detections is not None else [] class_names yolo_model.names # 获取类别名称映射字典 # 4. Depth Anything深度估计 print(正在进行深度估计...) image_tensor preprocess_image_for_depth(image_rgb) with torch.no_grad(): # 关闭梯度计算加速推理 depth depth_model(image_tensor) # depth形状为 (1, H, W)转换为numpy并缩放到0-255用于可视化 depth_map depth.squeeze().cpu().numpy() # (H, W) # 深度值归一化到0-1然后映射到0-255 depth_normalized (depth_map - depth_map.min()) / (depth_map.max() - depth_map.min() 1e-8) depth_vis (depth_normalized * 255).astype(np.uint8) # 应用颜色映射如‘jet’使深度图更直观 depth_colored cv2.applyColorMap(depth_vis, cv2.COLORMAP_INFERNO) # 5. 融合与可视化 print(正在生成可视化结果...) # 5.1 绘制YOLO检测结果在原图上 result_image image_rgb.copy() for box, conf, cls_id in zip(boxes, confs, class_ids): x1, y1, x2, y2 map(int, box) label f{class_names[cls_id]} {conf:.2f} # 画框 cv2.rectangle(result_image, (x1, y1), (x2, y2), (0, 255, 0), 2) # 画标签背景 (text_w, text_h), _ cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.6, 2) cv2.rectangle(result_image, (x1, y1 - text_h - 5), (x1 text_w, y1), (0, 255, 0), -1) # 画文字 cv2.putText(result_image, label, (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 0), 2) # 5.2 计算并显示每个检测物体的平均深度 # 确保边界框在图像范围内 x1_c, x2_c max(0, x1), min(original_w, x2) y1_c, y2_c max(0, y1), min(original_h, y2) if x2_c x1_c and y2_c y1_c: object_depth_region depth_map[y1_c:y2_c, x1_c:x2_c] if object_depth_region.size 0: avg_depth np.mean(object_depth_region) # 注意depth_map的值是相对的越小代表越近对于某些模型可能相反需根据模型输出确认 # 这里我们假设值越小越近 depth_text fDepth: {avg_depth:.3f} cv2.putText(result_image, depth_text, (x1, y2 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 0), 2) print(f检测到 {class_names[cls_id]}, 置信度 {conf:.2f}, 平均深度值: {avg_depth:.3f}) # 6. 保存和显示结果 # 将RGB图像转换回BGR以供OpenCV保存 result_image_bgr cv2.cvtColor(result_image, cv2.COLOR_RGB2BGR) output_path results/fused_result.jpg cv2.imwrite(output_path, result_image_bgr) cv2.imwrite(results/depth_map.jpg, depth_colored) print(f结果已保存至: {output_path}) # 使用Matplotlib并排显示 fig, axes plt.subplots(1, 3, figsize(18, 6)) axes[0].imshow(image_rgb) axes[0].set_title(Original Image) axes[0].axis(off) axes[1].imshow(result_image) axes[1].set_title(YOLO Detection with Depth Text) axes[1].axis(off) axes[2].imshow(cv2.cvtColor(depth_colored, cv2.COLOR_BGR2RGB)) axes[2].set_title(Depth Map (Colored)) axes[2].axis(off) plt.tight_layout() plt.savefig(results/comparison.png, dpi150) plt.show() if __name__ __main__: import torch main()4.2 运行与结果说明在项目根目录下确保已创建test_images文件夹并放入测试图片如street.jpg。创建results文件夹用于保存输出。在终端运行python main.py首次运行程序会自动从网上下载YOLOv8n的预训练权重和Depth Anything的模型权重请保持网络通畅。输出控制台会打印加载信息、检测到的物体及其平均深度值。程序会生成三张图results/fused_result.jpg原始图像上绘制了YOLO检测框、类别标签以及计算出的该物体的平均深度值。results/depth_map.jpg应用了颜色映射的深度估计图暖色如红、黄通常代表较近的区域冷色如蓝、紫代表较远的区域。results/comparison.png将原图、检测融合图、深度图并排对比显示。结果解读在融合结果图中你不仅能看到“汽车”、“行人”等标签还能看到每个框下方显示的“Depth: x.xxx”。这个数值是归一化后的相对深度数值越小代表该物体区域离相机越近对于Depth Anything的输出特性。通过对比不同物体的深度值你可以直观地理解场景的3D布局。5. 常见问题与排查思路在复现过程中你可能会遇到以下问题问题现象可能原因解决思路ModuleNotFoundError: No module named ‘depth_anything’未正确安装Depth Anything包。确保在Depth-Anything目录下执行了pip install -e .。检查Python环境是否激活正确。RuntimeError: CUDA out of memoryGPU显存不足。1. 使用更小的模型YOLO用yolov8n.ptDepth Anything用vits编码器。2. 减小输入图像尺寸在yolo_model()和预处理时传入imgsz640参数。3. 在load_*_model函数中强制使用devicecpu。YOLO检测框为空图片中无目标或置信度阈值太高。1. 换一张包含常见物体人、车的图片测试。2. 调整YOLO推理参数yolo_model(image_rgb, conf0.25, iou0.45, verboseFalse)降低conf置信度阈值。深度图全黑或全白深度值归一化或可视化环节出错。检查depth_map的数值范围print(depth_map.min(), depth_map.max())。Depth Anything的输出通常需要1 - depth_map或直接使用depth_map根据模型特性调整。确保depth_normalized计算正确。运行速度非常慢在CPU上运行大型模型。1. 确认PyTorch是否安装了CUDA版本print(torch.cuda.is_available())。2. 如果使用CPU考虑使用最小的模型组合YOLOv8n Depth Anything VITS。3. 对视频流处理时可以考虑异步处理或降低帧率。下载模型权重失败网络连接问题。1. 手动下载权重YOLO权重可在Ultralytics官网找到Depth Anything权重在Hugging Face Hub上。将下载的.pt或.pth文件放在指定路径修改load_model函数中的路径参数。2. 配置网络代理注意此处仅提及解决网络问题的通用思路不涉及任何具体工具或方法。6. 进阶应用与最佳实践6.1 视频流实时处理将上述单张图片处理逻辑嵌入到视频流循环中即可实现实时YOLO-DEPTH感知。# video_demo.py (简略框架) import cv2 from utils import load_yolo_model, load_depth_anything_model def process_video(video_path0): # 0 代表摄像头 cap cv2.VideoCapture(video_path) yolo_model load_yolo_model(yolov8n.pt) depth_model load_depth_anything_model(vits, cuda) while cap.isOpened(): ret, frame cap.read() if not ret: break # 1. 转换颜色空间 frame_rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # 2. YOLO检测 (可以每N帧检测一次以提升速度) results yolo_model(frame_rgb, imgsz320, verboseFalse)[0] # 缩小尺寸加速 # 3. 深度估计 (可以降低频率或使用小图) # 注意深度估计计算量大实时视频中可能需要跳帧或使用更低分辨率 # depth depth_model(preprocess(frame_rgb)) # 4. 绘制结果到frame上 annotated_frame results.plot() # 使用ultralytics内置绘图函数 # 5. 显示 cv2.imshow(YOLO-DEPTH Demo, annotated_frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()优化建议深度估计模型计算开销大在实时视频中可以每5-10帧计算一次深度图或者仅在检测到特定关键物体如行人、车辆时才计算其局部深度。6.2 3D空间位置估算需要相机内参如果已知相机的内参矩阵焦距fx, fy和光心cx, cy可以将2D像素点和深度值反投影到3D相机坐标系。def pixel_to_camera(u, v, d, fx, fy, cx, cy): 将像素坐标(u,v)和深度d转换为相机坐标系下的3D点(X, Y, Z) Z d # 深度值假设深度图单位为米需要根据模型输出进行缩放 X (u - cx) * Z / fx Y (v - cy) * Z / fy return X, Y, Z # 示例计算检测框中心点的3D坐标 fx, fy, cx, cy 500, 500, 320, 240 # 示例内参需替换为真实值 for box in boxes: x_center int((box[0] box[2]) / 2) y_center int((box[1] box[3]) / 2) # 获取该中心点的深度值注意深度图可能需要插值 depth_at_center depth_map[y_center, x_center] X, Y, Z pixel_to_camera(x_center, y_center, depth_at_center, fx, fy, cx, cy) print(f物体中心3D坐标: ({X:.2f}, {Y:.2f}, {Z:.2f}) meters)6.3 工程化建议模型选择在精度和速度间权衡。YOLOv8s/m和Depth Anything VITB是较好的平衡点。预处理标准化确保输入图像的预处理方式归一化、resize策略与模型训练时一致。ultralytics和DepthAnything的transform方法已内部处理。后处理YOLO的results对象包含了丰富的输出框、掩码、关键点根据需求提取。深度图后处理可能包括滤波如双边滤波以平滑噪声。错误处理在生产代码中务必添加对图像读取失败、模型加载失败、推理异常等的try-except处理。日志与监控记录推理时间、检测数量、平均深度等指标便于性能分析和调试。安全与隐私处理涉及人脸的图像或视频时需注意隐私法规。在公共场所部署时应考虑数据匿名化处理。通过本教程你不仅成功运行了一个YOLO-DEPTH联合测试项目还掌握了从环境搭建、模型推理、结果融合到进阶应用的完整链路。这套技术栈具有很强的可扩展性你可以尝试更换更大的模型以提升精度将其集成到机器人ROS节点中或者利用深度信息实现更复杂的3D交互应用。动手过程中遇到的每一个报错都是深入理解框架和模型的好机会。
返回列表