Support larger operator training samples
This commit is contained in:
@@ -12,7 +12,7 @@ import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from dataclasses import dataclass
|
||||
from dataclasses import dataclass, replace
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
@@ -196,6 +196,24 @@ def parse_args() -> argparse.Namespace:
|
||||
default="operator_samples_manifest.json",
|
||||
help="Manifest filename written inside output-dir.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--width",
|
||||
type=int,
|
||||
default=int(os.environ.get("OPERATOR_SAMPLE_WIDTH", "512")),
|
||||
help="Orthophoto WMS output width in pixels. Use larger values for operator training datasets.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--height",
|
||||
type=int,
|
||||
default=int(os.environ.get("OPERATOR_SAMPLE_HEIGHT", "512")),
|
||||
help="Orthophoto WMS output height in pixels. Use larger values for operator training datasets.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--half-size-scale",
|
||||
type=float,
|
||||
default=float(os.environ.get("OPERATOR_SAMPLE_HALF_SIZE_SCALE", "1")),
|
||||
help="Multiplier applied to each documented AOI half-size in meters.",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
@@ -229,6 +247,25 @@ def selected_samples(raw: str) -> list[OperatorSample]:
|
||||
return [SAMPLES[slug] for slug in slugs]
|
||||
|
||||
|
||||
def apply_sample_overrides(
|
||||
sample: OperatorSample,
|
||||
*,
|
||||
width: int,
|
||||
height: int,
|
||||
half_size_scale: float,
|
||||
) -> OperatorSample:
|
||||
if width <= 0 or height <= 0:
|
||||
raise SystemExit("--width and --height must be positive integers")
|
||||
if half_size_scale <= 0:
|
||||
raise SystemExit("--half-size-scale must be greater than zero")
|
||||
return replace(
|
||||
sample,
|
||||
width=width,
|
||||
height=height,
|
||||
half_size_m=sample.half_size_m * half_size_scale,
|
||||
)
|
||||
|
||||
|
||||
def sample_bounds(sample: OperatorSample) -> tuple[tuple[float, float, float, float], list[float]]:
|
||||
lambert = Transformer.from_crs("EPSG:4326", "EPSG:31370", always_xy=True)
|
||||
wgs84 = Transformer.from_crs("EPSG:31370", "EPSG:4326", always_xy=True)
|
||||
@@ -273,6 +310,12 @@ def geojson_feature_count(path: Path) -> int:
|
||||
return len(payload.get("features") or [])
|
||||
|
||||
|
||||
def sample_artifact_paths(sample: OperatorSample, output_dir: Path) -> tuple[Path, Path]:
|
||||
ortho_path = output_dir / f"{sample.slug}_orthophoto_wms_{sample.width}.tif"
|
||||
reference_path = output_dir / f"{sample.slug}_grb_gbg_buildings.geojson"
|
||||
return ortho_path, reference_path
|
||||
|
||||
|
||||
def fetch_orthophoto(sample: OperatorSample, ortho_path: Path, lambert_bbox: tuple[float, float, float, float]) -> str:
|
||||
minx, miny, maxx, maxy = lambert_bbox
|
||||
wms_params = {
|
||||
@@ -352,8 +395,7 @@ def fetch_reference(sample: OperatorSample, reference_path: Path, geo_bbox: list
|
||||
|
||||
|
||||
def prepare_sample(sample: OperatorSample, output_dir: Path, force: bool) -> dict[str, Any]:
|
||||
ortho_path = output_dir / f"{sample.slug}_orthophoto_wms_512.tif"
|
||||
reference_path = output_dir / f"{sample.slug}_grb_gbg_buildings.geojson"
|
||||
ortho_path, reference_path = sample_artifact_paths(sample, output_dir)
|
||||
lambert_bbox, geo_bbox = sample_bounds(sample)
|
||||
skip_existing = ortho_path.exists() and reference_path.exists() and not force
|
||||
|
||||
@@ -370,6 +412,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,
|
||||
"width": sample.width,
|
||||
"height": sample.height,
|
||||
"sample_role": sample.sample_role,
|
||||
"allow_empty_reference": sample.allow_empty_reference,
|
||||
"raster_path": str(ortho_path),
|
||||
@@ -416,13 +460,28 @@ def main() -> int:
|
||||
ensure_gis_dependencies()
|
||||
output_dir: Path = args.output_dir
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
samples = [prepare_sample(sample, output_dir, force=args.force) for sample in selected_samples(args.samples)]
|
||||
samples = [
|
||||
prepare_sample(
|
||||
apply_sample_overrides(
|
||||
sample,
|
||||
width=args.width,
|
||||
height=args.height,
|
||||
half_size_scale=args.half_size_scale,
|
||||
),
|
||||
output_dir,
|
||||
force=args.force,
|
||||
)
|
||||
for sample in selected_samples(args.samples)
|
||||
]
|
||||
write_readme(output_dir, samples)
|
||||
|
||||
manifest = {
|
||||
"schema_version": 1,
|
||||
"description": "GeoIntel operator real-data samples for configured-YOLO QA validation.",
|
||||
"output_dir": str(output_dir),
|
||||
"sample_width": args.width,
|
||||
"sample_height": args.height,
|
||||
"half_size_scale": args.half_size_scale,
|
||||
"samples": samples,
|
||||
}
|
||||
manifest_path = output_dir / args.manifest_name
|
||||
|
||||
Reference in New Issue
Block a user