|
import spaces |
|
import gradio as gr |
|
import subprocess |
|
from PIL import Image |
|
import json |
|
import os |
|
import time |
|
|
|
import mp_box |
|
import draw_landmarks68 |
|
import landmarks68_utils |
|
import io |
|
import numpy as np |
|
''' |
|
Face landmark detection based Face Detection. |
|
https://ai.google.dev/edge/mediapipe/solutions/vision/face_landmarker |
|
from model card |
|
https://storage.googleapis.com/mediapipe-assets/MediaPipe%20BlazeFace%20Model%20Card%20(Short%20Range).pdf |
|
Licensed Apache License, Version 2.0 |
|
Train with google's dataset(more detail see model card) |
|
|
|
''' |
|
|
|
dir_name ="files" |
|
passed_time = 60*60 |
|
def clear_old_files(dir,passed_time): |
|
try: |
|
files = os.listdir(dir) |
|
current_time = time.time() |
|
for file in files: |
|
file_path = os.path.join(dir,file) |
|
|
|
ctime = os.stat(file_path).st_ctime |
|
diff = current_time - ctime |
|
|
|
if diff > passed_time: |
|
os.remove(file_path) |
|
except: |
|
print("maybe still gallery using error") |
|
|
|
def get_image_id(image,length=32): |
|
buffer = io.BytesIO() |
|
image.save(buffer, format='PNG') |
|
hash_object = hashlib.sha256(buffer.getvalue()) |
|
hex_dig = hash_object.hexdigest() |
|
unique_id = hex_dig[:length] |
|
return unique_id |
|
|
|
def save_image(image,extension="jpg"): |
|
id = get_image_id(image) |
|
os.makedirs(dir_name,exist_ok=True) |
|
file_path = f"{dir_name}/{id}.{extension}" |
|
|
|
image.save(file_path) |
|
return file_path |
|
|
|
def picker_color_to_rgba(picker_color): |
|
color_value = picker_color.strip("rgba()").split(",") |
|
color_value[0] = int(float(color_value[0])) |
|
color_value[1] = int(float(color_value[1])) |
|
color_value[2] = int(float(color_value[2])) |
|
color_value[3] = int(float(color_value[3])) |
|
return color_value |
|
|
|
|
|
def process_images(image,progress=gr.Progress(track_tqdm=True)): |
|
if image == None: |
|
raise gr.Error("Need Image") |
|
|
|
progress(0, desc="Start Mediapipe") |
|
|
|
boxes,mp_image,face_landmarker_result = mp_box.mediapipe_to_box(image) |
|
annotated_image,bbox,landmark_points = draw_landmarks68.draw_landmarks_on_image(image,face_landmarker_result) |
|
landmark_list = draw_landmarks68.convert_to_landmark_group_json(landmark_points) |
|
|
|
annotations = [] |
|
galleries = [] |
|
|
|
def append(mask,label): |
|
file_path = save_image(mask) |
|
galleries.append((file_path,label)) |
|
annotations.append((np.array(mask.convert("1")),label)) |
|
|
|
def fill_points(points,base_image=None): |
|
if base_image == None: |
|
base_image = landmarks68_utils.create_color_image(image.width,image.height,(0,0,0)) |
|
landmarks68_utils.fill_points(base_image,points) |
|
return base_image |
|
|
|
|
|
left_eye_points = landmarks68_utils.get_landmark_points(landmark_list,landmarks68_utils.PARTS_LEFT_EYE) |
|
right_eye_points = landmarks68_utils.get_landmark_points(landmark_list,landmarks68_utils.PARTS_RIGHT_EYE) |
|
eyes_mask = fill_points(left_eye_points) |
|
eyes_mask = fill_points(right_eye_points,eyes_mask) |
|
append(eyes_mask,"eyes") |
|
|
|
|
|
upper_lip_points = landmarks68_utils.get_landmark_points(landmark_list,landmarks68_utils.PARTS_UPPER_LIP) |
|
upper_lip_mask = fill_points(upper_lip_points) |
|
append(upper_lip_mask,"upper-lip") |
|
|
|
lower_lip_points = landmarks68_utils.get_landmark_points(landmark_list,landmarks68_utils.PARTS_LOWER_LIP) |
|
lower_lip_mask = fill_points(lower_lip_points) |
|
append(lower_lip_mask,"lower-lip") |
|
|
|
inner_mouth_points = landmarks68_utils.get_innner_mouth_points(landmark_list) |
|
inner_mouth_mask = fill_points(inner_mouth_points) |
|
append(inner_mouth_mask,"inner-mouth") |
|
|
|
|
|
|
|
contour_points = landmarks68_utils.get_landmark_points(landmark_list,landmarks68_utils.PARTS_CONTOUR) |
|
|
|
contour_points=landmarks68_utils.get_face_points(landmark_list) |
|
|
|
contour_mask = fill_points(contour_points) |
|
append(contour_mask,"contour") |
|
|
|
mixed = Image.composite(eyes_mask,upper_lip_mask,eyes_mask.convert("L")) |
|
mixed = Image.composite(mixed,lower_lip_mask,mixed.convert("L")) |
|
mixed = Image.composite(mixed,inner_mouth_mask,mixed.convert("L")) |
|
append(mixed,"mixed") |
|
|
|
return [image,annotations],galleries |
|
|
|
|
|
def write_file(file_path,text): |
|
with open(file_path, 'w', encoding='utf-8') as f: |
|
f.write(text) |
|
|
|
def read_file(file_path): |
|
"""read the text of target file |
|
""" |
|
with open(file_path, 'r', encoding='utf-8') as f: |
|
content = f.read() |
|
|
|
return content |
|
|
|
css=""" |
|
#col-left { |
|
margin: 0 auto; |
|
max-width: 640px; |
|
} |
|
#col-right { |
|
margin: 0 auto; |
|
max-width: 640px; |
|
} |
|
.grid-container { |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
gap:10px |
|
} |
|
|
|
.image { |
|
width: 128px; |
|
height: 128px; |
|
object-fit: cover; |
|
} |
|
|
|
.text { |
|
font-size: 16px; |
|
} |
|
""" |
|
|
|
|
|
|
|
import hashlib |
|
|
|
def text_to_sha256(text): |
|
text_bytes = text.encode('utf-8') |
|
hash_object = hashlib.sha256() |
|
hash_object.update(text_bytes) |
|
sha256_hex = hash_object.hexdigest() |
|
return sha256_hex |
|
|
|
|
|
def create_json_download(text): |
|
file_id = f"{dir_name}/landmark_{text_to_sha256(text)[:32]}.json" |
|
write_file(file_id,text) |
|
|
|
return file_id |
|
|
|
with gr.Blocks(css=css, elem_id="demo-container") as demo: |
|
with gr.Column(): |
|
gr.HTML(read_file("demo_header.html")) |
|
gr.HTML(read_file("demo_tools.html")) |
|
with gr.Row(): |
|
with gr.Column(): |
|
image = gr.Image(height=800,sources=['upload','clipboard'],image_mode='RGB',elem_id="image_upload", type="pil", label="Upload") |
|
with gr.Row(elem_id="prompt-container", equal_height=False): |
|
with gr.Row(): |
|
btn = gr.Button("Create Landmark 68 Mask", elem_id="run_button",variant="primary") |
|
|
|
with gr.Accordion(label="Advanced Settings", open=False): |
|
with gr.Row( equal_height=True): |
|
draw_number = gr.Checkbox(label="draw Number") |
|
|
|
font_scale = gr.Slider( |
|
label="Font Scale", |
|
minimum=0.1, |
|
maximum=2, |
|
step=0.1, |
|
value=0.5) |
|
|
|
text_color = gr.ColorPicker(value="rgba(200,200,200,1)",label="text color") |
|
|
|
with gr.Row( equal_height=True): |
|
|
|
line_color = gr.ColorPicker(value="rgba(0,0,255,1)",label="line color") |
|
line_size = gr.Slider( |
|
label="Line Size", |
|
minimum=0, |
|
maximum=20, |
|
step=1, |
|
value=1) |
|
with gr.Row( equal_height=True): |
|
dot_color = gr.ColorPicker(value="rgba(255,0,0,1)",label="dot color") |
|
dot_size = gr.Slider( |
|
label="Dot Size", |
|
minimum=0, |
|
maximum=40, |
|
step=1, |
|
value=3) |
|
with gr.Row( equal_height=True): |
|
box_color = gr.ColorPicker(value="rgba(200,200,200,1)",label="box color") |
|
box_size = gr.Slider( |
|
label="Box Size", |
|
minimum=0, |
|
maximum=20, |
|
step=1, |
|
value=1) |
|
with gr.Row( equal_height=True): |
|
json_format = gr.Radio(choices=["raw","face-detection"],value="face-detection",label="json-output format") |
|
|
|
with gr.Column(): |
|
image_out = gr.AnnotatedImage(label="Output", elem_id="output-img") |
|
image_gallery = gr.Gallery(label="masks",preview=True) |
|
|
|
|
|
|
|
btn.click(fn=process_images, inputs=[image],outputs=[image_out,image_gallery] ,api_name='infer') |
|
gr.Examples( |
|
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"], |
|
inputs=[image] |
|
) |
|
gr.HTML(read_file("demo_footer.html")) |
|
|
|
if __name__ == "__main__": |
|
demo.launch() |
|
|