leonelhs commited on
Commit
8e7e652
·
1 Parent(s): f48a7f8

starting from the scratch

Browse files
Files changed (6) hide show
  1. README.md +20 -5
  2. app.py +86 -0
  3. face_analysis.py +58 -0
  4. meanshape_68.pkl +3 -0
  5. playground.py +24 -0
  6. requirements.txt +5 -0
README.md CHANGED
@@ -1,14 +1,29 @@
1
  ---
2
  title: FaceFusion
3
- emoji: 🏢
4
- colorFrom: red
5
- colorTo: gray
6
  sdk: gradio
7
  sdk_version: 5.49.0
8
  app_file: app.py
9
  pinned: false
10
  license: mit
11
- short_description: Image face swap
12
  ---
13
 
14
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
  title: FaceFusion
3
+ emoji: 😻
4
+ colorFrom: purple
5
+ colorTo: green
6
  sdk: gradio
7
  sdk_version: 5.49.0
8
  app_file: app.py
9
  pinned: false
10
  license: mit
11
+ short_description: Swap faces in images
12
  ---
13
 
14
+ ## Unofficial FaceFusion Implementation
15
+
16
+ FaceFusion has evolved significantly, increasing in complexity over time.
17
+ This project was therefore developed from scratch to provide a simplified and more accessible implementation while retaining the essential functionality.
18
+
19
+ ## Acknowledgments
20
+
21
+ This work preserves key functionality from the original authors:
22
+ - [DeepInsight](https://github.com/deepinsight/insightface)
23
+ - [FaceFusion](https://github.com/facefusion/facefusion)
24
+
25
+ ## Contact
26
+
27
+ For questions, comments, or feedback, please contact:
28
+ 📧 **[email protected]**
29
+
app.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #######################################################################################
2
+ #
3
+ # MIT License
4
+ #
5
+ # Copyright (c) [2025] [[email protected]]
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in all
15
+ # copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ # SOFTWARE.
24
+ #
25
+ #######################################################################################
26
+ #
27
+ # Source code is based on or inspired by several projects.
28
+ # For more details and proper attribution, please refer to the following resources:
29
+ #
30
+ # - [Deepinsight] - [https://github.com/deepinsight/insightface]
31
+ # - [FaceFusion] [https://github.com/facefusion/facefusion]
32
+ #
33
+
34
+ import gradio as gr
35
+ from huggingface_hub import hf_hub_download
36
+ from itertools import islice
37
+ from face_analysis import FaceAnalysis
38
+ from models.inswapper import INSwapper
39
+
40
+ REPO_ID = "leonelhs/insightface"
41
+ model_inswapper_path = hf_hub_download(repo_id=REPO_ID, filename="inswapper_128.onnx")
42
+
43
+ face_analyser = FaceAnalysis()
44
+ swapper = INSwapper(model_inswapper_path)
45
+
46
+
47
+ def predict(src_img, dst_img):
48
+
49
+ # Get faces
50
+ src_faces = face_analyser.get(src_img)
51
+ dst_faces = face_analyser.get(dst_img)
52
+
53
+ # Swap the first face found
54
+ if len(src_faces) > 0 and len(dst_faces) > 0:
55
+ return dst_img, swapper.get(dst_img, dst_faces[0], src_faces[0], paste_back=True)
56
+ else:
57
+ raise gr.Error("No faces were found!")
58
+
59
+ with gr.Blocks(title="FaceFusion") as app:
60
+ navbar = gr.Navbar(visible=True, main_page_name="Workspace")
61
+ gr.Markdown("## FaceFusion Lite")
62
+ with gr.Row():
63
+ with gr.Column(scale=1):
64
+ with gr.Row():
65
+ source_image = gr.Image(type="numpy", label="Face image")
66
+ target_image = gr.Image(type="numpy", label="Body image")
67
+ image_btn = gr.Button("Swap face")
68
+ with gr.Column(scale=1):
69
+ with gr.Row():
70
+ output_image = gr.ImageSlider(label="Swapped image", type="pil")
71
+ image_btn.click(
72
+ fn=predict,
73
+ inputs=[source_image, target_image],
74
+ outputs=output_image,
75
+ )
76
+
77
+ with app.route("Readme", "/readme"):
78
+ with open("README.md") as f:
79
+ for line in islice(f, 12, None):
80
+ gr.Markdown(line.strip())
81
+
82
+ app.launch(share=False, debug=True, show_error=True, mcp_server=True, pwa=True)
83
+ app.queue()
84
+
85
+
86
+
face_analysis.py ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ # @Organization : insightface.ai
3
+ # @Author : Jia Guo
4
+ # @Time : 2021-05-04
5
+ # @Function :
6
+
7
+
8
+ from __future__ import division
9
+
10
+ import onnxruntime
11
+
12
+ __all__ = ['FaceAnalysis']
13
+
14
+ from utils.common import Face
15
+ from models.arcface_onnx import ArcFaceONNX
16
+ from models.attribute import Attribute
17
+ from models.landmark import Landmark
18
+ from models.retinaface import RetinaFace
19
+ from huggingface_hub import hf_hub_download
20
+
21
+ REPO_ID = "leonelhs/insightface"
22
+
23
+ model_detector_path = hf_hub_download(repo_id=REPO_ID, filename="det_10g.onnx")
24
+ model_landmark_3d_68_path = hf_hub_download(repo_id=REPO_ID, filename="1k3d68.onnx")
25
+ model_landmark_2d_106_path = hf_hub_download(repo_id=REPO_ID, filename="2d106det.onnx")
26
+ model_genderage_path = hf_hub_download(repo_id=REPO_ID, filename="genderage.onnx")
27
+ model_recognition_path = hf_hub_download(repo_id=REPO_ID, filename="w600k_r50.onnx")
28
+
29
+ class FaceAnalysis:
30
+ def __init__(self):
31
+ onnxruntime.set_default_logger_severity(3)
32
+
33
+ self.detector = RetinaFace(model_file=model_detector_path, input_size=(640, 640), det_thresh=0.5)
34
+ self.landmark_3d_68 = Landmark(model_file=model_landmark_3d_68_path)
35
+ self.landmark_2d_106 = Landmark(model_file=model_landmark_2d_106_path)
36
+ self.genderage = Attribute(model_file=model_genderage_path)
37
+ self.recognition = ArcFaceONNX(model_file=model_recognition_path)
38
+
39
+ def get(self, img, max_num=0):
40
+ bboxes, kpss = self.detector.detect(img,
41
+ max_num=max_num,
42
+ metric='default')
43
+ if bboxes.shape[0] == 0:
44
+ return []
45
+ ret = []
46
+ for i in range(bboxes.shape[0]):
47
+ bbox = bboxes[i, 0:4]
48
+ det_score = bboxes[i, 4]
49
+ kps = None
50
+ if kpss is not None:
51
+ kps = kpss[i]
52
+ face = Face(bbox=bbox, kps=kps, det_score=det_score)
53
+ self.landmark_3d_68.get(img, face)
54
+ self.landmark_2d_106.get(img, face)
55
+ self.genderage.get(img, face)
56
+ self.recognition.get(img, face)
57
+ ret.append(face)
58
+ return ret
meanshape_68.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:39ffecf84ba73f0d0d7e49380833ba88713c9fcdec51df4f7ac45a48b8f4cc51
3
+ size 974
playground.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+
3
+ from face_analysis import FaceAnalysis
4
+ from models.inswapper import INSwapper
5
+
6
+ app = FaceAnalysis()
7
+
8
+ swapper = INSwapper('./inswapper_128.onnx')
9
+
10
+ source_img = "/home/leonel/Pictures/bun01.jpg"
11
+ target_img = "/home/leonel/Pictures/ac6a1e147711139.62c72d282c159.png"
12
+
13
+ # Load source and target images
14
+ src_img = cv2.imread(source_img)
15
+ dst_img = cv2.imread(target_img)
16
+
17
+ # Get faces
18
+ src_faces = app.get(src_img)
19
+ dst_faces = app.get(dst_img)
20
+
21
+ # Swap the first face found
22
+ if len(src_faces) > 0 and len(dst_faces) > 0:
23
+ result = swapper.get(dst_img, dst_faces[0], src_faces[0], paste_back=True)
24
+ cv2.imwrite("swapped2.jpg", result)
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ numpy~=2.2.6
2
+ opencv-python~=4.12.0.88
3
+ scikit-image~=0.25.2
4
+ onnx~=1.19.0
5
+ onnxruntime~=1.22.1