免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

YOLOV5+双目相机实现三维测距:从标定到部署全流程解析

YOLOV5+双目相机实现三维测距:从标定到部署全流程解析 简介这是一份YOLOV5与双目相机结合的三维测距实现方案面向自动驾驶、机器人导航、无人机避障等场景的开发者提供从目标检测到深度估计的完整工程代码。资源共141个文件除核心Python源码外还包含40个yaml配置、11个yml环境文件、模型权重pt、演示视频mp4、Dockerfile及tutorial.ipynb教学脚本压缩包约40MB目录结构清晰。已有2417人学习下载。通过YOLOV5预处理提升立体匹配精度资源内含可直接运行的模型与样例图像可加载预训练权重实时识别目标并计算三维空间坐标配置文件与文档便于环境搭建和二次开发适合希望快速复现三维定位功能并将其迁移到实际项目的计算机视觉学习者与工程师。 把YOLOV5和双目相机放在一起做三维测距这件事在项目里远没有论文里看起来那么顺。我一开始以为无非是“检测框架加一个深度图”跑起来才发现从相机标定到坐标解算每一个环节都在给最终精度暗暗加杠杆。这篇文章就把我最近用新版本YOLOV5配合双目相机实现三维测距的整套流程写透包括原理、代码、标定细节和边缘设备部署踩坑适合正在做毕业设计、智能巡检、辅助驾驶仿真的朋友直接参考。这套方案能干什么先说清楚从双目相机实时视频流里检测出人、车、障碍物等目标同时输出每个目标相对相机的三维坐标和距离不依赖激光雷达几百块钱的硬件就能搭起一套验证原型。全文我会按“选型→标定→检测→解算→部署”的顺序拆开讲已经把各部分代码串通的朋友也可以直接跳到自己关心的环节。1. 方案选型双目相机和YOLOV5是怎么凑到一起的1.1 为什么不是单目也不是激光雷达先说结论单目测距便宜但精度不够激光雷达精度高但太贵双目相机正好卡在中间是教学项目、毕设和轻量工业场景里最合适的选择。单目相机测距通常依赖目标在地面上的投影或者目标真实尺寸的先验然后结合相机安装高度和俯仰角在几何上解出距离。问题在于这个模型对相机姿态特别敏感车辆一颠簸、坡道一变化测出来的距离就大幅度漂移而且不同类别物体的尺寸差异很大误差很难统一修正。做做demo没问题真用到任务里会让人抓狂我身边不止一个人被单目方案坑到换思路。激光雷达倒是精度好但十几线的工业雷达价格就够买好几套双目模组了。而且点云数据稀疏和图像融合需要额外做传感器联合标定对于毕业设计、课题研究或者小成本的巡检项目性价比根本谈不上。双目相机的底气来自视差它不是“猜”出来的而是用两只眼睛同时看到的细微差别算出来的这也正是双目测距原理和应用上最核心的部分。1.2 视差测距公式和它的精度“天花板”这里先给出整个系统最核心的公式Z (f * B) / dZ是目标到相机的深度距离f是相机焦距B是两台相机光心之间的距离也就是基线长度d是同一个三维点在左右两张图里成像位置的水平像素差叫视差。用人话解释你把两根手指放在眼前闭上一只眼换另一只眼手指会“跳”得很厉害这就是视差大说明手指离你近放到远处再换眼手指几乎不动这就是视差小说明物体远。双目相机就是把这个“跳”精准量化。在这个公式里f和B都是标定出来的固定值运行时唯一要算准的就是视差d。但它是个像素级别的量距离越远单位距离变化对应的视差变化就越小所以双目测距天然就是“近距离友好、远距离衰减”。这里有个很好用的精度估算方法。假设焦距f800像素基线B0.12米视差估计误差按0.5像素算那么在Z6米处dZ ≈ Z² / (f·B) × Δd 36 / (800×0.12) × 0.5 ≈ 0.19米动态误差在3%左右看起来还行。但如果把距离推到10米dZ ≈ 100 / (800×0.12) × 0.5 ≈ 0.52米误差已经超过5%这还是理想情况。所以设计系统时先根据你的最大测量距离反推焦距和基线别等做完才发现硬件根本不匹配。我用的模组基线是12cm配6mm镜头6米内误差能控制在5%以内超过8米就只能当参考数据。2. 做测距最容易被坑的一步双目标定与立体校正标定这件事说简单也简单说难也难。很多人的YOLO能跑、相机也能出图结果算出来的距离完全不着边际根本原因就是标定环节偷了懒。我在这里栽过跟头所以单独拿出来讲。2.1 双目标定和单目标定差在哪单目标定的目标是得到每个相机自己的内参和畸变系数。内参包括fx、fy、cx、cy畸变系数包含径向畸变k1、k2、k3和切向畸变p1、p2。双目相机除了这些还需要知道两个镜头之间的相对位姿也就是旋转矩阵R和平移向量T这一步在OpenCV里对应stereoCalibrate。如果只做两次单目标定就直接拿内参去算深度忽略了两个相机之间真实的外参那左右图在任何位置都严格对齐不了视差永远是错的。这是我调试时第一个优先核查的问题。很多教程只演示了单目标定新手跟着做完就以为万事大吉后面测距飘了也找不到原因。2.2 标定板采集的实操细节我用的是棋盘格标定板角点数是9x6格子边长25mm。棋盘格一定要打印出来贴在平整的亚克力板或硬纸板上边缘弯曲会直接引入全局畸变误差。采集左右图像对时至少拍15到20组每组里棋盘格要在画面中心、边缘、四角都出现并且倾斜角度差别大一点这样内参解算会更稳定尤其是径向畸变参数不容易被约束成错误值。几点我反复踩坑后总结出来的建议棋盘格在画面里的像素尺寸不要太小我一般让最短边占到画面的三分之一以上否则OpenCV检测角点会有跳变拍的时候固定相机、移动标定板而不是举着相机到处晃前者能明显减少运动模糊反光严重的环境压低曝光或者换哑光打印纸否则黑白格的对比度不够找角点会失败采集完先用代码把角点投影回原位看一遍明显对不齐的直接删掉不要指望标定算法能“自动救回来”。标定完成后看重投影误差RMSOpenCV一般会输出0.1到0.2像素之间超过0.3就代表数据质量有问题建议重新采图。别急着保存参数多标定两遍选RMS最低的一组。2.3 立体校正和SGBM参数调节拿到内参和R、T后还不能直接算视差。双目立体匹配有个理想前提叫极线约束也就是说左图某个点在右图中的对应点只可能出现在同一条水平线上。但两台相机物理上不可能做到完全平行所以要用stereoRectify和remap把左右图重投影成“行对准”状态这个操作叫立体校正。stereoRectify会生成左右两套映射表之后每一帧图像都要用remap做重映射。这步不是一次性的而是每帧都要执行会占一部分CPU时间预算够的话建议用CUDA版本remap省出来的时间很可观。立体校正完成后视差匹配我用的是OpenCV的StereoSGBM。参数里影响最大的几个numDisparities最大视差值必须能被16整除设太小会截断近处目标设太大会浪费时间blockSize匹配窗口大小小窗口细节多但噪点多大窗口平滑但边缘糊我常用5到11之间P1和P2平滑惩罚项控制边缘保留和噪声抑制的平衡P2一般是P1的4倍以上。这些参数没有通用标准必须结合现场画面调。我习惯写一个带滑块的小脚本实时看视差图效果比嘴里估参数靠谱得多。3. YOLOV5模型准备、训练与“检测框→深度”融合链路3.1 为什么还在选YOLOV5网络结构与版本选择提到YOLOV5网络结构它主要分三块主干网络CSPDarknet负责提取特征Neck部分用PANet做多尺度特征融合Head输出三个尺度的预测框分别对应大、中、小目标。和更新的YOLOv6、YOLOv8相比YOLOV5在推理速度上已经不是最快的那一档但它胜在生态成熟、资料全、部署方案多遇到问题一搜就有答案迁移学习权重也多。新版本YOLOV5在训练和导出工具链上做了不少优化比如更完善的自动锚框搜索、超参数进化、ONNX/TensorRT导出支持。这些对做项目的人来说比单看榜单精度更重要所以我最后还是选了YOLOV5。3.2 自己数据集的标注与训练要点用YOLOV5训练自己的数据集最核心的准备工作是三件事图片、txt标注文件、data.yaml。每张图片对应一个同名txt每行格式是“类别序号 归一化中心x 归一化中心y 归一化宽 归一化高”。data.yaml里写train和val路径、类别数量nc、类别名字names。训练前一定要检查自动锚框开关。YOLOV5默认会根据你的数据集重新聚类锚框但如果关闭了或者没触发迁移自COCO预训练权重时目标尺寸和COCO差异大就会收敛很慢。我刚开始做车辆检测时目标大而方忘了关默认配置结果训练日志里的anchor fitness偏低后来手动开启autoanchor才正常。训练命令大致是这样python train.py --img 640 --batch 16 --epochs 100 --data data.yaml --weights yolov5s.pt训练过程中不要只看loss曲线要多盯val集上的mAP。loss降到很低但mAP上不去通常意味着过拟合或者标注有错需要回头检查标签而不是盲目加epoch。3.3 检测框和深度图融合的实现现在到了核心环节。YOLOV5输出的检测框在左图上深度图里的每个像素代表那个位置的深度把两路数据对齐后就能从框里提取出目标距离。我的做法是校正后的左图直接送进YOLOV5深度图也以左图坐标系为准这样不需要做任何额外的坐标变换。实际操作分三步统一分辨率。YOLOV5推理输入和深度图分辨率必须一致我统一resize到640x480否则框坐标和深度图位置对不上。在检测框内取深度。不要直接取整个框的平均值框边缘很容易混入背景我用框中心向外收缩到宽高各60%的区域作为ROI。在ROI内取中位数而不是平均值。中位数对边缘误匹配产生的离群像素更不敏感实测下来距离输出稳定很多。融合代码核心就几十行def get_object_depth(depth, box): x1, y1, x2, y2 [int(v) for v in box] w, h x2 - x1, y2 - y1 cx, cy (x1 x2) // 2, (y1 y2) // 2 rw, rh int(w * 0.6), int(h * 0.6) roi_x1 max(0, cx - rw // 2) roi_y1 max(0, cy - rh // 2) roi_x2 min(depth.shape[1], cx rw // 2) roi_y2 min(depth.shape[0], cy rh // 2) roi depth[roi_y1:roi_y2, roi_x1:roi_x2] valid roi[roi 0] return float(np.median(valid)) if len(valid) else -1.0在整套融合链路里最容易出问题的就是“检测框和深度图没对齐”。如果两路分辨率不一致或者深度图在目标边缘有空洞提取出来的值就会一跳一跳。我建议在输出距离前再加一层滑动平均或卡尔曼滤波平滑效果对工程应用非常明显。4. 从像素坐标到真实世界坐标三维测距解算与误差控制4.1 目标中心三维坐标怎么换算用上面的方法只能得到距离Z。如果只是显示“目标距离3.2米”那已经够用但如果要让机械臂去抓、让车辆去避障就得把像素坐标转换成相机坐标系下的三维坐标。换算公式如下X (u - cx) * Z / fx Y (v - cy) * Z / fy Z 深度值这里u、v是目标中心点在左图上的像素坐标cx、cy、fx、fy是左相机内参。因为深度图本身就是左相机坐标系下的数据所以这套换算天然成立。如果机械臂或车辆需要的是世界坐标系坐标再在这个基础上乘一个外参矩阵也就是把相机坐标转到车体或机械臂基座标系的旋转和平移。这一步也经常有人漏掉。我见过不少人算出来的坐标看起来是合理的但接上下位机后乱跑最后发现少做了一个坐标系变换把相机坐标直接当世界坐标用了。4.2 误差来源排查表与实测表现我根据自己踩坑和排查的经验把双目测距的误差主要分成四类误差来源特点解决思路视差量化误差距离越远越明显近处不明显亚像素插值、更高分辨率相机标定误差全局固定偏移距离越远越放大重新采图标定RMS压到0.2以下遮挡和低纹理误匹配只出现在目标边缘或纯色区域用中心ROI和中位数过滤左右图像时间不同步动态目标距离抖动使用硬件同步双目或限制目标速度别看这些问题听着小积累起来会非常难受。我调过一个现象目标静止时距离稳定在5.0米轻微晃动一下计算结果跳到5.5米又跳回来。排查到最后发现是左右相机采集不同步两个摄像头拍帧的时刻相差了十几毫秒目标一晃动视差就变了。这种问题用软件很难完全消除选型时最好选择硬件同步的双目模组。4.3 新版本整条管线的运行表现我这一版的完整流程是读取双路画面 → 用双目标定参数remap校正 → SGBM得到视差图并转成深度图 → YOLOV5推理检测框 → 每个目标ROI提取距离和三维坐标 → 画框叠加显示。在1080p输入、YOLOV5推理640x480的情况下整体帧率大约在18到25fps之间。其中SGBM视差计算最费时间大概30msYOLOV5s推理大概20ms剩下的图像处理和IO差不多10ms。这个性能对大多数场景够用。如果对帧率有更高要求可以把SGBM放到GPU上跑或者缩小numDisparities范围。实测精度3米内误差小于3%6米在5%左右8米以上会到10%。如果你的任务要求几十米测距双目方案不合适那是激光雷达或毫米波雷达的主场。5. 边缘端部署与实测记录树莓派5和STM32协同方案5.1 YOLOV5与YOLOV6在树莓派上的速度对比热搜里常出现“yolov5 yolov26推理速度对比”我也在树莓派5上做了个简单实测。使用相同输入尺寸、CPU推理导出成ONNX后跑YOLOV5s大约40到55ms一帧YOLOV6s大约35到48ms一帧YOLOV6确实稍快一些但差距没有理论分析里那么夸张。在双目测距整套管线里SGBM和remap占的时间更稳定模型部分的差距对整体流畅度影响不大。我最终还是选YOLOV5因为它导出到ONNX、OpenVINO、TensorRT的支持更完整踩坑少对项目落地更友好。5.2 部署优化与超参数调整心得在树莓派5上部署建议直接用export.py把YOLOV5导出成ONNX再用ONNX Runtime做CPU推理不要直接跑PyTorch不然推理延迟会到几百毫秒完全没法实时。内存吃紧的话可以转成INT8量化精度会略有下降但边缘场景可接受。YOLOV5的超参数主要写在hyp.*.yaml里。影响比较大的几个lr0和lrf学习率设置不当会造成振荡或收敛慢默认值起步先跑50轮再观察mosaic和mixup数据增强能提升小目标效果但太强会让模型训练时间变长边缘端模型不用开满fl_gammafocal loss参数类别不均衡时调大一点有明显帮助anchor一定要让YOLOV5根据自己数据重新计算训练日志里输入自动锚框的相关提示别忽略。另外部署时输入尺寸我用640x480不是YOLO常配的640x640因为相机画面是4:3。分辨率长宽比不一致时模型要学额外的形变精度会受损失。输入尺寸和实际画面长宽比保持一致是我实测下来非常简单却有效的优化。5.3 车辆检测和车位管理系统的完整链路最后用一个实际案例来讲清楚整套架构。我把这套双目测距系统用在一个模拟停车场入口树莓派5负责接收双目画面检测车辆并测距测出车辆进入设定距离后通过串口把“有车辆/距离/目标ID”发消息给STM32STM32控制道闸和车位指示屏。协同链路是这样树莓派5YOLOV5 双目测距 → 串口协议 → STM32 → GPIO控制指示设备串口协议我按最简单的结构化方式写帧头 数据长度 指令 数据 CRC校验避免出现乱码和误触发。最关键的一点是只有连续5帧检测到同一目标且距离在阈值范围内才允许发“放行”指令否则单帧抖动也会导致闸机乱动。很多朋友在毕设里会想“STM32上直接跑YOLOV5”老实说这个方向非常吃力不讨好。STM32的算力和内存注定了它更适合做执行器和控制器而不是视觉推理端。正确的“眼脑分工”是视觉交给树莓派或上位机动作控制交给STM32两边用串口通信工程实现简单稳定性也好很多。如果你现在准备自己动手搭这套系统我的第一条经验是先去把双目模组固定牢固两个相机之间连1毫米的松动都会在视差计算里放大成几厘米的深度误差。我在调试中途换过支架来回拆装之后外参变了测距精度立刻下降重新标定才恢复这是最容易忽略但影响最大的工程问题。第二条经验是先把YOLOV5跑通再把双目深度图跑通最后才去考虑融合。分步验证虽然看起来慢但排查效率最高。等你看到画面上每个检测框下方都稳定显示“距离2.35 m”的时候前面遇到的所有坑都会变成很值得的经验。本文还有配套的精品资源点击获取
返回列表