YOLOv5双目测距实战:从标定到部署的完整指南

发布时间:2026/9/8 12:22:48
YOLOv5双目测距实战:从标定到部署的完整指南 简介YOLOv5双目测距源码是一套面向计算机视觉开发者与深度学习初学者的完整可运行项目将YOLOv5目标检测与双目视觉测距结合适用于自动驾驶、机器人导航等实时距离估计场景。压缩包共106个文件、大小20.88MB主要包含Python源码.py/.pyc、模型权重yolov5s.pt、YAML配置、训练与预测脚本、Dockerfile以及测试图像和视频结构清晰便于对照学习。已有2837人学习下载项目描述中详细梳理了从模型结构、数据预处理、损失函数到双目匹配与视差计算的关键知识点能帮助读者理解完整技术链路。代码已跑通下载后配置好PyTorch环境即可复现实测效果适合用于课程设计、项目实战或二次开发。1. 项目背起与整体方案设计“检测测距”的组合拳先说说我为什么折腾这个项目。跑通 YOLOv5 双目测距源码不是单纯为了“我调通了别人的代码”这种成就感而是目标检测和距离估计在真实场景里往往是一体的需求——安防巡检要判断闯入目标离设备多远辅助驾驶要知道前方车辆和行人的距离农业机器人要定位果实位置引导机械臂抓取。单纯做检测只能告诉你“哪里有目标”加上双目测距才能回答“目标离我多远”感知维度立刻从二维升到三维。1.1 方案选型为什么是YOLOv5和双目相机目标检测框架可选很多YOLOv5 到今天依然是性价比极高的选择。相比 YOLOv8 和 v11它的网络结构更直观代码可读性好Github 上的资料和预训练模型极其丰富社区踩坑记录多到搜都搜不完。我实测下来同样的数据集 YOLOv5s 在推理速度上比 YOLOv8n 慢一点点但精度稳定性更扎实这对后续测距模块很重要——检测框抖动越小深度数值跳动越小。距离估计这边方案有三种单目测距、双目立体视觉、深度相机如 Kinect 或 Intel RealSense。单目测距依赖目标在图像中的尺寸和先验知识换个目标就要重新标定通用性差深度相机精度高但没有通用性且室外强光下红外结构光基本失效成本还不低。双目方案只需要两个普通摄像头成本低、可移植性强核心就是“三角测量”原理非常适合作为通用测距模块。这也是我最终选“YOLOv5 检测 双目测距”组合的根本原因——检测框负责锁定目标双目标定和视差计算负责输出深度信息。1.2 硬件与数据准备两台手机也能当双目相机这里透露一个能大幅降低试错成本的做法如果手头暂时没有工业双目相机用两台同型号的智能手机固定在水平支架上就能拼合成最简易的双目系统。我早期调试时就是这么干的两台手机同步录一段视频再用 FFmpeg 按帧抽图拼出一个左右视图数据集。缺点是无法硬件同步曝光所以只适合静态场景的算法验证动态目标测试还是建议直接买现成的双目摄像头模组比如常见的 720p/1080p USB 双目省去同步麻烦。数据集方面如果是训练自己的检测模型网上开源数据集很多比如 COCO 里就有 person、car、traffic light 等类别先拿它验证整个流程跑通。如果有定制目标比如工地安全帽、果园水果再用 LabelImg 或 Roboflow 标注 1000 到 3000 张自己的图片转成 YOLOv5 要求的 txt 格式。我自己做的时候大概花了两个晚上标注了 1200 张安全帽图片其实真正占时间的是每个类别样本的均衡度和遮挡场景的覆盖而不是标注动作本身。2. YOLOv5环境搭建与模型训练的关键细节2.1 环境配置Python版本和依赖包的那些坑YOLOv5 是出了名的“配置环境三天训练模型三小时”很多小伙伴卡在第一关。我的实测配置是Python 3.8 PyTorch 1.12 CUDA 11.6这个组合非常稳定。如果机器没有 N 卡纯 CPU 环境也能跑只是训练速度慢到怀疑人生推理勉强能接受。安装依赖这里有个独家经验requirements.txt里的版本号不要无脑全装最新。比如opencv-python装最新版有时候会和其他视觉库冲突numpy版本过新也会和 PyTorch 1.x 产生兼容警告。我自己习惯把numpy锁到1.23.5torch和torchvision版本严格对应避免出现 undefined symbol 一类的玄学报错。注意训练前先把datasets/coco128这个迷你数据集跑一轮完整流程确认环境没问题之后再上自己的数据集。这一步能帮你把“代码问题”和“数据集问题”分开排查省下大量调试时间。2.2 数据标注与训练参数调整标注格式是 YOLOv5 专属的.txt格式每行对应一个目标框class_id x_center y_center width height所有数值要归一化到 0~1。LabelImg 用起来上手最快保存时选 YOLO 格式它会自动生成一个同名的 txt 文件。标注完成后检查一遍目录结构指向训练集和验证集的 txt 文件各放一个文件夹和图片文件保持同名。训练命令我常用这样python train.py --data mydata.yaml --weights yolov5s.pt --img 640 --epochs 100 --batch-size 16几个影响训练效果的关键参数--img训练输入分辨率。640是默认值速度和精度最均衡。如果目标比较小可以尝试960但显存占用直线上升。--batch-size根据显存大小调整8GB 显存跑yolov5s用 16 问题不大更大的模型要降。--weights优先使用预训练模型yolov5s.pt做迁移学习比从头训练收敛快得多。我在调自己的数据集时发现前 50 个 epoch 的损失下降曲线比较陡之后进入平台期。如果训练到后期 mAP 不再提升可以尝试--hyp hyp.finetune.yaml调整超参数学习率、动量等。新手不太建议一开始就动超参数先跑通默认配置熟悉之后再做消融实验。2.3 模型导出与加速把YOLOv5跑进实时通道测距应用对实时性有要求所以训练完成后建议做一次模型导出优化。我最常用的是 ONNX 格式可以直接在 OpenCV DNN 或 ONNXRuntime 上推理比 PyTorch 原生推理快两到三倍。导出命令很简单python export.py --weights best.pt --include onnx --opset 12如果是在 Jetson Nano / 树莓派这类嵌入式设备上部署还可以导出 TensorRT engine加速效果更明显。不过 TensorRT 版本和显卡驱动强绑定配置起来比 ONNX 麻烦不少。我个人的建议是先用 ONNX 跑通实时性测试满足要求就不急着上 TensorRT。3. 双目测距原理与相机标定的完整流程3.1 双眼如何判断距离说说三角测量和视差双目测距的底层逻辑其实特别朴素——人眼判断距离靠的就是两只眼睛看到的画面存在“视差”。同一物体在左右相机成像平面上的位置是不同的物体越近这个位置的偏移量越大。用公式表达就是深度 Z (焦距 f × 基线距离 B) / 视差 d其中f是相机焦距单位是像素由标定得出B是两个相机光心之间的距离单位是毫米或厘米d是同一个点在左右图中的水平坐标差单位像素直观理解f × B相当于一个固定系数深度和视差成反比。所以测距精度取决于两个核心因素视差计算准不准算法层面以及基线距离够不够大硬件层面。基线距离太小近处目标视差变化不明显基线太长近距离目标又会跑出公共视野。室内场景我一般用 5 到 10 厘米的基线室外大场景可以放宽到 15 到 30 厘米。3.2 标定步骤张正友标定法和双目标定实操相机标定的目标就是获得左右相机的内参焦距、光心、畸变系数和外参相对平移旋转关系。这一步不能省直接影响后续测距精度。我用的是 OpenCV 的标定工具先打印一张棋盘格标定板建议 9x6 内角点用左右相机同时拍摄 20 到 30 张不同角度的照片。拍摄时注意让标定板尽量铺满画面并覆盖画面的各个角落特别是边缘区域——因为畸变主要出现在边缘。代码层面主要用到cv2.findChessboardCorners和cv2.calibrateCamera然后双目标定用cv2.stereoCalibrate最后用cv2.stereoRectify得到左右视图的行对齐变换矩阵。标定完成后的核心产出物是左/右相机内参矩阵M1, M2畸变系数D1, D2旋转矩阵R、平移向量T校正映射表map1_x, map1_y, map2_x, map2_y这些参数保存成.npz或.yaml文件后续运行时加载。我在实际项目中就把这几组参数存成了一个calib_params.npz整个测距模块启动时一次性读入。4. 源码拆解与核心模块实现思路4.1 整体架构从读图到输出距离的三条流水线这个项目的源码结构很清楚整体上是一个经典流水线左右图采集 - 立体校正 - 视差图计算 - YOLOv5 目标检测 - 目标框深度提取 - 距离输出。第一步是读取左右相机图像。如果用的是 USB 双目模组直接cv2.VideoCapture(0)读取一帧同时包含左右画面的图然后按宽高从中裁成左右两半如果是两个独立摄像头就需要两个VideoCapture分别读取。第二步是立体校正用标定得到的映射表对左右图做cv2.remap目的是让左右图像的同一行完全对齐这样后期计算视差时只需要水平搜索。第三路是目标检测YOLOv5 检测得到目标框坐标、类别和置信度。最后一步是把检测框映射到视差图上取框内有效像素的视差中位数或均值代进三角测量公式算出距离。4.2 核心代码逻辑SGBM参数调优是关键视差计算我推荐用cv2.StereoSGBM_create效果比默认的 BM 好不少特别是对纹理较弱的区域。核心参数大概是sgbm cv2.StereoSGBM_create( minDisparity0, numDisparities64, blockSize9, P18 * 3 * blockSize ** 2, P232 * 3 * blockSize ** 2, disp12MaxDiff1, uniquenessRatio10, speckleWindowSize100, speckleRange32, modecv2.STEREO_SGBM_MODE_SGBM_3WAY )参数含义很好理解numDisparities越大能感知的深度范围越大但计算量也越大blockSize控制匹配窗口大小窗口太小容易产生噪声太大则边缘模糊P1/P2是平滑惩罚系数纹理少的地方调大P2可以抑制视差空洞。注意SGBM 的blockSize必须是奇数。另外numDisparities必须是 16 的倍数这个不满足会直接报错属于非常经典的深坑。视差图计算出来后无效像素点值为 0 或-16等标记值要滤除我是做了一个二值掩膜只保留有效值。然后针对 YOLOv5 返回的检测框把框内所有有效视差收集起来用中位数作为目标的最终视差。为什么用中位数而不是均值因为目标边缘和背景像素容易混入均值会被极端值拉偏中位数更稳健。4.3 目标框到距离的映射细节一个容易踩坑的细节是YOLOv5 检测出的是整个目标的包围框但这个框不完全属于目标本身——框边缘很可能包含背景。如果直接把框内所有视差像素拿来做平均远处的背景或者近处的遮挡物都会带偏结果。更合理的做法是提取框的中心区域比如中心 50% 的矩形或者按检测到的目标类别做进一步膨胀腐蚀操作保留主体区域后再取视差。另外检测框的坐标是基于校正后的图像还是原始图像这个映射关系要在代码里理清楚。我的实现顺序是先把原图做remap校正再把校正后的图同时送入 YOLOv5 检测和 SGBM 视差计算这样检测框坐标和视差图坐标就天然对齐了不需要额外做坐标变换逻辑上最省事。5. 常见问题与排查技巧实例5.1 环境与训练阶段的坑问题现象解决方法依赖包冲突import torch 报段错误锁定 numpy 1.23.5torch/torchvision 严格对应版本显存不足CUDA out of memory降低 batch-size或用--device 0 --workers 0减少数据加载开销训练 loss 降不下去mAP 卡在 0.3 左右优先检查标注框是否贴合目标、类别是否均衡导出 ONNX 失败算子不受支持降--opset到 11 或 12或换 torch 1.12检测精度高但测距抖动同一目标距离值跳变用中位数滤波 多帧均值或调大 SGBM 平滑参数这里面最有代表性的是“测距抖动”问题。我一开始单帧输出距离目标稍微移动一点检测框跟着晃动距离数值就上下跳。后来改成对近 10 帧的目标深度做滑动平均滤波稳定性改善明显实测距离误差从 ±8% 降到 ±4%。5.2 标定与实时性相关的经验标定重投影误差高于 0.1 像素怎么办通常是拍摄的标定板图像数量不足或角度变化不够。建议把标定板放在不同深度位置翻拍 20 张以上且每张的标定板倾角差异大一点覆盖画面的四角和中心。还有一个低成本优化技巧标定时固定相机位置不动只手动移动棋盘格这样标定出的外参会更稳定。实时性不达标怎么优化我遇到过在普通笔记本上整条链路只有 8 帧每秒的问题。逐段排查后确定瓶颈在 SGBM 的大搜索范围上。优化手段有三个一是缩小numDisparities从 128 降到 64深度范围从 15 米缩到 8 米以内近场景完全够用二是只对检测框内的区域做视差计算而不是全图计算速度提升立竿见影三是把输入分辨率从 1080p 降到 720p测距精度损失不大但速度能翻倍。6. 最后的个人经验沉淀我把这个项目从头跑通大概用了不到一周其中一半时间花在标定和参数调试上。最想分享的心得是不要试图第一次就把所有参数调到最优先把最简链路跑通再逐级优化。我第一版代码只实现了“单张图片 - 视差图 - YOLOv5 检测 - 输出距离”全程不用摄像头、不优化速度但保证每一环的结果都能可视化、可验证。链路通了以后再加上实时视频流、滤波、速度优化每加一层都能立刻看到效果变化排查问题也容易得多。最后分享一个小技巧写测距模块时一定要把中间结果可视化出来——左右校正图、视差图、深度图、检测框叠加图全部一个窗口一张图地显示。哪怕只是增加几个cv2.imshow调试效率都会提升一个量级。很多“看起来玄学”的误差问题实际上只要你盯着视差图看十秒钟就能发现是背景像素混进来了还是 SGBM 参数不匹配。项目做到最后真正帮助你解决问题的不是更高深的算法而是对中间过程的极致理解和对每个环节误差来源的清醒认识。本文还有配套的精品资源点击获取