kerojohan Claude Sonnet 4.6 commited on
Commit
05fdfa4
·
1 Parent(s): be814bf

Port v5 scoring fixes: border penalty, valid-region clip

Browse files

- score_candidate: border contact penalty (×0.60 for 1 edge, ×0.35 for 2+)
prevents dark vegetation at image borders from outscoring contained cave voids
- process_image: hard-clip final mask to actual illumination columns after
refine_mask, removing IR vignette/penumbra reintroduced by GrabCut or smoothing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Files changed (1) hide show
  1. detect_cave.py +30 -1
detect_cave.py CHANGED
@@ -458,8 +458,25 @@ def score_candidate(mask, gray_f32, weight_map, left_col, right_col,
458
  if valid_score < 0.5:
459
  lateral_pen = 0.4
460
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
461
  total = (additive * area_mult * solidity_mult
462
- * texture_mult * vert_gate * lateral_pen)
463
 
464
  return {
465
  "total": round(float(total), 4),
@@ -480,6 +497,8 @@ def score_candidate(mask, gray_f32, weight_map, left_col, right_col,
480
  "valid_score": round(float(valid_score), 3),
481
  "mean_inside": round(float(mean_inside), 3),
482
  "mean_outside": round(float(mean_outside), 3),
 
 
483
  }
484
 
485
 
@@ -819,6 +838,7 @@ def process_image(input_path, output_dir):
819
  f"depth={scores['depth']:.2f} "
820
  f"area_m={scores['area_mult']:.2f} "
821
  f"sol={scores['solidity']:.2f}(×{scores['sol_mult']:.2f}) "
 
822
  f"in={scores['mean_inside']:.2f}±{scores['texture']:.2f} "
823
  f"out={scores['mean_outside']:.2f}")
824
 
@@ -921,6 +941,15 @@ def process_image(input_path, output_dir):
921
  best_mask = gc_result
922
 
923
  refined = refine_mask(best_mask, gray_f32)
 
 
 
 
 
 
 
 
 
924
  draw_result(gray_u8, refined, scores,
925
  out_r, out_m, out_dv,
926
  wmap, pn,
 
458
  if valid_score < 0.5:
459
  lateral_pen = 0.4
460
 
461
+ # Border contact penalty: true cave entrances are contained within the frame.
462
+ # Dark patches that bleed to an image edge are likely cast shadows or vegetation
463
+ # extending beyond the visible area, not a cave void.
464
+ bp = 3 # border margin in pixels
465
+ border_touches = int(
466
+ (mask[:bp, :] > 0).any() # top
467
+ + (mask[-bp:, :] > 0).any() # bottom
468
+ + (mask[:, :bp] > 0).any() # left
469
+ + (mask[:, -bp:] > 0).any() # right
470
+ )
471
+ if border_touches == 0:
472
+ border_mult = 1.0
473
+ elif border_touches == 1:
474
+ border_mult = 0.60
475
+ else:
476
+ border_mult = 0.35
477
+
478
  total = (additive * area_mult * solidity_mult
479
+ * texture_mult * vert_gate * lateral_pen * border_mult)
480
 
481
  return {
482
  "total": round(float(total), 4),
 
497
  "valid_score": round(float(valid_score), 3),
498
  "mean_inside": round(float(mean_inside), 3),
499
  "mean_outside": round(float(mean_outside), 3),
500
+ "border_touches": border_touches,
501
+ "border_mult": round(float(border_mult), 3),
502
  }
503
 
504
 
 
838
  f"depth={scores['depth']:.2f} "
839
  f"area_m={scores['area_mult']:.2f} "
840
  f"sol={scores['solidity']:.2f}(×{scores['sol_mult']:.2f}) "
841
+ f"border={scores['border_touches']}(×{scores['border_mult']:.2f}) "
842
  f"in={scores['mean_inside']:.2f}±{scores['texture']:.2f} "
843
  f"out={scores['mean_outside']:.2f}")
844
 
 
941
  best_mask = gc_result
942
 
943
  refined = refine_mask(best_mask, gray_f32)
944
+
945
+ # Hard-clip final mask to the actual illumination columns (not the capped
946
+ # lc/rc) to exclude IR vignette/penumbra that GrabCut or contour smoothing
947
+ # may have reintroduced after the expansion clip.
948
+ if actual_lc > int(w * 0.05):
949
+ refined[:, :actual_lc] = 0
950
+ if actual_rc < int(w * 0.95):
951
+ refined[:, actual_rc + 1:] = 0
952
+
953
  draw_result(gray_u8, refined, scores,
954
  out_r, out_m, out_dv,
955
  wmap, pn,