mr2along commited on
Commit
9c9d565
·
verified ·
1 Parent(s): 3f532f2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +87 -48
app.py CHANGED
@@ -7,16 +7,15 @@ import insightface
7
  import onnxruntime
8
  import gradio as gr
9
  from tqdm import tqdm
 
10
 
11
  from face_swapper import Inswapper, paste_to_whole
12
  from face_analyser import analyse_face
13
- from face_enhancer import (
14
- load_face_enhancer_model,
15
- get_available_enhancer_names,
16
- )
17
 
18
  # ------------------------------ ARGS ------------------------------
19
- parser = argparse.ArgumentParser(description="Face Swapper (Male+Female with Enhancers)")
20
  parser.add_argument("--out_dir", default=os.getcwd())
21
  parser.add_argument("--batch_size", default=32)
22
  parser.add_argument("--cuda", action="store_true", default=False)
@@ -50,82 +49,122 @@ FACE_SWAPPER = Inswapper(
50
 
51
  # ------------------------------ ENHANCERS ------------------------------
52
  ENHANCER_CHOICES = ["NONE"] + get_available_enhancer_names()
53
- # ví dụ: ["NONE", "CodeFormer", "GFPGAN", "REAL-ESRGAN 2x", "REAL-ESRGAN 4x", "REAL-ESRGAN 8x"]
54
-
55
- # ------------------------------ PROCESS ------------------------------
56
- def swap_faces(image_path, male_source_path, female_source_path, enhancer_name="NONE"):
57
- start_time = time.time()
58
-
59
- # Load target & sources
60
- target_bgr = cv2.imread(image_path)
61
- if target_bgr is None:
62
- raise ValueError("Không đọc được ảnh đích.")
63
-
64
- src_male_img = cv2.imread(male_source_path)
65
- src_female_img = cv2.imread(female_source_path)
66
- if src_male_img is None or src_female_img is None:
67
- raise ValueError("Không đọc được ảnh nguồn (nam/nữ).")
68
-
69
- analysed_source_male = analyse_face(src_male_img, FACE_ANALYSER)
70
- analysed_source_female = analyse_face(src_female_img, FACE_ANALYSER)
71
-
72
- # Phân tích các khuôn mặt trong ảnh đích
73
- analysed_faces = FACE_ANALYSER.get(target_bgr)
74
 
 
 
 
75
  preds, matrs = [], []
76
- for analysed_face in tqdm(analysed_faces, desc="Swapping faces"):
77
- # gender: 1 = male, 0 = female (theo insightface)
78
  src_face = analysed_source_male if analysed_face.get("gender", 1) == 1 else analysed_source_female
79
- batch_pred, batch_matr = FACE_SWAPPER.get([target_bgr], [analysed_face], [src_face])
80
  preds.extend(batch_pred)
81
  matrs.extend(batch_matr)
82
  EMPTY_CACHE()
83
 
84
- # Ghép lại
85
  for p, m in zip(preds, matrs):
86
- target_bgr = paste_to_whole(
87
  foreground=p,
88
- background=target_bgr,
89
  matrix=m,
90
  mask=None,
91
  crop_mask=(0, 0, 0, 0),
92
  blur_amount=0.1,
93
  erode_amount=0.15,
94
- blend_method="laplacian" # tự nhiên hơn
95
  )
96
 
97
- # Enhance (nếu chọn)
98
  if enhancer_name != "NONE":
99
  try:
100
  model, runner = load_face_enhancer_model(name=enhancer_name, device=device)
101
- target_bgr = runner(target_bgr, model)
102
- except AssertionError as e:
103
- print(f"[Enhancer] {e}. Trả về ảnh không enhance.")
104
  except Exception as e:
105
- print(f"[Enhancer] Lỗi khi chạy {enhancer_name}: {e}. Trả về ảnh không enhance.")
106
 
107
- print(f"✔ Hoàn tất trong {time.time() - start_time:.2f}s")
108
- return target_bgr[:, :, ::-1] # BGR -> RGB để hiển thị
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
 
110
  # ------------------------------ UI ------------------------------
111
  with gr.Blocks() as demo:
112
- gr.Markdown("## 🧑‍🦱➡👩 Face Swapper (2 nguồn nam/nữ) + Enhancer (CodeFormer / GFPGAN / Real-ESRGAN)")
113
 
114
  with gr.Row():
115
  with gr.Column():
116
- image_input = gr.Image(label="Ảnh đích (Target Image)", type="filepath")
117
- male_input = gr.Image(label="Ảnh nguồn Nam", type="filepath")
118
- female_input = gr.Image(label="Ảnh nguồn Nữ", type="filepath")
119
  enhancer = gr.Dropdown(ENHANCER_CHOICES, label="Face Enhancer", value="NONE")
120
  run_btn = gr.Button("✨ Swap")
121
 
122
  with gr.Column():
123
- output_image = gr.Image(label="Kết quả")
 
 
 
 
 
 
 
 
124
 
125
  run_btn.click(
126
- fn=swap_faces,
127
- inputs=[image_input, male_input, female_input, enhancer],
128
- outputs=output_image,
129
  )
130
 
131
  if __name__ == "__main__":
 
7
  import onnxruntime
8
  import gradio as gr
9
  from tqdm import tqdm
10
+ from moviepy.editor import VideoFileClip
11
 
12
  from face_swapper import Inswapper, paste_to_whole
13
  from face_analyser import analyse_face
14
+ from face_enhancer import load_face_enhancer_model, get_available_enhancer_names
15
+ from utils import merge_img_sequence_from_ref
 
 
16
 
17
  # ------------------------------ ARGS ------------------------------
18
+ parser = argparse.ArgumentParser(description="Face Swapper (Multi-target, Male+Female Sources)")
19
  parser.add_argument("--out_dir", default=os.getcwd())
20
  parser.add_argument("--batch_size", default=32)
21
  parser.add_argument("--cuda", action="store_true", default=False)
 
49
 
50
  # ------------------------------ ENHANCERS ------------------------------
51
  ENHANCER_CHOICES = ["NONE"] + get_available_enhancer_names()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
+ # ------------------------------ CORE SWAP FUNC ------------------------------
54
+ def swap_on_frame(frame_bgr, analysed_source_male, analysed_source_female, enhancer_name="NONE"):
55
+ analysed_faces = FACE_ANALYSER.get(frame_bgr)
56
  preds, matrs = [], []
57
+
58
+ for analysed_face in analysed_faces:
59
  src_face = analysed_source_male if analysed_face.get("gender", 1) == 1 else analysed_source_female
60
+ batch_pred, batch_matr = FACE_SWAPPER.get([frame_bgr], [analysed_face], [src_face])
61
  preds.extend(batch_pred)
62
  matrs.extend(batch_matr)
63
  EMPTY_CACHE()
64
 
 
65
  for p, m in zip(preds, matrs):
66
+ frame_bgr = paste_to_whole(
67
  foreground=p,
68
+ background=frame_bgr,
69
  matrix=m,
70
  mask=None,
71
  crop_mask=(0, 0, 0, 0),
72
  blur_amount=0.1,
73
  erode_amount=0.15,
74
+ blend_method="laplacian",
75
  )
76
 
 
77
  if enhancer_name != "NONE":
78
  try:
79
  model, runner = load_face_enhancer_model(name=enhancer_name, device=device)
80
+ frame_bgr = runner(frame_bgr, model)
 
 
81
  except Exception as e:
82
+ print(f"[Enhancer] Lỗi khi chạy {enhancer_name}: {e}")
83
 
84
+ return frame_bgr
85
+
86
+ # ------------------------------ PROCESS ------------------------------
87
+ def swap_faces(target_files, male_file, female_file, enhancer_name="NONE"):
88
+ start_time = time.time()
89
+
90
+ male_source_path = male_file.name
91
+ female_source_path = female_file.name
92
+ analysed_source_male = analyse_face(cv2.imread(male_source_path), FACE_ANALYSER)
93
+ analysed_source_female = analyse_face(cv2.imread(female_source_path), FACE_ANALYSER)
94
+
95
+ out_images, out_videos = [], []
96
+
97
+ for f in target_files:
98
+ target_path = f.name
99
+ ext = os.path.splitext(target_path)[-1].lower()
100
+
101
+ # -------------------- IMAGE --------------------
102
+ if ext in [".jpg", ".jpeg", ".png"]:
103
+ frame_bgr = cv2.imread(target_path)
104
+ out_frame = swap_on_frame(frame_bgr, analysed_source_male, analysed_source_female, enhancer_name)
105
+ out_images.append(out_frame[:, :, ::-1]) # RGB
106
+ out_videos.append(None)
107
+
108
+ # -------------------- VIDEO --------------------
109
+ elif ext in [".mp4", ".avi", ".mov"]:
110
+ temp_dir = os.path.join(DEF_OUTPUT_PATH, "temp_frames")
111
+ os.makedirs(temp_dir, exist_ok=True)
112
+
113
+ cap = cv2.VideoCapture(target_path)
114
+ fps = cap.get(cv2.CAP_PROP_FPS)
115
+ frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
116
+
117
+ print(f">>> Đang xử lý video {os.path.basename(target_path)}: {frame_count} frames @ {fps:.1f} FPS")
118
+
119
+ frame_paths = []
120
+ idx = 0
121
+ while True:
122
+ ret, frame = cap.read()
123
+ if not ret:
124
+ break
125
+ swapped = swap_on_frame(frame, analysed_source_male, analysed_source_female, enhancer_name)
126
+ frame_path = os.path.join(temp_dir, f"frame_{idx:05d}.jpg")
127
+ cv2.imwrite(frame_path, swapped)
128
+ frame_paths.append(frame_path)
129
+ idx += 1
130
+ cap.release()
131
+
132
+ out_path = os.path.join(DEF_OUTPUT_PATH, f"swapped_{os.path.basename(target_path)}")
133
+ merge_img_sequence_from_ref(target_path, frame_paths, out_path)
134
+
135
+ out_images.append(None)
136
+ out_videos.append(out_path)
137
+
138
+ print(f"✔ Hoàn tất tất cả trong {time.time() - start_time:.2f}s")
139
+ return out_images, out_videos
140
 
141
  # ------------------------------ UI ------------------------------
142
  with gr.Blocks() as demo:
143
+ gr.Markdown("## 🧑‍🦱➡👩 Face Swapper (Upload nhiều file target + nguồn nam/nữ) + Enhancer")
144
 
145
  with gr.Row():
146
  with gr.Column():
147
+ target_input = gr.File(label="Files đích (ảnh/video)", file_types=[".jpg", ".png", ".mp4"], file_types_allow_multiple=True)
148
+ male_input = gr.File(label="File nguồn Nam (ảnh)", file_types=[".jpg", ".png"])
149
+ female_input = gr.File(label="File nguồn Nữ (ảnh)", file_types=[".jpg", ".png"])
150
  enhancer = gr.Dropdown(ENHANCER_CHOICES, label="Face Enhancer", value="NONE")
151
  run_btn = gr.Button("✨ Swap")
152
 
153
  with gr.Column():
154
+ output_gallery = gr.Gallery(label="Kết quả ảnh")
155
+ output_videos = gr.File(label="Kết quả video", file_types=[".mp4"], file_types_allow_multiple=True)
156
+
157
+ def run_wrapper(target_files, male_file, female_file, enhancer_name):
158
+ out_imgs, out_vids = swap_faces(target_files, male_file, female_file, enhancer_name)
159
+ # Gallery hiển thị list ảnh
160
+ imgs = [img for img in out_imgs if img is not None]
161
+ vids = [v for v in out_vids if v is not None]
162
+ return imgs, vids
163
 
164
  run_btn.click(
165
+ fn=run_wrapper,
166
+ inputs=[target_input, male_input, female_input, enhancer],
167
+ outputs=[output_gallery, output_videos],
168
  )
169
 
170
  if __name__ == "__main__":