--- title: GeoAP Satellite CV (YOLO26m) emoji: 🛰️ colorFrom: green colorTo: blue sdk: gradio sdk_version: 6.21.0 app_file: app.py pinned: false license: agpl-3.0 short_description: Tiled YOLO26m detection + segmentation on aerial imagery models: - GeminiTwins/geoap-yolo26m-detection - GeminiTwins/geoap-yolo26m-segmentation --- # GeoAP — Satellite Detection & Segmentation on Hugging Face Standalone deployment project for the GeoAP models. Two YOLO26m checkpoints (detection + instance segmentation) served through a Gradio Space, plus scripts to publish the weights as Hub model repos. Nothing here imports from the parent `geoCV` package — the folder can be copied out and pushed to a Space as-is. | task | base checkpoint | classes | |---|---|---| | detection | `yolo26m.pt` | batiment, arbre, panneaux_solaires, bassin | | segmentation | `yolo26m-seg.pt` | parcelle_cultivee, terre_non_cultivee, route, riviere, piste_agricole | ## Layout ``` geoap-hf-space/ ├── app.py # Gradio UI (Space entry point) ├── config.yaml # classes, thresholds, tiling, Hub repo ids ├── requirements.txt ├── src/ │ ├── settings.py # config loader │ ├── model_loader.py # local -> Hub -> base weight resolution + cache │ ├── io_raster.py # GeoTIFF / TIFF / JP2 / PNG / JPG loading + CRS │ ├── tiling.py # sliding window, downscale, pad │ ├── inference.py # SAHI detection, tiled segmentation, GeoJSON │ ├── mapview.py # Leaflet map of the GeoJSON (iframe + .html) │ └── viz.py # palette, boxes, mask blending, optional sidebar ├── scripts/ │ ├── finetune_yolo26.py # train yolo26m / yolo26m-seg on GeoAP tiles │ ├── export_onnx.py # ONNX / TorchScript export │ ├── push_models_to_hub.py # create model repos + upload weights & cards │ └── deploy_space.py # create the Space and upload this folder ├── weights/ # put detection_best.pt / segmentation_best.pt here └── examples/ # sample images shown in the UI ``` ## 1. Local run ```bash cd geoap-hf-space python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate pip install -r requirements.txt python app.py # http://127.0.0.1:7860 ``` With no weights present the app falls back to the base COCO checkpoints so the UI is testable immediately — you will see COCO class names in that case. ## 2. Train the YOLO26m weights The parent project already produces tiled YOLO datasets under `artifacts/tiled_detection/` and `artifacts/tiled_segmentation/`. Point the script at their `data.yaml`: ```bash python scripts/finetune_yolo26.py \ --task detect \ --data ../artifacts/tiled_detection/data.yaml \ --epochs 100 --batch 16 --imgsz 640 python scripts/finetune_yolo26.py \ --task segment \ --data ../artifacts/tiled_segmentation/data.yaml \ --epochs 100 --batch 16 --imgsz 640 ``` Copy the results in: ```bash cp runs/detect/geoap_yolo26m_detect/weights/best.pt weights/detection_best.pt cp runs/segment/geoap_yolo26m_segment/weights/best.pt weights/segmentation_best.pt ``` ## 3. Publish the models ```bash huggingface-cli login # or: export HF_TOKEN=hf_xxx python scripts/push_models_to_hub.py --both ``` Creates (or updates) two model repos with `best.pt`, a generated model card, `config.yaml` and — if present — the training metrics from `results.csv`. Optional ONNX artefacts for CPU/edge serving: ```bash python scripts/export_onnx.py --task detect --format onnx --half false python scripts/push_models_to_hub.py --task detect --extra weights/detection_best.onnx ``` ## 4. Deploy the Space ```bash python scripts/deploy_space.py --hardware cpu-basic ``` Uploads this folder to `hub.space_repo` from `config.yaml`. Large `.pt` files in `weights/` are skipped by default — the Space pulls them from the model repos at runtime, which keeps the Space small and lets you version weights separately. If the model repos are private, add `HF_TOKEN` as a Space secret. ## Configuration Everything tunable lives in `config.yaml`: Hub repo ids, class lists, tile size and overlap, confidence/IoU defaults, SAHI merge type (`NMS` / `NMM` / `GREEDYNMM`), max image side and mask opacity. `GEOAP_DET_REPO` and `GEOAP_SEG_REPO` environment variables override the Hub ids at runtime, which is handy for staging a Space against test weights. ## Input formats The upload accepts `.tif` / `.tiff`, `.jp2`, `.vrt`, `.img`, `.png`, `.jpg`, `.webp`, `.bmp`, `.ppm`, `.pgm`. Georeferenced rasters go through `rasterio` so the CRS and geotransform survive; everything else falls back to OpenCV/Pillow. 16-bit and float imagery is percentile-stretched (2–98% per band) to 8-bit, which is what keeps raw satellite tiles from looking almost black. Single-band rasters are replicated to RGB. ## Map The last component is a Leaflet map of the predictions. - **Georeferenced input** — features are reprojected to EPSG:4326 and drawn over an OpenStreetMap basemap, with a per-class layer toggle and popups showing class, confidence and pixel area. - **Plain image** — the map switches to `L.CRS.Simple` and overlays the result image itself, so polygons are still browsable in pixel coordinates. Each run also produces a standalone `*_map.html` alongside the GeoJSON, openable directly in a browser without the Space running. ## Notes on inference - Detection uses SAHI `get_sliced_prediction`, so objects cut by a tile seam are merged rather than double-counted. - Segmentation tiles manually with `retina_masks=True` and composes masks onto a full-resolution float canvas, then draws contours for clean edges. - `to_geojson(result, px_to_lonlat=...)` takes a *batch* mapper `(xs, ys) -> (lons, lats)` — `Raster.px_to_lonlat` from `src.io_raster` is one. It rescales pixel coordinates back to the original raster size first, so downscaled large scenes still land in the right place. Without a mapper, coordinates stay in pixel space. - Class colours are reported in the Counts table (hex) and reused by the map, so the annotated image carries no baked-in legend panel. `run_detection(..., with_sidebar=True)` brings the old in-image legend back if you want it. - Instance counts are per-tile for segmentation — a river crossing five tiles counts as five instances. Use `area_px` if you need a size measure instead. ## License Ultralytics YOLO is AGPL-3.0. Any Space or model repo shipping these weights inherits that license unless you hold an Ultralytics Enterprise license.