from PIL import Image, ImageOps, ImageEnhance import mediapipe as mp import numpy as np import cv2 import gradio as gr import imageio class FaceSwapper: def __init__(self): self.landmarks_a = None self.landmarks_b = None self.image_a = None self.image_b = None self.image_a_origin = None self.image_b_origin = None def get_face_landmarks(self, image): with mp.solutions.face_mesh.FaceMesh( static_image_mode=True, max_num_faces=1, refine_landmarks=True, min_detection_confidence=0.5 ) as face_mesh: results = face_mesh.process(cv2.cvtColor(np.array(image), cv2.COLOR_BGR2RGB)) if not results.multi_face_landmarks: return None landmarks = results.multi_face_landmarks[0].landmark w, h = image.size face_landmarks = [(int(p.x * w), int(p.y * h)) for p in landmarks] return face_landmarks def load_images(self, image_a, image_b): if image_a: if image_a.convert("RGBA") != self.image_a_origin: self.image_a = image_a.convert("RGBA") self.image_a_origin = image_a.convert("RGBA") self.landmarks_a = self.get_face_landmarks(self.image_a) if image_b: if image_b.convert("RGBA") != self.image_a_origin: self.image_b = image_b.convert("RGBA") self.image_b_origin = image_b.convert("RGBA") self.landmarks_b = self.get_face_landmarks(self.image_b) if not self.landmarks_a or not self.landmarks_b: return None def overlay_image(self, background, overlay, position): x, y = position if background.mode != 'RGBA': background = background.convert('RGBA') if overlay.mode != 'RGBA': overlay = overlay.convert('RGBA') overlay_mask = overlay.split()[3] background.paste(overlay, (x, y), overlay_mask) return background def swap_faces(self, scale_factor=1.0, offset_x=0, offset_y=0, rotation_angle=0, margin_left=0.1, margin_right=0.1, margin_top=0.1, margin_bottom=0.1, mirror_face_a=False): if not self.landmarks_a or not self.image_a or not self.image_b: raise ValueError("Image Load Error Or Face Not Deteceted") min_x_a = min([p[0] for p in self.landmarks_a]) max_x_a = max([p[0] for p in self.landmarks_a]) min_y_a = min([p[1] for p in self.landmarks_a]) max_y_a = max([p[1] for p in self.landmarks_a]) width_a = max_x_a - min_x_a height_a = max_y_a - min_y_a face_a = self.image_a.crop(( int(min_x_a - width_a * margin_left), int(min_y_a - height_a * 0.85 * margin_top), int(max_x_a + width_a * margin_right), int(max_y_a + height_a * margin_bottom) )) if mirror_face_a: face_a = ImageOps.mirror(face_a) if not self.landmarks_b: width_b, height_b = self.image_b.size width_a, height_a = self.image_a.size center_x_b = width_b // 2 center_y_b = height_b // 5 scale_w = width_b / width_a * scale_factor scale_h = height_b / height_a * scale_factor else: min_x_b = min([p[0] for p in self.landmarks_b]) max_x_b = max([p[0] for p in self.landmarks_b]) min_y_b = min([p[1] for p in self.landmarks_b]) max_y_b = max([p[1] for p in self.landmarks_b]) width_b = max_x_b - min_x_b height_b = max_y_b - min_y_b center_x_b = min_x_b + width_b // 2 center_y_b = min_y_b + height_b // 2 scale_w = width_b / face_a.width * 1.4 * scale_factor scale_h = height_b / face_a.height * 1.4 * scale_factor scale = min(scale_w, scale_h) new_width = int(face_a.width * scale) new_height = int(face_a.height * scale) face_a_resized = face_a.resize((new_width, new_height), Image.LANCZOS) face_a_rotated = face_a_resized.rotate(rotation_angle, expand=True) final_offset_x = center_x_b - face_a_rotated.width // 2 + offset_x final_offset_y = center_y_b - face_a_rotated.height // 2 + offset_y result_image = self.overlay_image(self.image_b.copy(), face_a_rotated, (final_offset_x, final_offset_y)) return result_image def adjust_colors(self, is_select_image_a, saturation, temperature, contrast, brightness): image = self.image_a_origin if is_select_image_a else self.image_b_origin if not image: raise ValueError("Selected image is not loaded.") # Convert to RGB if necessary if image.mode != 'RGB': image = image.convert('RGB') # Adjust brightness enhancer = ImageEnhance.Brightness(image) image = enhancer.enhance(brightness) # Adjust contrast enhancer = ImageEnhance.Contrast(image) image = enhancer.enhance(contrast) # Adjust saturation enhancer = ImageEnhance.Color(image) image = enhancer.enhance(saturation) # Adjust temperature by modifying color balance r, g, b = image.split() # Handling three channels only r = r.point(lambda i: i + temperature * 10) b = b.point(lambda i: i - temperature * 10) image = Image.merge("RGB", (r, g, b)) # Re-merge as RGB if is_select_image_a: self.image_a = image else: self.image_b = image return image # Function to swap faces def process(image_a, image_b, scale_factor, offset_x, offset_y, rotation_angle, margin_left, margin_right, margin_top, margin_bottom, mirror_face_a): try: face_swapper = FaceSwapper() face_swapper.load_images(image_a, image_b) if face_swapper.image_a and face_swapper.image_b: result = face_swapper.swap_faces( scale_factor=scale_factor, offset_x=offset_x, offset_y=offset_y, rotation_angle=rotation_angle, margin_left=margin_left, margin_right=margin_right, margin_top=margin_top, margin_bottom=margin_bottom, mirror_face_a=mirror_face_a ) return result except Exception as e: return str(e) def adujst_color_process(image_a, image_b, scale_factor, offset_x, offset_y, rotation_angle, margin_left, margin_right, margin_top, margin_bottom, mirror_face_a, saturation, temperature, contrast, brightness, saturation_b, temperature_b, contrast_b, brightness_b): try: face_swapper = FaceSwapper() face_swapper.load_images(image_a, image_b) face_swapper.adjust_colors(True, saturation, temperature, contrast, brightness) face_swapper.adjust_colors(False, saturation_b, temperature_b, contrast_b, brightness_b) if face_swapper.image_a and face_swapper.image_b: result = face_swapper.swap_faces( scale_factor=scale_factor, offset_x=offset_x, offset_y=offset_y, rotation_angle=rotation_angle, margin_left=margin_left, margin_right=margin_right, margin_top=margin_top, margin_bottom=margin_bottom, mirror_face_a=mirror_face_a ) return result except Exception as e: return str(e) # Function for image masking (demonstrative) def dummy(img): # Assuming img is a dictionary with keys 'composite', 'background', and 'layers' composite_image = img["composite"] imageio.imwrite("output_image.png", composite_image) alpha_channel = img["layers"][0][:, :, 3] mask = np.where(alpha_channel == 0, 0, 255).astype(np.uint8) return mask # Function to update the image in Tab 1 def update_image(image): return image # Announcement text for tab 1 announcement = """ ## BRAUNDRESS ENTRY: BRAUNDRESS 入口: [Click Here](https://braundress.me/entry) ## Backup Inpaint Mask Maker: 备用蒙版工具: [Visit Here](https://huggingface.co/spaces/BraUndress/inpaint-mask-maker2) ## How to Use: 使用方法: [Learn More](https://telegra.ph/HowToUploadMaskOnBraundress-05-01) Source: BraUndress """ # Announcement text for tab 2 announcement_2 = """ ## Backup Inpaint Mask Maker: 备用蒙版工具: [Visit Here](https://huggingface.co/spaces/BraUndress/inpaint-mask-maker2) ## How to Use: 使用方法: [Learn More](https://telegra.ph/100-Similarity-Face-Swapped-with-Braundress-Mask-Upload-Mode-07-23) Source: BraUndress """ # Create Gradio interface with Tabs with gr.Blocks() as app: tab1 = gr.Tab("Inpaint Mask Maker") tab2 = gr.Tab("Face Swap") with tab1: with gr.Row(): with gr.Column(): announcement = gr.Markdown(announcement) with gr.Column(): with gr.Row(): img = gr.ImageMask( sources=["upload", "clipboard"], transforms=[], layers=False, format="png", label="base image", show_label=True ) img2 = gr.Image(label="mask image", show_label=True, format="png") btn = gr.Button("Generate Mask") btn.click(dummy, inputs=img, outputs=img2) with tab2: with gr.Row(): with gr.Column(): announcement_2 = gr.Markdown(announcement_2) with gr.Row(): img_input_a = gr.Image(type="pil", label="Input Face Image A(输入人脸图片)", height=300) img_input_b = gr.Image(type="pil", label="Input Face Swapped Image B(输入换脸图片)", height=300) with gr.Row(): scale_factor = gr.Slider(0.1, 3.5, 1, 0.1, label="Face Scale Factor(人脸放大)") offset_x = gr.Slider(-400, 400, 0, 1, label="Face Offset X(人脸水平横移)") offset_y = gr.Slider(-400, 400, 0, 1, label="Face Offset Y(人脸垂直横移)") rotation_angle = gr.Slider(-180, 180, 0, 1, label="Face Rotation Angle(人脸旋转)") margin_left = gr.Slider(0, 1, 0.1, 0.01, label="Face Margin Left(人脸左边缘扩展)") margin_right = gr.Slider(0, 1, 0.1, 0.01, label="Face Margin Right(人脸右边缘扩展)") margin_top = gr.Slider(0, 1, 0.1, 0.01, label="Face Margin Top(人脸上边缘扩展)") margin_bottom = gr.Slider(0, 1, 0, 0.01, label="Face Margin Bottom(人脸下边缘扩展)") mirror_face_a = gr.Checkbox(label="Mirror Face A(人脸镜像)") # btn_process = gr.Button("Swap Faces") with gr.Row(): image_select = gr.Radio(['Image A'], value='Image A', label="Adjust Color For Image A(图片A调整颜色)") saturation = gr.Slider(0, 2.0, 1.0, 0.1, label="Saturation(饱和度)") temperature = gr.Slider(-10, 10, 0, 0.1, label="Color Temperature(色温)") contrast = gr.Slider(0, 2.0, 1.0, 0.1, label="Contrast(对比度)") brightness = gr.Slider(0, 2.0, 1.0, 0.1, label="Brightness(亮度)") with gr.Row(): image_select_b = gr.Radio(['Image B'], value='Image B', label="Adjust Color For Image B(图片B调整颜色)") saturation_b = gr.Slider(0, 2.0, 1.0, 0.1, label="Saturation(饱和度)") temperature_b = gr.Slider(-10, 10, 0, 0.1, label="Color Temperature(色温)") contrast_b = gr.Slider(0, 2.0, 1.0, 0.1, label="Contrast(对比度)") brightness_b = gr.Slider(0, 2.0, 1.0, 0.1, label="Brightness(亮度)") result_image = gr.Image(type="pil", label="Result Image", height=600) # btn_process.click(process, inputs=[img_input_a, img_input_b, scale_factor, offset_x, offset_y, rotation_angle, margin_left, margin_right, margin_top, margin_bottom, mirror_face_a], outputs=result_image) scale_factor.release(adujst_color_process, inputs=[img_input_a, img_input_b, scale_factor, offset_x, offset_y, rotation_angle, margin_left, margin_right, margin_top, margin_bottom, mirror_face_a, saturation, temperature, contrast, brightness, saturation_b, temperature_b, contrast_b, brightness_b], outputs=result_image) offset_x.release(adujst_color_process, inputs=[img_input_a, img_input_b, scale_factor, offset_x, offset_y, rotation_angle, margin_left, margin_right, margin_top, margin_bottom, mirror_face_a, saturation, temperature, contrast, brightness, saturation_b, temperature_b, contrast_b, brightness_b], outputs=result_image) offset_y.release(adujst_color_process, inputs=[img_input_a, img_input_b, scale_factor, offset_x, offset_y, rotation_angle, margin_left, margin_right, margin_top, margin_bottom, mirror_face_a, saturation, temperature, contrast, brightness, saturation_b, temperature_b, contrast_b, brightness_b], outputs=result_image) rotation_angle.release(adujst_color_process, inputs=[img_input_a, img_input_b, scale_factor, offset_x, offset_y, rotation_angle, margin_left, margin_right, margin_top, margin_bottom, mirror_face_a, saturation, temperature, contrast, brightness, saturation_b, temperature_b, contrast_b, brightness_b], outputs=result_image) margin_left.release(adujst_color_process, inputs=[img_input_a, img_input_b, scale_factor, offset_x, offset_y, rotation_angle, margin_left, margin_right, margin_top, margin_bottom, mirror_face_a, saturation, temperature, contrast, brightness, saturation_b, temperature_b, contrast_b, brightness_b], outputs=result_image) margin_right.release(adujst_color_process, inputs=[img_input_a, img_input_b, scale_factor, offset_x, offset_y, rotation_angle, margin_left, margin_right, margin_top, margin_bottom, mirror_face_a, saturation, temperature, contrast, brightness, saturation_b, temperature_b, contrast_b, brightness_b], outputs=result_image) margin_top.release(adujst_color_process, inputs=[img_input_a, img_input_b, scale_factor, offset_x, offset_y, rotation_angle, margin_left, margin_right, margin_top, margin_bottom, mirror_face_a, saturation, temperature, contrast, brightness, saturation_b, temperature_b, contrast_b, brightness_b], outputs=result_image) margin_bottom.release(adujst_color_process, inputs=[img_input_a, img_input_b, scale_factor, offset_x, offset_y, rotation_angle, margin_left, margin_right, margin_top, margin_bottom, mirror_face_a, saturation, temperature, contrast, brightness, saturation_b, temperature_b, contrast_b, brightness_b], outputs=result_image) img_input_a.change(adujst_color_process, inputs=[img_input_a, img_input_b, scale_factor, offset_x, offset_y, rotation_angle, margin_left, margin_right, margin_top, margin_bottom, mirror_face_a, saturation, temperature, contrast, brightness, saturation_b, temperature_b, contrast_b, brightness_b], outputs=result_image) img_input_b.change(adujst_color_process, inputs=[img_input_a, img_input_b, scale_factor, offset_x, offset_y, rotation_angle, margin_left, margin_right, margin_top, margin_bottom, mirror_face_a, saturation, temperature, contrast, brightness, saturation_b, temperature_b, contrast_b, brightness_b], outputs=result_image) mirror_face_a.change(adujst_color_process, inputs=[img_input_a, img_input_b, scale_factor, offset_x, offset_y, rotation_angle, margin_left, margin_right, margin_top, margin_bottom, mirror_face_a, saturation, temperature, contrast, brightness, saturation_b, temperature_b, contrast_b, brightness_b], outputs=result_image) saturation.release(adujst_color_process, inputs=[img_input_a, img_input_b,scale_factor, offset_x, offset_y, rotation_angle, margin_left, margin_right, margin_top, margin_bottom, mirror_face_a, saturation, temperature, contrast, brightness, saturation_b, temperature_b, contrast_b, brightness_b], outputs=result_image) temperature.release(adujst_color_process, inputs=[img_input_a, img_input_b,scale_factor, offset_x, offset_y, rotation_angle, margin_left, margin_right, margin_top, margin_bottom, mirror_face_a, saturation, temperature, contrast, brightness, saturation_b, temperature_b, contrast_b, brightness_b], outputs=result_image) contrast.release(adujst_color_process, inputs=[img_input_a, img_input_b,scale_factor, offset_x, offset_y, rotation_angle, margin_left, margin_right, margin_top, margin_bottom, mirror_face_a, saturation, temperature, contrast, brightness, saturation_b, temperature_b, contrast_b, brightness_b], outputs=result_image) brightness.release(adujst_color_process, inputs=[img_input_a, img_input_b,scale_factor, offset_x, offset_y, rotation_angle, margin_left, margin_right, margin_top, margin_bottom, mirror_face_a, saturation, temperature, contrast, brightness, saturation_b, temperature_b, contrast_b, brightness_b], outputs=result_image) saturation_b.release(adujst_color_process, inputs=[img_input_a, img_input_b,scale_factor, offset_x, offset_y, rotation_angle, margin_left, margin_right, margin_top, margin_bottom, mirror_face_a, saturation, temperature, contrast, brightness, saturation_b, temperature_b, contrast_b, brightness_b], outputs=result_image) temperature_b.release(adujst_color_process, inputs=[img_input_a, img_input_b,scale_factor, offset_x, offset_y, rotation_angle, margin_left, margin_right, margin_top, margin_bottom, mirror_face_a, saturation, temperature, contrast, brightness, saturation_b, temperature_b, contrast_b, brightness_b], outputs=result_image) contrast_b.release(adujst_color_process, inputs=[img_input_a, img_input_b,scale_factor, offset_x, offset_y, rotation_angle, margin_left, margin_right, margin_top, margin_bottom, mirror_face_a, saturation, temperature, contrast, brightness, saturation_b, temperature_b, contrast_b, brightness_b], outputs=result_image) brightness_b.release(adujst_color_process, inputs=[img_input_a, img_input_b,scale_factor, offset_x, offset_y, rotation_angle, margin_left, margin_right, margin_top, margin_bottom, mirror_face_a, saturation, temperature, contrast, brightness, saturation_b, temperature_b, contrast_b, brightness_b], outputs=result_image) btn_send_to_tab1 = gr.Button("Send To Mask Maker(发送给蒙版制作页面)") btn_send_to_tab1.click(update_image, inputs=result_image, outputs=img) app.launch()