资讯详情

基于YOLO的深度学习人流量检测系统设计与Python实现

📅 2026/10/9 2:20:00 | 华诺云谱 👁 阅读
基于YOLO的深度学习人流量检测系统设计与Python实现
简介面向计算机相关专业本科生的毕业设计项目基于深度学习实现人流量检测内含完整Python源码、项目说明与运行环境配置参考可支撑毕业设计、课程设计或期末大作业等场景。压缩包共1235个文件、约61.54MB其中Python脚本.py为模型训练与检测核心代码网页交互文件html/js/css提供可视化展示ipynb和md文档记录调试过程与使用说明png/jpg/gif为演示素材代码与资源分类存放。已有263人学习下载。项目经导师指导并严格调试覆盖数据预处理、模型训练、实时检测和结果可视化完整流程同时备注了环境搭建、参数调整与常见排错思路便于读者快速理解算法原理并迁移到自己的数据上有效降低毕业设计或项目实战的入门门槛。1. 从YOLO到人流计数人流量检测系统到底在做什么商场物业、地铁安保、景区运营这些场景的管理者真正要的不是「画面里此刻有多少人」而是「每五分钟从哪个口进了多少人」。这个诉求落到技术上就是一套基于深度学习的人流量检测系统先用目标检测模型把画面里的行人或人头框出来再用跟踪逻辑给每个目标分配一个稳定ID最后通过虚拟线或区域判定完成计数。标题里的「Python源码项目说明」意味着这套链路的每一步都要有可运行的代码和可读的文档支撑放在毕业设计里就是一个从模型训练到业务计数都闭环的高分项目。适合计算机视觉方向的本科生或者想快速把检测模型接到实际计数业务的工程师。这套系统最容易在哪一步翻车不是检测而是计数——很多人把检测框数量直接当人流量结果同一帧里一个人被重复算了好几次最终数字完全不可信。2. 训练数据怎么来公开数据集选型与标注转YOLO格式2.1 人流量检测的数据集选型人头框还是人体框做这套系统之前先想清楚检测目标。常见做法是两种检测整个人体或者只检测头部。固定机位俯拍的闸机、安检口场景人体互相遮挡严重人体框大量重叠NMS之后框还在漂人头框虽然目标小但遮挡少、边界清晰。我在做这类项目时一般先拍一段现场视频统计目标的像素尺寸小于32像素的就果断走人头检测路线。数据的另一个来源是公开数据集MOT Challenge、CrowdHuman这类是绕不开的选择前者带跟踪标注后者密集人群标注质量高适合做检测预训练。但要注意公开数据集通常标注的是人体框而你的业务场景可能需要人头框这个不匹配会在迁移时吃大亏后面会专门讲。2.2 把labelme标注转换成YOLO训练格式转换脚本与参数说明YOLO系模型训练要求每张图片对应一个同名txt文件每行是「类别id 归一化x_center 归一化y_center 归一化宽 归一化高」。而手工标注工具labelme默认输出JSON里面是绝对像素坐标。这个格式差是第一个坑。我常用的转换脚本如下import json import os def labelme_to_yolo(json_path, out_dir, class_mapNone): with open(json_path, r, encodingutf-8) as f: data json.load(f) img_w data[imageWidth] img_h data[imageHeight] base os.path.splitext(os.path.basename(json_path))[0] lines [] for shape in data[shapes]: label shape[label] if class_map is not None: cls_id class_map[label] else: cls_id 0 points shape[points] xs [p[0] for p in points] ys [p[1] for p in points] x_min, x_max min(xs), max(xs) y_min, y_max min(ys), max(ys) # 计算中心点与宽高再归一化到 0~1 区间 x_center (x_min x_max) / 2.0 / img_w y_center (y_min y_max) / 2.0 / img_h box_w (x_max - x_min) / img_w box_h (y_max - y_min) / img_h # 边界裁剪标注框越界会导致训练时 loss 异常 x_center max(0.0, min(1.0, x_center)) y_center max(0.0, min(1.0, y_center)) box_w max(0.0, min(1.0, box_w)) box_h max(0.0, min(1.0, box_h)) lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}) out_path os.path.join(out_dir, base .txt) with open(out_path, w, encodingutf-8) as f: f.write(\n.join(lines))这段脚本的逻辑分三步读JSON拿图像宽高和标注多边形求外接矩形的中心点与宽高并做归一化最后写成YOLO需要的txt格式。class_map参数是一个字典例如{head: 0, person: 1}用来把字符串标签映射成从0开始的类别id。这里有个参数细节如果图片尺寸很小但标注很多多边形归一化后的小数位保留6位就够用更多位不影响训练真正影响训练的是标注框越界问题所以我在代码里强制做了clip这是标注数据清洗里最常见的修补方式。2.3 数据划分训练集验证集不能按视频帧随机切数据准备好后要划分目录推荐结构是dataset/images/{train,valid}和dataset/labels/{train,valid}比例用9比1或8比2。很多人图省事把视频抽帧后的所有图片按比例随机划分这会导致同一个人的连续帧同时出现在训练集和验证集评估指标虚高模型实际泛化能力很差。正确做法是先按视频片段划分比如前3段视频全部进训练集第4段视频全部进验证集保证验证集看到的人脸、衣着、光照与训练集不完全重叠。我在做毕业设计项目时还会额外留一段完全不同场景的视频作为最终测试这段完全不参与训练和调参专门用来模拟交付后的真实效果。3. 用YOLOv5做检测器训练命令、参数调节与结果判断3.1 为什么选YOLOv5而不是Faster RCNN或SSD人流量检测的实时性是硬指标。Faster RCNN在两阶段检测器里精度不错但单张1080P图片在GPU上推理要200毫秒以上做实时视频流很吃力SSD速度快但小目标召回率差密集人群里的小人头基本漏一半。YOLOv5是单阶段检测器平衡了速度和精度而且生态成熟从训练到TensorRT部署的教程资料多成熟度对单人开发的项目是很大的加成遇到问题能搜到答案比什么都重要。从前面第2章的数据准备可以看出YOLO格式的标注转换工具链也最完善。为什么总强调生态因为毕业设计周期有限你不可能把所有时间花在调一个冷门模型的推理代码上把精力留在计数逻辑和系统演示更划算。3.2 训练命令与关键参数img、batch、epochs怎么定数据目录和yaml配置就绪之后训练命令长这样python train.py \ --data datacfg/crowd.yaml \ --weights weights/yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 120 \ --device 0crowd.yaml里至少要写清三样东西训练集和验证集图片路径、类别数量、类别名称。weights用yolov5s.pt这个预训练权重做迁移学习而不是从空白权重开始训练这是COCO预训练模型自带的基础视觉特征能大幅缩短收敛时间。img参数是训练分辨率密集人头场景建议直接拉到768小目标特征在低分辨率下容易被下采样丢掉。batch大小受显存限制16G显存跑yolov5s可以到328G显存就老实16如果还爆显存把输入图缩到640比硬降batch更稳妥。epochs对小型数据集100到150之间足够再多大概率过拟合。下面是几个最影响结果的参数速查参数常见取值对结果的影响--img640 / 768密集人群用768能明显提升小目标召回--batch8 / 16 / 32在显存允许下尽量大太小会震荡--epochs100 / 150超过150收益递减易过拟合--weightsyolov5s.pt从COCO预训练迁移比随机初始化快很多3.3 训练结果怎么看loss降了不代表能交付训练过程要盯四个指标train loss、val loss、mAP50和Recall。很多新手只看mAP50觉得0.9就是好模型。在人流量检测里Recall比Precision更值得关注——漏掉一个人头计数结果就永久少一个人误检一个目标跟踪去重后可能只多算一次。mAP50-95这个指标可以忽略它对边界框的精确度要求过高而人流计数场景框稍微偏一点不影响计数。另一个判断点是训练结束前30个epoch的val loss是否稳定如果训练loss还在降、val loss开始反弹说明模型开始记训练集了这时候应该用倒数第30个epoch的权重而不是最后一个epoch的权重这个权重导出后做测试往往效果更好。4. 从检测框到人流量数字跟踪虚拟线计数的落地实现4.1 为什么纯检测计数一定会翻车检测模型每帧输出一堆带类别的边界框如果直接把这一帧的框数量当作人流量至少会有两个严重错误。第一同一个行人在连续帧里会被重复计数每帧都数一遍等于把停留时间换算成了虚假流量第二检测模型是逐帧独立的漏检、误检在时间轴上随机出现直接求和结果波动极大。这就是为什么人流量检测系统必须引入跟踪目标跟踪给每个行人分配一个唯一ID系统知道这一帧的框和上一帧的框是不是同一个人计数时按ID去重同一个ID只算一次。跟踪算法方面DeepSORT是经典选择ByteTrack近年更常用后者对低置信度检测框的处理更稳定密集人群里ID切换次数明显更少。4.2 虚拟线计数的Python实现思路按ID去重计数逻辑本身不复杂核心是维护一个已经通过的ID集合防止重复计数。以下是我常用的思路代码class CountLine: def __init__(self, line_y, directiondown): self.line_y line_y self.direction direction self.passed set() self.count 0 def update(self, track_id, cx, cy, prev_cy): # 这个ID已经跨过线直接跳过避免重复计数 if track_id in self.passed: return if prev_cy is None or cx is None: return # 从线上方走向下方上一帧在线上方当前帧在下方 if self.direction down and prev_cy self.line_y cy: self.count 1 self.passed.add(track_id) # 从下方走向上方 elif self.direction up and prev_cy self.line_y cy: self.count 1 self.passed.add(track_id)这个类不关心跟踪器怎么实现它只接收track_id和前后两帧的中心点纵坐标。当目标的中心点跨越设定好的直线时计数值加一并记录ID。关键参数是line_y它需要结合摄像头安装角度来定俯拍视角下放在画面中段偏下比较合理太靠近画面边缘容易被误检干扰。direction决定统计的是进还是出双向通道就建两个CountLine实例一个down一个up。这套逻辑有个前提track_id必须稳定如果同一个行人每几帧就被跟踪器换个新ID他过线时就会被重复计数。所以真正要调的是上游跟踪器的参数不是这个类。4.3 置信度阈值、帧率两个直接影响计数质量的参数检测置信度阈值一般设在0.3到0.5之间。设太低广告海报上的人形图案会被当成真行人设太高小头目标被过滤掉漏计严重。我一般先取0.4然后用验证视频跑一遍看检测出的False Positive和漏检数量再微调。帧率同样关键测试中发现每3帧检测一次足够跟踪器在40毫秒内不会跟丢目标如果为了性能降到每秒只处理5帧行人快速走动时跟踪框会跳跃ID切换概率剧增。建议在项目说明里明确写清「检测每N帧执行一次跟踪每帧执行」的配置这是实际部署时最容易忽略的细节也是答辩时对方可能会追问的点。5. 避坑与排查人流量检测系统常见的5个坑5.1 训练loss不降或反复震荡现象训练前10个epochloss从0.1降到0.07之后就不再变化或者在0.08附近来回跳。原因排查下来通常是三选一学习率过高、数据标注有误、类别数量不匹配。解决路径是这样的先看日志里的learning rate初始设置0.01对小数据集偏高降到0.001再试然后检查data yaml里的类别数量是否和标注一致比如你只标了person一类但class_map里给了三个类别模型在训练时就没法收敛最后随机抽几组标注txt画在原图上检查大概率能找到框没包住目标或中心点偏了的情况。5.2 验证mAP很高但视频里漏检严重现象训练日志里mAP50达到0.92在自采视频里一跑很多行人被漏掉。原因几乎都是训练集和测试集的分布差异公开数据集是户外大街场景你的摄像头是室内俯拍视角光照和拍摄角度完全不一样模型的泛化能力支撑不住这种分布偏移。解决方法是补拍100到200帧现场视频标注后加入训练集重新微调通常就能压下来。这条经验值钱在提醒你验证集应该模拟真实部署场景而不是只用公开数据集。5.3 计数结果反复横跳ID频繁切换现象一个人匀速走过虚拟线计数从1变成3再变回2。原因是跟踪器把同一个人的轨迹切断了中间换了一次ID前面已经记录过的ID在新ID出现时又被当成新人。ByteTrack默认对低置信度框做二次匹配但参数min_box_area设置过小时很多噪声框参与匹配反而导致轨迹断裂。解决方法是调大min_box_area过滤小噪声框或者把跟踪器内部的最大丢失帧数从默认值往上调一点让目标短暂遮挡后能重新接上原轨迹。这属于调参玄学但按这个路径试大概率能稳住。5.4 广告牌上的人的误检现象商场背景里有大幅海报海报里的人被检测成人流量计数虚高。原因就是训练集里缺少这类负样本。解决策略有两个一是收集十几张类似的广告牌图片加入数据集标注为空让模型学会判断这是背景二是在推理阶段加一个ROI过滤区域把海报所在的图像区域直接排除在检测范围之外。第二种方法在固定摄像头场景下更省事就是改一行配置的事。5.5 GPU显存OOM现象训练跑到第5个epoch直接报CUDA out of memory进程退出。原因是batch设太大或者训练分辨率拉到768的同时还开了多尺度训练。解决步骤从易到难先调小batch到8再把img降到640如果还不行检查是不是其他进程占用了显存最后可以开梯度累积替代物理batch增大。这个坑本身不难但容易出现一种情况系统自动重启之后显存被旧进程占用OOM一直报先重启机器再训练往往就解决了。6. 进阶与验证人头检测、轨迹热力图与计数精度自评6.1 俯拍场景优先切到人头检测如果你的摄像头装在通道正上方俯拍建议把检测目标从整个人换成头部。人体框在这种视角下高度方向压缩严重相邻行人的框互相重叠NMS会随机砍掉其中一个而头部目标在人脸上方彼此重叠概率小漏检率明显低。切换后要同步做两件事数据集全部换成头部标注训练分辨率提高到768因为头部目标像素面积比人体小一个量级需要更高分辨率兜底。6.2 用轨迹数据画区域热力图加分检测加跟踪的副产品是每个行人的完整轨迹点序列。把这些轨迹点按坐标聚合用OpenCV的addWeighted叠加到背景图上就能得到一张人流分布热力图。这个可视化在答辩演示时非常加分它直观展示了系统不只是会数数还能看出哪个区域最拥挤。实现上不用复杂的密度估计把轨迹点画到一张黑色画布上做高斯模糊再与原始帧叠加效果就足够好。6.3 计数精度怎么自评才算数给系统下结论之前先做一次手工基准测试。找一段3分钟的现场视频人工逐帧数出实际通过虚拟线的总人数然后跑系统对比输出。误差在正负5%以内算合格超过10%就算不可交付。更严格的做法是用MOT格式的Ground Truth轨迹文件计算MOTA和IDF1IDF1低于70说明ID切换太频繁计数结果就不能全信。这是我从几个项目里总结出来的习惯——评估不看检测mAP只看最终计数误差因为业主根本不在乎mAP是多少他们只想知道今天报上来的数字对不对。希望这篇笔记能帮你把系统的最后一公里走稳也祝你的项目顺利通过。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑