Spaces:
Runtime error
Runtime error
Initial commit
Browse files- .gitignore +1 -0
- README.md +3 -3
- app.py +104 -0
- config.json +5 -0
- requirements.txt +3 -0
.gitignore
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
yolov8n-face.pt
|
README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
---
|
2 |
title: FootballChecker
|
3 |
-
emoji:
|
4 |
-
colorFrom:
|
5 |
-
colorTo:
|
6 |
sdk: gradio
|
7 |
sdk_version: 3.35.2
|
8 |
app_file: app.py
|
|
|
1 |
---
|
2 |
title: FootballChecker
|
3 |
+
emoji: 👁️
|
4 |
+
colorFrom: purple
|
5 |
+
colorTo: pink
|
6 |
sdk: gradio
|
7 |
sdk_version: 3.35.2
|
8 |
app_file: app.py
|
app.py
ADDED
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
import zipfile
|
3 |
+
import numpy as np
|
4 |
+
import cv2
|
5 |
+
import os
|
6 |
+
import gradio as gr
|
7 |
+
from deepface import DeepFace
|
8 |
+
from ultralytics import YOLO
|
9 |
+
import urllib.request
|
10 |
+
|
11 |
+
with open("config.json", "r") as f:
|
12 |
+
config = json.load(f)
|
13 |
+
|
14 |
+
FACE_DIST_TRESH = config['FACE_DIST_TRESH']
|
15 |
+
FACE_DET_TRESH = config['FACE_DET_TRESH']
|
16 |
+
YOLO_WEIGHTS_URL = config['YOLO_WEIGHTS_URL']
|
17 |
+
|
18 |
+
yolo_weights_filename = os.path.basename(YOLO_WEIGHTS_URL)
|
19 |
+
|
20 |
+
if not os.path.exists(yolo_weights_filename):
|
21 |
+
urllib.request.urlretrieve(YOLO_WEIGHTS_URL, yolo_weights_filename)
|
22 |
+
|
23 |
+
model = YOLO(yolo_weights_filename)
|
24 |
+
|
25 |
+
def find_distance(base_face, check_face):
|
26 |
+
result = DeepFace.verify(base_face, check_face, enforce_detection=False)
|
27 |
+
return result['distance']
|
28 |
+
|
29 |
+
def find_faces(image):
|
30 |
+
outputs = model(image)
|
31 |
+
faces = []
|
32 |
+
for box in outputs[0].boxes:
|
33 |
+
if float(box.conf) >= FACE_DET_TRESH:
|
34 |
+
x, y, w, h = [int(coord) for coord in box.xywh[0]]
|
35 |
+
x_center, y_center = x + w / 2, y + h / 2
|
36 |
+
x1 = int(x_center - w)
|
37 |
+
y1 = int(y_center - h)
|
38 |
+
crop_img = image[y1:y1+h, x1:x1+w]
|
39 |
+
faces.append(crop_img)
|
40 |
+
return faces
|
41 |
+
|
42 |
+
def load_images_from_zip(zip_path):
|
43 |
+
images = []
|
44 |
+
with zipfile.ZipFile(zip_path, 'r') as zip_file:
|
45 |
+
for file_name in zip_file.namelist():
|
46 |
+
with zip_file.open(file_name) as file:
|
47 |
+
img_bytes = np.asarray(bytearray(file.read()), dtype=np.uint8)
|
48 |
+
img = cv2.imdecode(img_bytes, cv2.IMREAD_COLOR)
|
49 |
+
images.append(img)
|
50 |
+
return [img for img in images if img is not None]
|
51 |
+
|
52 |
+
def create_image(images):
|
53 |
+
if not images:
|
54 |
+
return np.zeros((1, 1, 3), dtype=np.uint8)
|
55 |
+
|
56 |
+
max_width = max([img.shape[1] for img in images])
|
57 |
+
total_height = sum([img.shape[0] for img in images])
|
58 |
+
|
59 |
+
new_image = np.zeros((total_height, max_width, 3), dtype=np.uint8)
|
60 |
+
|
61 |
+
y_offset = 0
|
62 |
+
for img in images:
|
63 |
+
new_image[y_offset:y_offset+img.shape[0], :img.shape[1], :] = img
|
64 |
+
y_offset += img.shape[0]
|
65 |
+
|
66 |
+
new_image = cv2.resize(new_image, (0, 0), fx=0.5, fy=0.5)
|
67 |
+
|
68 |
+
return new_image
|
69 |
+
|
70 |
+
def check(avatars_zip, photos_zip):
|
71 |
+
avatars = load_images_from_zip(avatars_zip.name)
|
72 |
+
photos = load_images_from_zip(photos_zip.name)
|
73 |
+
not_found_faces = []
|
74 |
+
for photo in photos:
|
75 |
+
photo = cv2.cvtColor(photo, cv2.COLOR_RGB2BGR)
|
76 |
+
input_faces = find_faces(photo)
|
77 |
+
for input_face in input_faces:
|
78 |
+
avatars_checked = 0
|
79 |
+
for avatar in avatars:
|
80 |
+
avatar = cv2.cvtColor(avatar, cv2.COLOR_RGB2BGR)
|
81 |
+
distance = find_distance(avatar, input_face)
|
82 |
+
if distance > FACE_DIST_TRESH:
|
83 |
+
break
|
84 |
+
else:
|
85 |
+
avatars_checked+=1
|
86 |
+
if avatars_checked == len(avatars):
|
87 |
+
not_found_faces.append(input_face)
|
88 |
+
|
89 |
+
return create_image(not_found_faces)
|
90 |
+
|
91 |
+
title = '<h1 style="text-align:center">FootballChecker</h1>'
|
92 |
+
|
93 |
+
with gr.Blocks(theme='soft', title='FootballChecker') as blocks:
|
94 |
+
gr.HTML(title)
|
95 |
+
gr.Markdown('Face checking toolkit')
|
96 |
+
with gr.Row():
|
97 |
+
avatars = gr.inputs.File(label="Avatar Images (zip)")
|
98 |
+
photos = gr.inputs.File(label="Check Photos (zip)")
|
99 |
+
inputs = [avatars, photos]
|
100 |
+
process_button = gr.Button('Check images')
|
101 |
+
outputs=gr.outputs.Image(type="numpy", label="Results")
|
102 |
+
process_button.click(fn=check, inputs=inputs, outputs=outputs)
|
103 |
+
|
104 |
+
blocks.launch()
|
config.json
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"FACE_DIST_TRESH": 0.15,
|
3 |
+
"FACE_DET_TRESH": 0.3,
|
4 |
+
"YOLO_WEIGHTS_URL": "https://github.com/akanametov/yolov8-face/releases/download/v0.0.0/yolov8n-face.pt"
|
5 |
+
}
|
requirements.txt
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
deepface
|
2 |
+
ultralytics
|
3 |
+
zipfile
|