| import gradio as gr |
| import insightface |
| from insightface.app import FaceAnalysis |
| import numpy as np |
| from PIL import Image |
| import cv2 |
| import tempfile |
| import os |
|
|
| MODEL_PATH = "inswapper_128.onnx" |
|
|
| |
| print("Loading models...") |
| face_app = FaceAnalysis(name="buffalo_l") |
| face_app.prepare(ctx_id=0, det_size=(640, 640)) |
| swapper = insightface.model_zoo.get_model(MODEL_PATH) |
| print("Models loaded.") |
|
|
| |
| def swap_faces_image(source, target): |
| if source is None or target is None: |
| raise gr.Error("Please upload both source and target images.") |
|
|
| |
| src = np.array(source) |
| dst = np.array(target) |
|
|
| src_faces = face_app.get(src) |
| dst_faces = face_app.get(dst) |
|
|
| if len(src_faces) == 0: |
| raise gr.Error("No face found in source image.") |
| if len(dst_faces) == 0: |
| raise gr.Error("No face found in target image.") |
|
|
| src_face = src_faces[0] |
| dst_face = dst_faces[0] |
|
|
| result = swapper.get(dst.copy(), dst_face, src_face, paste_back=True) |
| return Image.fromarray(result) |
|
|
| |
| def swap_faces_video(source_image, video_file): |
| if source_image is None: |
| raise gr.Error("Please upload a source face image.") |
| if video_file is None: |
| raise gr.Error("Please upload a target video (mp4).") |
|
|
| |
| src = np.array(source_image) |
| src_faces = face_app.get(src) |
| if len(src_faces) == 0: |
| raise gr.Error("No face found in source image.") |
| src_face = src_faces[0] |
|
|
| |
| video_path = video_file.name |
|
|
| cap = cv2.VideoCapture(video_path) |
| if not cap.isOpened(): |
| raise gr.Error("Could not open uploaded video.") |
|
|
| fps = cap.get(cv2.CAP_PROP_FPS) or 25 |
| w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) |
| h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) |
|
|
| |
| tmp_out = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") |
| tmp_out_path = tmp_out.name |
| tmp_out.close() |
|
|
| fourcc = cv2.VideoWriter_fourcc(*"mp4v") |
| writer = cv2.VideoWriter(tmp_out_path, fourcc, fps, (w, h)) |
|
|
| total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) |
| print(f"[INFO] Total frames: {total_frames}") |
|
|
| frame_idx = 0 |
| while True: |
| ret, frame = cap.read() |
| if not ret: |
| break |
| frame_idx += 1 |
| if frame_idx % 10 == 0: |
| print(f"[INFO] Frame {frame_idx}/{total_frames}") |
|
|
| |
| rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) |
| dst_faces = face_app.get(rgb) |
|
|
| if len(dst_faces) > 0: |
| dst_face = dst_faces[0] |
| swapped_rgb = swapper.get(rgb.copy(), dst_face, src_face, paste_back=True) |
| out_frame = cv2.cvtColor(swapped_rgb, cv2.COLOR_RGB2BGR) |
| writer.write(out_frame) |
| else: |
| writer.write(frame) |
|
|
| cap.release() |
| writer.release() |
|
|
| print(f"[INFO] Video finished: {tmp_out_path}") |
| return tmp_out_path |
|
|
| |
| with gr.Blocks() as demo: |
| gr.Markdown("## InsightFace FaceSwap (Image & Video) on HuggingFace") |
|
|
| with gr.Tab("Image Swap"): |
| src_img = gr.Image(type="numpy", label="Your Face (Source)") |
| tgt_img = gr.Image(type="numpy", label="Target Face") |
| out_img = gr.Image(label="Swapped Result") |
|
|
| btn_img = gr.Button("Swap Image") |
| btn_img.click(fn=swap_faces_image, inputs=[src_img, tgt_img], outputs=out_img) |
|
|
| with gr.Tab("Video Swap"): |
| src_vid_img = gr.Image(type="numpy", label="Your Face (Source)") |
| tgt_vid = gr.File(label="Target Video (mp4)") |
| out_vid = gr.Video(label="Swapped Video") |
|
|
| btn_vid = gr.Button("Swap Video") |
| btn_vid.click(fn=swap_faces_video, inputs=[src_vid_img, tgt_vid], outputs=out_vid) |
|
|
| if __name__ == "__main__": |
| demo.launch() |
|
|