The standalone Geospatial AI
platform — satellite to insight
PyGeoVision v2.0 is a fully independent geospatial AI platform with its own 119-model registry, foundation models (DINOv3 12 variants + Prithvi-EO-2.0 600M), production training stack, FastAPI serving, and edge/cloud deployment. PyGeoFetch (22 satellite providers) and GeoAI (legacy AI subsystems) are optional enhancements — not dependencies.
What's New in v2.0
PyGeoVision v2.0 is a major architectural change: the platform is now fully standalone with its own complete AI stack. GeoAI is no longer a dependency — it's an optional plugin.
| Area | v1.0 | v2.0 | Change |
|---|---|---|---|
| Architecture | Requires GeoAI | Fully standalone | Breaking |
| Model registry | 14 architectures | 119 architectures | +105 |
| Dataset registry | — | 503 datasets | New |
| Tests passing | 208 | 580 | +372 |
| Foundation models | — | DINOv3 (12 variants, SAT-493M) + Prithvi-EO-2.0 (600M) | New |
| VLM | — | CLIP + RemoteCLIP + Moondream 2 | New |
| Serving API | — | FastAPI + WebSocket streaming | New |
| Edge deployment | — | ONNX Runtime + Jetson TensorRT FP16 | New |
| Cloud deployment | — | AWS SageMaker + Azure ML + GCP Vertex AI | New |
| Few-shot learning | — | Prototypical networks (DINOv2-Large) | New |
| AutoML / HPO | — | Optuna integration, +2–4 mIoU typical | New |
| Time-series | — | GeoTimeSeries + anomaly detection | New |
| Monitoring | — | Drift detection + tracker + Slack/webhook alerts | New |
| Production notebooks | — | 25 notebooks, 357 cells, all 25 domains | New |
| GeoAI integration | Required dependency | Optional plugin (pip install "pygeovision[geoai]") | Improved |
client.geoai.*, install the optional plugin: pip install "pygeovision[geoai]". All v1.0 APIs remain backward-compatible.Architecture — Standalone with Optional Plugins
PyGeoVision v2.0 ships its own complete geospatial AI stack — no GeoAI or PyGeoFetch dependency required. Both are optional enhancements available as extras.
Up and running in 5 minutes
PyGeoVision works immediately with local GeoTIFF files — no cloud credentials required. Add PyGeoFetch later if you need satellite data acquisition.
Full Python walkthrough
import pygeovision as pgv from pygeovision.models import get_model from pygeovision.models.foundation.dinov3 import DINOv3Backbone from pygeovision.models.foundation.prithvi import PrithviTasks from pygeovision.inference.tiled import TiledInference from pygeovision.training.trainer import GeoTrainer client = pgv.PyGeoVision() print(client) # PyGeoVision(v2.0.0 | models=119 | datasets=503 | pygeofetch=optional | geoai=optional) # ── 1. Own model registry — 119 architectures ──────────────────────────── model = get_model("segformer-b2", num_classes=5, in_channels=6, pretrained=True) # ── 2. Tiled inference — own stack, no GeoAI ───────────────────────────── inf = TiledInference(model, chip_size=512, overlap=64, blend_mode="gaussian") result = inf.infer("large_scene.tif", "prediction.tif") # → {n_chips: 24, duration_seconds: 1.1, chips_per_second: 44.7} # ── 3. DINOv3 — own foundation stack ───────────────────────────────────── backbone = DINOv3Backbone("dinov3_vitl16_sat") # SAT-493M pre-training embeddings = backbone.extract_embeddings("scene.tif") # (1, 1024) features = backbone.extract_features("scene.tif") # (H_p, W_p, 1024) attention = backbone.get_attention_maps("scene.tif") # saliency map # ── 4. Prithvi-EO-2.0 — own foundation stack ───────────────────────────── tasks = PrithviTasks("prithvi_eo_2_0") land_cover = tasks.land_cover("scene.tif", source="sentinel2") crop_map = tasks.crop_mapping("scene.tif", source="sentinel2") flood = tasks.flood_detection("scene.tif", source="sentinel2") # ── 5. Auto-label without any manual annotation ────────────────────────── ms = client.labeling.microsoft_buildings(bbox=(-0.15,51.47,-0.10,51.52)) fused = client.labeling.pipeline(bbox=(-0.15,51.47,-0.10,51.52), sources=[{"type":"microsoft_buildings","weight":1.5},{"type":"osm","weight":1.0}]) # ── 6. GeoTrainer — own training pipeline ──────────────────────────────── from pygeovision.losses.segmentation import GeospatialMixedLoss from pygeovision.training.callbacks import EarlyStopping, ModelCheckpoint loss = GeospatialMixedLoss(weights={"combo":0.5,"boundary":0.3,"ohem":0.2}) trainer = GeoTrainer(model=model, task="segmentation", num_classes=5, epochs=100, learning_rate=6e-5, mixed_precision="bf16", loss_fn=loss) # ── 7. Serve as REST API ──────────────────────────────────────────────── from pygeovision.serving import InferenceServer server = InferenceServer(auth_keys={"prod":"SECRET"}) server.register("seg_v1", "model.onnx", task="segmentation", num_classes=5) server.serve(host="0.0.0.0", port=8080) # ── 8. Optional: PyGeoFetch satellite data ─────────────────────────────── # pip install pygeofetch results = client.search(bbox=(-0.15,51.47,-0.10,51.52), date_range=("2024-06-01","2024-06-30"), providers=["planetary_computer"]) downloads = client.download(results[:1], post_process=["cog"]) # ── 9. Optional: GeoAI plugin ──────────────────────────────────────────── # pip install "pygeovision[geoai]" # ga = client.geoai # lazy-loads geoai-py on first access # ga.detect.grounded("aerial.tif", "swimming pools") # GroundedSAM
Interactive demo
Data Acquisition via PyGeoFetch
When PyGeoFetch is installed (pip install pygeofetch), PyGeoVision can search and download satellite data from 22+ providers. This is entirely optional — all AI APIs work with local GeoTIFF files without any satellite credentials.
get_model("segformer-b2") + TiledInference work immediately. PyGeoFetch is only needed for automated imagery acquisition.# Add credentials (10 providers are free — no credentials needed) client.add_credentials("usgs", username="user", password="pass") client.add_credentials("planet", api_key="PL-xxxx") client.add_credentials("copernicus", client_id="id", client_secret="secret") # Search (free: planetary_computer, aws_earth, element84, esa_scihub, jaxa_earth …) results = client.search( bbox = (-0.15, 51.47, -0.10, 51.52), date_range = ("2024-06-01", "2024-06-30"), providers = ["planetary_computer"], cloud_cover_max = 10, sort_by = "cloud_cover", ) # Download with post-processing downloads = client.download(results[:2], output_dir = "./data/", parallel = 4, post_process = ["reproject:EPSG:32618", "cog"], bands = ["B02","B03","B04","B08","B11","B12"], ) # YAML pipeline (recurring workflow) p = client.create_pipeline("weekly_s2") p.search(bbox=..., providers=["planetary_computer"], date_range="last_7_days") p.download(post_process=["cog"], parallel=4) p.schedule(cron="0 3 * * 1") p.save("weekly.yaml") p.run(dry_run=True)
22 Satellite Data Providers
Available when PyGeoFetch is installed. 10 providers work with no credentials at all.
Model Registry — 119 Architectures
PyGeoVision's own model registry — load any of 119 architectures by name. Pretrained weights auto-downloaded from HuggingFace Hub. No GeoAI required.
from pygeovision.models import get_model, list_models from pygeovision.models.registry import ModelRegistry # List by task list_models(task="segmentation") # 24 architectures list_models(task="detection") # 18 architectures list_models(task="change_detection") # 12 architectures list_models(task="foundation") # 12 architectures (DINOv3 + Prithvi) list_models(task="vlm") # 9 architectures (CLIP, Moondream) # Load by name (pretrained weights downloaded automatically) model = get_model("segformer-b2", num_classes=5, in_channels=6, pretrained=True) model = get_model("changeformer", num_classes=4, in_channels=4) model = get_model("geoyolo-v8", num_classes=10, pretrained=True) model = get_model("prithvi_eo_2_0") model = get_model("dinov3_vitl16_sat") # Registry API registry = ModelRegistry() registry.list(task="segmentation", pretrained_only=True) registry.info("prithvi_eo_2_0") # params, tasks, input format
| Family | Count | Key Architectures |
|---|---|---|
| Segmentation | 24 | U-Net variants, SegFormer B0–B5, DeepLabV3+, PSPNet, Mask2Former, SAM, SAM2 |
| Detection | 18 | GeoYOLO v5/v8/v9/v10/v11, DETR, RT-DETR, RF-DETR, FCOS, RetinaNet, Faster R-CNN |
| Classification | 16 | ViT variants, Swin Transformer, EfficientNet B0–B7, ResNet, DenseNet, ConvNeXt |
| Change Detection | 12 | ChangeFormer, ChangeSTAR, BIT, DSAMNet, SNUNet, DTCDSCN, FC-EF, FC-Siam |
| Foundation | 12 | DINOv3 (6 ViT + 4 ConvNeXt, web + SAT), Prithvi-EO-1.0, Prithvi-EO-2.0 |
| VLM | 9 | CLIP ViT-B/32 & ViT-L/14, OpenCLIP, RemoteCLIP L/14, GeoRSCLIP, Moondream 2, LLaVA-Geo |
| 3D / Point Cloud | 8 | PointNet, PointNet++, RandLA-Net, KPConv, Point Transformer, PointMamba |
| Other | 20 | ESRGAN (SR), CHMv2 (canopy height), BioMassNet, SAR despeckling |
Dataset Registry — 503 Datasets
from pygeovision.datasets import DatasetRegistry, DatasetLoader
registry = DatasetRegistry()
registry.list(task="segmentation", sensor="sentinel2")
registry.list(task="change_detection")
registry.info("spacenet_buildings")
registry.download("deepglobe_roads", output_dir="./datasets/")
loader = DatasetLoader(registry)
train_ds = loader.load("spacenet_buildings", split="train", chip_size=512)
# 503 datasets covering:
# Buildings · Roads · Land cover · Change detection · Crops · Floods
# Wildfire · SAR · VHR · Hyperspectral · Point cloud · Time series
# SpaceNet 1–8, DOTA v1/v2, iSAID, DIOR, DeepGlobe, BigEarthNet,
# FloodNet, xBD, BreizhCrops, SEN12MS, MillionAID, RS5M, and 450+ more
Foundation Models — Own Stack (No GeoAI)
DINOv3 and Prithvi-EO-2.0 are integrated directly into PyGeoVision's codebase. Weights auto-downloaded from HuggingFace Hub on first use. GeoAI not required.
DINOv3 — 12 Variants
get_transform(model_name) — it auto-selects the correct normalisation stats. Using ImageNet stats with a SAT-pre-trained model silently costs 10–20 mIoU points.from pygeovision.models.foundation.dinov3 import (
DINOv3Backbone, get_transform, finetune_dinov3, CHMv2Model,
WEB_MEAN, WEB_STD, # ImageNet — for LVD-1689M web pre-trained
SAT_MEAN, SAT_STD, # Satellite — for SAT-493M pre-trained ← DIFFERENT
)
# get_transform() auto-selects correct stats for the model name
transform = get_transform("dinov3_vitl16_sat") # satellite stats
transform = get_transform("dinov3_vitl16") # ImageNet stats
backbone = DINOv3Backbone("dinov3_vitl16_sat") # 300M, 1024-dim, SAT-493M
# Feature extraction
embeddings = backbone.extract_embeddings("scene.tif") # (1, 1024) — global CLS
features = backbone.extract_features("scene.tif") # (H_p, W_p, 1024) — spatial
attention = backbone.get_attention_maps("scene.tif") # saliency map
# Canopy height — DINOv3 CHMv2 (1m global, GEDI calibrated)
chm = CHMv2Model()
result = chm.predict_canopy_height("sentinel2.tif") # mean_m, max_m, coverage_pct
biomass= chm.estimate_biomass("sentinel2.tif") # t DM/ha
# Fine-tuning (task: "segmentation" | "classification")
result = finetune_dinov3(
model_name="dinov3_vitl16_sat", dataset=my_dataset,
task="segmentation", num_classes=7, epochs=50,
learning_rate=1e-5, # low LR for SAT pre-trained
mixed_precision=True, # BF16 — critical for ViT-L
)
| Model Name | Params | Pre-training | Embed dim | Recommended for |
|---|---|---|---|---|
dinov3_vits16 | 21M | Web LVD-1689M | 384 | Fast inference |
dinov3_vitb16 | 86M | Web LVD-1689M | 768 | Balanced |
dinov3_vitl16 | 300M | Web LVD-1689M | 1024 | High accuracy (web images) |
dinov3_vitl16_sat | 300M | SAT-493M | 1024 | Satellite imagery ★ Recommended |
dinov3_vit7b16_sat | 6.7B | SAT-493M | 4096 | State-of-the-art ★ |
dinov3_convnext_base | 89M | Web | 1024 | Convolutional features |
| + 6 more variants (ViT-S+, ViT-7B web, ConvNeXt tiny/small/large) | ||||
Prithvi-EO-2.0 — 600M Parameters
map_bands(data, source="sentinel2") first.from pygeovision.models.foundation.prithvi import (
Prithvi, PrithviTasks, PrithviMultiTemporal,
map_bands, normalise_hls, finetune_prithvi,
)
# HLS band order: Blue(B02) Green(B03) Red(B04) NIR(B08) SWIR1(B11) SWIR2(B12)
data_hls = map_bands(data, source="sentinel2") # remaps S2 → HLS order
data_norm = normalise_hls(data_hls) # divides by HLS_SCALE_FACTOR=10000.0
# Task predictions (all auto-apply map_bands + normalise internally)
tasks = PrithviTasks("prithvi_eo_2_0")
land_cover = tasks.land_cover("sentinel2.tif", source="sentinel2") # 9 classes
crops = tasks.crop_mapping("sentinel2.tif", source="sentinel2") # 10 crops
flood = tasks.flood_detection("sentinel2.tif", source="sentinel2") # binary
defor = tasks.deforestation_detection("sentinel2.tif", source="sentinel2")
# Multi-temporal (4 frames simultaneously — key strength of Prithvi)
mt = PrithviMultiTemporal("prithvi_eo_2_0")
mt.process_time_series(images, dates=dates, source="sentinel2")
# Fine-tuning
result = finetune_prithvi(
model_name="prithvi_eo_2_0", task="land_cover", num_classes=9,
epochs=50, learning_rate=5e-5, batch_size=8, # memory-limited for 600M
mixed_precision=True,
)
Auto-Labeling — 7 Sources, Zero Manual Work
ms = client.labeling.microsoft_buildings(bbox, output_path="labels.tif") osm = client.labeling.osm(bbox, categories=["buildings","roads"]) esa = client.labeling.esa_worldcover(bbox) sam = client.labeling.sam_auto(scene_path, points_per_side=32) # Quality assessment report = client.labeling.quality("labels.tif") print(report["quality_grade"], report["quality_score"]) # 'A', 0.92 # Multi-source weighted fusion fused = client.labeling.pipeline(bbox=bbox, sources=[ {"type":"microsoft_buildings","weight":1.5}, {"type":"osm", "weight":1.0}, {"type":"sam", "weight":0.8}, ], fusion="weighted_vote", output_path="labels_fused.tif")
GeoTrainer — Production Training Pipeline
from pygeovision.models import get_model
from pygeovision.training.trainer import GeoTrainer
from pygeovision.training.callbacks import EarlyStopping, ModelCheckpoint
from pygeovision.losses.segmentation import GeospatialMixedLoss
from pygeovision.training.data import GeoSegDataset
from torch.utils.data import DataLoader
model = get_model("segformer-b2", num_classes=5, in_channels=6, pretrained=True)
loss = GeospatialMixedLoss(weights={"combo":0.40,"boundary":0.40,"ohem":0.20})
trainer = GeoTrainer(
model = model,
task = "segmentation",
num_classes = 5,
epochs = 100,
learning_rate = 6e-5, # low LR for transformer fine-tuning
weight_decay = 0.01,
mixed_precision = "bf16", # BF16 recommended for A100/H100
loss_fn = loss,
callbacks = [
EarlyStopping(monitor="val_iou", patience=15, mode="max"),
ModelCheckpoint("./checkpoints/", monitor="val_iou", save_top_k=3),
],
)
train_dl = DataLoader(GeoSegDataset("./chips/train/","./labels/train/"), batch_size=8)
val_dl = DataLoader(GeoSegDataset("./chips/val/", "./labels/val/"), batch_size=8)
history = trainer.fit(train_dl, val_dl)
print(f"Best val_iou: {history['best_metrics']['val_iou']:.4f}")
Losses: DiceLoss · FocalLoss · TverskyLoss · GeospatialMixedLoss (Dice+Boundary+OHEM) · ChangeDetectionLoss · BoundaryAwareLoss
Optimisers: AdamW · SGD · Lion | Schedulers: CosineAnnealing · OneCycleLR · WarmupCosine | Precision: FP32 · FP16 · BF16
Tiled Inference — No Seam Artefacts
from pygeovision.inference.tiled import TiledInference, EnsembleInference # Single model — any size GeoTIFF, Gaussian blending inf = TiledInference(model=model, chip_size=512, overlap=64, blend_mode="gaussian", num_classes=5, device="cuda") result = inf.infer("large_scene.tif", "prediction.tif") # → {n_chips: 48, duration_seconds: 1.1, chips_per_second: 44.7} # Ensemble (mean of multiple models) ensemble = EnsembleInference(models=[model_a, model_b, model_c], mode="mean") ensemble.infer("scene.tif", "ensemble_pred.tif")
Vision-Language Models — Own Stack
from pygeovision.advanced.vlm.clip_geo import CLIPGeo from pygeovision.advanced.vlm.moondream_geo import MoondreamGeo # ── RemoteCLIP (RS5M — 5M remote sensing image-text pairs) ─────────────── clip = CLIPGeo(model_name="remoteclip-l14") # Zero-shot classification (no fine-tuning needed) probs = clip.classify("scene.tif", [ "dense urban area", "tropical rainforest", "agricultural cropland", "flooded wetland", ]) # Build FAISS index over large satellite archive (one-time) clip.build_index("./archive/", "geo_index.faiss") # Text-to-image retrieval results = clip.search("flooded agricultural fields near river", top_k=10) similar = clip.search_by_image("query.tif", top_k=5) # ── Moondream 2 (1.87B VLM) ────────────────────────────────────────────── moon = MoondreamGeo() caption = moon.caption("scene.tif") answer = moon.vqa("scene.tif", "How many buildings are visible?") change = moon.describe_change("before.tif", "after.tif")
Advanced AI Features
FewShotLearner(backbone="dinov2-large")AutoML(n_trials=50)GeoTimeSeries(sensor="sentinel2")GeoGradCAM(model).generate(scene)get_model("pointnet2")from pygeovision.advanced.few_shot import FewShotLearner from pygeovision.advanced.automl import AutoML from pygeovision.advanced.timeseries import GeoTimeSeries # Few-Shot learner = FewShotLearner(backbone="dinov2-large", method="prototypical") learner.fit_support({"solar_panel":["img1.tif","img2.tif","img3.tif","img4.tif","img5.tif"]}) result = learner.predict("new_scene.tif") # {"class":"solar_panel","confidence":0.91} # AutoML automl = AutoML(model_family="segformer", task="segmentation", num_classes=5, n_trials=50, timeout_hours=4.0) best = automl.optimise(train_dl, val_dl) print(f"Best val_iou: {best['val_iou']:.4f} params: {best['params']}") # Time series ts = GeoTimeSeries(sensor="sentinel2") trend = ts.compute_trend(series) # direction, slope, R², p-value anom = ts.detect_anomalies(series, threshold=2.0) decomp = ts.decompose(series, period=12) # trend + seasonal + residual
Production Monitoring
from pygeovision.monitoring.drift import DriftDetector from pygeovision.monitoring.tracker import ModelPerformanceTracker from pygeovision.monitoring.alerts import AlertManager # Drift detection — PSI (Population Stability Index) detector = DriftDetector(method="psi", threshold_warn=0.1, threshold_critical=0.2) detector.fit(reference_images) report = detector.check(new_images) # PSI < 0.10: no drift | 0.10–0.20: warning | > 0.20: retrain # Performance tracking tracker = ModelPerformanceTracker(metrics=["val_iou","val_f1","throughput_fps"]) tracker.log(epoch=50, metrics={"val_iou":0.843,"val_f1":0.887,"throughput_fps":118}) trend = tracker.trend("val_iou") # direction, slope # Alerts — Slack / email / webhook alerts = AlertManager(channels={"slack":{"webhook_url":"https://..."}}) alerts.add_rule("iou_drop", "val_iou", "less_than", 0.78, "critical") alerts.add_rule("drift", "psi_score", "greater_than", 0.10, "warning") alerts.add_rule("throughput","fps", "less_than", 80, "warning") alerts.check({"val_iou":0.72}) # fires critical alert
10 End-to-End Pipelines
One call from bounding box to finished GeoJSON/GeoTIFF. PyGeoFetch handles data acquisition; PyGeoVision's own model stack handles inference.
# All 10 pipelines share the same interface result = client.pipeline("building_footprints", bbox=(-0.15,51.47,-0.10,51.52), date="2024-06") result.output_path # Path('./results/building_footprints/prediction.tif') result.stats # {"buildings_detected":1847, "coverage_pct":0.312} result = client.pipeline("change_detection", bbox=..., date_before="2020-01", date_after="2024-01") result = client.pipeline("carbon_estimation", bbox=(-55,-4,-54,-3), date="2024-07") # Amazon carbon stock (t CO2e/ha) # YAML pipeline (scheduled, recurring) p = client.create_pipeline("weekly_buildings") p.search(bbox=..., providers=["planetary_computer"], date_range="last_7_days") p.download(post_process=["reproject:EPSG:32618","cog"], parallel=4) p.ai_step("segment_buildings", model="segformer-b2", num_classes=2) p.export(format="geojson", output_dir="./results/") p.schedule(cron="0 3 * * 1") p.save("weekly_buildings.yaml") p.run(dry_run=True)
REST API Serving — FastAPI + WebSocket
from pygeovision.serving import InferenceServer
server = InferenceServer(
auth_keys = {"prod":"SECRET_KEY", "dev":"DEV_KEY"},
max_workers = 4,
enable_cors = True,
)
server.register("seg_v1", "model.onnx", task="segmentation", num_classes=5)
server.register("chg_v1", "change.onnx", task="change_detection")
server.register("det_v1", "detector.onnx", task="detection")
server.serve(host="0.0.0.0", port=8080)
# CLI equivalent
# pygeovision serve start --model model.onnx --port 8080 --auth-key SECRET
| Endpoint | Method | Description |
|---|---|---|
/predict | POST | Single-scene inference — multipart GeoTIFF upload, returns prediction GeoTIFF |
/predict/batch | POST | Batch inference — multiple scenes in one request |
/ws/stream | WS | WebSocket streaming for live ingestion and real-time tile-by-tile results |
/health | GET | Health check — GPU status, model registry, queue depth |
/models | GET | List registered models with metadata |
/metrics | GET | Prometheus-compatible — latency, throughput, queue depth |
Edge and Cloud Deployment
from pygeovision.edge.onnx_rt import ONNXRuntimeInference from pygeovision.edge.jetson import JetsonDeployer from pygeovision.cloud.deploy import AWSDeployer, AzureDeployer, GCPDeployer # Export + run ONNX ONNXRuntimeInference.from_pytorch(model, "model.onnx") eng = ONNXRuntimeInference("model.onnx", device="cuda") eng.infer_geotiff("scene.tif", "prediction.tif") # Jetson Orin TensorRT FP16 JetsonDeployer(device_type="orin").convert("model.onnx","model.trt",precision="fp16") # AWS SageMaker AWSDeployer(region="us-east-1").deploy( "model.onnx","buildings-prod",instance_type="ml.g4dn.xlarge") # Azure ML AzureDeployer(subscription_id="...",resource_group="rg").deploy( "model.onnx","buildings-ep",vm_size="Standard_NC6s_v3") # GCP Vertex AI GCPDeployer(project_id="my-project").deploy( "model.onnx","buildings-ep", machine_type="n1-standard-8",accelerator_type="NVIDIA_TESLA_T4")
GeoAI Plugin — Optional Enhancement
GeoAI is no longer a dependency of PyGeoVision v2.0. It is an optional plugin that adds additional subsystems when installed. PyGeoVision's own stack covers the same tasks natively.
# Install the optional GeoAI plugin # pip install "pygeovision[geoai]" or pip install geoai-py ga = client.geoai # lazy-loads geoai-py only on first attribute access ga.is_available # True / False ga.version # '0.39.x' # ── What GeoAI adds beyond PyGeoVision's own stack ───────────────────── # Tessera pre-computed satellite embeddings (large-scale) ga.tessera.available_years(bbox=(-74.1,40.6,-73.7,40.9)) ga.tessera.download(bbox=..., output_dir="./tessera/") # GroundedSAM — DINO + SAM for natural language object detection ga.detect.grounded("aerial.tif", "swimming pools in backyards") ga.detect.grounded("aerial.tif", "solar panels on rooftops") # Leafmap interactive visualisation (Jupyter) m = ga.map.leafmap() ga.map.view_raster("prediction.tif") ga.map.view_vector("buildings.geojson") # Moondream sliding-window caption over large scene results = ga.caption.sliding_window("large_scene.tif", prompt="Describe the dominant land use.", tile_size=512) # ── PyGeoVision own equivalents (no GeoAI needed) ──────────────────── # Buildings → get_model("segformer-b2") + TiledInference # Change det → get_model("changeformer") # DINOv3 → DINOv3Backbone("dinov3_vitl16_sat") # Prithvi → PrithviTasks("prithvi_eo_2_0") # CLIP → CLIPGeo("remoteclip-l14") # Moondream → MoondreamGeo()
GeoAI Plugin — Segmentation Extras
# GeoAI plugin segmentation extras (requires pip install "pygeovision[geoai]") ga.segment.buildings("s2.tif", output_vector="buildings.geojson") # BuildingFootprintExtractor ga.segment.solar_panels("aerial.tif", output_vector="solar.geojson") ga.segment.agriculture_fields("s2.tif", output_vector="fields.geojson") ga.segment.water("s2.tif", band_order="sentinel2") ga.segment.with_sam("aerial.tif", output_path="masks.tif") ga.segment.from_hub("scene.tif", "giswqs/building-footprint-usa") # HF Hub
GeoAI Plugin — Detection Extras
ga.detect.cars("aerial.tif", output_path="cars.geojson")
ga.detect.ships("port.tif", output_path="ships.geojson")
ga.detect.parking("lot.tif", output_path="spots.geojson")
ga.detect.grounded("aerial.tif","swimming pools",output_path="pools.geojson") # GroundedSAM
ga.detect.rfdetr("scene.tif", output_path="det.geojson")
ga.detect.multiclass("scene.tif","nwpu_model.pth",output_path="det.geojson")
GeoAI Plugin — Embeddings & Utilities
# Tessera pre-computed embeddings embeddings = ga.embed.patch("sentinel2.tif", chip_size=64) # (N, 512) ga.embed.cluster(embeddings, n_clusters=10) score = ga.embed.similarity(emb_a, emb_b) # 0.85 ga.embed.visualize(embeddings, method="umap") # Cloud masking ga.cloud.predict("sentinel2.tif", output_path="cloud.tif") stats = ga.cloud.statistics("cloud.tif") # {"cloud_cover": 0.08} # Super-resolution (ESRGAN ×4) ga.sr.enhance("landsat.tif", output_path="enhanced.tif", scale_factor=4) # Utilities ga.utils.raster_to_vector("pred.tif","polygons.geojson") ga.utils.smooth_vector("buildings.geojson","smooth.geojson") metrics = ga.utils.segmentation_metrics(pred, target) # mIoU, F1, accuracy ga.utils.get_device() # 'cuda' | 'mps' | 'cpu'
25 Production Notebooks — 357 Cells
Every notebook solves a real-world geospatial problem end-to-end. All 25 run without GPU in demo mode, and without satellite credentials (synthetic data substituted gracefully).
pip install "pygeovision[all]"
cd projects/
jupyter notebook # opens browser with all 25 notebooks
CLI Reference — 15 Command Groups
| Group | Key Subcommands | Description |
|---|---|---|
status / doctor | — | System status dashboard + installation diagnostics |
models | list, info, download, cache | Own 119-model registry management |
datasets | list, info, download | Own 503-dataset registry management |
ai infer | — | Tiled inference on large GeoTIFFs (own stack) |
ai segment | buildings, water, roads, custom | Segmentation — own models |
ai change | detect, list-models | Change detection — ChangeFormer / ChangeSTAR |
ai train | segmentation, detection, classification, chips | GeoTrainer — own training pipeline |
ai foundation | dinov3, prithvi, clip, moondream | Foundation model inference (own stack) |
ai label | ms-buildings, osm, worldcover, sam | Auto-labeling — 7 sources |
pipeline | building_footprints … (all 10) | End-to-end data + AI pipelines |
serve | start, stop, status, register | FastAPI inference server management |
data auth | add, list, test, remove | PyGeoFetch credentials (optional) |
data search / download | — | Satellite data acquisition (optional) |
data pipeline | run, validate, schedule, list, logs | YAML pipeline orchestration (optional) |
config | show, get, set, path, reset | Configuration management |
# System pygeovision status pygeovision doctor # Own model registry (119 architectures) pygeovision models list pygeovision models list --task foundation pygeovision models list --task segmentation --pretrained-only pygeovision models info prithvi_eo_2_0 pygeovision models info dinov3_vitl16_sat # Own inference stack (no satellite credentials needed) pygeovision ai infer \ --input large_scene.tif --model segformer-b2 \ --output prediction.tif --num-classes 5 \ --tile-size 512 --overlap 64 --precision bf16 # Foundation models (own stack) pygeovision ai foundation dinov3 \ --input scene.tif --model dinov3_vitl16_sat \ --output embeddings.npy pygeovision ai foundation prithvi \ --input sentinel2.tif --task land_cover --output lc.tif # Auto-labeling pygeovision ai label ms-buildings \ --bbox "-0.15,51.47,-0.10,51.52" --output labels.tif # Training pygeovision ai train segmentation \ --data ./chips/ --output model.pth \ --model segformer-b2 --num-classes 5 \ --epochs 100 --precision bf16 # Serving pygeovision serve start \ --model model.onnx --port 8080 --auth-key SECRET pygeovision serve status pygeovision serve stop # E2E pipelines pygeovision pipeline building_footprints \ --bbox "-0.15,51.47,-0.10,51.52" \ --date 2024-06 --output ./results/ pygeovision pipeline change_detection \ --bbox "-74.1,40.6,-73.7,40.9" \ --date-before 2020-01 --date-after 2024-01 # Optional: PyGeoFetch satellite data pygeovision data search \ --bbox "-74.1,40.6,-73.7,40.9" \ --date 2024-06 --providers planetary_computer \ --cloud-max 10 --output results.geojson pygeovision data download \ --from-search results.geojson \ --output ./data/ --parallel 4 \ --post-process reproject:EPSG:32618,cog
Error Handling
models list for all valid names.get_transform() auto-selects correct normalisation.client.search() without PyGeoFetch. Or pass local GeoTIFFs directly to AI APIs instead.client.geoai.* without the GeoAI plugin. Or use PyGeoVision's native equivalents.Security
- Credentials never written to disk in plain text
- System keyring: macOS Keychain, Windows Credential Manager, Linux Secret Service
- All logs redact passwords, tokens, and API keys
- Encrypted file fallback using Fernet AES-128-CBC
- TLS 1.2+ enforced on all provider connections
- SSL certificate verification always on
- Connection timeouts per provider
- No telemetry — PyGeoVision does not phone home
- SHA256 checksum verification on downloads
- Atomic file writes — partial downloads never corrupt data
- Temp files cleaned on failure
- ONNX model hash verification on load
- JWT Bearer token authentication on all endpoints
- Rate limiting — configurable per API key
- No user data stored on inference server
- CORS configurable, disabled by default
PYTHON_KEYRING_BACKEND=keyring.backends.null.Keyring and provide all credentials via environment variables.Docker
version: '3.8'
services:
pygeovision:
image: pygeovision/pygeovision:2.0
volumes:
- ~/.pygeovision:/root/.pygeovision
- ./pipelines:/pipelines
- ./data:/data
command: pygeovision serve start --model /data/model.onnx --port 8080
ports:
- "8080:8080"
restart: unless-stopped
environment:
- PYGEOVISION_GPU_DEVICE=cuda
- PYTHON_KEYRING_BACKEND=keyring.backends.null.Keyring
- pygeofetch_PLANET_API_KEY=${PLANET_API_KEY}
- pygeofetch_COPERNICUS_USERNAME=${COPERNICUS_USER}
- pygeofetch_COPERNICUS_PASSWORD=${COPERNICUS_PASS}
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
Testing — 580 Passing
tests/ 580 passing | 2 skipped | 0 failing ├── test_core.py Core config, exceptions, engine init ├── test_data_layer.py SatelliteFetcher, SearchResult, 22 providers ├── test_geoai_integration.py GeoAI plugin subsystems (mocked, optional) ├── test_foundation_models.py DINOv3 + Prithvi (own stack, mocked weights) ├── test_dinov3.py DINOv3 backbone, transforms, CHMv2 ├── test_prithvi.py Prithvi tasks, band mapping, multi-temporal ├── test_edge_cloud.py ONNX, Jetson, AWS, Azure, GCP ├── test_advanced.py Few-shot, AutoML, VLM, timeseries ├── test_monitoring.py Drift, tracker, alerts ├── test_serving.py FastAPI endpoints, WebSocket, JWT auth ├── test_training.py GeoTrainer, losses, metrics, callbacks ├── test_inference.py TiledInference, ensemble, postprocessing ├── test_labeling.py All 7 labelers + quality + fusion ├── test_models.py Model registry, loader, 119 architectures ├── test_datasets.py Dataset registry, loader, 503 datasets ├── test_pipelines.py All 10 end-to-end pipelines ├── test_explainability.py GradCAM, attention maps, uncertainty ├── test_cli.py All 15 CLI command groups ├── test_pointcloud.py PointNet++, RandLA-Net, KPConv └── conftest.py Shared fixtures, mock providers
pip install -e ".[dev]" pytest tests/ -q # all 580 pytest tests/test_foundation_models.py -v # own foundation stack pytest tests/test_models.py -v # 119-model registry pytest tests/test_geoai_integration.py -v # optional GeoAI plugin pytest tests/ --cov=pygeovision --cov-report=html # coverage report
PyGeoVision v2.0 vs Alternatives
| Feature | PyGeoVision v2 | EODAG | TorchGeo | TerraTorch | GeoAI | PyGeoFetch |
|---|---|---|---|---|---|---|
| Standalone (no AI dependency) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Own model registry | 119 | — | ~30 | ~50 | — | — |
| DINOv3 (12 variants, SAT) | ✓ Own | — | Partial | Partial | Partial | — |
| Prithvi-EO-2.0 (600M) | ✓ Own | — | Partial | Partial | Partial | — |
| Satellite data providers | 22+ (opt) | 10+ | — | — | 3 | 22+ |
| Production training (GeoTrainer) | ✓ | — | Partial | ✓ | Partial | — |
| Auto-labeling (7 sources) | ✓ | — | — | — | Partial | — |
| FastAPI serving + WebSocket | ✓ | — | — | — | — | — |
| Edge deployment (ONNX + Jetson) | ✓ | — | — | — | Partial | — |
| Cloud (AWS + Azure + GCP) | ✓ | — | — | — | — | — |
| VLM (CLIP + Moondream) | ✓ Own | — | — | — | Moondream | — |
| Few-shot + AutoML | ✓ | — | — | AutoML | — | — |
| Drift monitoring + alerts | ✓ | — | — | — | — | — |
| Production notebooks | 25 | — | — | — | — | — |
| Tests passing | 580 | ~200 | ~300 | ~100 | ~150 | ~200 |
| Full CLI (15 groups) | ✓ | Partial | — | — | — | ✓ |
Roadmap
- Own 119-model registry
- DINOv3 (12 variants, SAT-493M pre-training)
- Prithvi-EO-2.0 (600M, HLS global 10yr)
- CLIP + RemoteCLIP + Moondream 2
- 503 dataset registry
- GeoTrainer + GeospatialMixedLoss
- FastAPI serving + WebSocket
- ONNX + Jetson + AWS/Azure/GCP
- Few-shot, AutoML, Timeseries
- Drift monitoring + alert system
- 25 production notebooks (357 cells)
- 580 tests passing
- GeoAI demoted to optional plugin
- SAM 2 (Video SAM) integration
- SigLIP vision encoder
- LLaVA-Geo VQA model
- BlackSky + KOMPSAT providers
- Streaming COG partial reads
- Distributed inference workers
- MLflow experiment tracking
- GeoParquet for all pipelines
- Active learning loop
- Web monitoring dashboard
- Model versioning + A/B testing
- Hyperspectral (DESIS, EMIT) support
- Video satellite pipeline
- GeoAI v2 plugin compatibility
- Federated learning
- Multi-modal fusion (SAR + Optical)