你在互聯網上找到的大多數人臉識別算法和研究論文都會遭受照片***。這些方法在檢測和識別來自網絡攝像頭的圖像、視頻和視頻流中的人臉方面是很是有效,可是他們沒法區分現實生活中的面孔和照片上的面孔。這種沒法區別現實人臉的現象是因爲這些算法是在二維幀上工做的。
如今讓咱們去試想一下,咱們實現一我的臉識別系統,該系統能夠很好地區分已知面孔和未知面孔,以便只有受權人員才能訪問,儘管如此,一個心懷不軌的人只要出示受權人的照片也能訪問。至此一個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