anujakkulkarni commited on
Commit
039104b
·
verified ·
1 Parent(s): 017cd1f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +52 -42
app.py CHANGED
@@ -1,5 +1,4 @@
1
- from fastapi import FastAPI, UploadFile, File, HTTPException
2
- from fastapi.responses import JSONResponse
3
  from ultralytics import YOLO
4
  import cv2
5
  import numpy as np
@@ -8,57 +7,67 @@ from shapely.ops import unary_union
8
  import mediapipe as mp
9
  from collections import defaultdict
10
 
11
- app = FastAPI(title="Face Skin Percentage API")
 
 
 
12
 
13
- # -------------------- LOAD MODELS --------------------
14
- skin_model_path = "pores.pt" # Your YOLO model path
15
  skin_model = YOLO(skin_model_path)
16
- mp_face_mesh = mp.solutions.face_mesh.FaceMesh(static_image_mode=True)
 
17
 
18
- # -------------------- HOME ROUTE --------------------
19
- @app.get("/")
20
  def home():
21
- return {"message": "✅ Skin API is running",
22
- "usage": "POST an image (form-data key 'file') to /analyze"}
 
 
23
 
24
- # -------------------- ANALYZE ROUTE --------------------
25
- @app.post("/analyze")
26
- async def analyze(file: UploadFile = File(...)):
27
- if not file:
28
- raise HTTPException(status_code=400, detail="No file uploaded")
29
 
30
- # Read image bytes and convert to OpenCV image
31
- contents = await file.read()
32
- np_arr = np.frombuffer(contents, np.uint8)
33
- img = cv2.imdecode(np_arr, cv2.IMREAD_COLOR)
34
  if img is None:
35
- raise HTTPException(status_code=400, detail="Invalid image file")
36
 
37
  img_h, img_w = img.shape[:2]
38
 
39
- # -------------------- STEP 1: Detect face --------------------
40
  rgb_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
41
- result = mp_face_mesh.process(rgb_img)
42
 
43
- face_area = 0
44
  face_polygon = None
 
 
45
  if result.multi_face_landmarks:
46
- for facial_landmarks in result.multi_face_landmarks:
47
- points = [[int(lm.x * img_w), int(lm.y * img_h)] for lm in facial_landmarks.landmark]
48
- hull = cv2.convexHull(np.array(points, dtype=np.int32))
 
 
 
49
  face_area = cv2.contourArea(hull)
50
  face_polygon = Polygon(hull.reshape(-1, 2))
51
  break # only first face
52
  else:
53
- return JSONResponse({"success": False, "message": "No face detected", "percentages": {}})
54
 
55
- # -------------------- STEP 2: Run YOLO skin detection --------------------
56
- skin_results = skin_model(img)
57
- boxes_xy = skin_results[0].boxes.xyxy.cpu().numpy()
58
- boxes_cls = skin_results[0].boxes.cls.cpu().numpy().astype(int)
 
59
 
60
  class_polygons = defaultdict(list)
61
- for xy, cls_id in zip(boxes_xy, boxes_cls):
 
62
  x1, y1, x2, y2 = xy.astype(int)
63
  det_poly = shapely_box(x1, y1, x2, y2)
64
  if face_polygon.intersects(det_poly):
@@ -66,15 +75,16 @@ async def analyze(file: UploadFile = File(...)):
66
  if intersection.area > 0:
67
  class_polygons[cls_id].append(intersection)
68
 
69
- # -------------------- STEP 3: Calculate percentages --------------------
70
  skin_percentages = {}
71
- for cls_id, class_name in skin_model.names.items():
72
- polys = class_polygons.get(cls_id, [])
73
- if polys:
74
- union_poly = unary_union(polys)
75
- percentage = (union_poly.area / face_area) * 100 if face_area > 0 else 0.0
76
- else:
77
- percentage = 0.0
78
- skin_percentages[class_name] = round(percentage, 2)
79
 
80
- return {"success": True, "percentages": skin_percentages}
 
 
 
1
+ from flask import Flask, request, jsonify
 
2
  from ultralytics import YOLO
3
  import cv2
4
  import numpy as np
 
7
  import mediapipe as mp
8
  from collections import defaultdict
9
 
10
+ # -------------------- CONFIG --------------------
11
+ skin_model_path = "pores.pt" # replace with your model in HF Space
12
+ conf_threshold = 0.05
13
+ imgsz = 1024
14
 
15
+ # -------------------- INIT --------------------
16
+ app = Flask(__name__)
17
  skin_model = YOLO(skin_model_path)
18
+ mp_face_mesh = mp.solutions.face_mesh
19
+ face_mesh = mp_face_mesh.FaceMesh(static_image_mode=True)
20
 
21
+ # -------------------- ROUTES --------------------
22
+ @app.route("/", methods=["GET"])
23
  def home():
24
+ return jsonify({
25
+ "message": " Skin API is running",
26
+ "usage": "POST an image (form-data key 'file') to /analyze"
27
+ })
28
 
29
+ @app.route("/analyze", methods=["POST"])
30
+ def analyze():
31
+ if "file" not in request.files:
32
+ return jsonify({"success": False, "analysis": []}), 400
 
33
 
34
+ file = request.files["file"]
35
+ file_bytes = np.frombuffer(file.read(), np.uint8)
36
+ img = cv2.imdecode(file_bytes, cv2.IMREAD_COLOR)
 
37
  if img is None:
38
+ return jsonify({"success": False, "error": "Invalid image"}), 400
39
 
40
  img_h, img_w = img.shape[:2]
41
 
42
+ # -------------------- FACE DETECTION --------------------
43
  rgb_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
44
+ result = face_mesh.process(rgb_img)
45
 
 
46
  face_polygon = None
47
+ face_area = 0
48
+
49
  if result.multi_face_landmarks:
50
+ for landmarks in result.multi_face_landmarks:
51
+ points = np.array([
52
+ [int(lm.x * img_w), int(lm.y * img_h)]
53
+ for lm in landmarks.landmark
54
+ ])
55
+ hull = cv2.convexHull(points)
56
  face_area = cv2.contourArea(hull)
57
  face_polygon = Polygon(hull.reshape(-1, 2))
58
  break # only first face
59
  else:
60
+ return jsonify({"success": False, "error": "No face detected"}), 400
61
 
62
+ # -------------------- SKIN DETECTION --------------------
63
+ results = skin_model(img, conf=conf_threshold, imgsz=imgsz)
64
+ boxes_xy = results[0].boxes.xyxy.cpu().numpy()
65
+ boxes_conf = results[0].boxes.conf.cpu().numpy()
66
+ boxes_cls = results[0].boxes.cls.cpu().numpy().astype(int)
67
 
68
  class_polygons = defaultdict(list)
69
+
70
+ for i, (xy, cls_id) in enumerate(zip(boxes_xy, boxes_cls)):
71
  x1, y1, x2, y2 = xy.astype(int)
72
  det_poly = shapely_box(x1, y1, x2, y2)
73
  if face_polygon.intersects(det_poly):
 
75
  if intersection.area > 0:
76
  class_polygons[cls_id].append(intersection)
77
 
78
+ # -------------------- CALCULATE PERCENTAGES --------------------
79
  skin_percentages = {}
80
+ for cls_id, polys in class_polygons.items():
81
+ union_poly = unary_union(polys)
82
+ pixels = union_poly.area
83
+ percentage = (pixels / face_area) * 100 if face_area > 0 else 0.0
84
+ skin_percentages[skin_model.names.get(cls_id, str(cls_id))] = round(percentage, 2)
85
+
86
+ return jsonify({"success": True, "percentages": skin_percentages})
 
87
 
88
+ # -------------------- RUN --------------------
89
+ if __name__ == "__main__":
90
+ app.run(host="0.0.0.0", port=7860)