ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于YOLOv5与OpenCV的校园异常行为识别系统实战

基于YOLOv5与OpenCV的校园异常行为识别系统实战 简介这份资源面向计算机视觉与深度学习方向的毕业设计学生及校园安防系统开发者提供一套智能校园安全监控与异常行为识别的完整项目源码。系统以YOLOv5目标检测算法为核心结合OpenCV完成图像滤波、边缘检测与特征提取等预处理后端基于PyTorch构建并训练模型通过Flask搭建RESTful API供前后端数据交互检测日志、行为记录等数据由MySQL统一存储并融入人脸识别实现身份验证可对打架、侵入、异常停留等行为实时告警。压缩包共20个文件约112KB包含7个txt日志与说明、5个Python脚本、4个Shell运行脚本、3张结果图及1份README覆盖模型训练、实验对比与结果可视化等环节。目前已有64人学习适合作为课程设计或毕业设计的参考方案帮助读者快速理解多组件协同的智能监控体系搭建思路。1. 从一段校园监控录像说起YOLOv5 OpenCV PyTorch 能解决什么凌晨两点宿舍楼走廊的摄像头拍到有人翻越阳台护栏值班室的屏幕上只有实时画面没有人盯着。等第二天保安回看录像事情已经过去六个小时。这是很多学校保卫处的真实困境摄像头装了几百个但真正起作用的只有事后取证这一个功能。基于深度学习与计算机视觉的智能校园安全监控与异常行为识别系统要解决的就是把事后回看变成事中告警——用 YOLOv5 做目标检测OpenCV 做视频流预处理和图像增强PyTorch 做模型训练与推理Flask 暴露后端 APIMySQL 存告警记录和人员轨迹。这套方案适合谁有基本 Python 基础、想做一个能跑起来的计算机视觉落地项目的学生和初级工程师也适合学校信息中心的技术人员想用开源方案搭一套低成本异常行为识别原型。它不追求工业级精度但能让你在两周内从零跑通视频接入→检测→告警→入库的完整链路。下面按我实际搭过的顺序把选型理由、代码、参数和踩过的坑一次讲清楚。2. 技术选型与整体架构为什么是 YOLOv5 而不是 Faster R-CNN2.1 检测模型选型YOLOv5 在校园场景的三个实际优势校园安全监控的核心需求是实时。走廊、操场、食堂这些场景摄像头数量多如果单路推理延迟超过 200ms多路并发就会把服务器压垮。YOLOv5s 在 RTX 3060 上跑 640×640 输入单帧推理约 8-12ms这是它被选中的第一个理由。第二个理由是部署友好。YOLOv5 官方仓库提供export.py一条命令就能导出 ONNX 或 TorchScriptFlask 后端加载后不需要额外依赖。相比之下 Faster R-CNN 虽然精度略高但两阶段检测的推理速度在同等硬件上通常是 YOLOv5 的 3-5 倍而且导出和部署链路更长。第三个理由是训练成本。校园异常行为数据集通常需要自己标注样本量在几千到几万张之间。YOLOv5 支持从预训练权重做迁移学习--weights yolov5s.pt --epochs 100在单卡上几个小时就能收敛到一个可用水平。Faster R-CNN 在同样数据量下更容易过拟合调参也更玄学。注意YOLOv5 和 YOLOv8 的 API 有差异网上很多教程混着写。本文锁定 YOLOv5因为它的 Flask 部署案例最多遇到问题好搜。2.2 整体架构从 RTSP 流到 MySQL 告警记录的五个环节整套系统的数据流是这样的视频接入层OpenCV 的VideoCapture读取 RTSP 流或本地视频文件按固定帧率抽帧。预处理层OpenCV 做 resize、去噪、亮度均衡把图像统一到 640×640。推理层PyTorch 加载 YOLOv5 权重对每帧做目标检测输出类别、置信度、边界框。业务逻辑层根据检测结果判断是否触发异常规则如人员进入禁区多人聚集翻越动作Flask 提供/detect和/alerts接口。存储层MySQL 存告警记录、检测快照路径、时间戳和设备 ID。这个分层的好处是每一层可以独立替换。比如你后面想换 YOLOv8只需要改推理层想换 PostgreSQL只需要改存储层。2.3 环境搭建PyTorch 和 OpenCV 的版本对应关系环境是第一个翻车点。PyTorch 和 Python 版本不对应pip install会直接报错。我一般用 conda 建独立环境conda create -n campus_security python3.9 conda activate campus_security # PyTorch 安装CUDA 11.8 对应版本 pip install torch2.0.1 torchvision0.15.2 --index-url https://download.pytorch.org/whl/cu118 # OpenCV 和 Flask pip install opencv-python4.8.1.78 flask2.3.3 mysql-connector-python8.1.0 # YOLOv5 依赖 pip install -r requirements.txt # 从 YOLOv5 官方仓库获取参数说明python3.9是 YOLOv5 官方推荐的版本3.10 以上在某些 CUDA 版本下会有兼容问题。torch2.0.1对应torchvision0.15.2这两个版本号必须匹配否则import torchvision会报RuntimeError。OpenCV 用opencv-python而不是opencv-contrib-python除非你需要 SIFT 等专利算法。验证安装import torch import cv2 print(torch.__version__, torch.cuda.is_available()) print(cv2.__version__)如果torch.cuda.is_available()返回False先检查显卡驱动再检查 CUDA 版本是否和 PyTorch 编译版本一致。这一步不通过后面训练会慢到无法接受。3. 用 YOLOv5 训练校园异常行为检测模型数据集、参数与评估3.1 数据集准备从校园监控截图到 YOLO 格式标注校园异常行为没有现成的公开数据集需要自己采集和标注。常见做法是从学校保卫处申请脱敏后的监控截图按行为类别分文件夹然后用 LabelImg 标注。标注格式是 YOLO 的 txt 格式每行class_id x_center y_center width height坐标归一化到 0-1。目录结构campus_dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yamldata.yaml内容path: ./campus_dataset train: images/train val: images/val nc: 4 names: [person, fall, climb, gather]参数说明nc是类别数这里定义了 4 类——正常人员、摔倒、攀爬、聚集。类别不要贪多每类至少 500 张标注样本否则模型学不到特征。names的顺序必须和标注时的class_id一致错一个就会导致所有标签错位。3.2 训练命令与超参数YOLOv5 的 batch size 和学习率怎么定训练用 YOLOv5 官方train.pypython train.py \ --img 640 \ --batch 16 \ --epochs 100 \ --data campus_dataset/data.yaml \ --weights yolov5s.pt \ --cfg models/yolov5s.yaml \ --name campus_exp \ --cache参数说明--img 640是输入分辨率校园监控场景下 640 足够再大推理速度会明显下降。--batch 16是显存 8GB 左右的安全值如果报CUDA out of memory降到 8 或 4。--epochs 100配合预训练权重通常够用如果验证集 mAP 在 50 轮后还在涨可以加到 150。--cache把图像缓存到内存加快训练但数据集超过 10GB 时不要开。学习率不用手动设YOLOv5 默认用余弦退火初始lr00.01。如果你发现 loss 震荡厉害可以降到--lr0 0.001。--weights yolov5s.pt是迁移学习的关键从 COCO 预训练权重开始比从头训练收敛快 3-5 倍。3.3 评估指标mAP0.5 到多少才算能用训练完成后runs/train/campus_exp/下会有results.csv和confusion_matrix.png。重点看两个指标指标含义可用阈值mAP0.5IoU0.5 时的平均精度≥ 0.75mAP0.5:0.95多 IoU 阈值平均≥ 0.50Precision查准率≥ 0.80Recall查全率≥ 0.70校园安全场景下Recall 比 Precision 更重要。漏报一个攀爬行为可能意味着一次安全事故误报一次只是保安多跑一趟。如果 Recall 偏低可以降低推理时的置信度阈值--conf 0.25或者增加该类别的训练样本。注意mAP 高不代表实际好用。我遇到过 mAP0.5 到 0.85 的模型在夜间红外画面下几乎全漏。评估时一定要用和实际部署场景一致的验证集包括白天、夜间、逆光、雨雾等条件。4. OpenCV 预处理与 Flask 推理服务从视频流到告警 API4.1 OpenCV 视频抽帧与图像增强的四个关键参数OpenCV 读 RTSP 流的常见问题是缓冲堆积导致画面延迟越来越大。解决办法是设置缓冲区大小并跳帧import cv2 cap cv2.VideoCapture(rtsp://camera_ip:554/stream) cap.set(cv2.CAP_PROP_BUFFERSIZE, 1) # 缓冲区设为 1 帧 frame_count 0 while True: ret, frame cap.read() if not ret: break frame_count 1 if frame_count % 5 ! 0: # 每 5 帧取 1 帧 continue # 图像增强亮度均衡 高斯去噪 frame cv2.resize(frame, (640, 640)) frame cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) frame cv2.GaussianBlur(frame, (3, 3), 0) # 送入推理 results model(frame)参数说明CAP_PROP_BUFFERSIZE1是关键默认缓冲区可能积压几十帧导致你看到的画面是几秒前的。frame_count % 5是抽帧策略25fps 的流每 5 帧取 1 帧等效 5fps对异常行为识别足够同时把推理负载降到 1/5。GaussianBlur的核大小(3,3)是经验值太大如 7×7会模糊小目标导致漏检。4.2 Flask 后端/detect 接口的请求格式与返回结构Flask 负责把推理能力暴露成 HTTP API方便前端或其他系统调用from flask import Flask, request, jsonify import torch import cv2 import numpy as np app Flask(__name__) model torch.hub.load(ultralytics/yolov5, custom, pathbest.pt) model.conf 0.25 model.iou 0.45 app.route(/detect, methods[POST]) def detect(): file request.files[image] img_bytes file.read() img cv2.imdecode(np.frombuffer(img_bytes, np.uint8), cv2.IMREAD_COLOR) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) results model(img) detections results.pandas().xyxy[0].to_dict(orientrecords) alerts [d for d in detections if d[name] in [fall, climb, gather] and d[confidence] 0.5] return jsonify({ detections: detections, alerts: alerts, alert_count: len(alerts) }) if __name__ __main__: app.run(host0.0.0.0, port5000, threadedTrue)参数说明model.conf 0.25是置信度阈值低于这个值的检测框会被丢弃。model.iou 0.45是 NMS 的 IoU 阈值控制重叠框的合并。threadedTrue让 Flask 支持多线程否则并发请求会排队。返回结构里alerts只包含异常类别且置信度大于 0.5 的检测业务系统可以直接根据alert_count决定是否触发告警。4.3 MySQL 告警记录表设计与写入逻辑告警记录表设计要考虑查询效率。我一般建两张表alerts存告警事件detections存每帧的原始检测结果。CREATE TABLE alerts ( id INT AUTO_INCREMENT PRIMARY KEY, camera_id VARCHAR(50) NOT NULL, alert_type VARCHAR(20) NOT NULL, confidence FLOAT NOT NULL, snapshot_path VARCHAR(255), detected_at DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_camera_time (camera_id, detected_at), INDEX idx_type (alert_type) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;参数说明camera_id用 VARCHAR 而不是 INT因为实际部署中摄像头编号可能带字母前缀。idx_camera_time复合索引支持查某个摄像头某时间段的告警这个最高频查询。snapshot_path存告警截图路径不要直接把图片存进数据库会迅速膨胀。写入逻辑放在 Flask 的/detect接口里检测到异常时插入记录import mysql.connector def save_alert(camera_id, alert_type, confidence, snapshot_path): conn mysql.connector.connect( hostlocalhost, userroot, passwordyour_password, databasecampus_security ) cursor conn.cursor() cursor.execute( INSERT INTO alerts (camera_id, alert_type, confidence, snapshot_path) VALUES (%s, %s, %s, %s), (camera_id, alert_type, confidence, snapshot_path) ) conn.commit() cursor.close() conn.close()注意生产环境不要在每个请求里新建数据库连接用连接池。mysql-connector-python可以用pooling.MySQLConnectionPool或者换 SQLAlchemy。5. 避坑与排查部署这套系统时最容易翻车的五个地方5.1 坑一OpenCV 读 RTSP 流延迟越来越大现象程序跑了几分钟后画面比实时慢十几秒而且越来越慢。原因VideoCapture默认缓冲区会积压未处理的帧如果推理速度跟不上视频帧率缓冲区就无限增长。解决设置CAP_PROP_BUFFERSIZE1并且用独立线程读帧、主线程推理读帧线程只保留最新一帧。如果还不行用ffmpeg命令行拉流再转本地端口OpenCV 读本地流延迟更可控。5.2 坑二PyTorch 模型加载报 No module named models现象torch.hub.load(ultralytics/yolov5, custom, pathbest.pt)报模块找不到。原因YOLOv5 的hub.load依赖仓库内的models目录如果本地没有克隆完整仓库或者工作目录不对就会报这个错。解决先git clone https://github.com/ultralytics/yolov5然后在仓库根目录下运行你的 Flask 应用。或者用torch.load直接加载导出的 TorchScript 模型不依赖仓库结构。5.3 坑三MySQL 写入中文乱码现象告警类型存进去变成问号或乱码。原因数据库、表、连接三处的字符集不一致。解决建库时用CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci连接时加charsetutf8mb4。三处都统一缺一不可。5.4 坑四夜间红外画面检测全漏现象白天 mAP 正常晚上几乎检测不到任何目标。原因训练集全是白天画面模型没学过红外灰度图的特征分布。解决训练集里必须混入夜间红外截图至少占 20%。如果实在没有夜间数据可以在预处理阶段做直方图均衡化cv2.equalizeHist但效果有限不如补数据。5.5 坑五Flask 多线程下模型推理结果错乱现象并发请求时返回的检测框和图片对不上。原因PyTorch 模型不是线程安全的多个线程同时调用model(img)会共享内部状态。解决给推理加锁threading.Lock()或者用gunicorn起多个 worker 进程每个进程独立加载模型。加锁会降低并发但保证正确性。6. 进阶技巧用 OpenCV 光流做行为时序判断降低误报YOLOv5 是单帧检测它只能告诉你画面里有人但判断不了这个人是在正常走路还是翻越护栏。翻越是一个连续动作单帧看可能只是人靠近栏杆。我后来加了一层 OpenCV 光流做时序判断误报率降了大约 40%。思路是对连续 10 帧的检测框区域计算稠密光流如果光流方向集中向上且幅度超过阈值就判定为攀爬动作。核心代码import cv2 import numpy as np def compute_flow(prev_gray, curr_gray, bbox): x1, y1, x2, y2 map(int, bbox) prev_roi prev_gray[y1:y2, x1:x2] curr_roi curr_gray[y1:y2, x1:x2] flow cv2.calcOpticalFlowFarneback( prev_roi, curr_roi, None, pyr_scale0.5, levels3, winsize15, iterations3, poly_n5, poly_sigma1.2, flags0 ) mag, ang cv2.cartToPolar(flow[..., 0], flow[..., 1]) upward_ratio np.mean((ang np.pi * 0.75) (ang np.pi * 1.25) (mag 2.0)) return upward_ratio # 在检测循环中 if person in detections and upward_ratio 0.6: trigger_alert(climb)参数说明pyr_scale0.5是金字塔缩放比例越小越精细但越慢。winsize15是光流窗口大小太小噪声大太大丢失细节。mag 2.0是光流幅度阈值低于这个值认为是噪声。upward_ratio 0.6表示 60% 以上的像素在向上运动这个阈值需要根据实际摄像头角度调整。这套时序判断的代价是增加约 15ms 每帧的计算量但换来的是误报大幅下降。我的经验是单帧检测负责发现目标时序分析负责确认行为两者结合才是一套能用的异常行为识别系统。最后说一个习惯每次改完参数我都会用同一段测试视频跑一遍记录告警数量和误报数量做成表格对比。不靠感觉调参靠数据说话。这套系统我前后调了三个月最大的教训是——不要追求模型精度到极致先把数据质量和时序逻辑做扎实效果提升比换模型明显得多。希望帮到你。本文还有配套的精品资源点击获取
返回列表