资讯动态

口罩佩戴检测与人脸识别毕设项目:从模型串联到ONNX推理加速实战

发布时间:2026/10/18 4:50:45 来源:尧图企业网站定制
简介这份资源是一套基于Python深度学习实现的口罩佩戴检测与人脸识别系统完整源码面向计算机、电子信息等专业的学生及自学者可作为课程设计、期末大作业或毕业设计的参考方案帮助理解目标检测与人脸识别在实际项目中的落地方式。压缩包共86个文件约120.16MB包含21个py源码文件、19个pyc编译文件、17张jpg与jpeg图像、4个pth权重文件及配套的模型参数与视频素材另附requirements.txt依赖清单、README说明文档和界面文件覆盖从模型推理到图形界面交互的完整链路。项目内含mask检测、retinaface人脸检测、facenet识别等多个模块并配有图片、视频与摄像头三种推理入口便于对照学习检测流程与识别逻辑。目前已有437人学习下载适合希望快速上手深度学习视觉项目、需要完整可运行代码参考的读者。1. 口罩佩戴检测加人脸识别一个毕设项目为什么值得你花两周复现口罩佩戴检测和人脸识别放在同一个系统里听起来像是把两个独立任务硬拼在一起但真正动手跑过一遍就会发现它恰好覆盖了深度学习落地中最典型的几类问题目标检测的小目标漏检、分类阈值调参、人脸对齐与特征提取、以及多模型串联时的推理延迟。很多同学做毕设时卡在“模型能跑但效果玄学”的阶段本质原因不是网络结构不够新而是数据管道和阈值策略没吃透。这个方向适合已经学过 Python 基础、跑过至少一个 CNN 分类 demo 的人也适合想找一个完整度高、可拆解、能写进简历的工程型项目。你不需要从零训练一个 backbone但需要理解每个模块的输入输出边界以及当检测框抖动时人脸识别为什么会跟着翻车。2. 先搞清楚两个模型怎么串口罩检测与人脸识别的任务边界2.1 口罩佩戴检测到底在检测什么口罩佩戴检测通常被简化成“人脸检测 口罩分类”两步但实际落地时更稳的做法是直接训练一个多类别检测器输出三类框戴口罩、未戴口罩、未正确佩戴。常见做法是用 YOLOv5 或 YOLOv8 在 WIDER Face 基础上补充口罩标注数据因为 WIDER Face 本身只标了人脸框没有口罩类别。如果你手头只有分类数据集那就先用人脸检测器裁出人脸区域再送进一个二分类或三分类 CNN但这样会引入两个问题一是检测框裁剪时容易切掉口罩边缘二是级联延迟翻倍。我一般会建议毕设场景直接用 YOLO 系列做端到端检测类别数设为 3输入分辨率 640batch 16在单卡 8G 显存上就能跑起来。数据标注格式推荐 YOLO txt每行class x_center y_center width height归一化到 0 到 1。如果原始数据是 VOC XML需要写脚本转换注意xmin/ymin/xmax/ymax转中心点坐标时不要漏掉减一操作否则框会整体偏移一个像素在小目标上放大后很明显。import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_path, classes, output_txt): tree ET.parse(xml_path) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) lines [] for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in classes: continue cls_id classes.index(cls_name) bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 转中心点并归一化注意减一避免边界溢出 x_center (xmin xmax) / 2.0 / w y_center (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {bw:.6f} {bh:.6f}) with open(output_txt, w) as f: f.write(\n.join(lines))这段脚本的核心逻辑是把 VOC 的绝对坐标转成 YOLO 需要的归一化中心点格式。classes列表顺序必须和训练时data.yaml里的names一致否则类别会错乱。x_center和y_center除以宽高后范围在 0 到 1 之间如果出现大于 1 的值说明标注框超出了图像边界需要检查原始 XML 是否标错。2.2 人脸识别模块选型ArcFace 还是 FaceNet人脸识别部分毕设里最常见的是 ArcFace 和 FaceNet 两种。ArcFace 通过加性角度间隔损失让类内更紧凑、类间更分离适合做门禁机这类需要高区分度的场景FaceNet 用三元组损失训练时对样本挖掘策略敏感新手调参容易翻车。如果你只是做演示系统可以直接用预训练的 ArcFace 模型提取 512 维特征然后算余弦相似度做比对阈值一般设在 0.35 到 0.45 之间具体看你的底库规模。底库小于 100 人时阈值可以放到 0.45大于 1000 人时建议降到 0.35 以下否则误识率会飙升。人脸对齐是容易被跳过的一步。很多人直接把检测框裁出来送进识别模型结果侧脸和低头场景识别率断崖式下跌。常见做法是用 5 点关键点做仿射变换把眼睛和嘴巴对齐到标准位置。InsightFace 里自带face_align模块调用norm_crop即可输入是原图和 5 个关键点坐标输出是 112x112 的对齐人脸。这一步不做后面特征提取再强也白搭。2.3 两个模型串联时的输入输出约定口罩检测模型输出的是[x1, y1, x2, y2, conf, cls]列表人脸识别模型需要的是对齐后的 112x112 人脸图。串联逻辑是先跑检测过滤掉conf 0.5的框再对每个框做关键点检测或直接用检测框裁剪然后送进识别模型。注意如果检测框里的人是戴口罩的关键点检测可能会失败因为口罩遮挡了嘴巴区域。这时候可以退化成只用眼睛和鼻梁三点做粗略对齐或者直接跳过对齐用检测框裁剪后送进识别模型但识别率会下降 5 到 10 个百分点。我一般会在代码里加一个判断如果关键点数量少于 3 个就走降级路径保证系统不崩。3. 把环境跑起来从 Python 安装到 YOLO 训练的最小命令集3.1 Python 环境与依赖安装的避坑顺序Python 安装本身没什么好说的但版本选择有讲究。YOLOv5 官方要求 Python 3.8 以上PyTorch 1.7 以上但如果你用 YOLOv8建议 Python 3.9 到 3.10因为 3.11 在某些 CUDA 版本上会有兼容性问题。安装顺序应该是先装 CUDA 驱动再装 PyTorch最后装 ultralytics 或其他依赖。很多人反过来先pip install ultralytics结果 PyTorch 自动装了 CPU 版本训练时发现torch.cuda.is_available()返回 False又回头重装浪费一晚上。# 先确认 CUDA 版本再装对应 PyTorch nvidia-smi # 查看驱动支持的 CUDA 版本 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics opencv-python insightface onnxruntime-gpunvidia-smi右上角显示的 CUDA 版本是驱动支持的最高版本不是你必须装的版本。比如显示 12.2你可以装 cu118 或 cu121 的 PyTorch向下兼容。insightface安装时如果报编译错误先装cython和numpy再重试。onnxruntime-gpu的版本要和 CUDA 版本匹配否则推理时会报libcudnn.so找不到。3.2 用 YOLOv8 训练口罩检测模型的完整参数假设你已经把数据整理成images/train、images/val、labels/train、labels/val四个目录并且写好了data.yaml内容如下path: ./mask_dataset train: images/train val: images/val nc: 3 names: [mask, no_mask, improper]训练命令用 ultralytics 的 CLI 或 Python API 都行。我一般用 Python API方便加回调。from ultralytics import YOLO model YOLO(yolov8n.pt) # 从预训练权重开始小数据集上收敛更快 results model.train( datadata.yaml, epochs100, imgsz640, batch16, lr00.01, lrf0.01, patience20, device0, workers4, projectmask_train, nameexp1 )yolov8n.pt是 nano 版本参数量小适合毕设快速验证。epochs100配合patience20表示 20 轮没有提升就早停避免过拟合。lr00.01是初始学习率lrf0.01是最终学习率因子实际最终学习率是lr0 * lrf。workers4是数据加载线程数Windows 上如果报错就改成 0。训练完成后最佳权重在mask_train/exp1/weights/best.pt。3.3 人脸识别底库构建与比对脚本底库构建就是把每个人的人脸图跑一遍 ArcFace存成特征向量和姓名的映射。比对时算余弦相似度取最大值如果最大值低于阈值就判为陌生人。import cv2 import numpy as np from insightface.app import FaceAnalysis app FaceAnalysis(namebuffalo_l) app.prepare(ctx_id0, det_size(640, 640)) def build_gallery(image_paths, names): gallery {} for img_path, name in zip(image_paths, names): img cv2.imread(img_path) faces app.get(img) if len(faces) 0: print(f未检测到人脸: {img_path}) continue # 取最大人脸的特征 face max(faces, keylambda f: (f.bbox[2]-f.bbox[0])*(f.bbox[3]-f.bbox[1])) gallery[name] face.embedding return gallery def recognize(face_embedding, gallery, threshold0.4): best_name unknown best_score -1 for name, emb in gallery.items(): score np.dot(face_embedding, emb) / (np.linalg.norm(face_embedding) * np.linalg.norm(emb)) if score best_score: best_score score best_name name if best_score threshold: return unknown, best_score return best_name, best_scorebuffalo_l是 InsightFace 的预训练模型包包含检测和识别。det_size(640, 640)是检测输入尺寸如果图片里人脸很小可以调大到 1024但速度会下降。face.embedding是 512 维归一化向量直接算点积就是余弦相似度。阈值 0.4 是经验值实际部署时要用一批已知身份的图片跑 ROC 曲线选等错误率最低的点。4. 避坑与排查口罩遮挡、阈值玄学和显存溢出4.1 口罩遮挡导致关键点检测失败现象戴口罩的人脸送进关键点检测模型返回的关键点数量少于 3 个或者嘴巴点跑到口罩外面。原因关键点模型训练时用的数据大多没有口罩遮挡遇到口罩就懵了。解决在关键点检测前先判断是否戴口罩如果检测框类别是mask就只用眼睛和鼻梁三点做对齐或者直接跳过对齐用检测框裁剪后送识别模型。更稳的做法是训练一个口罩专用的关键点模型但毕设时间紧的话降级方案足够用。4.2 置信度阈值调高后漏检调低后误检现象conf0.5时有人戴口罩没检测出来conf0.3时背景里的口罩图案被误检成人脸。原因模型在验证集上的 mAP 高不代表实际场景好尤其是小目标和遮挡目标。解决不要全局调阈值按类别调。戴口罩类别可以设 0.4未戴口罩设 0.5未正确佩戴设 0.45。在 YOLOv8 里可以在推理时传classes和conf参数也可以后处理时按类别过滤。另外加一个 NMS 的iou_thres0.45避免同一个目标出多个框。4.3 显存溢出与 batch size 的取舍现象训练时CUDA out of memory或者推理时同时加载检测和识别模型导致显存不够。原因YOLOv8n 在 640 分辨率下 batch 16 大约占 4G 显存ArcFace 模型占 1G 左右如果显卡只有 6G两个模型同时跑就会爆。解决训练时把 batch 降到 8或者用imgsz416。推理时可以用 ONNX Runtime 或 TensorRT 加速减少显存占用。如果还是不够就把检测和识别分两个进程跑用队列通信但延迟会增加。4.4 人脸底库特征未归一化导致相似度计算错误现象余弦相似度算出来大于 1 或小于 -1识别结果乱跳。原因face.embedding已经是归一化向量但如果你自己用其他模型提取特征忘了做 L2 归一化点积就不是余弦相似度。解决在比对前统一做emb / np.linalg.norm(emb)或者直接用np.dot前检查范数是否为 1。另外底库特征存成float32不要存成float16否则精度损失会让相似度偏差 0.01 到 0.02在阈值附近就是误判。4.5 视频流推理延迟累积现象摄像头读帧后处理一帧要 200ms导致画面卡顿延迟越积越大。原因检测和识别串行执行且每帧都跑识别。解决检测每帧都跑识别每隔 5 帧跑一次或者用跟踪算法如 ByteTrack给每个人分配 ID同一个 ID 只识别一次。这样能把延迟降到 50ms 以内。另外把 OpenCV 的cv2.imread换成cv2.VideoCapture的read避免重复解码。5. 进阶技巧用 ONNX 导出把推理速度压到实时5.1 把 YOLOv8 和 ArcFace 都导出成 ONNX训练完的 PyTorch 模型推理时有一层 Python 开销导出成 ONNX 后用 ONNX Runtime 跑速度能提升 30% 到 50%。YOLOv8 导出很简单from ultralytics import YOLO model YOLO(mask_train/exp1/weights/best.pt) model.export(formatonnx, imgsz640, halfTrue)halfTrue表示用 FP16 精度显存占用减半速度提升但精度损失很小。ArcFace 的 ONNX 导出需要手动写import torch from insightface.model_zoo import get_model model get_model(buffalo_l, providers[CUDAExecutionProvider]) # 实际导出需要拿到 torch 模型这里用示例说明 # torch.onnx.export(model, dummy_input, arcface.onnx, opset_version11)注意 InsightFace 的模型包不一定直接暴露 torch 模型常见做法是用onnxruntime直接加载官方提供的 ONNX 文件或者用torch.onnx.export导出自己训练的模型。导出时opset_version建议 11 或 13太低不支持某些算子太高某些推理引擎不兼容。5.2 ONNX Runtime 推理的会话配置import onnxruntime as ort sess_options ort.SessionOptions() sess_options.graph_optimization_level ort.GraphOptimizationLevel.ORT_ENABLE_ALL sess_options.intra_op_num_threads 4 session ort.InferenceSession(mask.onnx, sess_options, providers[CUDAExecutionProvider]) input_name session.get_inputs()[0].name output session.run(None, {input_name: blob})graph_optimization_level设为ORT_ENABLE_ALL会做算子融合和常量折叠推理速度提升明显。intra_op_num_threads控制单算子并行线程数一般设为 CPU 核心数的一半。providers里CUDAExecutionProvider要放在CPUExecutionProvider前面否则会回退到 CPU。5.3 一个验证系统是否达标的小技巧不要只看准确率要看混淆矩阵和每类召回率。口罩检测里no_mask的召回率比精确率更重要因为漏掉一个未戴口罩的人比误报一个戴口罩的人风险更高。人脸识别里看 ROC 曲线和等错误率不要只看阈值 0.4 下的准确率。我一般会跑一个 200 张图的测试集统计检测 mAP50、识别 Top1 准确率、以及端到端延迟。如果 mAP50 低于 0.85先检查标注质量如果识别准确率低于 0.9先检查人脸对齐和底库特征归一化。最后说一个我踩过的坑不要等到最后一周才把检测和识别串起来。两个模型单独跑都正常串起来可能因为坐标系不一致、图像通道顺序不同、或者归一化参数不匹配而翻车。我习惯在项目第一天就写一个最小串联脚本用一张图跑通全流程后面再逐步替换模型和优化参数。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑