saketh-005 commited on
Commit
947d8e5
·
verified ·
1 Parent(s): f4268de

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +62 -6
app.py CHANGED
@@ -5,6 +5,13 @@ from fastapi.responses import JSONResponse
5
  from ultralytics import YOLO
6
  import insightface
7
 
 
 
 
 
 
 
 
8
  app = FastAPI()
9
 
10
  # ----------------------------
@@ -17,6 +24,10 @@ face_model = insightface.app.FaceAnalysis(name="buffalo_l")
17
  face_model.prepare(ctx_id=-1)
18
 
19
 
 
 
 
 
20
  def normalize(vec):
21
  vec = np.array(vec, dtype=np.float32)
22
  norm = np.linalg.norm(vec)
@@ -25,20 +36,52 @@ def normalize(vec):
25
  return (vec / norm).tolist()
26
 
27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  def process_image_np(image_np):
29
  results = yolo(image_np)
30
  faces_output = []
31
 
32
  for r in results:
33
  boxes = r.boxes
 
34
  for box, cls, conf in zip(boxes.xyxy, boxes.cls, boxes.conf):
35
- if int(cls) != 0:
36
  continue
 
37
  if float(conf) < 0.4:
38
  continue
39
 
40
- xmin, ymin, xmax, ymax = box.cpu().numpy()
41
- xmin, ymin, xmax, ymax = map(int, [xmin, ymin, xmax, ymax])
42
 
43
  h, w, _ = image_np.shape
44
  xmin = max(0, xmin)
@@ -54,6 +97,7 @@ def process_image_np(image_np):
54
 
55
  for face in detected_faces:
56
  embedding = normalize(face.embedding)
 
57
  fxmin, fymin, fxmax, fymax = face.bbox.astype(int)
58
 
59
  faces_output.append({
@@ -72,15 +116,27 @@ def process_image_np(image_np):
72
  return faces_output
73
 
74
 
 
 
 
 
75
  @app.post("/detect")
76
  async def detect(request: Request):
77
  body = await request.body()
78
 
79
- np_arr = np.frombuffer(body, np.uint8)
80
- image_np = cv2.imdecode(np_arr, cv2.IMREAD_COLOR)
 
 
 
 
 
81
 
82
  if image_np is None:
83
- return JSONResponse({"error": "Invalid image"}, status_code=400)
 
 
 
84
 
85
  result = process_image_np(image_np)
86
  return result
 
5
  from ultralytics import YOLO
6
  import insightface
7
 
8
+ from PIL import Image, ImageOps
9
+ import pillow_heif
10
+ import io
11
+
12
+ # Enable HEIC/HEIF support
13
+ pillow_heif.register_heif_opener()
14
+
15
  app = FastAPI()
16
 
17
  # ----------------------------
 
24
  face_model.prepare(ctx_id=-1)
25
 
26
 
27
+ # ----------------------------
28
+ # Utility: Normalize embedding
29
+ # ----------------------------
30
+
31
  def normalize(vec):
32
  vec = np.array(vec, dtype=np.float32)
33
  norm = np.linalg.norm(vec)
 
36
  return (vec / norm).tolist()
37
 
38
 
39
+ # ----------------------------
40
+ # Decode Image (JPEG/PNG/WEBP/HEIC/HEIF)
41
+ # ----------------------------
42
+
43
+ def decode_image(body: bytes):
44
+ # 🔥 Fast path: OpenCV (JPEG/PNG/WebP)
45
+ np_arr = np.frombuffer(body, np.uint8)
46
+ image = cv2.imdecode(np_arr, cv2.IMREAD_COLOR)
47
+ if image is not None:
48
+ return image
49
+
50
+ # 🔥 Fallback: Pillow (HEIC/HEIF support)
51
+ try:
52
+ image = Image.open(io.BytesIO(body))
53
+
54
+ # Auto-rotate based on EXIF
55
+ image = ImageOps.exif_transpose(image)
56
+
57
+ image = image.convert("RGB")
58
+ image_np = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
59
+
60
+ return image_np
61
+
62
+ except Exception:
63
+ return None
64
+
65
+
66
+ # ----------------------------
67
+ # Face Processing
68
+ # ----------------------------
69
+
70
  def process_image_np(image_np):
71
  results = yolo(image_np)
72
  faces_output = []
73
 
74
  for r in results:
75
  boxes = r.boxes
76
+
77
  for box, cls, conf in zip(boxes.xyxy, boxes.cls, boxes.conf):
78
+ if int(cls) != 0: # YOLO class 0 = person
79
  continue
80
+
81
  if float(conf) < 0.4:
82
  continue
83
 
84
+ xmin, ymin, xmax, ymax = map(int, box.cpu().numpy())
 
85
 
86
  h, w, _ = image_np.shape
87
  xmin = max(0, xmin)
 
97
 
98
  for face in detected_faces:
99
  embedding = normalize(face.embedding)
100
+
101
  fxmin, fymin, fxmax, fymax = face.bbox.astype(int)
102
 
103
  faces_output.append({
 
116
  return faces_output
117
 
118
 
119
+ # ----------------------------
120
+ # API Endpoint
121
+ # ----------------------------
122
+
123
  @app.post("/detect")
124
  async def detect(request: Request):
125
  body = await request.body()
126
 
127
+ if not body:
128
+ return JSONResponse(
129
+ {"error": "Empty request body"},
130
+ status_code=400
131
+ )
132
+
133
+ image_np = decode_image(body)
134
 
135
  if image_np is None:
136
+ return JSONResponse(
137
+ {"error": "Unsupported or invalid image format"},
138
+ status_code=400
139
+ )
140
 
141
  result = process_image_np(image_np)
142
  return result