作者:Adrian Rosebrock
翻译:张一然
校对:冯羽
本文约8800字,建议阅读10 分钟
本文为大家介绍了如何使用Opencv,Keras/Tensorflow构建一个口罩检测模型,以及如何将该模型应用到图片和视频中。
标签:深度学习
通过本篇文章你将会学到如何利用Opencv,Keras/Tensorflow和深度学习设计一个口罩检测器。
上周我写了一篇关于利用深度学习在X光图像中检测COVID-19的博客,读者反馈很喜欢这种及时且具有实际意义的应用,因此今天我们学习另一个与COVID相关的计算机视觉应用,即利用Opencv,Keras/Tensorflow检测人是否佩戴口罩。
我写这篇博客主要是受以下几个因素的影响:
- 很多读者要求我写一篇相关博客;
- 看到其他人有相关的实验(其中我最欣赏的是Prajna Bhandary的实现,也就是我们今天要用到的)。
如果部署正确的话,我们设计的COVID-19面罩检测器可能帮助确保你和其他人的安全(但我把实施和在户外分发这件事留给专业医疗人员来决定)。
COVID-19: 利用Opencv,Keras/Tensorflow和深度学习进行口罩检测
在本教程中,我们将会讨论两段COVID-19口罩检测器,详细说明如何实现一个基于计算机视觉/深度学习的pipeline。
首先,我们会了解用于训练自定义口罩检测器的数据集。
然后,我将向大家展示如何使用Keras和TensorFlow实现一个Python脚本在数据集中来训练口罩检测器。
我们将使用此Python脚本来训练口罩检测器并查看结果。
给定一个训练好的COVID-19口罩检测器,我们将继续实现另外两个Python脚本,这些脚本可用于:
- 检测图片中的COVID-19口罩;
- 检测实时视频流中的口罩。
文章最后我们会给出一些口罩检测器的结果,同时给出一些改进意见。
两段COVID-19口罩检测器
图一: 使用Python,OpenCV和TensorFlow/ Keras构建具有计算机视觉和深度学习功能的COVID-19口罩检测器的阶段和各个步骤。
为了训练自定义的口罩检测器,我们将项目分为两个不同的阶段,每个阶段都有各自的子步骤(如图1所示):
- 训练:在该阶段我们主要是从磁盘加载口罩检测数据集,在该数据集上训练模型(使用Keras / TensorFlow),然后将模型序列化到磁盘;
- 部署:训练完口罩检测器后,加载训练好的口罩检测器,进行人脸检测,然后将人脸分类为戴口罩或不戴口罩。
在本教程的其余部分中,我们将学习这两个阶段及其相关的子阶段,但与此同时,让我们看一下将用于训练COVID-19面罩检测器的数据集。
COVID-19 口罩检测数据集
图2:口罩检测数据集由“戴口罩”和“不戴口罩”图像组成。我们将使用该数据集,以及Python,OpenCV和TensorFlow/ Keras构建一个口罩检测器。
我们用的数据集是由PyImageSearch 的读者Prajna Bhandary提供。
数据集共含有1376张图片,包含两类:
- 戴口罩: 690张图片;
- 不戴口罩: 686张图片。
我们的目标是训练一个自定义的深度学习模型,以检测一个人是否佩戴口罩。
注意:为方便起见,我将Prajna创建的数据集包含在本教程的“下载”部分中。
如何制作口罩数据集?
Prajna和我一样,一直对世界的状况感到沮丧,每天有成千上万的人死亡,而对于我们大部分人来说,我们几乎无能为力。
为了保持精神振奋,Prajna决定通过应用计算机视觉和深度学习来解决现实问题来分散自己的注意力:
- 最好的情况——她可以利用自己的项目来帮助他人;
- 最坏的情况——这给了她急需的心理逃生。
无论哪种方式,它都是双赢的!
作为程序员,开发者和计算机视觉/深学习的从业者,我们都需要从Prajna那里学到一些东西——让你的技术,成为你的专注,成为你的天堂。
为了创建口罩数据集,Prajna提出了如下几种方案:
- 拍摄正常的脸部图像;
- 创建一个Python脚本向图片中的人脸添加口罩,从而创建一个人造的(但仍适用于现实世界)数据集。
添加面部标志(facial landmarks)可以简化这个问题,面部标志可以帮我们自动推断出面部结构的位置,包括:
- 眼
- 眼眉
- 鼻子
- 嘴
- 颚线
要使用面部标志构建戴着口罩的面部数据集,我们首先需要从不戴着口罩的人的图像开始:
图3:要构建COVID-19口罩数据集,我们首先从不戴口罩的人的照片开始。
首先,我们利用人脸检测来计算图像中人脸的边界框位置:
图4:下一步是应用人脸检测。在这里,我们借助了深度学习和OpenCV进行人脸检测。
知道人脸在图像中的位置之后,我们就可以提取出我们感兴趣的区域(ROI):
图5:下一步是使用OpenCV和NumPy切片提取面部ROI。
使用面部标志定位眼睛鼻子和嘴等:
图6:然后,我们使用dlib检测面部标志,找到将口罩放置在脸上的位置。
下一步我们需要一个口罩的图片(背景透明),如下:
图7:COVID-19 口罩的示例。由于我们知道面部标志位置,因此可将该口罩自动覆盖在人脸的ROI上。
通过使用面部标志(即沿着下巴和鼻子的点)来计算该口罩的放置位置,然后调整口罩的大小,旋转,将其放在脸上:
图8:在此图中,我们已将口罩添加到人脸上。不仔细看的话我们很难看出口罩是通过opencv和dlib面部标志人为添加上去的。
然后,对所有输入图像重复此过程,创建一个口罩数据集:
图9:展示了一组人工制作的COVID-19口罩图像。这将成为我们“戴口罩” /“不戴口罩”数据集的一部分,该数据集将被用于使用Python、OpenCV、Tensorflow/Keras的计算机视觉和深度学习技术训练的COVID-19面部口罩检测器。
但是,在使用此方法人为创建数据集时,你需要注意一个问题!
如果你使用了一组图像来制作“戴口罩”的数据集,那么你之后就不能在“不戴口罩”的训练数据集中重用这组图像,你需要重新收集不戴口罩的图像!
如果把用于生成“戴口罩”数据集的图片也加入到“无口罩”数据中,训练出来的模型将产生严重偏差,且无法很好地泛化。为了避免这些问题,我们应该花点时间收集没有带口罩的新的例子。
如何利用面部标志向人脸添加口罩超出了本教程的讨论范畴涵盖,如果您想了解更多信息,我建议:
- 参考Prajna的GitHub;
- 参考PyImageSearch上另一篇教程,如何利用面部标志自动将太阳镜戴在人脸上(https://www.pyimagesearch.com/2018/11/05/creating-gifs-with-opencv/)。
利用太阳镜教程中的相同原理制作口罩数据集: 使用面部标志来推断面部结构,旋转并调整口罩大小,然后将其应用于人脸。
项目结构
从本文的“下载”部分中获取文件后,将显示以下目录结构:
$ tree --dirsfirst --filelimit 10
.
├── dataset
│ ├── with_mask [690 entries]
│ └── without_mask [686 entries]
├── examples
│ ├── example_01.png
│ ├── example_02.png
│ └── example_03.png
├── face_detector
│ ├── deploy.prototxt
│ └── res10_300x300_ssd_iter_140000.caffemodel
├── detect_mask_image.py
├── detect_mask_video.py
├── mask_detector.model
├── plot.png
└── train_mask_detector.py
5 directories, 10 files
Dataset目录中包含“COVID19口罩检测数据集”一节中提到的数据。
Example目录中提供了三张可用于测试静态口罩图片检测器用的图片。
本教程中我们会解释下面三个pyhton脚本:
- train_mask_detector.py:接受输入数据,精调MobileNetV2,创建make_detector.model。同时以图片的形式输出训练过程中的准确度/损失曲线;
- Detect_mask_image.py:在静态图片上进行口罩检测;
- Detector_mask_video.py:此脚本将口罩检测应用于视频流中的每一帧。
在接下来的两个部分中,我们将训练我们的口罩检测器。
利用keras/tensorflow实现COVID-19口罩检测器训练脚本
在检查完了我们的口罩数据集之后,接下来我们要学习如何使用Keras和Tensorflow训练一个可以自动检测一个人是否佩戴口罩的分类器。
为了完成此任务,我们将对MobileNet V2进行微调,MobileNet V2是一种高效的架构,可应用于计算能力有限的嵌入式设备(例如,树莓派,Google Coral,NVIDIA Jetson Nano等)。
注意:如果您对嵌入式计算机视觉感兴趣,请务必阅读我的《 Raspberry Pi for Computer Vision》一书,其中涵盖了如何在计算资源有限的设备上使用计算机视觉和深度学习。
将我们的口罩检测器部署到嵌入式设备可以降低制造此类口罩检测系统的成本,这就是我们选择使用这种架构的原因。
让我们开始训练吧!
在目录结构中打开train_mask_detector.py文件,并插入以下代码:
# import the necessary packages
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.applications import MobileNetV2
from tensorflow.keras.layers import AveragePooling2D
from tensorflow.keras.layers import Dropout
from tensorflow.keras.layers import Flatten
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Input
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.applications.mobilenet_v2 import preprocess_input
from tensorflow.keras.preprocessing.image import img_to_array
from tensorflow.keras.preprocessing.image import load_img
from tensorflow.keras.utils import to_categorical
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from imutils import paths
import matplotlib.pyplot as plt
import numpy as np
import argparse
import os
训练脚本中的这么多import可能看起来很吓人。如果你刚入门深度学习,我建议在继续之前阅读我的Keras教程(https://www.pyimagesearch.com/2018/09/10/keras-tutorial-how-to-get-started-with-keras-deep-learning-and-python/)和精调教程(https://www.pyimagesearch.com/2019/06/03/fine-tuning-with-keras-and-deep-learning/)。
我们的tensorflow.keras导入集合允许:
- 数据增强;
- 加载MobilNetV2分类器(我们将使用预训练的ImageNet权重对该模型进行精调);
- 建立一个新的全连接(FC)头;
- 预处理;
- 加载图像数据。
我们将使用scikit-learn(sklearn)对类标签进行二值化处理,细分数据集并打印分类报告。
Imutils库中的paths模块将帮助我们在数据集中查找并列出图像。然后,我们将使用matplotlib绘制训练曲线。
为确保可以成功导入这些库,请遵循我的Tensorflow 2.0 安装指南:
- 如何在Ubuntu上安装TensorFlow2.0;
- 如何在macOS上安装TensorFlow2.0。
让我们继续分析一些从终端启动脚本所需的命令行参数:
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", required=True,
help="path to input dataset")
ap.add_argument("-p", "--plot", type=str, default="plot.png",
help="path to output loss/accuracy plot")
ap.add_argument("-m", "--model", type=str,
default="mask_detector.model",
help="path to output face mask detector model")
args = vars(ap.parse_args())
我们的命令行参数包括:
- --dataset:人脸和戴口罩的人脸的输入数据集的路径;
- --plot:输出训练过程图的路径,将使用matplotlib生成这些图;
- --model:生成的序列化口罩分类模型的路径。
我喜欢把深度学习超参数都定义在一起:
# initialize the initial learning rate, number of epochs to train for,
# and batch size
INIT_LR = 1e-4
EPOCHS = 20
BS = 32
在这里,我指定了超参数常量,包括我的初始学习率,训练次数和batch size。之后,我们会使用学习率衰减时间表,这就是为什么我们将学习率变量命名为初始学习率 INIT_LR的原因。
准备加载和预处理我们的训练数据:
在这个部分中,我们将:
- 抓取数据集中的所有imagePath(第44行);
- 初始化数据和标签列表(第45和46行);
- 循环遍历imagePaths并加载 预处理图像(第49-60行)。预处理步骤包括将尺寸调整为224×224像素,转换成数组格式并将输入图像中的像素值缩放到[-1,1]范围(通过preprocess_input函数);
- 将预处理的图像和相关标签分别添加到数据和标签列表中(第59行和第60行);
- 确保我们的训练数据是NumPy数组格式(第63和64行)。
上面的代码行假定你的整个数据集足够小,可以放到内存中。如果数据集大于可用内存,建议使用HDF5. 我在《使用Python进行计算机视觉的深度学习》(https://www.pyimagesearch.com/deep-learning-computer-vision-python-book/)(第9和10章)中介绍这个方法。
我们的数据准备工作还没有完成。接下来,我们将对标签进行编码,划分数据集,并为数据增强做准备:
第67-69行对类标签进行独热编码,这意味着我们的数据将采用以下格式:
labels数组的每个元素都由一个数组组成,该数组中只有一个索引是“ hot”(例如1)。
使用scikit-learn中的函数,第73行和第74行将我们的数据分为80%的训练集和20%的测试集。
在训练过程中,我们将对图像进行动态修改,以提高泛化性能。这称为数据增强,其中在第77-84行设置随机旋转,缩放,剪切,移位和翻转参数。我们将在训练时使用增强后的图片。
但是首先,我们需要准备MobileNetV2进行精调:
精调设置过程分为三个步骤:
- 向MobileNet加载预训练的ImageNet权重,而不用担心网络的损失(第88和89行);
- 构造一个新的全连接层,并将其附加到模型最后以代替旧的全连接层(第93-102行);
- 冻结网络的基础层(106和107行)。这些基础层的权重在反向传播过程中不会更新,而顶层的权重将被调整。
我经常建议别人使用精调的方法构建一个基线模型,这样可以节省大量时间。要了解有关理论,目的和策略的更多信息,请参阅我关于精调的博客和“使用Python进行计算机视觉的深度学习”(https://www.pyimagesearch.com/deep-learning-computer-vision-python-book/)
准备好数据和一个待精调的模型后,我们现在可以编译和训练我们的口罩检测器:
第111-113行使用Adam优化器,学习率衰减时间表和二分类交叉熵来编译我们的模型。如果您要使用此训练脚本训练多个类(大于2),请确保使用多分类交叉熵。
在117-122行开始进行口罩训练。请注意,我们如何用数据增强对象(aug)提供批量变化的图像数据。
训练完成后,我们将在测试集中评估结果模型:
第126-130行在测试集上进行预测,找到最高概率类别标签索引。然后,我们在终端中打印分类报告以进行检查。
第138行将我们的口罩分类模型序列化到磁盘。
我们的最后一步是绘制精度和损失曲线:
准备好绘图后,第152行使用--plot文件路径将图像保存到磁盘。
使用Keras / TensorFlow训练COVID-19口罩检测器
现在,我们准备使用Keras,TensorFlow和DeepLearning训练我们的口罩检测器。
确保已使用本教程的“下载”部分来下载源代码和面罩数据集。
下面打开一个终端,然后执行以下命令:
$ python train_mask_detector.py --dataset dataset
[INFO] loading images...
[INFO] compiling model...
[INFO] training head...
Train for 34 steps, validate on 276 samples
Epoch 1/20
34/34 [==============================] - 30s 885ms/step - loss: 0.6431 - accuracy: 0.6676 - val_loss: 0.3696 - val_accuracy: 0.8242
Epoch 2/20
34/34 [==============================] - 29s 853ms/step - loss: 0.3507 - accuracy: 0.8567 - val_loss: 0.1964 - val_accuracy: 0.9375
Epoch 3/20
34/34 [==============================] - 27s 800ms/step - loss: 0.2792 - accuracy: 0.8820 - val_loss: 0.1383 - val_accuracy: 0.9531
Epoch 4/20
34/34 [==============================] - 28s 814ms/step - loss: 0.2196 - accuracy: 0.9148 - val_loss: 0.1306 - val_accuracy: 0.9492
Epoch 5/20
34/34 [==============================] - 27s 792ms/step - loss: 0.2006 - accuracy: 0.9213 - val_loss: 0.0863 - val_accuracy: 0.9688
...
Epoch 16/20
34/34 [==============================] - 27s 801ms/step - loss: 0.0767 - accuracy: 0.9766 - val_loss: 0.0291 - val_accuracy: 0.9922
Epoch 17/20
34/34 [==============================] - 27s 795ms/step - loss: 0.1042 - accuracy: 0.9616 - val_loss: 0.0243 - val_accuracy: 1.0000
Epoch 18/20
34/34 [==============================] - 27s 796ms/step - loss: 0.0804 - accuracy: 0.9672 - val_loss: 0.0244 - val_accuracy: 0.9961
Epoch 19/20
34/34 [==============================] - 27s 793ms/step - loss: 0.0836 - accuracy: 0.9710 - val_loss: 0.0440 - val_accuracy: 0.9883
Epoch 20/20
34/34 [==============================] - 28s 838ms/step - loss: 0.0717 - accuracy: 0.9710 - val_loss: 0.0270 - val_accuracy: 0.9922
[INFO] evaluating network...
precision recall f1-score support
with_mask 0.99 1.00 0.99 138
without_mask 1.00 0.99 0.99 138
accuracy 0.99 276
macro avg 0.99 0.99 0.99 276
weighted avg 0.99 0.99 0.99 276
图10:COVID-19口罩检测器的训练精度/损失曲线显示出模型具有很高的准确率,并且在数据上几乎没有过拟合的迹象。现在,我们准备使用Python,OpenCV和TensorFlow/ Keras并应用我们的计算机视觉和深度学习知识来执行口罩检测。
如图所示,我们的测试集获得了约99%的准确性。
从图10可以看出,几乎没有过拟合的迹象,同时验证损失低于训练损失(我在这篇博文(https://www.pyimagesearch.com/2019/10/14/why-is-my-validation-loss-lower-than-my-training-loss/)中讨论的现象)。
鉴于这些结果,我们希望我们的模型能够很好地推广到我们训练和测试集之外的图像。
利用OpenCV实现COVID-19口罩检测器
训练好我们的口罩检测器后,下面我们将学习:
- 从磁盘加载输入图像;
- 检测图像中的人脸;
- 应用我们的口罩检测器将人脸分类为戴口罩或不戴口罩。
在目录结构中打开detect_mask_image.py文件,让我们开始吧:
# import the necessary packages
from tensorflow.keras.applications.mobilenet_v2 import preprocess_input
from tensorflow.keras.preprocessing.image import img_to_array
from tensorflow.keras.models import load_model
import numpy as np
import argparse
import cv2
import os
我们的驱动脚本需要以上三个TensorFlow / Keras函数去加载MaskNet模型和以及预处理输入图像。
OpenCV用来显示和对图像进行操作。
下一步是解析命令行参数:
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,
help="path to input image")
ap.add_argument("-f", "--face", type=str,
default="face_detector",
help="path to face detector model directory")
ap.add_argument("-m", "--model", type=str,
default="mask_detector.model",
help="path to trained face mask detector model")
ap.add_argument("-c", "--confidence", type=float, default=0.5,
help="minimum probability to filter weak detections")
args = vars(ap.parse_args())
其中:
- --image:输入图像的路径,其中包含用于推理的人脸图像;
- --face:人脸检测模型目录的路径(我们需要先对人脸进行定位,然后再对其进行分类);
- --model:口罩检测器模型的路径;
- --confidence:可选项将概率阈值设置为覆盖50%,以过滤较差的人脸检测结果。
接下来,我们将同时加载人脸检测器和口罩分类器模型:
# load our serialized face detector model from disk
print("[INFO] loading face detector model...")
prototxtPath = os.path.sep.join([args["face"], "deploy.prototxt"])
weightsPath = os.path.sep.join([args["face"],
"res10_300x300_ssd_iter_140000.caffemodel"])
net = cv2.dnn.readNet(prototxtPath, weightsPath)
# load the face mask detector model from disk
print("[INFO] loading face mask detector model...")
model = load_model(args["model"])
有了我们的深度学习模型后,我们的下一步就是加载和预处理输入图像:
从磁盘加载--image后(第37行),我们复制并记录图片尺寸信息以供将来缩放和显示(第38和39行)。
预处理由OpenCV的blobFromImage函数处理(第42和43行)。如参数所示,我们将尺寸调整为300×300 pixels并执行均值减法。
然后,第47行和第48行执行人脸检测以定位图像中所有人脸的位置。
知道每张脸的预测位置后,我们首先确保它们是否满足--confidence阈值,然后再提取脸部区域即faceROI:
我们遍历检测结果并提取置信度与--confidence作比较(第51-58行)。
然后,我们计算人脸的边界框值,并确保该框落在图像的边界内(第61-67行)。
接下来,我们将通过MaskNet模型运行面部ROI:
在这部分代码中,我们:
- 通过NumPy切片提取面部ROI(第71行);
- 采用与训练期间相同的方式对ROI进行预处理(第72-76行);
- 执行口罩检测以预测“戴口罩”或“不戴口罩”(第80行)。
接下来,我们将注释并显示结果!
首先,我们根据口罩检测器返回的概率确定类别标签(第84行),并为注释分配关联的颜色(第85行)。戴口罩的颜色是“绿色”,不戴口罩的颜色将为“红色”。
然后,我们使用OpenCV绘制功能(第92-94行)绘制标签文本(包括类别和概率),以及面部的边框矩形。
处理完所有检测后,第97和98行将显示输出图像。
使用OpenCV在图像中进行COVID-19口罩检测
让我们使用我们的COVID-19口罩检测器!
确保已使用本教程的“下载”部分来下载源代码,示例图像和预训练的口罩检测器。
接下来打开一个终端,然后执行以下命令:
$ python detect_mask_image.py --image examples/example_01.png
[INFO] loading face detector model...
[INFO] loading face mask detector model...
[INFO] computing face detections...
图11:这个男人在公共场所带口罩了吗?可以看出,我们的检测器检测到图中的人带着口罩. 使用Python,OpenCV和TensorFlow/ Keras的计算机视觉和深度学习方法使自动检测口罩成为可能。(图片来源:https://www.sunset.com/lifestyle/shopping/fashionable-flu-masks-germ-protection)
如图所示,我们的口罩检测器已将该图像正确标记为Mask(戴口罩)。
让我们尝试另一张图片,这个人没有戴口罩:
$ python detect_mask_image.py --image examples/example_02.png
[INFO] loading face detector model...
[INFO] loading face mask detector model...
[INFO] computing face detections...
图12:我在这张照片中没有戴口罩。使用Python,OpenCV和TensorFlow/ Keras,我们的系统已正确检测到我的脸部为No Mask(“无口罩”)。
我们的口罩检测器已正确预测“无面罩”。
让我们尝试最后一张图片:
$ python detect_mask_image.py --image examples/example_03.png
[INFO] loading face detector model...
[INFO] loading face mask detector model...
[INFO] computing face detections...
图13:为什么未检测到前景中的女士戴着口罩?使用Python,OpenCV和TensorFlow/ Keras构建的具有计算机视觉和深度学习功能的面罩检测器是否无效?(图片来源:https://www.medicaldevice-network.com/news/coronavirus-outbreak-mask-production/)
为什么会产生这样的结果?
为什么我们能够在背景中检测到两位男性的脸,并为他们正确分类戴口罩/不戴口罩,却无法检测到前景中的那个女人?
我将在课程的“改善建议”一节中讨论这个问题的原因,这个问题的关键在于我们过于依赖我们的两阶段流程。
请记住,为了对人是否戴着口罩进行分类,我们首先需要执行人脸检测-如果未找到人脸(此图像中就发生了这种情况),则不能使用口罩检测器!
我们无法检测到前景中的人脸的原因是:
- 口罩遮盖区域太大;
- 用于训练人脸检测器的数据集不包含戴口罩的人脸示例图像。
因此,如果人脸大部分区域被遮挡,我们的脸部检测器很可能无法检测到脸部。
我将在本教程的“进一步改进的建议”部分中更详细地讨论此问题,包括如何提高口罩检测器的精度。
使用OpenCV在实时视频流中实现我们的COVID-19口罩检测器
至此,我们知道可以对静态图像应用口罩检测了,但是在实时视频流该如何做呢?
我们的COVID-19口罩检测模型是否可以实时运行?
让我们来尝试一下。
在目录结构中打开detect_mask_video.py文件,并插入以下代码:
# import the necessary packages
from tensorflow.keras.applications.mobilenet_v2 import preprocess_input
from tensorflow.keras.preprocessing.image import img_to_array
from tensorflow.keras.models import load_model
from imutils.video import VideoStream
import numpy as np
import argparse
import imutils
import time
import cv2
import os
该脚本的算法与在静态图片中应用口罩检测算法是相同的,但它需要处理网络摄像流中的每一帧。
因此,我们还需要导入一个VideoStream类和time。两者将用来处理视频流。我们还将利用imutils的方面感知尺寸调整方法。
此脚本的面部检测/口罩预测逻辑在detect_and_predict_mask函数中:
def detect_and_predict_mask(frame, faceNet, maskNet):
# grab the dimensions of the frame and then construct a blob
# from it
(h, w) = frame.shape[:2]
blob = cv2.dnn.blobFromImage(frame, 1.0, (300, 300),
(104.0, 177.0, 123.0))
# pass the blob through the network and obtain the face detections
faceNet.setInput(blob)
detections = faceNet.forward()
# initialize our list of faces, their corresponding locations,
# and the list of predictions from our face mask network
faces = []
locs = []
preds = []
在此处定义该函数,便于稍后理解我们的帧处理循环。
此函数会检测人脸,然后将我们的口罩分类器应用于每个 face ROI。这样的功能可以使我们的代码更加健壮。如果你愿意的话,可以把它移动到单独的Python文件中。
我们的detect_and_predict_mask函数接受三个参数:
- 帧:我们信息流中的帧;
- faceNet:用于检测人脸在图像中的位置的模型;
- maskNet:我们的COVID-19口罩分类器模型。
在该函数内部,我们构造一个Blob,检测人脸并初始化一系列列表,并将其中两个列表作为返回值返回。这些列表包括我们的人脸(即ROI),位置(人脸位置)和预测值(口罩/无口罩预测列表)。
从这里开始,我们将遍历人脸检测:
在循环内部,我们过滤掉较差的检测结果(第34-38行),提取边界框并确保边界框坐标值不要超出图片边界(第41-47行)。
然后,我们将面部ROI 加到对应的两个列表里:
在提取了面部ROI并进行了预处理(第51-56行)之后,我们将面部ROI和边界框添加到它们各自的列表中。
现在,我们可以通过口罩预测器来进行预测:
上述代码逻辑主要用于提高速度。首先,我们确保至少检测到一张脸(第64行),否则,我们将返回空的pred。
其次,我们要在框架中对全部人脸进行推理,以使我们的pipeline更快(第68行)。由于开销的原因(特别是如果你使用的GPU需要在系统总线上进行大量开销通信),我们不必编写另一个循环来分别对每个人脸进行预测,批量执行预测更为有效。
第72行返回我们的人脸边界框位置和相应的戴口罩/不戴口罩预测值。
接下来,我们将定义命令行参数:
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-f", "--face", type=str,
default="face_detector",
help="path to face detector model directory")
ap.add_argument("-m", "--model", type=str,
default="mask_detector.model",
help="path to trained face mask detector model")
ap.add_argument("-c", "--confidence", type=float, default=0.5,
help="minimum probability to filter weak detections")
args = vars(ap.parse_args())
我们的命令行参数包括:
- --face:人脸检测器目录的路径;
- --model:训练好的口罩分类器的路径;
- --confidence:用来过滤较差检测的最小概率阈值。
准备好库,函数以及命令行参数后,在循环遍历框架之前,我们只需要处理一些初始化工作:
# load our serialized face detector model from disk
print("[INFO] loading face detector model...")
prototxtPath = os.path.sep.join([args["face"], "deploy.prototxt"])
weightsPath = os.path.sep.join([args["face"],
"res10_300x300_ssd_iter_140000.caffemodel"])
faceNet = cv2.dnn.readNet(prototxtPath, weightsPath)
# load the face mask detector model from disk
print("[INFO] loading face mask detector model...")
maskNet = load_model(args["model"])
# initialize the video stream and allow the camera sensor to warm up
print("[INFO] starting video stream...")
vs = VideoStream(src=0).start()
time.sleep(2.0)
在这里,我们已经初始化了:
- 人脸检测器;
- COVID-19口罩检测器;
- 网络摄像头视频流。
让我们试下历遍处理视频流:
我们开始遍历视频中的帧(第103行)。其中,我们从流中抓取一个帧并调整其大小(106和107行)。
同时我们使用便捷工具;第111行会检测并预测人们是否戴着口罩。
让我们对COVID-19口罩检测结果做一些后处理:
在对预测结果的循环中(从115行开始),我们:
- 展开人脸边界框和戴口罩/不戴口罩的预测(第117和118行);
- 确定标签和颜色(122-126行);
- 注释标签和面边界框(第130-132行)。
最后,我们显示结果并执行清理:
# show the output frame
cv2.imshow("Frame", frame)
key = cv2.waitKey(1) & 0xFF
# if the `q` key was pressed, break from the loop
if key == ord("q"):
break
# do a bit of cleanup
cv2.destroyAllWindows()
vs.stop()
视频帧被显示后,我们捕获按键。如果用户按q(退出),我们将跳出循环并执行释放内存。
用Python,OpenCV和TensorFlow/ Keras进行深度学习来实现一个实时口罩检测器真是太好了!
使用OpenCV实时检测COVID-19口罩
要查看实时COVID-19口罩检测器的效果,请确保使用本教程的“下载”部分下载源代码和预训练的口罩检测器模型。
然后使用以下命令在实时视频流中启动口罩检测器:
$ python detect_mask_video.py
[INFO] loading face detector model...
[INFO] loading face mask detector model...
[INFO] starting video stream...
可以看到我们的口罩检测器能够实时运行(并且准确预测)。
改善建议
从上面的结果部分可以看到,我们的口罩检测器可以很好地工作,尽管:
- 训练数据有限;
- 人工生成的戴口罩数据集(请参见上面的“如何创建我们的面罩数据集?”部分)。
为了进一步改善我们的口罩检测模型,你应该收集戴口罩的人的实际图像(而不是人工生成的图像)。
虽然我们的人工数据集在这种情况下效果很好,但并不能代替真实的戴口罩人像。
其次,你还应该收集可能会“迷惑”分类器的人脸图像,这些图片会让分类器误认为照片中的人戴口罩但实际上没有戴口罩。比如说:包裹在脸部的衬衫,遮挡在嘴部的头巾等. 所有这些都是可以“迷惑”我们的口罩检测器将其判断为戴口罩的示例。
最后,你应该考虑训练专用的两类目标检测器,而不是简单的图像分类器。
我们目前的人脸口罩检测的方法分为两个步骤:
- 步骤1:执行人脸检测;
- 步骤2:对每张脸进行口罩检测。
这种方法的问题在于,根据定义,口罩会遮盖脸部的一部分。如果遮挡了区域过大,则无法检测到脸部,也就无法使用口罩检测器。
为了避免该问题,我们应训练一个两类的目标检测器,该目标检测器由戴口罩类和不戴口罩类组成。
将目标检测器与戴口罩类结合使用将在以下两个方面改进模型。
首先,目标检测器将能够自然地检测戴着口罩的人,否则由于过多的面部被遮盖,人脸检测器将无法检测到这些对象。
其次,这种方法将我们的计算机视觉流程简化为一步-而不是先应用人脸检测,再应用口罩检测器模型,我们要做的就是在网络的一次前向传递过程中应用目标检测器对图像中戴口罩和不戴口罩的人计算出边界框。
这种方法不仅计算效率更高,更“优雅”而且是端到端。
原文标题:
COVID-19: Face Mask Detector with OpenCV, Keras/TensorFlow, and Deep Learning
原文链接:
https://www.pyimagesearch.com/2020/05/04/covid-19-face-mask-detector-with-opencv-keras-tensorflow-and-deep-learning/
编辑:黄继彦
校对:林奕霖
译者简介
张一然,哥本哈根大学计算机系硕士毕业,研究方向为图像补全。现从事自然语言处理工作。感兴趣方向为计算机视觉和自然语言处理,喜欢看书旅游。