The script detect blink eye (left and right) separately. If the number of blinks does not rich a threshold (10), the name of the person will be displayed. Each blink is noted by yellow sqaure. If the eyes are open the eyes sqaures remain in red color. The script would be optimized. The demo we show that the image from my phone is recognized as liveness person (display the name of the person in green!) when the screen of the phone goes out (black screen).
## set python version and anaconda environment
import os
import cv2
from PIL import Image
import numpy as np
from skimage.transform import resize
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.models import model_from_json
from keras.preprocessing.image import ImageDataGenerator
os.environ['KMP_DUPLICATE_LIB_OK']='True'
#from scipy.ndimage import imread
#from scipy.misc import imresize, imsave
#from imageio import imread
IMG_SIZE = 24
def collect():
train_datagen = ImageDataGenerator(
rescale=1./255,
shear_range=0.2,
horizontal_flip=True,
)
val_datagen = ImageDataGenerator(
rescale=1./255,
shear_range=0.2,
horizontal_flip=True, )
train_generator = train_datagen.flow_from_directory(
directory="dataset/train",
target_size=(IMG_SIZE, IMG_SIZE),
color_mode="grayscale",
batch_size=32,
class_mode="binary",
shuffle=True,
seed=42
)
val_generator = val_datagen.flow_from_directory(
directory="dataset/val",
target_size=(IMG_SIZE, IMG_SIZE),
color_mode="grayscale",
batch_size=32,
class_mode="binary",
shuffle=True,
seed=42
)
return train_generator, val_generator
def save_model(model):
model_json = model.to_json()
with open("model.json", "w") as json_file:
json_file.write(model_json)
# serialize weights to HDF5
model.save_weights("model.h5")
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_size
print('[LOG] Intialize Neural Network')
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'])
model.fit_generator(generator=train_generator,
steps_per_epoch=STEP_SIZE_TRAIN,
validation_data=val_generator,
validation_steps=STEP_SIZE_VALID,
epochs=20
)
save_model(model)
#dataset = collect()
#train(dataset[0], dataset[1])
import os
import cv2
import face_recognition
import numpy as np
from tqdm import tqdm
from collections import defaultdict
from imutils.video import VideoStream
from eye_status import *
def init():
face_cascPath = 'haarcascade_frontalface_alt.xml'
# face_cascPath = 'lbpcascade_frontalface.xml'
open_eye_cascPath = 'haarcascade_eye_tree_eyeglasses.xml'
left_eye_cascPath = 'haarcascade_lefteye_2splits.xml'
right_eye_cascPath ='haarcascade_righteye_2splits.xml'
dataset = 'faces'
face_detector = cv2.CascadeClassifier(face_cascPath)
open_eyes_detector = cv2.CascadeClassifier(open_eye_cascPath)
left_eye_detector = cv2.CascadeClassifier(left_eye_cascPath)
right_eye_detector = cv2.CascadeClassifier(right_eye_cascPath)
print("[LOG] Opening webcam ...")
video_capture = VideoStream(src=0).start()
model = load_model()
print("[LOG] Collecting images ...")
images = []
for direc, _, files in tqdm(os.walk(dataset)):
for file in files:
if file.endswith("jpg"):
images.append(os.path.join(direc,file))
return (model,face_detector, open_eyes_detector, left_eye_detector,right_eye_detector, video_capture, images)
def process_and_encode(images):
# initialize the list of known encodings and known names
known_encodings = []
known_names = []
print("[LOG] Encoding faces ...")
for image_path in tqdm(images):
# Load image
image = cv2.imread(image_path)
# Convert it from BGR to RGB
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# detect face in the image and get its location (square boxes coordinates)
boxes = face_recognition.face_locations(image, model='hog')
# Encode the face into a 128-d embeddings vector
encoding = face_recognition.face_encodings(image, boxes)
# the person's name is the name of the folder where the image comes from
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}
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
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()
# resize the frame
frame = cv2.resize(frame, (0, 0), fx=1, fy=1)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# Detect faces
faces = face_detector.detectMultiScale(
gray,
scaleFactor=1.2,
minNeighbors=5,
minSize=(50, 50),
flags=cv2.CASCADE_SCALE_IMAGE
)
# for each detected face
for (x,y,w,h) in faces:
# Encode the face into a 128-d embeddings vector
encoding = face_recognition.face_encodings(rgb, [(y, x+w, y+h, x)])[0]
# Compare the vector with all known faces encodings
matches = face_recognition.compare_faces(data["encodings"], encoding)
# For now we don't know the person name
name = "Unknown"
# If there is at least one match:
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
# determine the recognized face with the largest number of votes
name = max(counts, key=counts.get)
face = frame[y:y+h,x:x+w]
gray_face = gray[y:y+h,x:x+w]
eyes = []
# Eyes detection
# check first if eyes are open (with glasses taking into account)
open_eyes_glasses = open_eyes_detector.detectMultiScale(
gray_face,
scaleFactor=1.1,
minNeighbors=5,
minSize=(30, 30),
flags = cv2.CASCADE_SCALE_IMAGE
)
# if open_eyes_glasses detect eyes then they are open
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,0,255),2) # blue if eye + glasses + open
# otherwise try detecting eyes using left and right_eye_detector
# which can detect open and closed eyes
else:
# separate the face into left and right sides
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)]
# Detect the left eye
left_eye = left_eye_detector.detectMultiScale(
left_face_gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(30, 30),
flags = cv2.CASCADE_SCALE_IMAGE
)
# Detect the right eye
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 each eye check wether the eye is closed.
# If one is closed we conclude the eyes are closed
for (ex,ey,ew,eh) in right_eye:
color = (0,255,0) # lime color
pred = predict(right_face[ey:ey+eh,ex:ex+ew],model)
if pred == 'closed':
eye_status='0'
color = (0,225,255) # yellow color
cv2.rectangle(right_face,(ex,ey),(ex+ew,ey+eh),color,2)
for (ex,ey,ew,eh) in left_eye:
color = (0,255,0) # lime color
pred = predict(left_face[ey:ey+eh,ex:ex+ew],model)
if pred == 'closed':
eye_status='0'
color = (0,225,255) # yellow color
cv2.rectangle(left_face,(ex,ey),(ex+ew,ey+eh),color,2)
eyes_detected[name] += eye_status
# Each time, we check if the person has blinked
# If yes (10 blink), we display its name
if isBlinking(eyes_detected[name],200):
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2) # lime color
# Display name
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) # lime color
return frame
# if __name__ == "__main__":
# (model, face_detector, open_eyes_detector,left_eye_detector,right_eye_detector, video_capture, images) = init()
# data = process_and_encode(images)
#
# eyes_detected = defaultdict(str)
# while True:
# frame = detect_and_display(model, video_capture, face_detector, open_eyes_detector,left_eye_detector,right_eye_detector, data, eyes_detected)
# cv2.imshow("Face Liveness Detector", frame)
# if cv2.waitKey(1) & 0xFF == ord('q'):
# break
# cv2.destroyAllWindows()
# video_capture.stop()