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