资讯动态

基于YOLOv12的密集行人检测系统完整实现指南

发布时间:2026/10/22 21:24:19 来源:尧图企业网站定制
做密集行人检测这个项目我前后折腾了将近两个月踩了不少坑也积累了不少经验。最近把代码和模型整理归档想了想还是把整个实现过程完整写出来给想用YOLOv12做目标检测的朋友一条可参考的路径。这套系统本质上是一个完整的软硬件工程底层是YOLOv12检测模型上层是PySide6做的图形界面再加上登录注册模块、数据集标注流程、训练脚本和推理引擎属于把“模型训练”和“软件工程”缝合到一起的综合项目。如果你正打算做类似的毕业设计、竞赛项目或者要落地一个真实场景的监控检测系统这篇内容应该能帮你少走很多弯路。先聊聊这套系统能做什么。你打开程序首先看到的是登录注册界面注册完账号之后进入主界面主界面里可以加载本地图片、视频、调取摄像头实时画面模型会自动检测画面里的行人画出检测框、显示置信度、统计人数还能把检测结果导出成文件或者直接保存图片。听着不复杂但把这一整套流程跑通并且做到稳定涉及的点其实相当多数据集标注和质量、模型训练参数、UI线程调度、账号数据存储每一个环节都可能出问题。这篇文章我会按项目推进的顺序把设计和实操细节完整拆开来讲。1. 系统整体设计与思路拆解1.1 为什么选YOLOv12做密集行人检测选模型这件事我是认真对比过的。目标检测模型现在主流的就那几类两阶段的Faster R-CNN系列、单阶段的YOLO系列、基于Transformer的DETR系列。两阶段检测精度高但速度慢适合离线高精度场景DETR系列对小样本和重叠目标处理不错但模型体量大、部署麻烦YOLO系列在“速度精度”的平衡上一直做得最好。YOLOv12在v8基础上又引入了注意力机制层面的改进对特征提取和融合的细节做了优化小目标和密集重叠目标的检测能力比前代有肉眼可见的提升。密集行人场景和普通目标检测不一样它有几个特别致命的问题。第一个问题是尺度差异。监控摄像头往往架在高处远处行人只有二三十像素高近处行人可能占满半个画面。同一个画面里目标尺度跨度太大很多模型会把小目标漏掉。第二个问题是遮挡。行人是非刚性目标姿态多变人群密集的时候互相遮挡严重人跟人之间、人跟物体之间的边界很模糊。检测模型输出的框一旦重叠度较高后处理阶段的NMS很容易把两个行人的框误判成同一个直接吞掉一个检测结果。第三个问题是密度。像商场、地铁站出口、演唱会现场这种地方单张图可以挤下几百个人头光靠人脸检测肯定不现实必须靠全身或半身检测去做。YOLOv12针对这些痛点做了不少优化。它的Backbone和Neck部分在特征融合上更精细高分辨率特征层保留得更好加上注意力机制的权重分配让模型在复杂背景下能更准地把“前景行人”和“背景干扰”分开。我实际训练下来的感受是同样的数据集和训练轮数v12在密集小目标场景下的mAP比v8高了差不多2到3个点尤其是在遮挡严重的样本上效果差别一眼就能看出来。1.2 系统架构与功能模块划分整个系统我按“数据层—模型层—应用层”三层来组织。数据层负责数据集的管理原始图片、标注文件、训练集验证集划分、数据增强策略。这一层是基础做不好后面模型效果一定拉胯。很多人一上来就急着跑模型数据随便找几张就开训结果自然是模型根本学不到东西。模型层负责YOLOv12的训练和推理包括模型文件、训练脚本、推理引擎封装、结果后处理NMS、置信度过滤、绘制检测框。这一层要求代码结构清晰检测逻辑要能独立运行不能跟界面代码强耦合。应用层就是用户能直接操作的部分登录注册界面、主界面、检测逻辑的调度、检测结果的展示和导出。应用层的核心要求是响应快、不卡顿、操作直观。很多做AI的同学把模型训练做得很好但界面交互一塌糊涂用户点一下按钮要卡三秒这在落地场景里是完全不可接受的。技术选型上界面框架我用了PySide6也就是Qt的Python绑定。之所以不用Tkinter是因为它做复杂布局和现代化界面太吃力不用Web前端的原因是本地部署场景下桌面应用更轻便、不依赖浏览器环境打开即用。数据库用SQLite轻量且不需要单独装服务端用户信息存在本地文件里对单机应用来说完全够用。后端肯定是用PyTorchYOLOv12的原生训练推理生态都在PyTorch上社区资源也最丰富出了问题搜解决方案也好搜。1.3 方案选型背后的取舍逻辑有几个取舍我想单独说一下因为很多人会在这几个点上纠结很久。第一个是“直接拿预训练权重用还是要自己训练”。如果你检测的目标不是标准COCO 80类里的类别比如你只想检“安全帽”“车辆品牌”“施工人员”那预训练权重大概率不满足需求必须用自己标注的数据微调。行人检测有一点好公开数据集的person类本身就覆盖得非常充分预训练模型对行人的效果已经不错。但如果你的监控场景很特殊比如高空俯瞰摄像头、鱼眼镜头、特定角度下的行人直接拿官方权重去跑是hold不住的必须用场景数据重新微调效果差别很明显。第二个是界面端处理检测结果是“调用外部脚本”还是“封装成类”。很多人喜欢在UI里用subprocess直接弹一个detect.py命令去执行检测这样做开发省事但用户体验很差界面卡死、结果返回不及时、不能实时显示中间状态。我是花了时间把检测功能封装成独立的Detector类在UI主线程外开工作线程去跑推理再用信号把结果传回主线程刷新画面这才算是一个真正可用的桌面应用。第三个是Web还是桌面。有些朋友想做成网页版用Flask或FastAPI做后端浏览器做前端。这个方向适合远程访问场景但你需要额外处理并发请求、模型常驻内存、网关部署等一系列问题。纯本地单机场景桌面端反而更省心。我这套系统的目标场景就是一台终端机或者一台本地服务器直接跑所以选了桌面端。2. 密集行人场景的数据集准备与处理2.1 数据来源与标注格式数据集的质量直接决定模型性能上限这个怎么强调都不过分。算法圈里有句话“模型决定下限数据决定上限。”花时间把数据做成高质量比盲目堆模型参数量更有性价比。整个项目最耗时间的不是写代码调参数而是整理数据集和复查标注。我的数据来源分三块第一块是从开源行人检测数据集中筛选的图片大概占七成第二块是自己用手机和摄像机在不同场景拍的再按帧截取占两成第三块是从监控录像片段里截取的关键帧用来补足特殊角度和光线条件。开源数据的优点是量大、场景多样缺点是风格和我们的目标场景有偏差所以一定要混入自己的场景数据来微调纯靠开源数据模型很容易在真实场景上“水土不服”。标注格式用YOLO的txt格式每一行对应一个目标框格式是类别编号 x_center y_center width height。注意这四项坐标全部要归一化到0到1之间而且是相对于整张图片宽高的比例不是像素坐标。很多新手在这一步容易写错比如直接拿像素坐标除以2就填进去训出来的模型框全是偏的。标注工具我用的是LabelImg它可以直接导出YOLO格式省去自己写格式转换脚本的麻烦。标注密集行人最耗时的就是“不漏标”人一多就容易漏尤其是被遮挡了一半的行人。我的经验是宁可多标一个模糊框也不要漏标因为漏标对训练是负反馈会让模型学着忽略这些目标。2.2 关键数据预处理策略数据预处理这块密集场景和普通场景有个显著差异必须把“小目标增强”放在第一优先级。常规目标检测可以把精力放在颜色扰动、模糊模拟这些通用策略上但密集行人场景里提升小目标检测能力才是决定模型能不能用的核心。我用到的增强策略包括Mosaic、MixUp、HSV扰动、随机翻转、平移和缩放。Mosaic是YOLOv5提出来的策略把四张图拼成一张去训练相当于变相扩大了batch size还让模型学会在不同尺度下检测目标对小目标场景尤其有效。MixUp则是把两张图按透明度叠加模拟遮挡场景这个思路和行人互相遮挡的现实情况很贴近相当于预先让模型在训练阶段就见过了“目标有一部分被盖住”的情况。另外我重点做了“高分辨率训练”这个非常关键。YOLO系列默认的输入尺寸通常是640×640但对密集小目标场景我强烈建议把输入分辨率提到1280。代价是显存占用和训练时间明显增加但对小目标的检测效果提升非常直接。我用一张包含大量远处行人的测试图实测过640输入下远处行人漏检率很高1280输入下基本能框出大部分远处行人。如果你的显存不够可以先用640把baseline跑出来再用1280微调最后几十个epoch效果会比全程用640好很多。还有一点很多人会忽略检测框的标注质量在密集场景里尤其致命。如果标注框的边缘歪了模型学到的就是一堆歪框的先验最后输出结果也是歪的。我建议标注完一批数据后专门做一次“框质量复查”尤其是互相遮挡的行人附近标注框必须尽量贴合目标真实边缘不要为了赶进度随手拉一个框就完事。2.3 数据集划分与类别设定细节数据集按7:2:1划分训练集、验证集、测试集。划分必须在“图片级别”进行不能把同一段视频连续帧的图片同时分到训练集和验证集里否则验证集会严重高估模型的实际表现。正确做法是先把同一个视频的所有帧归为一组再按视频维度打散划分或者按场景文件夹分组保证同一个场景只出现在某一个集合里面。这个细节很多人不注意训练完看验证集指标很好一部署到真实场景就原形毕露。类别就一个person。这有一个小技巧如果你后续还想对行人做细分比如区分“正常行人”“倒地行人”“工作人员”等特殊状态就要在标注阶段一次性把所有需要的类别都标出来。不要等训练完再补标因为模型训练好后你要加新类别就得全量重新训练代价很大。我当时一度想加“骑行者”这个类别后来发现标注数据里骑行者样本太少硬加只会拉低整体精度果断放弃先把person类做到极致。训练集图片的尺寸也要统一处理。图片太大占用显存多太小又丢失细节。我统一做了两步首先按最长边缩放到接近模型输入尺寸同时保证宽高比不变多余部分用灰色填充到正方形避免直接拉伸导致目标变形。实际测试下来这种带padding的方式比直接resize的检测精度要稳定一些。3. 模型训练与参数调优实战3.1 环境搭建与依赖安装环境这关就能卡住一半的人我把完整流程整理出来照着做基本不会出大问题。操作系统建议用Ubuntu 20.04或22.04Windows 11也可以。Python版本建议3.9到3.11不建议用最新的3.12因为PyTorch和CUDA生态对3.12的支持还比较慢容易在装依赖的时候报错。GPU是训练的前提条件。个人训练建议显存至少8GB起步。我用的是某型号12GB显存的显卡训练1280分辨率的模型batch_size大概能开到8到16之间。如果你只有6GB显存训练1280会非常吃力建议退回640分辨率或者用云GPU。安装步骤很固定先装CUDA Toolkit和cuDNN再安装对应版本的PyTorch。CUDA版本和PyTorch的对应关系一定要去查官方兼容表版本不匹配会出现“CUDA unavailable”这种让人极度怀疑人生的报错。装完之后用下面这段代码验证环境import torch print(torch.__version__) print(torch.cuda.is_available()) if torch.cuda.is_available(): print(torch.cuda.get_device_name(0))如果CUDA可用性打印为True环境基本就通了。这一步能筛掉80%的环境问题不要跳过这个验证直接去跑训练脚本到时候报错都不知道从哪儿查起。3.2 训练关键参数解析训练参数直接影响模型质量我把自己调出来的稳定参数贴出来并解释每个参数为什么这么设。epochs训练了200个epoch。YOLO训练在100个epoch之后还在持续涨点不要过早停。我见过有人只训练了30个epoch就拿来部署结果漏检率高得离谱模型根本没有充分收敛。batch_size根据显存尽量开大建议8到16。imgsz640先训练50个epoch做baseline再用imgsz1280接着微调30到50个epoch。这种“低分辨率预训练高分辨率微调”的策略在很多实际项目里都有效。lr0初始学习率0.01配合余弦退火调整。weight_decay0.0005防止过拟合。优化器SGD足够AdamW不一定更好YOLO系列默认的SGD表现很稳定。训练命令大致是这样的python train.py --data data/person.yaml --weights yolov12.pt --img 640 --batch 16 --epochs 100 --device 0我把关键参数整理成速查表方便你排查问题的时候快速对照参数推荐值说明epochs150-200前100个epoch出baseline后面用更高分辨率微调batch_size8-16显存越大越好OOM就先降这个imgsz640→1280低频预训练、高频微调是密集小目标的制胜点lr00.01配合余弦退火最后阶段学习率降到很低weight_decay0.0005防止过拟合数据集小的时候尤其重要nms_iou0.5密集场景不要用默认0.45容易误杀重叠目标特别要说一个密集行人场景的独有参数NMS的IoU阈值。训练结束推理的时候默认的NMS阈值在密集场景往往会误杀大量互相遮挡的框。我把置信度阈值固定为0.25NMS的IoU阈值从默认的0.45调整到了0.5甚至0.55。同时可以考虑用soft-NMS或者DIoU-NMS替代普通NMS对密集目标有明显的改善这个在第五部分还会细说。3.3 训练过程监控与模型评估训练过程中我重点关注几个指标曲线loss、mAP50、mAP50-95、precision、recall。不要只看mAP50这一项指标因为密集场景下漏检多的时候precision和recall的平衡问题会被mAP掩盖。一个实用的经验当precision和recall差距较大时要根据业务场景做取舍。如果系统用在地铁站这种人流监控上我宁愿recall高一些、误检多一些也不愿意漏检因为漏一个行人可能意味着监管盲区。如果是做商场客流统计分析过多误检会导致统计人数虚高就需要适当提高置信度阈值牺牲一点recall保住precision。训练完要导出指标报告重点看验证集上的PR曲线和混淆矩阵。PR曲线越靠近右上角越好混淆矩阵能看出模型容易把什么背景误判成行人。比如看到大量把“栏杆”“柱子”这类竖条形物体误检成行人的样本说明训练集中行人周围的背景样本还不够多样需要专门收集这类负样本加入训练。模型导出这一步也很关键。最终交付时我建议同时导出PyTorch的.pt格式和ONNX格式ONNX格式用onnxruntime推理部署时不用纠结CUDA版本兼容性好很多。导出命令只需要调YOLOv12自带的export脚本导出后可以用onnxruntime的Python API写一个极简推理脚本验证导出的模型输出结果和PyTorch推理结果是否一致。这一步能提前发现很多模型转换带来的精度损失问题。4. 核心功能实现UI界面与登录注册4.1 界面布局与交互逻辑UI这块我用PySide6来做。主界面的布局分成三个区域左侧是控制面板中间是检测画面显示区右侧是结果信息栏。左侧控制面板放三个输入按钮打开图片、打开视频、打开摄像头。摄像头调用用的是OpenCV的VideoCapture视频流实时传入推理线程做检测每处理完一帧就把结果信号发到主线程刷新画面。中间显示区用QLabel配合QPixmap绘制。检测结果帧是把模型输出的boxes画到原图上的结果绘制用OpenCV的rectangle和putText。在这里有一个性能关键点推理线程和UI线程之间传递图像数据千万不要直接把整个大尺寸图像作为信号参数去发否则主线程会被大量图像数据的拷贝操作拖垮。我的做法是只发送检测结果结构体框坐标列表、类别、置信度由主线程根据结果在原图上自行绘制。实测这样处理视频流时UI帧率稳定不少。右侧结果栏显示当前帧的累计检测人数、平均置信度、当前模式以及“保存当前帧”“导出检测结果”两个按钮。保存当前帧很好理解导出功能是把当前画面的检测结果导出成CSV包含行人ID、坐标、置信度这些信息方便后续做数据分析。4.2 登录注册模块的实现细节登录注册模块是很多同学做系统最容易糊弄过去的部分但仔细做的话这里也有很多值得深挖的细节。数据库我用SQLite建了一张users表字段包括id、username、password_hash、salt、create_time。密码绝对不允许明文存储这是最基础的安全底线。我这里用sha256配合盐值做了迭代哈希。注册流程大致如下用户提交用户名和密码后后端生成一个随机盐值把密码和盐拼在一起做哈希运算把哈希结果和盐一起存库。用户登录时用同样的盐值重算哈希和库里的哈希比对一致则登录成功。代码核心部分大概是这样的import hashlib import os def hash_password(password: str, salt: str) - str: hashed hashlib.sha256((salt password).encode()).hexdigest() for _ in range(1000): # 增加迭代轮数提高暴力破解成本 hashed hashlib.sha256((hashed salt).encode()).hexdigest() return hashed def register(username, password): salt os.urandom(16).hex() password_hash hash_password(password, salt) # 写入SQLite # INSERT INTO users (username, password_hash, salt)登录成功后主界面里保存一个登录状态用全局变量或者配置文件记住当前用户后续可以按用户记录操作日志。还有一个容易被忽略的细节注册时要做“用户名唯一性校验”和“密码强度校验”。密码至少8位且包含数字和字母否则注册直接反馈错误。别小看这个细节很多系统的安全问题就是从弱密码开始的。测试的时候我试过用纯数字“123456”注册系统直接拒绝虽然一时觉得麻烦但这是该有的底线。4.3 检测引擎与UI的集成方式检测引擎和UI的集成是整个项目中最容易出现“卡死”问题的环节。核心原则是任何耗时操作都不能放在UI主线程里。YOLOv12单帧推理在GPU上大概需要20到60毫秒加上前后处理一轮耗时可能在100到200毫秒之间。如果你直接在按钮回调里同步执行推理点击按钮后界面会无响应看起来就像死机了一样。我的做法是利用QThread开一个工作线程把视频帧队列传给工作线程工作线程处理完毕之后通过pyqtSignal发信号回UI线程更新画面。核心结构如下class DetectWorker(QThread): result_ready pyqtSignal(dict) def __init__(self): super().__init__() self.frame_queue queue.Queue() self.running True def run(self): while self.running: frame self.frame_queue.get() result detector.predict(frame) self.result_ready.emit(result)UI里只需要在槽函数里接收结构化的检测结果再刷新画面即可主线程永远不做推理计算界面响应就会非常顺畅。这个多线程模型是整个桌面应用流畅度的核心保障。如果不这么做即使模型效果很好体验也是糟糕的。5. 常见问题与排查技巧实录5.1 漏检误检频繁怎么办这类问题排在所有问题出现频率第一位。排查思路要按顺序来先看输入图像质量再看模型推理参数最后考虑训练数据。输入图像质量问题比如摄像头画面模糊、逆光过曝、运动模糊这类情况任何模型都很难做得好要先把输入帧的预处理做干净。如果画面本身不行模型再强也没有意义。推理参数层面置信度阈值调低一点能缓解漏检但代价是误检增加。我自己用的是0.25这个折中值NMS IoU阈值调到0.5。如果漏检还是严重检查一下是否用了1280的高分辨率输入这个对远处小行人的检测影响极大。如果这些都不行问题大概率出在训练数据上要么数据里小目标样本、遮挡样本太少要么数据分布和实际测试场景差异太大。这时候不要盲目调参或者加大模型老老实实补数据永远比调参有效。我遇到过最典型的案例是某个监控角度特殊所有测试样本都是俯视角训练数据全是平视角模型效果自然差补了几百张俯视角标注图片之后检测效果立刻上一个台阶。我把排查顺序整理成速查表症状首选排查方向备注漏检严重置信度阈值、输入分辨率先确认是否在用1280输入训练/推理误检多训练数据负样本、置信度阈值补背景负样本调高置信度阈值推理卡UI是否在UI主线程做推理必须用QThread工作线程显存不足OOMbatch_size、imgsz开启amp混合精度模型部署后精度下降导出格式优先用ONNX统一部署环境5.2 训练和推理的速度与显存问题显存不足是新手最常见的“劝退点”。解决顺序是这样的先把batch_size调小再把输入分辨率从1280降到960或640最后考虑开启混合精度训练也就是ampTrue。混合精度训练可以在几乎不损失精度的情况下把显存占用降低将近一半而且能提速我建议不管显存够不够都开。推理速度太慢的话优先看是不是把推理放在了UI主线程这会导致视频流整体卡顿。排除之后可以用TensorRT或者ONNX Runtime做加速量化和图优化之后推理速度比PyTorch原生推理快不少。如果目标设备有GPUTensorRT是最优选纯CPU环境走ONNX Runtime加int8量化也能做到勉强可用的帧率。5.3 打包部署阶段的坑项目做完之后很多朋友想打包成exe或者独立可执行文件这个阶段简直是踩坑重灾区。第一个坑是PySide6资源文件打不进去空图标、白屏界面都是这个原因。要在打包配置里把qml和资源文件显式包含进去并且用相对路径引用资源。第二个坑是模型文件的路径冲突。打包后程序工作目录和开发时不一样写死绝对路径必然会崩。最好把模型路径设计成可配置项运行前自动检测同级目录下是否存在权重文件找不到就提示用户。第三个坑是CUDA运行库。目标机器如果和开发机器的CUDA版本不一致GPU推理可能直接报错或者退化到CPU模式。稳妥的做法是打包携带ONNX模型而不是PyTorch的pt权重运行时用ONNX Runtime的GPU版本兼容性会好很多。6. 几个容易被忽略但影响很大的细节这一节集中聊聊前面散落在各个章节里没有展开、但实战中体验非常明显的几个点。一个是模型导出的格式选择。训练好的模型是.pt格式在项目目录里用自然没问题但跨环境部署时.pt格式很依赖PyTorch环境兼容性问题多。我最终的交付形态是同时提供.pt和ONNX两种格式ONNX格式用onnxruntime推理部署时不用关心CUDA版本省掉很多麻烦。另一个是检测框的可视化样式。画框的时候我特意做了两种模式全身框和半身框。密集场景下半身框在很多情况下比全身框更稳定因为遮挡往往发生在腿部全身框会被遮挡物切断导致框的尺寸失真。我在界面里加了一个“检测框模式”的开关让使用者可以在全身框和半身框之间切换。实测极端拥挤场景下半身框模式的效果更稳。做产品的时候这种可视化细节就是体验差异。日志系统也是容易被忽略但非常实用的模块。我把每次登录、每次检测统计、异常信息都写进本地日志文件方便后续回溯问题。实际部署之后日志帮了大忙用户反馈说某个时段检测不准一翻日志就能定位是模型置信度设置问题还是视频流中断问题。另外训练过程中要定期保存best.pt和last.pt两个权重文件。best是验证集上效果最好的last是最后一个epoch的结果。很多人习惯只留最后一份结果训练中途效果最好的可能是第150个epoch后面那些epoch反而过拟合了最后拿了一个次优模型去部署白白浪费了前面的训练成果。结尾行这套基于YOLOv12的密集行人识别检测系统从数据集、训练、UI到登录注册的完整实现就讲到这里。希望对准备做类似系统的朋友有帮助。最后分享一个我踩过的很典型的坑给大家提个醒我第一次尝试用1280分辨率训练之前没有确认显存足够直接把batch_size设成了16结果GPU显存爆掉直接崩溃白跑了两个小时。后来学乖了任何新参数组合都先跑一个1个epoch的冒烟测试确认显存和速度都正常再跑完整训练。这个习惯帮我省下的时间比任何调参技巧都多。如果你在数据集标注、参数调优或者界面集成上遇到了具体问题欢迎一起交流我尽量把自己的实操经验讲明白。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑