很多读者要求我写一篇相关博客;
看到其他人有相关的实验(其中我最欣赏的是Prajna Bhandary的实现,也就是我们今天要用到的)。
检测图片中的COVID-19口罩;
检测实时视频流中的口罩。
训练:在该阶段我们主要是从磁盘加载口罩检测数据集,在该数据集上训练模型(使用Keras / TensorFlow),然后将模型序列化到磁盘;
部署:训练完口罩检测器后,加载训练好的口罩检测器,进行人脸检测,然后将人脸分类为戴口罩或不戴口罩。
戴口罩: 690张图片;
不戴口罩: 686张图片。
最好的情况——她可以利用自己的项目来帮助他人;
最坏的情况——这给了她急需的心理逃生。
拍摄正常的脸部图像;
创建一个Python脚本向图片中的人脸添加口罩,从而创建一个人造的(但仍适用于现实世界)数据集。
眼
眼眉
鼻子
嘴
颚线
首先,我们利用人脸检测来计算图像中人脸的边界框位置:
知道人脸在图像中的位置之后,我们就可以提取出我们感兴趣的区域(ROI):
通过使用面部标志(即沿着下巴和鼻子的点)来计算该口罩的放置位置,然后调整口罩的大小,旋转,将其放在脸上:
然后,对所有输入图像重复此过程,创建一个口罩数据集:
图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
train_mask_detector.py:接受输入数据,精调MobileNetV2,创建make_detector.model。同时以图片的形式输出训练过程中的准确度/损失曲线;
Detect_mask_image.py:在静态图片上进行口罩检测;
Detector_mask_video.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
数据增强;
加载MobilNetV2分类器(我们将使用预训练的ImageNet权重对该模型进行精调);
建立一个新的全连接(FC)头;
预处理;
加载图像数据。
如何在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
抓取数据集中的所有imagePath(第44行);
初始化数据和标签列表(第45和46行);
循环遍历imagePaths并加载+预处理图像(第49-60行)。预处理步骤包括将尺寸调整为224×224像素,转换成数组格式并将输入图像中的像素值缩放到[-1,1]范围(通过preprocess_input函数);
将预处理的图像和相关标签分别添加到数据和标签列表中(第59行和第60行);
确保我们的训练数据是NumPy数组格式(第63和64行)。
向MobileNet加载预训练的ImageNet权重,而不用担心网络的损失(第88和89行);
构造一个新的全连接层,并将其附加到模型最后以代替旧的全连接层(第93-102行);
冻结网络的基础层(106和107行)。这些基础层的权重在反向传播过程中不会更新,而顶层的权重将被调整。
$ 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并应用我们的计算机视觉和深度学习知识来执行口罩检测。
从磁盘加载输入图像;
检测图像中的人脸;
应用我们的口罩检测器将人脸分类为戴口罩或不戴口罩。
# 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
# 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"])
通过NumPy切片提取面部ROI(第71行);
采用与训练期间相同的方式对ROI进行预处理(第72-76行);
执行口罩检测以预测“戴口罩”或“不戴口罩”(第80行)。
$ 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)
$ 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/)
口罩遮盖区域太大;
用于训练人脸检测器的数据集不包含戴口罩的人脸示例图像。
# 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
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 = []
帧:我们信息流中的帧;
faceNet:用于检测人脸在图像中的位置的模型;
maskNet:我们的COVID-19口罩分类器模型。
# 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口罩检测器;
网络摄像头视频流。
展开人脸边界框和戴口罩/不戴口罩的预测(第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()
$ python detect_mask_video.py [INFO] loading face detector model... [INFO] loading face mask detector model... [INFO] starting video stream...
训练数据有限;
人工生成的戴口罩数据集(请参见上面的“如何创建我们的面罩数据集?”部分)。
步骤1:执行人脸检测;
步骤2:对每张脸进行口罩检测。