2024年Python最全人脸检测实战进阶:使用 OpenCV 进行活体检测
为了总结上述内容,请您按照以下规则提取核心信息:
提取关键操作:从视频文件中提取面部信息并使用深度学习模型进行活体检测。
确保总结涵盖所有主要部分:包括代码实现、技术细节(如OpenCV、Keras/TensorFlow)、数据增强、模型构建与训练等。
使用简洁的语言确保覆盖要点。
以下是最终总结:我们通过以下步骤从视频文件中提取面部信息并进行活体检测:
加载面部检测器:
- 使用OpenCV加载预训练的人脸检测器(如dlib)。
- 对于每个视频帧:
- 转换为灰度图像。
- 使用dlib检测脸部区域。
- 提取并保存 ROI 到磁盘。
构建和训练 LivenessNet 模型:- 定义一个浅层卷积神经网络(CNN)结构。
- 数据增强技术:旋转、缩放、剪切等以增加数据多样性。
- 编译和训练网络:使用 Adam 优化器和二元交叉熵损失函数。
- 评估结果并生成分类报告。
应用 LivenessNet 进行活体检测:- 初始化摄像头或视频流。
- 对每张人脸应用 LivenessNet 模型判断其真实性。
- 输出结果并生成预测分类报告。
整个过程由 liveness_demo.py 脚本实现,结合 OpenCV 和 Keras/TensorFlow 模块完成从视频到真实/虚假的脸部识别任务。
此总结涵盖了所有关键步骤和技术细节,适用于理解从视频中提取面部信息并进行活体检测的整体流程。
–input :我们输入视频文件的路径。
–output :将存储每个裁剪面的输出目录的路径。
请定义 –detector 为面部检测器的路径位置。本段代码将采用 OpenCV 深度学习技术中的 facial detector 算法实现人脸探测。建议您直接访问我们的在线课程资源页面进行下载操作。
–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§)
cv2.destroyAllWindows()
确保我们的脸部检测ROI达到最低阈值以减少误报。
从该处提取脸部ROI的边界框坐标及脸部ROI本身。
为每个脸部ROI生成对应的存储路径及其文件名,并将其保存于硬盘上。
此时,在存储系统中可以存储更多的人脸数据。
处理完毕后进行清理工作。
为了保证我们的脸部检测ROI达到最低阈值以减少误报,
从该处提取脸部ROI的边界框坐标及脸部ROI本身。
为每个脸部ROI生成对应的存储路径及其文件名,
并将其保存于硬盘上。
此时,在存储系统中可以存储更多的人脸数据。
处理完毕后进行清理工作。
=========================================================================

现在我们已经实现了 gather_examples.py 脚本,让我们开始工作。
打开一个终端并执行以下命令为我们的“假/欺骗”类提取人脸:
请执行Python程序`gather_images.py$并输入参数fake作为输入文件名,并设置输出目录为dataset/fake以及检测器名称为face_detector
同样,我们也可以对“真实”类做同样的事情:
执行以下命令:python gather_images.py --接收输入 real --输出到 dataset/real --使用 face_detector 检测器
考虑到实际应用中,“真实”的视频文件相较于"假"的视频文件通常会较长。为了确保各类别的人脸 ROI 数量均衡分布, 我们采用了较大的跳帧值进行处理。运行该脚本后, 预期可以获得以下图像统计结果:
Fake: 55images
Real: 84images
Total: 139images
=======================================================================================
下一步是实施“LivenessNet”,这是我们基于深度学习的活体检测器。
LivenessNet 的主体仅是一个基础型卷积神经网络结构。基于两个主要原因,我们特意选择了浅层结构,并采用了简化的参数设置方案:一方面是为了降低模型在有限数据集上过拟合的风险;另一方面则旨在确保系统能够在资源有限的情况下仍能高效运行。通过优化设计,我们成功实现了活体检测器功能与运算效率的最佳平衡。无论是在普通的微控制器还是高端嵌入式系统中都能稳定运行。
现在让我们实现 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 的静态成员方法。该成员方法接受四个参数:
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结构较为浅层化。该架构仅包含有限数量的训练过的滤波器。在理想条件下,我们无需采用深度网络来辨别真脸与假面图像。
第一部分是一个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 分类器头。
模型返回。
======================================================================

基于我们拥有的真实/欺骗图像数据集以及 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
import_from tensorflow.keras.preprocessing.image 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’后端,并因此能够方便地将我们的绘图存储在第三行硬盘上。
LivenessNet :我们在上一节中定义的 liveness CNN。
splitting strategy in machine learning**: A function from the scikit-learn library that partitions our dataset into training and testing subsets. Performance metrics: The classification report module provides a concise overview of our model's performance metrics link.
ImageDataGenerator 实现数据增强功能,并能够生成多样化的训练样本集作为模型训练的数据来源
Adam 是该模型的最佳选择。(替代方法包括 SGD 和 RMSprop 等)路径:从我的 imutils 包中获取图像文件路径入口点。
pyplot :用于生成一个很好的训练图。
numpy :Python 的数值处理库。这也是 OpenCV 的要求。
argparse :用于处理命令行参数。
pickle :用于将我们的标签编码器序列化到磁盘。
cv2 :我们的 OpenCV 绑定。
os :这个模块可以做很多事情,但我们只是将它用作操作系统路径分隔符。
查看脚本的其余部分应该更简单。 此脚本接受四个命令行参数:
data_set: 输入数据集路径。 在文章之前的部分中, 我们利用gather_examples.py脚本生成并完成了该data_set.
–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)
该系统采用 one-hot 标签编码方案。 我们将使用 scikit-learn 来将数据划分为两部分:其中约四分之三用于模型的训练过程(training),剩余四分之一则作为独立的数据源供后续评估使用。 在完成了上述划分后,接下来我们将创建实例来实现数据增强功能并完成模型的编译与训练流程。
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)
创建数据增强器对象用于生成一系列经过不同变换后的图像样本。这些变换包括随机角度旋转(θ)、尺度变化(s)以及平移变换(\Delta x, \Delta y)等操作。
搭建并训练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”])
基于测试集执行预测任务。通过生成分类报告并输出至终端来实现数据反馈。该模型与标签编码器协同工作以完成序列化任务至磁盘存储。
生成训练历史图以供以后检查。
========================================================================
python train.py --dataset dataset --model liveness.model --le le.pickle

===========================================================================
最后一步是组合所有部分:
我们将访问我们的网络摄像头/视频流
对每一帧应用人脸检测
对于检测到的每个人脸,应用我们的活体检测器模型
打开 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 的便利功能。
在软件开发领域深耕已有数十年,在这一过程中系统地学习了多种编程语言。我发现掌握优质学习资源对学习新语言至关重要,在过去几年中我已经收集了不少Python相关的干货内容。然而就个人而言这些资料现在已经不再具备实用价值;但对于希望深入学习Python的技术人员而言无价之宝始终存在其独特的意义。这些资料或许能为他们提供便利极大地方便了日常开发工作
不要在网路上胡乱学习。
我也进行了相关资源的更新工作。
如果你是我的粉丝群体中的成员,在这一期的内容中你将有机会获得相应的福利。
我先来介绍一下这些东西怎么用,文末抱走。
(1)Python所有方向的学习路线(新版)
我投入了几个白天的工作时间来系统地分类和总结Python各个技术领域的知识点。这套整理工作的一个显著优势在于帮助你快速找到所需的学习资料。通过这样的归纳学习方式,你可以对各个技术领域有比较系统的掌握。
最近我才对这些路线做了一下新的更新,知识体系更全面了。

(2)Python学习视频
该平台提供了丰富的学习资源包,涵盖Python入门、爬虫技术、数据分析方法以及基础web开发课程等内容。经过统计发现,该套课程共计超过100个视频资源。尽管其覆盖范围不完全系统化,在知识深度上可能无法满足所有需求者的要求,在实际应用中也未必能提供最专业化的指导方案。但就入门阶段的学习效果而言,则是足够应付日常工作中所需的各种技能运用需求了。学完这些核心课程之后,在深入研究的基础上还可以选择一些更具专业性的学习平台继续拓展自己的知识储备

(3)100多个练手项目
在观看视频进行学习的过程中,在理解相关知识后加以应用是非常重要的。这个时候开展实践练习就非常合适。由于这类项目的种类繁多且整体水平参差不齐,在选择时大家最好挑选适合自己能力范围的项目来练习。

(4)200多本电子书
这些年我也珍藏了大量的电子书籍,在实在携带实体书籍不太方便时,我常会打开电子书籍浏览;然而这并不意味着视频教程就无懈可击,在特别对于权威的技术书籍而言。
大多数主流的技术与经典方案均已完成收集工作。为了避免版权方面的纠纷,此处不再展示相关图片。经本人核查无误。
(5)Python知识点汇总
在结构上,知识点汇总与学习路线具有相似之处,在内容深度上具有显著优势。其主要区别在于,在知识系统性方面更具系统性与全面性。具体而言,在知识呈现方式上更加多样化与层次化。就知识载体而言,则以文字形式为主,并辅以图表辅助理解。总体来说,在知识组织形式上更具条理性与逻辑性。这种差异使得两种知识呈现方式各有侧重:一方面强调系统全面的知识覆盖;另一方面则注重突出重点与核心内容的提炼。

(6)其他资料
除此之外还有一些实用资源比如我自己制作了一款Python入门图文类教程特别适合刚开始接触编程的学习者即使没有电脑设备也能通过手机进行学习在掌握了基础理论知识后就可以利用空闲时间动手实践通过敲代码来加深对知识点的理解同时这份资源还包含了大量的知识点讲解视频以及配套的学习测试题帮助大家更好地消化所学内容除此之外还可以下载Python中文版的各种库资料以及MySQL和HTML标签的大全等这些都是非常实用的学习工具

这些都不是什么稀有的物品或重要资源,但对于缺乏必要学习条件或难以有效提升学习效果的人来说却很有价值.如果你需要这些资源的话就可以直接拿走.只要关注过我的人就能轻松获取这些资源.
网上资源浩如烟海,在遇到问题时往往停留在表面层次的学习状态;如果所学知识缺乏系统性,则难以实现实质性的技术进步。
如需获取这份系统化学习资料的朋友,请您点击此链接免费获取
单兵作战效率高;团队合作才能走得更远!无论你是IT行业的资深从业者还是新手,都欢迎加入我们的圈子(技术交流.学习资源.职场吐槽.大厂内推.面试辅导),让我们一起成长!
