ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

YOLOv7多任务联合检测:车牌+人脸+口罩端到端识别

YOLOv7多任务联合检测:车牌+人脸+口罩端到端识别 简介本资源是面向计算机视觉初学者与实战开发者的YOLOv7多任务检测实践包聚焦车牌定位、司机人脸区域识别及口罩佩戴状态判别三大工业场景需求。资源提供训练完成的高精度模型权重mAP超90%配套PR曲线、Loss变化图等训练可视化结果并附带一万张真实场景采集的车牌-人脸联合标注数据集支持txt与xml双格式标签便于快速迁移学习与算法调优。压缩包共219个文件含66张JPG/PNG图像样本、31个PyTorch训练与推理脚本.py、36个配置文件.yaml、14个Jupyter Notebook实验记录.ipynb以及ONNX/TensorRT部署示例整体体积304MB结构清晰、模块完整。目前已有3069人下载学习可直接用于课程设计、毕业项目或智能安防原型开发显著降低从数据准备到模型部署的全流程门槛。1. YOLOv7车牌与人脸联合检测不是OCR也不是纯人脸识别而是“位置属性”的端到端视觉理解你拿到的不是一套能直接输出“京A12345”或“张三”的系统而是一个在单帧图像中同步完成三项硬任务的轻量级工业级检测器精确定位车牌区域含倾斜矫正边界框、框出司机面部区域、并判断该面部是否佩戴口罩。它不依赖OCR后处理也不调用独立的人脸比对模型——所有逻辑压缩在YOLOv7主干Head结构内推理速度在RTX 3060上可达42 FPS640×480输入。这套方案专为车载DMS驾驶员监控系统、高速ETC辅助识别、停车场无感通行等场景设计解决的是“有没有人”“人在哪”“是否合规”三个层次的实时感知问题。适合需要快速落地、对车牌字符识别精度要求不高但对定位鲁棒性要求极高的嵌入式或边缘部署工程师也适合想复现YOLOv7多任务联合检测范式的算法同学——它把分类戴/不戴口罩、回归bbox、分割可选mask统一在anchor-free的检测框架下而非拼接多个模型。2. 模型结构解析与多任务Head设计原理2.1 为什么YOLOv7能同时输出车牌、人脸、口罩三类目标标准YOLOv7默认只支持单类别检测但本项目通过多分支Head重构实现三类目标联合输出。核心改动在models/yolo.py中的Detect模块原始YOLOv7的Detect层输出(batch, anchors, grid_h, grid_w, 5 nc)其中nc为类别数。本项目将nc设为3车牌/人脸/口罩但关键在于——口罩并非独立目标而是人脸的属性标签。实际实现采用共享Anchor 分离Class分支策略所有目标共用同一组anchor尺寸基于K-means聚类原始数据集得到的[12,16, 19,36, 40,28, 36,75, 76,55, 72,146, 142,110, 192,243, 459,401]Head输出通道数扩展为5 3xywhobj 车牌/人脸/口罩三类置信度后处理阶段通过NMS阈值分离车牌框IoU阈值设为0.45人脸框设为0.5口罩框强制绑定到人脸框内仅当人脸置信度0.6且口罩置信度0.7时才渲染口罩标签提示这种设计避免了传统级联流程先检人脸→再裁剪→再分类口罩带来的误差累积和延迟增加但要求训练时对口罩标注必须严格落在人脸bbox内部否则会破坏空间约束。2.2 数据集标签格式与多模态标注一致性校验项目提供txtYOLO格式和xmlPASCAL VOC格式双格式标签分别存于labels/和Annotations/目录。二者内容严格对齐验证脚本如下# verify_label_consistency.py import xml.etree.ElementTree as ET import os def parse_xml(xml_path): tree ET.parse(xml_path) root tree.getroot() boxes [] for obj in root.findall(object): cls obj.find(name).text bbox obj.find(bndbox) x1 int(bbox.find(xmin).text) y1 int(bbox.find(ymin).text) x2 int(bbox.find(xmax).text) y2 int(bbox.find(ymax).text) boxes.append((cls, x1, y1, x2, y2)) return boxes def parse_txt(txt_path, img_w, img_h): with open(txt_path, r) as f: lines f.readlines() boxes [] for line in lines: parts line.strip().split() cls_id int(parts[0]) cx, cy, w, h map(float, parts[1:5]) # 转换为绝对坐标 x1 max(0, int((cx - w/2) * img_w)) y1 max(0, int((cy - h/2) * img_h)) x2 min(img_w, int((cx w/2) * img_w)) y2 min(img_h, int((cy h/2) * img_h)) cls_map {0:plate, 1:face, 2:mask} boxes.append((cls_map[cls_id], x1, y1, x2, y2)) return boxes # 校验单张图 img_name 000001.jpg xml_boxes parse_xml(fAnnotations/{img_name.replace(.jpg,.xml)}) txt_boxes parse_txt(flabels/{img_name.replace(.jpg,.txt)}, 1280, 720) print(fXML标注数量: {len(xml_boxes)}, TXT标注数量: {len(txt_boxes)}) # 输出差异项 for i, (xml_box, txt_box) in enumerate(zip(xml_boxes, txt_boxes)): if xml_box ! txt_box: print(f第{i1}个标注不一致: XML{xml_box}, TXT{txt_box})运行结果应显示XML标注数量: X, TXT标注数量: X且无差异项。若存在不一致需检查convert_voc2yolo.py脚本中宽高归一化是否使用相同图像尺寸本数据集统一按1280×720 resize后标注。2.3 训练权重与PR曲线解读mAP0.5:0.95达90.3%的真实含义提供的best.pt权重在COCO-style评估协议下达到mAP0.5:0.9590.3%但需注意其计算范围仅限于车牌人脸两类主目标口罩作为属性不参与mAP统计。具体PR曲线生成命令如下# 在val_dataset目录下执行 python test.py --data data/plate_face.yaml \ --weights runs/train/exp/weights/best.pt \ --img 1280 \ --conf 0.001 \ --iou 0.65 \ --task val \ --save-json \ --plots生成的results.png中三条曲线分别对应Plate PR Curve: 车牌检测的Precision-Recall曲线AP0.5达94.2%Face PR Curve: 人脸检测曲线AP0.5达88.7%Mask Accuracy Curve: 口罩分类准确率非PR在人脸框内区域计算达91.5%注意mAP提升主要来自E-ELAN结构对小目标如远距离车牌的增强而非单纯增加参数量。对比YOLOv5m6本模型在同等FLOPs下召回率提升12.3%尤其在遮挡场景如司机戴墨镜、侧脸下漏检率降低37%。3. PyTorch训练全流程与关键超参配置3.1 环境搭建与数据集组织规范本项目依赖PyTorch 1.12.1cu113CUDA 11.3需严格匹配。创建conda环境命令conda create -n yolov7-pf python3.8 conda activate yolov7-pf pip install torch1.12.1cu113 torchvision0.13.1cu113 torchaudio0.12.1 --extra-index-url https://download.pytorch.org/whl/cu113 pip install -r requirements.txt # 包含opencv-python4.7.0.72, numpy1.23.5等数据集目录结构必须为dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ # YOLO格式txt │ └── val/ ├── Annotations/ # VOC格式xml └── trainval.txt # 列出所有训练图片名不含扩展名data/plate_face.yaml关键字段配置train: ../dataset/images/train val: ../dataset/images/val nc: 3 names: [plate, face, mask] # 顺序必须与label txt中cls_id一致3.2 训练命令与动态学习率策略使用train.py启动训练核心参数组合经消融实验验证最优python train.py \ --cfg cfg/training/yolov7-custom.yaml \ --data data/plate_face.yaml \ --weights \ --batch-size 16 \ --img 1280 720 \ --epochs 150 \ --evolve \ --name exp_plate_face \ --cache \ --workers 8 \ --optimizer SGD \ --lr0 0.01 \ --lrf 0.1 \ --warmup-epochs 5 \ --warmup-momentum 0.8 \ --multi-scale \ --rect \ --cos-lr参数说明--batch-size 16: 在RTX 3090上显存占用约14.2GB若显存不足可降至8并启用--cache--img 1280 720: 输入分辨率兼顾车牌细节需≥1280宽与人脸尺度720高防畸变--evolve: 启用遗传算法自动优化超参迭代300代后生成opt_evolve.yaml--cos-lr: 余弦退火学习率避免后期震荡配合--lrf 0.1使最终学习率0.01×0.10.001--multi-scale: 训练时随机缩放至[0.5,1.5]倍增强尺度鲁棒性训练过程每10 epoch自动保存last.pt最佳权重best.pt按val mAP更新。loss曲线中box_loss应在50 epoch后稳定在0.08以下obj_loss降至0.03cls_loss低于0.05。3.3 多任务损失函数权重调优YOLOv7默认box,obj,cls损失权重为0.05,0.7,0.3但本项目因车牌与人脸尺度差异大需重加权# models/yolo.py 中 compute_loss 函数修改 loss_box * 0.12 # 提升box_loss权重强化定位精度 loss_obj * 0.65 # 适度降低obj_loss防止过拟合背景 loss_cls * 0.23 # cls_loss权重微调平衡三类置信度输出该调整使车牌定位误差Center Distance Error从2.3px降至1.7px以1280×720图像计人脸框IoU提升0.042。4. ONNX/TensorRT部署实操与性能压测4.1 导出ONNX模型并验证结构完整性导出命令需指定动态batch和explicit batch维度python export.py \ --weights runs/train/exp_plate_face/weights/best.pt \ --include onnx \ --dynamic \ --img-size 1280 720 \ --simplify \ --opset 13生成best.onnx后用Netron可视化确认输入节点名为images输出节点为outputshape[1,25200,8]其中252003×80×703×40×353×20×18对应3个stride的anchor数。关键验证代码import onnxruntime as ort import numpy as np ort_session ort.InferenceSession(best.onnx, providers[CUDAExecutionProvider]) input_name ort_session.get_inputs()[0].name output_name ort_session.get_outputs()[0].name # 构造dummy input dummy_input np.random.randn(1, 3, 720, 1280).astype(np.float32) outputs ort_session.run([output_name], {input_name: dummy_input}) print(fONNX输出shape: {outputs[0].shape}) # 应为(1, 25200, 8) print(f输出值范围: [{outputs[0].min():.3f}, {outputs[0].max():.3f}]) # 验证数值稳定性若输出shape异常或数值溢出如出现inf/nan需检查export.py中torch.onnx.export的dynamic_axes参数是否包含{images: {0: batch}, output: {0: batch}}。4.2 TensorRT引擎构建与推理加速使用YOLOv7-Dynamic-Batch-TENSORRT.ipynb构建引擎核心步骤创建trtexec命令trtexec --onnxbest.onnx \ --saveEnginebest.engine \ --fp16 \ --workspace4096 \ --minShapesimages:1x3x720x1280 \ --optShapesimages:4x3x720x1280 \ --maxShapesimages:16x3x720x1280 \ --shapesimages:4x3x720x1280 \ --buildOnlyPython推理时启用动态batchimport pycuda.autoinit import pycuda.driver as cuda import tensorrt as trt # 加载引擎 with open(best.engine, rb) as f: engine trt.Runtime(trt.Logger()).deserialize_cuda_engine(f.read()) context engine.create_execution_context() context.set_binding_shape(0, (batch_size, 3, 720, 1280)) # 动态设置batch # 分配显存 d_input cuda.mem_alloc(batch_size * 3 * 720 * 1280 * 4) # float324bytes d_output cuda.mem_alloc(batch_size * 25200 * 8 * 4) # 推理 cuda.memcpy_htod(d_input, host_input.astype(np.float32)) context.execute_v2([int(d_input), int(d_output)]) host_output np.empty((batch_size, 25200, 8), dtypenp.float32) cuda.memcpy_dtoh(host_output, d_output)在T4 GPU上batch4时吞吐达168 FPS单图42 FPS较ONNX Runtime CUDA后端提升2.3倍。4.3 部署陷阱排查OpenCV DNN模块兼容性问题若使用OpenCVcv2.dnn.readNetFromONNX()加载需注意OpenCV 4.7.0才支持ONNX opset 13的NonMaxSuppression算子必须禁用OpenCV内置NMS改用YOLOv7原生后处理net cv2.dnn.readNetFromONNX(best.onnx) net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV) net.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU) # GPU后端不支持动态shape # 推理后手动NMS outs net.forward(net.getUnconnectedOutLayersNames()) boxes, confs, classes postprocess_yolov7(outs, conf_threshold0.5, nms_threshold0.45)postprocess_yolov7函数需实现YOLOv7特有的scale_coords和xywh2xyxy转换否则bbox坐标会错位。5. 实战技巧如何用现有权重快速适配新场景5.1 小样本微调Fine-tuning的3步法当你的实际场景存在光照突变如隧道出口强光或特殊车牌样式新能源绿牌反光无需重训只需50张图1小时微调数据增强强化在data/hyp.scratch.p5.yaml中修改hsv_h: 0.015 # 原0.015 → 0.025增强色相扰动应对反光 hsv_s: 0.7 # 原0.7 → 0.9提升饱和度扰动 mosaic: 0.0 # 关闭mosaic避免新场景中车牌被切分冻结Backbone前70层修改train.py中model.model[-1].parameters()前的梯度for i, (name, param) in enumerate(model.named_parameters()): if i 70: # YOLOv7-backbone共78层 param.requires_grad False学习率阶梯下降python train.py \ --weights runs/train/exp_plate_face/weights/best.pt \ --data data/custom_scene.yaml \ --epochs 30 \ --lr0 0.001 \ --lrf 0.01 \ --freeze 70实测在收费站夜间红外图像上微调后车牌检测mAP0.5从82.1%提升至89.7%。5.2 可视化调试用Grad-CAM定位模型关注区域快速验证模型是否真正关注车牌纹理而非背景干扰使用gradcam.pyfrom pytorch_grad_cam import GradCAM from pytorch_grad_cam.utils.image import show_cam_on_image model torch.load(best.pt)[model].float().eval() target_layers [model.model.model[-3].conv] # 最后一个SPPF层 cam GradCAM(modelmodel, target_layerstarget_layers, use_cudaTrue) rgb_img cv2.imread(test.jpg)[:, :, ::-1] / 255.0 input_tensor torch.tensor(rgb_img.transpose(2,0,1)[None]).float() grayscale_cam cam(input_tensorinput_tensor, targetsNone) cam_image show_cam_on_image(rgb_img, grayscale_cam[0, :], use_rgbTrue) cv2.imwrite(gradcam_plate.jpg, cam_image[:, :, ::-1])若热力图集中在车牌金属边框或字符区域说明特征提取有效若集中在车窗反光处则需加强反光数据增强。5.3 部署时的内存泄漏规避策略在长时间运行的DMS服务中发现TensorRT context未释放会导致显存缓慢增长。解决方案是在每次推理后显式同步# 在context.execute_v2()后添加 stream cuda.Stream() context.execute_async_v2(bindings, stream.handle) stream.synchronize() # 强制同步释放临时显存同时设置Python垃圾回收import gc gc.collect() # 每100帧执行一次 torch.cuda.empty_cache() # 清空缓存实测72小时连续运行显存波动控制在±12MB内T4 16GB显存。本文还有配套的精品资源点击获取
返回列表