Akjava commited on
Commit
58665c8
1 Parent(s): 404180f
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ *.task filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ __pycache__
2
+ files
app.py ADDED
@@ -0,0 +1,250 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import spaces
2
+ import gradio as gr
3
+ import subprocess
4
+ from PIL import Image
5
+ import json
6
+ import os
7
+ import time
8
+
9
+ import mp_box
10
+ import draw_landmarks68
11
+ import landmarks68_utils
12
+ import io
13
+ import numpy as np
14
+ '''
15
+ Face landmark detection based Face Detection.
16
+ https://ai.google.dev/edge/mediapipe/solutions/vision/face_landmarker
17
+ from model card
18
+ https://storage.googleapis.com/mediapipe-assets/MediaPipe%20BlazeFace%20Model%20Card%20(Short%20Range).pdf
19
+ Licensed Apache License, Version 2.0
20
+ Train with google's dataset(more detail see model card)
21
+
22
+ '''
23
+
24
+ dir_name ="files"
25
+ passed_time = 60*60
26
+ def clear_old_files(dir,passed_time):
27
+ try:
28
+ files = os.listdir(dir)
29
+ current_time = time.time()
30
+ for file in files:
31
+ file_path = os.path.join(dir,file)
32
+
33
+ ctime = os.stat(file_path).st_ctime
34
+ diff = current_time - ctime
35
+ #print(f"ctime={ctime},current_time={current_time},passed_time={passed_time},diff={diff}")
36
+ if diff > passed_time:
37
+ os.remove(file_path)
38
+ except:
39
+ print("maybe still gallery using error")
40
+
41
+ def get_image_id(image,length=32):
42
+ buffer = io.BytesIO()
43
+ image.save(buffer, format='PNG')
44
+ hash_object = hashlib.sha256(buffer.getvalue())
45
+ hex_dig = hash_object.hexdigest()
46
+ unique_id = hex_dig[:length]
47
+ return unique_id
48
+
49
+ def save_image(image,extension="jpg"):
50
+ id = get_image_id(image)
51
+ os.makedirs(dir_name,exist_ok=True)
52
+ file_path = f"{dir_name}/{id}.{extension}"
53
+
54
+ image.save(file_path)
55
+ return file_path
56
+
57
+ def picker_color_to_rgba(picker_color):
58
+ color_value = picker_color.strip("rgba()").split(",")
59
+ color_value[0] = int(float(color_value[0]))
60
+ color_value[1] = int(float(color_value[1]))
61
+ color_value[2] = int(float(color_value[2]))
62
+ color_value[3] = int(float(color_value[3]))
63
+ return color_value
64
+
65
+ #@spaces.GPU(duration=120)
66
+ def process_images(image,progress=gr.Progress(track_tqdm=True)):
67
+ if image == None:
68
+ raise gr.Error("Need Image")
69
+
70
+ progress(0, desc="Start Mediapipe")
71
+
72
+ boxes,mp_image,face_landmarker_result = mp_box.mediapipe_to_box(image)
73
+ annotated_image,bbox,landmark_points = draw_landmarks68.draw_landmarks_on_image(image,face_landmarker_result)
74
+ landmark_list = draw_landmarks68.convert_to_landmark_group_json(landmark_points)
75
+
76
+ annotations = []
77
+ galleries = []
78
+
79
+ def append(mask,label):
80
+ file_path = save_image(mask)
81
+ galleries.append((file_path,label))
82
+ annotations.append((np.array(mask.convert("1")),label))
83
+
84
+ def fill_points(points,base_image=None):
85
+ if base_image == None:
86
+ base_image = landmarks68_utils.create_color_image(image.width,image.height,(0,0,0))
87
+ landmarks68_utils.fill_points(base_image,points)
88
+ return base_image
89
+
90
+ # TODO support type
91
+ left_eye_points = landmarks68_utils.get_landmark_points(landmark_list,landmarks68_utils.PARTS_LEFT_EYE)
92
+ right_eye_points = landmarks68_utils.get_landmark_points(landmark_list,landmarks68_utils.PARTS_RIGHT_EYE)
93
+ eyes_mask = fill_points(left_eye_points)
94
+ eyes_mask = fill_points(right_eye_points,eyes_mask)
95
+ append(eyes_mask,"eyes")
96
+
97
+
98
+ upper_lip_points = landmarks68_utils.get_landmark_points(landmark_list,landmarks68_utils.PARTS_UPPER_LIP)
99
+ upper_lip_mask = fill_points(upper_lip_points)
100
+ append(upper_lip_mask,"upper-lip")
101
+
102
+ lower_lip_points = landmarks68_utils.get_landmark_points(landmark_list,landmarks68_utils.PARTS_LOWER_LIP)
103
+ lower_lip_mask = fill_points(lower_lip_points)
104
+ append(lower_lip_mask,"lower-lip")
105
+
106
+ inner_mouth_points = landmarks68_utils.get_innner_mouth_points(landmark_list)
107
+ inner_mouth_mask = fill_points(inner_mouth_points)
108
+ append(inner_mouth_mask,"inner-mouth")
109
+
110
+
111
+ # TODO support type
112
+ contour_points = landmarks68_utils.get_landmark_points(landmark_list,landmarks68_utils.PARTS_CONTOUR)
113
+
114
+ contour_points=landmarks68_utils.get_face_points(landmark_list)
115
+
116
+ contour_mask = fill_points(contour_points)
117
+ append(contour_mask,"contour")
118
+
119
+ mixed = Image.composite(eyes_mask,upper_lip_mask,eyes_mask.convert("L"))
120
+ mixed = Image.composite(mixed,lower_lip_mask,mixed.convert("L"))
121
+ mixed = Image.composite(mixed,inner_mouth_mask,mixed.convert("L"))
122
+ append(mixed,"mixed")
123
+
124
+ return [image,annotations],galleries
125
+
126
+
127
+ def write_file(file_path,text):
128
+ with open(file_path, 'w', encoding='utf-8') as f:
129
+ f.write(text)
130
+
131
+ def read_file(file_path):
132
+ """read the text of target file
133
+ """
134
+ with open(file_path, 'r', encoding='utf-8') as f:
135
+ content = f.read()
136
+
137
+ return content
138
+
139
+ css="""
140
+ #col-left {
141
+ margin: 0 auto;
142
+ max-width: 640px;
143
+ }
144
+ #col-right {
145
+ margin: 0 auto;
146
+ max-width: 640px;
147
+ }
148
+ .grid-container {
149
+ display: flex;
150
+ align-items: center;
151
+ justify-content: center;
152
+ gap:10px
153
+ }
154
+
155
+ .image {
156
+ width: 128px;
157
+ height: 128px;
158
+ object-fit: cover;
159
+ }
160
+
161
+ .text {
162
+ font-size: 16px;
163
+ }
164
+ """
165
+
166
+ #css=css,
167
+
168
+ import hashlib
169
+
170
+ def text_to_sha256(text):
171
+ text_bytes = text.encode('utf-8')
172
+ hash_object = hashlib.sha256()
173
+ hash_object.update(text_bytes)
174
+ sha256_hex = hash_object.hexdigest()
175
+ return sha256_hex
176
+
177
+
178
+ def create_json_download(text):
179
+ file_id = f"{dir_name}/landmark_{text_to_sha256(text)[:32]}.json"
180
+ write_file(file_id,text)
181
+ # try to save
182
+ return file_id
183
+
184
+ with gr.Blocks(css=css, elem_id="demo-container") as demo:
185
+ with gr.Column():
186
+ gr.HTML(read_file("demo_header.html"))
187
+ gr.HTML(read_file("demo_tools.html"))
188
+ with gr.Row():
189
+ with gr.Column():
190
+ image = gr.Image(height=800,sources=['upload','clipboard'],image_mode='RGB',elem_id="image_upload", type="pil", label="Upload")
191
+ with gr.Row(elem_id="prompt-container", equal_height=False):
192
+ with gr.Row():
193
+ btn = gr.Button("Create Landmark 68 Mask", elem_id="run_button",variant="primary")
194
+
195
+ with gr.Accordion(label="Advanced Settings", open=False):
196
+ with gr.Row( equal_height=True):
197
+ draw_number = gr.Checkbox(label="draw Number")
198
+
199
+ font_scale = gr.Slider(
200
+ label="Font Scale",
201
+ minimum=0.1,
202
+ maximum=2,
203
+ step=0.1,
204
+ value=0.5)
205
+
206
+ text_color = gr.ColorPicker(value="rgba(200,200,200,1)",label="text color")
207
+ #square_shape = gr.Checkbox(label="Square shape")
208
+ with gr.Row( equal_height=True):
209
+
210
+ line_color = gr.ColorPicker(value="rgba(0,0,255,1)",label="line color")
211
+ line_size = gr.Slider(
212
+ label="Line Size",
213
+ minimum=0,
214
+ maximum=20,
215
+ step=1,
216
+ value=1)
217
+ with gr.Row( equal_height=True):
218
+ dot_color = gr.ColorPicker(value="rgba(255,0,0,1)",label="dot color")
219
+ dot_size = gr.Slider(
220
+ label="Dot Size",
221
+ minimum=0,
222
+ maximum=40,
223
+ step=1,
224
+ value=3)
225
+ with gr.Row( equal_height=True):
226
+ box_color = gr.ColorPicker(value="rgba(200,200,200,1)",label="box color")
227
+ box_size = gr.Slider(
228
+ label="Box Size",
229
+ minimum=0,
230
+ maximum=20,
231
+ step=1,
232
+ value=1)
233
+ with gr.Row( equal_height=True):
234
+ json_format = gr.Radio(choices=["raw","face-detection"],value="face-detection",label="json-output format")
235
+
236
+ with gr.Column():
237
+ image_out = gr.AnnotatedImage(label="Output", elem_id="output-img")
238
+ image_gallery = gr.Gallery(label="masks",preview=True)
239
+ #download_button.click(fn=json_download,inputs=text_out,outputs=download_button)
240
+
241
+
242
+ btn.click(fn=process_images, inputs=[image],outputs=[image_out,image_gallery] ,api_name='infer')
243
+ gr.Examples(
244
+ examples =["examples/00003245_00.jpg","examples/00004200.jpg","examples/00002200.jpg","examples/00005259.jpg","examples/00018022.jpg","examples/img-above.jpg","examples/img-below.jpg","examples/img-side.jpg"],
245
+ inputs=[image]
246
+ )
247
+ gr.HTML(read_file("demo_footer.html"))
248
+
249
+ if __name__ == "__main__":
250
+ demo.launch()
demo_footer.html ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ <div>
2
+ <P> Images are generated with <a href="https://huggingface.co/black-forest-labs/FLUX.1-schnell">FLUX.1-schnell</a> and licensed under <a href="http://www.apache.org/licenses/LICENSE-2.0">the Apache 2.0 License</a>
3
+ </div>
demo_header.html ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div style="text-align: center;">
2
+ <h1>
3
+ Mediapipe 68-points facial landmark
4
+ </h1>
5
+ <div class="grid-container">
6
+ <img src="https://akjava.github.io/AIDiagramChatWithVoice-FaceCharacter/webp/128/00191245_09_00002200.webp" alt="Mediapipe Face Detection" class="image">
7
+
8
+ <p class="text">
9
+ This Space use <a href="http://www.apache.org/licenses/LICENSE-2.0">the Apache 2.0</a> Licensed <a href="https://ai.google.dev/edge/mediapipe/solutions/vision/face_landmarker">Mediapipe FaceLandmarker</a> <br>
10
+ One of json format is from MIT licensed <a href="https://github.com/ageitgey/face_recognition">face_recognition</a><br>
11
+ I should clarify because it is confusing: I'm not using dlib's non-MIT licensed 68-point model at all.<br>
12
+ Contour points are not point-to-point mapping,because when face rotated some point move inside.<br>
13
+ Most of points are always divided equal for balancing when face rotated<br>
14
+ </p>
15
+ </div>
16
+
17
+ </div>
demo_tools.html ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ <div style="text-align: center;">
2
+ <p><a href="https://huggingface.co/spaces/Akjava/mediapipe-face-detect">Mediapipe Face detector</a></p>
3
+ <p></p>
4
+ </div>
draw_landmarks68.py ADDED
@@ -0,0 +1,516 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import mediapipe as mp
3
+ from mediapipe.tasks import python
4
+ from mediapipe.tasks.python import vision
5
+ from mediapipe.framework.formats import landmark_pb2
6
+ from mediapipe import solutions
7
+ import numpy as np
8
+ import time
9
+ import cv2
10
+ import argparse
11
+ import os
12
+ import math
13
+
14
+ # modified in gradio
15
+
16
+ from mp_constants import *
17
+ from mp_utils import divide_line_to_points,points_to_bbox,expand_bbox
18
+
19
+ import logging
20
+
21
+ # for share lib,TODO make module
22
+ #import sys
23
+ #sys.path.append("C:\\Users\\owner\\Documents\\pythons\\glibvision")
24
+ from glibvision.glandmark_utils import bbox_to_glandmarks,convert_to_landmark_group_json
25
+ from glibvision.cv2_utils import draw_bbox,plot_points,set_plot_text
26
+
27
+ def parse_arguments():
28
+ """
29
+ 引数
30
+
31
+ """
32
+ parser = argparse.ArgumentParser(
33
+ description="draw 68 points"
34
+ )
35
+ parser.add_argument(
36
+ "--input_file","-i",required=True,help="Input file"
37
+ )
38
+ parser.add_argument(
39
+ "--model_path","-m",default="face_landmarker.task",help="model path"
40
+ )
41
+ parser.add_argument(
42
+ "--save_glandmark","-g",action="store_true",help="save godot-landmark json"
43
+ )
44
+ parser.add_argument(
45
+ "--save_group_landmark","-landmark",action="store_true",help="save group-landmark json"
46
+ )
47
+ return parser.parse_args()
48
+
49
+
50
+
51
+
52
+
53
+ def draw_landmarks_on_image(rgb_image, detection_result,draw_number=True,font_scale=0.5,text_color=(200,200,200),dot_size=3,dot_color=(255,0,0),line_size=1,line_color=(0,0,355),box_size=1,box_color=(200,200,200)):
54
+ #print(f"dot_size={dot_size},dot_color={dot_color},line_size={line_size},line_color={line_color}")
55
+ image_width,iamge_height = rgb_image.size
56
+ face_landmarks_list = detection_result.face_landmarks
57
+ annotated_image = np.copy(rgb_image)
58
+
59
+ def get_cordinate(index):
60
+ x=face_landmarks_list[0][index].x
61
+ y=face_landmarks_list[0][index].y
62
+ return x,y
63
+
64
+ def get_distance(x1,y1,x2,y2):
65
+ return math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
66
+
67
+ def get_centers():
68
+ center_indices =[
69
+ #(POINT_LEFT_HEAD_OUTER,POINT_RIGHT_HEAD_OUTER,POINT_FOREHEAD_TOP),
70
+ #(POINT_LEFT_HEAD_OUTER,POINT_RIGHT_HEAD_OUTER,POINT_CHIN_BOTTOM),
71
+ [POINT_NOSE_CENTER_MIDDLE],
72
+ #[POINT_LOWER_LIP_CENTER_BOTTOM]
73
+ #(POINT_UPPER_LIP_CENTER_BOTTOM,POINT_LOWER_LIP_CENTER_TOP)
74
+ ]
75
+ centers = []
76
+ for indices in center_indices:
77
+ total_x = 0
78
+ total_y = 0
79
+ for index in indices:
80
+ x,y = get_cordinate(index)
81
+ total_x+=x
82
+ total_y+=y
83
+ centers.append ((total_x/len(indices),total_y/len(indices)))
84
+ return centers
85
+
86
+ centers = get_centers()
87
+ for center in centers:
88
+ center_x,center_y = center
89
+
90
+ pt = int(center_x*image_width),int(center_y*iamge_height)
91
+
92
+ #cv2.circle(annotated_image,pt,20,(0,0,255),-1)
93
+
94
+ def get_closed_center(x,y):
95
+ closed = None
96
+ closed_distance = 0
97
+ for center in centers:
98
+ distance = get_distance(center[0],center[1],x,y)
99
+ if closed == None:
100
+ closed = center
101
+ closed_distance = distance
102
+ else:
103
+ if distance<closed_distance:
104
+ closed_distance = distance
105
+ closed = center
106
+ return closed
107
+
108
+
109
+ #landmark is [index-upper,index-lower]
110
+ def get_mean_point(landmark,width=image_width,height=iamge_height):
111
+ xs=[]
112
+ ys=[]
113
+ for index in landmark:
114
+ x,y = get_cordinate(index) #inner cordinate
115
+ xs.append(x)
116
+ ys.append(y)
117
+
118
+ return int(np.mean(xs)*width),int(np.mean(ys)*height)
119
+
120
+ def get_cordinate_point(landmark,width=image_width,height=iamge_height):
121
+ point = get_cordinate(landmark)
122
+
123
+ return int(point[0]*width),int(point[1]*height)
124
+ # TODO rename and explain this is for contour choose most outer point
125
+ def get_point(landmark,width=image_width,height=iamge_height):
126
+ xs=[]
127
+ ys=[]
128
+
129
+
130
+ def get_outer_point(indexes):
131
+ outer_point = None
132
+ max_distance = None
133
+ if len(indexes) == 0:
134
+ return None
135
+
136
+ ratio = 0.5
137
+ x,y = get_cordinate(indexes[-1]) #on contour 3 lines outer,center,inner cordinate
138
+
139
+ #x,y = get_cordinate(indexes[0])
140
+ center_x,center_y = get_closed_center(x,y)
141
+ x-=(center_x-x)*ratio
142
+ y-=(center_y-y)*ratio
143
+
144
+ outer_x = x
145
+ outer_y = y
146
+
147
+ for index in indexes:
148
+ x,y = get_cordinate(index)
149
+
150
+ distance = get_distance(outer_x,outer_y,x,y)
151
+ #print(f"{distance} index={index} x={x},y={y}")
152
+ if outer_point == None:
153
+ outer_point = (x,y)
154
+ max_distance = distance
155
+ else:
156
+ if distance<max_distance:
157
+ outer_point = (x,y)
158
+ return outer_point
159
+
160
+
161
+
162
+ for group in landmark:
163
+ outer_point = get_outer_point(group)
164
+ xs.append(outer_point[0])
165
+ ys.append(outer_point[1])
166
+
167
+
168
+ return int(np.mean(xs)*width),int(np.mean(ys)*height)
169
+
170
+ # Loop through the detected faces to visualize.
171
+ for idx in range(len(face_landmarks_list)):
172
+ face_landmarks = face_landmarks_list[idx]
173
+
174
+ # Draw the face landmarks. #something change format
175
+ face_landmarks_proto = landmark_pb2.NormalizedLandmarkList()
176
+ face_landmarks_proto.landmark.extend([
177
+ landmark_pb2.NormalizedLandmark(x=landmark.x, y=landmark.y, z=landmark.z) for landmark in face_landmarks
178
+ ])
179
+
180
+
181
+ def draw_sets(draw_set,color=(0,255,0)):
182
+ solutions.drawing_utils.draw_landmarks(
183
+ image=annotated_image,
184
+ landmark_list=face_landmarks_proto,
185
+ connections=draw_set,
186
+ landmark_drawing_spec=None,
187
+ connection_drawing_spec=mp.solutions.drawing_styles.DrawingSpec(color=color, thickness=1 ))
188
+ def draw_triangle(index1,index2,index3):
189
+ draw_sets({(index1,index2),(index2,index3),(index3,index1)})
190
+
191
+ def draw_lines(array,color=(0,0,128)):
192
+ my_set = set()
193
+ for i in range(len(array)-1):
194
+ v = (array[i],array[i+1])
195
+ my_set.add(v)
196
+ draw_sets(my_set,color)
197
+
198
+ def convert_to_box(face_landmarks_list,indices,w=1024,h=1024):
199
+ x1=0
200
+ y1=0
201
+ x2=w
202
+ y2=h
203
+ for index in indices:
204
+ x=min(w,max(0,(face_landmarks_list[0][index].x*w)))
205
+ y=min(h,max(0,(face_landmarks_list[0][index].y*h)))
206
+ if x>x1:
207
+ x1=x
208
+ if y>y1:
209
+ y1=y
210
+
211
+ if x<x2:
212
+ x2=x
213
+ if y<y2:
214
+ y2=y
215
+
216
+ return [x1,y1,x2-x1,y2-y1]
217
+
218
+
219
+ my_set ={(362,382),(382,398),(398,362)}
220
+ my_set = mp.solutions.face_mesh.FACEMESH_RIGHT_EYE
221
+
222
+ #mediapipe to 5point
223
+ """
224
+ draw_triangle(362,382,398)
225
+ draw_triangle(173,133,155)
226
+ draw_triangle(33,246,7)
227
+ draw_triangle(249,263,466)
228
+
229
+ draw_triangle(94,2,164)
230
+
231
+ draw_triangle(61,76,61)
232
+ draw_triangle(291,306,291)
233
+
234
+ draw_lines([17,18,200,199,175,152])
235
+
236
+ draw_lines([127,234,93,132,58,172,136,150,149,176,148,152],(255,0,0))
237
+ #draw_lines([127,234,132,172,150,176,152],(0,0,255))
238
+ """
239
+
240
+ #
241
+ #draw_lines([9,107])
242
+ """
243
+ draw_lines([148,171,208])
244
+ draw_lines([176,140])
245
+ draw_lines([149,170,211])
246
+ draw_lines([150,169,])
247
+
248
+ draw_lines([150,169])
249
+ draw_lines([136,135,214])
250
+ draw_lines([172,138,192])
251
+ draw_lines([58,215])
252
+ draw_lines([132,177,147])
253
+ draw_lines([58,215,213])
254
+ draw_lines([93,137,123])
255
+ #draw_lines([234,227])
256
+ #draw_lines([127,34,143])
257
+
258
+ """
259
+ #draw_lines([378,288,356,251,151,21,127,58,150,152])
260
+ #draw_lines(LINE_RIGHT_CONTOUR_OUTER_EYE_TO_CHIN)
261
+ #draw_lines(LINE_RIGHT_CONTOUR_EYE_TO_CHIN)
262
+ #draw_lines(LINE_RIGHT_CONTOUR_INNER_EYE_TO_CHIN,(0,255,0))
263
+ """
264
+ draw_lines(LINE_RIGHT_CONTOUR_0)
265
+ draw_lines(LINE_RIGHT_CONTOUR_1)
266
+ draw_lines(LINE_RIGHT_CONTOUR_2)
267
+ draw_lines(LINE_RIGHT_CONTOUR_3)
268
+ draw_lines(LINE_RIGHT_CONTOUR_4)
269
+ draw_lines(LINE_RIGHT_CONTOUR_5)
270
+ draw_lines(LINE_RIGHT_CONTOUR_6)
271
+ draw_lines(LINE_RIGHT_CONTOUR_7)
272
+ draw_lines(LINE_RIGHT_CONTOUR_8)
273
+ draw_lines(LINE_RIGHT_CONTOUR_9)
274
+ draw_lines(LINE_RIGHT_CONTOUR_10)
275
+ draw_lines(LINE_RIGHT_CONTOUR_11)
276
+
277
+
278
+ draw_lines(LINE_LEFT_CONTOUR_1)
279
+ draw_lines(LINE_LEFT_CONTOUR_2)
280
+ draw_lines(LINE_LEFT_CONTOUR_3)
281
+ draw_lines(LINE_LEFT_CONTOUR_4)
282
+ draw_lines(LINE_LEFT_CONTOUR_5)
283
+ draw_lines(LINE_LEFT_CONTOUR_6)
284
+ draw_lines(LINE_LEFT_CONTOUR_7)
285
+ draw_lines(LINE_LEFT_CONTOUR_8)
286
+ draw_lines(LINE_LEFT_CONTOUR_9)
287
+ draw_lines(LINE_LEFT_CONTOUR_10)
288
+ draw_lines(LINE_LEFT_CONTOUR_11)
289
+ #draw_lines(LINE_LEFT_CONTOUR_12)
290
+ """
291
+
292
+ #draw_lines(LINE_RIGHT_CONTOUR_6,(255,0,0))
293
+
294
+ def get_eye_brow_points(landmarks):
295
+ result_points= []
296
+ for landmark in landmarks:
297
+ point=get_mean_point(landmark)
298
+ result_points.append(point)
299
+
300
+ return result_points
301
+
302
+ def get_mean_points(landmarks):
303
+ result_points= []
304
+ for landmark in landmarks:
305
+ point=get_mean_point(landmark)
306
+ result_points.append(point)
307
+
308
+ return result_points
309
+
310
+ def get_divided_points(landmarks,divided=3):
311
+ result_points= []
312
+ landmark_points = []
313
+ for landmark in landmarks:
314
+ if isinstance(landmark, int):
315
+ pt=get_cordinate_point(landmark)
316
+ else:
317
+ pt =get_mean_point(landmark)
318
+ landmark_points.append(pt)
319
+
320
+ divided_points = divide_line_to_points(landmark_points,divided)
321
+
322
+ #print(centers[0][0]*1024,",",centers[0][1]*1024)
323
+ return divided_points
324
+
325
+
326
+ def get_half_contour(landmarks):
327
+ result_points= []
328
+ landmark_points = []
329
+ for landmark in landmarks:
330
+ pt =get_point(landmark)
331
+ landmark_points.append(pt)
332
+
333
+ divided_points = divide_line_to_points(landmark_points,8)#9
334
+ #for pt in divided_points:
335
+ # cv2.circle(annotated_image,pt,3,(255,0,0),-1)
336
+ # result_points.append((pt[0],pt[1]))
337
+
338
+ #print(centers[0][0]*1024,",",centers[0][1]*1024)
339
+ return divided_points
340
+
341
+ right_landmarks =[
342
+ #[LANDMARK_68_CONTOUR_5]
343
+ [LANDMARK_68_CONTOUR_1],[LANDMARK_68_CONTOUR_2_PART1,LANDMARK_68_CONTOUR_2_PART2],[LANDMARK_68_CONTOUR_3],[LANDMARK_68_CONTOUR_4],[LANDMARK_68_CONTOUR_5],[LANDMARK_68_CONTOUR_6_PART1,LANDMARK_68_CONTOUR_6_PART2],[LANDMARK_68_CONTOUR_7],[LANDMARK_68_CONTOUR_8_PART1,LANDMARK_68_CONTOUR_8_PART2],[LANDMARK_68_CONTOUR_9],
344
+
345
+ ]
346
+ contour_right_points=get_half_contour(right_landmarks)
347
+
348
+ left_landmarks =[
349
+ [LANDMARK_68_CONTOUR_9], [LINE_LEFT_CONTOUR_1], [LINE_LEFT_CONTOUR_2], [LINE_LEFT_CONTOUR_3], [LINE_LEFT_CONTOUR_4],[LINE_LEFT_CONTOUR_5],[LINE_LEFT_CONTOUR_6],[LINE_LEFT_CONTOUR_7],[LINE_LEFT_CONTOUR_8],[LINE_LEFT_CONTOUR_9],[LINE_LEFT_CONTOUR_10],[LINE_LEFT_CONTOUR_11]
350
+ ]
351
+ contour_left_points=get_half_contour(left_landmarks)
352
+
353
+ set_plot_text(draw_number,font_scale,text_color) # for reset
354
+ plot_points(annotated_image,contour_right_points+contour_left_points[1:],False,dot_size,dot_color,line_size,line_color)
355
+
356
+ right_eye_brow_points=get_eye_brow_points([
357
+ LANDMARK_68_RIGHT_EYEBROW_18,LANDMARK_68_RIGHT_EYEBROW_19,LANDMARK_68_RIGHT_EYEBROW_20,LANDMARK_68_RIGHT_EYEBROW_21,LANDMARK_68_RIGHT_EYEBROW_22
358
+ ])
359
+ plot_points(annotated_image,right_eye_brow_points,False,dot_size,dot_color,line_size,line_color)
360
+ left_eye_brow_points=get_eye_brow_points([
361
+ LANDMARK_68_LEFT_EYEBROW_23,LANDMARK_68_LEFT_EYEBROW_24,LANDMARK_68_LEFT_EYEBROW_25,LANDMARK_68_LEFT_EYEBROW_26,LANDMARK_68_LEFT_EYEBROW_27
362
+ ])
363
+ plot_points(annotated_image,left_eye_brow_points,False,dot_size,dot_color,line_size,line_color)
364
+
365
+ vertical_nose_points = get_divided_points([LANDMARK_68_VERTICAL_NOSE_28,LANDMARK_68_VERTICAL_NOSE_29,LANDMARK_68_VERTICAL_NOSE_30,LANDMARK_68_VERTICAL_NOSE_31],3)
366
+ plot_points(annotated_image,vertical_nose_points,False,dot_size,dot_color,line_size,line_color)
367
+
368
+ horizontal_nose_points = get_mean_points([LANDMARK_68_HORIZONTAL_NOSE_32,LANDMARK_68_HORIZONTAL_NOSE_33,LANDMARK_68_HORIZONTAL_NOSE_34,LANDMARK_68_HORIZONTAL_NOSE_35,LANDMARK_68_HORIZONTAL_NOSE_36])
369
+ plot_points(annotated_image,horizontal_nose_points,False,dot_size,dot_color,line_size,line_color)
370
+
371
+ right_upper_eye_points = get_divided_points(LINE_RIGHT_UPPER_MIXED_EYE2,3)
372
+ right_lower_eye_points = get_divided_points(LINE_RIGHT_LOWER_MIXED_EYE,3)
373
+ #right_eye_points = right_upper_eye_points+right_lower_eye_points # first and last is same as above
374
+ right_eye_points = right_upper_eye_points+right_lower_eye_points[1:-1]
375
+ plot_points(annotated_image,right_eye_points,True,dot_size,dot_color,line_size,line_color)
376
+
377
+ #draw_lines(LINE_RIGHT_LOWER_OUTER_EYE,(0,255,0))
378
+ #draw_lines(LINE_RIGHT_LOWER_INNER_EYE,(0,255,0))
379
+ #draw_lines(LINE_RIGHT_UPPER_OUTER_EYE,(0,255,0))
380
+ #draw_lines(LINE_RIGHT_UPPER_INNER_EYE,(0,255,0))
381
+
382
+ left_upper_eye_points = get_divided_points(LINE_LEFT_UPPER_MIXED_EYE2,3)
383
+ left_lower_eye_points = get_divided_points(LINE_LEFT_LOWER_MIXED_EYE,3)
384
+ #left_eye_points = left_upper_eye_points+left_lower_eye_points# first and last is same as above
385
+ left_eye_points = left_upper_eye_points+left_lower_eye_points[1:-1]
386
+ plot_points(annotated_image,left_eye_points,True,dot_size,dot_color,line_size,line_color)
387
+ # first and last is same as above
388
+
389
+ #draw_lines(LINE_LEFT_LOWER_OUTER_EYE,(0,255,0))
390
+ #draw_lines(LINE_LEFT_LOWER_INNER_EYE,(0,255,0))
391
+ #draw_lines(LINE_LEFT_UPPER_OUTER_EYE,(0,255,0))
392
+ #draw_lines(LINE_LEFT_UPPER_INNER_EYE,(0,255,0))
393
+
394
+ left_upper_outer_lip_points = get_divided_points(LINE_RIGHT_UPPER_OUTER_LIP,3)
395
+ right_upper_outer_lip_points = get_divided_points(LINE_LEFT_UPPER_OUTER_LIP,3)
396
+ upper_outer_lip_points = left_upper_outer_lip_points+right_upper_outer_lip_points[1:]# first and last is same as above
397
+ #plot_points(annotated_image,upper_outer_lip_points)
398
+ upper_outer_lip_points = get_mean_points([LANDMARK_68_UPPER_OUTER_LIP_49,LANDMARK_68_UPPER_OUTER_LIP_50,LANDMARK_68_UPPER_OUTER_LIP_51,LANDMARK_68_UPPER_OUTER_LIP_52,LANDMARK_68_UPPER_OUTER_LIP_53,LANDMARK_68_UPPER_OUTER_LIP_54,LANDMARK_68_UPPER_OUTER_LIP_55])
399
+ #plot_points(annotated_image,upper_outer_lip_points)
400
+
401
+ lower_outer_lip_points = get_mean_points([LANDMARK_68_UPPER_OUTER_LIP_55,LANDMARK_68_LOWER_OUTER_LIP_56,LANDMARK_68_LOWER_OUTER_LIP_57,LANDMARK_68_LOWER_OUTER_LIP_58,LANDMARK_68_LOWER_OUTER_LIP_59,LANDMARK_68_LOWER_OUTER_LIP_60,LANDMARK_68_UPPER_OUTER_LIP_49])
402
+ outer_lip_points = upper_outer_lip_points+lower_outer_lip_points[1:-1]
403
+ plot_points(annotated_image,outer_lip_points,True,dot_size,dot_color,line_size,line_color)
404
+
405
+ upper_inner_lip_points = get_mean_points([LANDMARK_68_UPPER_INNER_LIP_61,LANDMARK_68_UPPER_INNER_LIP_62,LANDMARK_68_UPPER_INNER_LIP_63,LANDMARK_68_UPPER_INNER_LIP_64,LANDMARK_68_UPPER_INNER_LIP_65])
406
+ #plot_points(annotated_image,upper_inner_lip_points)
407
+
408
+ lower_inner_lip_points = get_mean_points([LANDMARK_68_UPPER_INNER_LIP_65,LANDMARK_68_LOWER_INNER_LIP_66,LANDMARK_68_LOWER_INNER_LIP_67,LANDMARK_68_LOWER_INNER_LIP_68,LANDMARK_68_UPPER_INNER_LIP_61])
409
+ inner_lip_points = upper_inner_lip_points+lower_inner_lip_points[1:-1]
410
+ plot_points(annotated_image,inner_lip_points,True,dot_size,dot_color,line_size,line_color)
411
+
412
+ landmark_points = contour_right_points+contour_left_points[1:]
413
+ landmark_points += right_eye_brow_points + left_eye_brow_points
414
+ landmark_points += vertical_nose_points + horizontal_nose_points
415
+ landmark_points += right_eye_points + left_eye_points
416
+ landmark_points += outer_lip_points + inner_lip_points
417
+
418
+ #plot_points(annotated_image,landmark_points,20) # for debug
419
+ bbox = points_to_bbox(landmark_points)
420
+ bbox = expand_bbox(bbox,5,7,5,5)
421
+
422
+ draw_bbox(annotated_image,bbox,box_color,box_size)
423
+ #draw_lines([POINT_LEFT_HEAD_OUTER_EX,POINT_LEFT_EYE_OUTER_EX,POINT_LEFT_MOUTH_OUTER_EX,POINT_LEFT_CHIN_OUTER,POINT_CHIN_BOTTOM])
424
+ #draw_lines([LANDMARK_68_CONTOUR_1,LANDMARK_68_CONTOUR_2,LANDMARK_68_CONTOUR_3,LANDMARK_68_CONTOUR_4,LANDMARK_68_CONTOUR_5,LANDMARK_68_CONTOUR_6,LANDMARK_68_CONTOUR_7,LANDMARK_68_CONTOUR_8,LANDMARK_68_CONTOUR_9])
425
+ """solutions.drawing_utils.draw_landmarks(
426
+ image=annotated_image,
427
+ landmark_list=face_landmarks_proto,
428
+ connections=mp.solutions.face_mesh.FACEMESH_LEFT_EYE,#FACE_OVAL
429
+ landmark_drawing_spec=None,
430
+ connection_drawing_spec=mp.solutions.drawing_styles
431
+ .get_default_face_mesh_contours_style())"""
432
+
433
+ """solutions.drawing_utils.draw_landmarks(
434
+ image=annotated_image,
435
+ landmark_list=face_landmarks_proto,
436
+ connections=mp.solutions.face_mesh.FACEMESH_CONTOURS,# mix all
437
+ landmark_drawing_spec=None,
438
+ connection_drawing_spec=mp.solutions.drawing_styles
439
+ .get_default_face_mesh_contours_style())
440
+ """
441
+ """solutions.drawing_utils.draw_landmarks(
442
+ image=annotated_image,
443
+ landmark_list=face_landmarks_proto,
444
+ connections=mp.solutions.face_mesh.FACEMESH_IRISES,
445
+ landmark_drawing_spec=None,
446
+ connection_drawing_spec=mp.solutions.drawing_styles
447
+ .get_default_face_mesh_iris_connections_style()) """
448
+
449
+ return annotated_image,bbox,landmark_points
450
+
451
+
452
+ if __name__ == "__main__":
453
+ args = parse_arguments()
454
+ input_file = args.input_file
455
+
456
+ #file checks
457
+ if not os.path.isfile(input_file):
458
+ print(f"input is not file '{input_file}'")
459
+ exit(0)
460
+
461
+ model_path = args.model_path
462
+
463
+ BaseOptions = mp.tasks.BaseOptions
464
+ FaceLandmarker = mp.tasks.vision.FaceLandmarker
465
+ FaceLandmarkerOptions = mp.tasks.vision.FaceLandmarkerOptions
466
+ VisionRunningMode = mp.tasks.vision.RunningMode
467
+
468
+ options = FaceLandmarkerOptions(
469
+ base_options=BaseOptions(model_asset_path=model_path),
470
+ running_mode=VisionRunningMode.IMAGE
471
+ ,min_face_detection_confidence=0, min_face_presence_confidence=0
472
+ )
473
+
474
+
475
+ with FaceLandmarker.create_from_options(options) as landmarker:
476
+
477
+ start = time.time()
478
+ mp_image = mp.Image.create_from_file(input_file)
479
+ face_landmarker_result = landmarker.detect(mp_image)
480
+ detect_time = time.time()-start
481
+ print(detect_time)
482
+
483
+ annotated_image,bbox,landmark_points = draw_landmarks_on_image(mp_image.numpy_view(), face_landmarker_result)
484
+ #print(annotated_image)
485
+ #annotated_image=cv2.resize(annotated_image, (800, 800))
486
+ annotated_image=cv2.cvtColor(annotated_image, cv2.COLOR_RGB2BGR)
487
+ cv2.imwrite(input_file.replace(".jpg","_la68.jpg"),annotated_image)
488
+
489
+ if args.save_glandmark:
490
+ parent_path,file = os.path.split(input_file)
491
+ glandmark = bbox_to_glandmarks(file,bbox,landmark_points)
492
+ glandmark_path = input_file.replace(".jpg",f".json")
493
+ if os.path.exists(glandmark_path):
494
+ print(f"glandmark exist skipped {glandmark_path}")
495
+ else:
496
+ import json
497
+ with open(glandmark_path,"w") as f:
498
+ json.dump(glandmark,f)
499
+
500
+ # _landmark.json always overwrite because not design for edit
501
+ if args.save_group_landmark:
502
+ result=convert_to_landmark_group_json(landmark_points)
503
+ total = 0
504
+ for key in result[0].keys():
505
+ total += len(result[0][key])
506
+
507
+ print(total)
508
+ import json
509
+ group_landmark_path = input_file.replace(".jpg",f"_landmark.json")
510
+ with open(group_landmark_path,"w") as f:
511
+ json.dump(result,f)
512
+
513
+ #cv2.imshow("image",)
514
+ #cv2.waitKey(0)
515
+ #cv2.destroyAllWindows()
516
+
examples/00002200.jpg ADDED
examples/00003245_00.jpg ADDED
examples/00004200.jpg ADDED
examples/00005259.jpg ADDED
examples/00018022.jpg ADDED
examples/img-above.jpg ADDED
examples/img-below.jpg ADDED
examples/img-side.jpg ADDED
face_landmarker.task ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:64184e229b263107bc2b804c6625db1341ff2bb731874b0bcc2fe6544e0bc9ff
3
+ size 3758596
face_landmarker.task.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ Face landmark detection
2
+ https://ai.google.dev/edge/mediapipe/solutions/vision/face_landmarker
3
+
4
+ model card page is
5
+ https://storage.googleapis.com/mediapipe-assets/MediaPipe%20BlazeFace%20Model%20Card%20(Short%20Range).pdf
6
+
7
+ license is Apache2.0
8
+ https://www.apache.org/licenses/LICENSE-2.0.html
glibvision/cv2_utils.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import numpy as np
3
+
4
+ def draw_bbox(image,box,color=(255,0,0),thickness=1):
5
+ if thickness==0:
6
+ return
7
+
8
+ left = int(box[0])
9
+ top = int(box[1])
10
+ right = int(box[0]+box[2])
11
+ bottom = int(box[1]+box[3])
12
+ box_points =[(left,top),(right,top),(right,bottom),(left,bottom)]
13
+
14
+ cv2.polylines(image, [np.array(box_points)], isClosed=True, color=color, thickness=thickness)
15
+
16
+
17
+ def to_int_points(points):
18
+ int_points=[]
19
+ for point in points:
20
+ int_points.append([int(point[0]),int(point[1])])
21
+ return int_points
22
+
23
+ def draw_text(img, text, point, font_scale=0.5, color=(200, 200, 200), thickness=1):
24
+ font = cv2.FONT_HERSHEY_SIMPLEX
25
+ cv2.putText(img, str(text), point, font, font_scale, color, thickness, cv2.LINE_AA)
26
+
27
+ plot_text_color = (200, 200, 200)
28
+ plot_text_font_scale = 0.5
29
+ plot_index = 1
30
+ plot_text = True
31
+
32
+ def set_plot_text(is_plot,text_font_scale,text_color):
33
+ global plot_index,plot_text,plot_text_font_scale,plot_text_color
34
+ plot_text = is_plot
35
+ plot_index = 1
36
+ plot_text_font_scale = text_font_scale
37
+ plot_text_color = text_color
38
+
39
+ def plot_points(image,points,isClosed=False,circle_size=3,circle_color=(255,0,0),line_size=1,line_color=(0,0,255)):
40
+ global plot_index,plot_text
41
+ int_points = to_int_points(points)
42
+ if circle_size>0:
43
+ for point in int_points:
44
+ cv2.circle(image,point,circle_size,circle_color,-1)
45
+ if plot_text:
46
+ draw_text(image,plot_index,point,plot_text_font_scale,plot_text_color)
47
+ plot_index+=1
48
+ if line_size>0:
49
+ cv2.polylines(image, [np.array(int_points)], isClosed=isClosed, color=line_color, thickness=line_size)
glibvision/glandmark_utils.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import os
3
+
4
+ #simple single version
5
+ def bbox_to_glandmarks(file_name,bbox,points = None):
6
+ base,ext = os.path.splitext(file_name)
7
+ glandmark = {"image":{
8
+ "boxes":[{
9
+ "left":int(bbox[0]),"top":int(bbox[1]),"width":int(bbox[2]),"height":int(bbox[3])
10
+ }],
11
+ "file":file_name,
12
+ "id":int(base)
13
+ # width,height ignore here
14
+ }}
15
+ if points is not None:
16
+ parts=[
17
+ ]
18
+ for point in points:
19
+ parts.append({"x":int(point[0]),"y":int(point[1])})
20
+ glandmark["image"]["boxes"][0]["parts"] = parts
21
+ return glandmark
22
+
23
+ #technically this is not g-landmark/dlib ,
24
+ def convert_to_landmark_group_json(points):
25
+ if len(points)!=68:
26
+ print(f"points must be 68 but {len(points)}")
27
+ return None
28
+ new_points=list(points)
29
+
30
+ result = [ # possible multi person ,just possible any func support multi person
31
+
32
+ { # index start 0 but index-number start 1
33
+ "chin":new_points[0:17],
34
+ "left_eyebrow":new_points[17:22],
35
+ "right_eyebrow":new_points[22:27],
36
+ "nose_bridge":new_points[27:31],
37
+ "nose_tip":new_points[31:36],
38
+ "left_eye":new_points[36:42],
39
+ "right_eye":new_points[42:48],
40
+
41
+ # lip points customized structure
42
+ # MIT licensed face_recognition
43
+ # https://github.com/ageitgey/face_recognition
44
+ "top_lip":new_points[48:55]+[new_points[64]]+[new_points[63]]+[new_points[62]]+[new_points[61]]+[new_points[60]],
45
+ "bottom_lip":new_points[54:60]+[new_points[48]]+[new_points[60]]+[new_points[67]]+[new_points[66]]+[new_points[65]]+[new_points[64]],
46
+ }
47
+ ]
48
+ return result
landmarks68_utils.py ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image,ImageDraw
2
+
3
+ def create_color_image(width, height, color=(255,255,255)):
4
+ img = Image.new('RGB', (width, height), color)
5
+ return img
6
+
7
+ def fill_points(image,points,color=(255,255,255)):
8
+ draw = ImageDraw.Draw(image)
9
+ int_points = [(int(x), int(y)) for x, y in points]
10
+ draw.polygon(int_points, fill=color)
11
+ return image
12
+
13
+
14
+ def minus_point(pt1,pt2):
15
+ return [pt1[0]-pt2[0],pt1[1]-pt2[1]]
16
+
17
+ def lerp_point(pt1,pt2,pt2_ratio):
18
+ return [int(pt1[0]*(1.0-pt2_ratio)+pt2[0]*pt2_ratio),pt1[1]*(1.0-pt2_ratio)+pt2[1]*pt2_ratio]
19
+
20
+ def mean_point(points):
21
+ xs = 0
22
+ ys = 0
23
+ for pt in points:
24
+ xs +=pt[0]
25
+ ys +=pt[1]
26
+ return [int(xs/len(points)),int(ys/len(points))]
27
+
28
+ def get_face_points(face_landmarks_list):
29
+ contour_points=get_landmark_points(face_landmarks_list,PARTS_CONTOUR)
30
+ left_eyebrow_points=get_landmark_points(face_landmarks_list,PARTS_LEFT_EYEBROW)
31
+
32
+ right_eyebrow_points=get_landmark_points(face_landmarks_list,PARTS_RIGHT_EYEBROW)
33
+
34
+ nose_points=get_landmark_points(face_landmarks_list,PARTS_NOSE_BRIDGE)
35
+
36
+ diff_right = minus_point(contour_points[1],contour_points[0])
37
+ right_minus_corner = minus_point(contour_points[0] , diff_right)
38
+ right_contour = lerp_point(right_minus_corner,left_eyebrow_points[0],0.3)
39
+
40
+ diff_left = minus_point(contour_points[15],contour_points[16])
41
+ left_minus_corner = minus_point(contour_points[16] , diff_left)
42
+ left_contour = lerp_point(left_minus_corner,right_eyebrow_points[-1],0.3)
43
+
44
+ middle_face = mean_point([nose_points[0],right_eyebrow_points[0],left_eyebrow_points[-1]])
45
+ return [right_contour]+list(contour_points)+[left_contour,middle_face]
46
+
47
+
48
+ def get_innner_mouth_points(face_landmarks_list):
49
+ top_points=get_landmark_points(face_landmarks_list,PARTS_UPPER_LIP)
50
+ bottom_points=get_landmark_points(face_landmarks_list,PARTS_LOWER_LIP)
51
+ return top_points[7:]+bottom_points[7:]#[::-1]
52
+
53
+
54
+ PARTS_UPPER_LIP = "top_lip"
55
+ PARTS_LOWER_LIP = "bottom_lip"
56
+ PARTS_CONTOUR ="chin"
57
+ PARTS_LEFT_EYEBROW ="left_eyebrow"
58
+ PARTS_RIGHT_EYEBROW ="right_eyebrow"
59
+ PARTS_LEFT_EYE ="left_eye"
60
+ PARTS_RIGHT_EYE ="right_eye"
61
+ PARTS_NOSE_TIP ="nose_tip"
62
+ PARTS_NOSE_BRIDGE ="nose_bridge"
63
+
64
+ def get_landmark_points(face_landmarks_list,key):
65
+ matching_landmark_points = []
66
+ for face_landmarks in face_landmarks_list:
67
+ for landmark_name, landmark_points in face_landmarks.items():
68
+ matching_landmark_points = landmark_points.copy()
69
+ if landmark_name ==key:
70
+ return tuple(matching_landmark_points)
mp_box.py ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import mediapipe as mp
2
+ from mediapipe.tasks import python
3
+ from mediapipe.tasks.python import vision
4
+ from mediapipe.framework.formats import landmark_pb2
5
+ from mediapipe import solutions
6
+ import numpy as np
7
+
8
+ # for X,Y,W,H to x1,y1,x2,y2(Left-top,right-bottom style)
9
+ def xywh_to_xyxy(box):
10
+ return [box[0],box[1],box[0]+box[2],box[1]+box[3]]
11
+
12
+ def convert_to_box(face_landmarks_list,indices,w=1024,h=1024):
13
+ x1=w
14
+ y1=h
15
+ x2=0
16
+ y2=0
17
+ for index in indices:
18
+ x=min(w,max(0,(face_landmarks_list[0][index].x*w)))
19
+ y=min(h,max(0,(face_landmarks_list[0][index].y*h)))
20
+ if x<x1:
21
+ x1=x
22
+
23
+ if y<y1:
24
+ y1=y
25
+
26
+ if x>x2:
27
+ x2=x
28
+ if y>y2:
29
+ y2=y
30
+
31
+
32
+ return [int(x1),int(y1),int(x2-x1),int(y2-y1)]
33
+
34
+
35
+ def box_to_square(bbox):
36
+ box=list(bbox)
37
+ if box[2]>box[3]:
38
+ diff = box[2]-box[3]
39
+ box[3]+=diff
40
+ box[1]-=diff/2
41
+ elif box[3]>box[2]:
42
+ diff = box[3]-box[2]
43
+ box[2]+=diff
44
+ box[0]-=diff/2
45
+ return box
46
+
47
+
48
+ def face_landmark_result_to_box(face_landmarker_result,width=1024,height=1024):
49
+ face_landmarks_list = face_landmarker_result.face_landmarks
50
+
51
+
52
+ full_indices = list(range(456))
53
+
54
+ MIDDLE_FOREHEAD = 151
55
+ BOTTOM_CHIN_EX = 152
56
+ BOTTOM_CHIN = 175
57
+ CHIN_TO_MIDDLE_FOREHEAD = [200,14,1,6,18,9]
58
+ MOUTH_BOTTOM = [202,200,422]
59
+ EYEBROW_CHEEK_LEFT_RIGHT = [46,226,50,1,280,446,276]
60
+
61
+ LEFT_HEAD_OUTER_EX = 251 #on side face almost same as full
62
+ LEFT_HEAD_OUTER = 301
63
+ LEFT_EYE_OUTER_EX = 356
64
+ LEFT_EYE_OUTER = 264
65
+ LEFT_MOUTH_OUTER_EX = 288
66
+ LEFT_MOUTH_OUTER = 288
67
+ LEFT_CHIN_OUTER = 435
68
+ RIGHT_HEAD_OUTER_EX = 21
69
+ RIGHT_HEAD_OUTER = 71
70
+ RIGHT_EYE_OUTER_EX = 127
71
+ RIGHT_EYE_OUTER = 34
72
+ RIGHT_MOUTH_OUTER_EX = 58
73
+ RIGHT_MOUTH_OUTER = 215
74
+ RIGHT_CHIN_OUTER = 150
75
+
76
+ # TODO naming line
77
+ min_indices=CHIN_TO_MIDDLE_FOREHEAD+EYEBROW_CHEEK_LEFT_RIGHT+MOUTH_BOTTOM
78
+
79
+ chin_to_brow_indices = [LEFT_CHIN_OUTER,LEFT_MOUTH_OUTER,LEFT_EYE_OUTER,LEFT_HEAD_OUTER,MIDDLE_FOREHEAD,RIGHT_HEAD_OUTER,RIGHT_EYE_OUTER,RIGHT_MOUTH_OUTER,RIGHT_CHIN_OUTER,BOTTOM_CHIN]+min_indices
80
+
81
+ box1 = convert_to_box(face_landmarks_list,min_indices,width,height)
82
+ box2 = convert_to_box(face_landmarks_list,chin_to_brow_indices,width,height)
83
+ box3 = convert_to_box(face_landmarks_list,full_indices,width,height)
84
+ #print(box)
85
+
86
+ return [box1,box2,box3,box_to_square(box1),box_to_square(box2),box_to_square(box3)]
87
+
88
+
89
+ def draw_landmarks_on_image(detection_result,rgb_image):
90
+ face_landmarks_list = detection_result.face_landmarks
91
+ annotated_image = np.copy(rgb_image)
92
+
93
+ # Loop through the detected faces to visualize.
94
+ for idx in range(len(face_landmarks_list)):
95
+ face_landmarks = face_landmarks_list[idx]
96
+
97
+ # Draw the face landmarks.
98
+ face_landmarks_proto = landmark_pb2.NormalizedLandmarkList()
99
+ face_landmarks_proto.landmark.extend([
100
+ landmark_pb2.NormalizedLandmark(x=landmark.x, y=landmark.y, z=landmark.z) for landmark in face_landmarks
101
+ ])
102
+
103
+ solutions.drawing_utils.draw_landmarks(
104
+ image=annotated_image,
105
+ landmark_list=face_landmarks_proto,
106
+ connections=mp.solutions.face_mesh.FACEMESH_TESSELATION,
107
+ landmark_drawing_spec=None,
108
+ connection_drawing_spec=mp.solutions.drawing_styles
109
+ .get_default_face_mesh_tesselation_style())
110
+
111
+ return annotated_image
112
+
113
+ def mediapipe_to_box(image_data,model_path="face_landmarker.task"):
114
+ BaseOptions = mp.tasks.BaseOptions
115
+ FaceLandmarker = mp.tasks.vision.FaceLandmarker
116
+ FaceLandmarkerOptions = mp.tasks.vision.FaceLandmarkerOptions
117
+ VisionRunningMode = mp.tasks.vision.RunningMode
118
+
119
+ options = FaceLandmarkerOptions(
120
+ base_options=BaseOptions(model_asset_path=model_path),
121
+ running_mode=VisionRunningMode.IMAGE
122
+ ,min_face_detection_confidence=0, min_face_presence_confidence=0
123
+ )
124
+
125
+
126
+ with FaceLandmarker.create_from_options(options) as landmarker:
127
+ if isinstance(image_data,str):
128
+ mp_image = mp.Image.create_from_file(image_data)
129
+ else:
130
+ mp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data=np.asarray(image_data))
131
+ face_landmarker_result = landmarker.detect(mp_image)
132
+ boxes = face_landmark_result_to_box(face_landmarker_result,mp_image.width,mp_image.height)
133
+ return boxes,mp_image,face_landmarker_result
mp_constants.py ADDED
@@ -0,0 +1,320 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ # contour
3
+ POINT_LEFT_HEAD_OUTER_EX = 251 #on side face almost same as full
4
+ POINT_LEFT_HEAD_OUTER = 301
5
+ POINT_LEFT_EYE_OUTER_EX = 356
6
+ POINT_LEFT_EYE_OUTER = 264
7
+ POINT_LEFT_MOUTH_OUTER_EX = 288
8
+ POINT_LEFT_MOUTH_OUTER = 435
9
+ POINT_LEFT_CHIN_OUTER = 379
10
+ POINT_RIGHT_HEAD_OUTER_EX = 21
11
+ POINT_RIGHT_HEAD_OUTER = 71
12
+ POINT_RIGHT_EYE_OUTER_EX = 127
13
+ POINT_RIGHT_EYE_OUTER = 34
14
+ POINT_RIGHT_MOUTH_OUTER_EX = 58
15
+ POINT_RIGHT_MOUTH_OUTER = 215
16
+ POINT_RIGHT_CHIN_OUTER = 150
17
+ POINT_CHIN_BOTTOM = 152
18
+
19
+ POINT_FOREHEAD_TOP = 10
20
+
21
+ POINT_UPPER_LIP_CENTER_BOTTOM=13
22
+ POINT_LOWER_LIP_CENTER_TOP=14
23
+ POINT_LOWER_LIP_CENTER_BOTTOM=17
24
+ POINT_NOSE_CENTER_MIDDLE=5
25
+
26
+ LINE_RIGHT_CONTOUR_OUTER_EYE_TO_CHIN =[127,234,93,132,58,172,136,150,149,176,148,152]
27
+ LINE_RIGHT_CONTOUR_EYE_TO_CHIN = [34,227,137,177,215,138,135,169,170,140,171,175]
28
+ LINE_RIGHT_CONTOUR_INNER_EYE_TO_CHIN =[143,116,123,147,213,192,214,210,211,32,208,199]
29
+
30
+
31
+ LINE_RIGHT_CONTOUR_0 = [152,175,199]
32
+ LINE_RIGHT_CONTOUR_1 = [148,171,208]
33
+ LINE_RIGHT_CONTOUR_2 = [176,140,32]
34
+ LINE_RIGHT_CONTOUR_3 = [149,170,211]
35
+ LINE_RIGHT_CONTOUR_4 = [150,169,210]
36
+ LINE_RIGHT_CONTOUR_5 = [136,135,214]
37
+ LINE_RIGHT_CONTOUR_6 = [172,138,192]
38
+ LINE_RIGHT_CONTOUR_7 = [58,215,213]
39
+ LINE_RIGHT_CONTOUR_8 = [132,177,147]
40
+ LINE_RIGHT_CONTOUR_9 = [93,137,123]
41
+ LINE_RIGHT_CONTOUR_10 = [234,227,116]
42
+ LINE_RIGHT_CONTOUR_11 = [127,34,143]
43
+
44
+ LANDMARK_68_CONTOUR_1 = LINE_RIGHT_CONTOUR_11
45
+ LANDMARK_68_CONTOUR_2_PART1 = LINE_RIGHT_CONTOUR_10
46
+ LANDMARK_68_CONTOUR_2_PART2 = LINE_RIGHT_CONTOUR_9
47
+ LANDMARK_68_CONTOUR_3 = LINE_RIGHT_CONTOUR_8
48
+ LANDMARK_68_CONTOUR_4 = LINE_RIGHT_CONTOUR_7
49
+ LANDMARK_68_CONTOUR_5 = LINE_RIGHT_CONTOUR_6
50
+ LANDMARK_68_CONTOUR_6_PART1 = LINE_RIGHT_CONTOUR_5
51
+ LANDMARK_68_CONTOUR_6_PART2 = LINE_RIGHT_CONTOUR_4
52
+
53
+ LANDMARK_68_CONTOUR_7 = LINE_RIGHT_CONTOUR_3
54
+ LANDMARK_68_CONTOUR_8_PART1 = LINE_RIGHT_CONTOUR_2
55
+ LANDMARK_68_CONTOUR_8_PART2 = LINE_RIGHT_CONTOUR_1
56
+ LANDMARK_68_CONTOUR_9 = LINE_RIGHT_CONTOUR_0
57
+
58
+
59
+ LINE_LEFT_CONTOUR_1 = [377,396,428]
60
+ LINE_LEFT_CONTOUR_2 = [400,369,262]
61
+ LINE_LEFT_CONTOUR_3 = [378,395,431]
62
+ LINE_LEFT_CONTOUR_4 = [379,394,430]
63
+ LINE_LEFT_CONTOUR_5 = [365,364,434]
64
+ LINE_LEFT_CONTOUR_6 = [397,367,416]
65
+ LINE_LEFT_CONTOUR_7 = [288,435,433]
66
+ LINE_LEFT_CONTOUR_8 = [361,401,376]
67
+ LINE_LEFT_CONTOUR_9 = [323,366,352]
68
+ LINE_LEFT_CONTOUR_10 = [454,447,345]
69
+ LINE_LEFT_CONTOUR_11 = [356,264,372]
70
+ LINE_LEFT_CONTOUR_12 = [389,368,383]
71
+
72
+ LANDMARK_68_CONTOUR_10 = LINE_LEFT_CONTOUR_1
73
+ LANDMARK_68_CONTOUR_11_PART1 = LINE_LEFT_CONTOUR_2
74
+ LANDMARK_68_CONTOUR_11_PART2 = LINE_LEFT_CONTOUR_3
75
+ LANDMARK_68_CONTOUR_12 = LINE_LEFT_CONTOUR_4
76
+ LANDMARK_68_CONTOUR_13 = LINE_LEFT_CONTOUR_5
77
+ LANDMARK_68_CONTOUR_14 = LINE_LEFT_CONTOUR_6
78
+ LANDMARK_68_CONTOUR_15_PART1 = LINE_LEFT_CONTOUR_7
79
+ LANDMARK_68_CONTOUR_15_PART2 = LINE_LEFT_CONTOUR_8
80
+
81
+ LANDMARK_68_CONTOUR_16 = LINE_LEFT_CONTOUR_9
82
+ LANDMARK_68_CONTOUR_17_PART1 = LINE_LEFT_CONTOUR_10
83
+ LANDMARK_68_CONTOUR_17_PART2 = LINE_LEFT_CONTOUR_11
84
+
85
+ LANDMARK_68_RIGHT_EYEBROW_18 = [70,46] #upper,lower
86
+ LANDMARK_68_RIGHT_EYEBROW_19 = [63,53]
87
+ LANDMARK_68_RIGHT_EYEBROW_20 = [105,52]
88
+ LANDMARK_68_RIGHT_EYEBROW_21 = [66,65]
89
+ LANDMARK_68_RIGHT_EYEBROW_22 = [107,55]
90
+
91
+ LANDMARK_68_LEFT_EYEBROW_23 = [336,285] #upper,lower
92
+ LANDMARK_68_LEFT_EYEBROW_24 = [296,295]
93
+ LANDMARK_68_LEFT_EYEBROW_25 = [334,282]
94
+ LANDMARK_68_LEFT_EYEBROW_26 = [293,283]
95
+ LANDMARK_68_LEFT_EYEBROW_27 = [300,276]
96
+
97
+ POINT_NOSE_0 = 8
98
+ POINT_NOSE_1 = 168
99
+ POINT_NOSE_2 = 6
100
+ POINT_NOSE_3 = 197
101
+ POINT_NOSE_4 = 195
102
+ POINT_NOSE_5 = 5
103
+ POINT_NOSE_6 = 4
104
+ POINT_NOSE_7 = 19
105
+ POINT_NOSE_8 = 94
106
+ POINT_NOSE_9 = 2
107
+
108
+ #side
109
+ POINT_NOSE_10 = 98
110
+ POINT_NOSE_11 = 97
111
+ POINT_NOSE_12 = 326
112
+ POINT_NOSE_13 = 327
113
+
114
+ LANDMARK_68_VERTICAL_NOSE_28 =[8,168]
115
+ LANDMARK_68_VERTICAL_NOSE_29 = [6]
116
+ LANDMARK_68_VERTICAL_NOSE_30=[197,195]
117
+ LANDMARK_68_VERTICAL_NOSE_31=[5,4]
118
+
119
+ LANDMARK_68_HORIZONTAL_NOSE_32 =[POINT_NOSE_10]
120
+ LANDMARK_68_HORIZONTAL_NOSE_33 = [POINT_NOSE_11]
121
+ LANDMARK_68_HORIZONTAL_NOSE_34=[POINT_NOSE_9]
122
+ LANDMARK_68_HORIZONTAL_NOSE_35=[POINT_NOSE_12]
123
+ LANDMARK_68_HORIZONTAL_NOSE_36=[POINT_NOSE_13]
124
+
125
+
126
+ LINE_VERTICAL_NOSE = [POINT_NOSE_0,POINT_NOSE_1,POINT_NOSE_2,POINT_NOSE_3,POINT_NOSE_4,POINT_NOSE_5,POINT_NOSE_6,POINT_NOSE_7,POINT_NOSE_8,POINT_NOSE_9]
127
+ LINE_HORIZONTAL_NOSE =[POINT_NOSE_10,POINT_NOSE_11,POINT_NOSE_9,POINT_NOSE_12,POINT_NOSE_13]
128
+
129
+ ### EYES
130
+ POINT_RIGHT_UPPER_INNER_EYE_1 = 33
131
+ POINT_RIGHT_UPPER_INNER_EYE_2 = 246
132
+ POINT_RIGHT_UPPER_INNER_EYE_3 = 161
133
+ POINT_RIGHT_UPPER_INNER_EYE_4 = 160
134
+ POINT_RIGHT_UPPER_INNER_EYE_5 = 159
135
+ POINT_RIGHT_UPPER_INNER_EYE_6 = 158
136
+ POINT_RIGHT_UPPER_INNER_EYE_7 = 157
137
+ POINT_RIGHT_UPPER_INNER_EYE_8 = 173
138
+ POINT_RIGHT_UPPER_INNER_EYE_9 = 133
139
+
140
+ LINE_RIGHT_UPPER_INNER_EYE=[POINT_RIGHT_UPPER_INNER_EYE_1,POINT_RIGHT_UPPER_INNER_EYE_2,POINT_RIGHT_UPPER_INNER_EYE_3,POINT_RIGHT_UPPER_INNER_EYE_4,POINT_RIGHT_UPPER_INNER_EYE_5,POINT_RIGHT_UPPER_INNER_EYE_6,POINT_RIGHT_UPPER_INNER_EYE_7,POINT_RIGHT_UPPER_INNER_EYE_8,POINT_RIGHT_UPPER_INNER_EYE_9]
141
+
142
+ POINT_RIGHT_LOWER_INNER_EYE_1 = 155
143
+ POINT_RIGHT_LOWER_INNER_EYE_2 = 154
144
+ POINT_RIGHT_LOWER_INNER_EYE_3 = 153
145
+ POINT_RIGHT_LOWER_INNER_EYE_4 = 145
146
+ POINT_RIGHT_LOWER_INNER_EYE_5 = 144
147
+ POINT_RIGHT_LOWER_INNER_EYE_6 = 163
148
+ POINT_RIGHT_LOWER_INNER_EYE_7 = 7
149
+
150
+ LINE_RIGHT_LOWER_INNER_EYE=[POINT_RIGHT_UPPER_INNER_EYE_9,POINT_RIGHT_LOWER_INNER_EYE_1,POINT_RIGHT_LOWER_INNER_EYE_2,POINT_RIGHT_LOWER_INNER_EYE_3,POINT_RIGHT_LOWER_INNER_EYE_4,POINT_RIGHT_LOWER_INNER_EYE_5,POINT_RIGHT_LOWER_INNER_EYE_6,POINT_RIGHT_LOWER_INNER_EYE_7,POINT_RIGHT_UPPER_INNER_EYE_1]
151
+
152
+
153
+ POINT_RIGHT_UPPER_OUTER_EYE_1 = 130
154
+ POINT_RIGHT_UPPER_OUTER_EYE_2 = 247
155
+ POINT_RIGHT_UPPER_OUTER_EYE_3 = 30
156
+ POINT_RIGHT_UPPER_OUTER_EYE_4 = 29
157
+ POINT_RIGHT_UPPER_OUTER_EYE_5 = 27
158
+ POINT_RIGHT_UPPER_OUTER_EYE_6 = 28
159
+ POINT_RIGHT_UPPER_OUTER_EYE_7 = 56
160
+ POINT_RIGHT_UPPER_OUTER_EYE_8 = 190
161
+ POINT_RIGHT_UPPER_OUTER_EYE_9 = 243
162
+
163
+ LINE_RIGHT_UPPER_OUTER_EYE=[POINT_RIGHT_UPPER_OUTER_EYE_1,POINT_RIGHT_UPPER_OUTER_EYE_2,POINT_RIGHT_UPPER_OUTER_EYE_3,POINT_RIGHT_UPPER_OUTER_EYE_4,POINT_RIGHT_UPPER_OUTER_EYE_5,POINT_RIGHT_UPPER_OUTER_EYE_6,POINT_RIGHT_UPPER_OUTER_EYE_7,POINT_RIGHT_UPPER_OUTER_EYE_8,POINT_RIGHT_UPPER_OUTER_EYE_9]
164
+
165
+ LINE_RIGHT_UPPER_MIXED_EYE =[#firs eye1 and eye2 is intesionaly for moveup
166
+ [POINT_RIGHT_UPPER_INNER_EYE_1,POINT_RIGHT_UPPER_OUTER_EYE_2], [POINT_RIGHT_UPPER_INNER_EYE_2,POINT_RIGHT_UPPER_OUTER_EYE_2], [POINT_RIGHT_UPPER_INNER_EYE_3,POINT_RIGHT_UPPER_OUTER_EYE_3], [POINT_RIGHT_UPPER_INNER_EYE_4,POINT_RIGHT_UPPER_OUTER_EYE_4], [POINT_RIGHT_UPPER_INNER_EYE_5,POINT_RIGHT_UPPER_OUTER_EYE_5], [POINT_RIGHT_UPPER_INNER_EYE_6,POINT_RIGHT_UPPER_OUTER_EYE_6]
167
+ ,[POINT_RIGHT_UPPER_INNER_EYE_8],[POINT_RIGHT_UPPER_INNER_EYE_8,POINT_RIGHT_UPPER_INNER_EYE_9] #I'm not sure need this one or not POINT_RIGHT_LOWER_INNER_EYE_1
168
+ ]
169
+
170
+ LINE_RIGHT_UPPER_MIXED_EYE2 =[#firs eye1 and eye2 is intesionaly for moveup
171
+ [POINT_RIGHT_UPPER_INNER_EYE_1,POINT_RIGHT_UPPER_INNER_EYE_1,POINT_RIGHT_UPPER_OUTER_EYE_2],
172
+ [POINT_RIGHT_UPPER_INNER_EYE_2,POINT_RIGHT_UPPER_INNER_EYE_2,POINT_RIGHT_UPPER_OUTER_EYE_2],
173
+ [POINT_RIGHT_UPPER_INNER_EYE_3,POINT_RIGHT_UPPER_INNER_EYE_3,POINT_RIGHT_UPPER_OUTER_EYE_3],
174
+ [POINT_RIGHT_UPPER_INNER_EYE_4,POINT_RIGHT_UPPER_INNER_EYE_4,POINT_RIGHT_UPPER_OUTER_EYE_4],
175
+ [POINT_RIGHT_UPPER_INNER_EYE_5,POINT_RIGHT_UPPER_INNER_EYE_5,POINT_RIGHT_UPPER_OUTER_EYE_5],
176
+ [POINT_RIGHT_UPPER_INNER_EYE_6,POINT_RIGHT_UPPER_INNER_EYE_6,POINT_RIGHT_UPPER_OUTER_EYE_6]
177
+ ,[POINT_RIGHT_UPPER_INNER_EYE_8],
178
+ [POINT_RIGHT_UPPER_INNER_EYE_8,POINT_RIGHT_UPPER_INNER_EYE_9] #I'm not sure need this one or not POINT_RIGHT_LOWER_INNER_EYE_1
179
+ ]
180
+
181
+ POINT_RIGHT_LOWER_OUTER_EYE_1 = 112
182
+ POINT_RIGHT_LOWER_OUTER_EYE_2 = 26
183
+ POINT_RIGHT_LOWER_OUTER_EYE_3 = 22
184
+ POINT_RIGHT_LOWER_OUTER_EYE_4 = 23
185
+ POINT_RIGHT_LOWER_OUTER_EYE_5 = 24
186
+ POINT_RIGHT_LOWER_OUTER_EYE_6 = 110
187
+ POINT_RIGHT_LOWER_OUTER_EYE_7 = 25
188
+
189
+ LINE_RIGHT_LOWER_OUTER_EYE=[POINT_RIGHT_UPPER_OUTER_EYE_9,POINT_RIGHT_LOWER_OUTER_EYE_1,POINT_RIGHT_LOWER_OUTER_EYE_2,POINT_RIGHT_LOWER_OUTER_EYE_3,POINT_RIGHT_LOWER_OUTER_EYE_4,POINT_RIGHT_LOWER_OUTER_EYE_5,POINT_RIGHT_LOWER_OUTER_EYE_6,POINT_RIGHT_LOWER_OUTER_EYE_7,POINT_RIGHT_UPPER_OUTER_EYE_1]
190
+
191
+ LINE_RIGHT_LOWER_MIXED_EYE =[
192
+ [POINT_RIGHT_UPPER_INNER_EYE_8,POINT_RIGHT_UPPER_INNER_EYE_9,POINT_RIGHT_LOWER_INNER_EYE_1]
193
+ ,[POINT_RIGHT_LOWER_INNER_EYE_2]
194
+ ,POINT_RIGHT_LOWER_INNER_EYE_3,POINT_RIGHT_LOWER_INNER_EYE_4,POINT_RIGHT_LOWER_INNER_EYE_5,POINT_RIGHT_LOWER_INNER_EYE_6,POINT_RIGHT_LOWER_INNER_EYE_7
195
+ ,[POINT_RIGHT_UPPER_INNER_EYE_1,POINT_RIGHT_UPPER_OUTER_EYE_2] #combine 1 and 2 for move up
196
+ ]
197
+
198
+
199
+ POINT_LEFT_UPPER_INNER_EYE_1 = 362
200
+ POINT_LEFT_UPPER_INNER_EYE_2 = 398
201
+ POINT_LEFT_UPPER_INNER_EYE_3 = 384
202
+ POINT_LEFT_UPPER_INNER_EYE_4 = 385
203
+ POINT_LEFT_UPPER_INNER_EYE_5 = 386
204
+ POINT_LEFT_UPPER_INNER_EYE_6 = 387
205
+ POINT_LEFT_UPPER_INNER_EYE_7 = 388
206
+ POINT_LEFT_UPPER_INNER_EYE_8 = 466
207
+ POINT_LEFT_UPPER_INNER_EYE_9 = 263
208
+
209
+ LINE_LEFT_UPPER_INNER_EYE=[POINT_LEFT_UPPER_INNER_EYE_1,POINT_LEFT_UPPER_INNER_EYE_2,POINT_LEFT_UPPER_INNER_EYE_3,POINT_LEFT_UPPER_INNER_EYE_4,POINT_LEFT_UPPER_INNER_EYE_5,POINT_LEFT_UPPER_INNER_EYE_6,POINT_LEFT_UPPER_INNER_EYE_7,POINT_LEFT_UPPER_INNER_EYE_8,POINT_LEFT_UPPER_INNER_EYE_9]
210
+ LINE_LEFT_UPPER_INNER_EYE2=[POINT_LEFT_UPPER_INNER_EYE_1,POINT_LEFT_UPPER_INNER_EYE_2,POINT_LEFT_UPPER_INNER_EYE_3,POINT_LEFT_UPPER_INNER_EYE_4,POINT_LEFT_UPPER_INNER_EYE_5,POINT_LEFT_UPPER_INNER_EYE_6,POINT_LEFT_UPPER_INNER_EYE_7,POINT_LEFT_UPPER_INNER_EYE_8,POINT_LEFT_UPPER_INNER_EYE_9]
211
+
212
+
213
+
214
+ POINT_LEFT_LOWER_INNER_EYE_1 = 249
215
+ POINT_LEFT_LOWER_INNER_EYE_2 = 390
216
+ POINT_LEFT_LOWER_INNER_EYE_3 = 373
217
+ POINT_LEFT_LOWER_INNER_EYE_4 = 374
218
+ POINT_LEFT_LOWER_INNER_EYE_5 = 380
219
+ POINT_LEFT_LOWER_INNER_EYE_6 = 381
220
+ POINT_LEFT_LOWER_INNER_EYE_7 = 382
221
+
222
+
223
+ LINE_LEFT_LOWER_INNER_EYE=[POINT_LEFT_UPPER_INNER_EYE_9,POINT_LEFT_LOWER_INNER_EYE_2,POINT_LEFT_LOWER_INNER_EYE_3,POINT_LEFT_LOWER_INNER_EYE_4,POINT_LEFT_LOWER_INNER_EYE_5,POINT_LEFT_LOWER_INNER_EYE_6,POINT_LEFT_LOWER_INNER_EYE_7,POINT_LEFT_UPPER_INNER_EYE_1]
224
+
225
+ #outer
226
+
227
+ POINT_LEFT_UPPER_OUTER_EYE_1 = 463
228
+ POINT_LEFT_UPPER_OUTER_EYE_2 = 414
229
+ POINT_LEFT_UPPER_OUTER_EYE_3 = 286
230
+ POINT_LEFT_UPPER_OUTER_EYE_4 = 258
231
+ POINT_LEFT_UPPER_OUTER_EYE_5 = 257
232
+ POINT_LEFT_UPPER_OUTER_EYE_6 = 259
233
+ POINT_LEFT_UPPER_OUTER_EYE_7 = 260
234
+ POINT_LEFT_UPPER_OUTER_EYE_8 = 467
235
+ POINT_LEFT_UPPER_OUTER_EYE_9 = 359
236
+
237
+ LINE_LEFT_UPPER_OUTER_EYE=[POINT_LEFT_UPPER_OUTER_EYE_1,POINT_LEFT_UPPER_OUTER_EYE_2,POINT_LEFT_UPPER_OUTER_EYE_3,POINT_LEFT_UPPER_OUTER_EYE_4,POINT_LEFT_UPPER_OUTER_EYE_5,POINT_LEFT_UPPER_OUTER_EYE_6,POINT_LEFT_UPPER_OUTER_EYE_7,POINT_LEFT_UPPER_OUTER_EYE_8,POINT_LEFT_UPPER_OUTER_EYE_9]
238
+
239
+
240
+ POINT_LEFT_LOWER_OUTER_EYE_1 = 255
241
+ POINT_LEFT_LOWER_OUTER_EYE_2 = 339
242
+ POINT_LEFT_LOWER_OUTER_EYE_3 = 254
243
+ POINT_LEFT_LOWER_OUTER_EYE_4 = 253
244
+ POINT_LEFT_LOWER_OUTER_EYE_5 = 252
245
+ POINT_LEFT_LOWER_OUTER_EYE_6 = 256
246
+ POINT_LEFT_LOWER_OUTER_EYE_7 = 341
247
+
248
+ LINE_LEFT_LOWER_OUTER_EYE=[POINT_LEFT_UPPER_OUTER_EYE_9,POINT_LEFT_LOWER_OUTER_EYE_1,POINT_LEFT_LOWER_OUTER_EYE_2,POINT_LEFT_LOWER_OUTER_EYE_3,POINT_LEFT_LOWER_OUTER_EYE_4,POINT_LEFT_LOWER_OUTER_EYE_5,POINT_LEFT_LOWER_OUTER_EYE_6,POINT_LEFT_LOWER_OUTER_EYE_7,POINT_LEFT_UPPER_OUTER_EYE_1]
249
+
250
+ LINE_LEFT_UPPER_MIXED_EYE =[#firs eye1 and eye2 is intesionaly for moveup
251
+ [POINT_LEFT_UPPER_INNER_EYE_1,POINT_LEFT_UPPER_INNER_EYE_2,POINT_LEFT_LOWER_INNER_EYE_7],
252
+ [POINT_LEFT_UPPER_INNER_EYE_2,POINT_LEFT_UPPER_OUTER_EYE_2], [POINT_LEFT_UPPER_INNER_EYE_3,POINT_LEFT_UPPER_INNER_EYE_3,POINT_LEFT_UPPER_OUTER_EYE_3], [POINT_LEFT_UPPER_INNER_EYE_4,POINT_LEFT_UPPER_OUTER_EYE_4], [POINT_LEFT_UPPER_INNER_EYE_5,POINT_LEFT_UPPER_OUTER_EYE_5], [POINT_LEFT_UPPER_INNER_EYE_6,POINT_LEFT_UPPER_OUTER_EYE_6]
253
+ ,[POINT_LEFT_UPPER_INNER_EYE_8],[POINT_LEFT_UPPER_OUTER_EYE_8,POINT_LEFT_UPPER_INNER_EYE_9]
254
+ ]
255
+
256
+ LINE_LEFT_UPPER_MIXED_EYE2 =[#firs eye1 and eye2 is intesionaly for moveup
257
+ [POINT_LEFT_UPPER_INNER_EYE_1,POINT_LEFT_UPPER_INNER_EYE_1,POINT_LEFT_UPPER_INNER_EYE_2,POINT_LEFT_LOWER_INNER_EYE_7],
258
+ [POINT_LEFT_UPPER_INNER_EYE_2,POINT_LEFT_UPPER_INNER_EYE_2,POINT_LEFT_UPPER_OUTER_EYE_2],
259
+ [POINT_LEFT_UPPER_INNER_EYE_3,POINT_LEFT_UPPER_INNER_EYE_3,POINT_LEFT_UPPER_INNER_EYE_3,POINT_LEFT_UPPER_OUTER_EYE_3],
260
+ [POINT_LEFT_UPPER_INNER_EYE_4,POINT_LEFT_UPPER_INNER_EYE_4,POINT_LEFT_UPPER_OUTER_EYE_4],
261
+ [POINT_LEFT_UPPER_INNER_EYE_5,POINT_LEFT_UPPER_INNER_EYE_5,POINT_LEFT_UPPER_OUTER_EYE_5],
262
+ [POINT_LEFT_UPPER_INNER_EYE_6,POINT_LEFT_UPPER_INNER_EYE_6,POINT_LEFT_UPPER_OUTER_EYE_6]
263
+ ,[POINT_LEFT_UPPER_INNER_EYE_8],
264
+ [POINT_LEFT_UPPER_OUTER_EYE_8,POINT_LEFT_UPPER_INNER_EYE_9]
265
+ ]
266
+
267
+ LINE_LEFT_LOWER_MIXED_EYE =[
268
+ [POINT_LEFT_UPPER_OUTER_EYE_8,POINT_LEFT_UPPER_INNER_EYE_9]
269
+ ,[POINT_LEFT_LOWER_INNER_EYE_2]
270
+ ,POINT_LEFT_LOWER_INNER_EYE_3,POINT_LEFT_LOWER_INNER_EYE_4,POINT_LEFT_LOWER_INNER_EYE_5,POINT_LEFT_LOWER_INNER_EYE_6,POINT_LEFT_LOWER_INNER_EYE_7
271
+ , [POINT_LEFT_UPPER_INNER_EYE_1,POINT_LEFT_UPPER_INNER_EYE_2,POINT_LEFT_LOWER_INNER_EYE_7] #combine 1 and 2 for move up
272
+ ]
273
+
274
+
275
+ #LIP
276
+ LINE_RIGHT_UPPER_OUTER_LIP=[
277
+ 61,185,40,39,37,0
278
+ ]
279
+ LINE_LEFT_UPPER_OUTER_LIP=[
280
+ 0,267,269,270,409,291
281
+ ]
282
+
283
+
284
+ LINE_LOWER_OUTER_LIP=[291,#upper
285
+ 375,321,405,314,17,84,181,91,146
286
+ ,61 #upper
287
+ ]
288
+
289
+ LINE_UPPER_INNER_LIP=[
290
+ 61,185,40,39,37,0,267,269,270,409,291
291
+ ]
292
+
293
+ LINE_LOWER_INNER_LIP=[291,#upper
294
+ 375,321,405,314,17,84,181,91,146
295
+ ,61 #upper
296
+ ]
297
+
298
+ LANDMARK_68_UPPER_OUTER_LIP_49 =[61]
299
+ LANDMARK_68_UPPER_OUTER_LIP_50 =[40,39]
300
+ LANDMARK_68_UPPER_OUTER_LIP_51 =[37]
301
+ LANDMARK_68_UPPER_OUTER_LIP_52 =[0]
302
+ LANDMARK_68_UPPER_OUTER_LIP_53 =[267]
303
+ LANDMARK_68_UPPER_OUTER_LIP_54 =[270,269]
304
+ LANDMARK_68_UPPER_OUTER_LIP_55 =[291]
305
+
306
+ LANDMARK_68_LOWER_OUTER_LIP_56 =[375,321]
307
+ LANDMARK_68_LOWER_OUTER_LIP_57 =[405,314]
308
+ LANDMARK_68_LOWER_OUTER_LIP_58 =[17]
309
+ LANDMARK_68_LOWER_OUTER_LIP_59 =[84,181]
310
+ LANDMARK_68_LOWER_OUTER_LIP_60 =[146,91]
311
+
312
+ LANDMARK_68_UPPER_INNER_LIP_61 =[78]
313
+ LANDMARK_68_UPPER_INNER_LIP_62 =[81]
314
+ LANDMARK_68_UPPER_INNER_LIP_63 =[13]
315
+ LANDMARK_68_UPPER_INNER_LIP_64 =[311]
316
+ LANDMARK_68_UPPER_INNER_LIP_65 =[308]
317
+
318
+ LANDMARK_68_LOWER_INNER_LIP_66 =[402]
319
+ LANDMARK_68_LOWER_INNER_LIP_67 =[14]
320
+ LANDMARK_68_LOWER_INNER_LIP_68 =[178]
mp_utils.py ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ def calculate_distance(p1, p2):
3
+ """
4
+
5
+ """
6
+ return math.sqrt((p2[0] - p1[0])**2 + (p2[1] - p1[1])**2)
7
+ def to_int_points(points):
8
+ ints=[]
9
+ for pt in points:
10
+ #print(pt)
11
+ value = [int(pt[0]),int(pt[1])]
12
+ #print(value)
13
+ ints.append(value)
14
+ return ints
15
+
16
+ debug = False
17
+ def divide_line_to_points(points,divided): # return divided + 1
18
+ total_length = 0
19
+ line_length_list = []
20
+ for i in range(len(points)-1):
21
+ pt_length = calculate_distance(points[i],points[i+1])
22
+ total_length += pt_length
23
+ line_length_list.append(pt_length)
24
+
25
+ splited_length = total_length/divided
26
+
27
+ def get_new_point(index,lerp):
28
+ pt1 = points[index]
29
+ pt2 = points[index+1]
30
+ diff = [pt2[0] - pt1[0], pt2[1]-pt1[1]]
31
+ new_point = [pt1[0]+diff[0]*lerp,pt1[1]+diff[1]*lerp]
32
+ if debug:
33
+ print(f"pt1 ={pt1} pt2 ={pt2} diff={diff} new_point={new_point}")
34
+
35
+ return new_point
36
+
37
+ if debug:
38
+ print(f"{total_length} splitted = {splited_length} line-length-list = {len(line_length_list)}")
39
+ splited_points=[points[0]]
40
+ for i in range(1,divided):
41
+ need_length = splited_length*i
42
+ if debug:
43
+ print(f"{i} need length = {need_length}")
44
+ current_length = 0
45
+ for j in range(len(line_length_list)):
46
+ line_length = line_length_list[j]
47
+ current_length+=line_length
48
+ if current_length>need_length:
49
+ if debug:
50
+ print(f"over need length index = {j} current={current_length}")
51
+ diff = current_length - need_length
52
+
53
+ lerp_point = 1.0 - (diff/line_length)
54
+ if debug:
55
+ print(f"over = {diff} lerp ={lerp_point}")
56
+ new_point = get_new_point(j,lerp_point)
57
+
58
+ splited_points.append(new_point)
59
+ break
60
+
61
+ splited_points.append(points[-1]) # last one
62
+ splited_points=to_int_points(splited_points)
63
+
64
+ if debug:
65
+ print(f"sp={len(splited_points)}")
66
+ return splited_points
67
+
68
+ def points_to_bbox(points):
69
+ x1=float('inf')
70
+ x2=0
71
+ y1=float('inf')
72
+ y2=0
73
+ for point in points:
74
+ if point[0]<x1:
75
+ x1=point[0]
76
+ if point[0]>x2:
77
+ x2=point[0]
78
+ if point[1]<y1:
79
+ y1=point[1]
80
+ if point[1]>y2:
81
+ y2=point[1]
82
+ return [x1,y1,x2-x1,y2-y1]
83
+
84
+ def expand_bbox(bbox,left=5,top=5,right=5,bottom=5):
85
+ left_pixel = bbox[2]*(float(left)/100)
86
+ top_pixel = bbox[3]*(float(top)/100)
87
+ right_pixel = bbox[2]*(float(right)/100)
88
+ bottom_pixel = bbox[3]*(float(bottom)/100)
89
+ new_box = list(bbox)
90
+ new_box[0] -=left_pixel
91
+ new_box[1] -=top_pixel
92
+ new_box[2] +=left_pixel+right_pixel
93
+ new_box[3] +=top_pixel+bottom_pixel
94
+ return new_box
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ numpy
2
+ torch
3
+ spaces
4
+ mediapipe
5
+ opencv-python