尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

YOLOv8共享单车违停识别系统:从检测到PyQt5界面部署

YOLOv8共享单车违停识别系统:从检测到PyQt5界面部署 简介一套基于YOLOv8的共享单车违规停放识别系统面向计算机视觉、目标检测与人工智能方向的毕业设计或课程设计涵盖源码、数据集、可视化界面与部署教程可完成从模型训练、视频检测到界面展示的完整流程。资源包共8个文件3个Python脚本负责模型训练、视频检测与可视化页面运行3个PyTorch权重文件提供预训练与训练后的模型参数2个说明文档帮助快速上手压缩包大小约15.91MB整体轻量、便于部署。目前已有63人学习下载。代码经过实测运行启动后可直接使用并自动产出核心指标曲线、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果与标签分布图等足以支撑项目汇报与答辩展示。非常适合计算机、人工智能、通信工程、自动化、电子信息等专业的学生作为毕设或课设完整方案使用也方便在此基础上继续改进。1. 这套YOLOv8违停识别系统核心是“先检测单车再判定违规”如果拿到项目包后第一件事就是双击 train.py大概率会被一堆参数卡住。这套系统真正的主线不是“训练一个能直接输出违规的模型”而是把任务拆成两层YOLOv8 负责把画面里的共享单车用检测框找出来违规与否由后处理规则判断——单车框是否压到盲道、消防通道、地铁出入口这些预先画好的禁停区域。这么做的好处很直接改禁停范围只改配置文件不用重训模型演示时也能把“为什么判违规”讲清楚。下面从选型、数据、训练、界面到打包把一条能直接交接的完整链路过一遍。2. 识别方案与YOLOv8模型结构为什么选v8跑单车检测2.1 把“违规停放”拆成检测层与判定层共享单车违停识别的难点不在“认出自行车”而在“什么算违规”。同样是两辆单车停在白线内是合规停在盲道上就是违规同一条街道换一个时间段禁停范围可能跟着变。如果让模型直接学“违停”这个类别等于把地域规则塞进视觉特征里泛化能力会很差。常见做法是把任务拆成两层检测层只输出所有单车框判定层用几何规则判断每个框是否落在禁停区域内。禁停区可以是固定矩形、多边形也可以是语义分割出来的盲道区域。对毕设和课程设计来说矩形 ROI 最直观也最容易在 PyQt5 界面上用鼠标交互绘制。def check_violation(box, roi): # box: [x1, y1, x2, y2]YOLOv8 输出的原图坐标 # roi: [x1, y1, x2, y2]界面里手动框出的禁停区域 bw box[2] - box[0] bh box[3] - box[1] center_x, center_y box[0] bw / 2, box[1] bh / 2 # 判据一检测框中心点落在 ROI 内 in_roi (roi[0] center_x roi[2]) and (roi[1] center_y roi[3]) # 判据二检测框与 ROI 的交并比超过阈值 inter_w max(0, min(box[2], roi[2]) - max(box[0], roi[0])) inter_h max(0, min(box[3], roi[3]) - max(box[1], roi[1])) inter inter_w * inter_h area_box bw * bh area_roi (roi[2] - roi[0]) * (roi[3] - roi[1]) union area_box area_roi - inter iou inter / union if union 0 else 0 return in_roi or iou 0.5两个判据叠加是为了覆盖不同情况单车完全压住盲道时中心点和 IOU 都会命中单车只压到禁停区边缘时IOU 可能不到 0.5但中心点判据仍然有效。阈值 0.5 是经验值在界面上做成可调滑条更稳妥不同摄像头角度对“压线”的观感差异很大。2.2 C2f与Anchor-FreeYOLOv8的改动对单车检测意味着什么YOLOv8 的网络结构图在检索里出现频率很高核心改动可以压缩成三句话Backbone 用 C2f 模块替代了 C3Neck 依然是 PAN-FPN 结构检测头改成了解耦头并去掉 Anchor。对共享单车这个场景前两点影响最大。C2f 模块借鉴了 CSPNet 和 ELAN 的思路把输入特征图分成两支一支直接走带 Bottleneck 的梯度流另一支走短路径最后在输出维度上拼接。和 C3 相比它让梯度在传播过程中有更多“旁路”浅层细节能更完整地到达深层。单车目标尺寸小、纹理弱经常出现车把和车筐这种小结构C2f 保留细节的能力对召回率有帮助。Anchor-Free 意味着不需要再像 YOLOv5 那样手工聚类先验框。检测头直接回归目标中心点到四条边的距离配合解耦的类别分支和回归分支对重叠遮挡的单车更友好。YOLOv8n 参数量约 3.2MYOLOv8s 约 11.2M实测在 GTX 1660Ti 6G 显存上v8s 配合 batch8 可以稳定训练纯 CPU 演示机建议直接换 v8n精度降低但推理延迟明显更小。2.3 环境配置从 conda 到 Ultralytics 的最小可复现步骤环境配置是检索“yolov8环境配置”最集中的需求点通常卡在 torch 版本和 CUDA 不匹配上。先建独立环境避免把系统 Python 搞乱。conda create -n bike python3.10 -y conda activate bike pip install ultralytics pip install PyQt5 python -c import torch; print(torch.cuda.is_available())最后一行如果输出 True说明 torch 能调用 GPU输出 False 时先执行nvidia-smi看驱动支持的 CUDA 版本再按对应版本重装 GPU 版 torch。训练之前用一张公开权重验证整条链路是否通yolo predict modelyolov8s.pt sourceassets能输出结果图就说明依赖装齐了。依赖作用安装方式ultralyticsYOLOv8训练/推理/导出pip install ultralyticstorch torchvision深度学习后端随 ultralytics 自动安装GPU 版需手动确认opencv-python视频流读取与图像处理pip install opencv-pythonPyQt5可视化界面框架pip install PyQt53. 准备数据把“违停”变成YOLO能读的标注格式3.1 数据集从哪来公开资源与自采补量目前没有规模化的公开“共享单车违规停放”数据集可以直接用标题里说的完整数据集大概率是项目作者用公开检测数据集过滤或自采标注的。拿到手先别急着训练用下面的脚本确认目录完整YOLO 训练时缺标签的图片会被静默跳过等训完才发现数据没喂进去就很被动。import os from pathlib import Path root Path(D:/datasets/bike) for split in [train, val]: img_dir root / images / split lbl_dir root / labels / split imgs list(img_dir.glob(*.jpg)) list(img_dir.glob(*.png)) for img in imgs: lbl lbl_dir / (img.stem .txt) if not lbl.exists(): print(缺少标签:, img.name) lbls list(lbl_dir.glob(*.txt)) for lb in lbls: for line in lb.read_text().strip().splitlines(): parts line.split() if len(parts) ! 5: print(格式错误:, lb.name) break _, cx, cy, w, h map(float, parts) if w 1 or h 1 or cx 0 or cx 1: print(坐标越界:, lb.name)自建数据的常见组合是从 COCO 数据集中过滤出 bicycle 类做预训练再补 300 到 500 张本地拍摄的街景单车图。拍摄时注意覆盖不同时段、不同光照、不同遮挡程度尽量贴近实际部署场景否则训练集里全是正午顺光照片一到傍晚检测率就会明显下降。3.2 标注规则什么框该打、遮挡怎么处理标注直接影响模型行为比调参重要得多。建议只标一个类别bicycle把所有视觉上能认出的共享单车都框进去不区分“正常”和“违规”——违规判断交给第 5 章的 ROI 规则。原因前面说过规则可以随时改标注不行。场景标注建议说明白线内成排停放单车整体外轮廓每辆车单独一个框盲道、消防通道违停单车整体外轮廓同样只给一个框多车叠放框最外侧可见单车轮廓被完全遮挡的车不标骑行中的人推车不标容易引入“人车”的混合特征车把、车筐单独入镜不标面积太小标注只会增加噪声标注工具用 X-AnyLabeling 或 LabelImg 都可以保存成 YOLO 格式。X-AnyLabeling 原生支持自动标注辅助先用 YOLOv8 预训练权重打底稿再人工修正能省一半时间。遮挡场景宁可漏标也不要标出大量“半辆车”的框会让模型在验证时因定位偏差误判。3.3 数据集目录结构一份能直接喂给 YOLOv8 的配置YOLOv8 的数据配置走 YAML 文件路径和标签结构必须对应。标准目录如下bike/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── bike.yamlbike.yaml内容如下path用绝对路径可以省掉不少相对路径踩坑path: D:/datasets/bike train: images/train val: images/val nc: 1 names: 0: bicycleYOLO 标签文件里每行格式是class x_center y_center width height五个值全部归一化到 0 到 1。训练前用脚本随机抽样几十张图把标签框叠加到原图上检查一遍比直接训练后看 mAP 高效得多。坐标越界和数据格式错误的图片在训练时不会直接报错但结果曲线的波动会莫名其妙。4. 训练自己的数据集命令、参数与结果曲线4.1 最小可复现训练命令与关键参数表数据检查完毕用下面这条命令就可以启动训练。这是搜索“yolov8训练自己的数据集”时最需要的骨架命令其余参数要么有默认值要么可以在跑通后再调。yolo detect train databike.yaml modelyolov8s.pt \ epochs50 imgsz640 batch8 device0 \ patience15 namebike_runmodelyolov8s.pt表示从 COCO 预训练权重继续训练这叫迁移学习。从头训练一个小数据集效果会差很多预训练权重已经学会了边缘、纹理等基础特征新数据集只需要在高层特征上做适配。参数建议值说明epochs50 ~ 100先跑 50 轮看曲线趋势不够再加imgsz6406G 显存的安全值遮挡严重可试 960batch8GTX 1660Ti 上较稳OOM 就降到 4device0指定第一张 GPUCPU 训练则填cpupatience15验证集指标连续 15 轮不提升就早停cacheTrue小数据集可减少磁盘 IO显存够才开batch8不是越大越好。batch 翻倍显存占用接近翻倍但梯度更新更加平滑。6G 显存跑 v8s 在 640 分辨率下batch8 是常用值如果训练中途报 CUDA out of memory优先降 batch不要降 imgsz因为分辨率对检测精度的影响更直接。4.2 训练结果怎么读损失曲线和验证指标训练目录下会生成runs/detect/bike_run里面有results.png、results.csv和混淆矩阵等文件。results.png一次画出了训练损失、验证损失、精确率、召回率和 mAP 曲线但很多人不知道如何单独画某几项——比如搜“yolov8画损失函数曲线图”时最通用的做法是直接读 CSV 用 matplotlib 重画。import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/detect/bike_run/results.csv) # 列名中的空白会被 pandas 替换成下划线 box_loss df[train/box_loss] epochs df[epoch] plt.figure(figsize(8, 4)) plt.plot(epochs, box_loss, labelbox_loss) plt.xlabel(epoch) plt.ylabel(loss) plt.title(YOLOv8 Box Loss Curve) plt.legend() plt.grid(True) plt.savefig(box_loss_curve.png, dpi200)看曲线时抓住三个点box_loss 是否持续下降val/cls_loss 和 train 的差距是否拉大mAP50 是否在训练后半段停止增长。如果 mAP50 在 0.5 上下震荡先回头查数据标注再考虑调参而不是盲目加 epochs。验证用单独命令不要从训练日志里猜指标yolo detect val modelruns/detect/bike_run/weights/best.pt \ databike.yaml device0会输出 mAP50 和 mAP50-95 两类指标。对共享单车检测mAP50 至少达到 0.7 才适合接入界面演示mAP50-95 受定位精度影响不用过度纠结。4.3 识别效果不达标的三个调优方向第一分辨率不够时把 imgsz 提到 960小目标召回率提升明显代价是训练和推理都变慢6G 显存可能要把 batch 降到 4。第二Mosaic 增强虽然在最后 10 轮会自动关闭但共享单车场景中车辆密集时遮罩重叠太严重可以用close_mosaic15提前关闭 Mosaic让模型在真实分布上多拟合几轮。第三如果实验要求改结构优先考虑往 P2 层加检测头也就是把 stride 为 4 的浅层特征接入检测头专门增强小目标检测能力显存开销约增加 30%。5. PyQt5可视化界面模型、线程与违停标定如何串起来5.1 界面功能与交互设计可视化界面在这一类系统里承担的作用不只是展示而是让“违规判定”变得可操作。界面左侧放视频画布右侧放控制区控制区从上到下分别是打开图片、打开视频、打开摄像头、开始/停止检测、置信度阈值滑条、禁停区绘制按钮、违停统计标签。功能实现要点图片识别单帧送入模型并显示结果视频/摄像头识别QThread 子线程逐帧推理否则界面卡死禁停区绘制鼠标在画布上拖矩形保存为 ROI 列表违停统计每个 ROI 内命中的检测框计数并显示实时参数调整置信度滑条绑定推理线程的 conf 参数5.2 把推理放进 QThread别让界面卡死在视频帧上第一次写 PyQt5 视频识别最容易犯的错误是直接在主线程里while cap.read()帧率低、界面无响应视频窗口一拖动就白屏。正确做法是把推理放到 QThread 子线程通过信号把帧传回主线程刷新界面。import cv2 from PyQt5.QtCore import QThread, pyqtSignal class VideoThread(QThread): frame_signal pyqtSignal(object) stats_signal pyqtSignal(int) def __init__(self, model, source, conf0.3): super().__init__() self.model model self.source source self.conf conf self.running False def run(self): cap cv2.VideoCapture(self.source) self.running True while self.running and cap.isOpened(): ret, frame cap.read() if not ret: break results self.model.predict(frame, confself.conf, verboseFalse)[0] self.frame_signal.emit(results.plot()) # plot() 返回带框的图像 self.stats_signal.emit(0) cap.release() def stop(self): self.running False self.wait()# 在主线程中连接信号 self.thread VideoThread(model, source) self.thread.frame_signal.connect(self.update_frame) self.thread.start()results.plot()会返回 BGR 格式的标注图主线程拿到后要先转成 RGB 再包装成 QImage 显示否则颜色会偏蓝。注意model是全局加载一次的不要在 run() 里反复加载权重模型加载耗时比推理时间长得多。5.3 禁停区ROI判定把“违规”画成红色违规判定的逻辑在 2.1 节已经实现了check_violation这里要解决的是“ROI 从哪里来”。常见做法是让用户用鼠标在画布上拖出禁停区域按下按钮进入绘制模式后每次拖动记录一个矩形判定时遍历所有 ROI。def on_frame_detected(self, boxes): violation_count 0 for box in boxes.xyxy.cpu().numpy(): for roi in self.roi_list: if check_violation(box, roi): violation_count 1 break self.label_violation.setText(f违停数量{violation_count})一段 10 秒的视频里连续几帧都误报同一个目标可以用一个简单去抖目标连续 3 帧命中同一 ROI 才记一次违规。常见误判是行驶中的单车短暂经过盲道区域会被当违停记录加上连续帧确认逻辑后能明显减少虚报。6. 交付与一键部署把项目打包成别人也能跑验收环节最怕的不是功能不够而是把项目传到另一台电脑上跑不起来。经验是把“部署教程”里最脆弱的部分前置处理路径用英文、依赖写死版本、模型权重打进打包目录。pyinstaller -w -F main.py \ --collect-all ultralytics \ --add-data bike.pt;. \ --add-data bike.yaml;.Windows 下--add-data的分隔符是分号Linux 下是冒号很多环境报“文件不存在”都是这里写错。-F打成单文件但启动速度会比目录模式慢毕设演示用单文件加分实际长时间跑摄像头识别用目录模式更稳定。echo off cd /d %~dp0 python main.py pause打包后的 exe 不需要用户再装 Python 和 CUDA 依赖但要注意两点一是路径里不能有中文OpenCV 和 Qt 对中文路径的兼容在打包后经常出幺蛾子二是如果目标机器显卡驱动版本和目标 CUDA 不匹配最好在代码启动时先尝试 CUDA抛异常就自动回退 CPU 推理保证演示现场不会黑屏。训练阶段把 batch 先设成 1 跑一轮确认数据流没有问题再加大 batch 和 epochs是这套流程里回报最高的一个操作。本文还有配套的精品资源点击获取
返回列表