Spaces:
Runtime error
Runtime error
File size: 7,518 Bytes
e56cec2 a104d7b 0cb49c8 7fa60e6 a104d7b 81e3b01 a104d7b 8b567e1 26c854c 1b869d0 8b567e1 553046c 8b567e1 553046c 8b567e1 553046c 8b567e1 a104d7b 8b567e1 a104d7b 553046c a104d7b df76953 8b567e1 553046c 8b567e1 553046c 8b567e1 553046c a104d7b df76953 8b567e1 a104d7b df76953 8b567e1 81e3b01 553046c 8b567e1 553046c 81e3b01 8b567e1 81e3b01 a104d7b 7fa60e6 81e3b01 8b567e1 81e3b01 8b567e1 a104d7b 81e3b01 8b567e1 81e3b01 7fa60e6 8b567e1 18799a1 8b567e1 a104d7b 8b567e1 81e3b01 0cb49c8 df76953 8b567e1 a104d7b 8b567e1 a104d7b 553046c 1452ca4 553046c 8b567e1 553046c 8b567e1 553046c 8b567e1 d0bba24 c1420d3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | import os
import cv2
import gradio as gr
import numpy as np
import random
import tempfile
from PIL import Image
import face_alignment
# Initialize face alignment model
fa = face_alignment.FaceAlignment(face_alignment.LandmarksType.TWO_D, device='cpu', flip_input=False)
# Configuration
MAX_SEED = 999999
DEFAULT_MASK_PATHS = [
"mask1.jpg",
"mask2.jpg",
"mask3.png",
"mask4.png",
"mask5.png",
]
# Preload all mask images
MASK_IMAGES = []
for mask_path in DEFAULT_MASK_PATHS:
try:
mask_img = Image.open(mask_path)
MASK_IMAGES.append(mask_img)
except FileNotFoundError:
print(f"Warning: Default mask file not found: {mask_path}")
MASK_IMAGES.append(None)
css = """
#col-left { margin: 0 auto; max-width: 430px; }
#col-mid { margin: 0 auto; max-width: 430px; }
#col-right { margin: 0 auto; max-width: 430px; }
#col-showcase { margin: 0 auto; max-width: 1100px; }
#button { color: blue; }
.mask-thumbnail {
cursor: pointer;
border: 2px solid transparent;
border-radius: 5px;
margin: 5px;
height: 100px;
object-fit: contain;
}
.mask-thumbnail:hover {
border-color: #4a6cf7;
}
.mask-thumbnail.selected {
border-color: #4a6cf7;
box-shadow: 0 0 10px rgba(74, 108, 247, 0.5);
}
"""
def remove_mask_background(mask_img):
"""Remove all backgrounds (white, black, transparent) from mask image"""
if mask_img is None:
return None
mask_img = mask_img.convert("RGBA")
datas = mask_img.getdata()
new_data = []
for item in datas:
if (item[0] > 240 and item[1] > 240 and item[2] > 240) or \
(item[0] < 15 and item[1] < 15 and item[2] < 15) or \
(item[3] == 0):
new_data.append((255, 255, 255, 0))
else:
new_data.append(item)
mask_img.putdata(new_data)
return mask_img
def get_random_compliment():
"""Returns a random cute compliment with emoji"""
compliments = [
"π Wow, you look cute!",
"β¨ You look perfect with this!",
"π Amazing! This fits you well!",
"π Stunning look!",
"π Perfect match for your face!",
"π This suits you beautifully!",
"π Flawless execution!",
"π« You're rocking this look!"
]
return random.choice(compliments)
def apply_mask(person_img, mask_index, seed, randomize_seed):
"""Apply selected mask to face with perfect transparency"""
if person_img is None or mask_index is None or mask_index >= len(MASK_IMAGES):
return None, None, "Empty image or invalid mask"
mask_img = MASK_IMAGES[mask_index]
if mask_img is None:
return None, None, "Mask not found"
if randomize_seed:
seed = random.randint(0, MAX_SEED)
try:
# Convert to numpy array
img_np = np.array(person_img)
# Process the mask with background removal
processed_mask = remove_mask_background(mask_img)
if processed_mask is None:
return None, None, "Mask processing failed"
# Detect facial landmarks
landmarks = fa.get_landmarks(img_np)
if not landmarks:
return person_img, seed, "No face detected"
for landmark in landmarks:
left_eye = landmark[36:42]
right_eye = landmark[42:48]
left_pupil = np.mean(left_eye, axis=0).astype(int)
right_pupil = np.mean(right_eye, axis=0).astype(int)
eye_distance = np.linalg.norm(right_pupil - left_pupil).astype(int)
scale_w = int(eye_distance * 3)
scale_h = int(scale_w * processed_mask.size[1] / processed_mask.size[0])
resized_mask = processed_mask.resize((scale_w, scale_h), Image.Resampling.LANCZOS)
center_x = int((left_pupil[0] + right_pupil[0]) / 2)
center_y = int((left_pupil[1] + right_pupil[1]) / 2) - 20
top_left_x = center_x - scale_w // 2
top_left_y = center_y - scale_h // 2
# Create new RGBA images for perfect transparency handling
background_pil = Image.fromarray(cv2.cvtColor(img_np, cv2.COLOR_RGB2RGBA))
resized_mask = resized_mask.convert("RGBA")
# Create transparent result image
result_img = Image.new("RGBA", background_pil.size)
result_img.paste(background_pil, (0, 0))
# Paste mask with proper alpha channel
result_img.paste(resized_mask, (top_left_x, top_left_y), resized_mask)
return result_img.convert("RGB"), seed, get_random_compliment()
return person_img, seed, "Couldn't apply mask properly"
except Exception as e:
print(f"Error applying mask: {e}")
return person_img, seed, f"Error: {e}"
# Create interface
with gr.Blocks(css=css) as MaskSuggest:
gr.Markdown("# Mask Suggestion App")
with gr.Row():
with gr.Column(elem_id="col-left"):
gr.Markdown("### Step 1. Upload a person image")
person_img_input = gr.Image(label="Person image", sources='upload', type="pil")
person_img_example = gr.Examples(
examples=["human1.jpeg", "human2.jpeg", "human3.jpeg"],
inputs=person_img_input,
examples_per_page=12
)
with gr.Column(elem_id="col-mid"):
gr.Markdown("### Step 2. Choose a mask")
# Create mask selection thumbnails
mask_components = []
with gr.Row():
for i, mask_img in enumerate(MASK_IMAGES):
if mask_img is not None:
thumbnail = mask_img.resize((100, 100), Image.Resampling.LANCZOS)
thumbnail_component = gr.Image(
value=thumbnail,
label=f"Mask {i+1}",
interactive=False,
show_label=True,
elem_classes="mask-thumbnail"
)
mask_components.append(thumbnail_component)
# Hidden radio buttons for mask selection
mask_selection = gr.Radio(
choices=list(range(len(MASK_IMAGES))),
label="Selected Mask",
visible=False,
value=0
)
# Connect thumbnails to radio selection
for i, component in enumerate(mask_components):
component.select(
fn=lambda x, i=i: i,
outputs=[mask_selection]
)
with gr.Column(elem_id="col-right"):
gr.Markdown("### Step 3. Get result")
image_out = gr.Image(label="Result", show_share_button=False)
seed = gr.Number(value=42, label="Seed", visible=False)
randomize_seed = gr.Checkbox(value=True, label="Randomize seed", visible=False)
seed_used = gr.Number(label="Seed used", visible=False)
result_info = gr.Textbox(label="Status")
process_button = gr.Button("Apply Mask", elem_id="button")
process_button.click(
fn=apply_mask,
inputs=[person_img_input, mask_selection, seed, randomize_seed],
outputs=[image_out, seed_used, result_info],
api_name='apply_mask'
)
MaskSuggest.queue(api_open=False).launch(show_api=False) |