基于Python、Keras和OpenCV的实时人脸活体检测
作者|Jordan Van Eetveldt 编译|Flin 来源|towardsdatascience
你在互联网上找到的大多数人脸识别算法和研究论文都遭受照片攻击。这些方法在检测和识别来自网络摄像头的图像、视频和视频流中的人脸方面非常有效。然而,他们无法区分现实生活中的面孔和照片上的面孔。这种无法识别人脸的现象是由于这些算法在二维帧上工作。
现在让我们想象一下我们想要实现一个人脸识别开门器。该系统可以很好地区分已知面孔和未知面孔,以便只有授权人员才能访问。尽管如此,一个心怀不轨的人只要出示授权人的照片。这个3D探测器,类似于苹果的FaceID,应运而生了。但如果我们没有3D探测器呢?
本文的目标是实现一种基于眨眼检测的人脸活体检测算法,以抵抗照片攻击。该算法通过网络摄像头实时工作,只有当人的名字闪烁时才会显示出来。通俗地说,程序运行如下:
- 在网络摄像头生成的每个帧中检测人脸。
- 对于每个检测到的脸,检测眼睛。
- 对于每个检测到的眼睛,检测眼睛是否睁开或关闭。
- 如果在某个时候检测到眼睛是睁开的,然后是闭着的,然后是睁开的,我们就断定此人已经眨了眼睛,并且程序显示了他的名字(如果是人脸识别开门器,我们将授权此人进入)。
对于人脸的检测和识别,你需要安装face_recognition库,它提供了非常有用的深度学习方法来查找和识别图像中的人脸。特别是,face_locations、face_encodings和compare_faces函数是最有用的3个函数。人脸定位方法可以用两种方法来检测人脸:方向梯度直方图(HoG)和卷积神经网络(CNN)。由于时间限制,选择了HoG方法。
face_encodings函数是一个预先训练的卷积神经网络,能够将图像编码成128个特征向量。这个嵌入向量应该表示足够的信息来区分两个不同的人。最后,compare_faces计算两个嵌入向量之间的距离。它将允许算法识别从摄像头帧中提取的人脸,并将其嵌入向量与我们数据集中所有编码的人脸进行比较。最近的向量应该对应于同一个人。
1. 已知人脸数据集编码
在我的例子中,算法能够识别我和奥巴马。我为每个人挑选了大约10张照片。下面是处理和编码已知人脸数据库的代码。
def process_and_encode(images):known_encodings = []known_names = []print("[LOG] Encoding dataset ...")for image_path in tqdm(images):# 加载图片image = cv2.imread(image_path)# 将其从BGR转换为RGBimage = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)# 检测图像中的脸并获取其位置(方框坐标)boxes = face_recognition.face_locations(image, model='hog')# 将人脸编码为128维嵌入向量encoding = face_recognition.face_encodings(image, boxes)# 人物名称是图像来源文件夹的名称name = image_path.split(os.path.sep)[-2]if len(encoding) > 0 : known_encodings.append(encoding[0])known_names.append(name)return {"encodings": known_encodings, "names": known_names}
现在我们知道了每个想识别的人的编码,我们可以尝试通过网络摄像头识别人脸。然而,在转到这一部分之前,我们需要区分一张人脸照片和一张活人的脸。
- 人脸活体检测
作为提醒,我们的目标是在某个点上检测出一个睁闭的睁眼模式。我训练了一个卷积神经网络来分类眼睛是闭着的还是睁着的。所选择的模型是LeNet-5,它已经在Closed Eyes In The Wild (CEW)数据集上进行了训练。它由大约4800张24x24大小的眼睛图像组成。
Closed Eyes In The Wild (CEW)数据集地址:
- http://parnec.nuaa.edu.cn/xtan/data/ClosedEyeDatabases.html
from keras.models import Sequential
from keras.layers import Conv2D
from keras.layers import AveragePooling2D
from keras.layers import Flatten
from keras.layers import Dense
from keras.preprocessing.image import ImageDataGeneratorIMG_SIZE = 24
def train(train_generator, val_generator):STEP_SIZE_TRAIN=train_generator.n//train_generator.batch_sizeSTEP_SIZE_VALID=val_generator.n//val_generator.batch_sizemodel = Sequential()model.add(Conv2D(filters=6, kernel_size=(3, 3), activation='relu', input_shape=(IMG_SIZE,IMG_SIZE,1)))model.add(AveragePooling2D())model.add(Conv2D(filters=16, kernel_size=(3, 3), activation='relu'))model.add(AveragePooling2D())model.add(Flatten())model.add(Dense(units=120, activation='relu'))model.add(Dense(units=84, activation='relu'))model.add(Dense(units=1, activation = 'sigmoid'))model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])print('[LOG] Training CNN')model.fit_generator(generator=train_generator,steps_per_epoch=STEP_SIZE_TRAIN,validation_data=val_generator,validation_steps=STEP_SIZE_VALID,epochs=20)return model
在评估模型时,我达到了94%的准确率。
每次我们检测到一只眼睛,我们就用我们的模型来预测它的状态,并跟踪每个人的眼睛状态。因此,检测眨眼变得非常容易,它试图在眼睛状态历史中找到一个闭眼-睁眼-闭眼模式。
def isBlinking(history, maxFrames):""" @history: A string containing the history of eyes status where a '1' means that the eyes were closed and '0' open.@maxFrames: The maximal number of successive frames where an eye is closed """for i in range(maxFrames):pattern = '1' + '0'*(i+1) + '1'if pattern in history:return Truereturn False
- 活体的人脸识别
我们几乎拥有建立“真实”人脸识别算法的所有要素。我们只需要一种实时检测人脸和眼睛的方法。我使用openCV预先训练的Haar级联分类器来完成这些任务。有关Haar cascade人脸和眼睛检测的更多信息,我强烈建议你阅读openCV的这篇强大的文章。
- https://docs.opencv.org/3.4.3/d7/d8b/tutorial_py_face_detection.html
def detect_and_display(model, video_capture, face_detector, open_eyes_detector, left_eye_detector, right_eye_detector, data, eyes_detected):frame = video_capture.read()# 调整框架大小frame = cv2.resize(frame, (0, 0), fx=0.6, fy=0.6)gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)# 检测人脸faces = face_detector.detectMultiScale(gray,scaleFactor=1.2,minNeighbors=5,minSize=(50, 50),flags=cv2.CASCADE_SCALE_IMAGE)# 对于每个检测到的脸for (x,y,w,h) in faces:# 将人脸编码为128维嵌入向量encoding = face_recognition.face_encodings(rgb, [(y, x+w, y+h, x)])[0]# 将向量与所有已知的人脸编码进行比较matches = face_recognition.compare_faces(data["encodings"], encoding)# 目前我们不知道该人的名字name = "Unknown"# 如果至少有一次匹配:if True in matches:matchedIdxs = [i for (i, b) in enumerate(matches) if b]counts = {}for i in matchedIdxs:name = data["names"][i]counts[name] = counts.get(name, 0) + 1# 匹配次数最多的已知编码对应于检测到的人脸名称name = max(counts, key=counts.get)face = frame[y:y+h,x:x+w]gray_face = gray[y:y+h,x:x+w]eyes = []# 眼睛检测# 首先检查眼睛是否睁开(考虑到眼镜)open_eyes_glasses = open_eyes_detector.detectMultiScale(gray_face,scaleFactor=1.1,minNeighbors=5,minSize=(30, 30),flags = cv2.CASCADE_SCALE_IMAGE)# 如果open_eyes_glasses检测到眼睛,则眼睛睁开 if len(open_eyes_glasses) == 2:eyes_detected[name]+='1'for (ex,ey,ew,eh) in open_eyes_glasses:cv2.rectangle(face,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)# 否则尝试使用left和right_eye_detector检测眼睛# 以检测到睁开和闭合的眼睛 else:# 将脸分成左右两边left_face = frame[y:y+h, x+int(w/2):x+w]left_face_gray = gray[y:y+h, x+int(w/2):x+w]right_face = frame[y:y+h, x:x+int(w/2)]right_face_gray = gray[y:y+h, x:x+int(w/2)]# 检测左眼left_eye = left_eye_detector.detectMultiScale(left_face_gray,scaleFactor=1.1,minNeighbors=5,minSize=(30, 30),flags = cv2.CASCADE_SCALE_IMAGE)# 检测右眼right_eye = right_eye_detector.detectMultiScale(right_face_gray,scaleFactor=1.1,minNeighbors=5,minSize=(30, 30),flags = cv2.CASCADE_SCALE_IMAGE)eye_status = '1' # we suppose the eyes are open# 检查每只眼睛是否闭合。# 如果有人闭着眼睛,我们得出结论是闭着眼睛for (ex,ey,ew,eh) in right_eye:color = (0,255,0)pred = predict(right_face[ey:ey+eh,ex:ex+ew],model)if pred == 'closed':eye_status='0'color = (0,0,255)cv2.rectangle(right_face,(ex,ey),(ex+ew,ey+eh),color,2)for (ex,ey,ew,eh) in left_eye:color = (0,255,0)pred = predict(left_face[ey:ey+eh,ex:ex+ew],model)if pred == 'closed':eye_status='0'color = (0,0,255)cv2.rectangle(left_face,(ex,ey),(ex+ew,ey+eh),color,2)eyes_detected[name] += eye_status# 每次,我们都会检查该人是否眨眼# 如果是,我们显示其名字if isBlinking(eyes_detected[name],3):cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)# 显示名字y = y - 15 if y - 15 > 15 else y + 15cv2.putText(frame, name, (x, y), cv2.FONT_HERSHEY_SIMPLEX,0.75, (0, 255, 0), 2)return frame
上面的功能是用于检测和识别真实人脸的代码。它接受以下参数:
model:我们的睁眼/闭眼分类器
video_capture:流视频
face_detector:Haar级联的人脸分类器。我使用了haarcascade_frontalface_alt.xml
open_eyes_detector:Haar级联睁眼分类器。我使用了haarcascade_eye_tree_eyeglasses.xml
left_eye_detector:Haar级联的左眼分类器。我使用了haarcascade_lefteye_2splits.xml,它可以检测睁眼或闭眼。
right_eye_detector:Haar级联的右眼分类器。我使用了haarcascade_righteye_2splits.xml,它可以检测睁眼或闭眼。
data:已知编码和已知名称的字典
eyes_detected:包含每个名称的眼睛状态历史记录的字典。
在第2-4行,我们从网络摄像头流中获取一个帧,然后调整其大小以加快计算速度。
在第10行,我们从帧中检测人脸,然后在第21行,我们将其编码为128-d矢量。
在第23-38行,我们将这个向量与已知的人脸编码进行比较,并通过计算匹配的次数来确定此人的姓名。选择匹配次数最多的一个。
从第45行开始,我们试着探测眼睛进入人脸框。
首先,我们尝试用睁眼检测器来检测睁眼。如果探测器探测成功,则在第54行,将“1”添加到眼睛状态历史记录中,这意味着眼睛是睁开的,因为睁开的眼睛探测器无法检测到闭着的眼睛。否则,如果第一个分类器失败(可能是因为眼睛是闭着的,或者仅仅是因为它不能识别眼睛),则使用左眼和右眼检测器。人脸被分为左右两侧,以便对各个探测器进行分类。
从第92行开始,提取眼睛部分,训练后的模型预测眼睛是否闭合。如果检测到一只眼睛闭着,则两眼都将被预测为闭着,并将“0”添加到眼睛状态历史记录中。否则就可以断定眼睛是睁开的。
最后,在第110行,is blinking()函数用于检测眨眼,如果该人眨眼,则显示姓名。整个代码都可以在我的github帐户上找到。
- 我的github帐户
- https://github.com/Guarouba/face_rec
使用眨眼检测功能阻止照片攻击的演示视频: https://youtu.be/arQN6w0fZw8
参考文献
https://docs.opencv.org/3.4.3/d7/d8b/tutorial_py_face_detection.html
https://www.pyimagesearch.com/2018/06/18/face-recognition-with-opencv-python-and-deep-learning/
原文链接:https://towardsdatascience.com/real-time-face-liveness-detection-with-python-keras-and-opencv-c35dc70dafd3
欢迎关注磐创AI博客站: http://panchuang.net/
sklearn机器学习中文官方文档: http://sklearn123.com/
欢迎关注磐创博客资源汇总站: http://docs.panchuang.net/
基于Python、Keras和OpenCV的实时人脸活体检测相关推荐
- 活体检测算法 python_基于Python、Keras和OpenCV的实时人脸活体检测
作者|Jordan Van Eetveldt 编译|Flin 来源|towardsdatascience 你在互联网上找到的大多数人脸识别算法和研究论文都遭受照片攻击.这些方法在检测和识别来自网络摄像 ...
- python 活体检测_基于Python+Keras+OpenCV实现实时人脸活体检测 | 文末送书
你在互联网上找到的大多数人脸识别算法和研究论文都会遭受照片***.这些方法在检测和识别来自网络摄像头的图像.视频和视频流中的人脸方面是很是有效,可是他们没法区分现实生活中的面孔和照片上的面孔.这种没法 ...
- 基于Python+Keras+OpenCV实现实时人脸活体检测 | 文末送书
你在互联网上找到的大多数人脸识别算法和研究论文都会遭受照片攻击.这些方法在检测和识别来自网络摄像头的图像.视频和视频流中的人脸方面是非常有效,但是他们无法区分现实生活中的面孔和照片上的面孔.这种无法区 ...
- opencv入门基础(七)基于dlib进行本地图片、实时人脸检测
opencv入门基础(七)基于dlib进行本地图片.实时人脸检测 一.背景知识 1.Dlib是一个深度学习开源工具,基于C++开发,也支持Python开发接口. 2.由于Dlib对于人脸特征提取效果很 ...
- 基于Python下的OpenCv人脸检测
基于Python下的OpenCv人脸识别模拟 1.Pycharm下OpenCv的安装 2.人脸识别的原理 目标实现 基本原理 3.代码实现: 实现步骤 参考示意图: 1.Pycharm下OpenCv的 ...
- 五分钟快速搭建一个实时人脸口罩检测系统(OpenCV+PaddleHub 含源码)
导读 本文主要介绍如何使用OpenCV和PaddleHub实现一个实时人脸口罩检测系统.(公众号:OpenCV与AI深度学习) 背景介绍 从19年疫情爆发到现在,佩戴口罩对大家来说已是常态.应运而生的 ...
- 人脸活体检测系统(Python+YOLOv5深度学习模型+清新界面)
摘要:人脸活体检测系统利用视觉方法检测人脸活体对象,区分常见虚假人脸,以便后续人脸识别,提供系统界面记录活体与虚假人脸检测结果.本文详细介绍基于YOLOv5深度学习技术的人脸活体检测系统,在介绍算法原 ...
- 基于HSV+HOG特征和SVM的人脸口罩检测算法
基于HSV+HOG特征和SVM的人脸口罩检测算法 基于python语言编写,使用retinaface检测人脸和定位五个特征点,利用特征点进一步定位口鼻区域,提取该区域的HSV特征和HOG特征,使用SV ...
- 相机视频实时人脸追踪检测
相机视频实时人脸追踪检测 import cv2 as cv import matplotlib.pyplot as plt import numpy as np from PIL import Ima ...
最新文章
- android常见错误与问题
- MIT与商汤科技成立人工智能联盟
- 山东人为什么爱用倒装句?没有吧我觉得。
- 设计模式-UML图简单介绍
- tensorflow随笔-tf.while_loop
- wind10MySQL闪退什么密码_win10系统Mysql输入密码后闪退的解决方法
- Oracle10g备份集压缩新特性(Backupset Compression)
- em模型补缺失值_基于EM算法数据单变量缺失处理方法研究
- mysql 增大数据库链接_怎么增大MYSQL数据库连接数
- linux内核计数函数,linux中的内核引用计数器
- 封装jquery插件 uoload file
- 利用反射和lambda获取变量名字
- 基于wireshark和NetAssist的单机模拟抓TCP包:三次握手、四次挥手、长连接
- 用gambit学博弈-完全信息静态博弈
- python差异性分析_差异性分析
- 校园导航小助手—课程设计
- Spark History Server 没有生效
- Word批量转TXT宏
- 视频教程-C语言项目开发系列视频课程-C/C++
- [日常] 面试知识点总结(持续更新)
热门文章
- 在iPhone App中使用自定义字体
- 移动终端应用开发上机4服务与数据存储
- 安装Windows7和Office2013
- 深渊之刃 | Greenplum数据库之拉链表的实现
- SQLServer 随机生成指定范围的日期
- Excel中计算相隔月份的日期(EDATE函数)
- 植物2 IOS 怎么实名认证_和平精英防沉迷解除方法 和平精英实名认证强制下线休息怎么解除...
- 应用架构的核心使命是什么?阿里高级技术专家如是说
- [ 数据结构 ] 迪杰斯特拉算法(最短路径问题)
- 【CSS】450- 温故而知我不懂的CSS