☰
基于卷积神经网络的口罩佩戴检测:从数据集到部署的完整实践指南
2026/10/20 21:50:48 网站建设 项目流程

前两天有个学弟问我,毕设想做“基于卷积神经网络的口罩佩戴识别与检测”,但又怕难度太高做不完,还怕答辩时被评委追问到答不上来。我直接跟他说:这个选题选得挺聪明。为什么?因为它既蹭上了“人工智能”和“深度学习”这些热门标签,又不像自动驾驶、医学影像分割那些方向一样需要庞大的工程量和算力资源,同时还能做成摄像头实时检测的现场演示,答辩效果很好。

这篇文章就把我从选题定调、数据集整理、模型选型、训练调参到实际部署踩坑的完整过程拆开讲。不管你是正在为毕设选题发愁的本科生,还是想用目标检测练手的入门开发者,照着这套思路走,至少能绕过一半弯路。

1. 选题定调与核心需求拆解

1.1 这个题目到底在做什么

“基于卷积神经网络的口罩佩戴识别与检测”这个标题看上去长,拆开其实就三个词:卷积神经网络、识别、检测。

“识别”对应的是分类问题,就是判断一张脸到底有没有戴口罩。“检测”则要往前走一步,不光要判断有没有口罩,还要把脸的位置框出来,输出一个坐标框和一个类别标签。挨在一起的两张脸,一张戴口罩一张没戴,你不能只说“有一个人没戴”,你得用框指出是左边还是右边那个。

很多入门者容易纠结“识别”和“检测”用词的区别,实际做毕设时不用太较真,因为目标检测模型天然就把这两件事一起干了。模型在做的是回归出边界框坐标,同时给框内目标做一个多分类。用生活化的类比就是:分类任务好比蒙着眼睛摸出苹果和橘子,检测任务则是睁开眼睛,直接指着桌上那个苹果说“这是苹果”。

这里用到的核心技术就是卷积神经网络,简称CNN。它通过多层卷积核在图像上滑动,提取从边缘、纹理到眼睛、嘴巴这类高层语义的特征。口罩佩戴检测本质上是利用CNN判别“嘴和鼻子区域是否存在口罩遮挡特征”的模式识别过程。

1.2 为什么这题适合做毕设

我的判断标准就三条:工程量可控、数据好找、答辩有展示点。

先说工程量。纯算法部分用现成开源检测框架来做,训练一个模型少则几小时,多则一个晚上,远没到需要专业团队和大规模集群的地步。相对更友好的地方是,数据采集不需要进实验室,公共数据集或者自己拍都能搞定。

其次是数据好找。口罩佩戴检测属于比较成熟的方向,公开数据集不少,分类类别也不复杂,最基础的就是戴口罩(with_mask)和不戴口罩(without_mask)两类。哪怕只有几千张图片,配合数据增强,训练出一个像样的小模型是可行的。

最后是展示效果。因为检测模型出结果快,你可以直接拿着笔记本摄像头现场演示:你戴上口罩,界面上绿色框提示with_mask;你摘下来,红色框提示without_mask。这种直观展示在答辩现场非常有优势,评委很容易理解你做的东西。

1.3 技术栈选型概览

动手之前先把技术栈定下来,我建议走这一套:

组件用途选型理由
Python主力开发语言AI生态最丰富,案例多,调试方便
PyTorch深度学习框架动态图机制,网上资料多,适合毕设阶段反复改实验
OpenCV图像处理与视频流读取支持摄像头调用、图像预处理
YOLO系列检测算法核心算法框架单阶段检测,速度快,社区教程多
LabelImg / Label Studio数据标注工具图形化界面,不需写代码

如果你用的是YOLO框架,PyTorch版本的生态是最完善的。不建议在这个阶段用TensorFlow,虽然也不是不行,但遇到报错时能搜到的解答数量差很多。毕设阶段效率优先,选资料多、装起来顺的工具比选所谓“工业界主流”更实际。

2. 数据准备:比调模型更磨人的环节

2.1 数据集从哪里来

很多人上来就想用别人的数据集,这没毛病,但不能直接拿过来就训练。我见过太多同学习惯把数据下载完就丢进模型,结果训练几轮之后loss高得离谱,最后才发现标签信息混乱、类别编号对不上。

口罩数据集数量够不够用?我的建议是最少准备2000到4000张图,每类样本尽量均衡。数据来源大致有三个方向:

  • 开源数据集:网上能搜到不少口罩检测公开数据集,下载后先仔细核对自己需要哪几类。有的数据集有很多类别,包括“口罩佩戴不规范”,这种会增加工程复杂度,毕设阶段先做到两类即可。
  • 网络图片补充:可以写个爬虫脚本去爬公开的图片素材网站,但要注意图片质量和版权,尽量选可商用协议或无版权图源。
  • 自拍数据:这是最靠谱的补充方式,自己戴不同口罩、在不同光照和角度下拍几十张,对提升实际场景鲁棒性很有帮助。

拿到图片之后最重要的准备工作是清洗。有些网图其实是漫画或插画,有些是带口罩的人拿着口罩的图,这些噪声样本都会干扰训练。建议过一遍图片,把明显不符合“真实人物脸部近景”标准的图片删掉。

2.2 标注格式与转换

你找的开源数据集很多是VOC格式,也就是每张图片对应一个XML文件,里面存着目标框坐标和类别名。但YOLO系列常用的训练标签是TXT格式,每行一条目标,格式是:

类别id x_center y_center width height

注意后面四个值都不是像素值,是归一化到0到1之间的比例值。转换公式很简单:

x_center = (x_min + x_max) / 2 / img_width y_center = (y_min + y_max) / 2 / img_height width = (x_max - x_min) / img_width height = (y_max - y_min) / img_height

我当时用LabelImg标注了一批补充数据,另写了一个Python脚本把XML批量转成TXT。这种脚本网上一搜一大堆,但要弄清楚一件事:VOC的bbox记录的是左上角和右下角坐标,而YOLO需要的是中心点坐标加上宽高。转换之前先把原始坐标画出来验证一遍,不然就会出那种框全偏了的低级事故,排查起来很花时间。

如果你懒得自己写转换脚本,也可以用Label Studio或者X-AnyLabeling这类工具直接导出YOLO格式,省一步转换麻烦。

2.3 数据增强策略

数据增强一定要做,但不要做过头。我见过有人把图片旋转了90度,结果人脸检测框都“躺”下了,这种样本放进训练集纯属添乱。

推荐的安全增强操作包括:水平翻转、小角度旋转(正负10度以内)、亮度对比度调整、随机裁剪和缩放、HSV色域扰动。口罩检测对光照比较敏感,适当增加亮度抖动可以让模型在教室、走廊这些实际场景里更稳定。

如果你用的是YOLO官方仓库,训练时它会自动带着超参数做马赛克增强(Mosaic),所以你在数据层面不用做太激进的增强,保持数据集类别平衡更重要。一个比较常见的坑是:因为戴口罩的图片获取成本低,很多数据集里with_mask样本远多于without_mask,训练出的模型对没戴口罩的情况不够敏感,这在检测场景里是大忌。遇到这种情况,要么收集更多不戴口罩的样本,要么在训练配置文件里给两个类别设置不同权重。

3. 卷积神经网络与检测模型:选型逻辑与结构拆解

3.1 卷积层到底在提取什么

模型选型之前,先把卷积神经网络的作用说透。YOLO也好,Faster R-CNN也好,底层都离不开CNN这个“特征提取器”。

你可以把卷积网络理解成一个层层递进的筛子。输入一张人脸图,最开始的卷积层可能只是在检测各种边缘和颜色块,比如鼻梁两侧的阴影线、口罩边缘的直线条。到了中间层,它开始组合出眼睛、鼻子、嘴这些部件级别的特征。到了深层网络,它已经能判断“这一块区域有没有被口罩覆盖住”这种抽象概念。

关键概念是“感受野”。浅层卷积的感受野小,看到的只是图像的局部细节;深层卷积经过多次下采样,每个像素对应的原图范围大,能感知全局结构。目标检测模型之所以能判断“哪里有人脸”“是否佩戴口罩”,本质上就是融合了这些不同尺度的特征。

3.2 为什么我选YOLO系列而不是Faster R-CNN

做目标检测,常见的方案分两派:两阶段检测器和单阶段检测器。

两阶段检测器以Faster R-CNN为代表,思路是先用区域提议网络找出可能包含目标的候选框,再对这些候选框逐一分类和回归。优点是精度高,缺点是速度慢,一张图可能要几百毫秒。

单阶段检测器以YOLO为代表,思路是直接在特征图上划分网格,每个网格预测目标框和类别,一步到位。速度快的优势明显,在GPU上跑到每秒几十帧没问题,非常适合做实时摄像头Demo。

毕设答辩时,模型能现场演示远比单纯刷高几个点的精度重要。我当时选的是YOLOv5s,理由是它轻、快、文档多、bug好搜。同一批数据,如果想尝试更强的精度表现,可以试试YOLOv8n或者YOLOv8s,它们的框架封装更友好,后处理逻辑也更清晰。

3.3 模型结构里的Backbone、Neck和Head

这个知识点基本是答辩必问项,最好提前弄明白。

YOLO系列整体可以拆成三部分:Backbone负责提取图像特征,Neck负责融合多尺度特征,Head负责输出最终的目标框和类别概率。

Backbone通常是一串卷积和下采样模块,把高分辨率的图像逐步压缩成小尺寸但通道丰富的特征图。Neck部分常见的是FPN特征金字塔结构,把浅层的细节信息和高层的语义信息融合起来。这一步的意义在于:脸上戴着口罩这种大目标需要全局特征,而口罩边缘的细节则需要浅层特征,两者缺一不可。

Head部分则是最终输出。以YOLOv5为例,它会在三个不同尺度的特征图上分别做预测,分别对应大、中、小目标。每个网格会预设若干不同长宽比的锚框(Anchor),模型预测的是锚框相对于真实框的偏移量。

有个小技巧:做口罩检测不要照搬默认的Anchor配置,你可以用官方脚本对自建数据集聚一下类,重新聚类生成更合适的Anchor,对提升小尺寸人脸的检测效果有一定帮助。

3.4 轻量化改造可以作为加分项

常规的YOLOv5s模型大概有700多万参数,推理时大约需要16GFLOPs的浮点运算量。这个量级在答辩电脑上用GPU跑没有问题,但如果你的毕设想体现部署能力,可以尝试做轻量化改造,比如把Backbone换成MobileNet系列,或者用TensorRT做推理加速。

我当时额外做了一版ONNX导出,再把模型放到CPU上跑推理,速度虽然比GPU慢不少,但展示“模型可移植、可部署”这一点确实能加分。你不需要做得多深入,只要让评委看到你有意识地在考虑模型体积、推理速度这类工程化问题,答辩深度就不一样。

4. 从环境配置到模型训练的全过程

4.1 环境搭建踩过哪些坑

先交代环境版本,我给学弟推荐的是这套组合:

conda create -n maskdetect python=3.9 conda activate maskdetect pip install torch==1.13.1 torchvision==0.14.1 --index-url https://download.pytorch.org/whl/cu116 pip install opencv-python pip install pyyaml tqdm matplotlib pandas seaborn

这里最常见的坑是CUDA和PyTorch版本不匹配。你装好的显卡驱动支持的最高CUDA版本,和PyTorch编译时用的CUDA版本不一定要完全一致,但PyTorch的版本必须能识别到你的显卡。判断标准就一条,在Python里执行:

import torch print(torch.cuda.is_available())

如果输出True,说明GPU环境没问题。如果输出False,多半是重装了PyTorch的CPU版本,或者显卡驱动版本太老。这个坑我在好多台机器上都见到过,解决办法就是驱动能升就升、重装对应CUDA版本的PyTorch。

如果电脑没有NVIDIA显卡,也别太沮丧。口罩检测这种小模型用CPU也能训练,只是速度慢很多。一个100轮的训练可能在GPU上跑三四个小时,CPU可能要跑十几个小时。实在不行可以用云GPU平台,按时租卡训练,成本也不算高。

4.2 数据集目录与训练配置

YOLO官方仓库对数据目录结构有要求,建议按这样组织:

mask_dataset/ ├── images/ │ ├── train/ │ │ ├── 0001.jpg │ │ └── ... │ └── val/ │ ├── 0401.jpg │ └── ... └── labels/ ├── train/ │ ├── 0001.txt │ └── ... └── val/ ├── 0401.txt └── ...

我习惯用脚本按比例切分数据集,训练集、验证集按9比1或者8比2分,注意保证各类别的图片在两个集合里比例一致,不要让某个类别全跑到验证集里。

对应创建一个mask.yaml文件,内容大致是:

path: mask_dataset train: images/train val: images/val nc: 2 names: ['with_mask', 'without_mask']

类别顺序一定要和标注文件里的类别id完全一致。我自己就曾经犯过错,把names列表顺序写反,结果模型训练了很久都“觉得”带口罩的脸是without_mask,前功尽弃。

4.3 训练参数到底怎么调

直接给一组我实测过比较稳的参数,以YOLOv5官方仓库为例:

python train.py --img 640 --batch 16 --epochs 100 \ --data mask.yaml --weights yolov5s.pt --device 0

--img 640是输入图片的尺寸。图片太大显存吃紧,而且口罩检测并不需要特别高分辨率,640是个均衡的选择。

--batch 16是批量大小,这个要看显卡显存来定。显存8G左右跑batch 16是没问题的,如果报OOM错误就降到8或者4。批量大小直接影响训练稳定性,不建议为了赶时间硬怼到爆显存。

--epochs 100是训练轮数。对于2000到4000张图的小数据集,100轮足够收敛了,再多轮容易过拟合。

--weights yolov5s.pt是预训练权重,这个很关键。直接用COCO数据集上训练的通用特征做初始化,比从头训练收敛快得多。口罩检测这种任务,底层的人脸、边缘特征和COCO里的目标特征有共通之处,迁移学习能省下大量训练时间。

训练跑起来之后,别只看Loss逐步下降就放心,还要盯验证集指标。建议每训练一段时间就打开runs/train/exp目录里的训练曲线图看一眼。如果train/box_loss一直在降但val/box_loss先降后升,说明模型开始过拟合了,这时候可以提前停止训练,然后调小学习率做几轮微调,或者使用更轻量级的模型结构。

4.4 记录实验是好习惯

做毕设期间一定要养成记录实验参数的习惯。我做了一个简单表格记录每次实验的配置和结果:

实验版本模型图片尺寸Epochs平均精度mAP@0.5备注
v1YOLOv5s640500.887基线
v2YOLOv5s6401000.921增加轮数后提升明显
v3YOLOv5s4161000.902小图速度更快但精度下降
v4YOLOv5m6401000.936大模型精度更高但推理慢

答辩整理材料时,这个表非常有用。你不需要在PPT里堆技术细节,一张对比表就能说明你做过哪些尝试、为什么选最终方案,这是评委最看重的“工作量体现”。

5. 模型评估与推理部署

5.1 用哪些指标说明模型效果好

目标检测最常用的指标是mAP,也就是平均精度均值。这里要分清两个概念:mAP@0.5和mAP@0.5:0.95。

mAP@0.5表示当预测框和真实框的交并比大于0.5时就认为检测正确,这是一个相对宽松的指标,行业里经常拿它作为主指标,很多公开模型报告的数值就对应这个。mAP@0.5:0.95则把阈值从0.5到0.95按0.05步长累加再取平均,要求更苛刻,更看重框得准不准。

毕设报告呈现上,把mAP@0.5写清楚就行。像口罩检测这类场景,模型对框的精确度容忍度相对较高,只要位置别偏得离谱,就已经能支撑门禁报警、巡检这类应用需求了。

如果你的模型能做到mAP@0.5在0.9左右,在论文里写“该模型在测试集上取得了较高的检测精度,能够满足实际场景中的口罩佩戴检测需求”,这句话完全站得住脚。实测下来,在两类目标、光线均匀的开源数据集上,达到这个水平是比较轻松的。

5.2 静态图片和视频检测实操

训练完成之后,runs/train/exp/weights/best.pt就是验证集表现最好的模型权重。用官方仓库自带的检测脚本,可以直接喂图片:

python detect.py --weights runs/train/exp/weights/best.pt \ --source test_images/ --conf-thres 0.45

--conf-thres是置信度阈值,只有置信度超过这个值的预测框才会显示。默认值一般是0.25,但对口罩检测这种场景,我更喜欢设到0.4到0.5。太低会出现大量误报,比如把衣领、手部误判成口罩;太高又会漏掉一些角度刁钻的“未戴口罩”目标。

输出结果会保存到runs/detect/exp,每张图都会画上检测框、类别标签和置信度。这个可视化结果多保留几个典型案例,答辩PPT里直接放模型预测前后的对比图,外行也能一眼看懂。

5.3 摄像头实时检测

上面都没问题之后,就可以上摄像头了。

python detect.py --weights runs/train/exp/weights/best.pt \ --source 0 --conf-thres 0.45

--source 0表示调用编号为0的摄像头,也就是笔记本内置摄像头。执行后屏幕上会弹出实时画面,带口罩时是绿框,不带口罩是红框。

如果想让程序对外输出一个接口,做一个更完整的Demo,可以考虑用Flask包一层HTTP服务,前端页面调用摄像头并把画面推送到后端,后端把推理结果框叠加后返回给浏览器。这个方向可以作为一个扩展亮点,不少高校的毕设都喜欢加入网页端展示。核心逻辑不复杂,就是在每帧图像上调用模型推理:

import cv2 import torch model = torch.hub.load('ultralytics/yolov5', 'custom', path='best.pt') cap = cv2.VideoCapture(0) while True: ret, frame = cap.read() if not ret: break results = model(frame) rendered_frame = results.render()[0] cv2.imshow('Mask Detection', rendered_frame) if cv2.waitKey(1) & 0xFF == ord('q'): break

这里有个细节:如果你的模型是用YOLOv5官方仓库训练的,加载权重时直接用torch.hub.load是省事的做法;如果你的模型结构被改过,比如换了Backbone,就必须把模型定义代码一起放在工程目录里,否则加载会报错。

实时检测时,帧率是另一个关注点。如果发现画面明显卡顿,可以先把输入视频帧缩小到640再送入模型,推理后再把检测框映射回原分辨率。GPU推理一帧大概在20到30毫秒,CPU则要200毫秒以上,卡不卡基本取决于你有没有显卡。

6. 常见问题与排查实录

6.1 CUDA不可用、显存不足和训练不收敛

训练阶段最容易碰到的问题,先列一个排查表:

现象可能原因解决办法
torch.cuda.is_available()为False安装的PyTorch是CPU版;显卡驱动太老安装对应CUDA版本的PyTorch;升级显卡驱动
训练报OOMbatch太大,或图片分辨率太高减小batch;减小--img尺寸;关闭一些不必要的训练时增强
Loss一直不降学习率太大;标签文件错乱;类别顺序不匹配调低学习率;可视化标签框;检查yaml文件类别顺序
训练完检测效果极差过拟合;数据量太少;正负样本不平衡增加数据增强;收集更多数据;使用预训练权重

有个隐蔽问题值得单独提:如果你下载的数据集标注框的类别id和源文件记录对不上,比如XML里写成mask,而你的names里写的with_mask,模型会把所有目标都当一个类来训练。你可以在训练前写个小脚本,把所有标注信息可视化到图片上,一张张快速浏览,能帮你发现很多数据层面的低级错误。

6.2 漏检与误检的平衡问题

口罩检测最常见的结果问题就是漏检和误检打架。把置信度阈值调高,误报少了,但漏检多了;调低阈值,漏检少了,但把背景误判成口罩的情况又变多。

我的实测经验是conf-thres设在0.4附近比较合适。另外,如果某个特定场景频繁误报,比如阳光直射在额头上被认成口罩,可以考虑在那个场景下多采集一些负样本,专门训练一个“背景干扰”类别,或者干脆把这些容易干扰的图片挑出来做增强。

如果模型对侧脸或者戴面纱、围巾这些人脸变体检测效果不好,可以尝试分阶段检测:先用一个通用人脸检测器找到人脸区域,再把人脸区域裁出来做口罩分类。这种方式虽然流程变长了,但每个环节的任务都变简单了,往往比端到端硬训练更可靠。

6.3 摄像头调用与画面显示问题

摄像头读取偶尔会有打不开的情况,多半是系统权限问题。Windows下检查相机隐私权限是否允许应用访问摄像头,Linux下用ls /dev/video*确认设备节点是否存在。还有一个常见坑是摄像头被其他程序占用,先把Zoom、微信视频这些占摄像头的程序全部关掉再试。

检测画面显示时,如果发现检测框在屏幕上闪烁得很厉害,很可能是置信度阈值太低,检测器在“有目标”和“没目标”之间反复横跳。把--conf-thres调高一点能改善体验,另外不要开视频流的后处理抖动这类功能,保持原始输出反而更稳。

最后分享一点个人经验

如果你现在正准备做这个题目,我的核心建议是:把最多的时间花在数据上,而不是在模型上。模型结构随便用开源框架都差不了太多,但数据集的质量、标签的准确度、类别的平衡性,直接决定你的上限。做的时候记得把每一次实验的参数、结果都归档,答辩时拿出来做对比,既展示工作量,也显得你的工程素养扎实。

整套做下来,最终我的模型在验证集上mAP@0.5达到了0.92左右,单张图片推理耗时在GPU上不到30毫秒,实时摄像头检测很流畅。这个成绩作为毕业设计完全够用。如果再往深做一点,可以尝试ONNX导出后在树莓派这类嵌入式设备上跑推理,那个方向就是另一段有意思的折腾了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询