Add Mol multi-zone operational validation

This commit is contained in:
Codex
2026-07-13 18:12:48 +02:00
parent 4539e92bcf
commit 2c16ff2bc0
16 changed files with 605 additions and 12 deletions
@@ -146,9 +146,14 @@ with output_path.open("w", encoding="utf-8") as handle:
background_category = "reference_aoi"
if requested_categories and background_category not in requested_categories:
continue
bbox = sample.get("wgs84_bbox") or []
if len(bbox) != 4:
raise SystemExit(f"Background sample has no valid wgs84_bbox: {sample_slug}")
bbox_csv = ",".join(str(float(value)) for value in bbox)
municipality = str(sample.get("municipality") or "")
handle.write(
f"{sample_slug}\t{raster_path}\t{sample_role}\t{allow_empty_reference}\t"
f"{reference_count}\t{background_category}\n"
f"{reference_count}\t{background_category}\t{bbox_csv}\t{municipality}\n"
)
selected += 1
@@ -263,8 +268,12 @@ echo "Tile overlaps: ${tile_overlaps_normalized}"
echo "Thresholds: ${thresholds_normalized}"
echo "Output: ${HARD_NEGATIVE_OUTPUT_DIR}"
while IFS=$'\t' read -r sample_slug raster_path sample_role allow_empty_reference reference_feature_count background_category; do
while IFS=$'\t' read -r sample_slug raster_path sample_role allow_empty_reference reference_feature_count background_category wgs84_bbox municipality; do
echo "-- Background sample ${sample_slug}: role=${sample_role} category=${background_category} allow_empty_reference=${allow_empty_reference} reference_features=${reference_feature_count} --"
project_region="Kempen"
if [ "${municipality,,}" = "mol" ]; then
project_region="Mol, Kempen"
fi
while IFS=$'\t' read -r model_request tile_size tile_overlap threshold run_label; do
sample_output_dir="${HARD_NEGATIVE_OUTPUT_DIR}/${sample_slug}"
mkdir -p "${sample_output_dir}"
@@ -278,17 +287,17 @@ while IFS=$'\t' read -r sample_slug raster_path sample_role allow_empty_referenc
{
echo "sample=${sample_slug} model=${model_request} tile=${tile_size} overlap=${tile_overlap} threshold=${threshold}"
"${PYTHON_BIN}" - "${tmp_dir}/project_request.json" "${sample_slug}" "${model_request}" "${threshold}" <<'PY'
"${PYTHON_BIN}" - "${tmp_dir}/project_request.json" "${sample_slug}" "${model_request}" "${threshold}" "${project_region}" <<'PY'
import json
import sys
from datetime import datetime, timezone
path, sample_slug, model_request, threshold = sys.argv[1:5]
path, sample_slug, model_request, threshold, project_region = sys.argv[1:6]
stamp = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")
payload = {
"name": f"GeoIntel hard-negative {sample_slug} {model_request} {threshold} {stamp}",
"description": "Operator hard-negative validation: raster upload, tiling, configured YOLO detection count, no QA reference.",
"region": "Kempen",
"region": project_region,
}
with open(path, "w", encoding="utf-8") as handle:
json.dump(payload, handle)
@@ -300,6 +309,29 @@ PY
require_json_data "${tmp_dir}/project.json"
project_id="$(json_field "${tmp_dir}/project.json" "data.id")"
"${PYTHON_BIN}" - "${tmp_dir}/area_request.json" "${sample_slug} background AOI" "${wgs84_bbox}" <<'PY'
import json
import sys
path, area_name, bbox_raw = sys.argv[1:4]
minx, miny, maxx, maxy = [float(value.strip()) for value in bbox_raw.split(",")]
if minx >= maxx or miny >= maxy:
raise SystemExit("Background AOI bbox minimum values must be smaller than maximum values")
ring = [[minx, miny], [maxx, miny], [maxx, maxy], [minx, maxy], [minx, miny]]
payload = {
"name": area_name,
"crs": "EPSG:4326",
"geometry": {"type": "MultiPolygon", "coordinates": [[ring]]},
}
with open(path, "w", encoding="utf-8") as handle:
json.dump(payload, handle)
PY
curl -fsS -X POST "${BASE_URL%/}/api/v1/projects/${project_id}/areas" \
-H "Content-Type: application/json" \
--data-binary "@${tmp_dir}/area_request.json" > "${tmp_dir}/area.json"
require_json_data "${tmp_dir}/area.json"
area_id="$(json_field "${tmp_dir}/area.json" "data.id")"
curl -fsS -X POST "${BASE_URL%/}/api/v1/projects/${project_id}/datasets/upload" \
-F "file=@${raster_path}" \
-F "dataset_type=raster" \
@@ -407,6 +439,7 @@ PY
"${tile_overlap}" \
"${threshold}" \
"${project_id}" \
"${area_id}" \
"${raster_dataset_id}" \
"${manifest_path}" \
"${analysis_run_id}" \
@@ -430,6 +463,7 @@ import sys
tile_overlap,
threshold,
project_id,
area_id,
raster_dataset_id,
manifest_path,
analysis_run_id,
@@ -437,7 +471,7 @@ import sys
detections_list_count,
tile_count,
run_log,
) = sys.argv[1:20]
) = sys.argv[1:21]
detections = int(detection_count)
listed = int(detections_list_count)
@@ -456,6 +490,7 @@ summary = {
"tile_overlap": int(tile_overlap),
"threshold": float(threshold),
"project_id": project_id,
"area_id": area_id,
"raster_dataset_id": raster_dataset_id,
"manifest_path": manifest_path,
"analysis_run_id": analysis_run_id,