Raise configured YOLO max detections
GeoIntel CI / docs-smoke (push) Has been cancelled
GeoIntel CI / contract-smoke (push) Has been cancelled

This commit is contained in:
Codex
2026-07-09 10:14:07 +02:00
parent 9bef905da8
commit 25f098bde0
16 changed files with 82 additions and 1 deletions
+5
View File
@@ -359,6 +359,7 @@ YOLO_CONFIG_DIR=/app/storage/ultralytics
YOLO_DEVICE=cpu
YOLO_IMAGE_SIZE=640
YOLO_MAX_TILES=100
YOLO_MAX_DETECTIONS=1000
YOLO_BATCH_SIZE=1
```
@@ -384,6 +385,10 @@ python scripts/yolo_preflight.py --model-path /absolute/path/to/local-model.pt -
The preflight checks configuration, dependency availability, local model file existence, tile manifest validity, tile count and referenced tile paths. JSON output also includes runtime diagnostics for the model directory, `YOLO_CONFIG_DIR`, installed `torch`/`ultralytics` versions and CUDA availability when dependency checks pass. It does not load a YOLO model, run inference or download weights.
`YOLO_MAX_DETECTIONS` is forwarded to Ultralytics as `max_det`. The default is
`1000` because dense building AOIs can exceed the upstream default cap of 300
detections before QA/QC can measure recall honestly.
The same read-only status is available through the API and Detection Lab UI:
```bash
+1
View File
@@ -31,6 +31,7 @@ class Settings(BaseSettings):
yolo_device: str = Field(default="cpu", validation_alias="YOLO_DEVICE")
yolo_image_size: int = Field(default=640, validation_alias="YOLO_IMAGE_SIZE")
yolo_max_tiles: int = Field(default=100, validation_alias="YOLO_MAX_TILES")
yolo_max_detections: int = Field(default=1000, validation_alias="YOLO_MAX_DETECTIONS")
yolo_batch_size: int = Field(default=1, validation_alias="YOLO_BATCH_SIZE")
cors_origins: list[str] | str = Field(
default=["http://localhost:5173", "http://127.0.0.1:5173"],
+1
View File
@@ -72,6 +72,7 @@ class YoloDetectionAdapter:
conf=float(confidence_threshold),
imgsz=int(self.settings.yolo_image_size),
device=self.settings.yolo_device,
max_det=int(self.settings.yolo_max_detections),
verbose=False,
)
except AppError:
@@ -93,6 +93,7 @@ def test_env_example_uses_runtime_env_names_read_by_backend_and_frontend() -> No
assert "YOLO_MODEL_PATH=" in env_example
assert "YOLO_CONFIG_DIR=./storage/ultralytics" in env_example
assert "YOLO_MAX_TILES=100" in env_example
assert "YOLO_MAX_DETECTIONS=1000" in env_example
assert "ENABLE_YOLO" not in env_example
assert "ENABLE_SAM" not in env_example
assert "VITE_API_BASE_URL=" in env_example
@@ -245,4 +246,5 @@ def test_unraid_deploy_passes_ai_build_arg_and_yolo_runtime_env() -> None:
assert '-e YOLO_MODELS_DIR="$YOLO_MODELS_DIR"' in run_script
assert '-e YOLO_MODEL_PATH="$YOLO_MODEL_PATH"' in run_script
assert '-e YOLO_MAX_TILES="$YOLO_MAX_TILES"' in run_script
assert '-e YOLO_MAX_DETECTIONS="$YOLO_MAX_DETECTIONS"' in run_script
assert "-v \"${GEOINTEL_MODELS_PATH}:/app/models\"" in run_script
+16 -1
View File
@@ -93,7 +93,7 @@ class RecordingPredictModel:
def __init__(self) -> None:
self.seen_sources: list[dict] = []
def predict(self, *, source, conf, imgsz, device, verbose):
def predict(self, *, source, conf, imgsz, device, verbose, max_det):
from PIL import Image
with Image.open(source) as image:
@@ -106,6 +106,7 @@ class RecordingPredictModel:
"imgsz": imgsz,
"device": device,
"verbose": verbose,
"max_det": max_det,
}
)
return []
@@ -399,6 +400,20 @@ def test_yolo_adapter_converts_single_band_tiles_to_rgb_before_prediction(tmp_pa
assert model.seen_sources[0]["imgsz"] == 64
assert model.seen_sources[0]["device"] == "cpu"
assert model.seen_sources[0]["verbose"] is False
assert model.seen_sources[0]["max_det"] == 1000
def test_yolo_adapter_uses_configured_max_detections(tmp_path: Path) -> None:
Image = pytest.importorskip("PIL.Image")
tile_path = tmp_path / "rgb_tile.png"
Image.new("RGB", (16, 16), (10, 20, 30)).save(tile_path)
model = RecordingPredictModel()
settings = _settings(tmp_path, yolo_max_detections=1500)
detections = YoloDetectionAdapter(settings).predict_tile(model, tile_path, confidence_threshold=0.25)
assert detections == []
assert model.seen_sources[0]["max_det"] == 1500
def test_yolo_adapter_wraps_prediction_runtime_errors(tmp_path: Path) -> None: