Athagi commited on
Commit
3a54726
Β·
1 Parent(s): 570c459

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +90 -66
app.py CHANGED
@@ -1,42 +1,47 @@
1
- import os
 
 
2
  import cv2
3
  import numpy as np
4
- import gradio as gr
5
- from insightface.app import FaceAnalysis
6
- from insightface.model_zoo import get_model
7
  from PIL import Image
 
8
  import tempfile
9
-
10
- # Load InsightFace components
 
 
 
 
 
 
 
11
  face_analyzer = FaceAnalysis(name='buffalo_l', providers=['CPUExecutionProvider'])
12
  face_analyzer.prepare(ctx_id=0, det_size=(640, 640))
13
 
14
- swapper_model_path = "models/inswapper_128.onnx"
15
- swapper = get_model(swapper_model_path, download=False)
16
-
17
- def draw_faces(image_np, faces):
18
- """Draw bounding boxes and labels on detected faces."""
19
- image_draw = image_np.copy()
20
- for i, face in enumerate(faces):
21
- box = face.bbox.astype(int)
22
- cv2.rectangle(image_draw, (box[0], box[1]), (box[2], box[3]), (0, 255, 0), 2)
23
- cv2.putText(image_draw, f"Face {i}", (box[0], box[1] - 10),
24
- cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
25
- return image_draw
26
-
27
- def preview_faces(target_image):
28
- """Preview all detected faces in target image."""
29
- if target_image is None:
30
- raise gr.Error("Please upload a target image.")
31
- target_np = cv2.cvtColor(np.array(target_image), cv2.COLOR_RGB2BGR)
32
- faces = face_analyzer.get(target_np)
33
- if len(faces) == 0:
34
- raise gr.Error("No faces found in target image.")
35
- preview_img = draw_faces(target_np, faces)
36
- preview_img_rgb = cv2.cvtColor(preview_img, cv2.COLOR_BGR2RGB)
37
- return Image.fromarray(preview_img_rgb), [str(i) for i in range(len(faces))]
38
-
39
- def swap_faces(source_img, target_img, face_index_str, blend_alpha):
40
  if source_img is None or target_img is None:
41
  raise gr.Error("Please upload both source and target images.")
42
 
@@ -44,62 +49,81 @@ def swap_faces(source_img, target_img, face_index_str, blend_alpha):
44
  target_np = cv2.cvtColor(np.array(target_img), cv2.COLOR_RGB2BGR)
45
 
46
  source_faces = face_analyzer.get(source_np)
47
- if len(source_faces) == 0:
48
- raise gr.Error("No face found in source image.")
49
-
50
  target_faces = face_analyzer.get(target_np)
 
 
 
51
  if len(target_faces) == 0:
52
- raise gr.Error("No faces found in target image.")
53
 
54
  face_index = int(face_index_str)
55
  if face_index >= len(target_faces):
56
- raise gr.Error("Face index out of range.")
57
 
58
- # Perform face swap
59
  try:
60
  swapped = swapper.get(target_np, target_faces[face_index], source_faces[0], paste_back=True)
61
- # Blend original + swapped if alpha < 1.0
62
- if 0 <= blend_alpha < 1.0:
63
- blended = cv2.addWeighted(target_np, 1 - blend_alpha, swapped, blend_alpha, 0)
64
- else:
65
- blended = swapped
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  final_rgb = cv2.cvtColor(blended, cv2.COLOR_BGR2RGB)
67
  output_img = Image.fromarray(final_rgb)
68
 
69
- # Save temp file for download
70
  tmp_file = tempfile.NamedTemporaryFile(suffix=".jpg", delete=False)
71
  output_img.save(tmp_file.name)
72
- return output_img, tmp_file.name, "βœ… Face swap successful!"
73
-
74
  except Exception as e:
75
- raise gr.Error(f"Face swap failed: {e}")
 
 
 
 
 
 
 
76
 
77
  # Gradio UI
78
- with gr.Blocks(title="Enhanced Face Swap") as demo:
79
- gr.Markdown("## πŸ” Enhanced Face Swapper (CPU-only)")
 
 
 
80
 
81
  with gr.Row():
82
- source_image = gr.Image(label="Source Face", type="pil")
83
- target_image = gr.Image(label="Target Image", type="pil")
84
 
85
- preview_btn = gr.Button("πŸ‘οΈ Preview Detected Faces")
86
- preview_output = gr.Image(label="Target Faces Preview")
87
- face_dropdown = gr.Dropdown(choices=[], label="Select Face Index")
88
- blend_slider = gr.Slider(label="Swap Strength", minimum=0.0, maximum=1.0, step=0.1, value=1.0)
89
- swap_button = gr.Button("πŸ”„ Swap Face")
90
 
91
  with gr.Row():
92
- output_image = gr.Image(label="Swapped Result")
93
- download_file = gr.File(label="Download Swapped Image")
 
94
 
 
 
 
95
  status = gr.Textbox(label="Status", interactive=False)
96
 
97
- preview_btn.click(preview_faces, inputs=target_image,
98
- outputs=[preview_output, face_dropdown])
99
-
100
- swap_button.click(swap_faces,
101
- inputs=[source_image, target_image, face_dropdown, blend_slider],
102
- outputs=[output_image, download_file, status])
103
 
104
- if __name__ == "__main__":
105
- demo.launch()
 
1
+ # app.py
2
+
3
+ import gradio as gr
4
  import cv2
5
  import numpy as np
 
 
 
6
  from PIL import Image
7
+ import os
8
  import tempfile
9
+ from insightface.app import FaceAnalysis
10
+ from insightface.model_zoo.inswapper import INSwapper
11
+ from skimage.exposure import match_histograms
12
+ import torch
13
+ from basicsr.archs.rrdbnet_arch import RRDBNet
14
+ from realesrgan import RealESRGANer
15
+ from gfpgan import GFPGANer
16
+
17
+ # Setup face analyzer
18
  face_analyzer = FaceAnalysis(name='buffalo_l', providers=['CPUExecutionProvider'])
19
  face_analyzer.prepare(ctx_id=0, det_size=(640, 640))
20
 
21
+ # Load face swapper
22
+ swapper = INSwapper("models/inswapper_128.onnx")
23
+
24
+ # Load GFPGAN and Real-ESRGAN
25
+ bg_upsampler = RealESRGANer(
26
+ scale=2,
27
+ model_path='models/RealESRGAN_x2plus.pth',
28
+ model=RRDBNet(num_in_ch=3, num_out_ch=3, num_feat=64,
29
+ num_block=23, num_grow_ch=32, scale=2),
30
+ tile=400, tile_pad=10, pre_pad=0, half=False
31
+ )
32
+
33
+ face_enhancer = GFPGANer(
34
+ model_path='models/GFPGANv1.3.pth',
35
+ upscale=2,
36
+ arch='clean',
37
+ channel_multiplier=2,
38
+ bg_upsampler=bg_upsampler
39
+ )
40
+
41
+ def match_histogram(source_face, target_face):
42
+ return match_histograms(source_face, target_face, channel_axis=-1)
43
+
44
+ def swap_faces(source_img, target_img, face_index_str, blend_alpha, enhance_face):
 
 
45
  if source_img is None or target_img is None:
46
  raise gr.Error("Please upload both source and target images.")
47
 
 
49
  target_np = cv2.cvtColor(np.array(target_img), cv2.COLOR_RGB2BGR)
50
 
51
  source_faces = face_analyzer.get(source_np)
 
 
 
52
  target_faces = face_analyzer.get(target_np)
53
+
54
+ if len(source_faces) == 0:
55
+ raise gr.Error("No face detected in source image.")
56
  if len(target_faces) == 0:
57
+ raise gr.Error("No faces detected in target image.")
58
 
59
  face_index = int(face_index_str)
60
  if face_index >= len(target_faces):
61
+ raise gr.Error(f"Face index {face_index} out of range (found {len(target_faces)} faces).")
62
 
 
63
  try:
64
  swapped = swapper.get(target_np, target_faces[face_index], source_faces[0], paste_back=True)
65
+
66
+ box = target_faces[face_index].bbox.astype(int)
67
+ x1, y1, x2, y2 = box
68
+ original_face = target_np[y1:y2, x1:x2]
69
+ swapped_face = swapped[y1:y2, x1:x2]
70
+ matched = match_histogram(swapped_face, original_face)
71
+ swapped[y1:y2, x1:x2] = matched.astype(np.uint8)
72
+
73
+ mask = np.zeros_like(swapped[:, :, 0])
74
+ cv2.rectangle(mask, (x1, y1), (x2, y2), 255, -1)
75
+ mask = cv2.GaussianBlur(mask, (15, 15), 0)
76
+ blended = np.where(mask[..., None] > 0,
77
+ cv2.addWeighted(swapped, blend_alpha, target_np, 1 - blend_alpha, 0),
78
+ target_np)
79
+
80
+ if enhance_face:
81
+ _, _, enhanced = face_enhancer.enhance(blended, has_aligned=False, only_center_face=False, paste_back=True)
82
+ blended = enhanced
83
+
84
  final_rgb = cv2.cvtColor(blended, cv2.COLOR_BGR2RGB)
85
  output_img = Image.fromarray(final_rgb)
86
 
 
87
  tmp_file = tempfile.NamedTemporaryFile(suffix=".jpg", delete=False)
88
  output_img.save(tmp_file.name)
89
+ return output_img, tmp_file.name, "βœ… Swap & Enhancement Completed!"
 
90
  except Exception as e:
91
+ raise gr.Error(f"Swap failed: {str(e)}")
92
+
93
+ def count_faces(image):
94
+ if image is None:
95
+ return "Please upload a target image."
96
+ img_np = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
97
+ faces = face_analyzer.get(img_np)
98
+ return f"{len(faces)} face(s) detected in the target image."
99
 
100
  # Gradio UI
101
+ with gr.Blocks(title="πŸ’« Face Swap & Enhance App") as demo:
102
+ gr.Markdown("""
103
+ # πŸ”„ Face Swapper + πŸ‘©β€πŸ”§ GFPGAN Enhancer + πŸ§™ Real-ESRGAN
104
+ Upload a face and swap it into another photo. Optional face enhancement with GFPGAN!
105
+ """)
106
 
107
  with gr.Row():
108
+ source_input = gr.Image(label="πŸ§‘ Source Face", type="pil")
109
+ target_input = gr.Image(label="πŸ§‘ Target Image", type="pil")
110
 
111
+ detect_button = gr.Button("πŸ” Detect Faces in Target")
112
+ face_count = gr.Textbox(label="Detected Faces", interactive=False)
113
+ detect_button.click(count_faces, inputs=target_input, outputs=face_count)
 
 
114
 
115
  with gr.Row():
116
+ face_index = gr.Textbox(label="🎯 Face Index", value="0")
117
+ blend_slider = gr.Slider(label="πŸ’« Blend Smoothness", minimum=0, maximum=1, value=0.8, step=0.05)
118
+ enhance_face = gr.Checkbox(label="✨ Enhance Face with GFPGAN", value=True)
119
 
120
+ swap_button = gr.Button("πŸ” Run Face Swap")
121
+ output_img = gr.Image(label="πŸ–ΌοΈ Output")
122
+ download_path = gr.File(label="πŸ“₯ Download")
123
  status = gr.Textbox(label="Status", interactive=False)
124
 
125
+ swap_button.click(swap_faces, inputs=[source_input, target_input, face_index, blend_slider, enhance_face],
126
+ outputs=[output_img, download_path, status])
 
 
 
 
127
 
128
+ if __name__ == '__main__':
129
+ demo.launch()