Expand operator samples for YOLO hard negatives
GeoIntel CI / docs-smoke (push) Has been cancelled
GeoIntel CI / contract-smoke (push) Has been cancelled

This commit is contained in:
Codex
2026-07-07 21:42:23 +02:00
parent e8d79fccbb
commit 89c5729d33
8 changed files with 288 additions and 23 deletions
+64 -2
View File
@@ -36,6 +36,8 @@ class OperatorSample:
half_size_m: float = 250.0
width: int = 512
height: int = 512
sample_role: str = "reference"
allow_empty_reference: bool = False
SAMPLES: dict[str, OperatorSample] = {
@@ -57,6 +59,61 @@ SAMPLES: dict[str, OperatorSample] = {
center_lon=4.9488,
center_lat=51.3225,
),
"herentals": OperatorSample(
slug="herentals",
display_name="Herentals center",
center_lon=4.8339,
center_lat=51.1766,
half_size_m=220.0,
),
"balen": OperatorSample(
slug="balen",
display_name="Balen center",
center_lon=5.1703,
center_lat=51.1688,
half_size_m=220.0,
),
"retie": OperatorSample(
slug="retie",
display_name="Retie center",
center_lon=5.0827,
center_lat=51.2665,
half_size_m=220.0,
),
"westerlo": OperatorSample(
slug="westerlo",
display_name="Westerlo center",
center_lon=4.9158,
center_lat=51.0909,
half_size_m=220.0,
),
"postel_bos": OperatorSample(
slug="postel_bos",
display_name="Postel forest background candidate",
center_lon=5.16,
center_lat=51.305,
half_size_m=260.0,
sample_role="background_candidate",
allow_empty_reference=True,
),
"lommel_heide": OperatorSample(
slug="lommel_heide",
display_name="Lommel forest background candidate",
center_lon=5.287,
center_lat=51.249,
half_size_m=260.0,
sample_role="background_candidate",
allow_empty_reference=True,
),
"kasterlee_bos": OperatorSample(
slug="kasterlee_bos",
display_name="Kasterlee forest background candidate",
center_lon=4.965,
center_lat=51.273,
half_size_m=260.0,
sample_role="background_candidate",
allow_empty_reference=True,
),
}
@@ -218,7 +275,7 @@ def fetch_reference(sample: OperatorSample, reference_path: Path, geo_bbox: list
response.raise_for_status()
reference = response.json()
features = reference.get("features") or []
if not features:
if not features and not sample.allow_empty_reference:
raise SystemExit(f"GRB GBG returned no building features for {sample.slug} bbox {geo_bbox}")
reference["name"] = f"GRB GBG buildings - {sample.display_name} sample AOI"
@@ -227,11 +284,14 @@ def fetch_reference(sample: OperatorSample, reference_path: Path, geo_bbox: list
reference["attribution"] = "Bron: Grootschalig Referentie Bestand Vlaanderen, Digitaal Vlaanderen"
reference["bbox"] = geo_bbox
reference["sample_slug"] = sample.slug
reference["sample_role"] = sample.sample_role
reference["allow_empty_reference"] = sample.allow_empty_reference
for feature in features:
props = feature.setdefault("properties", {})
props.setdefault("source_name", "grb")
props.setdefault("reference_layer_name", "buildings")
props.setdefault("sample_slug", sample.slug)
props.setdefault("sample_role", sample.sample_role)
reference_path.write_text(json.dumps(reference, ensure_ascii=False), encoding="utf-8")
return prepared_url(GRB_GBG_URL, ogc_params), len(features)
@@ -256,6 +316,8 @@ def prepare_sample(sample: OperatorSample, output_dir: Path, force: bool) -> dic
"center_lon": sample.center_lon,
"center_lat": sample.center_lat,
"half_size_m": sample.half_size_m,
"sample_role": sample.sample_role,
"allow_empty_reference": sample.allow_empty_reference,
"raster_path": str(ortho_path),
"reference_path": str(reference_path),
"reference_feature_count": reference_feature_count,
@@ -288,7 +350,7 @@ def write_readme(output_dir: Path, samples: list[dict[str, Any]]) -> None:
lines.append(
f"- `{sample['sample_slug']}`: `{Path(sample['raster_path']).name}` and "
f"`{Path(sample['reference_path']).name}`, "
f"{sample['reference_feature_count']} reference features."
f"{sample['reference_feature_count']} reference features, role `{sample['sample_role']}`."
)
lines.append("")
lines.append("Purpose: configured-YOLO detection + persisted QA/QC validation with operator-provided files.")