简介:基于YOLOv4与PyTorch的人脸口罩识别项目,面向计算机视觉方向的在校学生、科研人员及需要完成课程设计或毕业设计的开发者,旨在帮助快速掌握目标检测工程流程,并直接用于口罩佩戴场景识别与演示。压缩包共367个文件,大小约9.31MB,内部包含可直接运行的Python源码、完整文档、预训练模型与3段测试视频,文件类型以XML标注、py脚本、txt配置、jpg预览图和avi视频为主,另附sqlite数据库与项目状态记录,便于梳理数据标签、网络结构与推理日志。已有53人浏览学习。项目提供清晰的README引导,代码经过测试可稳定运行,既能直接用于课设、毕设答辩演示,也能在此基础上替换数据集、调整检测类别,扩展为人脸检测、行人检测等其他视觉任务,具备较强的二次开发与学习进阶价值。
1. YOLOv4人脸口罩识别:这份毕设级PyTorch源码包能解决什么问题
人脸口罩识别是毕设和课设里的高频选题:数据集好找、模型不复杂、演示效果直观。但很多同学拿到一个YOLOv4源码包后,卡在环境装不上、视频读不出来、检测框偏移这几个地方,最后把时间全耗在排错上。这份基于YOLOv4和PyTorch的Python源码包,把一条完整的口罩识别链路带齐了——模型代码、训练好的权重、测试图mask.jpg、三段实测视频output202212031534.avi这类真实运行记录、以及结果图result.jpg。它适合计算机相关专业学生直接跑通毕设流程,也适合想快速上手YOLOv4推理的从业者当参考骨架。我拆完的感受是:它不是一个只能看不能跑的展示壳子,而是一套能验证的完整链路——从视频帧到检测框再到标注输出,每一步都有对应文件可以对照检查。接下来按项目结构、环境搭建、核心代码、踩坑记录和改造方式逐层拆。
2. 项目文件拆解与数据流向:先看懂每个文件再动手跑
拿到压缩包先别急着双击运行。YOLOv4这个项目代码量不小,如果连哪些文件是核心、哪些是IDE自动生成的都没分清,排错时会被无效信息干扰。我先带你过一遍文件结构,再讲数据是怎么从输入流到输出的。
2.1 文件清单与用途:核心文件、测试产物、环境痕迹要分开看
这个项目里的文件可以分三类。第一类是工程配置文件:.gitignore管理版本控制时的忽略列表,yolov4-pytorch-master.iml是IntelliJ IDEA的模块描述,VSWorkspaceState.json是VS Code的工作区状态记录。这三个都是开发环境自动生成的,不影响推理逻辑,删掉也不影响运行。唯一要注意的是,如果你换IDE打开项目,.iml和VSWorkspaceState.json可能会被重新生成或忽略,不用管它。
第二类是测试图像和结果图。mask.jpg是测试输入图,内容应该是一张戴口罩的人脸照片;result.jpg是推理结果图,模型检测到口罩后会在图上画出边界框和置信度标签。把这两张图放在一起对比,就能最快确认模型权重是否正常——如果mask.jpg里戴口罩的区域被框住且置信度显示在90%以上,说明模型工作正常;如果框偏了或者没有框,说明cfg配置或权重出了问题。video_tmp.jpg是中间过程帧,一般是抽帧调试用的临时文件,代表视频流里某一帧被单独保存下来做了处理,可以理解为视频检测的静态截图。
第三类是核心演示素材,也就是三个AVI视频:output202212031534.avi、output202212031535.avi、output202212041735.avi。从命名规则看,20221203是日期,1534是时分,这套命名是典型的实测输出记录。视频内容应该是摄像头或现成视频文件跑检测后的结果,连续帧上叠加了检测框。这是整份资源里最有说服力的部分——单张图片可以修图造假,但连续视频很难伪造,你可以直接看到模型在多帧画面上的稳定性和漏检率。
2.2 README.md在项目里的角色与运行入口
README.md是这份资源里唯一的说明文档。下载后第一步一定是打开它,里面一般会写明:环境依赖要求(Python版本、PyTorch版本、OpenCV版本)、模型文件位置、检测脚本入口、以及权重文件的来源说明。毕设项目通常还会附上训练集的来源和类别定义——比如这个口罩识别模型训练时用的是两类(佩戴口罩with_mask、未佩戴口罩without_mask)还是三类(额外加一个口罩佩戴不规范face_with_mask_wrong)。
现在的关键问题是:这份项目文件列表里没有直接出现.py文件和权重文件,但这不等于没有。YOLOv4的PyTorch实现一般需要cfg配置文件、weights权重文件和detect.py推理脚本。如果压缩包解压后找不到,你要先检查是不是在子目录里(比如yolov4-pytorch-master/文件夹内),这一步很多初学者直接忽略,结果报错No module named 'models'。如果确实没有,看README里有没有写权重下载链接,或者检查.gitignore是不是把weights/目录排除了。
2.3 数据流向:从mask.jpg到result.jpg再到AVI视频的完整链路
我把这个项目的数据流梳理成一条线,方便你后续调参时定位问题。整条链路是:读取输入(图片或视频帧)→ letterbox预处理(保持宽高比缩放并填充) → 归一化到0到1区间 → 输入Darknet53骨干网络提取特征 → CSP结构跨阶段局部连接 → PANet做多尺度特征融合 → 三个YOLO Head分别输出不同尺度的预测结果 → 解码边界框坐标 → 按置信度阈值过滤低分框 → NMS非极大值抑制去重 → 把检测框坐标还原到原图坐标系 → 在原图上绘制矩形框和类别标签 → 保存为result.jpg或写入输出视频。
mask.jpg到result.jpg是单帧静态验证链路,适合在调试参数时反复跑;三个AVI视频是连续帧循环链路,模型在每一帧上都走一遍完整流程。这里有个细节值得注意:视频检测时如果遇到画面里远处有人经过,小尺寸目标检测依赖的是YOLOv4的52×52大尺度特征图,这个特征图感受野小、对小目标敏感,但也更容易把背景误判成人脸,所以你看视频输出时会发现远处行人的检测框抖动得比近处明显,这是模型本身的特性,不是bug。
从项目正文的文件排列看,三个AVI视频体积不小,说明编码格式大概率是MJPG或类似格式,这会影响OpenCV读取时的兼容性,具体坑位在第5章会展开。接下来先把环境配起来,这一步过了,项目才能跑起来。
3. 环境搭建与依赖装法:PyTorch版本、CUDA和OpenCV怎么配不翻车
YOLOv4的PyTorch实现,最核心的依赖就三样:PyTorch本体、OpenCV(图像视频读写)、NumPy(张量操作)。这三样版本配不对,后面每一步都会出莫名其妙的问题。比如PyTorch版本太老,torchvision的transform接口对不上;OpenCV版本太新,某些YOLO代码里用的旧API被移除,直接抛AttributeError。我先给出一套我验证过的最稳组合,再讲参数怎么调整。
3.1 PyTorch安装与CUDA匹配:GPU和CPU两条路怎么选
YOLOv4推理对显存要求不高,以最常见的416×416输入尺寸为例,一张图前向传播的显存占用大约1.2GB到1.8GB,取决于batch size和是否开启梯度记录。所以如果你的显卡是GTX 1660及以上,优先装CUDA版PyTorch,跑视频检测能到30帧以上;如果电脑只有核显,CPU版也能跑,只是速度会掉到每秒3到5帧,作为毕设演示够用但流畅度差一些。
PyTorch的安装现在统一走pip或conda。以CUDA 11.8搭配PyTorch 2.0这个稳定组合为例,安装命令如下:
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118如果机器上没装NVIDIA驱动,或者驱动版本太老识别不了CUDA,那你就直接用CPU版:
pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu装完之后,立刻做一次验证,确认PyTorch能不能调用GPU:
python -c "import torch; print(torch.__version__); print('CUDA available:', torch.cuda.is_available())"这段命令会输出两个信息。第一个是PyTorch版本号,比如2.0.1+cu118,加号后面的cu118表示这个版本的PyTorch是用CUDA 11.8编译的。第二个是torch.cuda.is_available()的返回值,如果输出True,说明GPU可用;如果False,说明你的驱动版本和PyTorch要求的CUDA版本不匹配,或者压根没装驱动,后面推理会自动退回CPU,但不会直接报错。
这里有个常见的误区:不是驱动版本越高越好。PyTorch的CUDA运行时依赖驱动层的兼容版本,驱动太新(比如555版本配老PyTorch 1.7)反而可能出现CUDA error: no kernel image is available for execution on the device,这种报错就是驱动新过头了,老PyTorch里的kernel不认新GPU架构。遇到这种情况,要么升级PyTorch,要么装回和GPU架构匹配的老驱动,二选一,没有第三条路。
3.2 OpenCV和NumPy的安装与验证
OpenCV是这个项目里第二个容易翻车的依赖。推荐直接装opencv-python,不要图省事装opencv-contrib-python,后者体积大而且经常和某些YOLO工具函数冲突。安装命令:
pip install opencv-python numpy装完之后,用一段短脚本验证图像读写和视频解码能不能用:
import cv2 import numpy as np # 读取测试图,确认基础图像IO正常 img = cv2.imread('mask.jpg') print('image shape:', img.shape) # 输出(H, W, 3) # 打开视频文件,测试视频解码器是否可用 cap = cv2.VideoCapture('output202212031535.avi') if not cap.isOpened(): print('视频打开失败,检查路径或解码器') else: ret, frame = cap.read() if ret: print('frame shape:', frame.shape) else: print('视频文件无法解码出第一帧') cap.release()img.shape输出是三维元组,第一个值是图像高度,第二个是宽度,第三个是通道数3。如果mask.jpg读取后shape是None,说明路径不对或者图像文件已损坏。VideoCapture如果isOpened返回False,九成是文件路径写错,或者OpenCV编译时没带FFmpeg组件;如果isOpened是True但read返回False,那问题是视频编码格式不被OpenCV支持,具体解法放在第5章。
3.3 Python版本的选定与conda环境隔离建议
Python版本建议固定在3.8或3.10。3.7太老,部分新版本依赖库没有对应wheel包;3.11及以上跑老YOLOv4代码时,torch里某些API会报DeprecationWarning,虽然多数情况下不影响运行,但碰到个别算子重写的版本直接跑崩也不奇怪。
我用的是Anaconda做环境隔离,这条路径对毕设项目尤其重要——你电脑上可能还装TensorFlow或者其他深度学习框架,如果全部怼进base环境,版本冲突能把人逼疯。建一个独立环境再装依赖:
conda create -n yolov4 python=3.8 -y conda activate yolov4 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install opencv-python numpyconda create后面的-n yolov4是环境名,python=3.8指定版本,-y跳过确认提示。激活命令conda activate yolov4后,终端前面会出现(yolov4)前缀,这时候pip装的所有包都只在这个环境里生效,出了环境互不影响。环境隔离这件事,我从第一次被依赖冲突搞到重装系统后就开始强制执行,后面再也没翻过车。
4. 核心推理代码解读:模型加载、letterbox预处理与NMS参数怎么调
环境配好后,项目的核心是推理脚本。YOLOv4的PyTorch实现有很多个版本,但主链路大体一致。这一章会把模型加载、图像预处理、推理后处理三段代码拆开讲,让你知道每个参数动了之后会发生什么。
4.1 模型加载与cfg配置文件的对应关系
YOLOv4在PyTorch里的模型定义一般分成两套:一套是自定义的Darknet类,读取.cfg文件逐层构建网络;另一套是直接import现成模块。这套项目里大概率用的是自定义加载器。核心逻辑如下:
import torch from models import Darknet # cfg定义网络结构,weights存放训练好的参数 cfg_path = 'cfg/yolov4-mask.cfg' weights_path = 'weights/yolov4-mask.weights' model = Darknet(cfg_path) model.load_weights(weights_path) model.eval() # 切换到推理模式,关闭dropout和BN的batch统计Darknet(cfg_path)会逐行解析cfg文件里的[convolutional]、[route]、[shortcut]、[yolo]等层定义,构建出完整的CSPDarknet53骨干网络加PANet特征融合结构。load_weights把.weights文件里按层序排列的浮点参数填充到模型里。这里有一个非常关键的校验点:cfg文件里每个[yolo]层的classes字段必须和weights训练时的类别数一致。
比如训练时用两类(with_mask、without_mask),cfg里classes=2,那推理脚本里的类别标签列表也必须刚好两个名字,且顺序要和训练一致。如果cfg写的类别数和weights不匹配,加载过程不会报错,因为.weights文件按层数填充,但最后输出张量的第三维通道数会不一样,解析预测结果时维度对不上,直接崩在view()操作上。
4.2 letterbox预处理:为什么不能直接resize
口罩检测输入图片前,必须做letterbox处理,也就是保持原始宽高比缩放,短边用灰色填充到目标尺寸。直接粗暴resize到416×416会让画面里的脸变形拉伸,模型训练时学的是正常比例的特征,喂给它的图变形了,检测框位置必然偏。
这里给出一个标准letterbox实现的核心逻辑:
import cv2 import numpy as np def letterbox(img, new_shape=(416, 416), color=(114, 114, 114)): shape = img.shape[:2] # 原始尺寸 (H, W) r = min(new_shape[0] / shape[0], new_shape[1] / shape[1]) # r是缩放比例,取宽高两个方向较小的因子 # 保证整张图等比缩放后完整落在目标尺寸内 new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) # new_unpad是等比缩放后的宽高 # 计算需要填充的边长 dw = (new_shape[1] - new_unpad[0]) / 2 dh = (new_shape[0] - new_unpad[1]) / 2 # 先等比缩放 if shape[::-1] != new_unpad: img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR) # 再等分填充上下左右 top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1)) left, right = int(round(dw - 0.1)), int(round(dw + 0.1)) img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) return imgr是缩放比例,取min值保证宽高都不超出目标尺寸。dw和dh是填充像素数,除以2是因为上下和左右各填充一半,让内容集中在图像中心。cv2.copyMakeBorder的BORDER_CONSTANT模式用纯色填充,value=color默认114是YOLOv4训练时的填充色。
推理完成后,模型输出的框坐标是letterbox处理后的坐标系里的,画框前必须把坐标还原到原始图像坐标系。这一步是检测框偏移问题的高发区,常见的错误是只除以缩放比例忘了减填充量。正确做法是:
def scale_coords(img1_shape, coords, img0_shape): gain = min(img1_shape[0] / img0_shape[0], img1_shape[1] / img0_shape[1]) pad_x = (img1_shape[1] - img0_shape[1] * gain) / 2 pad_y = (img1_shape[0] - img0_shape[0] * gain) / 2 coords[:, [0, 2]] -= pad_x # x方向减去水平填充 coords[:, [1, 3]] -= pad_y # y方向减去垂直填充 coords[:, :4] /= gain # 再除以缩放比,还原到原图坐标 return coordspad_x和pad_y就是letterbox里算出的dw和dh,必须和预处理时完全一致。如果预处理改了输入尺寸,这里也要同步改,两个函数是成对出现的。coords[:, [0, 2]]是x1和x2坐标,coords[:, [1, 3]]是y1和y2坐标,先减pad再除gain,顺序不能反。
4.3 推理循环与后处理:置信度阈值和NMS怎么配合
模型前向传播输出的是三个尺度的原始预测张量,需要经过解码得到边界框坐标、置信度和类别概率,然后做合并和过滤器。这段是调参的核心地带:
conf_thres = 0.5 # 置信度阈值,低于这个分数的框直接丢弃 nms_thres = 0.4 # NMS的IoU阈值,重叠度超过这个值的框被合并 with torch.no_grad(): output = model(images) # 三个尺度的输出列表 # output经过解码后得到坐标、置信度、类别 boxes, scores, classes = decode_output(output, conf_thres) # 用OpenCV的NMS实现做去重 indices = cv2.dnn.NMSBoxes( boxes.tolist(), scores.tolist(), conf_thres, nms_thres )with torch.no_grad()是必须的。如果不加,PyTorch会为每个前向传播构建计算图保存梯度信息,推理几十帧后内存直接爆炸,视频检测跑到一半就OOM了。decode_output内部会把三个尺度的预测框叠加,然后按conf_thres过滤低于阈值的框。
conf_thres和nms_thres这两个参数是调优的重头戏。conf_thres控制检出的数量和误检率:调低到0.3能检出更多目标,但背景里的非人脸区域也会被误判成口罩,误检框增多;调高到0.7则相反,遮挡严重或模糊的小目标会被漏掉。口罩识别场景建议从0.5起步,根据测试视频里漏检和误检的比例再微调。
nms_thres控制相邻框的合并策略:调高到0.6会让重叠度高的框更容易合并,适合人多的密集场景,避免同一个人的脸被框两次;调低到0.3则保留更多独立框,适合单人或距离远的场景。这两个参数没有绝对最优,必须配合测试视频反复跑几轮才能找到平衡点。我的习惯是先固定nms_thres为0.4,单独调conf_thres,确定conf再调nms,避免两个参数同时动导致无法判断是谁的影响。
5. 避坑指南:口罩识别项目运行中的五个高频问题与修复路径
这一章直接给结论。下面五条都是我在实际跑YOLOv4口罩识别项目时真碰到过的坑,按复现频率排序,每一条都按现象→原因→解决的路子来写,可以直接抄作业。
5.1 AttributeError: 'Darknet' object has no attribute 'load_weights'
现象:运行推理脚本,第一行模型加载就报错,提示Darknet类没有load_weights这个属性。
原因:YOLOv4的PyTorch实现版本太多了,不同版本的权重加载方法名不统一。有的叫load_weights,有的叫load_darknet_weights,还有的直接用load_state_dict从.pth文件读取。你的脚本调用方式和模型类定义对不上。
解决:打开模型定义文件(一般是models.py或darknet.py),用Ctrl+F搜一下实际有哪些加载方法。如果是load_darknet_weights,改脚本调用名;如果只有load_state_dict,说明需要先把.weights文件转成.pth格式,或者找到项目里自带的转换脚本。毕设项目一般会附带转换工具,检查README里有没有说明。
5.2 视频文件读出来是黑屏或read失败
现象:cv2.VideoCapture打开output*.avi时,isOpened()返回True,但read()拿不到有效帧,要么返回False,要么frame是全黑图。
原因:OpenCV的FFmpeg后端对MJPG编码的AVI支持有时会有问题,尤其在Windows平台下默认安装的opencv-python可能缺少部分解码组件。项目输出视频如果用的是MJPG编码,刚好踩中这个兼容性盲区。
解决:两个方案。第一个是换用opencv-python-headless版本,它去掉了GUI模块但视频编解码组件更完整:
pip uninstall opencv-python pip install opencv-python-headless第二个是用ffmpeg命令行先把AVI转成MP4的H.264编码,再让OpenCV读新文件:
ffmpeg -i output202212031535.avi -vcodec libx264 -crf 23 output202212031535.mp4-crf 23是质量参数,数值越小画质越高,23是默认值,转出来的文件大小和质量都均衡。转完后把脚本里的路径改成.mp4后缀即可。
5.3 模型加载成功但推理结果全是空框
现象:脚本能跑通,视频窗口也弹出来了,但画面里没有任何检测框,或者框的置信度全部低于显示阈值。
原因:九成是conf_thres设太高。模型训练时如果数据里有大量远距离小人脸,这些目标的置信度天然就低,0.5的阈值会把它们全部滤掉。还有一成可能是预处理时letterbox的填充尺寸和推理脚本里设置的输入尺寸不一致。
解决:先把conf_thres降到0.1跑一轮视频,确认能出框再慢慢往上调。如果0.1都不出框,检查letterbox函数里的new_shape参数是不是和模型cfg里定义的width、height一致。cfg网络结构里第一层[net]的width=416, height=416,如果代码里用了608但cfg写的是416,虽然PyTorch不会报错(卷积层能处理任意输入尺寸),但权重是按416训练的特征响应,结果完全不可用。
5.4 GPU显存OOM(CUDA out of memory)
现象:跑视频推理到第几十帧时,终端报CUDA out of memory,进程直接退出。
原因:最常见的是输入尺寸被调到608×608或更高,显存占用成倍上涨。另一个隐蔽原因是推理循环里忘了加torch.no_grad(),每帧都在构建计算图,几十帧后累计显存爆掉。
解决:把输入尺寸固定为416×416,这是YOLOv4官方推荐的速度精度平衡点。另外在推理循环外侧加with torch.no_grad():,把前向传播包进去,这一步能立即释放掉梯度图占用的显存。如果还爆,把项目默认的batch_size改为1,不要用训练时的批量设置。
5.5 检测框整体偏移:位置偏左上或偏右下
现象:result.jpg里检测框能框住目标,但框的位置整体向左上或右下偏移,偏移量固定,戴口罩的嘴部区域不在框中心。
原因:坐标还原时漏了letterbox的填充量补偿。模型输出的是缩放填充后图像坐标系里的坐标,画框前没调用scale_coords函数,或者调用时传的输入尺寸参数和预处理时不一致。
解决:检查推理脚本里画框前的坐标转换部分。用4.2小节里的scale_coords函数,第一个参数传预处理后的图像尺寸(比如416, 416),第二个传模型输出的坐标张量,第三个传原始图像尺寸(比如frame.shape[:2])。关键是预处理时的dw、dh必须和scale_coords里算出来的一致,两个函数成对使用,不要拆分。
5.6 教训总结与检查习惯
这五个坑看起来分散,但根子是同一个:YOLOv4项目版本杂乱,代码风格不统一,换个环境编译就可能触发不同的兼容性问题。我的习惯是拿到任何YOLOv4源码包,先花十分钟做三件事:检查cfg里的classes数、确认推理脚本调用的方法名和模型定义一致、用单张图片跑通静态推理再上视频。这三步走完,上面五个坑能挡住四个。从那以后我每次拿到新的YOLO项目都强制走一遍这个检查流程,再开始调参。
6. 把静态视频改成摄像头实时检测:一个让毕设效果翻倍的改造技巧
项目默认输入是AVI视频文件,但如果答辩现场要展示,摄像头实时检测的冲击力远比播放录好的视频强得多。改造思路不复杂,核心是替换数据源、调整参数、优化延迟三步。
摄像头实时检测的代码改动集中在cv2.VideoCapture的入参上。视频文件传路径字符串,摄像头传设备索引号,0代表默认摄像头。但这里藏着一个容易忽略的坑:视频文件帧率固定,而摄像头帧率取决于环境光线和驱动,推理速度跟不上时画面会卡顿。所以实时模式下有三处参数要调:输入尺寸从416降到320或更低、conf_thres从0.5降到0.35左右、分辨率设置到640×480而不是默认的1920×1080。
import cv2 import torch from models import Darknet # 加载模型,cfg和weights路径保持不变 model = Darknet('cfg/yolov4-mask.cfg') model.load_weights('weights/yolov4-mask.weights') model.eval() # 关键改动:入参从文件路径换成设备索引号 cap = cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) while True: ret, frame = cap.read() if not ret: break # 单帧预处理,输入尺寸降到320提升速度 img = letterbox(frame, new_shape=(320, 320)) tensor = torch.from_numpy(img).permute(2, 0, 1).unsqueeze(0).float() / 255.0 # 推理循环必须包在no_grad里,否则显存会持续累积 with torch.no_grad(): output = model(tensor) boxes, scores, classes = decode_output(output, conf_thres=0.35) # 画框并显示 frame = draw_boxes(frame, boxes, scores, classes) cv2.imshow('mask detection', frame) # waitKey的1毫秒是刷新窗口的关键 if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows()cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)把采集分辨率降到640×480,这台下编码压力和摄像头曝光时间,低配笔记本也能流畅跑。permute(2, 0, 1)把OpenCV的HWC通道顺序转成PyTorch的CHW,unsqueeze(0)增加batch维度,除以255.0做归一化——这三步顺序不能错,漏了permute会出现通道错乱,检测出来的框完全随机。waitKey(1)里的那个1毫秒是刷新窗口的关键,设成0会阻塞等待按键,视频流就卡死假死了;设成10或更大则画面延迟明显,建议维持1。
如果跑起来后画面延迟明显,优先怀疑是OpenCV读帧和推理串行导致的总耗时超过帧间隔。一个优化技巧是把帧读取和推理拆开:循环体里先cap.read()下一帧,同时对上一帧做推理。这样推理耗时被帧采集时间掩盖,视觉上流畅度提升不少。另外,笔记本摄像头在OpenCV里打不开,多半是设备被微信或浏览器占用,关闭这些应用的摄像头权限再重试即可。
验证这套改造是否成功,看两点:一是画面窗口能否正常弹出并实时显示,二是戴口罩的人经过镜头时检测框的延迟是否在一帧以内。如果框的延迟明显超过一帧,把输入尺寸从416降到320,速度提升立竿见影,而对口罩识别这种类别特征明显的任务,精度损失几乎无感。这个320输入的小技巧是我在多个YOLO项目里反复验证过的,从那以后我每次跑实时检测都强制把分辨率、推理尺寸和置信度三项参数过一遍,再开始调别的玄学参数。希望帮到你。
本文还有配套的精品资源,点击获取