源代码地址:
https://www.pyimagesearch.com/2020/05/04/covid-19-face-mask-detector-with-opencv-keras-tensorflow-and-deep-learning/#download-the-code
在本教程中,您将学习如何使用OpenCV、Keras/TensorFlow和深度学习来训练COVID-19口罩探测器。
上个月,我在博客上写了一篇关于使用深度学习检测X光图像中COVID-19的文章。
读者真的很喜欢在及时、实用的教程中学习,所以今天我们来看看另一个与COVID相关的计算机视觉应用,这个应用是关于用OpenCV和Keras/TensorFlow检测口罩的。
我在受到以下情况的启发后编写了本教程:
1、收到许多来自PyImageSearch读者的请求,要求我写这样一篇博客
2、看到其他人实现的解决方案(我最喜欢的是Prajna Bhandary的,我们将从今天开始构建
在正确部署的情况下,今天我们在这里构建的COVID-19口罩探测器可能有助于确保您和其他人的安全(但我将把这留给医疗专业人员来决定、实施和在外部署)。
要学习如何使用OpenCV、Keras/TensorFlow和深度学习创建COVID-19口罩检测器,请继续阅读!
COVID-19:使用OpenCV、Keras/TensorFlow和深度学习实现口罩探测器
在本教程中,我们将讨论我们的两阶段COVID-19口罩检测器,详细说明如何实现我们的计算机视觉/深度学习流水线。
之后,我们将审查数据集并用于训练我们的自定义口罩探测器。
然后我将向您展示如何实现一个Python脚本来使用Keras和TensorFlow在我们的数据集上训练一个口罩检测器。
我们将使用这个Python脚本来训练一个口罩检测器并检查结果。
给定经过训练的COVID-19口罩检测器,我们将继续实现另外两个Python脚本,用于:
1、在图像中检测COVID-19口罩
2、实时视频流中的口罩检测
我们将通过探讨口罩探测器的效果来总结这篇文章。我还将提供一些进一步改进的建议。
两阶段COVID-19面罩检测器
图1:使用计算机视觉和深度学习构建COVID-19口罩检测器的阶段和各个步骤。
为了训练一个定制的口罩检测器,我们需要将我们的项目分成两个不同的阶段,每个阶段都有各自的子步骤(如上图1所示):
训练:在这里,我们将聚焦于从磁盘加载我们的口罩检测数据集,在此数据集上训练模型(使用Keras/TensorFlow),然后将口罩检测器序列化到磁盘
部署:一旦口罩检测器训练完毕,我们就可以加载口罩检测器,执行面部检测,然后将每个面部图像分为带口罩和不带口罩
在本教程的其余部分中,我们将详细介绍这些阶段和相关子集,但同时,先让我们看看将用于训练COVID-19口罩检测器的数据集。
我们的COVID-19口罩检测数据集
图2:面罩检测数据集由“带口罩”和“无口罩”图像组成。我们将使用该数据集构建一个COVID-19口罩检测器,该检测器基于计算机视觉,并使用Python、OpenCV和TensorFlow/Keras进行深度学习。
我们今天将在这里使用的数据集是由PyImageSearch读者Prajna Bhandary创建的。
此数据集包含1376个图像,属于两个类别:
1、带口罩:690张图片
2、无口罩:686张图片
我们的目标是训练一个定制的深度学习模型来检测一个人是否戴着口罩。
注意:为了方便起见,我在本教程的“下载”部分提供了Prajna创建的数据集。
我们的口罩数据集是如何创建的?
Prajna和我一样,一直对世界的现状感到失落和沮丧——每天都有成千上万的人死去,对我们许多人来说,我们能做的(如果有的话)很少。
为了保持积极的状态,Prajna决定运用计算机视觉和深度学习来解决现实世界的问题,以此分散自己的注意力:
1、最佳的场景-她可以利用自己的项目帮助他人
2、最差的场景-这给了她一个非常需要的精神寄托
不管怎样,都是双赢的!
作为程序员、开发人员和计算机视觉/深度学习实践者,我们都可以从Prajna的书中翻开一页——让你的技能成为你的寄托和避风港。
为了创建这个数据集,Prajna有一个巧妙的解决方案:
1、拍摄人脸的正常图像2、然后创建一个自定义的计算机视觉Python脚本来向它们添加口罩,从而创建一个人工(但仍然适用于现实世界)数据集
这种方法实际上比听起来容易地多,只需要使用面部标记来实现。面部标记允许我们自动推断面部结构的位置,包括:眼睛、眉毛、鼻子、嘴、下颌线。
要使用面部标记构建一个戴口罩的面部数据集,我们首先需要从一个没有戴口罩的人像开始:
图3:为了建立一个COVID-19/冠状病毒的口罩数据集,我们首先从一张没有戴口罩的人的照片开始。
在此基础上,我们应用人脸检测来计算人脸在图像中的边界位置:
图4:下一步是应用面部检测。这里我们使用了一种深度学习方法来使用OpenCV执行人脸检测。
一旦我们知道人脸在图像中的位置,我们就可以提取感兴趣区域(ROI):
图5:下一步是使用OpenCV和NumPy切片提取面部ROI。
从那里,我们应用面部标记,定位眼睛、鼻子、嘴等:
图6:然后,我们使用dlib检测面部标志,这样我们就知道在脸上的哪个位置放置面罩。
接下来,我们需要一个口罩的图像(带有透明背景),如下所示:
图7:COVID-19/冠状病毒面罩/防护罩示例。由于我们知道人脸的标记位置,这个面罩将自动覆盖在原始的人脸ROI上。
通过使用面部标记(即沿下巴和鼻子的点)来计算口罩的放置位置,该口罩将自动应用于面部。
然后调整口罩的大小并旋转,将其放置在面部上:
图8:在这个图中,口罩被放在原来的图片中的人的脸上。很难一眼看出,COVID-19口罩是通过OpenCV和dlib人脸标志的计算机视觉技术添加上去的。
然后,我们可以对所有输入图像重复此过程,从而创建我们的人工口罩数据集:
图9:显示了一组人工COVID-19口罩图像。这一套将是我们的“带口罩”和“不带口罩”数据集的一部分,用于COVID-19面罩的计算机视觉检测和使用Python、OpenCV和TensorFlow/Keras的深度学习。
但是,在使用此方法人工创建数据集时,需要注意一点!
如果使用一组图像创建戴口罩的人的人工数据集,则无法“重用”训练集中没有口罩的图像-仍需要收集未在人工生成过程中使用过的无口罩图像!
如果将用于生成口罩样本的原始图像作为无口罩样本,则模型将具有严重的偏向性,无法广泛适用。为了避免这种情况要不惜一切代价花时间收集没有口罩的面部图像。
介绍如何使用面部标记将口罩应用于面部不在本教程的范围内,但如果您想了解更多信息,我建议:
参考Prajna若的GitHub库
https://github.com/prajnasb/observations/tree/master/mask_classifier/Data_Generator
在PyImageSearch博客上阅读另一个教程,在那篇教程中我将讨论如何使用面部标记自动将太阳镜应用于面部(https://www.pyimagesearch.com/2018/11/05/creating-gifs-with-opencv/)
我的太阳镜帖子中的原理同样适用于构建一个人工口罩数据集——使用面部标记推断面部结构,旋转并调整口罩大小,然后将其应用于图像。
项目结构
从本文的“下载”部分获取文件后,将显示以下目录结构:
dataset/目录包含“我们的COVID-19口罩检测数据集”部分中描述的数据。
提供了三个图像示例/以便您可以测试静态图像口罩检测器。
在本教程中,我们将回顾三个Python脚本:
train_mask_detector.py:接受我们的输入数据集并对其进行微调,以创建我们的mask_detector.model。还将生成包含精度/损失曲线的training history plot.png
detect_mask_image.py:在静态图像中执行口罩检测
detect_mask_video.py:使用网络摄像头,此脚本将对视频流中的每个帧应用口罩检测
在接下来的两部分中,我们将训练我们的口罩检测器。
用Keras和TensorFlow实现COVID-19口罩检测器训练脚本
现在,我们已经回顾了我们的口罩数据集,让我们学习如何使用Keras和TensorFlow训练分类器来自动检测一个人是否戴着口罩。
为了完成这项任务,我们将对MobileNet V2体系结构进行微调,这是一种高效的体系结构,可应用于计算能力有限的嵌入式设备(例如,树莓Pi、Google Coral、NVIDIA Jetson Nano等)。
注意:如果你对嵌入式计算机视觉感兴趣,一定要看看我的《树莓派的计算机视觉》一书,书中介绍了如何使用性能有限的设备实现计算机视觉和深度学习。
将我们的口罩检测器部署到嵌入式设备可以降低制造此类口罩检测系统的成本,这也是我们选择使用此架构的原因。
我们开始吧!
打开目录结构中的train_mask_detector.py文件,并插入以下代码:
导入我们的训练脚本可能让您产生恐惧,要么是因为有太多的脚本,要么您是深度学习的新手。如果你是新手,我建议在前进之前阅读我的Keras教程和fine_tuning教程。
我们导入的tensorflow.keras实现:
1、数据扩充
2、加载MobilNetV2分类器(我们将使用预先训练的ImageNet权重微调此模型)3、构建新的全连接(FC)头
4、预处理
5、加载图像数据
我们将使用scikit learn(sklearn)对类标签进行二进制化、对数据集进行分段并打印分类报告。
我的imutils路径实现将帮助我们在数据集中查找和列出图像。我们将使用matplotlib绘制训练曲线。
要安装必要的软件以便您可以使用这些库,请务必遵循我的Tensorflow 2.0+安装指南:
1、如何在Ubuntu上安装TensorFlow 2.0
2、如何在macOS上安装TensorFlow 2.0
让我们继续分析一些从终端启动脚本所需的命令行参数:
我们的命令行参数包括:
--dataset:带口罩的面部和和面部输入数据集的路径
--plot:输出训练历史图,将使用matplotlib生成
--model:序列化生成的口罩分类模型的路径
我喜欢在一个地方定义我的深度学习超参数:
在这里,我指定了超参数常数,包括我的初始学习速率、训练阶段数和批处理大小。稍后,我们将应用“学习速率衰减计划”,这就是我们将学习速率变量命名为INIT_LR的原因。
现在,我们准备加载并预处理我们的训练数据:
在这个部分,我们做的是:
获取数据集中的所有imagepath(第44行)
初始化data和labels列表(第45行和第46行)
在imagePaths上循环并加载+预处理图像(第49-60行)。预处理步骤包括调整到224×224像素,转换为数组格式,并将输入图像中的像素强度缩放到范围[-1,1](通过preprocess_input快捷功能)
将预处理image和相关label分别附加到data和labels列表(第59行和第60)
确保我们的训练数据是NumPy数组格式(第63和64行)
上面几行代码假设您的整个数据集足够小,可以放入内存。如果您的数据集大于可用的内存,我建议使用HDF5,这是我在Deep Learning for Computer Vision with Python(从业者包第9章和第10章)中介绍的一种策略。
我们的数据准备工作还没有完成。接下来,我们将对标签进行编码,对数据集进行分区,并准备进行数据扩充:
第67-69行对我们的类标签进行one-hot编码,这意味着我们的数据将采用以下格式:
如您所见,labels数组的每个元素都由一个数组组成,其中只有一个索引是“hot”(即1)。
使用scikit learn的便利方法,第73行和第74行将我们的数据分成80%的训练和剩余的20%的测试。
在训练过程中,我们将对我们的图像应用动态突变,以提高泛化能力。这称为数据增强,第77-84行上设定随机旋转、缩放、剪切、偏移和翻转参数。我们将在训练时使用aug对象。
但首先,我们需要准备MobileNetV2进行微调:
微调设置是一个三步过程:
使用预先训练过的ImageNet权重加载MobileNet,排除网络头(第88行和第89行)
构造一个新的FC头,并将其附加到基座上以代替旧的头(第93-102行)
冻结网络的基本层(第106和107行)。在反向传播过程中,这些基本层的权重不会被更新,而头层的权重将被调整。
微调是一种策略,我几乎总是建议在节省大量时间的同时建立一个基线模型。要了解有关理论、目的和策略的更多信息,请参阅我的fine-tuning blog posts 和Deep Learning for Computer Vision with Python (从业者包第5章)。
随着我们的数据准备和模型结构的微调到位,我们现在准备编译和训练我们的训练检测网络:
第111-113行使用Adam优化器、学习率衰减计划和二进制交叉熵编译我们的模型。如果您是从这个训练脚本中构建的,并且超过2个类,请确保使用分类交叉熵。
口罩训练通过117-122行启动。请注意,我们的数据增强对象(aug)将如何提供一批经过修改的图像数据。
训练完成后,我们将在测试集上评估生成的模型:
这里,第126-130行在测试集上进行预测,获取最高概率的类标签索引。然后,我们在终端打印一份分类报告以供检查。
第138行将我们的口罩分类模型序列化到磁盘。
我们的最后一步是绘制精度和损失曲线:
一旦绘图就绪,第152行使用--plot文件路径将图形保存到磁盘。
用Keras/TensorFlow训练COVID-19口罩探测器
我们现在准备使用Keras、TensorFlow和深度学习来训练我们的口罩检测器。
确保您已经使用本教程的“下载”部分下载了源代码和口罩数据集。
从那里,打开一个终端,执行以下命令:
图10:COVID-19口罩检测仪的训练精度/图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文件,我们开始:
我们的驱动程序脚本需要导入三个TensorFlow/Keras库来(1)加载MaskNet模型和(2)预处理输入图像。
显示和图像处理需要OpenCV。
下一步是分析命令行参数:
我们的四个命令行参数包括:
--image:包含输入的用于推断的面部图像路径
--face:人脸检测器模型目录的路径(我们需要在对人脸进行分类之前对其进行本地化)
--model:我们在本教程前面训练的口罩检测器模型的路径
--confidence:可选的概率阈值可以设置为覆盖50%以过滤弱人脸检测
接下来,我们将同时加载人脸检测器和口罩分类器模型:
现在,我们的深度学习模型已经生成,下一步是加载并预处理输入图像:
在从磁盘加载--image(第37行)时,我们复制并获取帧尺寸,以便将来缩放和显示(第38行和第39行)。
预处理由OpenCV的blobFromImage函数(第42行和第43行)进行。如参数所示,我们将大小调整为300×300像素,并执行均值相减。
然后,第47行和第48行执行面部检测以定位图像中所有面部的位置。
一旦我们知道每个人脸的预测位置,我们将确保它们在提取FaceRoi之前满足--confidence 阈值:
在这里,我们循环detections 并提取confidence,以根据--confidence阈值(第51-58行)进行度量。
然后,我们计算特定面的边界框值,并确保该框落在图像的边界内(第61-67行)。
接下来,我们将通过MaskNet模型运行face ROI:
在这个区块,我们:
通过NumPy切片提取面部ROI(第71行)
像我们在训练期间那样预先处理ROI(第72-76行)
执行口罩检测以预测是否有口罩(第80行)
从这里开始,我们将注解并显示结果!
首先,我们根据口罩检测器模型返回的概率(第84行)确定类标签,并为注释指定相关颜色(第85行)。有口罩的颜色是绿色,没有口罩的颜色是红色。
然后,我们使用OpenCV绘图函数(第92-94行)绘制标签文本(包括类和概率)以及面部图像的边框。
处理完所有检测后,第97行和第98行显示输出图像。
OpenCV图像中COVID-19口罩的检测
让我们把COVID-19口罩探测器启动!确保您已经使用本教程的“下载”部分下载了源代码、示例图像和经过预训练的口罩检测器。
从那里,打开一个终端,执行以下命令:
a
图11:这名男子在公共场合是否戴着COVID-19/冠状病毒口罩?是的,他戴了,我们的计算机视觉和使用Python、OpenCV和TensorFlow/Keras的深度学习方法使得自动检测口罩的存在成为可能。(图片来源)
如您所见,我们的口罩检测器正确地将此图像标记为口罩。
让我们尝试另一个图像,这个人没有戴口罩:
图12:哦哦。这张照片里我没有戴COVID-19面罩。使用Python、OpenCV和TensorFlow/Keras,我们的系统已经正确地检测到我的脸“没有口罩”。
我们的口罩检测器已经准确地预测到没有口罩。
让我们尝试最后一个图像:
图13:结果是什么?为什么前景中的女士没有被发现戴着COVID-19面罩?我们用计算机视觉和使用Python、OpenCV和TensorFlow/Keras的深度学习构建的COVID-19面罩探测器失败了吗?(图片来源)
这里发生了什么事?
为什么我们能够检测到背景中两位男士的脸,并正确地为他们分类为没有口罩,但我们无法检测到前景中的女人?
我在本教程后面的“进一步改进的建议”部分讨论了这个问题的原因,但要点是我们太依赖于两个阶段的过程。
请记住,为了分类一个人是否戴着口罩,我们首先需要执行面部检测-如果找不到面部(这是在这幅图像中发生的事情),那么就不能应用口罩检测器!
我们无法检测前景中的人脸的原因是:
它被口罩遮住了
用于训练面部检测器的数据集不包含戴口罩的人的示例图像
因此,如果大部分人脸被遮挡,我们的人脸检测器很可能无法检测出人脸。
再次,我将在本教程的“进一步改进的建议”部分中更详细地讨论这个问题,包括如何提高口罩检测器的精度。
利用OpenCV在实时视频流中实现COVID-19人脸检测
现在,我们知道我们可以将口罩检测应用于静态图像-但是实时视频流呢?
我们的COVID-19口罩探测器能够实时运行吗?
让我们看看。
打开目录结构中的detect_mask_video.py文件,并插入以下代码:
这个脚本的算法是相同的,但是代码结构不同,它处理的是网络摄像头视频流的每一帧。
因此,在导入时唯一的区别是我们需要一个VideoStream和time。这都有助于我们处理视频流。我们还将利用imutils的aspect-aware调整方法。
此脚本的人脸检测/口罩预测逻辑位于detect_and_predict_mask方法中:
通过在这里定义这个快捷函数,我们的帧处理循环将更容易阅读。
此函数检测人脸,然后将我们的口罩分类器应用于每个人脸ROI。这样的函数整合了我们的代码——如果您愿意的话,它甚至可以移动到单独的Python文件中。
我们的detect_and_predict_mask函数接受三个参数:
frame:来自我们的视频流的帧
faceNet:用于检测图像中人脸位置的模型
maskNet:COVID-19人脸识别模型
在内部,我们构造一个blob、检测人脸和初始化列表,其中两个列表被设置为由函数返回。这些列表包括我们的面部(即roi)、locs(面部位置)和preds(口罩/无口罩预测列表)。
从这里开始,我们将对面部detections进行循环:
在循环中,我们过滤掉弱检测(第34-38行)并提取边界框,同时确保边界框坐标不超出图像的边界(第41-47行)。
接下来,我们将在两个对应的列表中添加面部roi:
在提取面部roi并进行预处理(第51-56行)之后,我们将面部roi和边界框附加到它们各自的列表中。
我们现在可以通过我们的口罩检测器来检测我们的面部图像了:
这里的逻辑是为效率而建立的。首先,我们确保至少检测到一个人脸(第64行)-如果没有,我们将返回空的pred。
其次,我们对框架中的面部图像进行批量推断,以便处理效率更快(第68行)。由于开销的原因,编写另一个循环来分别对每个面部进行预测是没有意义的(特别是如果您使用的GPU在系统总线上需要有大量通信开销)。批量执行预测更有效。
第72行将我们的面部边界框位置和相应的有口罩/无口罩预测返回给调用者。
接下来,我们将定义命令行参数:
我们的命令行参数包括:
--face:人脸检测器目录的路径
--model:经过训练的口罩分类器的路径
--confidence:过滤弱人脸检测的最小概率阈值
导入、快捷功能和命令行参数准备就绪后,在循环处理帧之前,我们只需处理一些初始化:
在这里,我们初始化了:
面部探测器
COVID-19口罩检测仪
网络摄像头视频流
让我们继续循环流中的帧:
我们开始在第103行的帧上循环。在内部,我们从流中获取一个帧并调整其大小(第106行和第107行)。
从这里开始,我们使用快捷程序;第111行检测并预测人们是否戴着口罩。
让我们对COVID-19口罩检测结果进行后置处理(比如注释):
在预测结果的循环中(从第115行开始),我们:
打开面部边界框并进行口罩/无口罩预测(第117行和第118行)
确定label 和color (第122-126行)
标注label 和面部边界框(第130-132行)
最后,我们显示结果并执行清理:
显示帧后,我们捕获按键。如果用户按q(quit),我们将跳出循环并结束程序。
用Python、OpenCV和TensorFlow/Keras实现你的实时口罩检测非常好!
OpenCV实时检测COVID-19口罩
要查看我们的实时COVID-19口罩检测器,请确保使用本教程的“下载”部分下载源代码和预先训练的口罩检测器模型。
然后,可以使用以下命令在实时视频流中启动口罩检测器:
在这里,您可以看到我们的口罩检测器能够实时运行(并且在其预测中也是正确的)。
改进建议
从上面的结果部分可以看出,我们的口罩检测器工作得很好,尽管:
训练数据有限
with_mask类是人工生成的(请参阅“如何创建我们的口罩数据集”章节)。
为了进一步改进我们的口罩检测模型,您应该收集戴口罩的人的实际图像(而不是人工生成的图像)。
虽然我们的人工数据集在这种情况下工作得很好,但没有什么可以替代真实的数据集。
其次,你还应该收集可能会“混淆”我们的分类器的图像,这些图像使其认为此人戴着口罩,而事实上他们并不是——潜在的例子包括裹在面部的衬衫、嘴上的绷带等。
所有这些都是一些可能被我们的口罩检测器混淆为口罩的例子。
最后,您应该考虑训练一个专用的二元分类对象检测器,而不是一个简单的图像分类器。
目前我们检测一个人是否戴口罩的方法分为两步:
步骤1:进行面部检测
步骤2:使用面部检测器监测每个面部
这种方法的问题在于,根据定义,口罩会遮住面部的一部分。如果有足够的人脸被遮挡,则无法检测到该人脸,因此,口罩检测器没有生效。
为了避免这个问题,您应该训练一个两类对象检测器,该检测器由带口罩类和不带口罩类组成。
将对象检测器与专用的with_mask类结合将会在两个方面改进模型。
首先,目标探测器将能够自然而然地探测到戴着口罩的人,否则由于太多的面部被遮挡,面部探测器将无法探测到这些人。
其次,这种方法将我们的计算机视觉管道简化为一个步骤-而不是应用人脸检测和我们的口罩检测器模型,我们需要做的只是使用对象检测器在网络的单向步骤中为有口罩和没有口罩的人提供区域边界 。
这样的方法不仅计算效率更高,而且更“优雅”,更符合端到端的风格。
接下来是什么?
图14:如果您想学习在自己的数据集上训练自己的深度学习模型,请获取《Deep Learning for Computer Vision with Python》的副本,然后开始学习。我和我的团队将在这条路上的每一步,确保您能够执行示例代码并得到您的问题的答案。
总结
在本教程中,您学习了如何使用OpenCV、Keras/TensorFlow和深度学习创建COVID-19口罩检测器。
为了创建我们的口罩检测器,我们训练了一个人戴口罩和不戴口罩的两类模型。
我们在戴口罩/不戴口罩数据集上对MobileNetV2进行了微调,得到了一个大约99%准确率的分类器。
然后,我们使用这个口罩分类器,并通过以下方式将其应用于图像和实时视频流:
图像/视频中的人脸检测
提取每个单独的面部图像
应用我们的口罩分类器
我们的口罩检测器是精确的,而且由于我们使用了MobileNetV2架构,它的计算效率也很高,使得将模型部署到嵌入式系统(树莓派、Google Coral、Jetosn、Nano等)更加容易。
希望你喜欢这个教程!
英文原文:https://www.pyimagesearch.com/2020/05/04/covid-19-face-mask-detector-with-opencv-keras-tensorflow-and-deep-learning/
译者:阿布铥