File size: 5,810 Bytes
3c2d542
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
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