Spaces:
Running
Running
| import gradio as gr | |
| import os | |
| import yaml | |
| import pandas as pd | |
| from src.face_texture import GetFaceTexture | |
| from src.face_symmetry import GetFaceSymmetry | |
| from src.face_demographics import GetFaceDemographics | |
| from src.face_proportions import GetFaceProportions | |
| from PIL import Image as PILImage | |
| from typing import List, Any | |
| def get_results(image_input: PILImage.Image) -> List[Any]: | |
| demographics_dict = GetFaceDemographics().main(image_input) | |
| ( | |
| ratios_dict, | |
| face_landmarks_image, | |
| ) = GetFaceProportions().main(image_input) | |
| face_symmetry_image, symmetry_dict = GetFaceSymmetry().main(image_input) | |
| face_image, face_texture_image, texture_dict = GetFaceTexture().main(image_input) | |
| results = { | |
| "Demographic predictions": demographics_dict, | |
| "Face proportions": ratios_dict, | |
| "Face symmetry metrics": symmetry_dict, | |
| "Face texture metrics": texture_dict, | |
| } | |
| return ( | |
| results, | |
| face_image, | |
| face_landmarks_image, | |
| face_symmetry_image, | |
| face_texture_image, | |
| ) | |
| def concatenate_image( | |
| image_1: PILImage.Image, image_2: PILImage.Image | |
| ) -> PILImage.Image: | |
| image = PILImage.new("RGB", (image_1.width + image_2.width, image_1.height)) | |
| image.paste(image_1, (0, 0)) | |
| image.paste(image_2, (image_1.width, 0)) | |
| return image | |
| def get_dict_child_data(results_image: dict, image_number: int) -> dict: | |
| flattened_data = {"image": f"Face {image_number}"} | |
| for key, sub_dict in results_image.items(): | |
| for sub_key, value in sub_dict.items(): | |
| flattened_data[sub_key] = value | |
| return flattened_data | |
| def output_fn( | |
| image_input_1: PILImage.Image, image_input_2: PILImage.Image | |
| ) -> List[Any]: | |
| with open("parameters.yml", "r") as file: | |
| data = yaml.safe_load(file) | |
| results_interpretation = data["results_interpretation"] | |
| if image_input_1 is not None and image_input_2 is not None: | |
| ( | |
| results_image_1, | |
| face_image_1, | |
| face_landmarks_image_1, | |
| face_symmetry_image_1, | |
| face_texture_image_1, | |
| ) = get_results(image_input_1) | |
| ( | |
| results_image_2, | |
| face_image_2, | |
| face_landmarks_image_2, | |
| face_symmetry_image_2, | |
| face_texture_image_2, | |
| ) = get_results(image_input_2) | |
| results_image_1, results_image_2 = get_dict_child_data( | |
| results_image_1, 1 | |
| ), get_dict_child_data(results_image_2, 2) | |
| results_df = pd.DataFrame([results_image_1, results_image_2]) | |
| face_image = concatenate_image(face_image_1, face_image_2) | |
| face_landmarks_image = concatenate_image( | |
| face_landmarks_image_1, face_landmarks_image_2 | |
| ) | |
| face_symmetry_image = concatenate_image( | |
| face_symmetry_image_1, face_symmetry_image_2 | |
| ) | |
| face_texture_image = concatenate_image( | |
| face_texture_image_1, face_texture_image_2 | |
| ) | |
| if image_input_1 == None and image_input_2 is not None: | |
| ( | |
| results, | |
| face_image, | |
| face_landmarks_image, | |
| face_symmetry_image, | |
| face_texture_image, | |
| ) = get_results(image_input_2) | |
| results_df = pd.DataFrame([get_dict_child_data(results, 2)]) | |
| if image_input_2 == None and image_input_1 is not None: | |
| ( | |
| results, | |
| face_image, | |
| face_landmarks_image, | |
| face_symmetry_image, | |
| face_texture_image, | |
| ) = get_results(image_input_1) | |
| results_df = pd.DataFrame([get_dict_child_data(results, 1)]) | |
| return ( | |
| results_df, | |
| results_interpretation, | |
| face_image, | |
| face_landmarks_image, | |
| face_symmetry_image, | |
| face_texture_image, | |
| ) | |
| gigi_hadid = os.path.join(os.path.dirname(__file__), "data/gigi_hadid.webp") | |
| iface = gr.Interface( | |
| fn=output_fn, | |
| inputs=[ | |
| gr.Image(type="pil", label="Upload Face 1", value=gigi_hadid), | |
| gr.Image(type="pil", label="Upload Face 2"), | |
| ], | |
| outputs=[ | |
| gr.DataFrame(label="Results"), | |
| gr.JSON(label="Results explainer"), | |
| gr.Image(type="pil", label="Extracted face"), | |
| gr.Image(type="pil", label="Face landmarks"), | |
| gr.Image(type="pil", label="Face symmetry"), | |
| gr.Image(type="pil", label="Extracted face texture"), | |
| ], | |
| title="Advanced Facial Feature Detector", | |
| description=""" | |
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>JSON Output in HTML</title> | |
| <style> | |
| .section { | |
| margin-bottom: 20px; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="section"> | |
| <font size="3"> | |
| <h3><center>Turn your selfie into insights! Discover age and gender predictions, symmetry evaluations, and detailed proportions and texture analyses with our app.</center></h3> | |
| <hr style="margin-top: 20px; margin-bottom: 20px;"> | |
| <p><strong>Instructions:</strong> Upload up to 2 photos. For optimal results, upload a clear front-facing image (see example). To do so, either drag and drop your photo or click <i>Upload Face</i>, then press <i>Submit</i>.</p> | |
| <p><strong>Other information:</strong></p> | |
| <ul> | |
| <li>The output computation requires approximately 5 to 30 seconds.</li> | |
| <li>No uploaded photo is stored.</li> | |
| <li>If an error occurs try again or try a different photo or angle.</li> | |
| <li>Once submitted, a section detailing the results and associated images will be displayed.</li> | |
| </ul> | |
| </font> | |
| </div> | |
| </body> | |
| </html> | |
| """, | |
| theme=gr.themes.Soft(), | |
| live=False, | |
| ) | |
| iface.launch(share=True) | |