news 2026/10/1 8:54:15

基于YOLOv7与Deepsort的智慧交通系统实战:从检测跟踪到车辆计数

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于YOLOv7与Deepsort的智慧交通系统实战:从检测跟踪到车辆计数

简介:这份资源面向人工智能与智慧交通方向的课程学习者、项目实践者及算法入门者,围绕基于YOLOv7与Deepsort的智慧交通系统展开,可用于交通目标检测、车辆行人多目标跟踪等典型场景的复现与二次开发。压缩包共17个文件,以15张png与1张jpeg图片为主,辅以1个py脚本,整体约8.15MB,图片多用于展示检测跟踪效果与运行截图,脚本则承担目录遍历等辅助功能,便于快速了解项目结构与视觉结果。目前已有213人学习下载,具备一定参考热度。读者可借助该资源理解YOLOv7检测与Deepsort跟踪的协同流程,结合配套教程梳理从环境配置到结果可视化的完整思路,并参考效果图排查常见问题,适合作为智慧交通课程设计或项目实践的起步素材。

1. 智慧交通项目拆包:YOLOv7 加 Deepsort 这套源码到底能跑出什么

路上跑的车一多,做视觉的人就绕不开两个词:检测和跟踪。检测负责把画面里的车、人、交通标志框出来,跟踪负责给每个框发一个稳定的 ID,让它在连续帧里不跳号。这套「人工智能-项目实践-智慧交通-基于YOLOv7和Deepsort的智慧交通系统」源码包,干的就是把这两件事串成一条能落地的流水线:YOLOv7 出检测框,Deepsort 接框做轨迹关联,最后落到交通流量统计、车辆计数、轨迹绘制这些具体场景上。它适合正在做课程设计、毕设或者想快速搭一个交通视频分析原型的同学,也适合手里有路口摄像头数据、想先跑通再谈优化的工程师。包里除了源码和教程,还带了一批效果截图和listdir.py这类辅助脚本,说明作者是把自己调试过程里的中间产物一起打包了,这种包通常比纯代码仓库更好复现,因为你能对着图判断自己跑出来的结果对不对。

2. YOLOv7 与 Deepsort 的选型逻辑:为什么不是 YOLOv5 配 Sort

2.1 检测器选 YOLOv7 的实际理由

YOLO 系列到 v7 这一代,在速度和精度的平衡上做了一个比较讨巧的设计:它引入了 E-ELAN 结构,在不破坏梯度路径的前提下堆叠了更多特征通道,同时用辅助训练头(aux head)在训练阶段提升召回,推理阶段再把辅助头砍掉,保证速度。对智慧交通这种场景,路口画面里小车、公交车、电动车尺度差异大,YOLOv7 的多尺度检测头比早期版本更稳。源码里如果用的是官方yolov7.pt权重,COCO 预训练里本来就包含 car、bus、truck、person 这些交通高频类别,直接拿来推理就能出框,不需要你从零训。常见做法是先用预训练权重跑通,再拿自己路口的数据做微调,这样能省掉大量标注成本。

2.2 Deepsort 相比 Sort 的改进点

Sort 只用了卡尔曼滤波加匈牙利匹配,靠 IOU 做关联,车一遮挡或者检测框抖一下,ID 就断了。Deepsort 在 Sort 基础上加了一个 ReID(重识别)特征提取网络,把每个检测框的外观特征存下来,匹配的时候同时看运动信息和外观相似度。交通场景里车被前车挡住两三秒再出来,Sort 基本会分配新 ID,Deepsort 因为外观特征还在,能把 ID 接回去。代价是每帧要多跑一次特征提取,速度会掉一些,但对交通计数这种要求 ID 稳定的任务,这个代价值得。源码把 Deepsort 的deep_sort_pytorch部分单独放出来,说明作者也是按这个思路组织的。

2.3 环境搭建与依赖安装

跑这套东西第一步是把环境对齐。YOLOv7 官方要求 PyTorch 1.7 以上,Deepsort 部分依赖torchreid和opencv-python。我一般会先建一个干净的 conda 环境,避免和系统里的包打架。

# 创建独立环境,python 版本建议 3.8 或 3.9 conda create -n traffic python=3.9 -y conda activate traffic # 安装 pytorch,按自己显卡的 cuda 版本选,这里以 cu118 为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 安装项目其余依赖 pip install opencv-python numpy scipy pillow tqdm pyyaml pip install torchreid

这段命令的逻辑是:先隔离环境,再装框架,最后补视觉和跟踪需要的库。参数上要注意--index-url后面的 cuda 版本必须和你nvidia-smi看到的驱动匹配,装错了会出现torch.cuda.is_available()返回 False 的情况。torchreid是 Deepsort 提取外观特征用的,如果装不上,检查一下 pip 源,有些镜像里这个包版本很旧。

2.4 权重文件与目录结构确认

源码包里通常不会带yolov7.pt这种大权重,需要你自己下。下载后放到项目根目录,和detect.py、deepsort文件夹同级。目录结构大致是:

路径作用
yolov7.pt检测模型权重
deep_sort_pytorch/Deepsort 跟踪代码与 ReID 权重
inference/推理入口脚本
listdir.py批量列出目录文件的辅助脚本
*.png / *.jpeg作者调试时的效果截图

listdir.py这种脚本别小看,它一般用来批量读取视频或图片列表,跑批量测试的时候能省事。先确认deep_sort_pytorch里的 ReID 权重(通常是ckpt.t7)在不在,不在的话跟踪部分会直接报错退出。

3. 从视频到轨迹:推理脚本的参数与运行步骤

3.1 推理主流程拆解

整个推理链路是:读一帧 → YOLOv7 检测 → 检测框送 Deepsort → Deepsort 输出带 ID 的轨迹 → 画框画线 → 写输出视频。源码里一般会有一个类似detect.py或inference.py的入口,核心逻辑集中在循环里。下面这段是这类项目里最常见的推理骨架,我按可复现的方式写出来:

import cv2 import torch from models.experimental import attempt_load from utils.datasets import letterbox from deep_sort_pytorch.utils.parser import get_config from deep_sort_pytorch.deep_sort import DeepSort # 加载 YOLOv7 权重,map_location 保证没显卡时也能跑 model = attempt_load('yolov7.pt', map_location='cpu') model.eval() # 初始化 Deepsort,配置文件里管 max_dist、max_iou_distance 这些阈值 cfg = get_config() cfg.merge_from_file('deep_sort_pytorch/configs/deep_sort.yaml') deepsort = DeepSort( cfg.DEEPSORT.REID_CKPT, max_dist=cfg.DEEPSORT.MAX_DIST, min_confidence=cfg.DEEPSORT.MIN_CONFIDENCE, nms_max_overlap=cfg.DEEPSORT.NMS_MAX_OVERLAP, max_iou_distance=cfg.DEEPSORT.MAX_IOU_DISTANCE, max_age=cfg.DEEPSORT.MAX_AGE, n_init=cfg.DEEPSORT.N_INIT, nn_budget=cfg.DEEPSORT.NN_BUDGET, use_cuda=torch.cuda.is_available() ) cap = cv2.VideoCapture('test.mp4') while cap.isOpened(): ret, frame = cap.read() if not ret: break # letterbox 保持长宽比缩放,避免检测框变形 img = letterbox(frame, 640, stride=32)[0] img = img[:, :, ::-1].transpose(2, 0, 1) # BGR 转 RGB 再转 CHW img = torch.from_numpy(img.copy()).float().div(255.0).unsqueeze(0) with torch.no_grad(): pred = model(img)[0] # 这里省略 NMS 和坐标还原,实际脚本里用 non_max_suppression 处理 # 假设 detections 是 [x1,y1,x2,y2,conf,cls] 的列表 outputs = deepsort.update(detections, frame) for x1, y1, x2, y2, track_id in outputs: cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(frame, f'ID {track_id}', (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) cv2.imshow('traffic', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows()

逻辑上分四段:模型加载、跟踪器初始化、逐帧推理、结果绘制。参数里最影响效果的是max_dist和max_age。max_dist控制外观特征匹配的距离阈值,调大更容易把同一辆车关联上,但太大容易串 ID;max_age是轨迹丢失后保留多少帧,交通场景里遮挡常见,这个值一般设 30 到 70 之间。min_confidence低于阈值的检测框直接丢掉,能减少误检带来的假轨迹。

3.2 关键参数怎么调

Deepsort 的配置文件deep_sort.yaml里几个参数值得单独说:

参数含义交通场景建议
MAX_DIST外观特征最大余弦距离0.2 左右,太大易串 ID
MIN_CONFIDENCE检测置信度下限0.5 起步,误检多就提到 0.6
MAX_IOU_DISTANCEIOU 匹配阈值0.7,遮挡多可降到 0.6
MAX_AGE轨迹最大存活帧数30~70,按帧率调
N_INIT确认轨迹所需连续命中数3,太小会出假轨迹

调参的顺序建议是:先固定检测置信度,把误检压下去;再调MAX_AGE解决遮挡断 ID;最后微调MAX_DIST。不要一上来就全改,否则出了问题根本不知道是哪个参数导致的。

3.3 批量处理与结果输出

单视频跑通后,通常要批量处理。listdir.py这类脚本就是干这个的,它把目录下的视频或图片列出来,喂给推理函数。批量跑的时候注意输出目录要提前建好,OpenCV 的VideoWriter不会自动创建路径,路径不存在会静默失败,写出来的视频是 0 字节。编码器选mp4v兼容性最好,想压得小一点可以用XVID配.avi后缀。

4. 避坑与排查:这套源码最容易翻车的五个地方

4.1 现象:跟踪 ID 频繁跳变,同一辆车换好几个号

原因:Deepsort 的外观特征提取没生效,或者MAX_DIST设得过大,匹配时几乎只看运动信息。也可能是检测框抖动太厉害,IOU 匹配阶段就不稳定。

解决:先确认ckpt.t7权重加载成功,打印一下特征维度;再把MAX_DIST从默认值往下调,交通场景 0.2 附近比较稳;如果检测框抖,检查 YOLOv7 的输入尺寸是不是太小,640 不够就上 1280,但速度会掉。

4.2 现象:运行报CUDA out of memory

原因:YOLOv7 加 Deepsort 的 ReID 网络同时占显存,批量推理时如果一次塞多帧或者输入分辨率太高,显存直接爆。

解决:把输入尺寸降到 640,推理时用torch.no_grad()包住,批量大小设 1。显存实在小就map_location='cpu'跑,速度慢但能出结果。另外检查有没有残留的 python 进程占着显存,nvidia-smi看一眼,有僵尸进程就 kill 掉。

4.3 现象:视频写出来是 0 字节或者打不开

原因:VideoWriter的路径目录不存在,或者编码器与文件后缀不匹配,比如用mp4v却写.avi。

解决:写之前用os.makedirs确保目录存在;编码器和后缀对齐,mp4v配.mp4,XVID配.avi;帧尺寸要和VideoWriter初始化时传的尺寸一致,不一致也会写失败。

4.4 现象:检测框位置整体偏移

原因:letterbox 缩放后坐标还原时忘了减 padding,或者缩放比例算错。这是 YOLO 系列里最经典的坑。

解决:还原坐标时严格按(x - pad_x) / scale来算,pad_x和pad_y是 letterbox 补的边。建议把还原逻辑单独写成一个函数,输入原始尺寸和缩放参数,输出还原后的框,方便单测。

4.5 现象:ReID 权重加载报 key 不匹配

原因:torchreid版本和权重训练时的版本不一致,state_dict 的 key 名字对不上。

解决:用strict=False加载,跳过不匹配的层,但要注意跳过的如果是关键层,特征质量会下降。更稳的做法是对齐torchreid版本,源码教程里一般会写推荐版本,照着装。

5. 进阶玩法:把计数逻辑接进跟踪结果

跑通推理只是第一步,智慧交通真正要的是统计数字。基于 Deepsort 输出的轨迹 ID,可以做车辆计数、流量统计、甚至简单的违章判断。核心思路是画一条虚拟线,轨迹 ID 从线的一侧穿到另一侧就计一次数,同时用一个集合记录已经计过的 ID,避免同一辆车来回穿被重复统计。

counted_ids = set() total_count = 0 line_y = 400 # 虚拟计数线的纵坐标 for x1, y1, x2, y2, track_id in outputs: center_y = (y1 + y2) // 2 # 轨迹中心越过计数线且该 ID 没计过 if center_y > line_y and track_id not in counted_ids: counted_ids.add(track_id) total_count += 1 cv2.line(frame, (0, line_y), (frame.shape[1], line_y), (0, 0, 255), 2) cv2.putText(frame, f'Count: {total_count}', (20, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)

这段逻辑里counted_ids是关键,没有它同一辆车会被反复计数。line_y要根据你的摄像头视角调,一般选画面中下部,因为车在远处太小、检测不稳,靠近画面底部时框最完整。方向判断可以再加一层:记录轨迹上一帧的中心位置,和当前帧比较,只有从下往上或从上往下单向穿越才计数,这样能区分车道方向。

验证计数准不准,我一般会拿一段已知车辆数的视频跑,人工数一遍和程序输出对比,误差在 5% 以内算可用。误差大就检查是不是有车在计数线附近来回抖动导致重复计,或者MAX_AGE太小导致轨迹断裂、同一辆车被当成两辆。还有个细节:公交车和卡车这种长车,中心点穿越线的时刻和小车不一样,如果场景里大车多,可以考虑用框的底部而不是中心点来判断。

从那以后我每次接跟踪类项目,都会先把虚拟线和计数逻辑单独跑一遍,确认 ID 稳定了再往上叠业务,不然统计数字全是玄学。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 8:54:14

Kaggle GPU环境原理与PyTorch CUDA兼容性实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/1 8:53:48

ESP32-P4实战ROS2小车:蓝牙遥控、温度采集与OTA升级全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/1 8:53:37

AIO Sandbox:全功能集成开发沙箱架构与实战指南

1. 项目概述:为什么需要一个“全功能集成沙箱”?AIO Sandbox 这个名字里的“AIO”不是“人工智能优化”,也不是“高级输入输出”,而是All-in-One——字面意思,把所有开发、调试、分析、交互场景塞进同一个容器里。我第…

作者头像 李华
网站建设 2026/10/1 8:50:13

马德拉自由行全攻略:8天7夜徒步路线、自驾住宿与美食避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华