
简介这份资源围绕 YOLOv5、DeepSORT 与 FastReID 的组合方案展开对视频行人多目标跟踪MOT和行人重识别ReID特征提取代码进行了重构并配套接口源码与详细文档面向计算机、人工智能、通信、自动化等专业的学生、教师及企业开发者可用于毕业设计、课程设计、项目立项演示或算法进阶学习。压缩包共 37 个文件以 31 个 Python 脚本为主体辅以 2 个 yaml 配置、2 个 txt 说明、1 个 md 文档及 gitignore整体约 38KB目录涵盖 mot-main、src、configs、models 等模块结构清晰便于按功能检索。项目为个人高分作品已通过导师指导与答辩评审代码经测试可正常运行。读者可据此理解检测、跟踪与特征提取的串联逻辑掌握 deep_reid 等关键实现并在此基础上修改扩展功能。目前已有 85 人学习关注。1. 从一段路口监控说起这套 YOLOv5DeepSORTFastReID 源码到底能干什么上个月帮朋友处理一段园区路口监控需求很朴素把画面里每个行人框出来、给个稳定 ID、跨镜头再认一次。我一开始想拿现成检测模型加个简单跟踪凑合结果行人互相遮挡两次 ID 就串了跨镜头更是完全对不上。翻了一圈最后落到这套基于 YOLOv5 DeepSORT FastReID 的重构源码上它把视频行人 MOT多目标跟踪和 ReID行人重识别特征提取的代码、接口、文档打包在一起省掉了我自己拼装三个仓库的功夫。这套东西适合两类人一类是想跑通行人跟踪跨镜重认完整链路的算法工程师另一类是要拿它当毕设或项目底座的学生。它解决的不是检测准不准这一个点而是检测→跟踪→特征→再认整条链路怎么接、接口怎么留、参数怎么调。下面我按自己拆包复现的顺序把能抄的步骤和踩过的坑都摊开讲。2. 拆开源码包先看结构三个模块怎么串成一条链路2.1 YOLOv5 负责检测DeepSORT 负责轨迹FastReID 负责身份先把三个模块的职责分清楚不然后面调参就是盲调。YOLOv5 是检测器输入一帧图像输出一堆[x1,y1,x2,y2,conf,cls]的框它只告诉你这一帧哪里有行人不关心上一帧那个人是谁。DeepSORT 是跟踪器它拿检测框和上一帧的轨迹做匹配匹配靠两部分运动信息卡尔曼滤波预测的位置和外观信息ReID 特征。这里就是关键——DeepSORT 原版自带一个小的 ReID 网络但精度一般这套源码把它换成了 FastReID用更强的特征来算外观相似度遮挡和交叉场景下 ID 切换会明显少。FastReID 是独立的行人重识别库输入一张行人裁剪图输出一个固定维度的特征向量常见 2048 维或 512 维两张图的特征做余弦距离就能判断是不是同一个人。所以整条链路是YOLOv5 出框 → 裁剪行人图 → FastReID 提特征 → DeepSORT 用特征运动做匹配 → 输出带 ID 的轨迹 → 跨镜头时用 FastReID 特征库做检索再认。理解这个数据流你才知道每个配置文件在改什么。常见做法是把三个模块的权重分开管理检测权重、ReID 权重、跟踪配置各放一处别混在一个目录里否则换模型时容易加载错。2.2 目录结构和关键文件定位解压后一般能看到类似这样的结构不同重构版本命名略有差异以你拿到的为准project/ ├── yolov5/ # 检测模块 │ ├── weights/ # 检测权重 .pt │ ├── models/ # 网络结构 yaml │ └── detect.py # 单帧/视频检测入口 ├── deepsort/ # 跟踪模块 │ ├── configs/ # 跟踪参数 yaml │ ├── deep_sort/ # 核心跟踪逻辑 │ └── tracker.py # 跟踪器封装 ├── fastreid/ # 重识别模块 │ ├── configs/ # ReID 模型配置 │ ├── weights/ # ReID 权重 │ └── demo.py # 特征提取入口 ├── interface/ # 对外接口封装 │ ├── mot_api.py # 跟踪接口 │ └── reid_api.py # 特征提取接口 └── docs/ # 详细文档重点看interface/目录这是重构版的价值所在——它把三个模块包成了可调用的接口你不用每次去改detect.py的main。mot_api.py一般暴露一个输入视频路径或帧输出带 track_id 的结果的函数reid_api.py暴露输入行人图输出特征向量的函数。先读这两个文件的函数签名比读文档快。2.3 环境依赖和权重放置环境这块YOLOv5 对 PyTorch 和 CUDA 版本敏感FastReID 又依赖一堆faiss、torchreid之类的库版本冲突是第一个坑。我一般用 conda 单独建环境conda create -n mot_reid python3.8 -y conda activate mot_reid # 先装 pytorch版本按你显卡 CUDA 选这里以 cu113 为例 pip install torch1.12.1cu113 torchvision0.13.1cu113 -f https://download.pytorch.org/whl/torch_stable.html # 再装检测和跟踪依赖 pip install -r yolov5/requirements.txt pip install -r deepsort/requirements.txt # FastReID 依赖单独装注意 faiss 版本 pip install faiss-gpu1.7.2 pip install -r fastreid/requirements.txt参数说明python3.8是这套组合比较稳的版本3.10 以上有些旧依赖会编译失败faiss-gpu如果没 GPU 就换faiss-cpu。权重放置按文档说明检测权重放yolov5/weights/ReID 权重放fastreid/weights/路径在配置 yaml 里对应改。装完先跑一个官方给的 demo 脚本验证环境别急着上自己的视频。3. 跑通 MOT从视频输入到带 ID 的轨迹输出3.1 检测跟踪的串联调用跑通 MOT 的核心是把检测结果喂给跟踪器。重构版一般提供了封装好的接口我按常见调用方式写一段from interface.mot_api import MOTTracker # 初始化跟踪器指定检测权重、ReID权重、跟踪配置 tracker MOTTracker( det_weightsyolov5/weights/yolov5s.pt, reid_weightsfastreid/weights/reid.pth, track_configdeepsort/configs/deepsort.yaml, conf_thres0.4, # 检测置信度阈值 iou_thres0.5, # NMS 的 IoU 阈值 devicecuda:0 ) # 输入视频输出带 track_id 的结果 results tracker.track_video( video_pathtest.mp4, save_pathoutput.mp4, showFalse )逻辑说明MOTTracker内部先调 YOLOv5 做单帧检测拿到行人框后按框裁剪出小图批量送进 FastReID 提特征再把框特征交给 DeepSORT 的update做匹配。conf_thres调低会召回更多框但误检增多跟踪容易断调高漏检增多轨迹容易丢。iou_thres影响 NMS行人密集时调低一点能减少框被合并。device按实际显卡改没卡就cpu但速度会慢很多。3.2 关键参数跟踪器里那几个决定 ID 稳不稳的阈值DeepSORT 的配置文件里有几个参数直接决定 ID 切换频率我列个表对照着调参数含义调大后果调小后果max_dist外观特征匹配最大余弦距离匹配宽松易串 ID匹配严格易丢轨迹max_iou_distance运动匹配最大 IoU 距离运动匹配宽松运动匹配严格max_age轨迹丢失后保留帧数遮挡后易恢复同一 ID遮挡后易新建 IDn_init确认轨迹所需连续命中帧数确认慢抗误检强确认快易被误检带偏血泪经验max_dist和max_age是一对遮挡场景下max_age给到 30~50 帧、max_dist给到 0.2~0.3 比较稳。但如果你换的 FastReID 权重特征维度或归一化方式不同max_dist的合适区间会变得重新试。别照抄别人的数值先跑一段自己的视频看 ID 切换次数。3.3 用 MOT 指标验证跟踪质量跑完不能只看视频顺不顺眼要用指标说话。MOT 常用 MOTA、IDF1、ID Switches 这几个。源码文档里一般会说明怎么在 MOT 数据集上评测常见做法是先把结果存成标准格式每行frame,id,x,y,w,h,conf,-1,-1,-1再用评测脚本算# 假设结果存为 results.txt标注在 gt.txt python deepsort/tools/eval_mot.py \ --gt gt.txt \ --result results.txt \ --metrics MOTA IDF1 IDS逻辑说明--gt是标注文件--result是你的跟踪输出--metrics指定要算的指标。MOTA 综合了漏检、误检、ID 切换IDF1 更侧重 ID 保持一致性。行人场景我一般重点看 IDF1 和 IDS因为 MOTA 对检测质量太敏感检测一差 MOTA 就难看但不代表跟踪逻辑有问题。跑评测前确认帧号和 ID 编号对齐格式错一位结果全废这是最常见的翻车点。4. 跑通 ReID特征提取、特征库和跨镜检索4.1 FastReID 特征提取接口怎么调ReID 这块重构版把 FastReID 包成了接口输入行人图输出特征向量from interface.reid_api import ReIDExtractor import cv2 extractor ReIDExtractor( weightsfastreid/weights/reid.pth, configfastreid/configs/reid.yaml, devicecuda:0 ) # 读一张行人裁剪图 img cv2.imread(person_crop.jpg) feat extractor.extract(img) # 返回归一化后的特征向量 print(feat.shape) # 例如 (2048,)逻辑说明extract内部做了 resize、归一化、送网络前向、L2 归一化几步。返回的特征已经归一化所以两张图相似度直接点积就是余弦相似度。config里定义了输入尺寸常见 256x128和特征维度换权重时 config 要跟着换否则维度对不上会报错。批量提取时别一张张调接口一般支持传 list批量走 GPU 利用率高很多。4.2 建特征库做跨镜检索跨镜头再认的本质是把 A 镜头里某个人的特征存进库在 B 镜头里提特征去检索最相似的。常见做法是用 faiss 建索引import faiss import numpy as np # 假设 gallery_feats 是 N 张底库图的特征N x 2048 gallery_feats np.load(gallery_feats.npy).astype(float32) faiss.normalize_L2(gallery_feats) # 建内积索引归一化后内积等价余弦相似度 index faiss.IndexFlatIP(gallery_feats.shape[1]) index.add(gallery_feats) # 查询query_feat 是待检索特征 query_feat extractor.extract(query_img).astype(float32).reshape(1, -1) faiss.normalize_L2(query_feat) sims, ids index.search(query_feat, k5) # 返回 top5 print(sims, ids)参数说明IndexFlatIP是精确检索底库小几千张够用底库上万张换IndexIVFFlat加速但要先训练。k5是返回最相似的 5 个实际判定是不是同一人还要设个相似度阈值比如余弦大于 0.6 才认。这个阈值跟你的 ReID 模型和数据集强相关别拍脑袋定拿一批有标注的 pair 画个相似度分布再定。4.3 ReID 数据集和评测想验证 ReID 效果得用标准数据集。Market1501、DukeMTMC、MSMT17 是常用的源码文档里一般会写支持哪个。评测看 mAP 和 Rank-1python fastreid/tools/eval.py \ --config fastreid/configs/reid.yaml \ --dataset market1501 \ --data-root /path/to/market1501逻辑说明--dataset指定数据集名--data-root是数据根目录。Rank-1 是首位命中率mAP 综合了所有正确匹配的排序质量。注意数据集划分要用官方的 query/gallery 划分自己乱切结果没可比性。如果 mAP 明显低于文档给的参考值先查输入尺寸和归一化参数是不是跟训练时一致这是最常见的精度掉点原因。5. 避坑排查这套源码我踩过的五个坑5.1 现象跟踪 ID 频繁切换画面里同一个人几帧换个号原因多半是 ReID 特征没起作用。要么 FastReID 权重没加载成功静默失败用了随机初始化要么max_dist设太大导致外观匹配形同虚设要么裁剪的行人图尺寸和 ReID 训练输入不一致特征质量差。解决先在reid_api里打印特征确认不是全零或全相同再检查权重路径和 config 是否匹配然后把max_dist从 0.3 往下调到 0.15 试。裁剪图 resize 那步要跟 ReID config 里的输入尺寸严格一致差一点精度就掉。5.2 现象检测框正常但跟踪器不输出任何轨迹原因n_init设太大轨迹还没确认视频就结束了或者检测置信度阈值太高喂给跟踪器的框太少凑不够确认帧数。解决先把n_init降到 1~2 验证链路通不通通了再往上加。conf_thres先给 0.25 左右别一上来就 0.5。另外确认检测输出的类别只留行人class 0如果混进其他类跟踪器会拿非行人框去匹配逻辑就乱了。5.3 现象FastReID 加载权重报维度不匹配原因config 里定义的特征维度或 backbone 结构和权重文件对不上。重构版可能换了 backbone 但 config 没同步改。解决打开权重文件看 state_dict 的 key 和 shape跟 config 里的MODEL.BACKBONE和MODEL.HEADS对照。常见是embedding_size不一致改 config 对齐即可。别硬改权重改配置。5.4 现象跑评测脚本报格式错误或指标全零原因结果文件格式跟评测脚本期望的不一致帧号、ID、坐标顺序错位或者用了 0 基/1 基帧号不匹配。解决拿评测脚本自带的示例结果文件对照格式逐列核对。MOT 标准格式是frame,id,x,y,w,h,conf,x,y,z坐标是左上角加宽高不是中心点。帧号一般从 1 开始。这个坑没有捷径就是对着格式一行行看。5.5 现象显存爆了跑到一半 OOM原因YOLOv5 和 FastReID 同时占显存加上 DeepSORT 缓存的特征和轨迹批量一大就爆。解决检测和 ReID 分时复用显存或者把 ReID 的 batch size 调小跟踪器里缓存的特征数量设上限别无限存。实在不够就把检测模型换成 yolov5s 甚至 yolov5n精度掉一点但能跑起来。显存这玩意儿宁可留余量也别卡满。6. 进阶技巧把 ReID 特征缓存和阈值自适应用起来跑通基础链路后真正影响体验的是两个细节特征缓存和阈值自适应。我一般会在跟踪器里加一层特征缓存同一个 track_id 的历史特征做滑动平均而不是每帧都用当前帧特征去匹配。这样单帧特征有噪声时平均后的特征更稳ID 切换会再降一截。实现上就是在 DeepSORT 的 track 对象里挂一个特征队列匹配时用队列均值class Track: def __init__(self, feat, max_cache30): self.feat_cache [feat] self.max_cache max_cache def update_feat(self, feat): self.feat_cache.append(feat) if len(self.feat_cache) self.max_cache: self.feat_cache.pop(0) def smooth_feat(self): import numpy as np feats np.stack(self.feat_cache) mean feats.mean(axis0) return mean / np.linalg.norm(mean) # 重新归一化逻辑说明max_cache控制缓存长度太长会拖慢对 appearance 变化的响应30 帧左右是个平衡点。smooth_feat返回归一化后的均值特征拿去算余弦距离。注意均值前每帧特征都要是归一化的否则量纲不一致。另一个技巧是阈值自适应。固定max_dist在不同场景下表现差异大可以根据当前帧检测框的密度动态调人密集时放宽一点避免丢轨迹人稀疏时收紧一点避免串 ID。常见做法是统计当前帧行人框数量映射到一个缩放系数乘到max_dist上。这个映射关系得在你的场景里试出来没有通用公式。最后说个验证习惯每次改完参数别只看一段视频固定跑同一段有遮挡、有交叉、有跨镜的测试片段记录 IDS 和 IDF1 的变化。我吃过亏凭感觉调完觉得好像好了换段视频又崩。从那以后我每次调参都强制走一遍固定测试集指标不涨就不认。希望帮到你。本文还有配套的精品资源点击获取