Spaces:
Runtime error
Runtime error
| import os | |
| import cv2 | |
| import numpy as np | |
| import gradio as gr | |
| import insightface | |
| import urllib.request | |
| from insightface.app import FaceAnalysis | |
| # --- 0. モデルの自動ダウンロード --- | |
| def download_model_if_missing(): | |
| model_filename = 'inswapper_128.onnx' | |
| url = "https://huggingface.co/ezioruan/inswapper_128.onnx/resolve/main/inswapper_128.onnx" | |
| if not os.path.exists(model_filename): | |
| print("Downloading model...") | |
| urllib.request.urlretrieve(url, model_filename) | |
| download_model_if_missing() | |
| # --- 1. モデルの初期化 --- | |
| app = FaceAnalysis(name='buffalo_l', providers=['CPUExecutionProvider']) | |
| app.prepare(ctx_id=0, det_size=(640, 640)) | |
| swapper = insightface.model_zoo.get_model('inswapper_128.onnx', download=False, providers=['CPUExecutionProvider']) | |
| # --- 2. 動画処理ロジック --- | |
| def process_video(source_img, target_video, progress=gr.Progress()): | |
| if source_img is None or target_video is None: | |
| return None, "画像と動画を選択してください。" | |
| # ソース顔の抽出 | |
| source_faces = app.get(source_img) | |
| if not source_faces: | |
| return None, "画像から顔が見つかりません。" | |
| source_face = source_faces[0] | |
| # 動画の読み込み | |
| cap = cv2.VideoCapture(target_video) | |
| if not cap.isOpened(): | |
| return None, "動画ファイルを開けませんでした。" | |
| fps = cap.get(cv2.CAP_PROP_FPS) | |
| width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) | |
| height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) | |
| total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) | |
| # 出力ファイル設定 (より汎用的な mp4v を使用) | |
| output_path = "output_result.mp4" | |
| fourcc = cv2.VideoWriter_fourcc(*'mp4v') | |
| out = cv2.VideoWriter(output_path, fourcc, fps, (width, height)) | |
| # フレーム処理ループ | |
| frame_idx = 0 | |
| while True: | |
| ret, frame = cap.read() | |
| if not ret: | |
| break | |
| # 顔の検出と入れ替え | |
| faces = app.get(frame) | |
| res_frame = frame.copy() | |
| for face in faces: | |
| res_frame = swapper.get(res_frame, face, source_face, paste_back=True) | |
| out.write(res_frame) | |
| frame_idx += 1 | |
| # 進捗をUIに反映 | |
| if total_frames > 0: | |
| progress(frame_idx / total_frames, desc=f"処理中... {frame_idx}/{total_frames}") | |
| cap.release() | |
| out.release() | |
| # 最終的なファイルの存在確認 | |
| if not os.path.exists(output_path): | |
| return None, "動画の生成に失敗しました。" | |
| return output_path, "完了しました!" | |
| # --- 3. UI --- | |
| with gr.Blocks() as demo: | |
| gr.Markdown("### 🎬 Stable Face Swapper") | |
| with gr.Row(): | |
| with gr.Column(): | |
| img_input = gr.Image(label="入れ替える顔画像", type="numpy") | |
| vid_input = gr.Video(label="ターゲット動画") | |
| submit_btn = gr.Button("変換開始") | |
| with gr.Column(): | |
| vid_output = gr.Video(label="出力結果") | |
| status_text = gr.Textbox(label="ステータス") | |
| submit_btn.click( | |
| fn=process_video, | |
| inputs=[img_input, vid_input], | |
| outputs=[vid_output, status_text] | |
| ) | |
| demo.launch() |