anujakkulkarni commited on
Commit
85d8b66
·
verified ·
1 Parent(s): ca6131c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +50 -80
app.py CHANGED
@@ -27,7 +27,6 @@ models = {name: YOLO(path) for name, path in model_paths.items()}
27
  mp_face_mesh = mp.solutions.face_mesh
28
  face_mesh = mp_face_mesh.FaceMesh(static_image_mode=True)
29
 
30
-
31
  # -------------------- SKIN TYPE DETECTOR --------------------
32
  def detect_skin_type_from_image(img):
33
  img = cv2.resize(img, (400, 400))
@@ -77,7 +76,6 @@ def detect_skin_type_from_image(img):
77
 
78
  return percentages, f"{final_type} ({final_value}%)"
79
 
80
-
81
  # -------------------- HELPERS --------------------
82
  def run_model(model_name, model, img, face_polygon, face_area):
83
  if model_name == "pores2":
@@ -119,7 +117,6 @@ def run_model(model_name, model, img, face_polygon, face_area):
119
 
120
  return skin_percentages
121
 
122
-
123
  def normalize_and_merge(percentages):
124
  normalized = {}
125
  for cls_name, value in percentages.items():
@@ -142,98 +139,72 @@ def normalize_and_merge(percentages):
142
 
143
  return normalized
144
 
145
-
146
  # -------------------- ROUTES --------------------
147
  @app.route("/", methods=["GET"])
148
  def home():
149
  return jsonify({
150
  "message": "✅ Skin API is running",
151
- "usage": "POST exactly 3 images (form-data key 'file') to /analyze"
152
  })
153
 
154
-
155
  @app.route("/analyze", methods=["POST"])
156
  def analyze():
157
  try:
158
  files = request.files.getlist("file")
159
- if not files or len(files) != 3:
160
  return jsonify({
161
  "success": False,
162
  "analysis": [],
163
- "error": "You must upload exactly 3 images."
164
  }), 400
165
 
166
- all_model_results = []
167
- all_skin_types = []
168
-
169
- for file in files:
170
- file_bytes = np.frombuffer(file.read(), np.uint8)
171
- img = cv2.imdecode(file_bytes, cv2.IMREAD_COLOR)
172
- if img is None:
173
- return jsonify({"success": False, "analysis": [], "error": "Invalid image."}), 400
174
-
175
- img_h, img_w = img.shape[:2]
176
-
177
- rgb_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
178
- result = face_mesh.process(rgb_img)
179
-
180
- face_polygon = None
181
- face_area = 0
182
- if result.multi_face_landmarks:
183
- for landmarks in result.multi_face_landmarks:
184
- points = np.array([[int(lm.x * img_w), int(lm.y * img_h)] for lm in landmarks.landmark])
185
- hull = cv2.convexHull(points)
186
- face_area = cv2.contourArea(hull)
187
- face_polygon = Polygon(hull.reshape(-1, 2))
188
- break
189
- else:
190
- return jsonify({"success": False, "analysis": [], "error": "No face detected."}), 400
191
-
192
- combined_percentages = {}
193
- with ThreadPoolExecutor() as executor:
194
- futures = {
195
- executor.submit(run_model, model_name, model, img, face_polygon, face_area): model_name
196
- for model_name, model in models.items()
197
- }
198
- for future in as_completed(futures):
199
- skin_percentages = future.result()
200
- combined_percentages.update(skin_percentages)
201
-
202
- final_percentages = normalize_and_merge(combined_percentages)
203
-
204
- # MERGE WRINKLES + FOREHEAD
205
- wrinkle_value = final_percentages.get("wrinkles", 0.0) + final_percentages.get("forehead", 0.0)
206
- final_percentages["wrinkles"] = round(wrinkle_value, 2)
207
- if "forehead" in final_percentages:
208
- final_percentages.pop("forehead")
209
-
210
- all_model_results.append(final_percentages)
211
-
212
- # Skin type percentages
213
- skin_type_percentages, _ = detect_skin_type_from_image(img)
214
- all_skin_types.append(skin_type_percentages)
215
-
216
- # -------------------- AVERAGE RESULTS --------------------
217
- avg_results = defaultdict(float)
218
- for res in all_model_results:
219
- for k, v in res.items():
220
- avg_results[k] += v
221
- for k in avg_results:
222
- avg_results[k] = round(avg_results[k] / 3, 2)
223
-
224
- # -------------------- AVERAGE SKIN TYPE --------------------
225
- avg_skin_type_percentages = defaultdict(float)
226
- for st in all_skin_types:
227
- for k, v in st.items():
228
- avg_skin_type_percentages[k] += v
229
- for k in avg_skin_type_percentages:
230
- avg_skin_type_percentages[k] = round(avg_skin_type_percentages[k] / 3, 2)
231
-
232
- final_skin_type = max(avg_skin_type_percentages, key=avg_skin_type_percentages.get)
233
- final_skin_type_str = f"{final_skin_type} ({avg_skin_type_percentages[final_skin_type]}%)"
234
-
235
- # -------------------- FORMAT RESPONSE --------------------
236
- analysis_list = [f"{cls_name.upper()}: {value}%" for cls_name, value in avg_results.items()]
237
  analysis_list.append(f"SKIN TYPE: {final_skin_type_str}")
238
 
239
  return jsonify({"success": True, "analysis": ["\n".join(analysis_list)]})
@@ -241,7 +212,6 @@ def analyze():
241
  except Exception as e:
242
  return jsonify({"success": False, "analysis": [], "error": str(e)}), 500
243
 
244
-
245
  # -------------------- RUN --------------------
246
  if __name__ == "__main__":
247
  app.run(host="0.0.0.0", port=7860)
 
27
  mp_face_mesh = mp.solutions.face_mesh
28
  face_mesh = mp_face_mesh.FaceMesh(static_image_mode=True)
29
 
 
30
  # -------------------- SKIN TYPE DETECTOR --------------------
31
  def detect_skin_type_from_image(img):
32
  img = cv2.resize(img, (400, 400))
 
76
 
77
  return percentages, f"{final_type} ({final_value}%)"
78
 
 
79
  # -------------------- HELPERS --------------------
80
  def run_model(model_name, model, img, face_polygon, face_area):
81
  if model_name == "pores2":
 
117
 
118
  return skin_percentages
119
 
 
120
  def normalize_and_merge(percentages):
121
  normalized = {}
122
  for cls_name, value in percentages.items():
 
139
 
140
  return normalized
141
 
 
142
  # -------------------- ROUTES --------------------
143
  @app.route("/", methods=["GET"])
144
  def home():
145
  return jsonify({
146
  "message": "✅ Skin API is running",
147
+ "usage": "POST one image (form-data key 'file') to /analyze"
148
  })
149
 
 
150
  @app.route("/analyze", methods=["POST"])
151
  def analyze():
152
  try:
153
  files = request.files.getlist("file")
154
+ if not files or len(files) != 1:
155
  return jsonify({
156
  "success": False,
157
  "analysis": [],
158
+ "error": "You must upload exactly 1 image."
159
  }), 400
160
 
161
+ file = files[0]
162
+ file_bytes = np.frombuffer(file.read(), np.uint8)
163
+ img = cv2.imdecode(file_bytes, cv2.IMREAD_COLOR)
164
+ if img is None:
165
+ return jsonify({"success": False, "analysis": [], "error": "Invalid image."}), 400
166
+
167
+ img_h, img_w = img.shape[:2]
168
+ rgb_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
169
+ result = face_mesh.process(rgb_img)
170
+
171
+ if not result.multi_face_landmarks:
172
+ return jsonify({"success": False, "analysis": [], "error": "No face detected."}), 400
173
+
174
+ # Face polygon
175
+ for landmarks in result.multi_face_landmarks:
176
+ points = np.array([[int(lm.x * img_w), int(lm.y * img_h)] for lm in landmarks.landmark])
177
+ hull = cv2.convexHull(points)
178
+ face_area = cv2.contourArea(hull)
179
+ face_polygon = Polygon(hull.reshape(-1, 2))
180
+ break
181
+
182
+ # Run YOLO models in parallel
183
+ combined_percentages = {}
184
+ with ThreadPoolExecutor() as executor:
185
+ futures = {
186
+ executor.submit(run_model, model_name, model, img, face_polygon, face_area): model_name
187
+ for model_name, model in models.items()
188
+ }
189
+ for future in as_completed(futures):
190
+ skin_percentages = future.result()
191
+ combined_percentages.update(skin_percentages)
192
+
193
+ final_percentages = normalize_and_merge(combined_percentages)
194
+
195
+ # Merge wrinkles + forehead
196
+ wrinkle_value = final_percentages.get("wrinkles", 0.0) + final_percentages.get("forehead", 0.0)
197
+ final_percentages["wrinkles"] = round(wrinkle_value, 2)
198
+ if "forehead" in final_percentages:
199
+ final_percentages.pop("forehead")
200
+
201
+ # Skin type
202
+ skin_type_percentages, _ = detect_skin_type_from_image(img)
203
+ final_skin_type = max(skin_type_percentages, key=skin_type_percentages.get)
204
+ final_skin_type_str = f"{final_skin_type} ({skin_type_percentages[final_skin_type]}%)"
205
+
206
+ # Format response
207
+ analysis_list = [f"{cls_name.upper()}: {value}%" for cls_name, value in final_percentages.items()]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
  analysis_list.append(f"SKIN TYPE: {final_skin_type_str}")
209
 
210
  return jsonify({"success": True, "analysis": ["\n".join(analysis_list)]})
 
212
  except Exception as e:
213
  return jsonify({"success": False, "analysis": [], "error": str(e)}), 500
214
 
 
215
  # -------------------- RUN --------------------
216
  if __name__ == "__main__":
217
  app.run(host="0.0.0.0", port=7860)