Corin1998 commited on
Commit
5bfcc41
·
verified ·
1 Parent(s): 8d7e167

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +46 -61
app.py CHANGED
@@ -6,107 +6,92 @@ import insightface
6
  import urllib.request
7
  from insightface.app import FaceAnalysis
8
 
9
- # --- 0. モデルの自動ダウンロード設定 ---
10
  def download_model_if_missing():
11
  model_filename = 'inswapper_128.onnx'
12
- # 公開されている信頼性の高いURLから取得
13
  url = "https://huggingface.co/ezioruan/inswapper_128.onnx/resolve/main/inswapper_128.onnx"
14
-
15
  if not os.path.exists(model_filename):
16
- print(f"【情報】{model_filename} が見つかりません。ダウンロードを開始します...")
17
- try:
18
- # プログレスバーなしのシンプルなダウンロード
19
- urllib.request.urlretrieve(url, model_filename)
20
- print(f"【完了】{model_filename} のダウンロードに成功しました。")
21
- except Exception as e:
22
- print(f"【エラー】ダウンロードに失敗しました: {e}")
23
 
24
- # 実行
25
  download_model_if_missing()
26
 
27
  # --- 1. モデルの初期化 ---
28
- try:
29
- # 顔検出モデル (buffalo_l)
30
- app = FaceAnalysis(name='buffalo_l', providers=['CPUExecutionProvider'])
31
- app.prepare(ctx_id=0, det_size=(640, 640))
32
-
33
- # 顔入れ替えモデル (inswapper_128.onnx)
34
- model_path = 'inswapper_128.onnx'
35
- if os.path.exists(model_path):
36
- swapper = insightface.model_zoo.get_model(model_path, download=False, providers=['CPUExecutionProvider'])
37
- else:
38
- swapper = None
39
- except Exception as e:
40
- print(f"Initialization Error: {e}")
41
- swapper = None
42
 
43
  # --- 2. 動画処理ロジック ---
44
- def process_video(source_img, target_video):
45
- if swapper is None:
46
- return None, "モデルファイルが読み込めていません。リポジトリを確認してください。"
47
  if source_img is None or target_video is None:
48
- return None, "画像と動画の両方アップロードしてください。"
49
 
50
- # ソース顔(入れ替え後顔)の抽出
51
  source_faces = app.get(source_img)
52
  if not source_faces:
53
- return None, "画像から顔を検出できませんでした。"
54
  source_face = source_faces[0]
55
 
56
- # 動画読み込み
57
  cap = cv2.VideoCapture(target_video)
 
 
 
58
  fps = cap.get(cv2.CAP_PROP_FPS)
59
  width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
60
  height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
61
-
62
- # 出力設定
63
- output_path = "output_swapped.mp4"
64
- # OpenCVのデフォルトmp4コーデック
65
  fourcc = cv2.VideoWriter_fourcc(*'mp4v')
66
  out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
67
 
68
- frame_count = 0
69
- while cap.isOpened():
 
70
  ret, frame = cap.read()
71
  if not ret:
72
  break
73
 
74
- # フレーム内の全ターゲット検出
75
- target_faces = app.get(frame)
76
-
77
- # 入れ替え実行(トラッキング的に全顔対応)
78
  res_frame = frame.copy()
79
- for face in target_faces:
80
  res_frame = swapper.get(res_frame, face, source_face, paste_back=True)
81
 
82
  out.write(res_frame)
83
- frame_count += 1
84
-
 
 
 
 
85
  cap.release()
86
  out.release()
87
 
88
- return output_path, f"成功! {frame_count} レームを処理しました。"
 
 
89
 
90
- # --- 3. UI (Gradio) ---
 
 
91
  with gr.Blocks() as demo:
92
- gr.Markdown("# 🎬 AI Face Swap Video Processor (Stable Ver.)")
93
- gr.Markdown("アップロードされた動画の全フレームをスキャンし、顔を自動で追跡して入れ替えます。")
94
-
95
  with gr.Row():
96
  with gr.Column():
97
- src_img = gr.Image(label="1. 入れ替え後の顔画像", type="numpy")
98
- tgt_vid = gr.Video(label="2. 対象の動画ファイル")
99
- btn = gr.Button("動画を変換する")
100
-
101
  with gr.Column():
102
- out_vid = gr.Video(label="3. 生成結果(ダウンロード可)")
103
- status = gr.Textbox(label="ステータス", interactive=False)
104
 
105
- btn.click(
106
  fn=process_video,
107
- inputs=[src_img, tgt_vid],
108
- outputs=[out_vid, status]
109
  )
110
 
111
- if __name__ == "__main__":
112
- demo.launch()
 
6
  import urllib.request
7
  from insightface.app import FaceAnalysis
8
 
9
+ # --- 0. モデルの自動ダウンロード ---
10
  def download_model_if_missing():
11
  model_filename = 'inswapper_128.onnx'
 
12
  url = "https://huggingface.co/ezioruan/inswapper_128.onnx/resolve/main/inswapper_128.onnx"
 
13
  if not os.path.exists(model_filename):
14
+ print("Downloading model...")
15
+ urllib.request.urlretrieve(url, model_filename)
 
 
 
 
 
16
 
 
17
  download_model_if_missing()
18
 
19
  # --- 1. モデルの初期化 ---
20
+ app = FaceAnalysis(name='buffalo_l', providers=['CPUExecutionProvider'])
21
+ app.prepare(ctx_id=0, det_size=(640, 640))
22
+ swapper = insightface.model_zoo.get_model('inswapper_128.onnx', download=False, providers=['CPUExecutionProvider'])
 
 
 
 
 
 
 
 
 
 
 
23
 
24
  # --- 2. 動画処理ロジック ---
25
+ def process_video(source_img, target_video, progress=gr.Progress()):
 
 
26
  if source_img is None or target_video is None:
27
+ return None, "画像と動画を選択してください。"
28
 
29
+ # ソース顔の抽出
30
  source_faces = app.get(source_img)
31
  if not source_faces:
32
+ return None, "画像から顔が見つかりません。"
33
  source_face = source_faces[0]
34
 
35
+ # 動画読み込み
36
  cap = cv2.VideoCapture(target_video)
37
+ if not cap.isOpened():
38
+ return None, "動画ファイルを開けませんでした。"
39
+
40
  fps = cap.get(cv2.CAP_PROP_FPS)
41
  width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
42
  height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
43
+ total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
44
+
45
+ # 出力ファイル設定 (より汎用的な mp4v を使用)
46
+ output_path = "output_result.mp4"
47
  fourcc = cv2.VideoWriter_fourcc(*'mp4v')
48
  out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
49
 
50
+ # フレーム処理ループ
51
+ frame_idx = 0
52
+ while True:
53
  ret, frame = cap.read()
54
  if not ret:
55
  break
56
 
57
+ # 顔検出と入れ替え
58
+ faces = app.get(frame)
 
 
59
  res_frame = frame.copy()
60
+ for face in faces:
61
  res_frame = swapper.get(res_frame, face, source_face, paste_back=True)
62
 
63
  out.write(res_frame)
64
+ frame_idx += 1
65
+
66
+ # 進捗をUIに反映
67
+ if total_frames > 0:
68
+ progress(frame_idx / total_frames, desc=f"処理中... {frame_idx}/{total_frames}")
69
+
70
  cap.release()
71
  out.release()
72
 
73
+ # 最終的なァイルの存在確認
74
+ if not os.path.exists(output_path):
75
+ return None, "動画の生成に失敗しました。"
76
 
77
+ return output_path, "完了しました!"
78
+
79
+ # --- 3. UI ---
80
  with gr.Blocks() as demo:
81
+ gr.Markdown("### 🎬 Stable Face Swapper")
 
 
82
  with gr.Row():
83
  with gr.Column():
84
+ img_input = gr.Image(label="入れ替え顔画像", type="numpy")
85
+ vid_input = gr.Video(label="ターゲット動画")
86
+ submit_btn = gr.Button("変換開始")
 
87
  with gr.Column():
88
+ vid_output = gr.Video(label="出力結果")
89
+ status_text = gr.Textbox(label="ステータス")
90
 
91
+ submit_btn.click(
92
  fn=process_video,
93
+ inputs=[img_input, vid_input],
94
+ outputs=[vid_output, status_text]
95
  )
96
 
97
+ demo.launch()