Spaces:
Running
Running
from huggingface_hub import snapshot_download | |
from insightface.app import FaceAnalysis | |
import numpy as np | |
import cv2 | |
import gradio as gr | |
# Download face encoder | |
snapshot_download( | |
"fal/AuraFace-v1", | |
local_dir="models/auraface", | |
) | |
app = FaceAnalysis( | |
name="auraface", | |
providers=["CUDAExecutionProvider", "CPUExecutionProvider"], | |
root=".", | |
) | |
app.prepare(ctx_id=0, det_size=(640, 640)) | |
def process_image_by_bbox_larger(input_image, bbox_xyxy, min_bbox_ratio=0.2): | |
""" | |
Process an image based on a bounding box, cropping and resizing as necessary. | |
Parameters: | |
- input_image: PIL Image object. | |
- bbox_xyxy: Tuple (x1, y1, x2, y2) representing the bounding box coordinates. | |
Returns: | |
- A processed image cropped and resized to 1024x1024 if the bounding box is valid, | |
or None if the bounding box does not meet the required size criteria. | |
""" | |
# Constants | |
target_size = 1024 | |
# min_bbox_ratio = 0.2 # Bounding box should be at least 20% of the crop | |
# Extract bounding box coordinates | |
x1, y1, x2, y2 = bbox_xyxy | |
bbox_w = x2 - x1 | |
bbox_h = y2 - y1 | |
# Calculate the area of the bounding box | |
bbox_area = bbox_w * bbox_h | |
# Start with the smallest square crop that allows bbox to be at least 20% of the crop area | |
crop_size = max(bbox_w, bbox_h) | |
initial_crop_area = crop_size * crop_size | |
while (bbox_area / initial_crop_area) < min_bbox_ratio: | |
crop_size += 10 # Gradually increase until bbox is at least 20% of the area | |
initial_crop_area = crop_size * crop_size | |
# Once the minimum condition is satisfied, try to expand the crop further | |
max_possible_crop_size = min(input_image.width, input_image.height) | |
while crop_size < max_possible_crop_size: | |
# Calculate a potential new area | |
new_crop_size = crop_size + 10 | |
new_crop_area = new_crop_size * new_crop_size | |
if (bbox_area / new_crop_area) < min_bbox_ratio: | |
break # Stop if expanding further violates the 20% rule | |
crop_size = new_crop_size | |
# Determine the center of the bounding box | |
center_x = (x1 + x2) // 2 | |
center_y = (y1 + y2) // 2 | |
# Calculate the crop coordinates centered around the bounding box | |
crop_x1 = max(0, center_x - crop_size // 2) | |
crop_y1 = max(0, center_y - crop_size // 2) | |
crop_x2 = min(input_image.width, crop_x1 + crop_size) | |
crop_y2 = min(input_image.height, crop_y1 + crop_size) | |
# Ensure the crop is square, adjust if it goes out of image bounds | |
if crop_x2 - crop_x1 != crop_y2 - crop_y1: | |
side_length = min(crop_x2 - crop_x1, crop_y2 - crop_y1) | |
crop_x2 = crop_x1 + side_length | |
crop_y2 = crop_y1 + side_length | |
# Crop the image | |
cropped_image = input_image.crop((crop_x1, crop_y1, crop_x2, crop_y2)) | |
# Resize the cropped image to 1024x1024 | |
resized_image = cropped_image.resize((target_size, target_size), Image.LANCZOS) | |
return resized_image | |
def calc_emb_cropped(image, app, min_bbox_ratio=0.2): | |
face_image = image.copy() | |
face_info = app.get(cv2.cvtColor(np.array(face_image), cv2.COLOR_RGB2BGR)) | |
face_info = face_info[0] | |
#print(face_info) | |
cropped_face_image = process_image_by_bbox_larger(face_image, face_info["bbox"], min_bbox_ratio=min_bbox_ratio) | |
return cropped_face_image | |
def get_embedding(image): | |
face_image = image.copy() | |
face_info = app.get(cv2.cvtColor(np.array(face_image), cv2.COLOR_RGB2BGR)) | |
# 获取人脸嵌入 | |
#face_info = app.get(cv2_image) | |
if len(face_info) > 0: | |
return face_info[0].normed_embedding | |
else: | |
return None | |
''' | |
from PIL import Image | |
im0 = Image.open("Unreal_5_render_of_a_handsome_man_gentle_snowfall_at_dusk_a_bustling_marketplace_in_the_background.png") | |
calc_emb_cropped(im0, app) | |
get_embedding(im0) | |
''' | |
def calculate_similarity(image1, image2): | |
# 获取两张图片的嵌入 | |
embedding1 = get_embedding(image1) | |
embedding2 = get_embedding(image2) | |
if embedding1 is not None and embedding2 is not None: | |
# 计算余弦相似度 | |
similarity = np.dot(embedding1, embedding2) / (np.linalg.norm(embedding1) * np.linalg.norm(embedding2)) | |
return f"图片相似度: {similarity:.4f}" | |
else: | |
return "无法检测到人脸或计算相似度" | |
# 创建Gradio界面 | |
iface = gr.Interface( | |
fn=calculate_similarity, | |
inputs=[gr.Image(type="pil"), gr.Image(type="pil")], | |
outputs="text", | |
title="图片相似度计算", | |
description="上传两张图片,计算它们的相似度。" | |
) | |
# 启动Gradio应用 | |
iface.launch(share = True) |