Geospatial object detection using RF-DETR
Project description
detr-geo
Object detection for satellite and aerial imagery. Feed in a GeoTIFF, get back georeferenced vector data -- GeoJSON, GeoPackage, or Shapefile -- with full CRS, coordinates, and attribute tables ready for QGIS, ArcGIS, or PostGIS.
detr-geo wraps RF-DETR and adds everything a geospatial workflow needs: automatic tiling with cross-tile NMS deduplication, multispectral band mapping, 16-bit imagery normalization, nodata handling, and spatial-aware training dataset preparation. Includes a training pipeline for fine-tuning on your own data, with xView-trained vehicle detection weights available as an example.
Quick Start
from detr_geo import DetrGeo
dg = DetrGeo(model_size="medium")
dg.set_image("parking_lot.tif")
detections = dg.detect_tiled(overlap=0.2, threshold=0.3)
dg.to_gpkg("vehicles.gpkg")
print(f"{len(detections)} vehicles found")
print(detections[["class_name", "confidence", "geometry"]].head())
Inspired by samgeo, but for bounding-box detection rather than segmentation.
What detr-geo does that raw RF-DETR cannot
| Capability | RF-DETR alone | detr-geo |
|---|---|---|
| Input | Single PIL image, <= 704px | GeoTIFF of any size, any CRS, 8/16-bit |
| Output | Pixel bounding boxes | Georeferenced polygons with CRS |
| Large imagery | Fails or requires manual slicing | Automatic tiling, overlap, cross-tile NMS |
| Multispectral | RGB only | Band presets for NAIP, Sentinel-2, WorldView |
| Nodata | Not handled | Skip empty tiles, fill partial tiles |
| Export | NumPy arrays | GeoJSON, GeoPackage, Shapefile |
| Training | Generic COCO format | Spatial splitting to prevent geospatial data leakage |
| Overhead imagery | Trained on ground-level photos | Fine-tuning pipeline + example xView vehicle weights |
xView Fine-Tuned Model
The COCO-pretrained model was trained on ground-level photography. It has never seen a car from above, and it shows -- overhead vehicles get labeled as "motorcycle", "skateboard", or "boat".
The xView fine-tuned model fixes this. Trained on the xView dataset (satellite imagery at 0.3m GSD), it detects 5 overhead vehicle classes:
| Class | Examples |
|---|---|
| Car | Sedans, SUVs, hatchbacks |
| Pickup Truck | Pickup trucks, utility pickups |
| Truck | Semi trucks, cargo trucks, tankers |
| Bus | Transit buses, school buses, coaches |
| Other Vehicle | Construction equipment, engineering vehicles |
from detr_geo import DetrGeo
dg = DetrGeo(
model_size="medium",
pretrain_weights="checkpoints/checkpoint_best_ema.pth",
custom_class_names={
0: "Car",
1: "Pickup Truck",
2: "Truck",
3: "Bus",
4: "Other Vehicle",
},
)
dg.set_image("satellite_scene.tif")
detections = dg.detect_tiled(overlap=0.2, threshold=0.3)
# Per-class counts
print(detections["class_name"].value_counts())
# Export for QGIS
dg.to_gpkg("vehicle_detections.gpkg")
Download the xView fine-tuned weights (optional):
huggingface-cli download gpriceless/detr-geo-xview \
checkpoint_best_ema.pth --local-dir checkpoints/
Installation
Prerequisites
detr-geo requires GDAL and rasterio. On most systems:
# Ubuntu/Debian
sudo apt install gdal-bin libgdal-dev
# macOS (with Homebrew)
brew install gdal
# conda (recommended for geospatial Python)
conda install -c conda-forge rasterio geopandas
Install detr-geo
pip install detr-geo # Core geospatial tools only (no model, no viz)
pip install detr-geo[rfdetr] # With RF-DETR model + PyTorch
pip install detr-geo[viz] # With leafmap + matplotlib visualization
pip install detr-geo[all] # Everything
Core installs rasterio, geopandas, pyproj, shapely, and numpy. This is sufficient for processing pre-computed detection results without running inference.
[rfdetr] adds the RF-DETR model, PyTorch, and supervision. Downloads ~2 GB of model weights on first use.
[viz] adds leafmap (interactive maps) and matplotlib (static plots).
GPU Support
RF-DETR runs on CPU but is 10-50x faster on GPU:
# CUDA (NVIDIA)
pip install torch --index-url https://download.pytorch.org/whl/cu121
pip install detr-geo[all]
# MPS (Apple Silicon) -- PyTorch detects automatically
pip install detr-geo[all]
Core Workflow
1. Load imagery
dg = DetrGeo(model_size="medium")
dg.set_image("orthomosaic.tif")
detr-geo reads the CRS and affine transform from your raster automatically. It supports GeoTIFF, COG, and any rasterio-readable format.
2. Detect objects
For small images (fits in memory):
detections = dg.detect(threshold=0.4)
For large rasters (orthomosaics, satellite scenes):
detections = dg.detect_tiled(
overlap=0.2, # 20% overlap prevents boundary artifacts
nms_threshold=0.5, # deduplicate across tiles
nodata_threshold=0.5, # skip tiles that are >50% empty
)
3. Export georeferenced results
dg.to_gpkg("detections.gpkg") # GeoPackage -- recommended
dg.to_geojson("detections.geojson") # GeoJSON (auto-reprojects to WGS84)
dg.to_shp("detections.shp") # Shapefile (legacy)
Or work with the GeoDataFrame directly:
gdf = dg.detections
cars = gdf[gdf["class_name"] == "Car"]
confident = gdf[gdf["confidence"] > 0.7]
4. Visualize
# Static matplotlib plot
dg.show_detections(figsize=(15, 12), save_path="output.png")
# Interactive leafmap (Jupyter)
m = dg.show_map(basemap="SATELLITE")
Band Selection
RF-DETR expects 3-channel RGB input. Different sensors store RGB in different bands. detr-geo maps them automatically:
dg.set_image("naip.tif", bands="rgb") # Default: bands 1-2-3
dg.set_image("sentinel2.tif", bands="sentinel2_rgb") # Sentinel-2: bands 4-3-2
dg.set_image("worldview.tif", bands="worldview_rgb") # WorldView: bands 5-3-2
dg.set_image("custom.tif", bands=(4, 3, 2)) # Any 3-band combo (1-indexed)
Fine-Tuning on Custom Data
Train RF-DETR on your own overhead imagery. detr-geo handles the full pipeline from GeoTIFF + vector annotations to trained model:
from detr_geo import prepare_training_dataset, train, DetrGeo
# 1. Tile raster, align CRS, clip annotations, split spatially
prepare_training_dataset(
raster_path="ortho.tif",
annotations_path="labels.geojson",
output_dir="training_data/",
tile_size=576,
split_method="block", # spatial splitting prevents leakage
split_ratios=(0.8, 0.15, 0.05),
)
# 2. Train with geospatial augmentations (rotation, flip -- no "up" in overhead)
dg = DetrGeo(model_size="medium")
train(
adapter=dg._adapter,
dataset_dir="training_data/",
epochs=50,
batch_size=8,
augmentation_preset="satellite_default",
)
# 3. Run inference with your trained weights
dg = DetrGeo(
model_size="medium",
pretrain_weights="output/checkpoint_best_ema.pth",
custom_class_names={0: "Building", 1: "Road", 2: "Tree"},
)
See the Fine-Tuning Guide for hardware requirements, monitoring, xView training details, and troubleshooting.
Model Sizes
| Size | Resolution | Parameters | Best For |
|---|---|---|---|
| nano | 384px | ~15M | CPU inference, quick prototyping |
| small | 512px | ~22M | Balanced speed and accuracy |
| medium | 576px | ~25M | Default. Best accuracy/speed tradeoff |
| base | 560px | ~29M | Higher accuracy, more VRAM |
| large | 704px | ~30M | Maximum accuracy, GPU recommended |
Real-World Use Cases
Parking lot occupancy -- Count vehicles across a commercial property from a single satellite capture. Export per-class counts (cars, trucks, buses) as a GeoJSON layer for the facilities team.
Construction site monitoring -- Detect heavy equipment in weekly drone surveys. Compare detections across dates to track mobilization and demobilization.
Fleet asset tracking -- Process satellite imagery of a logistics yard to locate trucks and trailers. Output GeoPackage layers with confidence scores for the dispatch team.
Urban planning -- Tile a city-wide orthomosaic and detect all vehicles. Aggregate detections by census tract for traffic density analysis.
Disaster response -- Rapidly scan post-event imagery for vehicles (potential rescue targets) in flood zones or collapsed structures.
Known Limitations
- Memory:
detect()loads the full raster. Usedetect_tiled()for rasters larger than ~5000x5000 pixels. - Geographic CRS tiling: Tiles in EPSG:4326 vary in ground size by latitude. Use a projected CRS for best results.
- Per-tile normalization: In tiled mode, each tile is normalized independently. For consistent 16-bit results, pre-compute stretch parameters with
detr_geo.io.compute_scene_stretch_params. - Batch inference: Tiles are processed sequentially on GPU. True tensor batching is planned.
Output Formats
| Format | Method | Notes |
|---|---|---|
| GeoJSON | to_geojson() |
Auto-reprojects to WGS84 per spec |
| GeoPackage | to_gpkg() |
Recommended. Preserves CRS, supports layers |
| Shapefile | to_shp() |
Legacy. 10-char field names, 2 GB limit |
| GeoDataFrame | .detections |
In-memory geopandas for further analysis |
License
Code: MIT
xView fine-tuned weights: CC BY-NC-SA 4.0 (following the xView dataset license). COCO-pretrained weights are unrestricted.
Links
- API Reference -- full method documentation
- Geospatial Guide -- tiling, CRS, bands, 16-bit, nodata
- Fine-Tuning Guide -- train on your own overhead imagery
- Examples -- runnable scripts for common workflows
- RF-DETR -- the underlying detection architecture
- xView Dataset -- satellite imagery used for fine-tuning
- samgeo -- the project that inspired this one
Acknowledgments
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file detr_geo-0.1.0.tar.gz.
File metadata
- Download URL: detr_geo-0.1.0.tar.gz
- Upload date:
- Size: 1.3 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
92902e3047f31bdec3caf6d0a8a46b369df228d84e5653323650a1364dc8ba04
|
|
| MD5 |
d7715da845b4ae279e58ec8cc36e3464
|
|
| BLAKE2b-256 |
f6f4ddf127683ecd7a4ec164a4480c532052046db4cc0d8843496cb26ff04c73
|
Provenance
The following attestation bundles were made for detr_geo-0.1.0.tar.gz:
Publisher:
publish.yml on gpriceless/detr-geo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
detr_geo-0.1.0.tar.gz -
Subject digest:
92902e3047f31bdec3caf6d0a8a46b369df228d84e5653323650a1364dc8ba04 - Sigstore transparency entry: 929759026
- Sigstore integration time:
-
Permalink:
gpriceless/detr-geo@82939d265bf38c98ca98dba3478782a5d141abb9 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/gpriceless
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@82939d265bf38c98ca98dba3478782a5d141abb9 -
Trigger Event:
release
-
Statement type:
File details
Details for the file detr_geo-0.1.0-py3-none-any.whl.
File metadata
- Download URL: detr_geo-0.1.0-py3-none-any.whl
- Upload date:
- Size: 53.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5e1945b343415f311c5a63f779fbff880bf2fa96752252be1ae8621939f6eb23
|
|
| MD5 |
53ce16260b924d5608885524c2e954ed
|
|
| BLAKE2b-256 |
6fc4e0e8b899fe82285c74130a84bed52230844a537bff98ebcbba7c3102e35b
|
Provenance
The following attestation bundles were made for detr_geo-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on gpriceless/detr-geo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
detr_geo-0.1.0-py3-none-any.whl -
Subject digest:
5e1945b343415f311c5a63f779fbff880bf2fa96752252be1ae8621939f6eb23 - Sigstore transparency entry: 929759027
- Sigstore integration time:
-
Permalink:
gpriceless/detr-geo@82939d265bf38c98ca98dba3478782a5d141abb9 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/gpriceless
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@82939d265bf38c98ca98dba3478782a5d141abb9 -
Trigger Event:
release
-
Statement type: