
简介基于YOLOv9的行人识别检测计数系统完整项目面向计算机视觉方向的在校学生、研究者及企业开发人员适合毕业设计、课程设计或实际安防场景快速落地。项目内置训练好的模型权重与评估指标曲线可直接加载权重进行推理也可按教程训练自有数据集解决行人目标检测与计数需求。压缩包共186个文件大小约62.46MB以83个Python源码文件、30个YAML配置、27张示例图片和3个PyTorch模型权重为主另含XML标注、CSV评估结果、IPython Notebook及说明文档源码中训练、验证、推理模块划分清晰便于二次开发与算法研究。目前已有237人学习下载。资源附详细运行教程涵盖从环境配置、数据准备、配置文件修改、训练参数调整到测试评估的全流程并提供yolo格式数据集准备指引帮助使用者从零掌握YOLOv9行人检测系统的搭建与调优无论是做课题还是投入实际项目都颇具参考价值。1. YOLOv9行人检测计数系统一套开箱即用的目标检测落地项目商场出入口的客流统计、园区通道的人员数量管控、学校教室的到课率统计背后都离不开同一件事把画面里的“人”找出来并数清楚。这个项目标题给你的正是一条完整链路——YOLOv9模型负责行人识别python源码里写好了检测和计数逻辑训练好的模型让你无需从零训练评估指标曲线则直接回答了“这个模型到底靠不靠谱”。对想快速跑通一个行人检测计数系统的开发者来说这是互联网上最典型的、也最值得先动手复现的一类源码包。适合刚入门目标检测的学生也适合需要在几天内做出原型验证的算法工程师。拿到手先别急着训练先把推理跑通再谈优化。2. 为什么是YOLOv9模型选型与运行环境搭建2.1 YOLOv9相比YOLOv8/YOLOv5胜在哪可编程梯度信息与GELANYOLOv9的核心卖点是引入了可编程梯度信息PGI和GELAN网络结构。用大白话说深层神经网络在反向传播时越往浅层走梯度信号越容易丢失或被污染导致浅层学不到东西。YOLOv9用PGI把梯度路径拆成多条可学习的支路让浅层也能拿到干净有效的梯度GELAN则是对推理速度做了优化的特征融合结构在同等算力下能拿到更高精度。对于行人检测这个具体场景YOLOv9的价值在于它同时照顾到两类需求一是行人是中小尺度目标需要较好的浅层特征来抓边缘和轮廓二是实际落地在监控视频流里帧率必须够快。YOLOv9的c规格和e规格模型在精度上比YOLOv5/v8同期版本有明显余量但推理成本并没有成倍上涨。项目包里如果直接带的是训练好的YOLOv9权重那选型逻辑基本已经替你定好你只需要关注这个模型在你的显卡上能不能跑得动。2.2 搭运行环境Conda、PyTorch与CUDA版本匹配的落地选择不管源码包是从哪里下载的环境装不好后面每一步都白搭。我一般会先用Conda建一个干净的独立环境避免和系统自带的Python版本打架。这里强烈建议不要用Windows系统的默认Python因为项目依赖的torch、opencv-python等包在Conda环境下出问题的概率会低很多。conda create -n yolov9 python3.10 -y conda activate yolov9 pip install -r requirements.txtrequirements.txt里通常会列torch、torchvision、opencv-python、pandas、pyyaml、matplotlib、seaborn、onnx这些包。装完之后第一件事不是急着运行而是确认GPU能被PyTorch识别python -c import torch; print(torch.__version__, torch.cuda.is_available(), torch.cuda.get_device_name(0))这一段代码的逻辑是验证两件事cuda.is_available()是否为True以及识别到的显卡型号是否符合预期。如果输出False说明安装的torch是CPU版本与CUDA不匹配需要根据显卡驱动版本重新安装匹配的torch。常见的翻车现场是装上了最新版torch但显卡驱动老旧导致CUDA运行时找不到设备。此时往往要退回torch 2.x早期的对应版本而不是追求最新。依赖方面还有一个老坑需要注意opencv-python和numpy的版本冲突。当你运行的时候突然报出与numpy相关的无法加载动态库错误通常是因为numpy版本过高把numpy降到1.24.x以下往往能解决。这不是玄学而是opencv-python的编译环境与新版numpy的ABI兼容问题。2.3 拿到源码包先做这三件事目录结构确认、权重校验与首轮冒烟测试免费源码包下载下来首先不要急着打开编辑器看代码而是先确认目录结构。一个结构完整的目标检测项目根目录下至少应该有train.py、val.py、detect.py三个入口脚本以及data、weights、runs等目录。如果缺少detect.py说明源码包被删改过如果weights目录下没有.pt文件那“训练好的模型”这一项就是缺失的。目录结构确认后先用校验和或文件大小确认权重文件完整。很多下载中断过的权重文件表面存在加载时才报错。最后做一次冒烟测试准备一张包含行人或者只有人的jpg图片跑一行最简命令能输出结果就说明环境、权重、源码三者匹配正常。这一步能帮你快速区分问题出在环境还是代码而不用通篇看代码陷入死循环。3. 加载训练好的模型做行人检测与计数推理命令、三组参数与计数逻辑3.1 用detect.py做第一轮推理读视频还是读图片源码包里的模型既然已经训练好第一轮推理直接走项目自带的detect.py就好。它的运行方式与YOLOv5/YOLOv9官方仓库保持一致。如果你下载的源码包是基于ultralytics风格封装的入口也仍是detect.py只是内部调用方式有差异。先跑图片再到视频这样排错最快。python detect.py --source test.jpg --weights weights/best.pt \ --conf-thres 0.5 --iou-thres 0.45 --imgsz 640 \ --device 0 --half这是一条典型的YOLOv9官方repo风格推理命令。--source指定输入图片来源可以是图片文件、视频文件也可以是摄像头设备号--weights指向项目自带的训练好的模型权重--half开启半精度推理在支持FP16的N卡上能明显加速。运行结束后标注好的图片会输出到runs/detect/exp目录下打开看行人是否被正确框住。这里要注意如果你用的是ultralytics接口安装的YOLOv9权重直接换一种写法等价实现from ultralytics import YOLO model YOLO(weights/best.pt) # 加载训练好的模型 results model(test.jpg, conf0.5, iou0.45, imgsz640) results[0].show() # 显示标注结果两种方式都可行选择哪个取决于你拿到的源码包基于官方repo还是ultralytics框架。我的习惯是优先用项目自带脚本因为它的默认参数和权重是配对调好的出问题的面更窄改用自己的脚本反而需要重新对齐参数。3.2 置信度、NMS与输入尺寸三个直接影响结果的参数三组参数直接决定这套行人识别系统的表现分别是置信度阈值conf-thres、NMS交并比阈值iou-thres和输入分辨率imgsz。参数没调好再好的训练好的模型也白搭。参数取值范围建议作用调小后调大后conf-thres行人场景0.3~0.6过滤低置信度检测框召回率上升、误检增多误检减少、漏检增多iou-thres0.4~0.6合并重叠框同一行人可能出现多框密集重叠行人被合并漏掉imgsz640或1280输入网络的分辨率推理变快、小目标易漏小目标召回变好、显存消耗大在行人检测里我一般不建议把置信度拉到0.7以上行人互相遮挡、姿态多样模型本身输出的置信度就在0.3~0.6区间密集分布。最合理的做法是先看模型生成的PR曲线和F1曲线找最佳阈值后面第4章会讲再根据现场接受误报还是漏报做微调。如果你发现同一个行人同时被框了两三个框通常就是iou-thres设得过大导致NMS没有有效合并反过来密集场景里两三个人被压成一个框则是iou-thres太小把所有重叠框都当成了同一个目标。输入分辨率imgsz是很多人忽略的关键变量。训练好的模型如果用的是640分辨率你推理时硬上1280不一定提升精度因为目标分布和特征尺度是按640学的。但如果视频里的行人普遍偏小把imgsz提到960或1280会带来明显收益前提是你的显存扛得住。3.3 从检测框到计数值瞬时计数、区域计数与跨帧去重检测框有了计数逻辑才是这个项目真正的工作量所在。如果你看过opencv硬币检测与计数的例子会记得那套阈值分割加轮廓计数的思路但在行人场景里完全不成立行人是动态的、互相遮挡的、尺度变化的必须基于检测框做跨帧管理而不只是对单帧画面数框。最常见也是最容易翻车的是“瞬时计数”直接把当前帧的检测框数量当作人数。这在人流较少、摄像头固定的场景下还能用但一旦有人在画面中停留、来回走动计数值就会反复跳变。所以稍微完善一点的系统至少要支持区域计数设定一个ROI多边形只统计检测框中心点落在区域内的目标数量。下面的代码演示了用检测框中心点做ROI过滤的核心逻辑适用于在detect.py输出结果后做二次计数import cv2 def point_in_polygon(point, polygon): # 用OpenCV的点在多边形内判断函数 return cv2.pointPolygonTest(polygon, point, False) 0 def count_person_in_roi(boxes, roi): # boxes为模型输出的检测框列表每个框格式为[x1, y1, x2, y2] count 0 for box in boxes: x1, y1, x2, y2 box center ((x1 x2) / 2, (y1 y2) / 2) if point_in_polygon(center, roi): count 1 return count这段代码的要点在于用“检测框中心点”而不是“检测框本身”来判断是否属于区域内这样行人在边界上稍微跨一步计数结果不会剧烈抖动。实际项目里ROI可以预先用鼠标在画面里点出来存成多边形顶点列表运行时加载即可。真要落地到“进出人数统计”级别还需要跨帧去重。最简单的常见做法是保存上一帧的检测框用当前帧每个框与上一帧所有框的中心点距离做最近邻匹配距离小于阈值就认为是同一人只更新位置不增加计数只有匹配不上超过一定帧数的新目标才计为新进入。这种做法在遮挡不严重、帧率稳定15FPS以上的情况下表现足够稳定比直接引入DeepSORT轻量得多也更容易维护。4. 训练自己的行人检测模型数据准备、训练命令与评估指标曲线4.1 行人数据集怎么选COCO Person、VOC Person与CrowdHuman如果你不想直接用项目自带的训练好的模型或者需要针对自己的场景比如俯视角度、夜间场景、密集人流重新训练那第一步是选择或标注数据集。行人检测最常用的三个公开数据集方向如下。COCO数据集里的person类别是最稳妥的基础选择类别覆盖了各个姿态、尺度、遮挡情况适合做通用行人检测的预训练起点。Pascal VOC的person类规模较小作为微调数据没问题但单独从头训练效果偏弱。CrowdHuman是专门面向密集行人场景的数据集行人密度高、遮挡严重如果你要做的场景是商场门口、闸机口这类人流密集区域用它微调会明显比COCO person更贴合但也更容易过拟合到特定相机视角需要配合自己场景的数据混训。如果使用自己的视频数据需要标注成YOLO格式即每个目标一行标注class_id, x_center, y_center, width, height坐标归一化到0~1。标注工具常见做法是labelImg或X-anyLabeling导出为YOLO格式后按8:1:1划分训练集、验证集和测试集。4.2 训练命令与关键参数epochs、batch-size、imgsz与预训练权重的关系训练前先把数据配置好。YOLOv9官方repo风格的数据配置文件是一个yaml里面指定训练集路径、验证集路径和类别信息下面是一个只检测行人的最小配置# data/person.yaml train: /home/user/datasets/person_train.txt val: /home/user/datasets/person_val.txt nc: 1 names: [person]train和val这里指向的是txt文件列表每一行是图片的绝对路径这是YOLOv5/YOLOv9官方仓库传统的写法。如果你拿到的是ultralytics版本也可以直接写成train和val指向图片文件夹的路径。两者都能被有效解析。关键点是txt路径最后不要把相对路径和绝对路径混用否则训练到一半报图片读取失败会让人排查半天。数据集就绪后训练命令如下python train.py --data data/person.yaml \ --weights yolov9-c-converted.pt \ --epochs 150 --batch-size 16 --img 640 \ --device 0 --workers 8 --close-mosaic 15 --patience 30--weights这里加载的是YOLOv9在COCO上的预训练权重不是项目里那个专门针对行人训练好的模型。很多人误以为“训练好的模型”就是用来继续训练的其实不然项目自带的best.pt是针对该项目数据集的最终产物拿来继续训练会把自己场景之外的特征固化更合理的做法是拿通用预训练权重做迁移学习用自己的行人数据做微调。--epochs在我做行人检测的经验里150是个比较稳妥的值少于100容易收敛不充分超过300则需要确认你是否加了足够强的数据增强否则会过拟合到训练集的拍摄视角。--batch-size不是越大越好在显存允许范围内取最大即可16在12GB显存上配640分辨率通常是舒服的。--close-mosaic 15表示最后15个epoch关闭马赛克增强这是让模型在训练末期稳定收敛的小技巧建议保留。4.3 评估曲线怎么读P_curve、PR_curve、mAP与F1曲线训练完成后很多人只看一眼mAP就收工这是不完整的。评估命令要先跑一遍python val.py --data data/person.yaml \ --weights runs/train/exp/weights/best.pt --img 640默认输出在runs/val/exp目录下里面有一批关于指标曲线的png文件这些就是源码包标题里“评估指标曲线”的完整来源。读懂这些曲线比看一堆loss数字更能指导你调参。曲线文件内容怎么用results.png训练/验证loss和mAP随epoch变化判断过拟合、欠拟合、收敛点PR_curve.png精确率-召回率曲线看整体检出能力曲线越靠近右上角越好P_curve.png精确率随置信度变化确定可接受的误检上限对应置信度R_curve.png召回率随置信度变化确定漏检可控时的最低置信度F1_curve.pngF1值随置信度变化取F1最大点作为默认置信度阈值实际使用中我习惯先打开F1_curve.png它的峰值横坐标就是一套很合理的初始置信度阈值。如果你的任务更在意不漏人就把置信度从F1峰值点往下调一档更在意不误报就往上调一档。PR_curve则是看这个模型整体上限的如果曲线后半段突然掉到很低说明模型在低置信度区域输出了大量错误框这时候去调置信度阈值解决不了根本要回到数据层面补样本或者换更大的模型规格。如果你发现results.png里验证集loss先降后升而训练集loss还在下降那就是典型的过拟合。此时优先做法是增加数据增强强度、加早停patience或者减少训练epochs重新训练一轮。5. 行人检测计数项目避坑5条来自实测现场的踩坑记录网上这类免费python源码包很多跑不通的原因高度一致跳不出下面这五条。这里按现象、原因、解决的顺序写清能帮你省下至少一个通宵。5.1 加载训练好的模型就报KeyError或size mismatch现象运行detect.py加载权重时直接抛出加载失败的错误提示某些层的键不存在或尺寸对不上。原因最常见的是把YOLOv5或YOLOv8的权重直接塞给了YOLOv9源码或者同一个YOLOv9项目里存在ultralytics导出格式和官方repo原生格式混用的情况。两种权重虽然扩展名都是.pt但序列化结构并不一致。解决确认你加载的权重是从本项目weights目录拿出来的必须换用其它模型时先检查来源是否与代码库匹配。一个高效验证方法是用torch.load加载权重检查state_dict里的层级名称与模型结构打印结果对比。5.2 视频推理速度低得离谱GPU利用率却上不去现象同样的模型别人显卡上跑30帧你的电脑只跑3帧而且显卡占用率只有20%。原因最常见的是detect.py运行在CPU设备上也就是--device参数没传或者传成了cpu其次是没开--half半精度在支持FP16的N卡上损失了两倍以上的吞吐还有可能是source视频文件分辨率太高模型在每帧上被放大了多次。解决明确传入--device 0指定GPU确认驱动支持FP16后加上--half对每秒处理帧数仍不达标的情况比较调低imgsz和调低视频源分辨率的差异再考虑换更轻量的m/s规格模型。5.3 计数结果反复跳变一分钟内人数忽高忽低现象画面没人进出计数器却从5跳到12又跳回6。原因上一帧检测到了人下一帧因为行人转身或遮挡漏检了再下一帧又检到于是被当成了新目标重复累加。这是单帧检测叠加瞬时计数方式最典型的缺陷。解决引入跨帧匹配逻辑用上一帧与当前帧检测框的中心点距离做最近邻匹配距离小于阈值就视为同一个行人继续计数而不累加连续多帧消失才算离开。代码参考第3.3节。如果你的视频帧率低于10帧这个方案会明显吃力需要换用带跟踪的ByteTrack方案。5.4 密集场景一坨人只被框住两三个计数严重偏低现象商场闸口人挤人模型只框出人群边缘的人中间密集部分被漏掉计数只有实际的一半。原因NMS在行人互相遮挡严重时合并了多个目标同时行人在640分辨率下成像太小网络没有足够特征把它们区分开。解决把imgsz从640提高到960或1280把iou-thres从0.45往0.35方向调低减少NMS误合并如果有俯视或密集场景的数据用CrowdHuman数据集的权重先做一轮预训练再微调比直接硬调参数有效得多。5.5 Windows下跑不起来路径反斜杠和编码问题现象代码在Linux上正常在Windows下解压后运行就报找不到文件或读取数据异常有时还出现类似UTF-8编解码报错。原因压缩包解压后路径带中文或空格yaml里的路径使用反斜杠写死Windows默认编码与脚本内UTF-8声明不一致。解决把项目放到纯英文且无空格的路径下例如D:/yolov9-personyaml和txt路径统一使用正斜杠在train.py和detect.py入口处加一行UTF-8编码声明。养成这三个习惯后这个坑基本能绕开。6. 把系统推到现场ONNX导出、TensorRT加速与计数结果上报模型在电脑上跑通只是第一步真正要交付给现场使用还得做两件事把模型部署到目标设备上以及让计数结果能被业务系统读取。模型导出的常见做法是先转成ONNX再按需转成目标推理引擎格式。这个导出过程在你下载的源码包里可以用export.py入口或一句转格式命令完成导出后的ONNX模型可以用ONNX Runtime直接做推理。从实践看如果目标设备是普通工控机或台式机ONNX Runtime加OpenCV的组合已经能覆盖大部分需求如果现场有N卡且帧率要求达到25FPS以上才值得投入时间做TensorRT加速参数量与精度对齐的双重工作量。要注意TensorRT导出的engine文件与显卡型号强绑定换台机器必须重新生成这点在交付文档里要写清。计数结果上报到业务系统常见做法是把每帧的计数结果封装成JSON通过HTTP接口推送或者发到MQTT消息队列里供看板订阅。一组最小可用的上报脚本大致是import requests def report_count(camera_id, count, timestamp): payload {camera_id: camera_id, count: count, ts: timestamp} requests.post(http://server:8080/api/count, jsonpayload, timeout2)这段代码把某一时刻的计数值发给后端服务。实际部署时要注意用独立的线程或进程处理网络上报不要阻塞检测主循环网络抖动时数据要能写入本地缓存文件避免计数丢失。我自己往现场推这套方案三轮后形成的习惯是先保证“断网也能计数”再考虑“联网能上报”顺序反了容易被网络问题拖垮整个系统。希望帮到你。本文还有配套的精品资源点击获取