Medvira commited on
Commit
46c8bcc
·
verified ·
1 Parent(s): 11ce322

Upload 3 files

Browse files
Files changed (3) hide show
  1. app.py +174 -0
  2. requirements.txt +4 -0
  3. utils.py +114 -0
app.py ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sys
3
+ import traceback
4
+ import gradio as gr
5
+ import cv2 as cv
6
+ import numpy as np
7
+ import mediapipe as mp
8
+ from utils import blinkRatio
9
+
10
+ def custom_excepthook(type, value, tb):
11
+ traceback.print_exception(type, value, tb)
12
+ sys.__excepthook__(type, value, tb)
13
+
14
+ sys.excepthook = custom_excepthook
15
+
16
+ def list_overlay_images(directory):
17
+ return [f for f in os.listdir(directory) if f.endswith('.png')]
18
+
19
+ def process_frame(frame, overlay, LEFT_EYE, RIGHT_EYE, LEFT_IRIS, RIGHT_IRIS,
20
+ min_detection_confidence, min_tracking_confidence, alpha):
21
+ try:
22
+ mp_face_mesh = mp.solutions.face_mesh
23
+ with mp_face_mesh.FaceMesh(
24
+ max_num_faces=1,
25
+ refine_landmarks=True,
26
+ min_detection_confidence=min_detection_confidence,
27
+ min_tracking_confidence=min_tracking_confidence
28
+ ) as face_mesh:
29
+ rgb_frame = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
30
+ rgba_frame = cv.cvtColor(frame, cv.COLOR_BGR2RGBA)
31
+ height, width = rgba_frame.shape[:2]
32
+ results = face_mesh.process(rgb_frame)
33
+ if results.multi_face_landmarks:
34
+ zero_overlay = np.zeros_like(rgba_frame)
35
+ mesh_points = np.array([np.multiply([p.x, p.y],
36
+ [width, height]).astype(int) for p in results.multi_face_landmarks[0].landmark])
37
+ iris_mask_left = np.zeros(rgba_frame.shape, dtype=np.uint8)
38
+ iris_mask_right = np.zeros(rgba_frame.shape, dtype=np.uint8)
39
+ _, re_ratio, le_ratio = blinkRatio(rgb_frame, mesh_points, RIGHT_EYE, LEFT_EYE)
40
+ (l_cx, l_cy), l_radius = cv.minEnclosingCircle(mesh_points[LEFT_IRIS])
41
+ (r_cx, r_cy), r_radius = cv.minEnclosingCircle(mesh_points[RIGHT_IRIS])
42
+ center_left = (int(l_cx), int(l_cy))
43
+ center_right = (int(r_cx), int(r_cy))
44
+ cv.circle(iris_mask_left, center_left, int(l_radius), (255, 0, 0, 255), -1, cv.LINE_AA)
45
+ cv.circle(iris_mask_right, center_right, int(r_radius), (255, 0, 0, 255), -1, cv.LINE_AA)
46
+ bbx_size_l = int((l_radius * 2) / 2)
47
+ bbx_size_r = int((r_radius * 2) / 2)
48
+ resized_overlay_l = cv.resize(overlay, (bbx_size_l * 2, bbx_size_l * 2), interpolation=cv.INTER_CUBIC)
49
+ resized_overlay_r = cv.resize(overlay, (bbx_size_r * 2, bbx_size_r * 2), interpolation=cv.INTER_CUBIC)
50
+ y1_r = center_right[1] - bbx_size_r
51
+ y2_r = center_right[1] + bbx_size_r
52
+ x1_r = center_right[0] - bbx_size_r
53
+ x2_r = center_right[0] + bbx_size_r
54
+ y1_l = center_left[1] - bbx_size_l
55
+ y2_l = center_left[1] + bbx_size_l
56
+ x1_l = center_left[0] - bbx_size_l
57
+ x2_l = center_left[0] + bbx_size_l
58
+ if (resized_overlay_l.shape == zero_overlay[y1_l:y2_l, x1_l:x2_l].shape) & (le_ratio < 5.0) & (le_ratio > 2.0):
59
+ zero_overlay[y1_l:y2_l, x1_l:x2_l] = resized_overlay_l
60
+ if (resized_overlay_r.shape == zero_overlay[y1_r:y2_r, x1_r:x2_r].shape) & (re_ratio < 5.0) & (re_ratio > 2.0):
61
+ zero_overlay[y1_r:y2_r, x1_r:x2_r] = resized_overlay_r
62
+ eye_mask_left = np.zeros(rgba_frame.shape, dtype=np.uint8)
63
+ eye_mask_right = np.zeros(rgba_frame.shape, dtype=np.uint8)
64
+ cv.fillPoly(eye_mask_left, [mesh_points[LEFT_EYE]], (255, 0, 0, 255))
65
+ cv.fillPoly(eye_mask_right, [mesh_points[RIGHT_EYE]], (255, 0, 0, 255))
66
+ zero_overlay[np.where((iris_mask_left[:, :, 3] > 0) & (eye_mask_left[:, :, 3] == 0))] = 0
67
+ zero_overlay[np.where((iris_mask_right[:, :, 3] > 0) & (eye_mask_right[:, :, 3] == 0))] = 0
68
+ rgba_frame = cv.addWeighted(rgba_frame, 1, zero_overlay, alpha, 0)
69
+ return rgba_frame
70
+ except Exception as e:
71
+ print(f"Error in process_frame: {e}")
72
+ traceback.print_exc()
73
+
74
+ def process_image(input_image, overlay_file, alpha=0.3, min_detection_confidence=0.5, min_tracking_confidence=0.5):
75
+ overlay_file = overlay_file + '.png'
76
+ overlay_path = os.path.join(os.getcwd(),'overlays', overlay_file)
77
+ overlay = cv.imread(overlay_path, cv.IMREAD_UNCHANGED)
78
+ frame = np.array(input_image)
79
+ processed_frame = process_frame(frame, overlay, LEFT_EYE, RIGHT_EYE, LEFT_IRIS, RIGHT_IRIS,
80
+ min_detection_confidence, min_tracking_confidence, alpha)
81
+ return cv.cvtColor(processed_frame, cv.COLOR_BGR2RGB)
82
+
83
+ def process_video(input_video, overlay_file, alpha=0.3, output_format='mp4', output_frame_rate=30,
84
+ min_detection_confidence=0.5, min_tracking_confidence=0.5):
85
+ overlay_file = overlay_file + '.png'
86
+ overlay_path = os.path.join(os.getcwd(),'overlays', overlay_file)
87
+ overlay = cv.imread(overlay_path, cv.IMREAD_UNCHANGED)
88
+ cap = cv.VideoCapture(input_video)
89
+ output_path = os.path.join(os.getcwd(),f'video_processed.{output_format}')
90
+ # Define the codec and create a VideoWriter object to save the processed video
91
+ if (not isinstance(overlay,type(None))) & (not isinstance(cap,type(None))):
92
+ # Get the dimensions of the frame, fps
93
+ fps=int(output_frame_rate)
94
+ if fps==0:
95
+ fps = cap.get(5)
96
+ ret, frame = cap.read()
97
+ height, width, _ = frame.shape
98
+ fourcc = cv.VideoWriter_fourcc(*'mp4v' if output_format == 'mp4' else 'MJPG')
99
+ out = cv.VideoWriter(output_path, fourcc, fps, (width, height))
100
+ while(cap.isOpened()):
101
+ ret, frame = cap.read()
102
+ if ret == True:
103
+ processed_frame = process_frame(frame,overlay,LEFT_EYE, RIGHT_EYE, LEFT_IRIS, RIGHT_IRIS,
104
+ float(min_detection_confidence),
105
+ float(min_tracking_confidence), float(alpha)) # Assuming process_frame is a function that processes a single frame
106
+ processed_frame = cv.cvtColor(processed_frame, cv.COLOR_RGBA2BGR)
107
+ out.write(processed_frame)
108
+ else:
109
+ break
110
+ cap.release()
111
+ out.release()
112
+ return output_path
113
+
114
+
115
+ def process_webcam(frame, overlay_file, alpha=0.3, min_detection_confidence=0.5, min_tracking_confidence=0.5):
116
+ overlay_file = overlay_file + '.png'
117
+ overlay_path = os.path.join(os.getcwd(), overlay_file)
118
+ overlay = cv.imread(overlay_path, cv.IMREAD_UNCHANGED)
119
+ processed_frame = process_frame(frame, overlay, LEFT_EYE, RIGHT_EYE, LEFT_IRIS, RIGHT_IRIS,
120
+ min_detection_confidence, min_tracking_confidence, alpha)
121
+ return processed_frame
122
+
123
+ LEFT_EYE = [362, 382, 381, 380, 374, 373, 390, 249, 263, 466, 388, 387, 386, 385, 384, 398]
124
+ RIGHT_EYE = [33, 7, 163, 144, 145, 153, 154, 155, 133, 173, 157, 158, 159, 160, 161, 246]
125
+ LEFT_IRIS = [474, 475, 476, 477]
126
+ RIGHT_IRIS = [469, 470, 471, 472]
127
+
128
+ overlay_dir = os.path.join(os.getcwd(),'overlays')
129
+ overlay_files = list_overlay_images(overlay_dir)
130
+ overlay_choices = [x.split('.png')[0] for x in overlay_files]
131
+ with gr.Blocks() as demo:
132
+ with gr.Tab("Image"):
133
+ with gr.Row():
134
+ overlay_file = gr.Dropdown(choices=overlay_choices, value='Blue', label="Select a color")
135
+ # min_detection_confidence = gr.Slider(minimum=0.0, maximum=1.0, value=0.5, label="Min Detection Confidence")
136
+ # min_tracking_confidence = gr.Slider(minimum=0.0, maximum=1.0, value=0.5, label="Min Tracking Confidence")
137
+ # alpha = gr.Slider(minimum=0.0, maximum=1.0, value=0.3, label="Overlay Transparency")
138
+ with gr.Row():
139
+ input_image = gr.Image(height=500,width=400,label="Upload Image")
140
+ output_image = gr.Image(height=500,width=400,label="Processed Image")
141
+ process_image_btn = gr.Button("Process Image")
142
+ process_image_btn.click(process_image,
143
+ inputs=[input_image, overlay_file,],
144
+ outputs=output_image)
145
+
146
+ with gr.Tab("Video"):
147
+ with gr.Row():
148
+ overlay_file = gr.Dropdown(choices=overlay_choices, value='Blue', label="Select a color")
149
+ # min_detection_confidence = gr.Slider(minimum=0.0, maximum=1.0, value=0.5, label="Min Detection Confidence")
150
+ # min_tracking_confidence = gr.Slider(minimum=0.0, maximum=1.0, value=0.5, label="Min Tracking Confidence")
151
+ # alpha = gr.Slider(minimum=0.0, maximum=1.0, value=0.3, label="Overlay Transparency")
152
+ with gr.Row():
153
+ input_video = gr.Video(height=500,width=400,label="Upload Video")
154
+ output_video = gr.Video(height=500,width=400,label="Processed Video")
155
+ process_video_btn = gr.Button("Process Video")
156
+ process_video_btn.click(process_video,
157
+ inputs=[input_video, overlay_file,],
158
+ outputs=output_video)
159
+
160
+ with gr.Tab("Webcam"):
161
+ with gr.Row():
162
+ overlay_file = gr.Dropdown(choices=overlay_choices, value='Blue', label="Select a color")
163
+ # min_detection_confidence = gr.Slider(minimum=0.0, maximum=1.0, value=0.5, label="Min Detection Confidence")
164
+ # min_tracking_confidence = gr.Slider(minimum=0.0, maximum=1.0, value=0.5, label="Min Tracking Confidence")
165
+ # alpha = gr.Slider(minimum=0.0, maximum=1.0, value=0.3, label="Overlay Transparency")
166
+ with gr.Row():
167
+ input_webcam = gr.Video(sources="webcam", label="Webcam")
168
+ output_webcam = gr.Image(label="Processed Webcam")
169
+ process_webcam_btn = gr.Button("Process Webcam")
170
+ process_webcam_btn.click(process_webcam,
171
+ inputs=[input_webcam, overlay_file,],
172
+ outputs=output_webcam)
173
+
174
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ gradio
2
+ opencv-python
3
+ opencv-python-headless
4
+ mediapipe
utils.py ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ import numpy as np
3
+ import cv2 as cv
4
+
5
+ def valid_float(n):
6
+ if not n.isfloat():
7
+ raise argparse.ArgumentTypeError('Invalid integer value: {}'.format(n))
8
+ return float(n)
9
+
10
+
11
+ def euclaideanDistance(point, point1):
12
+ x, y = point
13
+ x1, y1 = point1
14
+ distance = math.sqrt((x1 - x)**2 + (y1 - y)**2)
15
+ return distance
16
+
17
+ # Blinking Ratio
18
+ def blinkRatio(img, landmarks, right_indices, left_indices):
19
+ # Right eyes
20
+ # horizontal line
21
+ rh_right = landmarks[right_indices[0]]
22
+ rh_left = landmarks[right_indices[8]]
23
+ # vertical line
24
+ rv_top = landmarks[right_indices[12]]
25
+ rv_bottom = landmarks[right_indices[4]]
26
+ # draw lines on right eyes
27
+ # cv.line(img, rh_right, rh_left, utils.GREEN, 2)
28
+ # cv.line(img, rv_top, rv_bottom, utils.WHITE, 2) # LEFT_EYE
29
+ # horizontal line
30
+ lh_right = landmarks[left_indices[0]]
31
+ lh_left = landmarks[left_indices[8]] # vertical line
32
+ lv_top = landmarks[left_indices[12]]
33
+ lv_bottom = landmarks[left_indices[4]] # Finding Distance Right Eye
34
+ rhDistance = euclaideanDistance(rh_right, rh_left)
35
+ rvDistance = euclaideanDistance(rv_top, rv_bottom)
36
+ # Finding Distance Left Eye
37
+ lvDistance = euclaideanDistance(lv_top, lv_bottom)
38
+ lhDistance = euclaideanDistance(lh_right, lh_left) # Finding ratio of LEFT and Right Eyes
39
+ reRatio=0.0
40
+ leRatio=0.0
41
+ if (rvDistance > 0.0) & (lvDistance > 0.0):
42
+ reRatio = rhDistance/rvDistance
43
+ leRatio = lhDistance/lvDistance
44
+
45
+ ratio = (reRatio+leRatio)/2
46
+ return ratio, reRatio, leRatio
47
+
48
+ def process_frame(frame, overlay, LEFT_EYE, RIGHT_EYE, LEFT_IRIS, RIGHT_IRIS,
49
+ mp_face_mesh, min_detection_confidence, min_tracking_confidence,alpha):
50
+ with mp_face_mesh.FaceMesh(
51
+ max_num_faces=1,
52
+ refine_landmarks=True,
53
+ min_detection_confidence=min_detection_confidence,
54
+ min_tracking_confidence=min_tracking_confidence
55
+ ) as face_mesh:
56
+ # Convert frame to RGB
57
+ rgb_frame = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
58
+ # Convert RGB frame to RGBA
59
+ rgba_frame = cv.cvtColor(frame, cv.COLOR_BGR2RGBA)
60
+ # Get frame dimensions
61
+ height, width = rgba_frame.shape[:2]
62
+ # Process frame with face mesh
63
+ results = face_mesh.process(rgb_frame)
64
+ if results.multi_face_landmarks:
65
+ # Initialize overlay with zeros
66
+ zero_overlay = np.zeros_like(rgba_frame)
67
+ # Get mesh points
68
+ mesh_points = np.array([np.multiply([p.x, p.y],
69
+ [width, height]).astype(int) for p in results.multi_face_landmarks[0].landmark])
70
+ # Initialize iris masks
71
+ iris_mask_left = np.zeros(rgba_frame.shape, dtype=np.uint8)
72
+ iris_mask_right = np.zeros(rgba_frame.shape, dtype=np.uint8)
73
+ # Get blink ratio
74
+ _, re_ratio, le_ratio = blinkRatio(rgb_frame, mesh_points, RIGHT_EYE, LEFT_EYE)
75
+ # Get iris centers and radii
76
+ (l_cx, l_cy), l_radius = cv.minEnclosingCircle(mesh_points[LEFT_IRIS])
77
+ (r_cx, r_cy), r_radius = cv.minEnclosingCircle(mesh_points[RIGHT_IRIS])
78
+ center_left = (int(l_cx), int(l_cy))
79
+ center_right = (int(r_cx), int(r_cy))
80
+ # Draw circles on iris masks
81
+ cv.circle(iris_mask_left, center_left, int(l_radius), (255, 0, 0, 255), -1, cv.LINE_AA)
82
+ cv.circle(iris_mask_right, center_right, int(r_radius), (255, 0, 0, 255), -1, cv.LINE_AA)
83
+ # Get bounding box sizes
84
+ bbx_size_l = int((l_radius * 2) / 2)
85
+ bbx_size_r = int((r_radius * 2) / 2)
86
+ # Resize overlay
87
+ resized_overlay_l = cv.resize(overlay, (bbx_size_l * 2, bbx_size_l * 2), interpolation=cv.INTER_CUBIC)
88
+ resized_overlay_r = cv.resize(overlay, (bbx_size_r * 2, bbx_size_r * 2), interpolation=cv.INTER_CUBIC)
89
+ # Get bounding box coordinates
90
+ y1_r = center_right[1] - bbx_size_r
91
+ y2_r = center_right[1] + bbx_size_r
92
+ x1_r = center_right[0] - bbx_size_r
93
+ x2_r = center_right[0] + bbx_size_r
94
+ y1_l = center_left[1] - bbx_size_l
95
+ y2_l = center_left[1] + bbx_size_l
96
+ x1_l = center_left[0] - bbx_size_l
97
+ x2_l = center_left[0] + bbx_size_l
98
+ # Add resized overlay to zero overlay if conditions are met
99
+ if (resized_overlay_l.shape == zero_overlay[y1_l:y2_l, x1_l:x2_l].shape) & (le_ratio < 5.0) & (le_ratio > 2.0):
100
+ zero_overlay[y1_l:y2_l, x1_l:x2_l] = resized_overlay_l
101
+ if (resized_overlay_r.shape == zero_overlay[y1_r:y2_r, x1_r:x2_r].shape) & (re_ratio < 5.0) & (re_ratio > 2.0):
102
+ zero_overlay[y1_r:y2_r, x1_r:x2_r] = resized_overlay_r
103
+ # Initialize eye masks
104
+ eye_mask_left = np.zeros(rgba_frame.shape, dtype=np.uint8)
105
+ eye_mask_right = np.zeros(rgba_frame.shape, dtype=np.uint8)
106
+ # Fill eye masks with polygons
107
+ cv.fillPoly(eye_mask_left, [mesh_points[LEFT_EYE]], (255, 0, 0, 255))
108
+ cv.fillPoly(eye_mask_right, [mesh_points[RIGHT_EYE]], (255, 0, 0, 255))
109
+ # Use the 4-channel masks to create zero_overlay
110
+ zero_overlay[np.where((iris_mask_left[:, :, 3] > 0) & (eye_mask_left[:, :, 3] == 0))] = 0
111
+ zero_overlay[np.where((iris_mask_right[:, :, 3] > 0) & (eye_mask_right[:, :, 3] == 0))] = 0
112
+ # Add weighted overlay to frame
113
+ rgba_frame = cv.addWeighted(rgba_frame, 1, zero_overlay, alpha, 0)
114
+ return rgba_frame