Spaces:
Sleeping
Sleeping
import math | |
import mediapipe | |
import time | |
import cv2 | |
from tqdm import tqdm | |
import numpy as np | |
def EuclideanDistance(point1, point2): | |
x1, y1 = point1 | |
x2, y2 = point2 | |
distance = math.sqrt((x2 - x1)**2 + (y2 - y1)**2) | |
return distance | |
class BlinkDetector: | |
def __init__(self): | |
self.COUNTER = 0 | |
self.TOTAL_BLINKS = 0 # put 1 when divide | |
self.blink_start_time = 0 | |
self.blink_durations = [] | |
self.LEFT_EYE = [362, 382, 381, 380, 374, 373, 390, 249, 263, 466, 388, 387, 386, 385, 384, 398] | |
self.RIGHT_EYE = [33, 7, 163, 144, 145, 153, 154, 155, 133, 173, 157, 158, 159, 160, 161, 246] | |
def FaceMeshInitialiser(self, | |
max_num_faces, | |
min_detection_confidence, | |
min_tracking_confidence): | |
face_mesh = mediapipe.solutions.face_mesh.FaceMesh(max_num_faces=max_num_faces, | |
min_detection_confidence=min_detection_confidence, | |
min_tracking_confidence=min_tracking_confidence) | |
return face_mesh | |
def LandmarksDetector(self, | |
frame, | |
face_mesh_results, | |
draw: bool=False | |
): | |
image_height, image_width = frame.shape[:2] | |
mesh_coordinates = [(int(point.x * image_width), int(point.y * image_height)) for point in face_mesh_results.multi_face_landmarks[0].landmark] | |
if draw: | |
[cv2.circle(frame, i, 2, (0, 255, 0), -1) for i in mesh_coordinates] | |
return mesh_coordinates | |
def BlinkRatioCalculator(self, | |
landmarks): | |
right_eye_landmark1 = landmarks[self.RIGHT_EYE[0]] | |
right_eye_landmark2 = landmarks[self.RIGHT_EYE[8]] | |
right_eye_landmark3 = landmarks[self.RIGHT_EYE[12]] | |
right_eye_landmark4 = landmarks[self.RIGHT_EYE[4]] | |
left_eye_landmark1 = landmarks[self.LEFT_EYE[0]] | |
left_eye_landmark2 = landmarks[self.LEFT_EYE[8]] | |
left_eye_landmark3 = landmarks[self.LEFT_EYE[12]] | |
left_eye_landmark4 = landmarks[self.LEFT_EYE[4]] | |
right_eye_horizontal_distance = EuclideanDistance(right_eye_landmark1, right_eye_landmark2) | |
right_eye_verticle_distance = EuclideanDistance(right_eye_landmark3, right_eye_landmark4) | |
left_eye_horizontal_distance = EuclideanDistance(left_eye_landmark1, left_eye_landmark2) | |
left_eye_verticle_distance = EuclideanDistance(left_eye_landmark3, left_eye_landmark4) | |
try: | |
right_eye_ratio = right_eye_horizontal_distance / right_eye_verticle_distance | |
except: | |
right_eye_ratio = 0 | |
try: | |
left_eye_ratio = left_eye_horizontal_distance / left_eye_verticle_distance | |
except: | |
left_eye_ratio=0 | |
# eyes_ratio = (right_eye_ratio + left_eye_ratio) / 2 | |
return [right_eye_ratio, left_eye_ratio] | |
def BlinkCounter(self, | |
eyes_ratio): | |
if eyes_ratio[0] > 4 or eyes_ratio[1] > 4: | |
if self.COUNTER == 0: | |
self.blink_start_time = time.time() | |
self.COUNTER += 1 | |
else: | |
if self.COUNTER > 4: | |
self.TOTAL_BLINKS += 1 | |
blink_duration = time.time() - self.blink_start_time | |
self.blink_durations.append(blink_duration) | |
self.COUNTER = 0 | |
return [self.TOTAL_BLINKS, self.blink_durations] | |
def InitialiseVariables(): | |
return BlinkDetector() | |
class Facetrack(BlinkDetector): | |
def __init__(self): | |
super().__init__() | |
# create object for mediapipe face_mesh | |
self.mediapipe_face_mesh = self.FaceMeshInitialiser(max_num_faces=1, | |
min_detection_confidence=0.6, | |
min_tracking_confidence=0.7) | |
self.frame = None | |
self.avg_blink_duration=0 | |
self.list_blinks=[] | |
def predict(self,img): | |
self.rgb_frame = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) | |
self.results = self.mediapipe_face_mesh.process(self.rgb_frame) | |
if self.results.multi_face_landmarks: | |
self.mesh_coordinates = self.LandmarksDetector(img, self.results, draw=True) | |
self.eyes_ratio = self.BlinkRatioCalculator(self.mesh_coordinates) | |
self.list_blinks = self.BlinkCounter(self.eyes_ratio) | |
if self.list_blinks[1]: | |
try: | |
self.avg_blink_duration = sum(self.list_blinks[1]) / len(self.list_blinks[1]) | |
except: | |
self.avg_blink_duration = sum(self.list_blinks[1]) | |
self.blink_durations = self.list_blinks[1] | |
if len(self.list_blinks)>0 : | |
self.TOTAL_BLINKS = self.list_blinks[0] | |
else: | |
self.TOTAL_BLINKS = 0 | |
def eye_track_predict(fc,frames,fps): | |
preds=[] | |
for frame in tqdm(frames): | |
if frame is not None: | |
frame=np.copy(frame) | |
fc.predict(frame) | |
data=fc.TOTAL_BLINKS | |
else: | |
data='frame error' | |
preds.append(data) | |
return preds,fc.blink_durations,fc.TOTAL_BLINKS | |