contact_lens / utils.py
Medvira's picture
Update utils.py
3c2d542 verified
import math
import numpy as np
import cv2 as cv
LEFT_EYE = [362, 382, 381, 380, 374, 373, 390, 249, 263, 466, 388, 387, 386, 385, 384, 398]
RIGHT_EYE = [33, 7, 163, 144, 145, 153, 154, 155, 133, 173, 157, 158, 159, 160, 161, 246]
LEFT_IRIS = [474, 475, 476, 477]
RIGHT_IRIS = [469, 470, 471, 472]
def valid_float(n):
if not n.isfloat():
raise argparse.ArgumentTypeError('Invalid integer value: {}'.format(n))
return float(n)
def euclaideanDistance(point, point1):
x, y = point
x1, y1 = point1
distance = math.sqrt((x1 - x)**2 + (y1 - y)**2)
return distance
# Blinking Ratio
def blinkRatio(img, landmarks, right_indices, left_indices):
# Right eyes
# horizontal line
rh_right = landmarks[right_indices[0]]
rh_left = landmarks[right_indices[8]]
# vertical line
rv_top = landmarks[right_indices[12]]
rv_bottom = landmarks[right_indices[4]]
# draw lines on right eyes
# cv.line(img, rh_right, rh_left, utils.GREEN, 2)
# cv.line(img, rv_top, rv_bottom, utils.WHITE, 2) # LEFT_EYE
# horizontal line
lh_right = landmarks[left_indices[0]]
lh_left = landmarks[left_indices[8]] # vertical line
lv_top = landmarks[left_indices[12]]
lv_bottom = landmarks[left_indices[4]] # Finding Distance Right Eye
rhDistance = euclaideanDistance(rh_right, rh_left)
rvDistance = euclaideanDistance(rv_top, rv_bottom)
# Finding Distance Left Eye
lvDistance = euclaideanDistance(lv_top, lv_bottom)
lhDistance = euclaideanDistance(lh_right, lh_left) # Finding ratio of LEFT and Right Eyes
reRatio=0.0
leRatio=0.0
if (rvDistance > 0.0) & (lvDistance > 0.0):
reRatio = rhDistance/rvDistance
leRatio = lhDistance/lvDistance
ratio = (reRatio+leRatio)/2
return ratio, reRatio, leRatio
def process_frame(frame, overlay, LEFT_EYE, RIGHT_EYE, LEFT_IRIS, RIGHT_IRIS,
mp_face_mesh, min_detection_confidence, min_tracking_confidence,alpha):
with mp_face_mesh.FaceMesh(
max_num_faces=1,
refine_landmarks=True,
min_detection_confidence=min_detection_confidence,
min_tracking_confidence=min_tracking_confidence
) as face_mesh:
# Convert frame to RGB
rgb_frame = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
# Convert RGB frame to RGBA
rgba_frame = cv.cvtColor(frame, cv.COLOR_BGR2RGBA)
# Get frame dimensions
height, width = rgba_frame.shape[:2]
# Process frame with face mesh
results = face_mesh.process(rgb_frame)
if results.multi_face_landmarks:
# Initialize overlay with zeros
zero_overlay = np.zeros_like(rgba_frame)
# Get mesh points
mesh_points = np.array([np.multiply([p.x, p.y],
[width, height]).astype(int) for p in results.multi_face_landmarks[0].landmark])
# Initialize iris masks
iris_mask_left = np.zeros(rgba_frame.shape, dtype=np.uint8)
iris_mask_right = np.zeros(rgba_frame.shape, dtype=np.uint8)
# Get blink ratio
_, re_ratio, le_ratio = blinkRatio(rgb_frame, mesh_points, RIGHT_EYE, LEFT_EYE)
# Get iris centers and radii
(l_cx, l_cy), l_radius = cv.minEnclosingCircle(mesh_points[LEFT_IRIS])
(r_cx, r_cy), r_radius = cv.minEnclosingCircle(mesh_points[RIGHT_IRIS])
center_left = (int(l_cx), int(l_cy))
center_right = (int(r_cx), int(r_cy))
# Draw circles on iris masks
cv.circle(iris_mask_left, center_left, int(l_radius), (255, 0, 0, 255), -1, cv.LINE_AA)
cv.circle(iris_mask_right, center_right, int(r_radius), (255, 0, 0, 255), -1, cv.LINE_AA)
# Get bounding box sizes
bbx_size_l = int((l_radius * 2) / 2)
bbx_size_r = int((r_radius * 2) / 2)
# Resize overlay
resized_overlay_l = cv.resize(overlay, (bbx_size_l * 2, bbx_size_l * 2), interpolation=cv.INTER_CUBIC)
resized_overlay_r = cv.resize(overlay, (bbx_size_r * 2, bbx_size_r * 2), interpolation=cv.INTER_CUBIC)
# Get bounding box coordinates
y1_r = center_right[1] - bbx_size_r
y2_r = center_right[1] + bbx_size_r
x1_r = center_right[0] - bbx_size_r
x2_r = center_right[0] + bbx_size_r
y1_l = center_left[1] - bbx_size_l
y2_l = center_left[1] + bbx_size_l
x1_l = center_left[0] - bbx_size_l
x2_l = center_left[0] + bbx_size_l
# Add resized overlay to zero overlay if conditions are met
if (resized_overlay_l.shape == zero_overlay[y1_l:y2_l, x1_l:x2_l].shape) & (le_ratio < 5.0) & (le_ratio > 2.0):
zero_overlay[y1_l:y2_l, x1_l:x2_l] = resized_overlay_l
if (resized_overlay_r.shape == zero_overlay[y1_r:y2_r, x1_r:x2_r].shape) & (re_ratio < 5.0) & (re_ratio > 2.0):
zero_overlay[y1_r:y2_r, x1_r:x2_r] = resized_overlay_r
# Initialize eye masks
eye_mask_left = np.zeros(rgba_frame.shape, dtype=np.uint8)
eye_mask_right = np.zeros(rgba_frame.shape, dtype=np.uint8)
# Fill eye masks with polygons
cv.fillPoly(eye_mask_left, [mesh_points[LEFT_EYE]], (255, 0, 0, 255))
cv.fillPoly(eye_mask_right, [mesh_points[RIGHT_EYE]], (255, 0, 0, 255))
# Use the 4-channel masks to create zero_overlay
zero_overlay[np.where((iris_mask_left[:, :, 3] > 0) & (eye_mask_left[:, :, 3] == 0))] = 0
zero_overlay[np.where((iris_mask_right[:, :, 3] > 0) & (eye_mask_right[:, :, 3] == 0))] = 0
# Add weighted overlay to frame
rgba_frame = cv.addWeighted(rgba_frame, 1, zero_overlay, alpha, 0)
return rgba_frame