你在互联网上找到的大多数人脸识别算法和研究论文都会遭受照片***。这些方法在检测和识别来自网络摄像头的图像、视频和视频流中的人脸方面是很是有效,可是他们没法区分现实生活中的面孔和照片上的面孔。这种没法区别现实人脸的现象是因为这些算法是在二维帧上工做的。
如今让咱们去试想一下,咱们实现一我的脸识别系统,该系统能够很好地区分已知面孔和未知面孔,以便只有受权人员才能访问,尽管如此,一个心怀不轨的人只要出示受权人的照片也能访问。至此一个3D人脸的识别系统,相似于苹果的FaceID,应运而生了,但若是咱们没有3D探测器该怎么办呢?
本文的目标是实现一种基于眨眼检测的人脸活体检测算法,以抵抗照片***。该算法经过网络摄像头实时工做,经过检测眨眼来区分现实生活中的面孔和照片上的面孔。通俗地说,程序运行以下:html
def process_and_encode(images):
known_encodings = []
known_names = []
print("[LOG] Encoding dataset ...")python
for image_path in tqdm(images): # 加载图片 image = cv2.imread(image_path) # 将其从BGR转换为RGB image = 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}
如今咱们知道了每一个想识别的人的编码,咱们能够尝试经过网络摄像头识别人脸,然而,在转到这一部分以前,咱们须要区分一张人脸照片和一张活人的脸。 **2.人脸活体检测** 咱们的目标是在某个点上检测出一个睁闭的睁眼模式。我训练了一个卷积神经网络来分类眼睛是闭着的仍是睁着的,所选择的模型是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 ImageDataGeneratorgit
IMG_SIZE = 24
def train(train_generator, val_generator):
STEP_SIZE_TRAIN=train_generator.n//train_generator.batch_size
STEP_SIZE_VALID=val_generator.n//val_generator.batch_sizegithub
model = 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 True
return False数据库
**3.活体的人脸识别** 咱们几乎拥有了创建“真实”人脸识别算法的全部要素,咱们只须要一种实时检测人脸和眼睛的方法。我使用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 + 15 cv2.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