diff --git a/.gitattributes b/.gitattributes index ca39e4c171d39f87c166190ed9172248869625f7..090b9a5b4119790cb85914f03b6f7f3fc9f84920 100644 --- a/.gitattributes +++ b/.gitattributes @@ -34,3 +34,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text *.zst filter=lfs diff=lfs merge=lfs -text *tfevents* filter=lfs diff=lfs merge=lfs -text shape_predictor_81_face_landmarks.dat filter=lfs diff=lfs merge=lfs -text +stickers/noses/clown.png filter=lfs diff=lfs merge=lfs -text diff --git a/app.py b/app.py new file mode 100644 index 0000000000000000000000000000000000000000..3a3227745f0f62219914561f36dc2b7726d5fb19 --- /dev/null +++ b/app.py @@ -0,0 +1,690 @@ +import gradio as gr +import cv2 +import numpy as np +from PIL import Image +import dlib +import os +import math + +from constants import * + +MAX_EXPECTED_FACES=7 +# get a list of faces in the image +def face_detecting(image): + detector = dlib.get_frontal_face_detector() + faces = detector(image, 1) + return faces + +# show all the faces in rectangles in the image +def face_showing(image, faces): + for face in faces: + cv2.rectangle(image, (face.left(), face.top()), (face.right(), face.bottom()), (255, 255, 255), 2) + return image + +# highlight the selected face in the image, using index to select the face +def face_selecting(image, faces, index): + face = faces[index] + cv2.rectangle(image, (face.left(), face.top()), (face.right(), face.bottom()), (255, 255, 255), 2) + return image + +# get the landmarks of the face +def face_landmarking(image, face): + predictor = dlib.shape_predictor('shape_predictor_81_face_landmarks.dat') + landmarks = predictor(image, face) + return landmarks + + +# Function to overlay a transparent image onto another image +def overlay_transparent(background, overlay, x, y): + bg_height, bg_width = background.shape[:2] + if x >= bg_width or y >= bg_height: + return background + + h, w = overlay.shape[:2] + if x + w > bg_width: + w = bg_width - x + overlay = overlay[:, :w] + + if y + h > bg_height: + h = bg_height - y + overlay = overlay[:h] + + if overlay.shape[2] < 4: + overlay = np.concatenate([overlay, np.ones((overlay.shape[0], overlay.shape[1], 1), dtype=overlay.dtype) * 255], axis=2) + + overlay_img = overlay[..., :3] + mask = overlay[..., 3:] / 255.0 + + background[y:y+h, x:x+w] = (1.0 - mask) * background[y:y+h, x:x+w] + mask * overlay_img + + return background + + +def calculate_eye_angle(landmarks, left_eye_indices, right_eye_indices): + + # Calculate the center point of the left eye + left_eye_center = ( + sum([landmarks.part(i).x for i in left_eye_indices]) // len(left_eye_indices), + sum([landmarks.part(i).y for i in left_eye_indices]) // len(left_eye_indices) + ) + + # Calculate the center point of the right eye + right_eye_center = ( + sum([landmarks.part(i).x for i in right_eye_indices]) // len(right_eye_indices), + sum([landmarks.part(i).y for i in right_eye_indices]) // len(right_eye_indices) + ) + + # Calculate the differences in the x and y coordinates between the centers of the eyes + dx = right_eye_center[0] - left_eye_center[0] + dy = right_eye_center[1] - left_eye_center[1] + + # Calculate the angle using the arctangent of the differences + angle = math.degrees(math.atan2(dy, dx)) + + return angle + + +# Function to add ear stickers +def add_ears_sticker(img_bgr, sticker_path, faces): + ears_pil = Image.open(sticker_path) + + # Check the color mode and convert to RGBA + ears_rgba = ears_pil.convert('RGBA') + + # Convert the ears_rgba to BGRA + r, g, b, a = ears_rgba.split() + ears_bgra = Image.merge("RGBA", (b, g, r, a)) + + + # A copy of the original image + img_with_stickers = img_bgr.copy() + + for face in faces: + landmarks = face_landmarking(img_bgr, face) + + # the landmarks 68 to 80 are for the forehead + forehead = [landmarks.part(i) for i in range(68, 81)] + + # The landmarks 36 to 41 are for the left eye, and 42 to 47 are for the right eye + left_eye = [landmarks.part(i) for i in range(36, 42)] + right_eye = [landmarks.part(i) for i in range(42, 48)] + + # Calculate the center point between the eyes + left_eye_center = ((left_eye[0].x + left_eye[3].x) // 2, (left_eye[0].y + left_eye[3].y) // 2) + right_eye_center = ((right_eye[0].x + right_eye[3].x) // 2, (right_eye[0].y + right_eye[3].y) // 2) + + # Calculate the angle of tilt + dx = right_eye_center[0] - left_eye_center[0] + dy = right_eye_center[1] - left_eye_center[1] + angle = math.degrees(math.atan2(dy, dx)) + + + # Calculate the bounding box for the ears based on the eye landmarks + ears_width = int(abs(forehead[0].x - forehead[-1].x) * 2.1) + ears_height = int(ears_width * ears_bgra.height / ears_bgra.width) + + # Resize the ears image + resized_ears_pil = ears_bgra.resize((ears_width, ears_height)) + rotated_ears = resized_ears_pil.rotate(-angle, expand=True, resample=Image.BICUBIC) + + # Calculate the position for the ears + y1 = min([point.y for point in forehead]) - int(0.7 * ears_height) + x1 = forehead[0].x - int(0.2 * ears_width) + + # Convert PIL image to NumPy array + # ears_np = np.array(resized_ears_pil) + ears_np = np.array(rotated_ears) + + # Overlay the ears on the image + img_with_stickers = overlay_transparent(img_with_stickers, ears_np, x1, y1) + + return img_with_stickers + +# Function to add hats stickers +def add_hats_sticker(img_bgr, sticker_path, faces): + hat_pil = Image.open(sticker_path) + + # Check the color mode and convert to RGBA + hat_rgba = hat_pil.convert('RGBA') + + # Convert the hat_rgba to BGRA + r, g, b, a = hat_rgba.split() + hat_bgra = Image.merge("RGBA", (b, g, r, a)) + + # A copy of the original image + img_with_stickers = img_bgr.copy() + + for face in faces: + landmarks = face_landmarking(img_bgr, face) + + # The landmarks 36 to 41 are for the left eye, and 42 to 47 are for the right eye + left_eye = [landmarks.part(i) for i in range(36, 42)] + right_eye = [landmarks.part(i) for i in range(42, 48)] + + forehead = [landmarks.part(i) for i in range(68, 81)] + + # Calculate the center point between the eyes + left_eye_center = ((left_eye[0].x + left_eye[3].x) // 2, (left_eye[0].y + left_eye[3].y) // 2) + right_eye_center = ((right_eye[0].x + right_eye[3].x) // 2, (right_eye[0].y + right_eye[3].y) // 2) + eye_center_x = (left_eye_center[0] + right_eye_center[0]) // 2 + eye_center_y = (left_eye_center[1] + right_eye_center[1]) // 2 + + # Calculate the angle of tilt + dx = right_eye_center[0] - left_eye_center[0] + dy = right_eye_center[1] - left_eye_center[1] + angle = math.degrees(math.atan2(dy, dx)) + + # Calculate the size of the hat based on the width between the eyes + hat_width = int(abs(left_eye[0].x - right_eye[3].x) * 1.75) + hat_height = int(hat_width * hat_bgra.height / hat_bgra.width) + + # Resize and rotate the hat image + resized_hat = hat_bgra.resize((hat_width, hat_height)) + rotated_hat = resized_hat.rotate(-0.8*angle, expand=True, resample=Image.BICUBIC) + + + # Calculate the position for the hat + y1 = eye_center_y - hat_height - int(0.3 * hat_height) + # x1 = eye_center_x - (hat_width // 2) # Centering the hat on the midpoint between the eyes + # x1 = eye_center_x - (hat_width // 2) - int(0.03 * hat_width) # Moving the hat a bit further to the left + x1 = forehead[0].x - int(0.2 * hat_width) + # Convert PIL image to NumPy array + hat_np = np.array(rotated_hat) + + # Overlay the hat on the image + img_with_stickers = overlay_transparent(img_with_stickers, hat_np, x1, y1) + + return img_with_stickers + +def add_headbands_sticker(img_bgr, sticker_path, faces): + headband_pil = Image.open(sticker_path) + + # Check the color mode and convert to RGBA + headband_rgba = headband_pil.convert('RGBA') + + # Convert the headband_rgba to BGRA + r, g, b, a = headband_rgba.split() + headband_bgra = Image.merge("RGBA", (b, g, r, a)) + + # A copy of the original image + img_with_stickers = img_bgr.copy() + + for face in faces: + landmarks = face_landmarking(img_bgr, face) + + # Determine the forehead region using landmarks + # Assuming the headband will be placed between the temples + left_temple = landmarks.part(0) + right_temple = landmarks.part(16) + + # Calculate the width of the headband based on the temples + headband_width = int(abs(left_temple.x - right_temple.x) * 1.6) + headband_height = int(headband_width * headband_bgra.height / headband_bgra.width) + + # Resize the headband image + resized_headband = headband_bgra.resize((headband_width, headband_height)) + + # Calculate the angle of tilt using the eyes as reference + left_eye_indices = range(36, 42) + right_eye_indices = range(42, 48) + angle = calculate_eye_angle(landmarks, left_eye_indices, right_eye_indices) + + # Rotate the headband image + rotated_headband = resized_headband.rotate(-angle, expand=True, resample=Image.BICUBIC) + + # Calculate the position for the headband + x1 = (left_temple.x + right_temple.x) // 2 - (headband_width // 2) + y1 = left_temple.y - (headband_height // 2) + + # Convert PIL image to NumPy array + headband_np = np.array(rotated_headband) + + # Overlay the headband on the image + img_with_stickers = overlay_transparent(img_with_stickers, headband_np, x1, y1) + + return img_with_stickers + + +# Function to add glasses stickers +def add_glasses_sticker(img_bgr, sticker_path, faces): + glasses_pil = Image.open(sticker_path) + + # Check the color mode and convert to RGBA + glasses_rgba = glasses_pil.convert('RGBA') + + # Convert the glasses_rgba to BGRA + r, g, b, a = glasses_rgba.split() + glasses_bgra = Image.merge("RGBA", (b, g, r, a)) + + # A copy of the original image + img_with_stickers = img_bgr.copy() + + for face in faces: + landmarks = face_landmarking(img_bgr, face) + + # the landmarks 36 to 41 are for the left eye, and 42 to 47 are for the right eye + left_eye = [landmarks.part(i) for i in range(36, 42)] + right_eye = [landmarks.part(i) for i in range(42, 48)] + + # Calculate the center points of the eyes + left_eye_center = (sum([p.x for p in left_eye]) // len(left_eye), sum([p.y for p in left_eye]) // len(left_eye)) + right_eye_center = (sum([p.x for p in right_eye]) // len(right_eye), sum([p.y for p in right_eye]) // len(right_eye)) + + # Calculate the angle of tilt + dx = right_eye_center[0] - left_eye_center[0] + dy = right_eye_center[1] - left_eye_center[1] + angle = math.degrees(math.atan2(dy, dx)) # Angle in degrees + + # Calculate the bounding box for the glasses based on the eye landmarks + glasses_width = int(abs(left_eye_center[0] - right_eye_center[0]) * 2) + glasses_height = int(glasses_width * glasses_bgra.height / glasses_bgra.width) + + # Resize and rotate the glasses image + resized_glasses = glasses_bgra.resize((glasses_width, glasses_height)) + rotated_glasses = resized_glasses.rotate(-0.8*angle, expand=True, resample=Image.BICUBIC) # Negative angle to correct orientation + + # Calculate the position for the glasses, adjusting for the rotation + x1 = left_eye_center[0] - int(0.25 * glasses_width) + y1 = min(left_eye_center[1], right_eye_center[1]) - int(0.45 * glasses_height) + + # Convert PIL image to NumPy array + glasses_np = np.array(rotated_glasses) + + # Overlay the glasses on the image + img_with_stickers = overlay_transparent(img_with_stickers, glasses_np, x1, y1) + + return img_with_stickers + + + +def add_noses_sticker(img_bgr, sticker_path, faces): + nose_pil = Image.open(sticker_path) + + # Check the color mode and convert to RGBA + nose_rgba = nose_pil.convert('RGBA') + + # Convert the nose_rgba to BGRA + r, g, b, a = nose_rgba.split() + nose_bgra = Image.merge("RGBA", (b, g, r, a)) + + # A copy of the original image + img_with_stickers = img_bgr.copy() + + for face in faces: + landmarks = face_landmarking(img_bgr, face) + + # Assuming that the landmarks 27 to 35 are for the nose area + nose_area = [landmarks.part(i) for i in range(27, 36)] + + # Calculate the bounding box for the nose based on the nose landmarks + nose_width = int(abs(nose_area[0].x - nose_area[-1].x) * 2.1) + nose_height = int(nose_width * nose_bgra.height / nose_bgra.width) + + # the landmarks 31 and 35 are the leftmost and rightmost points of the nose area + nose_left = landmarks.part(31) + nose_right = landmarks.part(35) + + # Calculate the center point of the nose + nose_center_x = (nose_left.x + nose_right.x) // 2 + + nose_top = landmarks.part(27) # Use 28 if it's more accurate + nose_bottom = landmarks.part(33) + + # Calculate the midpoint of the vertical length of the nose + nose_center_y = (nose_top.y + nose_bottom.y) // 2 + + # Calculate the angle of tilt using the eyes as reference + left_eye_indices = range(36, 42) + right_eye_indices = range(42, 48) + angle = calculate_eye_angle(landmarks, left_eye_indices, right_eye_indices) + + # Resize the nose image + resized_nose_pil = nose_bgra.resize((nose_width, nose_height)) + + rotated_nose = resized_nose_pil.rotate(-angle, expand=True, resample=Image.BICUBIC) + + + # the position for the nose + x1 = nose_center_x - (nose_width // 2) + y1 = nose_center_y - (nose_height // 2)+ int(0.1 * nose_height) # Adding a slight downward offset + # Convert PIL image to NumPy array + nose_np = np.array(rotated_nose) + + # Overlay the nose on the image + img_with_stickers = overlay_transparent(img_with_stickers, nose_np, x1, y1) + + return img_with_stickers + +def add_animal_faces_sticker(img_bgr, sticker_path, faces): + animal_face_pil = Image.open(sticker_path) + + # Check the color mode and convert to RGBA + animal_face_rgba = animal_face_pil.convert('RGBA') + + # Convert the animal_face_rgba to BGRA + r, g, b, a = animal_face_rgba.split() + animal_face_bgra = Image.merge("RGBA", (b, g, r, a)) + + # A copy of the original image + img_with_stickers = img_bgr.copy() + + for face in faces: + landmarks = face_landmarking(img_bgr, face) + + # Find the top of the forehead using landmarks above the eyes + # Assuming landmarks 19 to 24 represent the eyebrows + forehead_top = min(landmarks.part(i).y for i in range(68, 81)) + + # Calculate the center point between the eyes as an anchor + left_eye = [landmarks.part(i) for i in range(36, 42)] + right_eye = [landmarks.part(i) for i in range(42, 48)] + eye_center_x = (left_eye[0].x + right_eye[3].x) // 2 + eye_center_y = (left_eye[3].y + right_eye[0].y) // 2 + + # Calculate the size of the animal face sticker based on the width between the temples + head_width = int(abs(landmarks.part(0).x - landmarks.part(16).x)*1.4) + head_height = int(head_width * animal_face_bgra.height *1.2 / animal_face_bgra.width) + + + # Calculate the angle of tilt using the eyes as reference + left_eye_indices = range(36, 42) + right_eye_indices = range(42, 48) + angle = calculate_eye_angle(landmarks, left_eye_indices, right_eye_indices) + + # Resize the animal face sticker + resized_animal_face = animal_face_bgra.resize((head_width, head_height)) + + rotated_animal_face = resized_animal_face.rotate(-angle, expand=True, resample=Image.BICUBIC) + + + # Calculate the position for the animal face sticker + x1 = eye_center_x - (head_width // 2) + y1 = forehead_top - int(0.18 * head_height) + + # Convert PIL image to NumPy array + animal_face_np = np.array(rotated_animal_face) + + # Overlay the animal face on the image + img_with_stickers = overlay_transparent(img_with_stickers, animal_face_np, x1, y1) + + return img_with_stickers + + +# Function to process the image +def process_image(image, sticker_choice): + if sticker_choice: + # add .png to the sticker_choice + sticker_name = sticker_choice + '.png' + # find sticker's category + sticker_category = STICKER_TO_CATEGORY[sticker_name] + # Path to the single sticker + sticker_path = os.path.join('stickers',sticker_category, sticker_name) + + # Convert PIL image to OpenCV format BGR + image_bgr = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR) + + # Detect faces + faces = face_detecting(image_bgr) + # print(sticker_category) + if sticker_category == 'ears': + img_with_stickers = add_ears_sticker(image_bgr, sticker_path, faces) + elif sticker_category == 'glasses': + img_with_stickers = add_glasses_sticker(image_bgr, sticker_path, faces) + elif sticker_category == 'noses': + img_with_stickers = add_noses_sticker(image_bgr, sticker_path, faces) + elif sticker_category == 'headbands': + img_with_stickers = add_ears_sticker(image_bgr, sticker_path, faces) + else: + img_with_stickers = add_glasses_sticker(image_bgr, sticker_path, faces) + # Convert back to PIL image + img_with_stickers_pil = Image.fromarray(cv2.cvtColor(img_with_stickers, cv2.COLOR_BGR2RGB)) + return img_with_stickers_pil + else: + return image + +def process_image_with_selections(image_input): + # Convert PIL image to OpenCV format BGR + image_bgr = cv2.cvtColor(np.array(image_input), cv2.COLOR_RGB2BGR) + + # Detect faces + faces = face_detecting(image_bgr) + + # A copy of the original image to apply stickers on + img_with_stickers = image_bgr.copy() + + for category, sticker_name in sticker_selections.items(): + if sticker_name: # Check if a sticker was selected in this category + # the sticker file path + sticker_path = os.path.join('stickers', category, sticker_name + '.png') + + # Apply the selected sticker based on its category + if category == 'ears': + img_with_stickers = add_ears_sticker(img_with_stickers, sticker_path, faces) + elif category == 'glasses': + img_with_stickers = add_glasses_sticker(img_with_stickers, sticker_path, faces) + elif category == 'noses': + img_with_stickers = add_noses_sticker(img_with_stickers, sticker_path, faces) + elif category == 'headbands': + img_with_stickers = add_hats_sticker(img_with_stickers, sticker_path, faces) + elif category == 'hats': + img_with_stickers = add_hats_sticker(img_with_stickers, sticker_path, faces) + elif category == 'animal face': + img_with_stickers = add_animal_faces_sticker(img_with_stickers, sticker_path, faces) + else: + img_with_stickers = img_with_stickers + # Convert back to PIL image + img_with_stickers_pil = Image.fromarray(cv2.cvtColor(img_with_stickers, cv2.COLOR_BGR2RGB)) + + print("Selected stickers:") + for category, selection in sticker_selections.items(): + print(f"{category}: {selection}") + + return img_with_stickers_pil + +# This dictionary will hold the user's sticker selections +sticker_selections = {} + +# Function to update sticker selections +def update_selections(category, selection): + # sticker_selections[category] = selection + sticker_selections[category] = None if selection == "None" else selection + return "" + +# Function to load an example image +def load_example_image(image_path): + return gr.Image.from_file(image_path) + +from PIL import Image + +def resize_image(image, target_width, target_height): + # Maintain aspect ratio + original_width, original_height = image.size + ratio = min(target_width/original_width, target_height/original_height) + new_width = int(original_width * ratio) + new_height = int(original_height * ratio) + # Use Image.LANCZOS for high-quality downsampling + resized_image = image.resize((new_width, new_height), Image.LANCZOS) + return resized_image + +def get_face_crops(image_bgr, faces, target_width=500, target_height=130): + face_crops = [] + for face in faces: + x, y, w, h = face.left(), face.top(), face.width(), face.height() + face_crop = image_bgr[y:y+h, x:x+w] + face_pil = Image.fromarray(cv2.cvtColor(face_crop, cv2.COLOR_BGR2RGB)) + # Resize image to fit the display while maintaining aspect ratio + resized_face = resize_image(face_pil, target_width, target_height) + face_crops.append(resized_face) + return face_crops + + +def get_face_crops2(image_bgr, faces): + # Convert color space from BGR to RGB since OpenCV uses BGR by default + image_rgb = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB) + face_crops = [] + for face in faces: + # Extract the region of interest (the face) from the original image + x, y, w, h = face.left(), face.top(), face.width(), face.height() + face_crop = image_rgb[y:y+h, x:x+w] + face_pil = Image.fromarray(face_crop) + face_crops.append(face_pil) + return face_crops + +# Function to process uploaded images and display face crops +def process_and_show_faces(image_input): + # Convert PIL image to OpenCV format BGR + image_bgr = cv2.cvtColor(np.array(image_input), cv2.COLOR_RGB2BGR) + # Detect faces + faces = face_detecting(image_bgr) + # Get individual face crops + face_crops = get_face_crops(image_bgr, faces) + # Return face crops to display them in the interface + return face_crops + + +face_outputs = [] +for i in range(MAX_EXPECTED_FACES): + face_output = gr.Image(label=f"Face {i+1}") + face_outputs.append(face_output) + +# This list will hold the Checkbox components for each face +checkboxes = [] + +def process_selected_faces(image_input, selected_face_indices): + # Convert PIL image to OpenCV format BGR + image_bgr = cv2.cvtColor(np.array(image_input), cv2.COLOR_RGB2BGR) + + # Detect all faces + all_faces = face_detecting(image_bgr) + + # Filter faces to get only those selected + faces = [all_faces[i] for i in selected_face_indices] + + img_with_stickers = image_bgr.copy() + + for category, sticker_name in sticker_selections.items(): + if sticker_name: # Check if a sticker was selected in this category + # the sticker file path + sticker_path = os.path.join('stickers', category, sticker_name + '.png') + + # Apply the selected sticker based on its category + if category == 'ears': + img_with_stickers = add_ears_sticker(img_with_stickers, sticker_path, faces) + elif category == 'glasses': + img_with_stickers = add_glasses_sticker(img_with_stickers, sticker_path, faces) + elif category == 'noses': + img_with_stickers = add_noses_sticker(img_with_stickers, sticker_path, faces) + elif category == 'headbands': + img_with_stickers = add_hats_sticker(img_with_stickers, sticker_path, faces) + elif category == 'hats': + img_with_stickers = add_hats_sticker(img_with_stickers, sticker_path, faces) + elif category == 'animal face': + img_with_stickers = add_animal_faces_sticker(img_with_stickers, sticker_path, faces) + else: + img_with_stickers = img_with_stickers + # Convert back to PIL image + img_with_stickers_pil = Image.fromarray(cv2.cvtColor(img_with_stickers, cv2.COLOR_BGR2RGB)) + + print("Selected stickers:") + for category, selection in sticker_selections.items(): + print(f"{category}: {selection}") + + return img_with_stickers_pil + +def handle_face_selection(image_input, *checkbox_states): + selected_face_indices = [i for i, checked in enumerate(checkbox_states) if checked] + print("selected_face_indices:",selected_face_indices) + return process_selected_faces(image_input, selected_face_indices) + +def update_interface_with_faces(image_input): + image_bgr = cv2.cvtColor(np.array(image_input), cv2.COLOR_RGB2BGR) + faces = face_detecting(image_bgr) + face_crops = get_face_crops(image_bgr, faces) + return [(face, f"Face {i+1}") for i, face in enumerate(face_crops)] + +def detect_and_display_faces(image_input): + image_bgr = cv2.cvtColor(np.array(image_input), cv2.COLOR_RGB2BGR) + faces = face_detecting(image_bgr) + face_crops = get_face_crops(image_bgr, faces) + if not face_crops: + # Return empty images and unchecked boxes if no faces are detected + return [None] * MAX_EXPECTED_FACES + [False] * MAX_EXPECTED_FACES + # Return face crops and True for each checkbox to indicate they should be checked + # Pad the list with None and False if fewer faces than MAX_EXPECTED_FACES are detected + output = face_crops + [None] * (MAX_EXPECTED_FACES - len(face_crops)) + output += [True] * len(face_crops) + [False] * (MAX_EXPECTED_FACES - len(face_crops)) + return output + + +css = """ +#category { + padding-left: 100px; + font-size: 20px; + font-weight: bold; + margin-top: 20px; +} + +#sticker { + height: 130px; + width: 30px; + padding: 10px; +} +.radio { + display: flex; + justify-content: space-around; +} +""" + +# Create the Gradio interface +with gr.Blocks(css=css) as demo: + + with gr.Row(): + with gr.Column(): + image_input = gr.Image(type="pil", label="Original Image") + with gr.Column(): + output_image = gr.Image(label="Image with Stickers") + # Prepare the checkboxes and image placeholders + detect_faces_btn = gr.Button("Detect Faces") + + with gr.Row(): + face_checkboxes = [gr.Checkbox(label=f"Face {i+1}") for i in range(7)] + + with gr.Row(): + face_images = [gr.Image(height=150, width=100, min_width=30, interactive=False, show_download_button=False) for i in range(7)] + + detect_faces_btn.click( + detect_and_display_faces, + inputs=[image_input], + outputs=face_images + face_checkboxes + ) + + process_button = gr.Button("Apply Stickers To Selected Faces") + + process_button.click( + handle_face_selection, + inputs=[image_input] + face_checkboxes, + outputs=output_image + ) + + # Iterate over each category to create a row for the category + for category, stickers in STICKER_PATHS.items(): + with gr.Row(): + with gr.Column(scale=1, elem_id="category_row"): + gr.Markdown(f"## {category}", elem_id="category") + with gr.Column(scale=10): + # Iterate over stickers in sets of 10 + for i in range(0, len(stickers), 10): + with gr.Row(): + for sticker_path in stickers[i:i+10]: + gr.Image(value=sticker_path, min_width=50, interactive=False, show_download_button=False, container=False, elem_id="sticker") + with gr.Row(): + # radio = gr.Radio(label=' ', choices=[stickers[i].split('/')[-1].replace('.png', '') for i in range(len(stickers))], container=False, min_width=50) + choices = [sticker.split('/')[-1].replace('.png', '') for sticker in stickers] + radio = gr.Radio(label='', choices=choices, value="None", container=False, min_width=50, elem_classes="radio") + radio.change(lambda selection, cat=category: update_selections(cat, selection), inputs=[radio], outputs=[]) + + + +demo.launch() + + diff --git a/constants.py b/constants.py new file mode 100644 index 0000000000000000000000000000000000000000..e8fa123ea3f69f08be14337a8da3310bbcc0c891 --- /dev/null +++ b/constants.py @@ -0,0 +1,62 @@ +# Sticker's paths for each category +STICKER_PATHS = {'hats': ['./stickers/hats/None.png', './stickers/hats/santa.png', './stickers/hats/top.png', './stickers/hats/party.png', './stickers/hats/witch.png', './stickers/hats/green.png', './stickers/hats/chef.png', './stickers/hats/Christmas.png', './stickers/hats/mexican.png'], + 'animal face': ['./stickers/animal face/None.png', './stickers/animal face/laughing.png', './stickers/animal face/cool.png', './stickers/animal face/love.png', './stickers/animal face/cry.png', './stickers/animal face/evil.png', './stickers/animal face/blowing.png', './stickers/animal face/logy.png', './stickers/animal face/mysterious.png'], + 'ears': ['./stickers/ears/None.png', './stickers/ears/bunny.png', './stickers/ears/fox.png', './stickers/ears/fluffy.png', './stickers/ears/carrot.png', './stickers/ears/tiger.png', './stickers/ears/white.png', './stickers/ears/bent.png', './stickers/ears/bunny2.png'], + 'glasses': ['./stickers/glasses/None.png', './stickers/glasses/heart.png', './stickers/glasses/round.png', './stickers/glasses/pink.png', './stickers/glasses/cool.png', './stickers/glasses/gray.png', './stickers/glasses/blue.png', './stickers/glasses/rainbow.png', './stickers/glasses/reading.png'], + 'noses': ['./stickers/noses/None.png', './stickers/noses/clown.png', './stickers/noses/pig.png', './stickers/noses/dog1.png', './stickers/noses/dog2.png', './stickers/noses/dog3.png', './stickers/noses/dog4.png', './stickers/noses/dog5.png', './stickers/noses/dog6.png'], + 'headbands': ['./stickers/headbands/None.png', './stickers/headbands/deer.png', './stickers/headbands/blue.png', './stickers/headbands/bow.png', './stickers/headbands/flower.png', './stickers/headbands/devil.png', './stickers/headbands/cat.png', './stickers/headbands/christmas.png', './stickers/headbands/green.png']} + + + + +# Creating a new dictionary with sticker name as key and category as value +STICKER_TO_CATEGORY = { +'santa.png': 'hats', +'top.png': 'hats', +'party.png': 'hats', +'mexican.png': 'hats', +'witch.png': 'hats', +'green.png': 'hats', +'chef.png': 'hats', +'Christmas.png': 'hats', +'laughing.png': 'animal face', +'cool.png': 'animal face', +'love.png': 'animal face', +'cry.png': 'animal face', +'evil.png': 'animal face', +'blowing.png': 'animal face', +'logy.png': 'animal face', +'mysterious.png': 'animal face', +'bunny.png': 'ears', +'fox.png': 'ears', +'fluffy.png': 'ears', +'carrot.png': 'ears', +'tiger.png': 'ears', +'white.png': 'ears', +'bent.png': 'ears', +'bunny2.png': 'ears', +'heart.png': 'glasses', +'round.png': 'glasses', +'pink.png': 'glasses', +'cool.png': 'glasses', +'gray.png': 'glasses', +'blue.png': 'glasses', +'rainbow.png': 'glasses', +'reading.png': 'glasses', +'dog1.png': 'noses', +'pig.png': 'noses', +'clown.png': 'noses', +'dog2.png': 'noses', +'dog3.png': 'noses', +'dog4.png': 'noses', +'dog5.png': 'noses', +'dog6.png': 'noses', +'devil.png': 'headbands', +'cat.png': 'headbands', +'christmas.png': 'headbands', +'blue.png': 'headbands', +'bow.png': 'headbands', +'deer.png': 'headbands', +'flower.png': 'headbands', +'green.png': 'headbands', +} diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..005a488bf7f460125737f363c5847e4dbd2a742d --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +opencv-python +dlib +matplotlib +numpy +gradio \ No newline at end of file diff --git a/stickers/.DS_Store b/stickers/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..bde4bd12fe0a5290ada8efc93568c5e50b3a7a56 Binary files /dev/null and b/stickers/.DS_Store differ diff --git a/stickers/animal face/.DS_Store b/stickers/animal face/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..2a94d312b2ec2984af37635c47f7710273cc5cfe Binary files /dev/null and b/stickers/animal face/.DS_Store differ diff --git a/stickers/animal face/None.png b/stickers/animal face/None.png new file mode 100644 index 0000000000000000000000000000000000000000..0e5169af616984361a05f55f727a091789fb41d7 Binary files /dev/null and b/stickers/animal face/None.png differ diff --git a/stickers/animal face/blowing.png b/stickers/animal face/blowing.png new file mode 100644 index 0000000000000000000000000000000000000000..eb3ea86e9828c4395b7ebfbafcaac52fb04753cf Binary files /dev/null and b/stickers/animal face/blowing.png differ diff --git a/stickers/animal face/cool.png b/stickers/animal face/cool.png new file mode 100644 index 0000000000000000000000000000000000000000..ebf4023edf53145475107d3a2cc646e987d7fabc Binary files /dev/null and b/stickers/animal face/cool.png differ diff --git a/stickers/animal face/cry.png b/stickers/animal face/cry.png new file mode 100644 index 0000000000000000000000000000000000000000..51ff667fff75e7809938c2de87097f6104c1bf45 Binary files /dev/null and b/stickers/animal face/cry.png differ diff --git a/stickers/animal face/evil.png b/stickers/animal face/evil.png new file mode 100644 index 0000000000000000000000000000000000000000..eecab292ffcf1e5e9400125506d2a78ef833acbe Binary files /dev/null and b/stickers/animal face/evil.png differ diff --git a/stickers/animal face/laughing.png b/stickers/animal face/laughing.png new file mode 100644 index 0000000000000000000000000000000000000000..09544955181cb223ddaa187fa090976915b18ee7 Binary files /dev/null and b/stickers/animal face/laughing.png differ diff --git a/stickers/animal face/logy.png b/stickers/animal face/logy.png new file mode 100644 index 0000000000000000000000000000000000000000..e032be183709107a907566d38eba966ffd014ab1 Binary files /dev/null and b/stickers/animal face/logy.png differ diff --git a/stickers/animal face/love.png b/stickers/animal face/love.png new file mode 100644 index 0000000000000000000000000000000000000000..bc90c2869b8dea8270a578ebac710df4bf6b76f6 Binary files /dev/null and b/stickers/animal face/love.png differ diff --git a/stickers/animal face/mysterious.png b/stickers/animal face/mysterious.png new file mode 100644 index 0000000000000000000000000000000000000000..36a34efca7a4d0cdda9b6e129517cb5ea9fc7ea6 Binary files /dev/null and b/stickers/animal face/mysterious.png differ diff --git a/stickers/ears/.DS_Store b/stickers/ears/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..dd78cacb59e73a5384963291722cdedfd67e6dbc Binary files /dev/null and b/stickers/ears/.DS_Store differ diff --git a/stickers/ears/None.png b/stickers/ears/None.png new file mode 100644 index 0000000000000000000000000000000000000000..0e5169af616984361a05f55f727a091789fb41d7 Binary files /dev/null and b/stickers/ears/None.png differ diff --git a/stickers/ears/bent.png b/stickers/ears/bent.png new file mode 100644 index 0000000000000000000000000000000000000000..588a9862a646b08f1a9b53fe64e1605ca1c99dce Binary files /dev/null and b/stickers/ears/bent.png differ diff --git a/stickers/ears/bunny.png b/stickers/ears/bunny.png new file mode 100644 index 0000000000000000000000000000000000000000..169281dde57cb32427bf466d58e79a195f7e8232 Binary files /dev/null and b/stickers/ears/bunny.png differ diff --git a/stickers/ears/bunny2.png b/stickers/ears/bunny2.png new file mode 100644 index 0000000000000000000000000000000000000000..38f9c94fdf65f1db2bd65fda2af9da84c0f736c0 Binary files /dev/null and b/stickers/ears/bunny2.png differ diff --git a/stickers/ears/carrot.png b/stickers/ears/carrot.png new file mode 100644 index 0000000000000000000000000000000000000000..9da0cf0b78349f751618f9de200a6ae199ab2fe9 Binary files /dev/null and b/stickers/ears/carrot.png differ diff --git a/stickers/ears/fluffy.png b/stickers/ears/fluffy.png new file mode 100644 index 0000000000000000000000000000000000000000..8455a36e512dc54cb46e92c9b15eae58e5521f75 Binary files /dev/null and b/stickers/ears/fluffy.png differ diff --git a/stickers/ears/fox.png b/stickers/ears/fox.png new file mode 100644 index 0000000000000000000000000000000000000000..8f33a9de0fee76b4bb915bb12362540a62d246ea Binary files /dev/null and b/stickers/ears/fox.png differ diff --git a/stickers/ears/tiger.png b/stickers/ears/tiger.png new file mode 100644 index 0000000000000000000000000000000000000000..d48a1a910042ee9c97507068851f9672f9afba1a Binary files /dev/null and b/stickers/ears/tiger.png differ diff --git a/stickers/ears/white.png b/stickers/ears/white.png new file mode 100644 index 0000000000000000000000000000000000000000..b1c3cd2008eaa0a02e94fb0fc3449de7588934c4 Binary files /dev/null and b/stickers/ears/white.png differ diff --git a/stickers/glasses/.DS_Store b/stickers/glasses/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..27007a5027ee67e0408314244da6bbd0c6d98be0 Binary files /dev/null and b/stickers/glasses/.DS_Store differ diff --git a/stickers/glasses/None.png b/stickers/glasses/None.png new file mode 100644 index 0000000000000000000000000000000000000000..0e5169af616984361a05f55f727a091789fb41d7 Binary files /dev/null and b/stickers/glasses/None.png differ diff --git a/stickers/glasses/blue.png b/stickers/glasses/blue.png new file mode 100644 index 0000000000000000000000000000000000000000..6d55bad17a92093a8a39c3fbb1b58381e053af35 Binary files /dev/null and b/stickers/glasses/blue.png differ diff --git a/stickers/glasses/cool.png b/stickers/glasses/cool.png new file mode 100644 index 0000000000000000000000000000000000000000..dbba2b6788ab7459e733762673d5ac871630a315 Binary files /dev/null and b/stickers/glasses/cool.png differ diff --git a/stickers/glasses/gray.png b/stickers/glasses/gray.png new file mode 100644 index 0000000000000000000000000000000000000000..4ea3401af431ac2d19df9bc6624ce5280f6a941e Binary files /dev/null and b/stickers/glasses/gray.png differ diff --git a/stickers/glasses/heart.png b/stickers/glasses/heart.png new file mode 100644 index 0000000000000000000000000000000000000000..7ea46c6a7531d66d8975686293f21e426f32743e Binary files /dev/null and b/stickers/glasses/heart.png differ diff --git a/stickers/glasses/pink.png b/stickers/glasses/pink.png new file mode 100644 index 0000000000000000000000000000000000000000..757f6dfe0883b48e12017bbeb23ec6011bc7dd90 Binary files /dev/null and b/stickers/glasses/pink.png differ diff --git a/stickers/glasses/rainbow.png b/stickers/glasses/rainbow.png new file mode 100644 index 0000000000000000000000000000000000000000..4d8ff8fcaee026dde523256d43e90b3853e9e637 Binary files /dev/null and b/stickers/glasses/rainbow.png differ diff --git a/stickers/glasses/reading.png b/stickers/glasses/reading.png new file mode 100644 index 0000000000000000000000000000000000000000..1049022483523ede4171be1668e473e8463c6e31 Binary files /dev/null and b/stickers/glasses/reading.png differ diff --git a/stickers/glasses/round.png b/stickers/glasses/round.png new file mode 100644 index 0000000000000000000000000000000000000000..9eaca70d06508cb1ec111ec1b3730fd1ea0ca0a9 Binary files /dev/null and b/stickers/glasses/round.png differ diff --git a/stickers/hats/.DS_Store b/stickers/hats/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..a81c2a46d9b7447cf01363f75e7631bc12c7b88f Binary files /dev/null and b/stickers/hats/.DS_Store differ diff --git a/stickers/hats/Christmas.png b/stickers/hats/Christmas.png new file mode 100644 index 0000000000000000000000000000000000000000..55e577f50ce5db282fb6c9e1645e3deb89f6c1c3 Binary files /dev/null and b/stickers/hats/Christmas.png differ diff --git a/stickers/hats/None.png b/stickers/hats/None.png new file mode 100644 index 0000000000000000000000000000000000000000..0e5169af616984361a05f55f727a091789fb41d7 Binary files /dev/null and b/stickers/hats/None.png differ diff --git a/stickers/hats/chef.png b/stickers/hats/chef.png new file mode 100644 index 0000000000000000000000000000000000000000..5c837f34ad7314300559fa6c3a0663b74769ceab Binary files /dev/null and b/stickers/hats/chef.png differ diff --git a/stickers/hats/green.png b/stickers/hats/green.png new file mode 100644 index 0000000000000000000000000000000000000000..31c8bc402670870122976aef5d8c3edb98c3f277 Binary files /dev/null and b/stickers/hats/green.png differ diff --git a/stickers/hats/mexican.png b/stickers/hats/mexican.png new file mode 100644 index 0000000000000000000000000000000000000000..3719f787a7bfa37f85d45b7b99b664f48650fd2b Binary files /dev/null and b/stickers/hats/mexican.png differ diff --git a/stickers/hats/party.png b/stickers/hats/party.png new file mode 100644 index 0000000000000000000000000000000000000000..b02116e839f5e9efd6881e1bb706afb375bb38ec Binary files /dev/null and b/stickers/hats/party.png differ diff --git a/stickers/hats/santa.png b/stickers/hats/santa.png new file mode 100644 index 0000000000000000000000000000000000000000..84e09eabf0ff17cdbc469dc731cb232c325d9fc3 Binary files /dev/null and b/stickers/hats/santa.png differ diff --git a/stickers/hats/top.png b/stickers/hats/top.png new file mode 100644 index 0000000000000000000000000000000000000000..38cf00013ea05e5fd5f3c5dc07b333c22cc37487 Binary files /dev/null and b/stickers/hats/top.png differ diff --git a/stickers/hats/witch.png b/stickers/hats/witch.png new file mode 100644 index 0000000000000000000000000000000000000000..f8659f16c45f44ddac7a733a55dbf2a983eb0344 Binary files /dev/null and b/stickers/hats/witch.png differ diff --git a/stickers/headbands/.DS_Store b/stickers/headbands/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..7eb0e1c47437548ef218fd9e5a354063f6cea9f4 Binary files /dev/null and b/stickers/headbands/.DS_Store differ diff --git a/stickers/headbands/None.png b/stickers/headbands/None.png new file mode 100644 index 0000000000000000000000000000000000000000..0e5169af616984361a05f55f727a091789fb41d7 Binary files /dev/null and b/stickers/headbands/None.png differ diff --git a/stickers/headbands/blue.png b/stickers/headbands/blue.png new file mode 100644 index 0000000000000000000000000000000000000000..b6f596bc2b900fc5f2963628542b32bfbcd4cb43 Binary files /dev/null and b/stickers/headbands/blue.png differ diff --git a/stickers/headbands/bow.png b/stickers/headbands/bow.png new file mode 100644 index 0000000000000000000000000000000000000000..4878dfa0ee8e169f7071702f8c6b1c6b2c8023fb Binary files /dev/null and b/stickers/headbands/bow.png differ diff --git a/stickers/headbands/cat.png b/stickers/headbands/cat.png new file mode 100644 index 0000000000000000000000000000000000000000..cf64776b410a15df0d7cdb5d3020284322ff650e Binary files /dev/null and b/stickers/headbands/cat.png differ diff --git a/stickers/headbands/christmas.png b/stickers/headbands/christmas.png new file mode 100644 index 0000000000000000000000000000000000000000..f261e1fc187e18d4651429f660423707d0b16260 Binary files /dev/null and b/stickers/headbands/christmas.png differ diff --git a/stickers/headbands/deer.png b/stickers/headbands/deer.png new file mode 100644 index 0000000000000000000000000000000000000000..473ecbe84b92a042e5a292edd1d5a5de9773acc8 Binary files /dev/null and b/stickers/headbands/deer.png differ diff --git a/stickers/headbands/devil.png b/stickers/headbands/devil.png new file mode 100644 index 0000000000000000000000000000000000000000..8c22fa2c29bf42c53499939f51314fcc11641c6d Binary files /dev/null and b/stickers/headbands/devil.png differ diff --git a/stickers/headbands/flower.png b/stickers/headbands/flower.png new file mode 100644 index 0000000000000000000000000000000000000000..53c566fe83f4dea178e92f8d0272402060e84a68 Binary files /dev/null and b/stickers/headbands/flower.png differ diff --git a/stickers/headbands/green.png b/stickers/headbands/green.png new file mode 100644 index 0000000000000000000000000000000000000000..e227045a8d9b9b7e2046d3bd4fc68a48ff2f3c5a Binary files /dev/null and b/stickers/headbands/green.png differ diff --git a/stickers/noses/.DS_Store b/stickers/noses/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..e5f627e3353f10834989b381a2aa2a131a32d164 Binary files /dev/null and b/stickers/noses/.DS_Store differ diff --git a/stickers/noses/None.png b/stickers/noses/None.png new file mode 100644 index 0000000000000000000000000000000000000000..0e5169af616984361a05f55f727a091789fb41d7 Binary files /dev/null and b/stickers/noses/None.png differ diff --git a/stickers/noses/clown.png b/stickers/noses/clown.png new file mode 100644 index 0000000000000000000000000000000000000000..ffe204d636cfcbaba7fc2b4a81599764ca700afa --- /dev/null +++ b/stickers/noses/clown.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:229a4f423f3752f27bc26dfd41336be67598972361afc600559f776ca624af74 +size 2191686 diff --git a/stickers/noses/dog1.png b/stickers/noses/dog1.png new file mode 100644 index 0000000000000000000000000000000000000000..a8ca16c6555bcce61fec85c825a1a2530ccd947d Binary files /dev/null and b/stickers/noses/dog1.png differ diff --git a/stickers/noses/dog2.png b/stickers/noses/dog2.png new file mode 100644 index 0000000000000000000000000000000000000000..f81aee61f5c3778c1475e041c1838f45ee3eba39 Binary files /dev/null and b/stickers/noses/dog2.png differ diff --git a/stickers/noses/dog3.png b/stickers/noses/dog3.png new file mode 100644 index 0000000000000000000000000000000000000000..cbab74a7acfce893510d9be8e75fcd84bb50a6c1 Binary files /dev/null and b/stickers/noses/dog3.png differ diff --git a/stickers/noses/dog4.png b/stickers/noses/dog4.png new file mode 100644 index 0000000000000000000000000000000000000000..130e58e32612e6c7d6482394d73f69f761361397 Binary files /dev/null and b/stickers/noses/dog4.png differ diff --git a/stickers/noses/dog5.png b/stickers/noses/dog5.png new file mode 100644 index 0000000000000000000000000000000000000000..87ccf61c66318b45ad1e3d0a3b9da00b61a810e1 Binary files /dev/null and b/stickers/noses/dog5.png differ diff --git a/stickers/noses/dog6.png b/stickers/noses/dog6.png new file mode 100644 index 0000000000000000000000000000000000000000..3e2ce2f2e9eb863920870b5a54775208dc98827c Binary files /dev/null and b/stickers/noses/dog6.png differ diff --git a/stickers/noses/pig.png b/stickers/noses/pig.png new file mode 100644 index 0000000000000000000000000000000000000000..1e8507062ca6830d1f4f3e412e49e35440033c98 Binary files /dev/null and b/stickers/noses/pig.png differ