在 Python 中使用 TensorFlow 进行面部口罩检测
我们将使用此 Python 脚本来训练口罩检测器并查看结果。鉴于训练有素的 COVID-19 口罩检测器,我们将继续实现另外两个 Python 脚本,用于:
- 检测图像中的 COVID-19 口罩
- 检测实时视频流中的口罩
口罩检测系统流程图
为了训练自定义口罩检测器,我们需要将项目分为两个不同的阶段,每个阶段都有各自的子步骤(如上图 1 所示):
- 训练:这里我们将重点从磁盘加载口罩检测数据集,在此数据集上训练模型(使用 Keras/TensorFlow),然后将口罩检测器序列化到磁盘
- 部署:训练完口罩检测器后,我们就可以继续加载口罩检测器,执行人脸检测,然后将每个人脸分类为 with_mask 或 without_mask。
我们将使用这些图像使用 TensorFlow 构建 CNN 模型,通过 PC 的网络摄像头检测您是否戴着口罩。此外,您还可以使用手机的相机来执行相同的操作!
逐步实施
第一步:数据可视化
第一步,让我们可视化数据集中两个类别的图像总数。我们可以看到“是”类有 690 张图像,“否”类有 686 张图像。
逐步实施
第 1 步:数据可视化
第一步,让我们可视化数据集中两个类别的图像总数。我们可以看到“是”类有 690 张图像,“否”类有 686 张图像。
第 2 步:数据增强
在下一步中,我们将扩充数据集以包含更多数量的图像用于训练。在数据增强的这一步中,我们旋转并翻转数据集中的每个图像。我们看到,在数据增强之后,我们总共有 2751 张图像,其中 1380 张图像属于“是”类,“1371”张图像属于“否”类。
第 3 步:分割数据
在此步骤中,我们将数据分为训练集和测试集,其中训练集将包含用于训练 CNN 模型的图像,而测试集则包含用于测试模型的图像。在此,我们取 split_size =0.8,这意味着总图像的 80% 将进入训练集,其余 20% 的图像将进入测试集。
第 4 步:构建模型
下一步,我们使用 Conv2D、MaxPooling2D、Flatten、Dropout 和 Dense 等各个层构建序列 CNN 模型。在最后一个 Dense 层中,我们使用“softmax”函数输出一个向量,该向量给出两个类别中每个类别的概率。
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(100, (3, 3), activation='relu',
input_shape=(150, 150, 3)),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(100, (3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Flatten(),
tf.keras.layers.Dropout(0.5),
tf.keras.layers.Dense(50, activation='relu'),
tf.keras.layers.Dense(2, activation='softmax')
])
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['acc'])
在这里,我们使用“adam”优化器和“binary_crossentropy”作为损失函数,因为只有两个类。此外,您甚至可以使用 MobileNetV2 来获得更高的准确性。
第 5 步:预训练CNN模型
构建模型后,让我们创建“train_generator”和“validation_generator”,以便在下一步中将它们适合我们的模型。我们看到训练集中共有 2200 张图像,测试集中共有 551 张图像。
第 6 步:训练 CNN 模型
此步骤是我们将训练集中的图像和测试集适合我们使用 keras 库构建的顺序模型的主要步骤。我已经对模型进行了 30 轮训练(迭代)。然而,我们可以训练更多的 epoch 来获得更高的准确率,测试是否会发生过度拟合。
我们看到,在第 30 个 epoch 之后,我们的模型在训练集上的准确率为 98.86%,在测试集上的准确率为 96.19%。这意味着它经过良好的训练,没有任何过度拟合。
第 7 步:标记信息
构建模型后,我们为结果标记两个概率。['0' 为 'without_mask','1' 为 'with_mask']。我还使用 RGB 值设置边界矩形颜色。[“红色”代表“without_mask”,“绿色”代表“with_mask”]
第 8 步:导入人脸检测程序
之后,我们打算用它来通过电脑的网络摄像头检测我们是否戴着口罩。为此,首先我们需要实现人脸检测。在此,我们使用基于 Haar 特征的级联分类器来检测面部特征。
这个级联分类器是由 OpenCV 设计的,通过训练数千张图像来检测正面。需要下载相同的 .xml 文件并将其用于检测人脸。我们已将文件上传到 GitHub 存储库。
第 9 步:检测戴口罩和不戴口罩的人脸
在最后一步中,我们使用 OpenCV 库运行无限循环来使用我们的网络摄像头,其中我们使用级联分类器检测面部。代码webcam = cv2.VideoCapture(0)表示网络摄像头的使用。
该模型将预测两个类别([without_mask, with_mask])中每一个类别的可能性。根据较高的概率,标签将被选择并显示在我们的脸部周围。
# 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 imutils
import time
import cv2
import os
def detect_and_predict_mask(frame, faceNet, maskNet):
# 获取框架的尺寸,然后
# 然后从中构建一个 blob
(h, w) = frame.shape[:2]
blob = cv2.dnn.blobFromImage(frame, 1.0, (224, 224),
(104.0, 177.0, 123.0))
# 将 Blob 通过网络
# 并获得人脸检测结果
faceNet.setInput(blob)
detections = faceNet.forward()
print(detections.shape)
# 初始化人脸列表、对应的位置以及来自我们的口罩检测网络的预测列表
faces = []
locs = []
preds = []
# 循环检测
for i in range(0, detections.shape[2]):
# 确保置信度高,过滤掉弱检测结果
greater than the minimum confidence
if confidence > 0.5:
# 为以下对象计算边界框的 (x, y) 坐标
the object
box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
(startX, startY, endX, endY) = box.astype("int")
(startX, startY) = (max(0, startX), max(0, startY))
(endX, endY) = (min(w - 1, endX), min(h - 1, endY))
face = frame[startY:endY, startX:endX]
face = cv2.cvtColor(face, cv2.COLOR_BGR2RGB)
face = cv2.resize(face, (224, 224))
face = img_to_array(face)
face = preprocess_input(face)
# 添加面和边界框 添加到各自的列表中
faces.append(face)
locs.append((startX, startY, endX, endY))
# 只有检测到至少一张人脸时才进行预测
if len(faces) > 0:
faces = np.array(faces, dtype="float32")
preds = maskNet.predict(faces, batch_size=32)
# 返回面位置的 2 元组 及其对应位置的 2 元组
return (locs, preds)
# 从磁盘加载序列化的人脸检测器模型
prototxtPath = r"face_detector\deploy.prototxt"
weightsPath = r"face_detector\res10_300x300_ssd_iter_140000.caffemodel"
faceNet = cv2.dnn.readNet(prototxtPath, weightsPath)
maskNet = load_model("mask_detector.model")
print("[INFO] starting video stream...")
vs = VideoStream(src=0).start()
while True:
frame = vs.read()
frame = imutils.resize(frame, width=400)
(locs, preds) = detect_and_predict_mask(frame, faceNet, maskNet)
# 循环检测人脸位置及其相应位置
for (box, pred) in zip(locs, preds):
# 解包边界框和预测值
(startX, startY, endX, endY) = box
(mask, withoutMask) = pred
label = "Mask" if mask > withoutMask else "No Mask"
color = (0, 255, 0) if label == "Mask" else (0, 0, 255)
# 在标签中加入概率
label = "{}: {:.2f}%".format(label, max(mask, withoutMask) * 100)
# 显示标签和边界框 在输出框上显示矩形
cv2.putText(frame, label, (startX, startY - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.45, color, 2)
cv2.rectangle(frame, (startX, startY), (endX, endY), color, 2)
cv2.imshow("Frame", frame)
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
# 做一些清理工作
cv2.destroyAllWindows()
vs.stop()
输出: