简介面向遮挡视频场景的行人重识别毕设项目整套方案以Python源码为核心并配有可视化GUI操作界面适合深度学习或计算机视觉方向的学生用于毕业设计、课程设计的完整演示与二次开发。压缩包共744个文件大小约10.94MB其中715张jpg为行人检测与重识别数据集图像16个py文件对应视频帧提取、行人检测、特征提取、遮挡区域定位、特征增强和最终匹配等模块另有xml配置、txt说明、ttf字体、gitignore等文件便于快速复现项目环境。整体流程覆盖从视频导入、预处理、检测定位到特征比对的全链路检测部分支持YOLO/Faster R-CNN类算法特征提取可基于ResNet/DenseNet结构并通过注意力机制重点强化未遮挡区域特征降低遮挡对识别结果的干扰。压缩包已包含数据集样例和GUI效果可直接检验遮挡行人识别效果并替换模型参数做实验。目前已有197人学习浏览适合需要可运行毕设源码、数据配套和界面演示的学生参考。1. 遮挡视频行人重识别这份源码解决的三个核心问题行人重识别在监控场景里的难度从来不在“同一人正面走过来的那张脸”而在遮挡——树干挡一半、人群挤过去、目标出画再入画。这套基于深度学习毕设的遮挡视频行人重识别python源码把视频输入、行人检测、特征提取、遮挡增强到最终匹配的全链路做成了一个带GUI界面的可运行系统意味着你不需要从零去拼模型和界面拿到手就能跑通一条完整的识别流程。它适合两类人一类是正在做深度学习相关课设或毕设的学生需要一套能演示、能改参、能出结果的系统另一类是刚接触行人重识别、想快速理解YOLO检测ResNet特征注意力机制怎么在一个python工程里落地的开发者。与其把时间花在到处找视频帧和调GUI布局上不如直接用这份源码把主流程跑通再针对自己的数据集做替换。2. 算法链路拆解检测、特征、遮挡增强与匹配怎么做2.1 两段式框架为什么适合遮挡场景行人重识别最主流的落地结构是“检测再识别”两段式第一个模型负责在视频帧里把人框出来第二个模型负责对框出来的行人图像提特征。这份源码走的就是这个路线行人检测部分用YOLO这类目标检测算法从视频帧中定位行人而特征提取部分用ResNet这类预训练深度神经网络把每个行人图像转成一个特征向量。两段式的优势在于检测和识别是解耦的——检测模型不需要关心“这个人是谁”只需要回答“这里有没有人”识别模型不需要关心“人在画面里的哪个位置”只需要对裁剪出来的图像做特征编码。遮挡场景下两段式的这个解耦特性特别重要因为遮挡只影响“框住的人的完整性”不影响“检测器能不能把人框住”这个基本任务。实际跑这套系统时你会看到处理流程是这样的视频被按一定帧率抽取成帧图像YOLO在每一帧上输出行人框然后按照框的坐标把行人区域裁剪出来归一化到模型输入尺寸再送进ResNet。注意这里有一个隐藏前提——检测框的质量直接决定后续特征提取的上限。如果检测框把遮挡物一起框进去了或者框得太紧把行人的一部分切掉了后面无论特征模型多强识别结果都会受影响。所以这类系统的工程调优往往先从检测框的置信度阈值和NMS参数下手而不是一上来就换特征提取网络。def extract_frame_features(video_path, detector, embedder, frame_interval5): cap cv2.VideoCapture(video_path) frame_idx 0 features [] while True: ret, frame cap.read() if not ret: break if frame_idx % frame_interval ! 0: frame_idx 1 continue boxes detector.detect(frame, conf_threshold0.5) # YOLO检测行人框 for box in boxes: x1, y1, x2, y2 box person_img frame[y1:y2, x1:x2] person_img cv2.resize(person_img, (224, 224)) # 对齐ResNet输入尺寸 feat embedder.encode(person_img) features.append({frame: frame_idx, box: box, feat: feat}) frame_idx 1 return features这段代码是整套视频处理的骨架。frame_interval5表示每5帧取一帧处理这个值决定了处理速度与检测精度的平衡——视频里人移动不快时5到10帧取一帧完全够用能省下大量推理时间如果人跑步或者镜头移动快就要适当调小到2到3。conf_threshold0.5是YOLO的置信度阈值低于0.5的框会被丢掉这个值在遮挡场景下需要格外小心因为被遮挡的行人检测置信度往往偏低阈值设太高会把目标漏掉设太低又会出现大量误检框。resize((224, 224))是ResNet系列的标准输入尺寸换成ResNet50或ResNet101时这个尺寸不变。2.2 遮挡检测与特征增强的实现思路遮挡是行人重识别里最难处理的问题因为同一个人的特征向量在有遮挡和没有遮挡的情况下差异很大——上半身被挡住和下半身被挡住得到的特征分布完全不同。这份源码的遮挡处理思路分两步先检测遮挡区域再对未被遮挡部分的特征做增强。遮挡检测的常见做法是对行人图像做注意力热力图可视化模型在判断“这个人是谁”时不同区域的重要程度是不一样的——通常头部和躯干上半部分权重最高腿部次之背景区域权重最低。当某个高权重区域被遮挡时识别结果会明显波动系统就是利用这个波动来判断遮挡发生的位置和程度。特征增强则用注意力机制来实现。简单理解就是给特征向量的每个维度加一个权重未被遮挡区域对应的特征维度权重加大被遮挡区域对应的特征维度权重减小。这样即使输入图像里有一部分被遮挡物覆盖特征向量里仍然保留了足够的判别性信息去区分不同身份。这套源码里封装好的注意力模块输入是ResNet输出的特征图输出是经过权重加权后的增强特征向量。实际效果上遮挡增强并不会让识别精度产生质的飞跃但能让精度下降曲线变得平缓——也就是说在没有遮挡时它几乎不损失精度而在遮挡严重时能比不加增强高出一截。这对毕设答辩特别有用因为你可以直接做一个消融实验对比把“加了遮挡增强比不加高多少”用数字讲清楚。class OcclusionAttention(nn.Module): def __init__(self, in_channels, reduction16): super(OcclusionAttention, self).__init__() self.avg_pool nn.AdaptiveAvgPool2d(1) self.fc nn.Sequential( nn.Linear(in_channels, in_channels // reduction), nn.ReLU(inplaceTrue), nn.Linear(in_channels // reduction, in_channels), nn.Sigmoid() ) self.mask_estimator nn.Conv2d(in_channels, 1, kernel_size1) def forward(self, x): b, c, h, w x.shape mask torch.sigmoid(self.mask_estimator(x)) # 遮挡区域概率图 weight self.avg_pool(x).view(b, c) weight self.fc(weight).view(b, c, 1, 1) # 利用mask弱化遮挡区域响应再按通道注意力加权 x_enhanced x * mask * weight return x_enhanced, mask这个模块的forward过程做了两件核心事情。第一用mask_estimator这个1x1卷积生成一个空间注意力masksigmoid之后每个位置的值在0到1之间值越接近0说明该位置越可能被遮挡后续特征乘以这个mask实际上就是把遮挡区域的响应压下去。第二通过全局平均池化和两层全连接生成通道注意力权重突出对身份判别最有用的特征通道。这里有个细节值得注意mask_estimator输出的mask是硬编码在模型里的这个模块不是端到端训练出来的而是在推理时对特征图做的后处理增强。这意味着你在实际使用时如果发现某个遮挡场景效果不好可以调整mask的生成逻辑比如对上半身区域的mask值手动加一个偏置让系统更信任头部特征。2.3 匹配与重识别推理流程特征提取完成之后剩下的就是匹配。这份源码的匹配逻辑是把视频里每一帧检测到的行人特征向量与预先注册好的行人特征库做相似度计算相似度超过阈值的就判定为同一人。相似度计算用得最多的是余弦相似度因为特征向量经过L2归一化之后余弦相似度和欧氏距离在排序意义上是等价的但余弦相似度的取值范围固定更容易设定阈值。在注册阶段每个行人会录入多张不同姿态、不同遮挡程度的图像特征取平均后作为该行人身份的代表向量这样能缓解单张图片特征不稳定带来的误匹配。def reid_matching(query_feat, gallery_feats, gallery_ids, threshold0.7): query_norm query_feat / np.linalg.norm(query_feat) best_id None best_score 0.0 for feat, pid in zip(gallery_feats, gallery_ids): feat_norm feat / np.linalg.norm(feat) score float(np.dot(query_norm, feat_norm)) # 余弦相似度 if score best_score: best_score score best_id pid if best_score threshold: return None, best_score # 低于阈值视为陌生人 return best_id, best_score这段匹配代码逻辑不复杂但有一个工程上的坑threshold0.7这个值不是普适的。不同特征提取模型输出的特征分布不同有的模型特征天生集中在0.6到0.8这个区间0.7的阈值就会导致大量误匹配有的模型特征区分度好同一人的相似度能到0.85以上这时0.7反而太低。正确做法是先跑一批注册好的数据统计类内相似度和类间相似度的分布用两者的分界点去定阈值而不是拍脑袋设一个固定值。在你拿这套源码做实验时这个统计过程也可以直接写进毕设报告里让阈值的选择显得有理有据。匹配结果出来后GUI界面上会同时显示当前帧的行人框、匹配到的身份编号、相似度分数以及该身份在注册库里的参考图像。整套推理链路是视频帧→YOLO检测→裁剪缩放→ResNet提特征→遮挡增强→余弦匹配→GUI展示。每一步的中间结果都可以单独打印出来调试这也是用python写深度学习应用比用C推理引擎方便的地方。3. 把系统跑起来环境、目录与GUI操作流程3.1 项目结构先摸清拿到这份源码压缩包后第一步不是急着跑而是先看清目录结构。一个典型的深度学习毕设工程目录会包含核心python模块、模型权重文件、测试视频帧文件和GUI界面文件。压缩包里出现的.gitignore和reid_system.iml说明项目是用PyCharm这类IDE开发的.iml文件记录了项目模块配置。出现的大量jpg文件是视频帧或测试图像这类素材在毕设项目里很常见通常用作跑通流程的示例数据。你需要注意的重点是找到主要入口python文件、核心算法模块文件和GUI界面模块文件分别在哪里。project_root/ ├── main.py # GUI主入口 ├── detector.py # YOLO行人检测封装 ├── embedder.py # ResNet特征提取封装 ├── reid_model.py # 遮挡注意力增强模块 ├── matcher.py # 余弦匹配与阈值判断 ├── ui/ │ └── main_window.py # PyQt5界面逻辑 ├── weights/ │ ├── yolov5s.pt # 行人检测权重 │ └── resnet50_reid.pth # 特征提取权重 └── data/ └── gallery/ # 注册行人图像库如果没有在压缩包里看到weights和data目录说明权重文件需要单独下载放置这是毕设源码经常出现的情况——代码在但模型参数文件太大传不上来。遇到这种情况先确认代码里读取权重文件的路径然后去对应方向下载预训练权重放到指定位置。PyCharm的.iml文件还有一个作用它会记录Python解释器路径和项目依赖如果其他人打开项目时提示依赖缺失装依赖时参考.iml文件里列出的包版本会比较稳妥。3.2 环境安装与依赖准备运行这套系统主要依赖三个方向深度学习框架、目标检测库和GUI库。特征提取用的是ResNet所以PyTorch是主框架行人检测封装的是YOLO需要安装对应的ultralytics或pytorch的yolov5版本GUI界面用的是PyQt5或Tkinter。如果你电脑里有NVIDIA显卡安装GPU版PyTorch能大幅提升检测和特征提取的速度只有CPU的话也能跑就是处理一段视频会比较慢建议先把测试视频的分辨率降低或者调大frame_interval来换取可接受的等待时间。pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics opencv-python numpy pip install pyqt5这里的安装顺序有个讲究。先装PyTorch再装ultralytics因为ultralytics会依赖PyTorch的版本如果系统里已经有一个旧版PyTorch直接装ultralytics可能触发版本冲突最典型的报错是找不到torchvision.ops.nms这个函数。国内网络环境下PyTorch建议直接使用官方whl地址按CUDA版本安装这样能避免pip去解析一堆依赖。opencv-python负责视频读取和图像处理pyqt5负责GUI窗口。如果安装的是Tkinter版本那GUI代码会用到系统自带的Tk库不需要额外安装但界面美观度和控件丰富度不如PyQt5。3.3 通过GUI完成一次遮挡重识别环境就绪后运行主入口文件启动GUI界面。界面布局通常分四个区域左侧是视频播放区负责显示原始视频和检测框右侧上方是注册行人库列表展示已经录入的身份编号和参考图像右侧下方是识别结果区显示当前帧中每个行人的匹配身份和相似度得分底部是操作按钮区包含“打开视频”“开始识别”“暂停”“注册行人”等常用操作。整套操作流程是这样的先点“打开视频”选择本地视频文件系统自动按预设帧率抽取视频帧然后点“开始识别”系统在每一帧上跑行人检测和特征提取检测到行人后GUI在画面中绘制绿色检测框框上方标出身份编号和相似度。当遇到被遮挡的行人时识别分数会下降可能从0.9掉到0.6左右但不会完全丢失目标。python main.py运行前确认两个路径配置正确模型权重路径和视频文件路径。如果权重路径写的是相对路径就从main.py所在目录按config里的配置放置权重如果用的是绝对路径注意路径中不能有中文和空格否则opencv读取视频时经常报错或者读到空帧。视频文件路径通过GUI选择相对可控但权重文件的路径是写死在config里的每次换环境都要检查。3.4 常用参数说明整套系统的核心参数集中在config文件或模型封装类的构造函数里调参时重点关注这几组。第一组是检测参数conf_threshold控制行人框置信度阈值iou_threshold控制NMS去重时的交并比阈值frame_interval控制每隔多少帧处理一次input_size控制检测器的输入分辨率。第二组是特征提取参数feature_dim由ResNet的输出维度决定通常是2048或512normalize决定是否对特征做L2归一化。第三组是匹配参数similarity_threshold是判定是否为同一人的阈值matching_method可以选择余弦相似度或欧氏距离。第四组是GUI相关参数display_interval控制界面刷新频率max_display_height控制显示画面的缩放尺寸。这些参数在毕设答辩时是很好的切入点——你只要调整conf_threshold从0.5改到0.7展示识别结果的变化就能说明白检测置信度阈值对重识别系统的影响。如果答辩老师问到“你的系统对遮挡的鲁棒性体现在哪里”你就可以演示一组对比同一段视频开启遮挡增强前后识别分数的变化曲线。这套可调参数的设计本身就适合做成实验分析而不是一个只能演示的黑匣子。4. 避坑排查遮挡重识别最常见的五个坑4.1 检测框把遮挡物当成人框进去了现象检测框框住的区域不仅包含行人还包含一部分树干、路灯杆或另一个行人的身体导致特征提取时混入大量无关信息识别分数忽高忽低。原因YOLO检测的置信度阈值设得偏低比如0.3以下会把一些边缘模糊的目标也当作行人输出加上NMS的IoU阈值偏高两个重叠目标没有被合并导致一个行人被框了两次其中一个框就包含了遮挡物。解决把conf_threshold从0.5往上调建议先试0.6或0.65同时把NMS的IoU阈值从默认的0.45调低到0.35到0.4让重叠框更积极地去重。调完参数后重新跑一遍视频观察检测框是否贴着行人边缘而不是跟着遮挡物一起框进来。如果你发现检测框在某些帧还是偏大可以在检测输出后加一个代码层面的框体收缩处理按框宽高各缩小5%再送进特征提取。4.2 视频读取时OpenCV报错或读到黑帧现象GUI里点“打开视频”后视频区域黑屏或终端报cv2.error: OpenCV(4.8.0) ... framesync.这类错误。原因最常见的有两种一是视频文件路径包含中文或空格OpenCV底层用的是文件流读取对非ASCII路径支持不好二是视频编码格式OpenCV不认比如某些手机拍摄的H.265编码视频。解决把视频文件和项目放到同一目录下用纯英文命名比如test_video_01.mp4。如果文件已经是英文路径但仍读不出来用格式工厂或FFmpeg把视频转成H.264编码的MP4格式注意分辨率不要太高1080p就够。我一般会准备一段5到10秒的短视频做测试既能看到遮挡场景又不至于等太久。4.3 PyTorch在GUI界面里每帧推理越来越慢现象刚启动时处理一帧大概0.1秒运行几十秒后变成0.5秒甚至更慢显存占用持续增长。原因这是一个典型的显存不断累积的问题。在视频循环里每一帧的检测结果、特征张量如果没有及时释放引用PyTorch的显存缓存不会自动收缩导致可用显存越来越少推理速度越来越慢。解决在不影响功能的前提下减少GPU显存的持有对象。检测器和特征提取器各实例化一次不要每帧重新创建视频帧处理完后把不再用的tensor手动del然后调用torch.cuda.empty_cache()。更彻底的做法是设置环境变量PYTORCH_CUDA_ALLOC_CONFmax_split_size_mb:128让PyTorch的显存分配更碎片化减少大块缓存占用。这个坑在CPU上没有但用GPU跑的人几乎都会遇到属于典型的“跑着跑着变卡”的玄学问题。4.4 遮挡增强模块加上之后精度反而下降现象在测试集上对比加了遮挡注意力模块的识别准确率比不加还低尤其在无遮挡或少遮挡场景下掉点明显。原因遮挡增强模块的mask是网络预估的这个预估本身有误差。在无遮挡情况下真实的mask应该全部是1即不压制任何区域但模型预估的mask可能在某些区域输出0.7或0.8导致这些位置的特征被错误弱化判别信息丢失。解决给mask加一个带约束的训练策略在训练阶段的loss里加上mask的正则项惩罚mask偏离全1矩阵的情况。如果你不想重新训练那就提供一个开关只在遮挡程度超过某个阈值时才启用遮挡增强。判断遮挡程度可以用mask的均值均值低于0.8说明遮挡较多启用增强高于0.8说明画面干净直接用原始特征。这样一来遮挡增强的收益最大化了副作用被锁在“确实有遮挡”的场景里。4.5 CPU推理慢到怀疑人生的处理策略现象没有NVIDIA显卡的笔记本上跑这套系统一段10秒的720p视频要跑好几分钟GUI画面卡顿严重。原因YOLO检测和ResNet特征提取都是深度卷积网络CPU推理速度比GPU慢一个数量级这是硬件限制。解决先降低分辨率把视频帧缩放成640x480再送入检测器然后调大frame_interval到10或15也就是每秒只处理2到3帧画面再把测试视频压缩到5秒钟以内。这样处理一轮下来等待时间能缩短到可接受的范围。如果你的电脑性能确实太差还有一种折中方案把检测和特征提取结果的中间数据展示在GUI上推理结果本身允许延迟这样至少在答辩演示时画面不会完全卡死。5. 验证与进阶用批量交叉视角检验识别效果5.1 批量打分脚本单段视频跑通只能说明系统能工作不能说明系统可靠。拿到这套源码后我做的第一件事是写一个批量验证脚本把注册库里的行人特征和一段测试视频里检测到的行人特征全部配对打分统计正确匹配率和误匹配率。这个脚本的核心逻辑很简单逐帧检测行人、提特征、计算余弦相似度然后把所有帧的匹配结果汇总成混淆矩阵。def batch_evaluate(gallery_dir, query_video, detector, embedder, matcher, threshold0.7): gallery_feats, gallery_ids load_gallery(gallery_dir, embedder) # 加载注册库 query_feats [] query_ids [] frames extract_frames(query_video, interval5) for frame in frames: boxes detector.detect(frame, conf_threshold0.6) for box in boxes: person_img crop_resize(frame, box, size(224, 224)) feat embedder.encode(person_img) query_feats.append(feat) query_ids.append(gt_id_from_name(frame, box)) # 真实身份来自脚本标注 correct 0 total 0 for qf, qid in zip(query_feats, query_ids): pred_id, score matcher.match(qf, gallery_feats, gallery_ids, threshold) if pred_id qid: correct 1 total 1 print(fAccuracy {correct / max(total, 1):.2f} ({correct}/{total}))这段脚本里有一个关键环节gt_id_from_name是从哪里来的。通用的做法是在测试视频预处理阶段导出一个标注文件记录每一帧里每个行人框对应的真实身份编号格式可以是frame_id, x1, y1, x2, y2, person_id的CSV。这样批量验证才能真正量化评估而不是目测。5.2 阈值选择与可视化跑完批量验证后把不同相似度阈值下的准确率绘制成曲线你会看到一条典型的下降曲线——阈值设得越高误匹配越少但漏匹配越多阈值设得越低能把遮挡目标都找出来但误报也多。这个曲线的拐点位置就是你系统的最佳工作点。把这个曲线截图放在毕设论文的实验章节里说理逻辑就成立了。从那以后我每次拿到一套重识别源码都先强制自己走一遍批量验证脚本再碰GUI因为GUI演示出来的效果带着很强的主观视角人眼会不自觉地忽略那些匹配错的框而批量脚本不会说谎。你调整参数后看准确率数字的变化比肉眼看界面直观得多。这条习惯帮我避开了不少“演示很完美、实验数据一塌糊涂”的尴尬场景。这套遮挡视频行人重识别系统的工程框架是完整的检测、增强、匹配各环节都给了你动手改的空间剩下的就是拿你的数据把数字做出来希望帮到你。本文还有配套的精品资源点击获取