简介:一套基于YOLOv5与Qt5的行人范围超界报警系统完整方案,面向计算机视觉开发者、智能监控项目集成人员及Qt应用学习者,解决实时行人检测、目标区域划定与越界报警联动问题。系统使用YOLOv5从视频流中识别行人,再经Qt5界面实现区域框选、距离计算与报警提醒,模块化结构便于二次开发。压缩包共30个文件,约13.45MB,主要含14个Python源码、11个pyc编译文件、YOLOv5模型权重、Dockerfile部署配置、模型参数yaml及Qt界面ui文件,覆盖数据加载、模型推理、损失计算、UI交互等环节;pyc文件可直接调用,yaml用于参数调整,ui用于界面布局。已有2207人学习浏览,该方案适用性经过验证。配合预训练权重可快速搭建演示环境,Dockerfile有助于统一复现测试,适合需要掌握目标检测系统落地流程或扩展行人越界报警功能的开发者参考,也可根据监控场景调整区域与阈值。
1. 这个 zip 包到底给了你什么:开箱即跑的行人超界报警
先说结论:yolov5 行人范围超界报警.zip本质上是一个“检测 + 业务判定”二合一的工程包,前半段是 YOLOv5 推理,后半段是判断“行人落脚点是否越过你划定的安全区域”,越界就触发报警。它适合两类人:一类是做园区周界、工地危险区、仓库禁入区监控的工程师,想先拿现成包跑通流程;另一类是刚接触 YOLOv5 的开发者,需要一个能交代得过去的毕设或 Demo。真正的难点不在 YOLOv5 本身,而在超界判定怎么做得不误报、不抖动、能和现场设备对接。
2. 先把 zip 变成能跑的检测服务:环境配置与最小验证
2.1 解压前先做的事:查伪加密、清路径、确认权重在不在
先别急着双击解压。这类打包工程落地后 70% 的报错都出在解压和路径上,其中最常见的三个:压缩包带了“伪加密”标志、项目路径里有中文、以及解压后才发现权重文件缺失。
伪加密是 zip 格式里一个很经典的状态:文件头把加密标志位置位了,但实际没有用密码加密任何数据。表现是 Windows 自带解压工具弹窗要密码,但随便输入一串字符又能解出来。遇到这种情况,我一般先拿 7-Zip 打开这个 zip,如果能看到文件名但不能直接预览内容,再考虑是不是伪加密。处理办法是用 7-Zip 重新执行一次“压缩并替换”操作,或者右键“添加到压缩包”,在压缩选项里把“加密文件名”去掉重新打一次包,内部数据不受影响。
另一个更隐蔽的坑是路径。这个 zip 解压出来的顶层目录经常叫“yolov5行人范围超界报警”,这一串中文在 Windows 上问题不大,但 YOLOv5 里很多相对路径拼接、OpenCV 读取视频、PyTorch 加载权重都会因为非 ASCII 路径出莫名奇妙的错。我建议解压后立刻改成一个纯英文目录:
unzip yolov5行人范围超界报警.zip -d YOLOv5_Pedestrian_Alarm cd YOLOv5_Pedestrian_Alarm ls -launzip的-d参数指定目标目录,这里直接把它释放进YOLOv5_Pedestrian_Alarm。ls -la是为了看一眼目录结构,重点确认三样东西:weights/下面的.pt权重文件在不在、根目录有没有detect.py或等价的主入口脚本、以及requirements.txt是不是完整的。很多分享出来的 zip 包会漏掉权重,因为.pt文件体积大、网盘容易失败。权重缺失时先别急,YOLOv5 官方 Release 里有对应版本的yolov5s.pt,按你包里的 YOLOv5 版本号找同版本权重放回去就行。
如何判断这个 zip 对应哪个 YOLOv5 版本?我一般是先翻requirements.txt里的 torch 约束范围,再看根目录是不是官方仓库裁剪出来的结构。v5.0、v6.0、v7.0 的源码差异不小,跨版本混用会出现维度不匹配,所以版本必须对齐。如果包内只有几个脚本没有完整仓库,那大概率发布者用的是 v6.0 官方仓库裁剪版,依赖也按 v6.0 处理就好。
2.2 用 conda 装出可复现的 YOLOv5 环境
环境部分不要图省事直接pip install到 base 环境。这类工程包的依赖版本经常和 YOLOv5 版本绑定,装乱了一次只能重来。常见做法是给这个项目单独开一个 conda 环境,名字就叫yolov5,Python 版本按包内requirements.txt的说明来,如果没有说明就用 3.8,这个版本在多数 YOLOv5 版本上都稳定。
conda create -n yolov5 python=3.8 -y conda activate yolov5 pip install -r requirements.txtconda create -n yolov5 python=3.8 -y里的-y是跳过确认提示,脚本化执行时不会卡住。为什么用 conda 而不是 Docker?Docker 在 Windows 上要依赖 WSL2,在国产化服务器上兼容性又参差不齐;conda 是 Python 项目里最省心的环境隔离,换机器迁移也容易,conda env export一下就能把依赖带走。
requirements.txt通常只列了 opencv-python、numpy、matplotlib、seaborn 这些纯 Python 依赖,不包含 PyTorch。PyTorch 需要单独按你机器的 CUDA 版本来装,这一步建议去 PyTorch 官网选对应版本,生成命令后复制到终端执行。注意不要用pip install torch这种不带版本来源的写法,它会拉到当前默认的 CPU 版或和 CUDA 不匹配的版本,后面跑检测会慢到怀疑人生。
装完依赖后先做一次烟雾验证:
python -c "import torch; print(torch.__version__, torch.cuda.is_available())"输出的True表示 CUDA 可用,False的原因不是没装 CUDA 版 PyTorch,就是机器本身没显卡。没有独立显卡也一样能跑这个项目,就是推理帧率会很难看,CPU 上跑 640x640 的输入大概在 1 到 3 FPS,做单路报警够用,做实时多路监控就吃力。
提示:conda 环境创建后如果
pip install -r requirements.txt报依赖冲突,逐条放宽版本号比重新建环境快,最常见是opencv-python版本拉高了最低要求,降到 4.5 系列能解决大多数问题。
2.3 最小命令:先跑通官方的 detect.py 再做报警
环境就绪后,第一件事不是直接运行里面的报警主程序,而是先用 YOLOv5 自带的detect.py跑一张测试图,把“检测链路”和“报警链路”分开验证。如果一上来就点那个报警主程序,出问题时你会分不清到底是模型没加载、还是区域判定代码有 bug。
python detect.py --weights weights/yolov5s.pt --source data/test.jpg --conf-thres 0.35 --classes 0--weights指定权重文件;--source可以是图片、视频文件、摄像头编号(0表示第一个摄像头)或目录;--conf-thres 0.35是置信度阈值,低于 0.35 的检测结果会被直接丢掉;--classes 0是关键参数,COCO 数据集中第 0 类就是 person,只保留行人可以大幅减少“检测到别的物体也报警”的干扰。
跑通后,你要在runs/detect/exp/目录里看到那张画了检测框的测试图。这个命令背后的意义是把 YOLOv5 推理和后处理(NMS、类别筛选)验证完毕。确认检测框稳定之后,再进入超界报警的逻辑部分,这时候你手里的 YOLOv5 就从一个“黑匣子”变成了一个可以接业务判定的检测源。
预算够的话,直接拿现场视频验证更稳。把--source换成视频文件路径,启动后按q键退出、不要用 Ctrl+C 强杀,否则 OpenCV 的视频流对象可能残留未释放资源,下次跑摄像头时出现无法打开设备的报错。
3. 超界报警的判定逻辑:在检测结果上画一条看不见的线
3.1 原理:检测 + 区域判定是后处理,不是改模型
很多人拿到这个 zip 会误以为“行人超界”是 YOLOv5 模型自己学会的能力,其实不是。YOLOv5 只负责输出“画面里哪里有行人”,输出形式是矩形框坐标(x1, y1, x2, y2)、置信度和类别。至于这个框是否越界、要不要报警,是模型之外的业务逻辑,业界叫它后处理。这个 zip 里真正值钱的可能不是检测部分,而是超界判定那几十行代码。
常见做法是先在画面里定义一块安全区域,叫 ROI,可以是矩形也可以是不规则多边形,对应监控画面里的围墙边界、生产线警戒线、停车场出入口。检测到行人后,取行人框上的某个代表点,最常用的是脚点(中心x, y2),因为人站在地面上,脚点位置比框的中心更贴近“人是否进入区域”的物理事实。拿到这个点后判断它是否落在 ROI 内,落在外部就叫超界,触发报警。整个过程不涉及任何模型改动,所以这个 zip 只在推理阶段依赖 YOLOv5,业务判定阶段只依赖 OpenCV 的几何函数。
这个设计对工程落地的价值在于:检测模型和告警规则完全解耦。现场要换警戒区域,只改 ROI 坐标;要改误报灵敏度,只调判定帧数和阈值;将来要升级检测模型,报警逻辑一行不用动。这也是为什么我会把“超界判定”单独抽成一个模块,而不是写死在主循环里。
3.2 把检测结果接进区域判定:ROI 定义与 pointPolygonTest
下面这段代码是这个项目最核心的业务逻辑:输入 YOLOv5 的检测结果,输出越界行人的坐标列表。det_boxes是推理后处理完的结果,每个元素是[x1, y1, x2, y2, conf, cls],这个结构从 YOLOv5 的detect.py或你自己封装的推理函数里都能拿到。
import cv2 import numpy as np # 多边形 ROI:四个顶点按顺时针或逆时针给出,单位是像素坐标 roi = np.array([[100, 400], [600, 350], [800, 500], [200, 600]], dtype=np.int32) def point_in_roi(x, y, roi_points): # pointPolygonTest 返回 1 表示在多边形内,0 在边上,-1 在外部 return cv2.pointPolygonTest(roi_points, (float(x), float(y)), False) def judge_violation(det_boxes, roi_points=roi): violations = [] for *xyxy, conf, cls in det_boxes: if int(cls) != 0: # 只处理 person 类 continue x1, y1, x2, y2 = [int(v) for v in xyxy] foot_x = (x1 + x2) // 2 # 脚点中心 x foot_y = int(y2) # 框底边 y 当作脚点 y if point_in_roi(foot_x, foot_y, roi_points) < 0: violations.append((foot_x, foot_y, float(conf))) return violations这段代码里有两个值得留意的选择。第一是取脚点而不是框中心点:如果取中心点,行人站在安全区域边缘、半个身体探出去时就会触发报警,而在很多工厂场景里“探身”并不算违规,误报率会明显升高;取脚点则更接近真实的行为意图。第二是pointPolygonTest的第三个参数False,它表示不做距离计算、只返回位置关系,性能开销极小,一路视频流上每帧调用几百次都没有压力,这也是我推荐用它的原因,比手写射线法省心。
ROI 坐标不是靠猜的。我的做法是打开一张现场画面截图,用 OpenCV 的鼠标回调函数把多边形顶点坐标逐个点出来,打印到终端再填进配置文件。部署阶段可以先用 matplotlib 把 ROI 和行人框叠在一张图上,肉眼看一遍顶点是不是落在警戒线外侧,再交给代码跑,这一步能省掉大量反复调试。
有了violations列表,报警就简单了:len(violations) > 0就说明当前帧有行人越界。但这里必须引入“去抖”逻辑,也就是连续若干帧都检测到越界才真正报警。因为单帧的检测框本身有抖动,行人站在边界附近时,框底边会来回跳动,造成“报警-恢复-报警”的闪烁。我一般取 3 到 5 帧连续命中作为触发条件,这个参数后面单独说。
3.3 报警输出:本地弹窗、蜂鸣器与消息推送三条路
判定出越界之后,报警动作是另一个容易被低估的部分。最朴素的做法是在画面上把越界行人的框标红、正常行人标绿,这是给监控室值班员看的;稍微正式一点的工程会加声音告警,要么是 PC 蜂鸣器,要么是树莓派 GPIO 接一个有源蜂鸣器;再往上就是消息推送,把告警截图或文字推到钉钉、企业微信的机器人 Webhook,让不在监控室的人也能第一时间知道。
import requests def push_alarm(message, webhook_url): payload = {"msgtype": "text", "text": {"content": message}} # timeout 必须给,推送服务故障时不能让检测主循环卡住 requests.post(webhook_url, json=payload, timeout=5)这段推送代码里的timeout=5是我踩过坑之后保留下来的习惯。现场网络偶尔抖动,如果请求长时间挂起,检测线程会被requests.post阻塞,画面帧率掉下来,告警延迟。更稳的写法是把推送放进独立线程或消息队列,但大多数单路监控场景用timeout=5加“推送失败打印日志”就够了,不必为了这个单独引入消息队列中间件,那会让部署复杂度上升一个量级。
推送内容里我建议带上三样信息:触发时间、越界行人的置信度、以及当前帧截图。截图是在报警瞬间保存一张 JPEG,方便事后追查“到底是谁越界”,也方便验证报警的准确性。置信度则能帮你判断这次报警是否可信:如果报警时置信度只有 0.36,刚好卡在阈值边缘,那就该考虑是调高阈值,还是边框抖动造成的误判。
4. 想用自己的场景:训练行人模型与超参数解释
4.1 行人数据集准备:标注格式与类别筛选
这个 zip 里如果自带的是 COCO 预训练权重,直接跑通用行人检测问题不大。但现场场景一旦偏离常规——比如摄像头是俯视角度拍的工地,或者晚上红外补光的园区——预训练权重的表现会肉眼可见地下降。这时候需要训练自己的行人模型,第一步是准备数据集。
YOLOv5 的训练数据格式是每个图片对应一个同名.txt标注文件,放在labels/下,内容一行一个目标:cls cx cy w h,其中cx、cy、w、h都是归一化到 0 到 1 的浮点数。标注工具用 labelImg 最多,输出就是这种格式。注意类别编号要从 0 开始,如果你的数据集只有行人一类,这个编号永远写0。
dataset/ ├── images/ │ ├── train/ │ │ ├── frame_0001.jpg │ │ └── frame_0002.jpg │ └── val/ │ ├── frame_1001.jpg │ └── frame_1002.jpg ├── labels/ │ ├── train/ │ │ ├── frame_0001.txt │ │ └── frame_0002.txt │ └── val/ │ ├── frame_1001.txt │ └── frame_1002.txt └── data.yamldata.yaml里写三项:train 和 val 路径、类别数量、类别名。对纯行人场景就是nc: 1、names: ['person']。标注质量比数量重要,漏标的目标会在训练时被当作背景,模型会在那个位置上学会“假装看不见”,这种错误后面很难纠正。所以我的习惯是每批图标注完,抽 10% 让第二个人过一遍,宁可少标的重新补,也不要带错误标签进训练。
采样策略也要讲一下:从现场录像里抽帧,每 10 秒取一帧,尽量覆盖上午、下午、傍晚、夜晚不同时段,晴天雨天都要有。俯视机位的行人标注框要紧贴人头肩区,不要硬套全身框,因为俯视画面里模型根本看不到腿,全身框反而会把背景学进来,导致检测框忽大忽小。
这里有个细节:这个 zip 里如果只给了推理代码,没有训练代码,就把data.yaml和images/labels目录按上面的样子准备好,再拷贝 YOLOv5 官方仓库的train.py进来即可。YOLOv5 的源码和权重版本要一一对应,用 v6.0 的源码就去匹配 v6.0 的权重,跨版本混用会报维度不匹配或者最终效果诡异。
4.2 超参数怎么调:conf_thres、iou_thres、imgsz 对误报的影响
训练完成之后,真正影响体验的不是 epochs 和 batch-size,而是推理阶段的三个参数。很多人在这个 zip 里改来改去都不知道自己在改什么,我先把它们拆开讲清楚。
conf_thres是置信度阈值,YOLOv5 会输出每一个候选框的置信度,低于这个值的都丢掉。它的值越大,误报越少,但漏报也越多。做行人超界报警时,我一般从 0.35 起步,现场误报多就往上加到 0.45,漏报多就降到 0.25。iou_thres是 NMS 的 IoU 阈值,决定重叠的框算一个还是算两个。行人目标彼此挨得近时,iou_thres设置太小会把人合并成一个框,设置太大会出现一个行人被套两三个框,框抖动就加重,建议 0.45 到 0.5。imgsz是输入分辨率,默认 640,如果摄像头画面里行人只占 30 个像素,640 基本检测不到,要提到 960 或 1280 才能稳定出框,代价是推理耗时几乎翻倍。
| 参数名 | 推荐范围 | 对超界报警的影响 |
|---|---|---|
| conf_thres | 0.25 - 0.45 | 调大减少误报,调小减少漏报 |
| iou_thres | 0.45 - 0.5 | 过小合并行人框,过大导致重复框 |
| imgsz | 640 / 960 / 1280 | 行人像素少时必须要加大,速度线性下降 |
python train.py --data dataset/data.yaml --weights yolov5s.pt --epochs 100 --batch-size 16 --img 640训练命令本身不复杂,--weights yolov5s.pt表示在 COCO 预训练权重的基础上继续训练,这叫迁移学习,小数据集上能比从零训练节省一半以上的收敛时间。--epochs 100是个比较稳妥的起点,我在 2000 张行人数据上做到 80 轮后 loss 基本就不再下降,100 轮足够看到趋势。训练结束看runs/train/exp*/下的results.png,如果验证集的mAP@0.5能达到 0.85 以上,这个模型接回报警项目里就比直接用 COCO 权重踏实得多。
要铺到树莓派这类边缘设备时,训练完的模型建议转成yolov5n或者 TensorRT 格式,推理前把imgsz降到 416 甚至 320。精度会掉,但换来的是帧率从 1 FPS 拉到可用的 10 FPS 以上,报警项目先保证“响”,再保证“准”。
提示:更换权重文件后如果输出一堆形状奇怪的框,优先怀疑权重和当前 YOLOv5 源码版本不匹配,对齐版本再排查逻辑,不要先去调 NMS 参数。
5. 从解压到现场:5 个高频踩坑与排查记录
5.1 解压与路径问题:伪加密、坏包与中文目录
现象:Windows 解压时弹“需要密码”,或者 Linux 上unzip提示cannot find zipfile directory。原因:一是伪加密,文件头加密位被置位但没有实际加密;二是压缩包本身在传输中断裂,尾部目录缺失。解决:先换 7-Zip 打开,能列出内部文件就说明只是伪加密,重新打包即可;如果 7-Zip 也打不开,找发布者重新要一份,比折腾修复工具省时间。这类 zip 包从网盘分享出来经常出现传输问题,不要为了个坏包浪费时间。
现象:解压后运行报ModuleNotFoundError,依赖明明装完了还是报错。原因:项目路径里带了中文,Python 的sys.path在拼接脚本目录时对非 ASCII 路径支持不好,import 模块找不到包。解决:把整个项目挪到纯英文、无空格的路径下,比如D:\workspace\YOLOv5_Pedestrian_Alarm,重新解压或者直接移动文件夹,再跑一次主程序。
5.2 检测结果不稳定:阈值抖动与夜间光照
现象:行人站在原地没动,框底边一会儿在线内一会儿在线外,报警响一下停一下。原因:YOLOv5 对同一行人的输出框本身有像素级抖动,脚点 y 坐标在边界附近摆动,pointPolygonTest的结果就来回翻转。解决:不要用单帧判定,改成连续 3 到 5 帧都越界才触发。如果加了去抖还是频繁,就调高conf_thres,把那些置信度低、位置不稳定的框过滤掉。我一般在核心区域用 5 帧去抖,边缘区域才用 3 帧,去抖帧数不建议超过 10,否则快速跑过警戒区的人根本触发不了报警。
现象:白天测试一切正常,傍晚之后开始疯狂误报或者漏报。原因:YOLOv5 训练数据大多是白天场景,夜间行人对比度低,检测置信度整体下降;如果摄像头自动曝光,晚上画面噪点还会被模型误认成人形。解决:固定摄像头位置后关闭自动曝光,开启宽动态模式,夜间场景补一盏红外灯。代码里按时间段切换置信度阈值只能缓解,最靠谱的方向还是收集夜间样本加入训练集,这正是第 4 章那个方案的用武之地。
5.3 报警链路问题:类别过滤与坐标系错位
现象:画面上行人被框住了,violations却一直为空。原因最可能有两处:一是取检测结果时没有过滤cls,把类别 0 当成了 person,而 COCO 里 person 的类别就是 0,如果包内模型换成了别的数据集,类别编号就不一样了,需要先打印cls看看;二是roi的坐标和图像尺寸对不上,比如 ROI 是按 1920x1080 的原始图画的,但推理时图像被缩放到 640,坐标全偏了。解决:在judge_violation入口打印一行(cls, xyxy),比对框坐标范围和 ROI 坐标范围是否在同一量级。如果差很多,就按640 / 原图宽的缩放比例把 ROI 顶点换算回来。
这类坐标错位的坑最隐蔽,因为它不报错,只是永远不报警或永远报警。调试时把检测框和 ROI 画到同一张图上输出保存,一眼就能看出坐标基准是不是一样的。
6. 进阶:把超界报警升级成跨线轨迹报警
6.1 给行人分配 ID:接入跟踪器
区域超界报警的天然局限是:行人站在警戒线外时也会报警,哪怕他只是路过。更贴近业务的做法是跨线报警——人从一侧跨到另一侧才触发。这需要先给每个行人一个稳定的 ID,用 ByteTrack 或 DeepSort 这类跟踪器给每帧的检测框分配 ID。YOLOv5 官方仓库里没有集成跟踪器,常见做法是把推理帧传入跟踪器,跟踪器输出带 ID 的框,然后按 ID 记录每一帧该行人的脚点位置。
6.2 跨线判定的向量叉积
有了 ID 并按 ID 维护“上一帧在哪一侧”之后,判定就变成一个向量叉积问题。假设警戒线由两点a、b定义,行人脚点是p,叉积的符号表示 p 在线的哪一侧。上一帧为正、这一帧为负,说明这个人真的跨过了线。
def cross_line_side(p, a, b): # 返回正值表示 p 在 ab 直线一侧,负值表示另一侧 return (b[0] - a[0]) * (p[1] - a[1]) - (b[1] - a[1]) * (p[0] - a[0])配合跟踪器,维护一个dict: track_id -> last_side。每帧更新时用叉积先算当前侧,再和上一次的值比较,符号翻转就报警。这个做法比区域超界判定多了一个维度,误报率明显下降,因为它不再关心“站在线外的人”,而只关心“跨线的人”。
6.3 从视频回放到业务台账
验证和交付不要止步于“能跑”。我会在报警代码里顺手写一个 CSV 记录文件,字段是时间、track_id、跨线方向、置信度、触发帧号。调优时打开 CSV 和原视频回放逐帧对比,一眼就能看出是哪一帧误判。这也是我有别于“跑通就撒手”的习惯:任何报警系统,没有台账就等于没有发生过,回看不了的历史,出了问题也无从追责。拿到类似的项目包时,先跑通、再做区域判定、最后如果现场需要,把跨线逻辑带上。这套路径走下来,方向就对了,希望帮到你。
本文还有配套的精品资源,点击获取