Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -196,54 +196,6 @@ def add_hats_sticker(img_bgr, sticker_path, faces):
|
|
196 |
|
197 |
return img_with_stickers
|
198 |
|
199 |
-
def add_headbands_sticker(img_bgr, sticker_path, faces):
|
200 |
-
headband_pil = Image.open(sticker_path)
|
201 |
-
|
202 |
-
# Check the color mode and convert to RGBA
|
203 |
-
headband_rgba = headband_pil.convert('RGBA')
|
204 |
-
|
205 |
-
# Convert the headband_rgba to BGRA
|
206 |
-
r, g, b, a = headband_rgba.split()
|
207 |
-
headband_bgra = Image.merge("RGBA", (b, g, r, a))
|
208 |
-
|
209 |
-
# A copy of the original image
|
210 |
-
img_with_stickers = img_bgr.copy()
|
211 |
-
|
212 |
-
for face in faces:
|
213 |
-
landmarks = face_landmarking(img_bgr, face)
|
214 |
-
|
215 |
-
# Determine the forehead region using landmarks
|
216 |
-
# Assuming the headband will be placed between the temples
|
217 |
-
left_temple = landmarks.part(0)
|
218 |
-
right_temple = landmarks.part(16)
|
219 |
-
|
220 |
-
# Calculate the width of the headband based on the temples
|
221 |
-
headband_width = int(abs(left_temple.x - right_temple.x) * 1.6)
|
222 |
-
headband_height = int(headband_width * headband_bgra.height / headband_bgra.width)
|
223 |
-
|
224 |
-
# Resize the headband image
|
225 |
-
resized_headband = headband_bgra.resize((headband_width, headband_height))
|
226 |
-
|
227 |
-
# Calculate the angle of tilt using the eyes as reference
|
228 |
-
left_eye_indices = range(36, 42)
|
229 |
-
right_eye_indices = range(42, 48)
|
230 |
-
angle = calculate_eye_angle(landmarks, left_eye_indices, right_eye_indices)
|
231 |
-
|
232 |
-
# Rotate the headband image
|
233 |
-
rotated_headband = resized_headband.rotate(-angle, expand=True, resample=Image.BICUBIC)
|
234 |
-
|
235 |
-
# Calculate the position for the headband
|
236 |
-
x1 = (left_temple.x + right_temple.x) // 2 - (headband_width // 2)
|
237 |
-
y1 = left_temple.y - (headband_height // 2)
|
238 |
-
|
239 |
-
# Convert PIL image to NumPy array
|
240 |
-
headband_np = np.array(rotated_headband)
|
241 |
-
|
242 |
-
# Overlay the headband on the image
|
243 |
-
img_with_stickers = overlay_transparent(img_with_stickers, headband_np, x1, y1)
|
244 |
-
|
245 |
-
return img_with_stickers
|
246 |
-
|
247 |
|
248 |
# Function to add glasses stickers
|
249 |
def add_glasses_sticker(img_bgr, sticker_path, faces):
|
@@ -410,83 +362,11 @@ def add_animal_faces_sticker(img_bgr, sticker_path, faces):
|
|
410 |
return img_with_stickers
|
411 |
|
412 |
|
413 |
-
# Function to process the image
|
414 |
-
def process_image(image, sticker_choice):
|
415 |
-
if sticker_choice:
|
416 |
-
# add .png to the sticker_choice
|
417 |
-
sticker_name = sticker_choice + '.png'
|
418 |
-
# find sticker's category
|
419 |
-
sticker_category = STICKER_TO_CATEGORY[sticker_name]
|
420 |
-
# Path to the single sticker
|
421 |
-
sticker_path = os.path.join('stickers',sticker_category, sticker_name)
|
422 |
-
|
423 |
-
# Convert PIL image to OpenCV format BGR
|
424 |
-
image_bgr = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
|
425 |
-
|
426 |
-
# Detect faces
|
427 |
-
faces = face_detecting(image_bgr)
|
428 |
-
# print(sticker_category)
|
429 |
-
if sticker_category == 'ears':
|
430 |
-
img_with_stickers = add_ears_sticker(image_bgr, sticker_path, faces)
|
431 |
-
elif sticker_category == 'glasses':
|
432 |
-
img_with_stickers = add_glasses_sticker(image_bgr, sticker_path, faces)
|
433 |
-
elif sticker_category == 'noses':
|
434 |
-
img_with_stickers = add_noses_sticker(image_bgr, sticker_path, faces)
|
435 |
-
elif sticker_category == 'headbands':
|
436 |
-
img_with_stickers = add_ears_sticker(image_bgr, sticker_path, faces)
|
437 |
-
else:
|
438 |
-
img_with_stickers = add_glasses_sticker(image_bgr, sticker_path, faces)
|
439 |
-
# Convert back to PIL image
|
440 |
-
img_with_stickers_pil = Image.fromarray(cv2.cvtColor(img_with_stickers, cv2.COLOR_BGR2RGB))
|
441 |
-
return img_with_stickers_pil
|
442 |
-
else:
|
443 |
-
return image
|
444 |
-
|
445 |
-
def process_image_with_selections(image_input):
|
446 |
-
# Convert PIL image to OpenCV format BGR
|
447 |
-
image_bgr = cv2.cvtColor(np.array(image_input), cv2.COLOR_RGB2BGR)
|
448 |
-
|
449 |
-
# Detect faces
|
450 |
-
faces = face_detecting(image_bgr)
|
451 |
-
|
452 |
-
# A copy of the original image to apply stickers on
|
453 |
-
img_with_stickers = image_bgr.copy()
|
454 |
-
|
455 |
-
for category, sticker_name in sticker_selections.items():
|
456 |
-
if sticker_name: # Check if a sticker was selected in this category
|
457 |
-
# the sticker file path
|
458 |
-
sticker_path = os.path.join('stickers', category, sticker_name + '.png')
|
459 |
-
|
460 |
-
# Apply the selected sticker based on its category
|
461 |
-
if category == 'ears':
|
462 |
-
img_with_stickers = add_ears_sticker(img_with_stickers, sticker_path, faces)
|
463 |
-
elif category == 'glasses':
|
464 |
-
img_with_stickers = add_glasses_sticker(img_with_stickers, sticker_path, faces)
|
465 |
-
elif category == 'noses':
|
466 |
-
img_with_stickers = add_noses_sticker(img_with_stickers, sticker_path, faces)
|
467 |
-
elif category == 'headbands':
|
468 |
-
img_with_stickers = add_hats_sticker(img_with_stickers, sticker_path, faces)
|
469 |
-
elif category == 'hats':
|
470 |
-
img_with_stickers = add_hats_sticker(img_with_stickers, sticker_path, faces)
|
471 |
-
elif category == 'animal face':
|
472 |
-
img_with_stickers = add_animal_faces_sticker(img_with_stickers, sticker_path, faces)
|
473 |
-
else:
|
474 |
-
img_with_stickers = img_with_stickers
|
475 |
-
# Convert back to PIL image
|
476 |
-
img_with_stickers_pil = Image.fromarray(cv2.cvtColor(img_with_stickers, cv2.COLOR_BGR2RGB))
|
477 |
-
|
478 |
-
print("Selected stickers:")
|
479 |
-
for category, selection in sticker_selections.items():
|
480 |
-
print(f"{category}: {selection}")
|
481 |
-
|
482 |
-
return img_with_stickers_pil
|
483 |
-
|
484 |
# This dictionary will hold the user's sticker selections
|
485 |
-
sticker_selections = {}
|
486 |
|
487 |
# Function to update sticker selections
|
488 |
def update_selections(category, selection):
|
489 |
-
# sticker_selections[category] = selection
|
490 |
sticker_selections[category] = None if selection == "None" else selection
|
491 |
return ""
|
492 |
|
@@ -494,7 +374,6 @@ def update_selections(category, selection):
|
|
494 |
def load_example_image(image_path):
|
495 |
return gr.Image.from_file(image_path)
|
496 |
|
497 |
-
from PIL import Image
|
498 |
|
499 |
def resize_image(image, target_width, target_height):
|
500 |
# Maintain aspect ratio
|
@@ -518,17 +397,6 @@ def get_face_crops(image_bgr, faces, target_width=500, target_height=130):
|
|
518 |
return face_crops
|
519 |
|
520 |
|
521 |
-
def get_face_crops2(image_bgr, faces):
|
522 |
-
# Convert color space from BGR to RGB since OpenCV uses BGR by default
|
523 |
-
image_rgb = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB)
|
524 |
-
face_crops = []
|
525 |
-
for face in faces:
|
526 |
-
# Extract the region of interest (the face) from the original image
|
527 |
-
x, y, w, h = face.left(), face.top(), face.width(), face.height()
|
528 |
-
face_crop = image_rgb[y:y+h, x:x+w]
|
529 |
-
face_pil = Image.fromarray(face_crop)
|
530 |
-
face_crops.append(face_pil)
|
531 |
-
return face_crops
|
532 |
|
533 |
# Function to process uploaded images and display face crops
|
534 |
def process_and_show_faces(image_input):
|
@@ -565,23 +433,24 @@ def process_selected_faces(image_input, selected_face_indices):
|
|
565 |
for category, sticker_name in sticker_selections.items():
|
566 |
if sticker_name: # Check if a sticker was selected in this category
|
567 |
# the sticker file path
|
568 |
-
|
569 |
-
|
570 |
-
|
571 |
-
|
572 |
-
|
573 |
-
|
574 |
-
|
575 |
-
|
576 |
-
|
577 |
-
|
578 |
-
|
579 |
-
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
|
|
|
585 |
# Convert back to PIL image
|
586 |
img_with_stickers_pil = Image.fromarray(cv2.cvtColor(img_with_stickers, cv2.COLOR_BGR2RGB))
|
587 |
|
@@ -635,15 +504,44 @@ css = """
|
|
635 |
}
|
636 |
"""
|
637 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
638 |
# Create the Gradio interface
|
639 |
with gr.Blocks(css=css) as demo:
|
640 |
|
641 |
with gr.Row():
|
642 |
with gr.Column():
|
643 |
image_input = gr.Image(type="pil", label="Original Image")
|
|
|
|
|
|
|
|
|
|
|
644 |
with gr.Column():
|
645 |
output_image = gr.Image(label="Image with Stickers")
|
646 |
# Prepare the checkboxes and image placeholders
|
|
|
647 |
detect_faces_btn = gr.Button("Detect Faces")
|
648 |
|
649 |
with gr.Row():
|
@@ -661,7 +559,8 @@ with gr.Blocks(css=css) as demo:
|
|
661 |
process_button = gr.Button("Apply Stickers To Selected Faces")
|
662 |
|
663 |
process_button.click(
|
664 |
-
handle_face_selection,
|
|
|
665 |
inputs=[image_input] + face_checkboxes,
|
666 |
outputs=output_image
|
667 |
)
|
@@ -682,20 +581,8 @@ with gr.Blocks(css=css) as demo:
|
|
682 |
choices = [sticker.split('/')[-1].replace('.png', '') for sticker in stickers]
|
683 |
radio = gr.Radio(label='', choices=choices, value="None", container=False, min_width=50, elem_classes="radio")
|
684 |
radio.change(lambda selection, cat=category: update_selections(cat, selection), inputs=[radio], outputs=[])
|
|
|
685 |
|
686 |
-
# function to clear all inputs and restart
|
687 |
-
def clear_all():
|
688 |
-
for i in range(MAX_EXPECTED_FACES):
|
689 |
-
face_images[i].value = None
|
690 |
-
face_checkboxes[i].value = False
|
691 |
-
output_image.value = None
|
692 |
-
for category in STICKER_TO_CATEGORY.values():
|
693 |
-
sticker_selections[category] = None
|
694 |
-
# radio.value = "None"
|
695 |
-
print(sticker_selections)
|
696 |
-
|
697 |
-
|
698 |
-
image_input.clear(fn=clear_all)
|
699 |
|
700 |
demo.launch()
|
701 |
|
|
|
196 |
|
197 |
return img_with_stickers
|
198 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
199 |
|
200 |
# Function to add glasses stickers
|
201 |
def add_glasses_sticker(img_bgr, sticker_path, faces):
|
|
|
362 |
return img_with_stickers
|
363 |
|
364 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
365 |
# This dictionary will hold the user's sticker selections
|
366 |
+
# sticker_selections = {}
|
367 |
|
368 |
# Function to update sticker selections
|
369 |
def update_selections(category, selection):
|
|
|
370 |
sticker_selections[category] = None if selection == "None" else selection
|
371 |
return ""
|
372 |
|
|
|
374 |
def load_example_image(image_path):
|
375 |
return gr.Image.from_file(image_path)
|
376 |
|
|
|
377 |
|
378 |
def resize_image(image, target_width, target_height):
|
379 |
# Maintain aspect ratio
|
|
|
397 |
return face_crops
|
398 |
|
399 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
400 |
|
401 |
# Function to process uploaded images and display face crops
|
402 |
def process_and_show_faces(image_input):
|
|
|
433 |
for category, sticker_name in sticker_selections.items():
|
434 |
if sticker_name: # Check if a sticker was selected in this category
|
435 |
# the sticker file path
|
436 |
+
if sticker_name != 'None':
|
437 |
+
sticker_path = os.path.join('stickers', category, sticker_name + '.png')
|
438 |
+
|
439 |
+
# Apply the selected sticker based on its category
|
440 |
+
if category == 'ears':
|
441 |
+
img_with_stickers = add_ears_sticker(img_with_stickers, sticker_path, faces)
|
442 |
+
elif category == 'glasses':
|
443 |
+
img_with_stickers = add_glasses_sticker(img_with_stickers, sticker_path, faces)
|
444 |
+
elif category == 'noses':
|
445 |
+
img_with_stickers = add_noses_sticker(img_with_stickers, sticker_path, faces)
|
446 |
+
elif category == 'headbands':
|
447 |
+
img_with_stickers = add_hats_sticker(img_with_stickers, sticker_path, faces)
|
448 |
+
elif category == 'hats':
|
449 |
+
img_with_stickers = add_hats_sticker(img_with_stickers, sticker_path, faces)
|
450 |
+
elif category == 'animal face':
|
451 |
+
img_with_stickers = add_animal_faces_sticker(img_with_stickers, sticker_path, faces)
|
452 |
+
else:
|
453 |
+
img_with_stickers = img_with_stickers
|
454 |
# Convert back to PIL image
|
455 |
img_with_stickers_pil = Image.fromarray(cv2.cvtColor(img_with_stickers, cv2.COLOR_BGR2RGB))
|
456 |
|
|
|
504 |
}
|
505 |
"""
|
506 |
|
507 |
+
def handle_image_upload(image):
|
508 |
+
global sticker_selections
|
509 |
+
sticker_selections = {category: "None" for category in STICKER_PATHS.keys()}
|
510 |
+
print("reset sticker_selections called") # Reset selections when a new image is loaded
|
511 |
+
# Print out the sticker selections state for each category
|
512 |
+
for category, selection in sticker_selections.items():
|
513 |
+
print(f"{category}: {selection}")
|
514 |
+
return image
|
515 |
+
|
516 |
+
# Initialize the sticker selections dictionary
|
517 |
+
def initialize_sticker_selections():
|
518 |
+
return {
|
519 |
+
'hats': None,
|
520 |
+
'animal face': None,
|
521 |
+
'ears': None,
|
522 |
+
'glasses': None,
|
523 |
+
'noses': None,
|
524 |
+
'headbands': None
|
525 |
+
}
|
526 |
+
|
527 |
+
|
528 |
+
sticker_selections = initialize_sticker_selections()
|
529 |
+
radio_components = {}
|
530 |
# Create the Gradio interface
|
531 |
with gr.Blocks(css=css) as demo:
|
532 |
|
533 |
with gr.Row():
|
534 |
with gr.Column():
|
535 |
image_input = gr.Image(type="pil", label="Original Image")
|
536 |
+
image_input.change(
|
537 |
+
handle_image_upload,
|
538 |
+
inputs=[image_input],
|
539 |
+
outputs=[image_input]
|
540 |
+
)
|
541 |
with gr.Column():
|
542 |
output_image = gr.Image(label="Image with Stickers")
|
543 |
# Prepare the checkboxes and image placeholders
|
544 |
+
|
545 |
detect_faces_btn = gr.Button("Detect Faces")
|
546 |
|
547 |
with gr.Row():
|
|
|
559 |
process_button = gr.Button("Apply Stickers To Selected Faces")
|
560 |
|
561 |
process_button.click(
|
562 |
+
handle_face_selection,
|
563 |
+
# inputs=[image_input, face_checkboxes, sticker_selections],
|
564 |
inputs=[image_input] + face_checkboxes,
|
565 |
outputs=output_image
|
566 |
)
|
|
|
581 |
choices = [sticker.split('/')[-1].replace('.png', '') for sticker in stickers]
|
582 |
radio = gr.Radio(label='', choices=choices, value="None", container=False, min_width=50, elem_classes="radio")
|
583 |
radio.change(lambda selection, cat=category: update_selections(cat, selection), inputs=[radio], outputs=[])
|
584 |
+
radio_components[category] = radio # Store the radio component
|
585 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
586 |
|
587 |
demo.launch()
|
588 |
|