ARTICLE DETAIL

资讯详情

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

YOLOv8行人闯红灯抓拍检测:从数据集到部署的完整实战指南

YOLOv8行人闯红灯抓拍检测:从数据集到部署的完整实战指南 简介《基于YOLOv8的行人闯红灯抓拍检测系统》是一套面向计算机视觉毕业设计与课程设计的完整工程包涵盖源码、数据集、可视化界面与部署教程定位精准适合计科、人工智能、通信工程、自动化等专业学生及入门开发者快速上手。系统基于YOLOv8目标检测模型融合深度学习与计算机视觉技术可实现行人闯红灯自动抓拍识别并能输出核心指标曲线、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果和标签分布图功能完善、操作简单无需复杂配置即可作为毕设答辩的稳妥方案。资源共8个文件包含3个Python源码脚本对应可视化界面、视频检测、模型训练三个模块、3个模型权重文件.pt以及2个说明文档.txt压缩包仅15.91MB轻量易部署。目前已有73人浏览学习代码经测试运行成功下载后按README指引操作即可直接运行也可在此基础上二次开发扩展至其他违禁行为检测场景覆盖完整实验流程具有较高实用与参考价值。1. 行人闯红灯抓拍检测一套能直接跑起来的 YOLOv8 毕设项目行人闯红灯抓拍检测是计算机视觉里目标检测与行为判定结合的高频毕设课题每年都有大量课程设计和毕业设计选这个方向。这套基于 YOLOv8 的项目资源把训练源码、训练好的权重、可视化检测界面、完整标注数据集和部署教程打包在一起解压后按照教程走一遍就能看到实际检测效果。它解决的核心问题是不用自己从零写网络结构、不用四处凑数据集、不用为演示界面发愁。适合正在做毕设或课程设计、需要一套能演示能答辩的完整系统的同学也适合刚接触 YOLOv8、想通过现成项目打通训练到部署全流程的入门者。2. YOLOv8 检测原理与数据集结构为什么选这套方案2.1 YOLOv8 的网络结构与检测头做行人闯红灯检测选目标检测模型时常见的选择有 Faster R-CNN、SSD 和 YOLO 系列。Faster R-CNN 精度高但推理速度慢实时抓拍场景下帧率上不去SSD 速度尚可但对小目标召回率一般。这套资源选 YOLOv8 不是跟风而是它的结构设计恰好贴合行人检测的需求。YOLOv8 的基本结构可以拆成三块。Backbone 是 CSPDarknet 的改进版里面的 C2f 模块把特征图拆成两个分支经过不同层级的 Bottleneck 处理后拼接再通过跨阶段连接保留梯度流。相比 YOLOv5 的 C3 模块C2f 在相同计算量下提取到了更丰富的梯度信息。Neck 部分沿用 PAN-FPN 结构自顶向下和自底向上两条路径做多尺度特征融合P3、P4、P5 三层分别负责小、中、大目标。Head 是 Decoupled Head分类分支和回归分支独立不再共享参数收敛更快对类别相似但形状差异大的目标区分得更干净。行人目标有几个特点在红绿灯场景下往往处于中远距离像素尺寸偏小路口行人密集互相遮挡严重。YOLOv8 的多尺度融合对中远距离小目标友好anchor-free 设计让每个位置直接预测目标中心与宽高省去了 anchor 超参调优的工作量。实际训练中 s 版本在 NVIDIA 显卡上能以 60 FPS 以上跑推理n 版本更快满足抓拍场景的实时性要求。换到 CPU 机器上推理速度会掉到每秒几帧但只要不做实时摄像头检测分析视频文件逐帧处理也还能接受。2.2 数据集组织方式与 label 格式拿到这套资源之后先看数据集的目录结构。YOLOv8 训练要求 images 和 labels 分属两个目录各自内部再按 train/val 划分。常见结构如下dataset/ ├── images/ │ ├── train/ # 训练图片 │ └── val/ # 验证图片 ├── labels/ │ ├── train/ # 训练标注 │ └── val/ # 验证标注 └── data.yaml # 数据集配置labels 目录下每个 txt 文件与对应图片同名每一行代表一个目标格式是class x_center y_center width height其中坐标全部归一化到 01。比如0 0.4621 0.5312 0.0865 0.2431表示类别 0 的目标中心点位于图片的 46% 宽度、53% 高度处宽高分别为图片尺寸的 8.65% 和 24.31%。这套格式是 YOLO 系列通用的用 LabelImg 或 labelme 导出时只要选 YOLO 格式就会自动生成但如果标注工具里选成了 VOC 的 XML 或 COCO 的 JSON导出后必须转换才能用于训练。data.yaml 里定义数据集路径和类别名称。这套资源的类别通常按两类来组织train: dataset/images/train val: dataset/images/val nc: 2 names: [person, traffic_light]train 和 val 字段指向图片目录YOLOv8 会自动在同级目录下找 labels。nc 是类别总数names 是类别名称列表顺序必须和标注文件里的 class id 一一对应。如果资源里把红绿灯细分成了 red_light 和 green_light类别会变成三个训练脚本里所有涉及 nc 的地方都要一起改。改完 data.yaml 后可以用yolo train datadata.yaml modelyolov8n.pt epochs1跑一轮快速验证确认数据路径和类别配置没问题再正式训练。数据集划分比例上train 和 val 按 8:2 或 9:1 都常见。需要注意图片和标注文件要严格同名否则训练时会提示找不到对应 label。还有一种隐蔽的情况某些图片里没有目标对应的 txt 文件是空文件这种情况训练时不会报错但会影响训练效率最好把这些空标注图片单独放到一个目录留作测试用。2.3 训练前的数据校验跑训练之前先做一遍数据校验。这一步很多人跳过结果训练到一半报错或者精度奇差还以为是模型的问题。实际上大部分翻车都出在标注文件上。最常见的两类问题坐标越界和类别 id 与 data.yaml 对不上。我一般会用下面这个脚本把 labels 目录整体过一遍import os def check_labels(label_dir, num_classes): for root, _, files in os.walk(label_dir): for f in files: if not f.endswith(.txt): continue path os.path.join(root, f) with open(path, r, encodingutf-8) as fp: lines fp.readlines() for line in lines: parts line.strip().split() if len(parts) ! 5: print(f[格式异常] {path}: {line.strip()}) continue cls int(float(parts[0])) x, y, w, h map(float, parts[1:]) if cls num_classes: print(f[类别越界] {path}: class{cls}) if not (0 x 1 and 0 y 1): print(f[中心点越界] {path}: x{x}, y{y}) if w 0 or w 1 or h 0 or h 1: print(f[宽高异常] {path}: w{w}, h{h}) check_labels(dataset/labels/train, 2) check_labels(dataset/labels/val, 2)这个脚本的逻辑是遍历 labels 下所有 txt逐行检查五个字段是否存在、类别 id 是否超出 num_classes、归一化坐标是否落在 01 区间、宽高是否为正数且不超过 1。发现异常直接打印文件路径和具体行几秒钟就能把整个数据集的卫生状况摸清楚。跑完之后再开始训练可以省掉很多半夜起来看报错的时间。如果发现 txt 里的坐标是像素值而不是归一化值说明标注工具导出时选错了格式需要批量转换。转换时读取对应的图片尺寸用像素值除以宽高得到归一化坐标import cv2, os def convert_pixel_to_normalized(img_dir, label_dir): for f in os.listdir(label_dir): if not f.endswith(.txt): continue img_path os.path.join(img_dir, f.replace(.txt, .jpg)) if not os.path.exists(img_path): img_path os.path.join(img_dir, f.replace(.txt, .png)) h, w cv2.imread(img_path).shape[:2] path os.path.join(label_dir, f) with open(path, r) as fp: lines fp.readlines() new_lines [] for line in lines: parts line.strip().split() cls, x, y, bw, bh int(parts[0]), float(parts[1]), float(parts[2]), float(parts[3]), float(parts[4]) new_lines.append(f{cls} {x/w:.6f} {y/h:.6f} {bw/w:.6f} {bh/h:.6f}\n) with open(path, w) as fp: fp.writelines(new_lines) convert_pixel_to_normalized(dataset/images/train, dataset/labels/train)注意这段转换脚本假定标注文件记录的是中心点像素坐标和宽高像素值并且图片扩展名是 jpg 或 png。如果你的标注是左上右下两个角点的像素坐标需要先换算成中心点再把宽高算出来不能直接套这个脚本。转换完再跑一遍校验脚本确认没有越界就可以放心进训练流程了。3. 环境配置与模型训练从零把权重训出来3.1 环境安装与依赖版本训练 YOLOv8 只需要装 ultralytics 这一个核心包它把训练、验证、推理、导出封装成了一条命令。底层依赖的 PyTorch、OpenCV、NumPy 会在安装时自动带上但 PyTorch 需要根据本机显卡手动选择对应版本。推荐用 conda 隔离环境避免把系统 Python 搞乱conda create -n yolo python3.8 -y conda activate yolo pip install ultralytics pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118第一条命令创建 Python 3.8 的虚拟环境PyTorch 官方对 3.83.10 都支持选 3.8 是兼容性最稳的选择。第二条安装 ultralytics 包它会自动拉取训练所需的依赖。第三条里的--index-url指定了 PyTorch 的 CUDA 11.8 版本下载源如果本机是 CUDA 12.x把 cu118 换成 cu121 或 cu124如果是纯 CPU 机器去掉--index-url直接装默认的 CPU 版即可。不确定 CUDA 版本时在终端跑nvidia-smi右上角能看到驱动支持的 CUDA 版本号选一个小于等于它的版本就行。装完后用一条命令验证环境是否通yolo predict modelyolov8n.pt sourcehttps://ultralytics.com/images/bus.jpg如果能在 runs/detect 下看到输出图片说明环境没问题。CPU 机器也能跑只是速度慢推理一张图要几秒训练则要做好以小时为单位的心理准备。装完如果遇到ImportError: libGL.so.1之类的报错是 OpenCV 缺少系统依赖Ubuntu 下执行sudo apt install libgl1 libglib2.0-0就能解决。3.2 训练脚本与参数含义环境就绪后进入项目目录执行训练。先确认 data.yaml 里路径写的是绝对路径还是相对路径如果写的是相对路径最好改成绝对路径因为 ultralytics 在解析相对路径时偶尔会在换目录后找不到数据集改绝对路径能少踩一个坑。yolo train datadata.yaml modelyolov8s.pt epochs100 batch16 imgsz640 lr00.01 optimizerAdamW patience20逐项拆解参数参数示例值含义modelyolov8s.pt预训练权重s 是 small 版本显存不足可换 yolov8n.ptepochs100训练轮数数据集小的话 80150 之间都能接受batch16批大小显存不足时降到 8 或 4imgsz640输入图片分辨率行人密集场景可试 960 提升小目标精度lr00.01初始学习率AdamW 优化器一般 0.0010.01optimizerAdamW优化器也可以换 SGD 但收敛节奏不同patience20早停轮数验证集 mAP 连续 20 轮不涨就自动停batch 是最直接影响显存占用的参数。8GB 显存跑 yolov8s 640 分辨率batch16 基本是上限超出会报 CUDA out of memory。如果只有 4GB 显存建议 batch8、imgsz640或者直接换 yolov8n。训练命令里没有设置 workers 时 ultralytics 会按 CPU 核数加载数据如果训练时发现 CPU 被打满而 GPU 利用率不高手动加workers4限制数据加载线程数。还有两个训练进阶参数值得知道cosineTrue让学习率按余弦曲线衰减适合 epoch 数较多的训练mosaic0.5控制马赛克增强的概率如果发现训练后期模型在小目标上表现不稳可以考虑把 mosaic 调低到 0.5 或直接关掉。3.3 训练过程监控与结果评估训练过程中每完成一个 epochultralytics 会把结果写入 runs/detect/train 目录不需要额外装 TensorBoard。训练完重点看三个文件results.png、confusion_matrix.png、F1_curve.png。results.png 里包含 loss 曲线和 mAP 曲线。loss 曲线分 box_loss、cls_loss、dfl_loss 三路前几十轮快速下降、之后趋于平缓属于正常形态。如果 cls_loss 出现先降后升的 U 形反转大概率是学习率过大或数据里有噪声标签。mAP50 是 IoU 阈值 0.5 下的平均精度行人检测做到 0.85 以上已经不错mAP50-95 是更严格的综合指标通常比 mAP50 低 20 到 30 个百分点不用过度纠结。选权重时用 best.pt 而不是 last.pt。best.pt 是验证集 mAP 最高的 checkpointlast.pt 是最后一轮的权重后者可能因为后期过拟合而表现不如中间轮次。验证阶段直接跑yolo val modelruns/detect/train/weights/best.pt datadata.yaml输出里会列出每个类别的 precision、recall、mAP50重点看 person 类别的 recall。行人检测最怕漏检因为漏检意味着有人闯红灯而系统没记录比误检严重得多。如果 person 类别的 recall 低于 0.8考虑增加训练轮数、扩大数据集或提高 imgsz。如果 training loss 很低但 validation loss 明显偏高说明过拟合了此时调低 epochs 或者增加数据增强都比继续加大模型更有效。4. 可视化界面与抓拍判定把模型接进业务场景4.1 界面功能与交互逻辑训练好模型之后真正让答辩老师眼前一亮的往往是那套可视化界面。这个资源的界面基于 PyQt5 和 OpenCV 实现打开后可以加载视频文件也可以直接调用摄像头实时画面。界面左侧是视频显示区右侧是检测结果列表和控制按钮检测框实时叠加在画面上每检测到一次目标就在列表里追加一条记录。界面代码的核心是一个独立的后台线程。推理放在 QThread 里跑界面主线程只负责刷新画面和响应按钮两者通过信号槽通信。如果直接把模型推理写在主线程里视频流会出现明显的卡顿移动鼠标都费劲这是 PyQt5 做视觉应用最常见的翻车点之一。下面是从界面推理线程中抽出的核心部分class DetectThread(QThread): frame_ready pyqtSignal(object) def __init__(self, model_path, source): super().__init__() self.model YOLO(model_path) self.cap cv2.VideoCapture(source) def run(self): while self.cap.isOpened(): ret, frame self.cap.read() if not ret: break results self.model(frame, conf0.45) annotated results[0].plot() self.frame_ready.emit(annotated)YOLO 对象在init里创建这样只加载一次权重不会每帧都重新初始化模型。run 方法循环读帧、推理、把画好检测框的画面通过信号发回主线程。frame_ready 信号绑定到主界面的更新槽函数槽函数里只做 QImage 转换和 setPixmap不做任何重活保证界面流畅。资源里还额外加了暂停和单步按钮调试时逐帧查看检测效果比直接播放更实用。4.2 闯红灯判定逻辑如何界定闯红灯整个系统里最容易糊弄、也最值得说清楚的是闯红灯判定逻辑。如果只是检测到行人就抓拍那这个系统没有任何实用价值——行人站在路边等红灯也会被拍。合理判定需要把三个信息组合起来红绿灯当前状态、行人检测框位置、停止线位置。常见做法是先在图上标定一条停止线的 y 坐标然后按这个逻辑判断def judge_violation(person_box, stop_line_y, light_state): # person_box: [x1, y1, x2, y2] 行人检测框 if light_state ! red: return False x1, y1, x2, y2 person_box if y1 stop_line_y y2: return True return False判定的三个条件缺一不可红灯亮、行人检测框的纵向范围覆盖停止线 y 坐标、行人在画面中处于越过停止线的位置。停止线 y 坐标可以在界面上用鼠标点选标定通常选取画面中斑马线起始位置的水平线。灯色状态来自另一个检测模块在这个资源里通常用 traffic_light 类别的检测结果结合颜色分析得到。实际场景还要加一个时间条件连续 N 帧满足越线才判定违规单帧误检直接触发抓拍会让误报率失控。N 一般取 35配合帧率 25 算下来大约 0.2 秒的持续时间既能过滤跳变噪声又不会漏掉快速通过的行人。这个连续计数逻辑放在判定函数外层用一个计数器维护帧间不满足条件就清零实现起来简单答辩时也容易解释清楚。4.3 结果存储与导出抓拍记录包括三部分现场截图、违规信息、结构化表格。截图直接保存到 capture 目录文件名用时间戳和序号拼接保证不重名。违规信息写入 CSV 文件每行包含时间、帧号、行人位置坐标、置信度、灯色状态。CSV 可以用 Excel 直接打开答辩时导出一份记录表比口头描述效果直观得多。写入 CSV 的代码示意import csv from datetime import datetime def save_violation(record_path, frame, person_box, conf, light_state): with open(record_path, a, newline, encodingutf-8) as fp: writer csv.writer(fp) writer.writerow([ datetime.now().strftime(%Y-%m-%d %H:%M:%S), frame, person_box, round(conf, 3), light_state ])保存 CSV 时注意两点。第一用newline防止 Windows 下写入时出现空行第二指定encodingutf-8否则 Excel 打开中文会乱码。如果 CSV 文件不存在记得先写表头否则后续追加的行没有列名统计时不方便做筛选。截图文件名建议和 CSV 行号配对比如在第 5 条记录时生成capture_005.jpg这样事后核查时能在截图和记录之间快速对应。5. 避坑指南训练和部署中的五个常见坑5.1 显存不足导致训练中断现象训练跑到第几个 epoch 时直接报 CUDA out of memory进程终止前面训的白训了。原因batch 和 imgsz 的乘积超出显卡显存容量。yolov8s 在 640 分辨率下8GB 显存跑 batch16 就到了临界点如果同时开了多个程序占用显存当场爆。解决先把 batch 降到 8还不行就降到 4。另外把 imgsz 从 640 改成 480显存占用立刻下降一大截。如果显存只剩 2GB直接换 yolov8n。设置epochs时配合patience20早停机制能避免在模型已经收敛的情况下继续空转浪费显存。训练时关掉浏览器等吃显存的应用也能腾出不少空间。5.2 数据集标注与类别混淆现象训练过程不报错但验证时 person 类别的精度极低检测框把行人和交通灯杆混在一起。原因标注时类别 id 标错了。比如 data.yaml 里第 0 类写的是 person但某几张图把行人标成了 1模型训练时看到的是同一类目标的特征互相打架自然学不好。解决训练前跑一遍 2.3 节的校验脚本同时统计每个类别的目标数量是否合理。如果 person 类只有几百个框而 traffic_light 有几千个需要补充行人标注或做类别重采样。训练完看一眼 confusion_matrix.png如果 person 和 traffic_light 之间有大量误分优先怀疑标注而不是模型结构。还有一个隐蔽情况用 labelme 标注时导出的类别顺序和 data.yaml 不一致id 错位的框在可视化里看着没问题但训练时已经被归到了错误的类。5.3 检测框抖动导致误抓拍现象静止站在路边等红灯的行人检测框忽大忽小、位置左右飘偶尔还跳出一帧错误的高置信度检测触发抓拍。原因单帧推理没有时序信息模型对遮挡、姿态变化敏感相邻帧的检测结果天然存在波动。置信度阈值设得太低把大量低质量检测框放进了判定逻辑。解决界面上把置信度阈值调到 0.40.5过滤掉低置信度框。判定逻辑里加连续帧确认机制连续 3 帧以上满足越线条件才记录违规。还可以对检测框做简单的指数平滑用上一帧位置和当前帧位置的加权平均减轻框的抖动幅度。平滑系数取 0.6 左右系数太大响应会变得迟钝行人快速移动时框跟不上。5.4 模型导出转换失败现象训练好的 best.pt 转 ONNX 时报错提示 opset 版本不兼容或某个算子不支持导出。原因ultralytics 版本和 ONNX 导出器版本不匹配。YOLOv8 的某些模块在特定版本下导出到 ONNX 有已知问题比如 DFL 层在旧版 ONNX 中没有对应算子。解决先升级 ultralytics 到较新版本再执行导出yolo export modelbest.pt formatonnx opset12 simplifyTrueopset 固定用 12 是因为它兼容性最广OpenCV 的 DNN 模块和 ONNX Runtime 都支持。simplify 会做计算图简化去掉冗余节点推理速度略有提升。如果导出后 ONNX Runtime 推理结果和 PyTorch 不一致检查输入图像的预处理方式是否一致包括归一化、letterbox 和通道顺序大多数导出后检测框偏移的问题都不在模型本身而是预处理流程没对齐。5.5 界面卡顿与检测延迟现象视频播放不流畅鼠标操作有延迟检测结果比画面慢好几秒。原因推理阻塞了 UI 线程。PyQt5 主线程里直接调用 model() 推理模型每帧推理耗时 2050 毫秒加上视频解码和画面绘制主线程被塞满事件循环来不及处理鼠标事件。解决把模型推理放到 QThread 里界面只负责显示这就是 4.1 节那样结构化的原因。另外摄像头输入时 OpenCV 的 VideoCapture 默认缓冲较大可以调小缓冲区减少延迟。界面更新时用队列缓存最近一帧丢弃积压的旧帧保证画面实时性而不是逐帧排队处理。实测把推理线程化之后界面操作响应从秒级回到毫秒级体验差别非常明显。6. 进阶从验证集指标到现场可用的最后一步拿 best.pt 在验证集上跑出不错的 mAP 只代表模型在静态图片上能检测离现场可用还差一步用一段真实的红绿灯路口视频做端到端测试统计误报率和漏报率。这一步是决定系统能不能拿去答辩演示的分水岭。视频测试时我会做一次阈值扫描。固定好停止线和红绿灯检测逻辑只调整置信度阈值从 0.25 到 0.6 每隔 0.05 跑一遍同一段视频统计每个阈值下的抓拍总数和被人工确认的误抓拍数。阈值太高漏检多闯红灯的人不拍下来等于系统失职阈值太低误报多正常人过马路也被记录。两个指标的交汇点就是当前场景的最优阈值这个值写在配置文件里别写死在代码里。如果 mAP 指标不错但视频测试频繁漏检优先怀疑小目标召回问题。可以尝试把 imgsz 提到 960 重新训练代价是推理时间翻倍或者改用 yolov8m 配合原始 640 分辨率兼顾速度和召回。想要更好可以试 P2 检测头它对小目标定位更敏感但训练时间会明显变长毕设时间不充裕时慎开。改完任何结构都别只盯着 mAP 对比重新跑一遍视频测试才是有效的验证方式。做这个项目时我在导出模型上栽过一次跟头PyTorch 里推理一切正常导出 ONNX 后检测框全部偏移最后发现是导出时输入尺寸写死成了 480而训练时用的 640。从那以后我每次导出前都重新核对 img_size 参数部署端和训练端的输入尺寸必须严格一致这是最容易被忽略的坑。资源和教程里其实反复强调了这一点真到自己动手时还是要走一遍完整流程才记得住。希望这份拆解能帮你把系统跑起来少走我当年走过的弯路。本文还有配套的精品资源点击获取
返回列表