基于深度学习的口罩识别与检测PyTorch实现

  • 1. 设计思路
    • 1.1 两阶段检测器:先检测人脸,然后将人脸进行分类,戴口罩与不戴口罩。
    • 1.2 一阶段检测器:直接训练口罩检测器,训练样本为人脸的标注信息,戴口罩的,不带口罩的。
  • 2. 算法具体实现
    • 2.1 两阶段口罩识别与检测器设计思路概述
    • 2.2 实现代码分析
      • 2.2.1 训练分类器并且保存模型
      • 2.2.2 人脸检测与剪裁,然后进行分类。
  • 3. 总结
  • 4. 参考链接

1. 设计思路

  • 已经完成,两阶段口罩检测的算法设计与实现。主要讲解整体pipeline的设计,即:人脸检测算法+口罩二分类CNN模型。
    全文的代码和技术讲解,在这里可以下载。mask_detection代码讲解.
  • 一阶段口罩检测算法设计与实现。这一部分安排下一个博客讲解。

1.1 两阶段检测器:先检测人脸,然后将人脸进行分类,戴口罩与不戴口罩。

对于这种两阶段方法,是能快速实现的。首先用现有的人脸检测算法,直接对图像进行人脸检测,然后将检测的每一个人脸,单独切割出来,进行是否戴口罩的二分类。

所以只需要训练一个CNN网络,包含两类图像,mask和without_maks。前端接一个face detector,就能应对大多数情况了。单独的讲解文档链接:口罩检测思路讲解文档。

1.2 一阶段检测器:直接训练口罩检测器,训练样本为人脸的标注信息,戴口罩的,不带口罩的。

先对图像中的人脸进行标注,包括了戴口罩的,和不带口罩的两个label的目标。然后进行标注。直接对人脸检测模型进行transfer learning,微调一下模型,就能检测了。

直接对戴口罩和不带口罩的人脸进行标注就可以了。

类似这种标注方法:

2. 算法具体实现

2.1 两阶段口罩识别与检测器设计思路概述

  1. 用数据集训练一个CNN二分类器。
    其中的数据为两类,mask 和without_mask。可以用现成的模型参数,在ImageNet上预训练好的weights,进行finetune。本方法采用的是ResNet18 为backbone,来进行训练。详细代码如下。其中,mask的数据集来这里: Mask Dataset
    如果这个数据集链接失效,用这一个:Mask Dataset 备份地址
    注意,下载数据集是google drive,科学上网。
    对训练好的模型,进行权重参数的保存,用于第二阶段的分类任务。保存为:将训练好的模型保存在pth中,然后在evaluation中,或者在Inference中,直接使用这个模型参数。

    ## 将训练好的模型保存在pth中,然后在evaluation中,或者在Inference中,直接使用这个模型参数。
    torch.save(model_ft, 'finetuned_model_resnet18.pth')
    
  2. 使用人脸检测器,检测人脸,切割人脸。这里如果有必要,需要重点关注戴口罩的人脸的检测效果。

  3. 对切割的人脸,用上述训练好的分类器,对人脸进行分类:戴口罩和不带口罩的。

  4. 下面的训练分类器的代码,和人脸检测与分类代码,都在这个链接里面下载。mask_detection代码详细讲解。

2.2 实现代码分析

2.2.1 训练分类器并且保存模型

from __future__ import print_function, divisionimport torch
import torch.nn as nn
import torch.optim as optim
from torch.optim import lr_scheduler
import numpy as np
import torchvision
from torchvision import datasets, models, transforms
import matplotlib.pyplot as plt
import time
import os
import copy
import PIL.ImageOps
import requests
from PIL import Image# Load Data
# Data augmentation and normalization for training
# Just normalization for validation
data_transforms = {'train': transforms.Compose([transforms.RandomResizedCrop(224),transforms.RandomHorizontalFlip(),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])]),'val': transforms.Compose([transforms.Resize(256),transforms.CenterCrop(224),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])]),
}data_dir = 'data/mask'
image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),data_transforms[x])for x in ['train', 'val']}
dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=4,shuffle=True, num_workers=4)for x in ['train', 'val']}
dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']}
class_names = image_datasets['train'].classesdevice = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")#Visualize a few imagesdef imshow(inp, title=None):"""Imshow for Tensor."""inp = inp.numpy().transpose((1, 2, 0))mean = np.array([0.485, 0.456, 0.406])std = np.array([0.229, 0.224, 0.225])inp = std * inp + meaninp = np.clip(inp, 0, 1)plt.imshow(inp)if title is not None:plt.title(title)plt.pause(0.001)  # pause a bit so that plots are updated# Get a batch of training data
inputs, classes = next(iter(dataloaders['train']))# Make a grid from batch
out = torchvision.utils.make_grid(inputs)imshow(out, title=[class_names[x] for x in classes])def train_model(model, criterion, optimizer, scheduler, num_epochs=25):since = time.time()best_model_wts = copy.deepcopy(model.state_dict())best_acc = 0.0for epoch in range(num_epochs):print('Epoch {}/{}'.format(epoch, num_epochs - 1))print('-' * 10)# Each epoch has a training and validation phasefor phase in ['train', 'val']:if phase == 'train':model.train()  # Set model to training modeelse:model.eval()   # Set model to evaluate moderunning_loss = 0.0running_corrects = 0# Iterate over data.for inputs, labels in dataloaders[phase]:inputs = inputs.to(device)labels = labels.to(device)# zero the parameter gradientsoptimizer.zero_grad()# forward# track history if only in trainwith torch.set_grad_enabled(phase == 'train'):outputs = model(inputs)_, preds = torch.max(outputs, 1)loss = criterion(outputs, labels)# backward + optimize only if in training phaseif phase == 'train':loss.backward()optimizer.step()# statisticsrunning_loss += loss.item() * inputs.size(0)running_corrects += torch.sum(preds == labels.data)if phase == 'train':scheduler.step()epoch_loss = running_loss / dataset_sizes[phase]epoch_acc = running_corrects.double() / dataset_sizes[phase]print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))# deep copy the modelif phase == 'val' and epoch_acc > best_acc:best_acc = epoch_accbest_model_wts = copy.deepcopy(model.state_dict())print()time_elapsed = time.time() - sinceprint('Training complete in {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))print('Best val Acc: {:4f}'.format(best_acc))# load best model weightsmodel.load_state_dict(best_model_wts)return model#Visualizing the model predictionsdef visualize_model(model, num_images=6):was_training = model.trainingmodel.eval()images_so_far = 0fig = plt.figure()with torch.no_grad():for i, (inputs, labels) in enumerate(dataloaders['val']):inputs = inputs.to(device)labels = labels.to(device)outputs = model(inputs)_, preds = torch.max(outputs, 1)for j in range(inputs.size()[0]):images_so_far += 1ax = plt.subplot(num_images//2, 2, images_so_far)ax.axis('off')ax.set_title('predicted: {}'.format(class_names[preds[j]]))imshow(inputs.cpu().data[j])if images_so_far == num_images:model.train(mode=was_training)returnmodel.train(mode=was_training)if __name__ == "__main__":#Finetuning the convnet
#Load a pretrained model and reset final fully connected layer.model_ft = models.resnet18(pretrained=True)num_ftrs = model_ft.fc.in_features# Here the size of each output sample is set to 2.# Alternatively, it can be generalized to nn.Linear(num_ftrs, len(class_names)).model_ft.fc = nn.Linear(num_ftrs, 2)model_ft = model_ft.to(device)criterion = nn.CrossEntropyLoss()# Observe that all parameters are being optimizedoptimizer_ft = optim.SGD(model_ft.parameters(), lr=0.001, momentum=0.9)# Decay LR by a factor of 0.1 every 7 epochsexp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)model_ft = train_model(model_ft, criterion, optimizer_ft, exp_lr_scheduler,num_epochs=25)torch.save(model_ft, 'finetuned_model_resnet18.pth')visualize_model(model_ft)        

这是一些数据集的可视化图:

训练后的分类结果展示:

2.2.2 人脸检测与剪裁,然后进行分类。

这里我们采用MTCNN进行人脸检测。

import cv2
from mtcnn.core.detect import create_mtcnn_net, MtcnnDetector
from mtcnn.core.vision import vis_faceif __name__ == '__main__':### part1: face detectionpnet, rnet, onet = create_mtcnn_net(p_model_path="./original_model/pnet_epoch.pt", r_model_path="./original_model/rnet_epoch.pt", o_model_path="./original_model/onet_epoch.pt", use_cuda=False)mtcnn_detector = MtcnnDetector(pnet=pnet, rnet=rnet, onet=onet, min_face_size=24)img = cv2.imread("./s_l.jpg")img_bg = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)bboxs, landmarks = mtcnn_detector.detect_face(img)save_name = 'r_1.jpg'## visulaze the face detection effect. vis_face(img_bg,bboxs,None, save_name)### part2: mask classification.## load classification model.mask_model = torch.load('finetuned_model_resnet18.pth',map_location='cpu')mask_list  = []for i in range(bboxs.shape[0]):bbox = bboxs[i, :4]print(img.shape)print(bbox)## 这里主要是人脸的剪裁,然后数据的转换,mat 格式转换为 numpy。cropImg1 = img[int(bbox[1]):int(bbox[3]),int(bbox[0]):int(bbox[2])]cv2.imshow('face',cropImg1)cv2.waitKey(0)## 剪裁人脸的格式转换PIL_image = Image.fromarray(cropImg1)face_img = data_transforms['val'](PIL_image) face_img = face_img.to(device).unsqueeze(0)output = mask_model (face_img)_, pred = torch.max(output, 1)mask_list.append(class_names[pred.item()])print(class_names[pred.item()])### 可视化的一些操作,包括人脸的rectangle以及putText到图像上。cv2.rectangle(img, (int(bbox[0]),int(bbox[1])), (int(bbox[2]),int(bbox[3])), (0,255,0), 4)font = cv2.FONT_HERSHEY_SIMPLEXcv2.putText(img, class_names[pred.item()],  (int(bbox[0]),int(bbox[1])), font, 1, (0,0,255), 2)cv2.imshow('original',img)# cv2.imshow('face',cropImg1)cv2.waitKey(0)cv2.imwrite('result_new.jpg', img)img_result = Image.open('result_new.jpg')plt.imshow(img_result)

算法的效果图

  • 先是人脸检测效果:
  • 识别分类后的效果:
  • 大规模实际效果图
    用比较强的人脸检测算法,能够检测出来人脸,然后在进行分类。

3. 总结

由于采用两阶段的方法,依赖于人脸检测算法的鲁棒性,如果人脸检测算法,对戴口罩之后的遮挡,大面积遮挡,导致人脸特征减少,导致不能检出人脸。这时候,第二阶段的分类,是没有意义的。因为第一步就检测不出人脸来,性能差主要是第一阶段的能力导致的,而对于分类这一块,分类器没什么大问题。因此主要的精力放在人脸检测器的优化上来。由于原始数据集没有戴口罩的人脸,因此需要对数据分布进行调整。关于这些缺点和对应解决方案的描述文档,在这里。口罩检测描述与解决方案的文档。

下面的图像就是戴口罩之后检测不出例子,当口罩太大,遮住2/3的人脸之后,人脸检测算法检测不出来。

一些原因描述:

解决方法:

  1. 重新训练人脸检测算法,将戴口罩,不带口罩的人脸,全部标注出来,都标注为人脸,然后训练模型,加强其对戴口罩,遮挡住嘴巴鼻子的这一类人脸的检出率。重点关注这种戴口罩人脸的检测效果。 主要训练人脸检测模型,在普通人脸的数据基础上,增强人脸检测性能,提升戴口罩人脸检测的鲁棒性。
  2. 当然是直接使用人脸检测算法,将人脸标注为两类目标,戴口罩的,不带口罩的。直接在人脸检测的基础上,进行两类目标的直接检测。

其中绝大部分的问题和解决方法,都在我给的技术文档,ppt,或者下面的链接中,都描述了的,所以认真看一下我给的文件。mask_detection文档与代码讲解。

  • 已经完成,两阶段口罩检测的算法设计与实现。
  • TODO:一阶段口罩检测算法设计与实现。

4. 参考链接

  1. https://www.analyticsvidhya.com/blog/2020/08/how-to-build-a-face-mask-detector-using-retinanet-model/
  2. https://github.com/chandrikadeb7/Face-Mask-Detection
  3. https://towardsdatascience.com/covid-19-face-mask-detection-using-tensorflow-and-opencv-702dd833515b
  4. https://www.mygreatlearning.com/blog/real-time-face-detection/
  5. https://data-flair.training/blogs/face-mask-detection-with-python/
  6. https://www.pyimagesearch.com/2020/05/04/covid-19-face-mask-detector-with-opencv-keras-tensorflow-and-deep-learning/
  7. https://www.ideas2it.com/blogs/face-mask-detector-using-deep-learning-pytorch-and-computer-vision-opencv/

如果有用,记得点赞

基于深度学习的口罩识别与检测PyTorch实现相关推荐

  1. 基于深度学习的口罩规范佩戴检测【树莓派+PC训练、测试】

    训练.测试.部署代码下载地址:下载地址 一.硬件: PC端运行:Windows10或11(无需GPU,有最好)或MacOS 都测试可行 树莓派运行:树莓派 4B model B 8G 版 USB RG ...

  2. 基于深度学习的口罩检测系统(Python+清新界面+数据集)

    摘要:口罩检测系统用于日常生活中检测行人是否规范佩戴口罩,利用深度学习算法可实现图片.视频.连接摄像头等方式的口罩检测,另外支持和结果可视化.在介绍算法原理的同时,给出Python的实现代码以及PyQ ...

  3. 基于深度学习的高精度家禽猪检测识别系统(PyTorch+Pyside6+YOLOv5模型)

    摘要:基于深度学习的高精度家禽猪检测识别系统可用于日常生活中或野外来检测与定位家禽猪目标,利用深度学习算法可实现图片.视频.摄像头等方式的家禽猪目标检测识别,另外支持结果可视化与图片或视频检测结果的导 ...

  4. 基于深度学习的高精度牙齿健康检测识别系统(PyTorch+Pyside6+YOLOv5模型)

    摘要:基于深度学习的高精度牙齿健康检测识别系统可用于日常生活中检测牙齿健康状况,利用深度学习算法可实现图片.视频.摄像头等方式的牙齿目标检测识别,另外支持结果可视化与图片或视频检测结果的导出.本系统采 ...

  5. 【深度学习实践】基于深度学习的车牌识别(python,车牌检测+车牌识别)

    车牌识别具有广泛的应用前景,基于传统方法的车牌识别效果一般比较差,随着计算机视觉技术的快速发展,深度学习的方法能够更好的完成车牌识别任务. 本文提供了车牌识别方案的部署链接,您可以在网页上体验该模型的 ...

  6. 基于深度学习的脑电图识别 综述篇(二)数据采样及处理

    作者|Memory逆光 本文由作者授权分享 导读 脑电图(EEG)是一个复杂的信号,一个医生可能需要几年的训练并利用先进的信号处理和特征提取方法,才能正确解释其含义.而如今机器学习和深度学习的发展,大 ...

  7. 基于深度学习的安卓恶意应用检测----------android manfest.xml + run time opcode, use 深度置信网络(DBN)...

    基于深度学习的安卓恶意应用检测 from:http://www.xml-data.org/JSJYY/2017-6-1650.htm 苏志达, 祝跃飞, 刘龙     摘要: 针对传统安卓恶意程序检测 ...

  8. python dlib caffe人脸相似度_基于深度学习的人脸识别系统(Caffe+OpenCV+Dlib)【一】如何配置caffe属性表...

    前言 基于深度学习的人脸识别系统,一共用到了5个开源库:OpenCV(计算机视觉库).Caffe(深度学习库).Dlib(机器学习库).libfacedetection(人脸检测库).cudnn(gp ...

  9. 开发基于深度学习的人脸识别【考勤/签到】系统

    开发基于深度学习的人脸识别[考勤/签到]系统 人脸识别介绍 平台环境需求 技术点 系统流程 细节设计 人脸检测 人脸关键点定位 人脸特征提取 模型的训练 模型的部署 MySQL数据库的使用 MFC工程 ...

最新文章

  1. 掌握这10个Python小技巧,让你敲代码速度快5倍不止
  2. bind函数怎么用JAVA_c++bind函数的用法
  3. 第五章 常用Lua开发库2-JSON库、编码转换、字符串处理
  4. 后端工程师面试BAT,被问到了前端?就倒下了?【VUE面试20连问】
  5. POJ C++程序设计 编程题#7:字符串排序
  6. asp.net记录错误日志的方法
  7. 使用 jQuery Mobile 与 HTML5 开发 Web App (十) —— jQuery Mobile 默认配置与事件基础
  8. Python中fastapi构建的web项目进行docker部署
  9. java面试-JVM调优和参数配置
  10. 如何使用EasyRecovery巧妙恢复被误删的办公文档?
  11. 全站HTTPS来了!有何优势、与HTTP有何不同
  12. 4.设计包(design package)
  13. 智慧城市项目在PPP模式中的应用
  14. java 多线程 实现死锁问题
  15. MJB,阿里又一次成功的营销?
  16. 深度解析FUTABA的SBUS协议(/天地飞遥控器的WBUS协议/Robomaster接收机的DBUS协议)到底是啥?
  17. 查表程序c8051汇编语言,汇编程序 查表求平方的实现
  18. 域对抗(域适应)训练
  19. 云计算实战:Amazon EC2之初体验
  20. 著名C9院校!接连发表5篇Nature/Cell!

热门文章

  1. 2022-2028年中国树脂行业市场研究及前瞻分析报告
  2. Jquery DIV滚动至浏览器顶部后固定不动代码
  3. java 手编线程池_死磕 java线程系列之自己动手写一个线程池
  4. SpringBoot (一) :入门篇 Hello World
  5. 理解 Word2Vec 之 Skip-Gram 模型
  6. 云端一体全栈解决方案
  7. DeepLabV3+语义分割实战
  8. CodeGen融合核心关系循环扩展
  9. Java的File类
  10. GIT上传服务器同步到web目录