Advertisement

人脸检测实战进阶:使用 OpenCV 进行活体检测

阅读量:

这篇教程详细介绍了如何利用Python和OpenCV进行视频分析,结合预训练的深度学习模型进行活性检测。内容涵盖了以下几个关键部分:
视频流处理和面部检测:

  • 解析视频参数并加载视频流。
  • 使用OpenCV进行面部检测,提取面部区域并生成输出文件。
  • 实现跳帧技术以减少处理时间。
    LivenessNet模型:
  • 介绍LivenessNet模型,这是一个浅层卷积神经网络,用于区分真实和欺骗的面部图像。
  • 提供模型构建代码,包括数据预处理、标签编码、数据分割以及模型训练和评估。
    活性检测流程:
  • 使用检测到的面部图像输入到训练好的LivenessNet模型中进行分类。
  • 生成分类报告并输出训练图以供分析。
    教程结构清晰,从数据预处理到模型训练再到模型应用,涵盖了从头到尾的流程。代码示例详细,适合实际应用中处理不同视频和检测器路径的需求。

help=“# of frames to skip before applying face detection”)

args = vars(ap.parse_args())

导入需要的包。 除了内置的 Python 模块,这个脚本只需要 OpenCV 和 NumPy。

解析命令行参数:

–input :我们输入视频文件的路径。

–output :将存储每个裁剪面的输出目录的路径。

facial detector 的路径为: 我们计划采用 OpenCV 的深度学习 人脸识别技术。 为便利起见,该 Caffe 模型已包含在今天的下载包中。

–confidence : 过滤弱人脸检测的最小概率。 默认情况下,此值为 50%。

由于相邻帧具有高度相似性,因此我们无需对每个图像进行检测和存储。相反地,我们会跳过 N 帧,两次检测之间。您可以通过调整此参数来修改默认值为16。

让我们继续加载人脸检测器并初始化我们的视频流:

load our serialized face detector from disk

print(“[INFO] loading face detector…”)

protoPath = os.path.sep.join([args[“detector”], “deploy.prototxt”])

modelPath = os.path.sep.join([args[“detector”],

“res10_300x300_ssd_iter_140000.caffemodel”])

net = cv2.dnn.readNetFromCaffe(protoPath, modelPath)

open a pointer to the video file stream and initialize the total

number of frames read and saved thus far

images = os.listdir(args[“input”])

read = 0

saved = 0

加载 OpenCV 的深度学习人脸检测器。

收集全部图像。 我们还初始化了两个变量,分别用于记录读取的帧数和循环处理时的帧数。 接下来,我们将开始一个循环来处理每一帧。

for filename in images:

filepath = os.path.join(args[“input”], filename)

img = cv2.imread(filepath)

​ 循环读取图片。

​ 继续检测人脸:

(h, w) = img.shape[:2]

blob = cv2.dnn.blobFromImage(cv2.resize(img, (300, 300)), 1.0,

(300, 300), (104.0, 177.0, 123.0))

pass the blob through the network and obtain the detections and

predictions

net.setInput(blob)

detections = net.forward()

ensure at least one face was found

if len(detections) > 0:

we’re making the assumption that each image has only ONE

face, so find the bounding box with the largest probability

i = np.argmax(detections[0, 0, :, 2])

confidence = detections[0, 0, i, 2]

为了执行人脸检测,我们需要从图像中创建一个 blob。

该 blob 具有 300×300 像素的分辨率,为了适应我们的 Caffe 人脸检测器,随后将需要调整边界框尺寸,获取相应的框架尺寸。

该脚本对深度学习的人脸检测器执行前向传播操作。该脚本假设每帧视频仅包含一张脸,这有助于减少误报的发生。对于处理包含多个面孔的视频,建议对算法进行相应的优化。因此,该脚本选择具有最高置信度的人脸检测结果。使用索引提取检测的置信度。

让我们过滤弱检测并将人脸 ROI 写入磁盘:

ensure that the detection with the largest probability also

means our minimum probability test (thus helping filter out

weak detections)

if confidence > args[“confidence”]:

compute the (x, y)-coordinates of the bounding box for

the face and extract the face ROI

box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])

(startX, startY, endX, endY) = box.astype(“int”)

face = img[startY:endY, startX:endX]

write the frame to disk

p = os.path.sep.join([args[“output”],

“{}.png”.format(saved)])

cv2.imwrite(p, face)

saved += 1

print(“[INFO] saved {} to disk”.format§)

cv2.destroyAllWindows()

为了减少误报,确保我们的脸...达到最小阈值;在该处,我们获取人脸 ROI 边界框坐标和人脸 ROI 本身;通过该方式,我们创建路径 + 文件名,并将其存储在磁盘上;此时可以增加存储的人脸数量;处理完毕后,我们完成清理。

构建我们的活体检测图像数据集

=========================================================================

image-20211124160643388

现在我们已经实现了 gather_examples.py 脚本,让我们开始工作。

打开一个终端并执行以下命令为我们的“假/欺骗”类提取人脸:

python script.py --input fakes --output dataset/fake --detector face_recog

同样,我们也可以对“真实”类做同样的事情:

python script.py --input_dir real --output_dir dataset/real --face_detector

因为实际视频文件比模拟视频文件长,所以我们将采用更高的帧率以平衡每个类别的人脸 ROI 数量。执行脚本后,您应获得以下图像计数:

Fake: 55images

Real: 84images

Total: 139images

实施“LivenessNet”,我们的深度学习活性检测器

=======================================================================================

下一步是实施“LivenessNet”,这是我们基于深度学习的活体检测器。

在本质上,LivenessNet采用了极其简单的架构设计。这一设计主要归因于两个关键因素:其一,保持这个网络的浅层架构和最少参数数量,可以有效减少在我们的小数据集上过度拟合的机会;其二,通过减少参数数量,可以确保我们的活体检测器能够快速运行,即使在资源受限的设备上,例如Raspberry Pi也能正常工作。

现在让我们实现 LivenessNet——打开 livenessnet.py 并插入以下代码:

import the necessary packages

from tensorflow.keras.models import Sequential

from tensorflow.keras.layers import BatchNormalization

from tensorflow.keras.layers import Conv2D

from tensorflow.keras.layers import MaxPooling2D

from tensorflow.keras.layers import Activation

from tensorflow.keras.layers import Flatten

from tensorflow.keras.layers import Dropout

from tensorflow.keras.layers import Dense

from tensorflow.keras import backend as K

class LivenessNet:

@staticmethod

def build(width, height, depth, classes):

initialize the model along with the input shape to be

“channels last” and the channels dimension itself

model = Sequential()

inputShape = (height, width, depth)

chanDim = -1

if we are using “channels first”, update the input shape

and channels dimension

if K.image_data_format() == “channels_first”:

inputShape = (depth, height, width)

chanDim = 1

导入必要的库包。 为了全面掌握这些层和功能,建议深入学习使用 Python 实现计算机视觉深度学习。

实现LivenessNet类。该类包含一个静态方法build。build方法接受四个参数:

width :图像/体积的宽度。

height :图像有多高。

depth :图像的通道数(在本例中为 3,因为我们将使用 RGB 图像)。

classes:类别的数量。 我们总共有两个类:“real”和“fake”。

为模型进行初始化设置,首先需要指定输入通道的形状。在此过程中,需要特别注意通道的排序方式。接下来,我们将逐步添加各层结构,构建完整的CNN网络框架。

first CONV => RELU => CONV => RELU => POOL layer set

model.add(Conv2D(16, (3, 3), padding=“same”,

input_shape=inputShape))

model.add(Activation(“relu”))

model.add(BatchNormalization(axis=chanDim))

model.add(Conv2D(16, (3, 3), padding=“same”))

model.add(Activation(“relu”))

model.add(BatchNormalization(axis=chanDim))

model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Dropout(0.25))

second CONV => RELU => CONV => RELU => POOL layer set

model.add(Conv2D(32, (3, 3), padding=“same”))

model.add(Activation(“relu”))

model.add(BatchNormalization(axis=chanDim))

model.add(Conv2D(32, (3, 3), padding=“same”))

model.add(Activation(“relu”))

model.add(BatchNormalization(axis=chanDim))

model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Dropout(0.25))

CNN架构类似于VGG。 它简短,仅包含预定义的滤波器。 理论上,我们无需深度学习架构来区分真脸和假脸。

第一个卷积层,经过RELU激活,再连接另一个卷积层和RELU激活,最后进行池化。第二个卷积层,经过RELU激活,再连接另一个卷积层和RELU激活,最后进行池化。最后,我们将添加一个全连接层,经过RELU激活。

first (and only) set of FC => RELU layers

model.add(Flatten())

model.add(Dense(64))

model.add(Activation(“relu”))

model.add(BatchNormalization())

model.add(Dropout(0.5))

softmax classifier

model.add(Dense(classes))

model.add(Activation(“softmax”))

return the constructed network architecture

return model

全连接层和 ReLU 激活层组成,带有 softmax 分类器头。

模型返回。

创建活体检测器训练脚本

======================================================================

img

基于我们收集的真实/欺骗图像数据集以及 LivenessNet 的实现,我们现在准备开始训练网络。

set the matplotlib backend so figures can be saved in the background

import matplotlib

matplotlib.use(“Agg”)

import the necessary packages

from pyimagesearch.livenessnet import LivenessNet

from sklearn.preprocessing import LabelEncoder

from sklearn.model_selection import train_test_split

from sklearn.metrics import classification_report

from tensorflow.keras.preprocessing.image import ImageDataGenerator

from tensorflow.keras.optimizers import Adam

from tensorflow.keras.utils import to_categorical

from imutils import paths

import matplotlib.pyplot as plt

import numpy as np

import argparse

import pickle

import cv2

import os

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(“-m”, “–model”, type=str, required=True,

help=“path to trained model”)

ap.add_argument(“-l”, “–le”, type=str, required=True,

help=“path to label encoder”)

ap.add_argument(“-p”, “–plot”, type=str, default=“plot.png”,

help=“path to output loss/accuracy plot”)

args = vars(ap.parse_args())

我们的面部活力训练脚本由许多导入(第 2-19 行)组成。现在让我们回顾一下:

matplotlib 用于生成训练图表。通过指定‘Agg’后端,我们能够方便地将绘图保存至磁盘的第3行。

LivenessNet :我们在上一节中定义的 liveness CNN。

train_test_split 由 scikit-learn 开发,负责构建数据分割,用于训练和测试。分类报告同样源自 scikit-learn,提供模型性能的简要统计报告。

ImageDataGenerator 用于执行数据增强操作,生成多样的图像样本,为模型训练提供多样化的图像数据。

Adam:为这个模型提供最佳优化选择。此外,替代方法还包括SGD、RMSprop等。路径设置:从我的imutils包中,该模块将帮助我们高效地收集磁盘上所有图像文件的路径。

pyplot :用于生成一个很好的训练图。

numpy :Python 的数值处理库。这也是 OpenCV 的要求。

argparse :用于处理命令行参数。

pickle :用于将我们的标签编码器序列化到磁盘。

cv2 :我们的 OpenCV 绑定。

os :这个模块可以做很多事情,但我们只是将它用作操作系统路径分隔符。

查看脚本的其余部分应该更简单。 此脚本接受四个命令行参数:

–dataset表示输入数据集的路径。在文章的前面部分,我们利用gather_examples.py脚本生成了数据集。

–model :我们的脚本将生成一个输出模型文件——在这里你提供它的路径。

–le :还需要提供输出序列化标签编码器文件的路径。

该脚本将生成一个绘图文件。 如果你希望覆盖默认的 plot.png 文件,建议在命令行参数中指定该文件名。

下一个代码块将执行一些初始化并构建我们的数据:

initialize the initial learning rate, batch size, and number of

epochs to train for

INIT_LR = 1e-4

BS = 8

EPOCHS = 50

grab the list of images in our dataset directory, then initialize

the list of data (i.e., images) and class images

print(“[INFO] loading images…”)

imagePaths = list(paths.list_images(args[“dataset”]))

data = []

labels = []

loop over all image paths

for imagePath in imagePaths:

extract the class label from the filename, load the image and

resize it to be a fixed 32x32 pixels, ignoring aspect ratio

label = imagePath.split(os.path.sep)[-2]

image = cv2.imread(imagePath)

image = cv2.resize(image, (32, 32))

update the data and labels lists, respectively

data.append(image)

labels.append(label)

convert the data into a NumPy array, then preprocess it by scaling

all pixel intensities to the range [0, 1]

data = np.array(data, dtype=“float”) / 255.0

设置训练参数,包括初始学习率、批量大小和EPOCHS。

在该位置,我们的imagePaths被获取。我们还创建了两个列表,用于存储我们的数据和类标签。通过循环构建数据和标签列表,数据由我们加载并调整为32×32像素的图像构成,每个图像都有一个对应的标签存储在标签列表中。

对像素强度进行归一化处理,并将列表转换为 NumPy 数组。接下来,我们对标签进行编码,并对数据进行分区。

encode the labels (which are currently strings) as integers and then

one-hot encode them

le = LabelEncoder()

labels = le.fit_transform(labels)

labels = to_categorical(labels, 2)

partition the data into training and testing splits using 75% of

the data for training and the remaining 25% for testing

(trainX, testX, trainY, testY) = train_test_split(data, labels,

test_size=0.25, random_state=42)

单热编码标签方案。首先,我们使用 scikit-learn 来划分数据集,其中 75% 用于训练,25% 保留作为测试集。随后,我们将初始化数据增强器并进行训练,以构建面部活力模型。

construct the training image generator for data augmentation

aug = ImageDataGenerator(rotation_range=20, zoom_range=0.15,

width_shift_range=0.2, height_shift_range=0.2, shear_range=0.15,

horizontal_flip=True, fill_mode=“nearest”)

initialize the optimizer and model

print(“[INFO] compiling model…”)

opt = Adam(lr=INIT_LR, decay=INIT_LR / EPOCHS)

model = LivenessNet.build(width=32, height=32, depth=3,

classes=len(le.classes_))

model.compile(loss=“binary_crossentropy”, optimizer=opt,

metrics=[“accuracy”])

train the network

print(“[INFO] training network for {} epochs…”.format(EPOCHS))

H = model.fit(x=aug.flow(trainX, trainY, batch_size=BS),

validation_data=(testX, testY), steps_per_epoch=len(trainX) // BS,

epochs=EPOCHS)

创建数据增强模块,该模块能够支持随机旋转、缩放、平移、剪切以及翻转等图像处理操作。

搭建并优化LivenessNet模型。随后,我们投入了大量资源进行训练。鉴于我们采用的浅层网络架构和有限的数据量,整个训练过程所需的时间将较短。训练完成后,我们即可评估模型性能并生成训练曲线图。

evaluate the network

print(“[INFO] evaluating network…”)

predictions = model.predict(x=testX, batch_size=BS)

print(classification_report(testY.argmax(axis=1),

predictions.argmax(axis=1), target_names=le.classes_))

save the network to disk

print(“[INFO] serializing network to ‘{}’…”.format(args[“model”]))

model.save(args[“model”], save_format=“h5”)

save the label encoder to disk

f = open(args[“le”], “wb”)

f.write(pickle.dumps(le))

f.close()

plot the training loss and accuracy

plt.style.use(“ggplot”)

plt.figure()

plt.plot(np.arange(0, EPOCHS), H.history[“loss”], label=“train_loss”)

plt.plot(np.arange(0, EPOCHS), H.history[“val_loss”], label=“val_loss”)

plt.plot(np.arange(0, EPOCHS), H.history[“accuracy”], label=“train_acc”)

plt.plot(np.arange(0, EPOCHS), H.history[“val_accuracy”], label=“val_acc”)

plt.title(“Training Loss and Accuracy on Dataset”)

plt.xlabel(“Epoch #”)

plt.ylabel(“Loss/Accuracy”)

plt.legend(loc=“lower left”)

plt.savefig(args[“plot”])

基于测试集进行预测。随后生成一个分类报告并输出至终端。将 LivenessNet 模型与其标签编码器一并序列化至磁盘。

生成训练历史图以供以后检查。

训练LivenessNet

========================================================================

python train.py --dataset dataset --model liveness.model --le le.pickle

image-20211124130403714

使用 OpenCV 进行活体检测

===========================================================================

最后一步是组合所有部分:

我们将访问我们的网络摄像头/视频流

对每一帧应用人脸检测

对于检测到的每个人脸,应用我们的活体检测器模型

打开 liveness_demo.py 并插入以下代码:

import the necessary packages

from imutils.video import VideoStream

from tensorflow.keras.preprocessing.image import img_to_array

from tensorflow.keras.models import load_model

import numpy as np

import argparse

import imutils

import pickle

import time

import cv2

import os

construct the argument parser and parse the arguments

ap = argparse.ArgumentParser()

ap.add_argument(“-m”, “–model”, type=str, required=True,

help=“path to trained model”)

ap.add_argument(“-l”, “–le”, type=str, required=True,

help=“path to label encoder”)

ap.add_argument(“-d”, “–detector”, type=str, required=True,

help=“path to OpenCV’s deep learning face detector”)

ap.add_argument(“-c”, “–confidence”, type=float, default=0.5,

help=“minimum probability to filter weak detections”)

args = vars(ap.parse_args())

最后

不知道你们使用什么开发环境,我通常使用Python 3.6版本和PyCharm作为开发工具。没有软件安装,或者缺乏相关资料支持,遇到问题无人解答,都可以免费获取相应的代码资源。过几天,我计划录制一个视频教程,有需要的小伙伴也可以关注获取。

给大家准备的学习资料包括但不限于:

Python 环境、pycharm编辑器/永久激活/翻译插件

python 零基础视频教程

Python 界面开发实战教程

Python 爬虫实战教程

Python 数据分析实战教程

python 游戏开发实战教程

Python 电子书100本

Python 学习路线规划

网上充斥着大量学习资料,但如果所学的知识体系不够完善,遇到问题时满足于浅尝辄止,缺乏深入研究的意愿,那么难以实现真正的技术突破。

有需要的系统化学习资料学习者,点击链接即可获取。

一个人可以单兵作战效率高,但团队协作更卓越!无论你是...还是...,我们都热忱欢迎你加入我们的技术交流圈子(技术交流、学习资源、大厂内推、职场吐槽、面试辅导),让我们一起学习成长!

全部评论 (0)

还没有任何评论哟~