FanMagnetAgency commited on
Commit
0dd4bc4
·
verified ·
1 Parent(s): 510d2b7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +122 -59
app.py CHANGED
@@ -1,4 +1,5 @@
1
- # app.py - Interface principale
 
2
  import gradio as gr
3
  import cv2
4
  import insightface
@@ -7,96 +8,158 @@ from insightface.model_zoo import get_model
7
  import numpy as np
8
  import os
9
 
10
- # Initialiser le modèle
11
- app = FaceAnalysis(name='buffalo_l')
12
- app.prepare(ctx_id=0, det_size=(640, 640))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
  # Charger le modèle de swap
15
- model_path = 'inswapper_128.onnx'
16
 
17
- if not os.path.exists(model_path):
18
- print("Téléchargement du modèle inswapper...")
19
- os.system('wget -O inswapper_128.onnx https://github.com/deepinsight/insightface/releases/download/v0.7/inswapper_128.onnx')
20
- swapper = get_model(model_path, download=False, download_zip=False)
21
 
22
  def swap_face(source_img, target_img):
23
  """
24
  Swap le visage de source_img vers target_img
25
  """
26
  try:
27
- # Convertir en BGR pour OpenCV
 
 
 
28
  source = cv2.cvtColor(np.array(source_img), cv2.COLOR_RGB2BGR)
29
  target = cv2.cvtColor(np.array(target_img), cv2.COLOR_RGB2BGR)
30
-
31
- # Détecter les visages
32
  source_faces = app.get(source)
33
  target_faces = app.get(target)
34
-
35
  if len(source_faces) == 0:
36
  return None, "❌ Aucun visage détecté dans l'image source"
37
-
38
  if len(target_faces) == 0:
39
  return None, "❌ Aucun visage détecté dans l'image cible"
40
-
41
- # Prendre le premier visage de chaque image
42
  source_face = source_faces[0]
43
-
44
- # Effectuer le swap sur tous les visages de la cible
45
  result = target.copy()
46
- for target_face in target_faces:
47
- result = swapper.get(result, target_face, source_face, paste_back=True)
48
-
49
- # Reconvertir en RGB pour affichage
 
 
 
 
 
 
 
50
  result_rgb = cv2.cvtColor(result, cv2.COLOR_BGR2RGB)
51
-
52
- return result_rgb, "✅ Face swap réussi !"
53
-
54
  except Exception as e:
55
- return None, f"❌ Erreur: {str(e)}"
 
 
 
 
56
 
57
- # Interface Gradio
58
  with gr.Blocks(title="Face Swapper Pro", theme=gr.themes.Soft()) as demo:
59
  gr.Markdown("""
60
- # 🎭 Face Swapper Pro
61
- ### Échangez les visages entre deux photos en quelques secondes
62
-
63
- **Instructions :**
64
- 1. Uploadez une photo **source** (le visage que vous voulez utiliser)
65
- 2. Uploadez une photo **cible** (la photo remplacer le visage)
66
- 3. Cliquez sur "🔄 Swap Faces"
67
- """)
68
-
69
  with gr.Row():
70
- with gr.Column():
71
- source_image = gr.Image(
72
- label="📸 Image Source (votre visage)",
73
- type="pil",
74
- height=400
75
- )
76
- with gr.Column():
77
- target_image = gr.Image(
78
- label="🎯 Image Cible (visage à remplacer)",
79
- type="pil",
80
- height=400
81
- )
82
-
83
- swap_btn = gr.Button("🔄 Swap Faces", variant="primary", size="lg")
84
-
85
  status_text = gr.Textbox(label="Statut", interactive=False)
86
-
87
  result_image = gr.Image(label="✨ Résultat", height=500)
88
-
89
- # Actions
90
  swap_btn.click(
91
  fn=swap_face,
92
  inputs=[source_image, target_image],
93
  outputs=[result_image, status_text]
94
  )
95
-
96
  gr.Markdown("""
97
- ---
98
- **Note:** Pour de meilleurs résultats, utilisez des images avec des visages bien visibles et bien éclairés.
99
- """)
 
 
 
 
 
 
 
100
 
101
  if __name__ == "__main__":
102
- demo.launch()
 
 
1
+ # app.py - Interface principale Face Swap (Hugging Face Space safe)
2
+
3
  import gradio as gr
4
  import cv2
5
  import insightface
 
8
  import numpy as np
9
  import os
10
 
11
+ # ===============================
12
+ # 1️⃣ Initialisation FaceAnalysis
13
+ # ===============================
14
+
15
+ app = FaceAnalysis(name="buffalo_l")
16
+
17
+ # GPU si dispo, sinon CPU
18
+ try:
19
+ app.prepare(ctx_id=0, det_size=(640, 640))
20
+ print("✅ FaceAnalysis chargé avec GPU")
21
+ except Exception:
22
+ app.prepare(ctx_id=-1, det_size=(640, 640))
23
+ print("⚠️ GPU indisponible → fallback CPU")
24
+
25
+ # ===============================
26
+ # 2️⃣ Téléchargement sécurisé du modèle inswapper
27
+ # ===============================
28
+
29
+ MODEL_PATH = "inswapper_128.onnx"
30
+ HF_URL = (
31
+ "https://huggingface.co/ezioruan/inswapper_128.onnx/"
32
+ "resolve/main/inswapper_128.onnx"
33
+ )
34
+ MIN_BYTES = 200 * 1024 * 1024 # 200 MB minimum (sécurité)
35
+
36
+ def ensure_inswapper(path: str):
37
+ # Fichier existant mais trop petit = corrompu
38
+ if os.path.exists(path) and os.path.getsize(path) < MIN_BYTES:
39
+ print(f"⚠️ {path} corrompu → suppression")
40
+ os.remove(path)
41
+
42
+ # Télécharger si absent
43
+ if not os.path.exists(path):
44
+ print("⬇️ Téléchargement de inswapper_128.onnx depuis Hugging Face...")
45
+ cmd = (
46
+ "wget -L --retry-connrefused --waitretry=1 "
47
+ "--tries=5 --timeout=30 "
48
+ f"-O {path} '{HF_URL}'"
49
+ )
50
+ code = os.system(cmd)
51
+ if code != 0:
52
+ raise RuntimeError("❌ Échec du téléchargement de inswapper_128.onnx")
53
+
54
+ # Vérification finale
55
+ size = os.path.getsize(path)
56
+ if size < MIN_BYTES:
57
+ raise RuntimeError(
58
+ f"❌ inswapper_128.onnx invalide (taille {size} bytes)"
59
+ )
60
+
61
+ print(f"✅ inswapper_128.onnx prêt ({size // (1024*1024)} MB)")
62
+
63
+ ensure_inswapper(MODEL_PATH)
64
 
65
  # Charger le modèle de swap
66
+ swapper = get_model(MODEL_PATH, download=False, download_zip=False)
67
 
68
+ # ===============================
69
+ # 3️⃣ Fonction de face swap
70
+ # ===============================
 
71
 
72
  def swap_face(source_img, target_img):
73
  """
74
  Swap le visage de source_img vers target_img
75
  """
76
  try:
77
+ if source_img is None or target_img is None:
78
+ return None, "❌ Merci de charger deux images"
79
+
80
+ # Convertir PIL → OpenCV (BGR)
81
  source = cv2.cvtColor(np.array(source_img), cv2.COLOR_RGB2BGR)
82
  target = cv2.cvtColor(np.array(target_img), cv2.COLOR_RGB2BGR)
83
+
84
+ # Détection des visages
85
  source_faces = app.get(source)
86
  target_faces = app.get(target)
87
+
88
  if len(source_faces) == 0:
89
  return None, "❌ Aucun visage détecté dans l'image source"
90
+
91
  if len(target_faces) == 0:
92
  return None, "❌ Aucun visage détecté dans l'image cible"
93
+
 
94
  source_face = source_faces[0]
 
 
95
  result = target.copy()
96
+
97
+ # Swap sur chaque visage cible
98
+ for face in target_faces:
99
+ result = swapper.get(
100
+ result,
101
+ face,
102
+ source_face,
103
+ paste_back=True
104
+ )
105
+
106
+ # OpenCV → RGB
107
  result_rgb = cv2.cvtColor(result, cv2.COLOR_BGR2RGB)
108
+
109
+ return result_rgb, "✅ Face swap réussi"
110
+
111
  except Exception as e:
112
+ return None, f"❌ Erreur : {str(e)}"
113
+
114
+ # ===============================
115
+ # 4️⃣ Interface Gradio
116
+ # ===============================
117
 
 
118
  with gr.Blocks(title="Face Swapper Pro", theme=gr.themes.Soft()) as demo:
119
  gr.Markdown("""
120
+ # 🎭 Face Swapper Pro
121
+ ### Échangez les visages entre deux images
122
+
123
+ **Instructions :**
124
+ 1. Image source = visage à utiliser
125
+ 2. Image cible = visage(s) à remplacer
126
+ 3. Cliquez sur **Swap Faces**
127
+ """)
128
+
129
  with gr.Row():
130
+ source_image = gr.Image(
131
+ label="📸 Image source",
132
+ type="pil",
133
+ height=400
134
+ )
135
+ target_image = gr.Image(
136
+ label="🎯 Image cible",
137
+ type="pil",
138
+ height=400
139
+ )
140
+
141
+ swap_btn = gr.Button("🔄 Swap Faces", variant="primary")
 
 
 
142
  status_text = gr.Textbox(label="Statut", interactive=False)
 
143
  result_image = gr.Image(label="✨ Résultat", height=500)
144
+
 
145
  swap_btn.click(
146
  fn=swap_face,
147
  inputs=[source_image, target_image],
148
  outputs=[result_image, status_text]
149
  )
150
+
151
  gr.Markdown("""
152
+ ---
153
+ 💡 **Conseils**
154
+ - Visages bien éclairés
155
+ - Angle similaire = meilleur rendu
156
+ - Fonctionne avec plusieurs visages sur la cible
157
+ """)
158
+
159
+ # ===============================
160
+ # 5️⃣ Lancement
161
+ # ===============================
162
 
163
  if __name__ == "__main__":
164
+ demo.launch()
165
+