这次我们来看一个很典型的「感知全链路」Demo:基于 YOLO26 的目标检测前端,再接上多目标跟踪、单目深度测距和速度估算,最终把检测、跟踪、测距、测速整合成一条可以直接跑视频的管线。
先说这类项目最值得关注的点:它不需要激光雷达、不需要双目相机、也不需要毫米波雷达。按照项目标题的定位,只要一路普通单目摄像头,就能输出目标类别、跟踪编号、距离和速度。对于智慧交通、车路协同、园区安防等场景的原型验证来说,这是一套低成本、容易复现的感知方案。
对读者而言,判断这个 Demo 值不值得下载,主要看三件事:
- 你是不是已经会跑 YOLO 检测,想进一步扩展跟踪和测速能力。
- 你手头有没有一块能跑 PyTorch 推理的 NVIDIA 显卡。纯 CPU 推理离线处理一段短视频可以,实时视频基本不现实。
- 你能不能接受单目方案在距离和速度上的固有误差。单目测距本质上是一个欠约束的几何反推问题,它给出的是估算值,不是雷达级的精确值。
这篇文章会从核心能力、技术方案、环境准备、部署启动、功能测试、接口与批量任务、资源占用、常见问题、最佳实践这几个角度拆解这条管线。
1. 核心能力速览
先看项目整体画像。由于不同仓库对 YOLO26 的实现细节可能不同,下面表格里的内容结合了项目标题、通用单目测距技术方案和 YOLO 生态的习惯做法,标注为「需确认」的地方请以你下载的仓库 README 和源码为准。
| 能力项 | 说明 |
|---|---|
| 项目定位 | 基于 YOLO26 的检测 + 多目标跟踪 + 单目测距 + 测速开源 Demo |
| 感知链路 | YOLO26 检测 → 多目标跟踪 → 单目深度测距 → 速度估算 |
| 核心输入 | 视频文件、摄像头视频流或单帧图像,以仓库参数为准 |
| 核心输出 | 标注视频、目标框 + Track ID + 距离 + 速度、结构化记录 |
| 传感器要求 | 单目摄像头即可,无激光雷达、毫米波雷达、双目相机要求 |
| 硬件推荐 | 有 NVIDIA GPU 的机器更合适;CPU 只适合离线验证或低分辨率测试 |
| 显存占用 | 需按权重版本、推理分辨率和实际视频测试,不预先下结论 |
| 启动方式 | 命令行为主;部分整合包会提供一键启动脚本,需看仓库 |
| API 能力 | 项目可能只给 Python 主流程,没有现成 HTTP 服务时需自行包一层 |
| 批量任务 | 如果 CLI 支持传视频目录或写循环脚本,可以批量跑 |
| 适合场景 | 道路车流统计、车路协同感知原型、园区安防监控、教学实验 |
| 使用边界 | 距离是估算值,测速结果不建议直接作为执法或事故认定依据 |
接下来要解释一个容易被忽略的点:这条链路的瓶颈通常不在 YOLO26 检测,而在跟踪和测距。检测只负责在单帧里找到目标;要让测距和测速有意义,必须有稳定的 Track ID,把同一辆车在不同帧里的位置关联起来。很多第一次跑通 Demo 的人发现测速波动很大,问题往往不是模型不够好,而是跟踪 ID 跳变或者测距几何参数没标定。
2. 适用场景与使用边界
2.1 这条 Demo 适合谁
最合适的用户是做智慧交通或城市感知原型验证的开发者。比如要在某个路口装一路固定摄像头,统计车流量、识别车辆类型、粗算经过车辆的相对速度,这类需求用单目方案就够了。固定视角摄像头是单目测距最友好的场景:相机高度、俯仰角、焦距都可以提前标定,目标在画面里的形态也相对稳定。
它也适合教学和课题实验。很多高校的计算机视觉课程或横向课题会涉及目标检测、多目标跟踪和单目深度估计,一条跑通的 Demo 能省去大量拼接模块的时间。你可以把 YOLO26 换成其他检测器,或把速度估计算法换成卡尔曼滤波,观测不同模块对整体效果的影响。
2.2 不适合什么场景
单目测距对快速横向移动目标不敏感。如果你关注的车辆是斜穿画面、横穿路口,甚至从正侧面经过,基于「目标与相机之间径向距离」的测速方法误差会非常大。更准确的做法是先把路面做逆透视变换,把目标脚点转换到俯视世界坐标,再计算真实位移。
纯 CPU 实时处理也不适合。YOLO26 这类检测网络本身就吃算力,再加上跟踪、测距和绘图,CPU 很难达到实时帧率。如果只有 CPU,建议把验证目标定为「离线跑通流程」而不是「实时视频流」。
2.3 合规与安全边界
这条 Demo 属于视觉监控类应用,使用前必须注意边界:
- 摄像头采集范围要经过场地管理者或个人信息主体同意,不要私自部署在非授权区域。
- 输出的监控视频如果包含清晰人脸或车牌,建议发布或存储前做模糊处理。
- 距离和速度数据不能直接作为交通执法、保险定责、事故鉴定的证据。测速类设备在法律上有计量认证要求,软件 Demo 只能作为参考。
- 不要将此类技术用于非法采集、跟踪个人或搭建未授权的监控系统。
这段话不是套话。公开一个带可运行代码的视觉测距测速 Demo,本身就是面向合法场景的技术分享,所以使用边界必须写清楚。
3. YOLO26 感知管线技术方案拆解
要把「检测 → 多目标跟踪 → 单目测距 → 速度估算」跑通,先理解每个模块在链路里的职责和数据流。下面按通用技术方案拆解,具体到仓库代码可能有差异。
3.1 检测模块:YOLO26 作为感知前端
YOLO26 是标题里给出的检测器版本。它在 YOLO 系列较新的框架基础上迭代,输出目标框、类别和置信度。在管线里它负责的是单帧感知:每一帧独立检测,不关心目标是不是上一帧出现过的同一个对象。
从工程角度看,检测模块第一个要确认的是权重语义。仓库使用的是 COCO 预训练权重,还是用交通数据集专门训练过的权重,会直接影响结果。COCO 类别里包含 person、car、truck、bus、motorcycle、bicycle,对交通场景相对够用;如果项目针对特定车辆类型做了自定义训练,则需要参考仓库提供的类别映射表。
检测端常见的坑有两个:一是置信度阈值设太低,大量误检框会干扰跟踪和测速;二是目标在远处只有十几个像素高时,检测框会一帧有一帧无,直接导致跟踪断链。建议先跑一段视频观察漏检率,再决定阈值。
3.2 多目标跟踪:给每个目标分配稳定编号
检测只能告诉你这一帧有什么,跟踪才能告诉你连续帧里谁是同一个目标。多目标跟踪模块负责维护 track ID,常见方案有 ByteTrack、BoT-SORT、DeepSORT 或者简化版的 IoU 匹配。
对单目测距和测速来说,跟踪结果至少要有两个信息:目标在每一帧的检测框,以及一个保持稳定的 ID。有了这条连续轨迹,才能把第 t 帧的距离和第 t+k 帧的距离配对成速度。
跟踪质量直接影响下游。如果两辆车交错时 ID 发生交换,后续测速会得到一条跳变的距离曲线,速度自然也会异常。如果目标被遮挡几帧后丢失,track 生命周期结束,重新出现又是一个新 ID,测速就无法累积。判断一个 Demo 适不适合你的场景,先看它的跟踪器在遮挡和交叉场景是否扛得住。
3.3 单目测距:从 2D 像素坐标反推 3D 距离
单目测距是整条管线最「反直觉」的一部分。单个摄像头成像时,物体离得越远,在图像里越小;但仅凭大小无法唯一确定距离,因为如果不知道真实尺寸,一个远处的大物体和一个近处的小物体可能成像完全相同。
因此工程实现的单目测距必须引入先验条件。常见方法有两种:
方法一,几何投影法。假设地面是平面,摄像头安装高度和俯仰角已知,利用目标检测框底部中心点在地面上的投影位置反推距离。对于道路固定摄像头,目标框的底边中心点通常视为车辆与地面的接触点。此时距离近似为:
D = h / tan(θ + atan((v - cy) / fy))其中 h 是相机高度,θ 是相机俯仰角,v 是接触点在图像中的行坐标,cy 是光心行坐标,fy 是焦距像素值。
这个方法的优点是稳定,缺点是对几何参数敏感。相机高度差了 20 厘米,远处目标的距离误差可能放大到几米;画面有坡度或路面不是平面,也会引入系统性偏差。
方法二,用单目深度估计模型得到逐像素深度图,再做尺度对齐。深度图给出的是相对深度关系,要得到以米为单位的距离,需要借助已知尺寸的参照物来反算尺度系数。这条路线的灵活性高,适合相机视角不固定、地面不规则的场景,但深度模型本身要额外消耗算力,尺度对齐如果做得不好,误差甚至比几何投影法更大。
具体仓库用的是哪种,要去看源码里测距部分的实现。不要只看 README 里贴的效果图,截图里的标注距离并不代表任意场景重现。
3.4 速度估算:距离差除以时间差
速度估算在拿到连续轨迹后才有意义。最简单的思路是:
v = (D(t2) - D(t1)) / (t2 - t1)这里的 D 是该目标在 t1、t2 时刻与相机之间的估计距离,速度正负表示接近或远离相机。
但单帧距离抖动很厉害。检测框略有变化、跟踪匹配略有偏移,都会让 D 出现波动。直接做差分会得到锯齿状的速度曲线。实际工程里通常要做三件事:
- 对距离序列做平滑,比如移动平均或卡尔曼滤波。
- 设置最短轨迹阈值,轨迹帧数太少不输出速度。
- 速度突变超过合理范围时丢弃该帧结果。
更严谨的道路测速还要求把轨迹映射到世界坐标系。如果目标沿着相机光轴方向运动,径向距离测速比较接近真实车速;如果目标斜穿或横穿画面,仅靠径向距离会严重低估车速。处理方法是对路面求单应矩阵,将目标脚点像素坐标转换到俯视世界坐标后再算位移。
4. 本地部署环境准备
下面给出通用准备清单。因为仓库没有提供官方实测环境记录,版本号不写死,建议以 PyTorch 和项目 requirements.txt 的实际约束为准。
4.1 硬件与软件清单
| 项目 | 建议 |
|---|---|
| 操作系统 | Windows 10/11 或 Ubuntu 20.04/22.04 |
| GPU | NVIDIA 显卡,显存越大越从容,具体占用需实测 |
| 驱动 | 最新 NVIDIA 驱动,确保能被 PyTorch 的 CUDA 识别 |
| CUDA | 以 PyTorch 对应版本为准,通常 CUDA 11.8 或 12.x |
| Python | 建议 3.9 - 3.11,先看 requirements.txt 是否限制版本 |
| 磁盘 | 至少预留 15-20GB,包含权重、测试视频和输出视频 |
| 摄像头参数 | 如果仓库要求配置相机高度、焦距、俯仰角,需要先测量 |
4.2 检查基础环境
先确认 Python 和 GPU 环境可用。打开终端,执行:
python --version nvidia-smi如果 nvidia-smi 能正常输出显卡信息,说明驱动没问题。接着确认 PyTorch 能调用 GPU:
python -c "import torch; print(torch.__version__, torch.cuda.is_available())"输出里torch.cuda.is_available()为True,说明 PyTorch 的 CUDA 环境可用。如果是False,不要急着开始跑项目,先把 PyTorch 版本与 CUDA 驱动之间的匹配关系处理好。
5. 安装部署与启动方式
开源 Demo 的部署通常就是三条路:git clone 仓库、安装依赖、下载权重并运行主脚本。因为无法确认具体仓库命令,下面给出通用模板,请把仓库地址、目录名、权重文件名替换成实际内容。
# 1. 克隆仓库 git clone <project-repo-url> cd <project-dir> # 2. 创建虚拟环境(推荐) python -m venv .venv # Windows 激活 .venv\Scripts\activate # Linux / macOS 激活 source .venv/bin/activate # 3. 安装依赖 pip install -r requirements.txt依赖安装完成后,下一步是准备权重。仓库可能提供下载脚本,也可能需要从 Release 页面手动下载:
# 如果仓库提供权重下载脚本 python scripts/download_weights.py # 手动下载时,把权重文件放到仓库指定目录,一般是 weights/ 或项目根目录 ls -lh weights/启动推理前,先查看主脚本支持哪些参数。很多仓库会提供--source、--weights、--device这类参数:
python main.py --help常见启动方式如下,参数名称必须按实际项目的 help 结果调整:
# 用 GPU 推理一段视频 python main.py --source demo.mp4 --device 0 # 指定配置文件 python main.py --config configs/traffic.yaml如果仓库恰好有基于 50 系显卡或老显卡适配的文档,优先按文档处理驱动和 PyTorch 版本。无论什么显卡,跑通之前先别追求实时。
管线类项目通常会有一个配置文件,集中管理检测器、跟踪器、测距和测速参数。以下是一个常见结构示例,真正的字段需要对照仓库源码修改:
# 配置文件模板,实际内容以仓库为准 detector: model_path: weights/yolo26s.pt # 权重文件放在实际路径 conf_thres: 0.25 img_size: 640 tracker: max_age: 30 # 目标丢失多少帧后销毁 track track_thresh: 0.5 range: camera_height_m: 6.0 # 相机离地高度 pitch_deg: 5.0 # 相机俯仰角 focal_px: 1200.0 # 以像素为单位的焦距,由标定获得 speed: smooth_window: 10 min_track_len: 5如果项目没有提供摄像头参数配置入口,也没有预设默认值,说明它可能只是一套「跑通演示数据」的 Demo。你要用自己的摄像头视频,就得自己补标定。
6. 功能测试与效果验证
部署完成的下一步不是调模型,而是设计一套验证流程,判断 Demo 到底跑没跑对。建议按下面顺序做。
6.1 端到端视频推理测试
测试目的是确认管线能否完整处理一段视频。建议准备一段固定视角的交通视频,分辨率 1280x720 左右,时长 30 秒到 1 分钟,画面里最好有两种运动模式:一个目标明显朝相机接近,另一个目标横向穿过画面。
操作步骤:
- 把视频放到项目输入目录。
- 运行主脚本,让推理结果保存为输出视频。
- 观察终端日志是否打印检测数量、跟踪 ID、距离和速度。
- 播放输出视频,检查画面里是否同时叠加 bounding box、ID、距离和速度文本。
判断成功的标准:检测框能稳定框住目标,Track ID 不是每个两三帧就换一次,目标接近相机时距离值单调变小,目标远离时距离值单调变大。
6.2 距离合理性测试
单目测距是否准确,需要用已知距离来验证。如果视频场景里有车道线、路灯杆等尺寸已知的参照物,可以先量出某个位置相对摄像头的真实距离,再对比 Demo 输出。
具体操作:截取目标出现在已知距离处的若干帧,记录 Demo 输出的距离估算值和真实距离,填写成一张对照表。
| 帧号 | 真实参考距离(米) | Demo 估算距离(米) | 偏差 |
|---|---|---|---|
| 示例 | 由车道标记量得 | 从画面标注读取 | 记录差值 |
如果近处偏差很小、远处偏差明显增大,这是单目方案的正常表现。不要因为远处误差去盲目调参,要先确认摄像头高度、俯仰角和焦距配置是否准确。
6.3 跟踪 ID 稳定性测试
跟踪质量直接影响测速。测试目标是观察目标交叉和遮挡时,ID 是否保持稳定。
测试方法:找一段有两辆车交会的视频,用带轨迹可视化效果的参数运行。常见做法是打开输出视频,看同一辆车在接近、交会、分离过程中 ID 是否一致。
如果 ID 在交会后交换,说明跟踪器的关联逻辑对遮挡场景处理不够好。如果目标短时间被遮住后重新出现变成新 ID,说明 max_age 参数太短或缺少目标重识别能力。
6.4 测速合理性测试
测速结果需要一个合理的置信区间。以普通乘用车和城市道路为例,如果是城市道路,常见区间在 20-60 km/h;高速道路在 60-120 km/h。Demo 输出的速度如果出现几百 km/h 的瞬间值,基本可以判断为跟踪跳变或距离平滑不足。
更严格的验证方法是用路面标记的长度作为真实参考。例如,在画面中用两处已知距离的地面标记做基准,观察车辆经过两个标记点的时间,反过来算参考速度,再与 Demo 输出对比。
判断标准:速度曲线经过平滑后,与参考速度偏差不超过可接受范围(例如 10%-15%)。如果偏差很大,第一步检查的是距离模块的标定参数,而不是急着换更大的 YOLO 权重。
7. 接口 API 与批量任务
这类感知 Demo 是否自带 HTTP 服务,完全取决于仓库实现。有的仓库只提供main.py,有的会额外提供server.py或api.py。动手改造前,先看仓库目录结构里有没有 FastAPI、Flask 依赖,以及 README 是否提到端口号。
7.1 如果仓库自带 API
启动 API 服务一般是运行一个 server 脚本。启动成功后,用 curl 测试:
curl -X POST http://127.0.0.1:8000/process \ -H "Content-Type: application/json" \ -d '{"source": "videos/car.mp4"}'请求参数和返回结构要以仓库接口文档为准。如果项目使用的是 WebUI 形态,比如 Gradio,那么调用往往是先启动 Web 页面,再通过页面传入视频文件。
7.2 如果仓库没有 API,如何自己包一层
没有 API 不代表不能集成。把项目核心入口整理成一个 Python 函数,再用 FastAPI 包一层即可。下面是通用包装思路:
from fastapi import FastAPI, BackgroundTasks from pydantic import BaseModel # 假设仓库核心入口是一个 process(source, output) 函数 # 实际模块名、函数名、参数以仓库源码为准 from pipeline import process app = FastAPI() class TaskRequest(BaseModel): source_path: str output_path: str = "outputs/result.mp4" @app.post("/process") async def submit_task(req: TaskRequest, background_tasks: BackgroundTasks): background_tasks.add_task(process, req.source_path, req.output_path) return {"status": "queued", "output": req.output_path}调用方继续用 curl 提交任务:
curl -X POST http://127.0.0.1:8000/process \ -H "Content-Type: application/json" \ -d '{"source_path": "videos/car.mp4", "output_path": "outputs/car_out.mp4"}'包装接口要注意两点:一是推理任务可能占用几十秒甚至几分钟,不要让 HTTP 请求同步阻塞,最好用后台任务加任务 ID 查询结果;二是对外提供服务时,只监听本机或内网地址,不要直接暴露到公网。
7.3 批量视频处理
如果仓库 CLI 支持--source指定输入文件,批量处理就可以直接写循环。以下模板可以快速处理一个目录下的所有视频:
mkdir -p outputs logs for video in videos/*.mp4; do echo "$(date) start $video" python main.py --source "$video" --output "outputs/$(basename "$video")" \ >> "logs/$(basename "$video").log" 2>&1 echo "$(date) finish $video" done批量处理建议不要一次性把所有任务丢进并行队列,尤其在显存有限的环境里。稳妥做法是逐条处理,每处理一个视频记录日志。日志里至少包含视频文件名、处理耗时、异常堆栈,方便中途失败后快速重跑失败项。
8. 资源占用与性能观察
视觉管线跑起来之后,第一步观察 GPU 显存和利用率。不要凭截图判断性能,要以本机实际监控为准。
8.1 怎么观察资源
最简单的 GPU 实时监控:
nvidia-smi -l 1也可以在 Python 脚本里打印当前显存占用:
import torch if torch.cuda.is_available(): device = torch.cuda.current_device() allocated = torch.cuda.memory_allocated(device) / 1024**3 reserved = torch.cuda.memory_reserved(device) / 1024**3 print(f"GPU {device}: allocated {allocated:.2f} GB, reserved {reserved:.2f} GB")8.2 影响性能的因素
这条管线里最消耗资源的部分通常是 YOLO 检测模型。影响速度的关键变量包括:
| 因素 | 影响方向 |
|---|---|
| 模型版本 | s/m/l/x 越大,精度越高,速度越慢 |
| 推理分辨率 | 640 比 1280 快很多,960/1280 会明显增加耗时 |
| 跟踪算法 | ByteTrack 类轻量跟踪额外开销不大,带 ReID 的跟踪会更耗时 |
| 深度估计方式 | 几何投影法几乎不额外耗算力,深度网络推理会明显增加显存 |
| 输出叠加 | 绘制轨迹、保存标注视频会占用 CPU 和磁盘,但不影响推理帧率 |
| Batch 大小 | 离线批量推理可以提高吞吐,但显存占用会上升 |
8.3 如何降低显存占用
如果自己的显卡跑不动,优先调整推理分辨率和模型尺寸,而不是换整个项目。先看主脚本是否支持--img-size,把分辨率从 1280 降到 640,速度通常能提升数倍。再看能否启用 FP16 半精度推理,大多数 YOLO 模型都支持。
测速不需要逐帧高密度处理。实际场景里,检测和跟踪可以跑 25 FPS,但速度计算完全可以从轨迹里每 0.2 秒或 0.5 秒取一个点,能有效降低单帧抖动带来的速度毛刺。
另外要注意,跑完一次推理后,如果反复卡死,可能是显存没释放或进程残留。结束程序后执行nvidia-smi,如果没有残留进程但显存占用很高,说明可能存在显存泄漏。排查时先重启进程,再检查模型加载是否重复执行。
9. 常见问题与排查方法
参考同类感知项目的排查经验,把最常见的坑整理成下表:
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| pip 安装依赖报 PyTorch/CUDA 版本冲突 | 环境里已有不同版本 PyTorch | 打印 torch 版本,检查 requirements 约束 | 新建虚拟环境,按项目要求重装 PyTorch |
| 找不到权重文件 | 权重未下载或路径错误 | 检查 weights 目录和日志报错路径 | 从 Release 页面下载对应权重 |
| torch.cuda.is_available() 返回 False | 驱动旧、PyTorch 与 CUDA 不匹配 | 跑 nvidia-smi 看 CUDA 版本 | 升级驱动或重装匹配的 PyTorch |
| 启动后帧率很低 | CPU 推理、分辨率过高、模型过大 | nvidia-smi 看 GPU 利用率 | 换小模型、降分辨率,或用 GPU 推理 |
| 距离显示在远处剧烈跳动 | 几何标定不准或检测框底边不稳定 | 输出检测框,看远处目标框是否抖动 | 调整置信度阈值,重新标定相机高度与俯仰 |
| Track ID 频繁变换 | 跟踪 max_age 太小、缺少 ReID | 观察遮挡或目标出画面场景 | 增大 max_age,检查跟踪器配置 |
| 两车交会后速度异常 | ID 交换或测速平滑不足 | 打开轨迹可视化 | 换更强的跟踪器,或对距离做卡尔曼滤波 |
| 输出视频打不开或编码失败 | OpenCV 编码器不支持该格式 | 检查日志中的 VideoWriter 报错 | 换 MP4V / avc1 编码参数 |
| 摄像头接入失败 | 设备索引错误或权限不足 | 用 OpenCV 单独测试摄像头 | 更换设备编号,检查摄像头占用 |
| API 只能本机访问 | 服务绑定在 127.0.0.1 | 查看服务监听地址 | 按需改为 0.0.0.0,并加防火墙和鉴权 |
下面展开两个常见问题。
第一个是依赖冲突。这类仓库的 requirements.txt 往往是按官方环境锁过版本的,不要用一套全局 Python 环境强行安装多个感知项目。实际解决方式就是为本项目单独创建虚拟环境,或者直接使用对应版本的 PyTorch 镜像容器。
第二个是测距远端的误差放大。目标距离越远,同一个像素偏移对应的世界距离越大。画面里 20 米处目标移动 1 个像素,可能只对应几厘米;到了 80 米处,1 个像素可能对应半米甚至更多。所以远端结果跳动远大于近端,这属于单目测距的固有问题,不是代码写错了。排查时将摄像头标定参数代入距离公式,先确认近处 10-20 米是否足够准。
10. 最佳实践与使用建议
这条管线要真正用起来,而不是停留在跑通 Demo 层面,建议遵守下面几条工程建议。
第一,先固定一套最小可运行配置。把输入视频、配置文件、权重路径都固定下来,任何改动都能回滚。YOLO 权重、配置文件、输出目录千万不能全部混在项目根目录里,建议用目录分隔。
第二,距离标定是最关键的一步。使用前至少要知道摄像头高度、俯仰角、焦距这三个参数。最稳妥的办法是拍摄一段包含已知长度参照物的地面视频,例如车道线或量尺,从画面中反推配置。不要直接照抄 README 里的摄像头参数,那是别人的场景。
第三,测速前先确认运动方向。如果要测的是沿道路方向的速度,建议对地面求单应矩阵,做逆透视变换。下面是通用俯视映射代码思路:
import cv2 import numpy as np # 在画面中选择至少 4 个地面参考点,例如车道线角点 # 注意:对应世界坐标需要实际测量 src_points = np.array([[200, 400], [600, 400], [900, 700], [300, 700]], dtype=np.float32) dst_points = np.array([[0, 0], [10, 0], [10, 20], [0, 20]], dtype=np.float32) # 单位:米 homography = cv2.getPerspectiveTransform(src_points, dst_points) # 将检测框底部中心点转换到俯视世界坐标 point = np.array([[[x_center, y_bottom]]], dtype=np.float32) world_point = cv2.perspectiveTransform(point, homography)[0][0] print(world_point)之后用俯视世界坐标位移除以时间差,得到的就是接近真实道路方向的速度,比直接计算径向距离可靠。
第四,批量任务必须加日志和失败重试。处理几十个视频时中途失败是常态,建议每个视频独立日志,失败后能定位到具体文件,重跑时只跑失败项。
第五,涉及真实道路、车辆、行人的素材时,务必确认数据获取和发布授权。公开 Demo 演示请避免出现完整车牌和清晰人脸,必要时做模糊处理。
11. 总结与下一步
这个项目的价值在于把 YOLO26 检测、多目标跟踪、单目测距和测速串成一条完整链路,适合作为交通感知原型或视觉课程实验的起点。拿到代码后,最先验证的应该是端到端视频推理,其次是近处目标的距离合理性,第三步才是测试速度是否稳定。
最容易踩的坑有三个:依赖环境没隔离导致 PyTorch 跑不通、忽略摄像头几何标定导致距离误差被错误归因于模型、跟踪 ID 不稳定却去硬调测速参数。这三个问题在单目测距测速类项目里几乎都会遇到。
跑通之后,值得继续扩展的方向包括:把跟踪器换成带 ReID 的版本以提升遮挡场景表现,把 YOLO26 导出为 TensorRT 以提升运行速度,整合逆透视变换来做沿道路方向的精确速度估算,或者加上一段简单的 HTTP 服务和批量调度脚本,把离线 Demo 变成可对接其他系统的感知模块。
一句话收尾:先别追求高精度,把「检测 → 跟踪 → 测距 → 测速」这条链路用固定场景跑稳,后续再逐步替换模块,这是这类开源 Demo 最合理的上手路径。