Harden SAM roof refinement geometry gates
GeoIntel release gates / Compile, test, contracts and builds (push) Canceled after 0s
GeoIntel release gates / Python and npm vulnerability policy (push) Canceled after 0s
GeoIntel release gates / GIS image, SBOM and container scan (push) Canceled after 0s

This commit is contained in:
Jens
2026-07-30 04:00:24 +02:00
parent 5ac3238c27
commit 29378bba42
4 changed files with 74 additions and 6 deletions
+31 -3
View File
@@ -7,6 +7,7 @@ import argparse
import gc
import hashlib
import json
import math
import os
import shutil
from pathlib import Path
@@ -38,11 +39,29 @@ def plausible_refinement(
min_iou: float,
min_area_ratio: float,
max_area_ratio: float,
max_center_shift_ratio: float,
min_dimension_ratio: float,
max_dimension_ratio: float,
) -> bool:
source_area = (source[2] - source[0]) * (source[3] - source[1])
refined_area = (refined[2] - refined[0]) * (refined[3] - refined[1])
source_width, source_height = source[2] - source[0], source[3] - source[1]
refined_width, refined_height = refined[2] - refined[0], refined[3] - refined[1]
source_area = source_width * source_height
refined_area = refined_width * refined_height
ratio = refined_area / source_area if source_area > 0 else 0.0
return min_area_ratio <= ratio <= max_area_ratio and iou(source, refined) >= min_iou
if source_width <= 0 or source_height <= 0:
return False
width_ratio = refined_width / source_width
height_ratio = refined_height / source_height
source_centre = ((source[0] + source[2]) / 2, (source[1] + source[3]) / 2)
refined_centre = ((refined[0] + refined[2]) / 2, (refined[1] + refined[3]) / 2)
centre_shift_ratio = math.dist(source_centre, refined_centre) / math.hypot(source_width, source_height)
return (
min_area_ratio <= ratio <= max_area_ratio
and min_dimension_ratio <= width_ratio <= max_dimension_ratio
and min_dimension_ratio <= height_ratio <= max_dimension_ratio
and centre_shift_ratio <= max_center_shift_ratio
and iou(source, refined) >= min_iou
)
def read_boxes(path: Path, width: int, height: int) -> list[tuple[float, float, float, float]]:
@@ -85,6 +104,9 @@ def main() -> int:
parser.add_argument("--min-source-iou", type=float, default=0.15)
parser.add_argument("--min-area-ratio", type=float, default=0.25)
parser.add_argument("--max-area-ratio", type=float, default=4.0)
parser.add_argument("--max-center-shift-ratio", type=float, default=0.75)
parser.add_argument("--min-dimension-ratio", type=float, default=0.5)
parser.add_argument("--max-dimension-ratio", type=float, default=2.0)
parser.add_argument("--max-prompts-per-pass", type=int, default=96)
parser.add_argument("--force", action="store_true")
args = parser.parse_args()
@@ -139,6 +161,9 @@ def main() -> int:
min_iou=args.min_source_iou,
min_area_ratio=args.min_area_ratio,
max_area_ratio=args.max_area_ratio,
max_center_shift_ratio=args.max_center_shift_ratio,
min_dimension_ratio=args.min_dimension_ratio,
max_dimension_ratio=args.max_dimension_ratio,
):
output_boxes[start + local_index] = candidate
unmatched.remove(candidate_index)
@@ -184,6 +209,9 @@ def main() -> int:
"min_source_iou": args.min_source_iou,
"min_area_ratio": args.min_area_ratio,
"max_area_ratio": args.max_area_ratio,
"max_center_shift_ratio": args.max_center_shift_ratio,
"min_dimension_ratio": args.min_dimension_ratio,
"max_dimension_ratio": args.max_dimension_ratio,
"max_prompts_per_pass": args.max_prompts_per_pass,
"refined_label_count": refined_count,
"fallback_label_count": fallback_count,