Spaces:
Sleeping
Sleeping
Upload 5 files
Browse files- app.py +282 -0
- functions.py +57 -0
- image.jpg +0 -0
- maps.py +241 -0
- requirements.txt +4 -0
app.py
ADDED
@@ -0,0 +1,282 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import cv2
|
3 |
+
import os
|
4 |
+
import mediapipe as mp
|
5 |
+
import numpy as np
|
6 |
+
import tempfile
|
7 |
+
from maps import *
|
8 |
+
from functions import *
|
9 |
+
|
10 |
+
class CosmeticInjectionVisualizer:
|
11 |
+
def __init__(self, muscles_map, tasks_map):
|
12 |
+
self.mp_face_mesh = mp.solutions.face_mesh
|
13 |
+
self.mp_drawing = mp.solutions.drawing_utils
|
14 |
+
self.mp_drawing_styles = mp.solutions.drawing_styles
|
15 |
+
self.muscles_map = muscles_map
|
16 |
+
self.tasks_map = tasks_map
|
17 |
+
|
18 |
+
def process_image(self, image, task_name):
|
19 |
+
frame_shape = image.shape
|
20 |
+
with self.mp_face_mesh.FaceMesh(
|
21 |
+
static_image_mode=True,
|
22 |
+
refine_landmarks=True,
|
23 |
+
max_num_faces=1,
|
24 |
+
min_detection_confidence=0.5) as face_mesh:
|
25 |
+
|
26 |
+
results = face_mesh.process(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
|
27 |
+
if results.multi_face_landmarks:
|
28 |
+
for face_landmarks in results.multi_face_landmarks:
|
29 |
+
points = self.get_muscle_points(task_name, face_landmarks, frame_shape)
|
30 |
+
self.draw_muscle_points(image, points, face_landmarks, task_name)
|
31 |
+
return image
|
32 |
+
|
33 |
+
def draw_rounded_rectangle(self,image, start_point, end_point, color, thickness, radius):
|
34 |
+
top_left = start_point
|
35 |
+
bottom_right = end_point
|
36 |
+
|
37 |
+
if thickness < 0: # Filled rectangle
|
38 |
+
thickness = cv2.FILLED
|
39 |
+
|
40 |
+
# Draw filled rectangle with rounded corners
|
41 |
+
if thickness == cv2.FILLED:
|
42 |
+
# Top-left corner
|
43 |
+
cv2.ellipse(image, (top_left[0] + radius, top_left[1] + radius), (radius, radius), 180, 0, 90, color, -1)
|
44 |
+
# Top-right corner
|
45 |
+
cv2.ellipse(image, (bottom_right[0] - radius, top_left[1] + radius), (radius, radius), 270, 0, 90, color, -1)
|
46 |
+
# Bottom-left corner
|
47 |
+
cv2.ellipse(image, (top_left[0] + radius, bottom_right[1] - radius), (radius, radius), 90, 0, 90, color, -1)
|
48 |
+
# Bottom-right corner
|
49 |
+
cv2.ellipse(image, (bottom_right[0] - radius, bottom_right[1] - radius), (radius, radius), 0, 0, 90, color, -1)
|
50 |
+
|
51 |
+
# Top and bottom border
|
52 |
+
cv2.rectangle(image, (top_left[0] + radius, top_left[1]), (bottom_right[0] - radius, top_left[1] + radius), color, -1)
|
53 |
+
cv2.rectangle(image, (top_left[0] + radius, bottom_right[1] - radius), (bottom_right[0] - radius, bottom_right[1]), color, -1)
|
54 |
+
# Left and right border
|
55 |
+
cv2.rectangle(image, (top_left[0], top_left[1] + radius), (top_left[0] + radius, bottom_right[1] - radius), color, -1)
|
56 |
+
cv2.rectangle(image, (bottom_right[0] - radius, top_left[1] + radius), (bottom_right[0], bottom_right[1] - radius), color, -1)
|
57 |
+
# Center rectangle
|
58 |
+
cv2.rectangle(image, (top_left[0] + radius, top_left[1] + radius), (bottom_right[0] - radius, bottom_right[1] - radius), color, -1)
|
59 |
+
else:
|
60 |
+
# Top-left corner
|
61 |
+
cv2.ellipse(image, (top_left[0] + radius, top_left[1] + radius), (radius, radius), 180, 0, 90, color, thickness)
|
62 |
+
# Top-right corner
|
63 |
+
cv2.ellipse(image, (bottom_right[0] - radius, top_left[1] + radius), (radius, radius), 270, 0, 90, color, thickness)
|
64 |
+
# Bottom-left corner
|
65 |
+
cv2.ellipse(image, (top_left[0] + radius, bottom_right[1] - radius), (radius, radius), 90, 0, 90, color, thickness)
|
66 |
+
# Bottom-right corner
|
67 |
+
cv2.ellipse(image, (bottom_right[0] - radius, bottom_right[1] - radius), (radius, radius), 0, 0, 90, color, thickness)
|
68 |
+
|
69 |
+
# Top border
|
70 |
+
cv2.line(image, (top_left[0] + radius, top_left[1]), (bottom_right[0] - radius, top_left[1]), color, thickness)
|
71 |
+
# Bottom border
|
72 |
+
cv2.line(image, (top_left[0] + radius, bottom_right[1]), (bottom_right[0] - radius, bottom_right[1]), color, thickness)
|
73 |
+
# Left border
|
74 |
+
cv2.line(image, (top_left[0], top_left[1] + radius), (top_left[0], bottom_right[1] - radius), color, thickness)
|
75 |
+
# Right border
|
76 |
+
cv2.line(image, (bottom_right[0], top_left[1] + radius), (bottom_right[0], bottom_right[1] - radius), color, thickness)
|
77 |
+
|
78 |
+
def draw_muscle_points(self, image, points, face_landmarks, task, draw_background=False, verbose=False):
|
79 |
+
# Calculate bounding box of the face landmarks
|
80 |
+
x_min = min([landmark.x for landmark in face_landmarks.landmark]) * image.shape[1]
|
81 |
+
y_min = min([landmark.y for landmark in face_landmarks.landmark]) * image.shape[0]
|
82 |
+
x_max = max([landmark.x for landmark in face_landmarks.landmark]) * image.shape[1]
|
83 |
+
y_max = max([landmark.y for landmark in face_landmarks.landmark]) * image.shape[0]
|
84 |
+
face_width = x_max - x_min
|
85 |
+
face_height = y_max - y_min
|
86 |
+
|
87 |
+
# Determine text size and circle size based on face size relative to the image
|
88 |
+
scale_factor = 0.0005 * (face_width + face_height)
|
89 |
+
text_scale = scale_factor
|
90 |
+
thickness = int(2 * scale_factor)
|
91 |
+
margin = int(10 * scale_factor)
|
92 |
+
circle_radius = int(5 * scale_factor)
|
93 |
+
radius = int(10 * scale_factor) # For rounded corners
|
94 |
+
|
95 |
+
muscle_names = set()
|
96 |
+
for (x, y, muscle) in points:
|
97 |
+
# Draw the circle for the muscle point
|
98 |
+
cv2.circle(image, (x, y), circle_radius, (0, 0, 255), -1)
|
99 |
+
|
100 |
+
# Determine text size and background size
|
101 |
+
text = "3 U"
|
102 |
+
(text_width, text_height), baseline = cv2.getTextSize(text, cv2.FONT_HERSHEY_SIMPLEX, text_scale, thickness)
|
103 |
+
text_x = x
|
104 |
+
text_y = y - 10
|
105 |
+
text_x_end = text_x + text_width + 2 * margin
|
106 |
+
text_y_end = text_y - text_height - 2 * margin
|
107 |
+
|
108 |
+
if draw_background:
|
109 |
+
# Draw background rectangle with margins and rounded corners
|
110 |
+
self.draw_rounded_rectangle(image, (text_x - margin, text_y + margin), (text_x_end, text_y_end), (0, 0, 0), cv2.FILLED, radius)
|
111 |
+
|
112 |
+
if verbose:
|
113 |
+
# Draw the text on top of the rectangle
|
114 |
+
cv2.putText(image, text, (text_x, text_y), cv2.FONT_HERSHEY_SIMPLEX, text_scale, (0, 255, 0), thickness, cv2.LINE_AA)
|
115 |
+
|
116 |
+
muscle_names.add(muscle)
|
117 |
+
muscles = ','.join(muscle_names)
|
118 |
+
# Draw legend in the bottom-left corner with background
|
119 |
+
legend_texts = ['Total dose : 42','Name of patient: Julia Juila',f'Muscle : {muscles}', f'Task : {task}','Cosmetic App']
|
120 |
+
legend_x = 10
|
121 |
+
legend_y = image.shape[0] - 10
|
122 |
+
legend_margin = 5
|
123 |
+
legend_scale_factor = 1.5 * text_scale # Make legend text larger
|
124 |
+
legend_thickness = int(2 * legend_scale_factor)
|
125 |
+
legend_radius = int(10 * legend_scale_factor)
|
126 |
+
max_text_width = 0
|
127 |
+
total_text_height = 0
|
128 |
+
|
129 |
+
for text in legend_texts:
|
130 |
+
(text_width, text_height), _ = cv2.getTextSize(text, cv2.FONT_HERSHEY_SIMPLEX, legend_scale_factor, legend_thickness)
|
131 |
+
max_text_width = max(max_text_width, text_width)
|
132 |
+
total_text_height += text_height + 2 * legend_margin
|
133 |
+
|
134 |
+
legend_start_point = (legend_x - legend_margin, legend_y - total_text_height - legend_margin)
|
135 |
+
legend_end_point = (legend_x + max_text_width + legend_margin, legend_y + legend_margin)
|
136 |
+
|
137 |
+
if True:
|
138 |
+
self.draw_rounded_rectangle(image, legend_start_point, legend_end_point, (0, 0, 0), cv2.FILLED, legend_radius)
|
139 |
+
|
140 |
+
for text in legend_texts:
|
141 |
+
(text_width, text_height), _ = cv2.getTextSize(text, cv2.FONT_HERSHEY_SIMPLEX, legend_scale_factor, legend_thickness)
|
142 |
+
cv2.putText(image, text, (legend_x, legend_y), cv2.FONT_HERSHEY_SIMPLEX, legend_scale_factor, (255, 255, 255), legend_thickness, cv2.LINE_AA)
|
143 |
+
legend_y -= text_height + 2 * legend_margin
|
144 |
+
|
145 |
+
|
146 |
+
def get_muscle_points(self, task_name, face_landmarks, frame_shape):
|
147 |
+
if task_name not in self.tasks_map:
|
148 |
+
raise ValueError(f"Task '{task_name}' not found in tasks map.")
|
149 |
+
muscles_names = self.tasks_map[task_name]['muscles']
|
150 |
+
points = []
|
151 |
+
for muscle in muscles_names:
|
152 |
+
for region in self.muscles_map[muscle]:
|
153 |
+
if 'points' in self.muscles_map[muscle][region]:
|
154 |
+
for point_idx in self.muscles_map[muscle][region]['points']:
|
155 |
+
landmark = face_landmarks.landmark[point_idx]
|
156 |
+
x = int(landmark.x * frame_shape[1])
|
157 |
+
y = int(landmark.y * frame_shape[0])
|
158 |
+
points.append((x, y, muscle))
|
159 |
+
else:
|
160 |
+
for subregion in self.muscles_map[muscle][region]:
|
161 |
+
for point_idx in self.muscles_map[muscle][region][subregion]['points']:
|
162 |
+
landmark = face_landmarks.landmark[point_idx]
|
163 |
+
x = int(landmark.x * frame_shape[1])
|
164 |
+
y = int(landmark.y * frame_shape[0])
|
165 |
+
points.append((x, y, muscle))
|
166 |
+
return points
|
167 |
+
|
168 |
+
def process_video(self, video_path, task_name):
|
169 |
+
cap = cv2.VideoCapture(video_path)
|
170 |
+
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.mp4')
|
171 |
+
output_path = temp_file.name
|
172 |
+
|
173 |
+
# Get the width and height of the frames
|
174 |
+
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
175 |
+
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
|
176 |
+
fps = int(cap.get(cv2.CAP_PROP_FPS))
|
177 |
+
|
178 |
+
# Define the codec and create VideoWriter object
|
179 |
+
fourcc = cv2.VideoWriter_fourcc(*'mp4v') # Use appropriate codec for .mp4 files
|
180 |
+
out = cv2.VideoWriter(output_path, fourcc, fps, (frame_width, frame_height))
|
181 |
+
|
182 |
+
with self.mp_face_mesh.FaceMesh(
|
183 |
+
static_image_mode=False,
|
184 |
+
refine_landmarks=True,
|
185 |
+
max_num_faces=1,
|
186 |
+
min_detection_confidence=0.5,
|
187 |
+
min_tracking_confidence=0.5) as face_mesh:
|
188 |
+
|
189 |
+
while cap.isOpened():
|
190 |
+
ret, frame = cap.read()
|
191 |
+
if not ret:
|
192 |
+
break
|
193 |
+
frame_shape = frame.shape
|
194 |
+
results = face_mesh.process(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
|
195 |
+
if results.multi_face_landmarks:
|
196 |
+
for face_landmarks in results.multi_face_landmarks:
|
197 |
+
points = self.get_muscle_points(task_name, face_landmarks, frame_shape)
|
198 |
+
self.draw_muscle_points(frame, points, face_landmarks, task_name)
|
199 |
+
|
200 |
+
# Write the processed frame to the output video file
|
201 |
+
out.write(frame)
|
202 |
+
|
203 |
+
cap.release()
|
204 |
+
out.release()
|
205 |
+
cv2.destroyAllWindows()
|
206 |
+
|
207 |
+
return output_path
|
208 |
+
|
209 |
+
def process_webcam(self, task_name):
|
210 |
+
cap = cv2.VideoCapture(0)
|
211 |
+
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.mp4')
|
212 |
+
output_path = temp_file.name
|
213 |
+
|
214 |
+
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
|
215 |
+
out = cv2.VideoWriter(output_path, fourcc, 20.0, (640, 480))
|
216 |
+
|
217 |
+
with self.mp_face_mesh.FaceMesh(
|
218 |
+
static_image_mode=False,
|
219 |
+
refine_landmarks=True,
|
220 |
+
max_num_faces=1,
|
221 |
+
min_detection_confidence=0.5,
|
222 |
+
min_tracking_confidence=0.5) as face_mesh:
|
223 |
+
|
224 |
+
while cap.isOpened():
|
225 |
+
ret, frame = cap.read()
|
226 |
+
if not ret:
|
227 |
+
break
|
228 |
+
frame_shape = frame.shape
|
229 |
+
results = face_mesh.process(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
|
230 |
+
if results.multi_face_landmarks:
|
231 |
+
for face_landmarks in results.multi_face_landmarks:
|
232 |
+
points = self.get_muscle_points(task_name, face_landmarks, frame_shape)
|
233 |
+
self.draw_muscle_points(frame, points, face_landmarks, task_name)
|
234 |
+
out.write(frame)
|
235 |
+
|
236 |
+
cap.release()
|
237 |
+
out.release()
|
238 |
+
cv2.destroyAllWindows()
|
239 |
+
|
240 |
+
return output_path
|
241 |
+
|
242 |
+
visualizer = CosmeticInjectionVisualizer(muscles_map, tasks_map)
|
243 |
+
|
244 |
+
def inference_image(image, task_name):
|
245 |
+
result_image = visualizer.process_image(image, task_name)
|
246 |
+
return result_image
|
247 |
+
|
248 |
+
def inference_video(video_path, task_name):
|
249 |
+
result_video_path = visualizer.process_video(video_path, task_name)
|
250 |
+
return result_video_path
|
251 |
+
|
252 |
+
def inference_webcam(task_name):
|
253 |
+
result_video_path = visualizer.process_webcam(task_name)
|
254 |
+
return result_video_path
|
255 |
+
|
256 |
+
task_names = list(tasks_map.keys())
|
257 |
+
base_path=os.getcwd()
|
258 |
+
default_image_path = os.path.join(base_path,'image.jpg')
|
259 |
+
default_video_path = os.path.join(base_path,'video.mp4')
|
260 |
+
|
261 |
+
with gr.Blocks() as demo:
|
262 |
+
gr.Markdown("# Cosmetic Injection Visualizer")
|
263 |
+
|
264 |
+
with gr.Tabs():
|
265 |
+
with gr.TabItem("Image"):
|
266 |
+
image_input = gr.Image(type="numpy", label="Input Image", value=default_image_path)
|
267 |
+
task_input_image = gr.Dropdown(choices=task_names, label="Task Name")
|
268 |
+
image_output = gr.Image(type="numpy", label="Output Image")
|
269 |
+
gr.Button("Process Image").click(inference_image, inputs=[image_input, task_input_image], outputs=image_output)
|
270 |
+
|
271 |
+
with gr.TabItem("Video"):
|
272 |
+
video_input = gr.Video(label="Input Video", value=default_video_path)
|
273 |
+
task_input_video = gr.Dropdown(choices=task_names, label="Task Name")
|
274 |
+
video_output = gr.Video(label="Output Video")
|
275 |
+
gr.Button("Process Video").click(inference_video, inputs=[video_input, task_input_video], outputs=video_output)
|
276 |
+
|
277 |
+
with gr.TabItem("Webcam"):
|
278 |
+
task_input_webcam = gr.Dropdown(choices=task_names, label="Task Name")
|
279 |
+
webcam_output = gr.Video(label="Output Video")
|
280 |
+
gr.Button("Process Webcam").click(inference_webcam, inputs=[task_input_webcam], outputs=webcam_output)
|
281 |
+
|
282 |
+
demo.launch()
|
functions.py
ADDED
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import cv2
|
2 |
+
import numpy as np
|
3 |
+
import os
|
4 |
+
|
5 |
+
def is_bgr(image):
|
6 |
+
"""
|
7 |
+
Heuristic check to see if an image is in BGR format.
|
8 |
+
This function checks if the values at a specific pixel match the expected BGR to RGB order.
|
9 |
+
"""
|
10 |
+
# Choose a pixel to check (e.g., the top-left corner)
|
11 |
+
pixel = image[0, 0]
|
12 |
+
|
13 |
+
# Check if the pixel values match BGR order
|
14 |
+
# This is a heuristic; it assumes the color channels have distinct values.
|
15 |
+
return pixel[0] > pixel[1] and pixel[1] > pixel[2]
|
16 |
+
|
17 |
+
def convert_bgr_to_rgb(image):
|
18 |
+
return cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
19 |
+
|
20 |
+
def convert_rgb_to_bgr(image):
|
21 |
+
return cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
|
22 |
+
|
23 |
+
|
24 |
+
def crop_video(input_path, output_path, x, y, width, height):
|
25 |
+
# Open the input video
|
26 |
+
cap = cv2.VideoCapture(input_path)
|
27 |
+
|
28 |
+
if not cap.isOpened():
|
29 |
+
print("Error: Could not open video.")
|
30 |
+
return
|
31 |
+
|
32 |
+
# Get the width and height of the frames
|
33 |
+
original_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
34 |
+
original_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
|
35 |
+
fps = cap.get(cv2.CAP_PROP_FPS)
|
36 |
+
|
37 |
+
# Define the codec and create VideoWriter object
|
38 |
+
fourcc = cv2.VideoWriter_fourcc(*'mp4v') # You can also use other codecs
|
39 |
+
out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
|
40 |
+
|
41 |
+
while cap.isOpened():
|
42 |
+
ret, frame = cap.read()
|
43 |
+
if not ret:
|
44 |
+
break
|
45 |
+
|
46 |
+
# Crop the frame
|
47 |
+
cropped_frame = frame[y:y+height, x:x+width]
|
48 |
+
|
49 |
+
# Write the cropped frame to the output video file
|
50 |
+
out.write(cropped_frame)
|
51 |
+
|
52 |
+
# Release everything if job is finished
|
53 |
+
cap.release()
|
54 |
+
out.release()
|
55 |
+
cv2.destroyAllWindows()
|
56 |
+
|
57 |
+
print(f"Cropping completed. Saved to {output_path}")
|
image.jpg
ADDED
![]() |
maps.py
ADDED
@@ -0,0 +1,241 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
muscles_map = {
|
2 |
+
'Corrugator Supercilii':{
|
3 |
+
'right':{
|
4 |
+
'points':[70,63,105,66,107],
|
5 |
+
'description':'',
|
6 |
+
},
|
7 |
+
'left':{
|
8 |
+
'points':[336,296,334,293,300],
|
9 |
+
'description':'',
|
10 |
+
},
|
11 |
+
},
|
12 |
+
'Procerus':{
|
13 |
+
'center':{
|
14 |
+
'points':[9,8],
|
15 |
+
'description':'',
|
16 |
+
},
|
17 |
+
},
|
18 |
+
'Medial Orbicularis Oculi':{
|
19 |
+
'right':{
|
20 |
+
'points':[221,189],
|
21 |
+
'description':'',
|
22 |
+
},
|
23 |
+
'left':{
|
24 |
+
'points':[413,441],
|
25 |
+
'description':'',
|
26 |
+
},
|
27 |
+
},
|
28 |
+
'Frontalis':{
|
29 |
+
'right':{
|
30 |
+
'superior':{
|
31 |
+
'points':[104,69,108],
|
32 |
+
'description':'',
|
33 |
+
},
|
34 |
+
'inferior':{
|
35 |
+
'points':[103,67,109],
|
36 |
+
'description':'',
|
37 |
+
},
|
38 |
+
|
39 |
+
},
|
40 |
+
'center':{
|
41 |
+
'superior':{
|
42 |
+
'points':[10],
|
43 |
+
'description':'',
|
44 |
+
},
|
45 |
+
'inferior':{
|
46 |
+
'points':[151],
|
47 |
+
'description':'',
|
48 |
+
},
|
49 |
+
|
50 |
+
},
|
51 |
+
'left':{
|
52 |
+
'superior':{
|
53 |
+
'points':[338,297,332],
|
54 |
+
'description':'',
|
55 |
+
},
|
56 |
+
'inferior':{
|
57 |
+
'points':[337,299,333],
|
58 |
+
'description':'',
|
59 |
+
},
|
60 |
+
},
|
61 |
+
},
|
62 |
+
'Lateral Orbicularis Oculi':{
|
63 |
+
'right':{
|
64 |
+
'internal':{
|
65 |
+
'points':[156,143,116],
|
66 |
+
'description':'',
|
67 |
+
},
|
68 |
+
'external':{
|
69 |
+
'points':[139,34,227],
|
70 |
+
'description':'',
|
71 |
+
},
|
72 |
+
|
73 |
+
},
|
74 |
+
'left':{
|
75 |
+
'internal':{
|
76 |
+
'points':[383,372,345],
|
77 |
+
'description':"Crow's feet",
|
78 |
+
},
|
79 |
+
'external':{
|
80 |
+
'points':[368,264,447],
|
81 |
+
'description':"Crow's feet",
|
82 |
+
},
|
83 |
+
},
|
84 |
+
},
|
85 |
+
'Lateral Superior Orbicularis Oculi':{
|
86 |
+
'right':{
|
87 |
+
'points':[224,225,113],
|
88 |
+
'description':"Eyebrow lift",
|
89 |
+
},
|
90 |
+
'left':{
|
91 |
+
'points':[444,445,342],
|
92 |
+
'description':"Eyebrow lift",
|
93 |
+
},
|
94 |
+
},
|
95 |
+
'Nasalis':{
|
96 |
+
'right':{
|
97 |
+
'points':[196,174,217],
|
98 |
+
'description':"Rabbit's lines",
|
99 |
+
},
|
100 |
+
'left':{
|
101 |
+
'points':[419,399,437],
|
102 |
+
'description':"Rabbit's lines",
|
103 |
+
},
|
104 |
+
},
|
105 |
+
'Dilator nasalis':{
|
106 |
+
'right':{
|
107 |
+
'points':[134,131],
|
108 |
+
'description':"Reduce nostril size",
|
109 |
+
},
|
110 |
+
'left':{
|
111 |
+
'points':[363,360],
|
112 |
+
'description':"Reduce nostril size",
|
113 |
+
},
|
114 |
+
},
|
115 |
+
'Depressor septi nasi':{
|
116 |
+
'center':{
|
117 |
+
'points':[2],
|
118 |
+
'description':"Nose lift",
|
119 |
+
},
|
120 |
+
},
|
121 |
+
'Depressor anguli oris':{
|
122 |
+
'right':{
|
123 |
+
'points':[202,169,149],
|
124 |
+
'description':"corner lip lift",
|
125 |
+
},
|
126 |
+
'left':{
|
127 |
+
'points':[422,394,378],
|
128 |
+
'description':"corner lip lift",
|
129 |
+
},
|
130 |
+
},
|
131 |
+
'Orbicularis':{
|
132 |
+
'right':{
|
133 |
+
'superior':{
|
134 |
+
'points':[61,185,40,39,37],
|
135 |
+
'description':'',
|
136 |
+
},
|
137 |
+
'inferior':{
|
138 |
+
'points':[61,146,91,181,84],
|
139 |
+
'description':'',
|
140 |
+
},
|
141 |
+
|
142 |
+
},
|
143 |
+
'center':{
|
144 |
+
'superior':{
|
145 |
+
'points':[0],
|
146 |
+
'description':'',
|
147 |
+
},
|
148 |
+
'inferior':{
|
149 |
+
'points':[17],
|
150 |
+
'description':'',
|
151 |
+
},
|
152 |
+
|
153 |
+
},
|
154 |
+
'left':{
|
155 |
+
'superior':{
|
156 |
+
'points':[267,269,270,409,291],
|
157 |
+
'description':'',
|
158 |
+
},
|
159 |
+
'inferior':{
|
160 |
+
'points':[314,405,321,375,291],
|
161 |
+
'description':'',
|
162 |
+
},
|
163 |
+
},
|
164 |
+
},
|
165 |
+
'Levator labii superioris alaeque nasi':{
|
166 |
+
'right':{
|
167 |
+
'points':[203],
|
168 |
+
'description':"gummy smile",
|
169 |
+
},
|
170 |
+
'left':{
|
171 |
+
'points':[423],
|
172 |
+
'description':"gummy smile",
|
173 |
+
},
|
174 |
+
},
|
175 |
+
'Mentalis':{
|
176 |
+
'right':{
|
177 |
+
'points':[171,148],
|
178 |
+
'description':"Chin crease",
|
179 |
+
},
|
180 |
+
'center':{
|
181 |
+
'points':[152],
|
182 |
+
'description':"Chin crease",
|
183 |
+
},
|
184 |
+
'left':{
|
185 |
+
'points':[396,377],
|
186 |
+
'description':"Chin crease",
|
187 |
+
},
|
188 |
+
},
|
189 |
+
}
|
190 |
+
|
191 |
+
|
192 |
+
tasks_map = {
|
193 |
+
"Gallabela crease":{
|
194 |
+
'muscles':['Corrugator Supercilii','Procerus'],
|
195 |
+
'description':"",
|
196 |
+
},
|
197 |
+
"Forehead crease":{
|
198 |
+
'muscles':['Frontalis'],
|
199 |
+
'description':"",
|
200 |
+
},
|
201 |
+
"Crow's feet crease":{
|
202 |
+
'muscles':['Lateral Orbicularis Oculi'],
|
203 |
+
'description':"",
|
204 |
+
},
|
205 |
+
"Lift of eyebrows":{
|
206 |
+
'muscles':['Lateral Superior Orbicularis Oculi'],
|
207 |
+
'description':"",
|
208 |
+
},
|
209 |
+
"Chemical lift of eyebrows":{
|
210 |
+
'muscles':['Lateral Superior Orbicularis Oculi','Corrugator Supercilii','Procerus'],
|
211 |
+
'description':"",
|
212 |
+
},
|
213 |
+
"Nose crease":{
|
214 |
+
'muscles':['Nasalis'],
|
215 |
+
'description':"",
|
216 |
+
},
|
217 |
+
"Lift of nose":{
|
218 |
+
'muscles':['Depressor septi nasi'],
|
219 |
+
'description':"",
|
220 |
+
},
|
221 |
+
"Reducing the size of nostrils":{
|
222 |
+
'muscles':['Dilator nasalis'],
|
223 |
+
'description':"",
|
224 |
+
},
|
225 |
+
"Lift of the corner of the lips":{
|
226 |
+
'muscles':['Depressor anguli oris'],
|
227 |
+
'description':"",
|
228 |
+
},
|
229 |
+
"Ciggarete crease":{
|
230 |
+
'muscles':['Orbicularis'],
|
231 |
+
'description':"",
|
232 |
+
},
|
233 |
+
"Gummy smile":{
|
234 |
+
'muscles':['Levator labii superioris alaeque nasi'],
|
235 |
+
'description':"",
|
236 |
+
},
|
237 |
+
"Chin crease":{
|
238 |
+
'muscles':['Mentalis'],
|
239 |
+
'description':"",
|
240 |
+
},
|
241 |
+
}
|
requirements.txt
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
gradio
|
2 |
+
opencv-python-headless
|
3 |
+
mediapipe
|
4 |
+
numpy
|