news 2026/10/20 4:35:26

深度学习行人口罩佩戴检测实战:基于YOLOv8的完整毕设项目实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深度学习行人口罩佩戴检测实战:基于YOLOv8的完整毕设项目实现

毕业设计项目:深度学习行人口罩佩戴检测

做毕设的时候选了这个方向的同学,十有八九是看中了它“既落地又容易出效果”。行人口罩佩戴检测,本质上是一个目标检测任务,属于计算机视觉里最成熟、上手路径最清晰的方向之一。它不需要你发明新算法,把现有框架吃透、调通、部署出来,就已经是一份合格的毕设工作量。这篇就把我当时从零到一做完整个项目的思路、步骤、坑和心得完整写出来,给正在做类似题目的同学一个参考。

先给还没入门的同学交代清楚:这个项目解决的核心问题是——给定一张图片或一段视频画面,用深度学习模型自动框出画面里的行人,并判断每个人是否戴了口罩。它的应用场景很直白:公共出入口的实时监控、商场或园区的闸机联动、校园或办公楼的通行核验,都属于这类需求。适合的读者包括计算机视觉方向做毕设的本科生或研究生、想快速上手YOLO系列检测模型的人,以及刚接触深度学习但需要交出一个可演示结果的项目新手。

1. 项目整体设计与方案选型

1.1 需求拆解:从题目倒推出毕设工作量

“行人口罩佩戴检测”这个题目看着简单,但想拿高分,一开始就要把需求拆细。我自己在动手前列了这样几个子问题:

  • 检测对象是“行人”还是“人脸”?如果是行人,那模型要能区分人的整体轮廓,再判断口罩状态;如果是人脸,本质就是人脸检测加分类。毕设题目写的是行人,但实际部署中按行人检测再配合口罩分类,才更贴近监控场景。
  • 口罩状态分几类?常见做法是三类:正确佩戴口罩、未佩戴口罩、佩戴口罩不规范(比如露出鼻子,或者口罩挂在下巴上)。只做二分类(戴/没戴)能降低难度,但答辩时容易暴露思考深度不够,我建议至少做三分类。
  • 实时性有没有硬指标?毕设演示一般要跑视频流或摄像头实时画面。如果帧率低于10 FPS,演示效果会明显卡顿,体验不好。
  • 最终交付物是什么?是只有模型训练代码,还是一个带界面能上传图片和视频的演示系统?后者在答辩时加分非常明显。

把这些需求写清楚以后,整个项目的工作量边界就出来了:数据集准备、模型训练、推理优化、界面封装。四个环节缺一不可。

1.2 技术选型:为什么是YOLO系列而不是别的

当前的检测算法基本分成两大类:两阶段(如Faster R-CNN家族)和单阶段(如SSD、YOLO系列)。两阶段精度高但速度慢,单阶段速度快、精度也够用。毕设项目要做实时演示,单阶段是必然选择。

在YOLO系列中我对比过几个版本:

  • YOLOv5:生态成熟,社区资料最多,部署方案丰富。虽然被质疑“非官方”,但胜在好上手,出了问题搜一下基本上都有答案。
  • YOLOv6/YOLOv7:性能强,但对新手不友好,有些细节优化是论文性质的改进,工程化资料少。
  • YOLOv8:模块设计更现代,集成了分类、检测、分割、姿态估计多个任务,一个库里全搞定,而且API非常简洁,适合在毕设里展示“工程能力”。

我最终选了YOLOv8。理由有一个很关键:它原生支持导出为ONNX和TensorRT格式,后面做CPU或GPU推理都快,而且配套的Python库更新频繁,写代码时不用自己造轮子。

1.3 整体架构设计

整个系统分成三块:

  1. 数据处理模块:负责把原始图片和标注文件统一成YOLO格式,做数据清洗和增强。
  2. 模型训练模块:加载预训练权重,配置训练参数,在自建数据集上微调,输出最佳模型。
  3. 推理展示模块:支持图片、视频、摄像头三类输入,把检测结果可视化,同时输出统计结果(比如总人数、未戴口罩人数)。

这三块各自独立又前后衔接,刚好对应毕业设计论文里的“系统设计”“系统实现”“系统测试”三个章节,写论文的时候非常顺。

2. 数据准备与预处理

2.1 数据集怎么来:公开数据集与自建数据互补

当时搜了一圈公开的口罩检测数据集,发现一个普遍问题:要么数量太少(几千张),要么场景单一(几乎全是正面人脸特写),模型训练完在真实监控视角下效果很差。监控摄像头拍到的往往是斜上方视角、行人远近不同、有遮挡、光线复杂,数据分布差太远了。

我的做法是两条腿走路:

  • 从公开渠道找口罩检测数据,筛选出监控视角、行人全身或半身、多人场景的图片,作为基础数据。
  • 自己补充采集:让同学、朋友在不同场景下拍摄视频(多人行走、排队、进出门口等),从中抽帧。

补充采集的过程并不复杂,用手机拍5段视频,每段一两分钟,抽帧后能得到几百张图,覆盖的场景非常真实。

2.2 标注规范与格式统一

数据集最终要转成YOLO格式,也就是每个图片对应一个同名的txt文件,每行是“类别id x_center y_center width height”,坐标都是归一化到0~1之间的相对值。

类别我用的是:

  • 0: face_with_mask(正确佩戴口罩)
  • 1: face_without_mask(未佩戴口罩)
  • 2: face_mask_incorrect(佩戴口罩不规范)

这里有个容易纠结的点:到底标人脸还是标人体。如果题目强调“行人”,有些人会去标整个人体。但实践下来,口罩状态的判断必须看人脸,人体框对判断没有任何帮助。我最终只标人脸区域,类别定义写在报告里说明“先检测人脸区域,再根据人脸区域判断口罩佩戴状态”,逻辑上完全成立。

标注工具我用的是LabelImg,一个小众但好用的本地标注工具,支持PascalVOC和YOLO格式导出。多人图片注意不要漏标,也不要标重,一张图如果有20个人但只标了15个,训练的时候会产生大量漏检的负样本信息。

2.3 数据增强:防止过拟合的关键操作

口罩检测的场景比较固定,但监控场景的光线、角度、遮挡变化很大,所以增强是必须的。YOLOv8训练时自带一批增强策略,包括:

  • Mosaic增强:把4张图拼接成一张,增加单张图里的目标数量,对小人脸检测和遮挡场景提升非常明显。
  • HSV扰动:随机调整色相、饱和度、亮度,模拟不同光线条件。
  • 随机平移、缩放、旋转:模拟摄像头不同角度。

不过增强强度不是越大越好。实测下来,Mosaic在训练后期如果比例太大,会导致模型对小目标“见过太多拼接痕迹”,反而降低真实场景精度。我的做法是训练前50个epoch用默认增强,后面关掉Mosaic继续精调。

2.4 数据集规模与分配

完整做过一遍以后,我建议的最低数据量是这样的:

类别最低图像数量建议图像数量
正确佩戴口罩8002000
未佩戴口罩8002000
佩戴口罩不规范300800

我当时用的规模是接近3000张图,总标注目标约6000多个,训练集、验证集、测试集按8:1:1划分。这个体量对毕业设计来说已经足够,重点不在数量多,而是场景覆盖要广。

注意:三个类别的样本量要尽量均衡,至少不要差出10倍以上。不规范佩戴这类样本最难收集,但它恰恰是答辩时最容易被问到的场景,少了会影响模型表现。

3. 模型训练与优化过程

3.1 环境配置与训练基础设施

训练环境没什么特别的,一张中端显卡就能跑。我用的是单卡训练,显存8GB以上都够。具体软件版本:

  • 操作系统:Ubuntu 20.04
  • Python版本:3.9
  • 深度学习框架:PyTorch 2.0
  • CUDA版本:11.8(和显卡驱动配套即可)
  • YOLOv8库:ultralytics最新版

装环境这个环节,新手最容易翻车的是CUDA和PyTorch版本对不上。我的建议是直接用conda创建独立环境,不要动系统级的Python。具体指令:

conda create -n maskdet python=3.9 conda activate maskdet pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics

安装完以后跑一个最简单的人脸检测示例,确认环境能正常工作,再开始训练。这一步能省掉后面排查环境问题的大量时间。

3.2 训练参数配置与实验记录

训练时我选择的骨干网络是YOLOv8s,比最小的nano模型精度高不少,比中等的m模型速度更快,是权衡速度和精度之后的合理选择。输入分辨率我用640×640,这是速度和精度的常见平衡点。

关键参数记录一下:

  • 批次大小(batch size):16,显存不够可以减到8
  • 初始学习率(lr):0.01,用了余弦退火调度
  • 优化器:SGD,动量0.937,权重衰减0.0005
  • 训练轮数:120个epoch

第一次训练时我先小批量跑了20个epoch验证流程没问题,再跑完整120轮。每5个epoch保存一次权重,同时记录验证集mAP,训练结束以后选mAP最高那一轮的权重,而不是最后一轮。

这是我当时记录的几个关键实验结果:

模型配置验证集mAP@0.5单张推理耗时(ms)结论
YOLOv8n,640输入0.8236.8速度最快,精度略低
YOLOv8s,640输入0.87611.2速度和精度平衡
YOLOv8s,960输入0.89222.5小目标提升明显,速度下降
YOLOv8m,640输入0.88318.6精度提升有限,性价比较低

从结果看,YOLOv8s加640输入是我最推荐的配置。如果项目演示环境只有CPU,建议换成nano模型,并且把输入分辨率降到416,推理速度能提升一倍以上。

3.3 训练过程中的loss曲线怎么看

训练时loss曲线是判断模型是否健康学习的核心依据。YOLO的loss由三部分组成:box回归loss、分类loss、目标置信度loss。

我观察到的经验规律:

  • 前10个epoch loss下降非常快,这是模型在学习基本特征。
  • 20~50个epoch loss下降变慢,但mAP仍在爬升,这属于正常现象。
  • 最后几十个epoch如果loss有小幅波动,是余弦退火调整学习率导致的,不用太紧张。
  • 如果训练集loss持续下降但验证集mAP止步不前,说明过拟合了,需要加增广或者加数据。

还要重点看一个指标:PR曲线。在验证集上查看每个类别的精确率和召回率曲线,如果哪一类曲线下的面积明显小,就针对性补哪类的数据。

4. 推理部署与系统实现

4.1 检测流程设计与核心代码逻辑

模型训练完以后,下一步是把模型用起来。我实现了一个简单的检测服务,核心逻辑是这样:

  1. 读取输入帧(图片文件、视频帧、摄像头帧)。
  2. 送入模型推理,得到检测框、类别、置信度。
  3. 过滤低置信度结果(阈值我设置为0.45)。
  4. 对同一类别的框做非极大值抑制(NMS),消除重复框。
  5. 在原始帧上画框和标签。
  6. 统计各分类数量,反馈结果。

核心推理代码大概是这样的结构:

from ultralytics import YOLO # 加载训练好的模型 model = YOLO("best.pt") # 对单张图片推理 results = model.predict( source="test.jpg", conf=0.45, iou=0.5, imgsz=640, device="cuda" ) # 解析检测结果 for r in results: boxes = r.boxes for box in boxes: cls = int(box.cls.item()) conf = float(box.conf.item()) x1, y1, x2, y2 = box.xyxy.tolist()[0] print(f"类别: {cls}, 置信度: {conf:.2f}, 坐标: ({x1:.0f}, {y1:.0f}) - ({x2:.0f}, {y2:.0f})")

这段代码看起来简单,但里面有个非常容易被忽略的细节:模型输出的坐标是像素坐标,但如果你用了缩放或裁剪预处理,回画的时候要注意坐标是相对于哪个分辨率的。YOLOv8的predict方法自带缩放逻辑,输出坐标对应的是原图坐标,可以直接画,但如果自己写预处理就要额外处理坐标变换。

4.2 实时视频流与摄像头检测

毕设演示如果只检测图片,说服力会打折扣。我当时加了摄像头实时检测,使用OpenCV读取摄像头帧,逐帧送入模型推理。

import cv2 from ultralytics import YOLO model = YOLO("best.pt") cap = cv2.VideoCapture(0) while cap.isOpened(): success, frame = cap.read() if not success: break results = model(frame, conf=0.45, iou=0.5, imgsz=640) annotated = results[0].plot() # 直接在帧上画标注 cv2.imshow("Mask Detection Demo", annotated) if cv2.waitKey(1) & 0xFF == ord("q"): break cap.release() cv2.destroyAllWindows()

这里有一个关键性能问题:如果摄像头分辨率是1920×1080,而模型输入是640×640,GPU推理一次大约10毫秒(RTX 3070级别),但整条链路帧率仍然可能只有20到30 FPS。瓶颈往往在OpenCV读取和图像缩放这种CPU操作上。优化思路有两个:降低摄像头捕获分辨率到1280×720;或者把读取和推理放到两个线程里,用队列做缓冲区,实测帧率能提高50%以上。

4.3 Web端展示方案

为了答辩演示方便,我封装了一个简单的Web界面,用Flask做后端,前端页面支持上传图片、上传视频、打开摄像头三类功能。这个方案的思路是:后端接收文件,调用模型推理,返回标注后的图片和统计信息,前端展示结果。

Flask接口的大致逻辑:

from flask import Flask, request, jsonify, render_template import cv2 import numpy as np from ultralytics import YOLO app = Flask(__name__) model = YOLO("best.pt") @app.route("/detect", methods=["POST"]) def detect(): file = request.files["image"] img_bytes = np.frombuffer(file.read(), np.uint8) img = cv2.imdecode(img_bytes, cv2.IMREAD_COLOR) results = model(img, conf=0.45, iou=0.5) annotated = results[0].plot() # 统计各类别数量 counts = {} for r in results: for box in r.boxes: cls = int(box.cls.item()) counts[cls] = counts.get(cls, 0) + 1 _, buffer = cv2.imencode(".jpg", annotated) img_base64 = base64.b64encode(buffer).decode("utf-8") return jsonify({ "image": img_base64, "counts": counts })

Web端的价值在于让毕设看起来更完整,系统不用依赖命令行操作。而且Flask代码量小,写起来不费时间。如果你熟悉前端框架,用Vue或React改写会更漂亮,但对毕设来说Flask够用了。

提示:Web端和摄像头端引用同一个模型实例时要小心。如果两个功能分别加载了模型,显存占用翻倍先不说,第一次加载耗时也长。建议在Flask项目启动时预加载模型,之后所有请求共用同一个模型实例。

5. 常见问题与排查技巧实录

5.1 训练loss不下降,或loss直接为NaN

这个是我最早遇到的问题,相信很多人也碰过。可能的原因和排查顺序:

  1. 确认数据集标注文件没问题:检查YOLO格式的txt有没有类别id超过类别总数、坐标超出0~1范围的情况。
  2. 确认类别顺序和数据集配置文件一致:yaml文件里names的顺序和标注里的id要一一对应。
  3. 检查学习率是否过大:把初始学习率从0.01调低到0.001,如果loss恢复正常,就是学习率设置问题。
  4. 检查预训练权重版本:如果加载的预训练权重和模型的类别数不一致,头部初始化可能出问题。

训练时直接在终端打印loss值观察,如果前20个step就出现NaN,立即停止训练排查数据问题,不要硬着头皮往下跑。

5.2 小目标检测效果差,远处行人识别不到

监控场景里行人往往离摄像头比较远,人脸在画面里只占几个像素。这种情况下需要两个方向同时努力:

  • 数据侧重:把原始图片切分成小块,让小人脸变成“大人脸”再训练。我当时把部分图片做了滑窗切分,比如一张1920×1080的图切成4张960×540的图,这种操作相当于变相增加了小目标样本。
  • 推理设置:推理时把imgsz调到960或1280,小目标召回率会明显提升。代价是速度降低。针对视频检测可以做一个折中:每两帧用640分辨率,每隔一帧用960分辨率。

5.3 误检和漏检的具体优化经验

系统测试阶段发现的典型问题有:

  • 把戴口罩的人判定为未佩戴口罩,尤其是在侧面角度。原因往往是训练数据里侧面样本太少。对策是补充侧面、俯视角度的图片,或者用旋转增强。
  • 把非人脸的物体(比如背景海报上的人脸、玩偶脸)检测成未佩戴口罩。缓解办法是把conf阈值从0.45提升到0.55或0.6,虽然会漏掉一些模糊的人脸,但极大降低误报。
  • 多人相互遮挡时,漏检严重的往往是被遮挡的人脸。这种情况没有特别好的办法,能做的就是把NMS的IoU阈值调低一些,比如从0.5降到0.4,让两个高度重叠的框更可能都被保留。

5.4 推理速度不够怎么办

如果运行环境只有CPU,或者显卡性能一般,从这几个方向依次尝试:

  • 模型换小:从YOLOv8s换成YOLOv8n,实测在CPU上速度能快三倍。
  • 输入分辨率降低:从640降到416或320,代价是精度下降。
  • 导出为ONNX格式:用ONNX Runtime跑推理,比PyTorch的CPU推理快不少。YOLOv8官方支持一键导出:
yolo export model=best.pt format=onnx

导出的ONNX模型用ONNX Runtime加载推理,环境依赖更干净,也更容易部署到边缘设备上。

6. 个人经验与项目扩展方向

做完这个项目我最深的体会是:毕设项目“完成”和“做得好”之间差的不是技术难度,而是工程细节的完整度。数据集是否覆盖了足够多的真实场景、模型调参是否有记录、系统是否有可视化的交互界面、答辩时能不能清楚讲出每一步为什么这么选——这些才是拉开差距的地方。

如果你做完基础版本还有余力,有几个不错的扩展方向:

  • 在检测结果基础上加入跟踪算法,比如ByteTrack,可以对视频里同一目标跨帧计数,统计真实的人流数据。
  • 叠加一个人脸识别功能作为身份核验,把“是否佩戴口罩”和“是谁”两个信息联动起来。
  • 模型蒸馏:用大模型做教师、小模型做学生,在保持速度的前提下进一步提升精度,这个方向写进论文里会显得有思考深度。

最后说一个所有做毕设的人都应该养成的好习惯:每一次实验,不管是改数据、调参数还是换模型,都记在表格里。我当时维护了一张实验记录表,每一条包含时间、配置、mAP、速度、备注。答辩时老师问“你试过哪种方案、效果如何”,我直接照着表格讲,清晰又从容。这一点比多调几个参数都重要。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/20 4:35:25

zbrush精确输入角度旋转一个sub子物体

用 Tool → Deformation → Rotate,这是 ZBrush 里最接近“输数字”的地方。步骤:选中要转的 SubTool打开 Tool → Deformation找到 Rotate,右边有 X Y Z 三个字母点一下 X(或 Y/Z,变橙生效轴)再点一下 Rot…

作者头像 李华
网站建设 2026/10/20 4:34:30

多Agent协作的握手协议:优雅关机与计划审批从原理到落地

系列写到第 10 篇,前面聊了工具调用、上下文管理、路由分发,今天聊团队协作。在 Claude Code 这种 Agent 开发环境里,单机跑通只是开始,真正让它能进生产、能跟别的 Agent 一起干活,有两件小事绕不过去:一是…

作者头像 李华
网站建设 2026/10/20 4:34:11

ElevenLabs Brand Kit上线Creative:打造品牌声音资产

做内容做得久了,你会发现一个特别现实的问题:视频封面、字幕字体、图文排版都有统一的视觉规范,但声音往往是临时凑出来的。今天找一个配音搭子录两段,明天换一个 AI 音色顶上,后台音频文件翻出来五花八门,…

作者头像 李华
网站建设 2026/10/20 4:34:10

UNet图像分割毕设实战:从数据预处理到答辩话术的完整Python工程方案

简介:本资源是一份面向Python图像处理初学者与深度学习实践者的U-Net图像分割实战项目,聚焦生物医学、遥感及卫星影像等场景下的像素级分割任务。压缩包共21个文件,含7张JPG/PNG格式的原始图与预测结果图(如6100_2_4_pred_float_f…

作者头像 李华
网站建设 2026/10/20 4:34:02

MCGS串口通信实战:从配置到调试的完整指南

简介:这份资源围绕MCGS组态软件中的串口数据收发技术展开,面向工业自动化领域的组态开发人员、设备调试工程师以及需要实现设备间串行通信的初学者与进阶者。内容聚焦串口参数配置、通信对象建立、自由口协议下的数据收发与解析,以及超时重试…

作者头像 李华
网站建设 2026/10/20 4:33:24

面对一条孤立链接,如何拆解成可分析可复现的项目

1. 从一条链接说起:为什么“链接本身”也值得被当作一个项目来拆解先把话说在前头:我拿到的输入只有一条链接,没有任何正文、没有关键词、没有摘要描述。这种情况在实际工作里其实特别常见——同事甩过来一个地址,说“你看看这个”…

作者头像 李华