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

使用 OpenCV 进行活体检测

在本篇博客中,我们将探讨如何使用OpenCV进行活体检测,以增强人脸识别系统的安全性和可靠性。我们将构建一个能够检测出假人脸并防止反人脸欺骗的活体检测器。

首先,我们来了解一下什么是活体检测以及为什么我们需要它来改进人脸识别系统。

然后,我们将审查我们将用于执行活体检测的数据集。这包括构建用于活体检测的数据集,例如真实的脸部图像和假脸部图像。同时,我们还将了解项目结构,以便更好地理解后续步骤。

接下来,为了创建活体检测器,我们将训练一个能够区分真脸和假脸的深度神经网络。为此,我们需要构建图像数据集本身,实现一个能够执行活体检测器的卷积神经网络(我们将其称为“LivenessNet”),并训练该网络。

最后,我们将创建一个Python + OpenCV脚本来应用经过训练的活体检测器模型到实时视频中。

现在,让我们开始逐步构建这个活体检测器吧!

什么是活体检测,我们为什么需要它?

image-20211124160627445

在深度学习广泛应用于计算机视觉任务的今天,人脸识别已成为一项重要的应用,而活体检测作为人脸识别中的一项重要技术,也受到了广泛关注。

在人脸识别系统中,活体检测的主要目的是判断输入的人脸图像是否为真实的人脸,从而防止恶意攻击,如使用照片、面具等手段来绕过人脸识别系统。这使得人脸识别系统更加安全可靠。

为了实现活体检测,我们可以采用多种方法。其中一种常见的方法是基于卷积神经网络(CNN)的分类方法。这种方法将活体检测视为一个二元分类问题,即区分真实人脸和伪造/欺骗人脸。

在训练过程中,我们需要构建一个包含真实人脸和伪造人脸的数据库,并将这些图像输入到卷积神经网络中进行训练。通过训练,卷积神经网络可以学习到区分真实人脸和伪造人脸的特征,并能够自动地进行分类。

除了基于CNN的分类方法,还有其他一些方法可以实现活体检测。例如,通过分析面部特征的变化规律,使用傅立叶变换等方法进行频率分析;通过检测眼球运动、嘴唇运动和眨眼等生理特征来进行基于启发式的检测;通过分析光流的差异和特性来进行光流算法等。

在选择适合的活体检测模型时,我们需要考虑其准确性、实时性、鲁棒性等因素。同时,我们还需要不断地改进和优化模型,以提高其性能和适应性。

项目结构

$ tree --dirsfirst --filelimit 10
.
├── dataset
│   ├── fake [150 entries]
│   └── real [161 entries]
├── face_detector
│   ├── deploy.prototxt
│   └── res10_300x300_ssd_iter_140000.caffemodel
├── model
│   ├── __init__.py
│   └── livenessnet.py
├── fake
├── real  
├── gather_examples.py
├── train.py
├── liveness_demo.py
├── le.pickle
├── liveness.model
└── plot.png

我们的项目中有四个主要目录:

dataset/ :我们的数据集目录由两类图像组成:

  • 在播放我的脸部视频时,来自相机的假图像对准我的屏幕。
  • 用我的手机从自拍视频中捕捉到的我的真实图像。

face_detector/ :由我们预训练的 Caffe 人脸检测器组成,用于定位人脸 ROI。

model/ :这个模块包含我们的 LivenessNet 类。 视频/:我提供了两个输入视频来训练我们的 LivenessNet 分类器。

fake:存放手机拍摄的图片。

real:存放真实的图片

今天我们将详细回顾三个 Python 脚本。 到文章结束时,您将能够在自己的数据上运行它们并输入视频源。 按照在本教程中出现的顺序,这三个脚本是:

gather_examples.py :此脚本从输入视频文件中获取人脸 ROI,并帮助我们创建深度学习人脸活跃度数据集。

train.py :正如文件名所示,此脚本将训练我们的 LivenessNet 分类器。 我们将使用 Keras 和 TensorFlow 来训练模型。 训练过程产生几个文件:

le.pickle :我们的类标签编码器。

liveness.model :我们的序列化 Keras 模型,用于检测面部活力。

plot.png :训练历史图显示了准确性和损失曲线,因此我们可以评估我们的模型(即过度/欠拟合)。

liveness_demo.py :我们的演示脚本将启动您的网络摄像头以抓取帧以实时进行面部活体检测。

从我们的训练(视频)数据集中检测和提取人脸 ROI

image-20211124124931022

现在我们已经有机会回顾我们的初始数据集和项目结构,让我们看看如何从我们的输入视频中提取真实和虚假的人脸图像。 如果此脚本将填充两个目录,则最终目标是:

dataset/fake/:包含来自 fake文件夹的人脸 ROI

dataset/real/:保存 real文件夹中的面部 ROI。

鉴于这些帧,我们稍后将在图像上训练基于深度学习的活体检测器。 打开gather_images.py文件并插入以下代码:

# import the necessary packages
import numpy as np
import argparse
import cv2
import os
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--input", type=str, required=True,
	help="path to input video")
ap.add_argument("-o", "--output", type=str, required=True,
	help="path to output directory of cropped faces")
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")
ap.add_argument("-s", "--skip", type=int, default=16,
	help="# of frames to skip before applying face detection")
args = vars(ap.parse_args())

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

解析命令行参数:

  • –input :我们输入视频文件的路径。
  • –output :将存储每个裁剪面的输出目录的路径。
  • –detector :面部检测器的路径。 我们将使用 OpenCV 的深度学习人脸检测器。 为方便起见,此 Caffe 模型包含在今天的“下载”中。
  • –confidence : 过滤弱人脸检测的最小概率。 默认情况下,此值为 50%。
  • –skip :我们不需要检测和存储每个图像,因为相邻的帧是相似的。 相反,我们将在两次检测之间跳过 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 人脸检测器。 稍后将需要缩放边界框,获取框架尺寸。

执行 blob 通过深度学习人脸检测器的前向传递。 我们的脚本假设视频的每一帧中只有一张脸。 这有助于防止误报。 如果您正在处理包含多个面孔的视频,我建议您相应地调整逻辑。 因此,抓取了最高概率的人脸检测指标。使用索引提取检测的置信度。

让我们过滤弱检测并将人脸 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(p))

cv2.destroyAllWindows()

确保我们的人脸检测 ROI 满足最小阈值以减少误报。 从那里我们提取人脸 ROI 边界框坐标和人脸 ROI 本身。 我们为面部 ROI 生成路径 + 文件名,并将其写入磁盘。 此时,我们可以增加保存的人脸数量。 处理完成后,执行清理。

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

image-20211124160643388

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

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

python gather_images.py --input fake --output dataset/fake --detector face_detector

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

python gather_images.py --input real --output dataset/real --detector 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”。

初始化模型。 定义inputShape ,而通道排序。 让我们开始向我们的 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。 它非常浅,只有几个学习过的过滤器。 理想情况下,我们不需要深度网络来区分真实和欺骗的面孔。

第一个 CONV => RELU => CONV => RELU => POOL 层,其中还添加了批量归一化和 dropout。 第二个 CONV => RELU => CONV => RELU => POOL 层。 最后,我们将添加我们的 FC => 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 的实现,我们现在准备训练网络。 打开 train.py 文件并插入以下代码:

# 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 :训练脚本将生成一个绘图。 如果你想覆盖 “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 像素的图像组成。 每个图像都有一个对应的标签存储在标签列表中。

所有像素强度都缩放到 [0, 1] 范围内,同时将列表制成 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())

导入我们需要的包。 值得注意的是,我们将使用 -

  • VideoStream 以访问我们的相机提要。
  • img_to_array 以便我们的框架采用兼容的数组格式。
  • load_model 加载我们序列化的 Keras 模型。
  • imutils 的便利功能。
  • cv2 用于我们的 OpenCV 绑定。

让我们解析我们的命令行参数:

  • –model :我们用于活体检测的预训练 Keras 模型的路径。
  • –le :我们到标签编码器的路径。
  • –detector :OpenCV 的深度学习人脸检测器的路径,用于查找人脸 ROI。
  • –confidence :过滤掉弱检测的最小概率阈值。

现在让我们继续初始化人脸检测器、LivenessNet 模型 + 标签编码器和我们的视频流:

# 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)
# load the liveness detector model and label encoder from disk
print("[INFO] loading liveness detector...")
model = load_model(args["model"])
le = pickle.loads(open(args["le"], "rb").read())
# initialize the video stream and allow the camera sensor to warmup
print("[INFO] starting video stream...")
vs = VideoStream(src=0).start()
time.sleep(2.0)

OpenCV 加载人脸检测器通。

从那里我们加载我们的序列化、预训练模型 (LivenessNet) 和标签编码器。 我们的 VideoStream 对象被实例化,我们的相机被允许预热两秒钟。 在这一点上,是时候开始遍历帧来检测真人脸与假人脸/欺骗人脸了:

# loop over the frames from the video stream
while True:
	# grab the frame from the threaded video stream and resize it
	# to have a maximum width of 600 pixels
	frame = vs.read()
	frame = imutils.resize(frame, width=600)
	# grab the frame dimensions and convert it to a blob
	(h, w) = frame.shape[:2]
	blob = cv2.dnn.blobFromImage(cv2.resize(frame, (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()

打开一个无限 while 循环块,我们从捕获和调整单个帧的大小开始。

调整大小后,会抓取框架的尺寸,以便我们稍后执行缩放。 使用 OpenCV 的 blobFromImage 函数,我们生成一个 blob,然后通过将其传递到人脸检测器网络来继续执行推理。

现在我们准备好迎接有趣的部分——使用 OpenCV 和深度学习进行活体检测:

# loop over the detections
	for i in range(0, detections.shape[2]):
		# extract the confidence (i.e., probability) associated with the
		# prediction
		confidence = detections[0, 0, i, 2]
		# 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")
			# ensure the detected bounding box does fall outside the
			# dimensions of the frame
			startX = max(0, startX)
			startY = max(0, startY)
			endX = min(w, endX)
			endY = min(h, endY)
			# extract the face ROI and then preproces it in the exact
			# same manner as our training data
			face = frame[startY:endY, startX:endX]
			face = cv2.resize(face, (32, 32))
			face = face.astype("float") / 255.0
			face = img_to_array(face)
			face = np.expand_dims(face, axis=0)
			# pass the face ROI through the trained liveness detector
			# model to determine if the face is "real" or "fake"
			preds = model.predict(face)[0]
			j = np.argmax(preds)
			label = le.classes_[j]
			# draw the label and bounding box on the frame
			label = "{}: {:.4f}".format(label, preds[j])
			cv2.putText(frame, label, (startX, startY - 10),
				cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
			cv2.rectangle(frame, (startX, startY), (endX, endY),
				(0, 0, 255), 2)

遍历人脸检测。 在循环里面:

  • 过滤掉弱检测。
  • 提取人脸边界框坐标并确保它们不超出框架的尺寸。
  • 提取人脸 ROI 并以与我们的训练数据相同的方式对其进行预处理。
  • 使用我们的活体检测器模型来确定面部是“真实的”还是“假的/欺骗的”。
  • 接下来是您插入自己的代码以执行人脸识别的地方,但仅限于真实图像。 伪代码类似于 if label == “real”: run_face_reconition() )。
  • 最后(对于这个演示),我们在脸部周围绘制标签文本和一个矩形。

让我们显示我们的结果并清理:

# show the output frame and wait for a key press
	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 liveness_demo.py --model liveness.model --le le.pickle \
	--detector face_detector

image-20211124134514008

总结

您已经提供了很多有用的信息,但我还想补充一些关于活体检测的额外细节。

活体检测的目的是确定输入的人脸图像是否是由真实的人脸生成的,而不是某种形式的欺骗或伪造。这通常涉及到识别和区分各种特征,如纹理、光流、面部形状和生理活动(如眨眼和嘴唇运动)。

在构建活体检测模型时,通常需要一个标记的数据集,其中包含真实的人脸图像和欺骗(如照片或动画)的图像。这个数据集需要被划分为训练集和测试集,以便我们可以在训练集上训练模型,然后在测试集上评估模型的性能。

在选择模型时,需要考虑其准确性、实时性、鲁棒性和可扩展性。有些模型可能需要大量的计算资源,这可能使其难以在资源受限的环境中运行。另外,如果模型过于复杂,可能会导致过拟合,这意味着模型可能在新数据上表现不佳。

在训练模型后,我们通常需要将其部署到实际环境中,以在实际使用条件下评估其性能。这可能涉及到处理各种实际挑战,如光照变化、面部朝向和遮挡等。

总的来说,活体检测是一个复杂的任务,需要深入理解机器学习和计算机视觉技术。希望这个补充信息能帮助您更深入地理解这个主题。如果您还有其他问题或需要进一步的澄清,请随时提问!
完整项目详见:
https://download.csdn.net/download/hhhhhhhhhhwwwwwwwwww/48148645

  • 12
    点赞
  • 110
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
### 回答1: OpenCV(Open Source Computer Vision Library)是一款基于开放源代码的计算机视觉库,其中包括很多用于图像处理、计算机视觉和机器学习的算法和工具,并适用于多个开发平台,如Windows、Linux、Mac OS等。Python是一种简单易用、高效和强大的编程语言,由于其可读性高、代码简洁且易于维护等特点,被广泛应用于计算机视觉和机器学习等领域。 在Python语言中,OpenCV 4可以用于实现很多计算机视觉的任务,如图像处理、图像分类、特征提取、目标检测、人脸识别等。在OpenCV 4中,最新的特性包括了对深度学习模型和神经元网络的支持,能够实现更强大的图像处理和识别任务。同时,OpenCV 4还支持Python 3版本,使得开发和实现过程更简易。 对于初学者而言,实现针对计算机视觉的Python代码,可以采用OpenCV 4作为基础库。首先需要安装OpenCV 4库,并学习相关的API接口。然后,学习Python的基础语法,并尝试使用OpenCV 4库中提供的函数和类,实现不同的计算机视觉任务。最后,可以熟练掌握OpenCV 4和Python之间的交互方式,从而完成针对计算机视觉的Python代码的编写。 总之,OpenCV 4库和Python语言互为补充,可以为计算机视觉爱好者和开发人员提供简易且高效的图像处理和计算机视觉方式,开发出更智能和高效的计算机视觉系统。 ### 回答2: OpenCV是一种广泛使用的计算机视觉库,它提供了各种技术和算法,用于图像和视频处理以及人工智能相关的任务等。 Python是一种非常流行的编程语言,它具有简单易学、灵活易用、代码清晰等优点,因此被许多开发者广泛使用。 近年来,Python和OpenCV的结合被越来越多的人所青睐。在实现计算机视觉相关的应用中,使用Python和OpenCV可以快速构建、测试和部署。 对于想要学习Python和OpenCV的人们,最好的学习资源是一份清晰且易懂的PDF资料。这份PDF应该包含Python和OpenCV的基础知识介绍、实用的代码示例和实战应用,以及常见问题的解答等。 在编写这样一份PDF时,应该注重让读者理解语法和算法的基础知识,在实现时也能够有效使用各种函数和模块。同时,应该将更多的内容放在实例应用中,以便让读者自己实践。 总体而言,一份好的Python与OpenCV计算机视觉的PDF资料应该不光是简单的介绍语法,同时也要与实践联系在一起,给予读者足够的参考价值。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI浩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值