dhruvilhere commited on
Commit
93ac3cd
Β·
1 Parent(s): 46e04d2

Relaxed Image validation limits for mobile photos

Browse files
Files changed (2) hide show
  1. main.py +3 -3
  2. model.py +9 -10
main.py CHANGED
@@ -219,9 +219,9 @@ async def predict(file: UploadFile = File(...)) -> dict:
219
  # ── 8. Validate confidence threshold ───────────────────────────────────
220
  top_confidence = predictions[0]["confidence"]
221
 
222
- # Hard reject only truly uncertain predictions (lowered from 25 β†’ 15 %
223
- # because genuine skin photos of mild or early conditions can score low)
224
- if top_confidence < 15.0:
225
  raise HTTPException(
226
  status_code=422,
227
  detail={
 
219
  # ── 8. Validate confidence threshold ───────────────────────────────────
220
  top_confidence = predictions[0]["confidence"]
221
 
222
+ # Hard reject only truly uncertain predictions (lowered from 25 -> 15 -> 5 %
223
+ # because genuine skin photos of mild or early conditions can score low, especially on smartphones)
224
+ if top_confidence < 5.0:
225
  raise HTTPException(
226
  status_code=422,
227
  detail={
model.py CHANGED
@@ -288,7 +288,7 @@ def is_skin_image(image_array: np.ndarray) -> dict:
288
  skin_pixels = int(cv2.countNonZero(skin_mask))
289
  skin_pct = (skin_pixels / total_pixels) * 100
290
 
291
- MIN_SKIN_PCT = 15.0 # at least 15 % of the frame must be skin-coloured
292
 
293
  if skin_pct < MIN_SKIN_PCT:
294
  return {
@@ -329,7 +329,7 @@ def is_skin_image(image_array: np.ndarray) -> dict:
329
 
330
  # The largest blob must cover β‰₯ 8 % of the total image
331
  largest_blob_pct = (max(large_blobs) / total_pixels) * 100
332
- if largest_blob_pct < 8.0:
333
  return {
334
  "is_skin": False,
335
  "skin_percentage": round(skin_pct, 1),
@@ -348,8 +348,8 @@ def is_skin_image(image_array: np.ndarray) -> dict:
348
 
349
  if sat_skin.size > 0:
350
  sat_std = float(np.std(sat_skin))
351
- # Paint / metal usually has sat_std < 18; real skin > 25
352
- if sat_std < 15.0:
353
  return {
354
  "is_skin": False,
355
  "skin_percentage": round(skin_pct, 1),
@@ -368,8 +368,8 @@ def is_skin_image(image_array: np.ndarray) -> dict:
368
 
369
  if skin_pixels > 0:
370
  edge_skin_ratio = edge_count / skin_pixels
371
- # If edges outnumber skin pixels 1:1 this is almost certainly not skin
372
- if edge_skin_ratio > 0.9:
373
  return {
374
  "is_skin": False,
375
  "skin_percentage": round(skin_pct, 1),
@@ -409,10 +409,9 @@ def check_image_quality(image_array: np.ndarray) -> dict:
409
  gray = cv2.cvtColor(image_array, cv2.COLOR_RGB2GRAY)
410
  lap_var = float(cv2.Laplacian(gray, cv2.CV_64F).var())
411
 
412
- # Threshold calibrated so that genuine medical photos from modern phones
413
- # (which often have high detail) always pass. Only extremely blurry or
414
- # artificially downscaled images will fail.
415
- BLUR_THRESHOLD = 20.0
416
 
417
  if lap_var < BLUR_THRESHOLD:
418
  return {
 
288
  skin_pixels = int(cv2.countNonZero(skin_mask))
289
  skin_pct = (skin_pixels / total_pixels) * 100
290
 
291
+ MIN_SKIN_PCT = 3.0 # dramatically lowered to allow partial/small skin patches or phone crops
292
 
293
  if skin_pct < MIN_SKIN_PCT:
294
  return {
 
329
 
330
  # The largest blob must cover β‰₯ 8 % of the total image
331
  largest_blob_pct = (max(large_blobs) / total_pixels) * 100
332
+ if largest_blob_pct < 3.0:
333
  return {
334
  "is_skin": False,
335
  "skin_percentage": round(skin_pct, 1),
 
348
 
349
  if sat_skin.size > 0:
350
  sat_std = float(np.std(sat_skin))
351
+ # Paint / metal usually has sat_std < 18; phone images can be heavily compressed and lose variance
352
+ if sat_std < 5.0:
353
  return {
354
  "is_skin": False,
355
  "skin_percentage": round(skin_pct, 1),
 
368
 
369
  if skin_pixels > 0:
370
  edge_skin_ratio = edge_count / skin_pixels
371
+ # Relaxed edge density check to accommodate textured or noisy images
372
+ if edge_skin_ratio > 1.5:
373
  return {
374
  "is_skin": False,
375
  "skin_percentage": round(skin_pct, 1),
 
409
  gray = cv2.cvtColor(image_array, cv2.COLOR_RGB2GRAY)
410
  lap_var = float(cv2.Laplacian(gray, cv2.CV_64F).var())
411
 
412
+ # Threshold lowered drastically because smartphone images often exhibit close-up focus blur
413
+ # or compression artifacts which lower variance significantly.
414
+ BLUR_THRESHOLD = 5.0
 
415
 
416
  if lap_var < BLUR_THRESHOLD:
417
  return {