Skip to content

Instantly share code, notes, and snippets.

@Asadullah-Dal17
Last active September 1, 2021 07:03
Show Gist options
  • Select an option

  • Save Asadullah-Dal17/fd71c31bac74ee84e6a31af50fa62961 to your computer and use it in GitHub Desktop.

Select an option

Save Asadullah-Dal17/fd71c31bac74ee84e6a31af50fa62961 to your computer and use it in GitHub Desktop.
Mediapipe landmarks detection for each individual part, like an face-oval, eyes, lips, and Eyebrows
import cv2 as cv
import mediapipe as mp
import time
import utils
import math
# variables
FRAME_COUNTER =0
TOTAL_BLINKS = 0
CLOSED_EYES_FRAME_COUNTER =0 # Counts frames while Eyes are closed
# constants
FONTS =cv.FONT_HERSHEY_COMPLEX
CLOSED_EYES_FRAME = 3 # threshold to count a blink, after number of frames
# face bounder indices
FACE_OVAL=[ 10, 338, 297, 332, 284, 251, 389, 356, 454, 323, 361, 288, 397, 365, 379, 378, 400, 377, 152, 148, 176, 149, 150, 136, 172, 58, 132, 93, 234, 127, 162, 21, 54, 103,67, 109]
# lips indices for Landmarks
LIPS=[ 61, 146, 91, 181, 84, 17, 314, 405, 321, 375,291, 308, 324, 318, 402, 317, 14, 87, 178, 88, 95,185, 40, 39, 37,0 ,267 ,269 ,270 ,409, 415, 310, 311, 312, 13, 82, 81, 42, 183, 78 ]
LOWER_LIPS =[61, 146, 91, 181, 84, 17, 314, 405, 321, 375, 291, 308, 324, 318, 402, 317, 14, 87, 178, 88, 95]
UPPER_LIPS=[ 185, 40, 39, 37,0 ,267 ,269 ,270 ,409, 415, 310, 311, 312, 13, 82, 81, 42, 183, 78]
# Left eyes indices
LEFT_EYE =[ 362, 382, 381, 380, 374, 373, 390, 249, 263, 466, 388, 387, 386, 385,384, 398 ]
LEFT_EYEBROW =[ 336, 296, 334, 293, 300, 276, 283, 282, 295, 285 ]
# right eyes indices
RIGHT_EYE=[ 33, 7, 163, 144, 145, 153, 154, 155, 133, 173, 157, 158, 159, 160, 161 , 246 ]
RIGHT_EYEBROW=[ 70, 63, 105, 66, 107, 55, 65, 52, 53, 46 ]
map_face_mesh = mp.solutions.face_mesh
# camera object
camera = cv.VideoCapture(0)
# landmark detection function
def landmarksDetection(img, results, draw=False):
img_height, img_width= img.shape[:2]
# list[(x,y), (x,y)....]
mesh_coord = [(int(point.x * img_width), int(point.y * img_height)) for point in results.multi_face_landmarks[0].landmark]
if draw :
[cv.circle(img, p, 2, utils.GREEN, -1) for p in mesh_coord]
# returning the list of tuples for each landmarks
return mesh_coord
# finding distance between two points
def euclideanDistance(point1, point2):
x, y = point1
x1, y1 = point2
euclidean_dist = math.sqrt((x1 - x) ** 2 + (y1 - y) ** 2)
return euclidean_dist
# Blinking Detector Function
def blinkRatio(frame, landmarks, right_eye_indics, left_eye_indics):
# getting the points
# Right Eye horizontal points
rh_right = landmarks[right_eye_indics[0]]
rh_left = landmarks[right_eye_indics[7]]
# left Eyes horizontal points
lh_right = landmarks[left_eye_indics[0]]
lh_left = landmarks[left_eye_indics[7]]
cv.circle(frame, rh_right, 2, utils.GREEN, -1)
cv.circle(frame, rh_left, 2, utils.WHITE, -1)
cv.circle(frame, lh_right, 2, utils.GREEN, -1)
cv.circle(frame, lh_left, 2, utils.WHITE, -1)
# vertical points for Right Eyes
rv_top= landmarks[right_eye_indics[12]]
rv_bottom = landmarks[right_eye_indics[4]]
# Vertical points for Left Eye
lv_top = landmarks[left_eye_indics[12]]
lv_bottom = landmarks[left_eye_indics[4]]
cv.circle(frame, rv_top, 2, utils.GREEN, -1)
cv.circle(frame, rv_bottom, 2, utils.WHITE, -1)
cv.circle(frame, lv_top, 2, utils.GREEN, -1)
cv.circle(frame, lv_bottom, 2, utils.WHITE, -1)
# finding euclidean distance
h_right_euclid_dist =euclideanDistance(rh_right, rh_left)
v_right_euclid_dist =euclideanDistance(rv_top, rv_bottom)
h_left_euclid_dist = euclideanDistance(lh_right, lh_left)
v_left_euclid_dist = euclideanDistance(lv_top, lv_bottom)
eyes_ratio =( (h_right_euclid_dist/v_right_euclid_dist) + (h_left_euclid_dist/ v_left_euclid_dist))/2
return eyes_ratio
with map_face_mesh.FaceMesh(min_detection_confidence =0.5, min_tracking_confidence=0.5) as face_mesh:
# starting time here
start_time = time.time()
# starting Video loop here.
while True:
FRAME_COUNTER +=1 # frame counter
ret, frame = camera.read() # getting frame from camera
fr_height, fr_width = frame.shape[:2]
if not ret:
break # no more frames break
# frame = cv.resize(frame, None, fx=2, fy=2, interpolation=cv.INTER_AREA)
rgb_frame = cv.cvtColor(frame, cv.COLOR_RGB2BGR)
results = face_mesh.process(rgb_frame)
if results.multi_face_landmarks:
mesh_coords = landmarksDetection(frame, results, False)
# blinking ratio
ratio = blinkRatio(frame, mesh_coords, RIGHT_EYE, LEFT_EYE)
if ratio >4.1:
CLOSED_EYES_FRAME_COUNTER +=1
print(CLOSED_EYES_FRAME_COUNTER, ratio)
cv.putText(frame, f'Blink', (int(fr_width/2), 30), FONTS, 1.4, utils.GREEN, 2, cv.LINE_AA)
else:
if CLOSED_EYES_FRAME_COUNTER>CLOSED_EYES_FRAME:
TOTAL_BLINKS +=1
CLOSED_EYES_FRAME_COUNTER=0
cv.putText(frame, f'Total Blinks: {TOTAL_BLINKS}', (int(20), 100), FONTS, 0.5, utils.GREEN, 1, cv.LINE_AA)
# calculating frame per seconds FPS
end_time = time.time()-start_time
fps = FRAME_COUNTER/end_time
frame =utils.textWithBackground(frame,f'FPS: {round(fps,1)}',FONTS, 1.0, (20, 50), bgOpacity=0.9, textThickness=2)
cv.imshow('frame', frame)
key = cv.waitKey(2)
if key==ord('q') or key ==ord('Q'):
break
cv.destroyAllWindows()
camera.release()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment