File size: 2,864 Bytes
1073356
 
1a84c6b
8c10e13
c26ed98
f97d8fd
c26ed98
1073356
20df945
f97d8fd
20df945
 
6815378
20df945
8c10e13
6815378
20df945
 
 
 
 
 
 
 
 
 
f97d8fd
8c10e13
 
660fdf1
1a84c6b
20df945
 
d48a803
 
20df945
f6d0414
660fdf1
f6d0414
8c10e13
 
20df945
 
 
 
 
 
8c10e13
20df945
 
 
8c10e13
 
 
20df945
 
8c10e13
 
20df945
 
 
8c10e13
20df945
 
 
 
8c10e13
 
 
 
 
1073356
20df945
f97d8fd
c26ed98
f97d8fd
 
c26ed98
 
 
 
 
 
 
 
 
 
f97d8fd
 
c26ed98
 
f97d8fd
c26ed98
f97d8fd
 
 
 
 
 
 
 
 
c26ed98
f97d8fd
c26ed98
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
import gradio as gr
import numpy as np
from ultralytics import YOLO
import insightface
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
import cv2

# ----------------------------
# Load models (CPU)
# ----------------------------

yolo = YOLO("yolov8n.pt")

face_model = insightface.app.FaceAnalysis(name="buffalo_l")
face_model.prepare(ctx_id=-1)


def normalize(vec):
    vec = np.array(vec, dtype=np.float32)
    norm = np.linalg.norm(vec)
    if norm == 0:
        return vec.tolist()
    return (vec / norm).tolist()


def process_image_np(image_np):
    results = yolo(image_np)
    faces_output = []

    for r in results:
        boxes = r.boxes
        for box, cls, conf in zip(boxes.xyxy, boxes.cls, boxes.conf):
            if int(cls) != 0:
                continue
            if float(conf) < 0.4:
                continue

            xmin, ymin, xmax, ymax = box.cpu().numpy()
            xmin, ymin, xmax, ymax = map(int, [xmin, ymin, xmax, ymax])

            h, w, _ = image_np.shape
            xmin = max(0, xmin)
            ymin = max(0, ymin)
            xmax = min(w, xmax)
            ymax = min(h, ymax)

            person_crop = image_np[ymin:ymax, xmin:xmax]
            if person_crop.size == 0:
                continue

            detected_faces = face_model.get(person_crop)

            for face in detected_faces:
                embedding = normalize(face.embedding)
                fxmin, fymin, fxmax, fymax = face.bbox.astype(int)

                faces_output.append({
                    "cx": float((fxmin + fxmax) / 2 + xmin),
                    "cy": float((fymin + fymax) / 2 + ymin),
                    "confidence": float(conf),
                    "box": {
                        "xmin": int(fxmin + xmin),
                        "ymin": int(fymin + ymin),
                        "xmax": int(fxmax + xmin),
                        "ymax": int(fymax + ymin)
                    },
                    "embedding": embedding
                })

    return faces_output


# ----------------------------------------
# Create Gradio Blocks
# ----------------------------------------

with gr.Blocks() as demo:
    gr.Markdown("Face Processing API Running")

# Get underlying FastAPI app from Gradio
app = demo.app


# ----------------------------------------
# ADD REAL REST ENDPOINT TO SAME APP
# ----------------------------------------

@app.post("/detect")
async def detect(request: Request):
    body = await request.body()

    np_arr = np.frombuffer(body, np.uint8)
    image_np = cv2.imdecode(np_arr, cv2.IMREAD_COLOR)

    if image_np is None:
        return JSONResponse({"error": "Invalid image"}, status_code=400)

    result = process_image_np(image_np)
    return result


# Launch
demo.queue(False)
demo.launch(server_name="0.0.0.0", server_port=7860, ssr_mode=False)