Skip to main content

fundayao

A Python library for processing remote sensing imagery, developed for educational use in courses on the basic principles of remote sensing and its applications.

Data from different sensors is imported into a common, self-describing format (GeoTIFF + XML metadata), so that all processing steps work the same way regardless of the data source. The format supports both geocoded products (map geometry) and sensor-geometry products (image coordinates + RPC model) and is specified in docs/file-format.md. Guidance for AI coding agents working on this repository lives in AGENTS.md.

Features

  • Import: Sentinel-2 L1C (SAFE), SuperView Neo-1 L1B (PAN + MUX, with RPCs) and WH-1 / LJ-3 L1A (PAN + MSS, with RPCs) → fundayao products (one GeoTIFF per resolution group + XML metadata with geometry, calibration, angles, provenance)
  • Radiometry: DN → TOA reflectance/radiance, sun-elevation correction, DOS atmospheric correction (TOA → BOA) — each formula is an explicit, inspectable processing step recorded in the product provenance
  • Spectral indices: NDVI, NDWI, MNDWI, NDBI, NDMI, SAVI, EVI — bands are selected from the metadata by central wavelength, not hardcoded band names, so the same code works across sensors
  • Band math: custom index formulas over wavelength-addressed bands (e.g. "(nir - red) / (nir + red)")
  • AOI subsetting: windowed crops for geocoded products; sensor-geometry products get freshly re-estimated RPCs (via rpcfit) so the geometry model stays exact after cropping
  • Statistics: per-band statistics (min/max/mean/std/percentiles), raw or calibrated
  • Visualization: true-color and false-color (CIR) composites with percentile stretch, band/index maps with map coordinates, histograms, spectral profiles (reflectance vs wavelength at chosen points), band scatterplots (e.g. red–NIR)
  • Segmentation: SAM-based automatic segmentation via samgeo (segment-geospatial), producing an L3 index mask product with optional unique segment IDs or a binary foreground mask, and optional vector output
  • Unsupervised classification: classic k-means and ISODATA clustering (train on a pixel sample, classify the whole scene block-wise) producing an L3 product with uint8 class labels
  • Supervised classification: nearest neighbour (minimum distance), box (parallelepiped), maximum likelihood, spectral angle mapper (SAM) and random forest (scikit-learn, with per-band feature importances in the provenance), trained from vector labels (any geopandas-readable format, e.g. Shapefile, GeoPackage, GeoJSON) on the grid of a chosen band resolution (10 m or 20 m for Sentinel-2); produces an L3 product whose XML records the label → class-name mapping
  • Accuracy assessment: confusion matrix, overall/producer's/user's accuracy and Cohen's kappa of a supervised product against independent reference polygons (fundayao accuracy)
  • Provenance & metadata: every processing step is recorded in the product XML; the radiometric state (DN / TOA / BOA / index) is explicit and checked by every consumer

Installation

python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"

Requires Python ≥ 3.10. Main dependencies: rasterio, numpy, matplotlib, rpcfit, geopandas (supervised classification training labels), scikit-learn (random forest). The SAM segmentation feature is optional: install it with pip install -e ".[sam]" (requires segment-geospatial, which pulls in PyTorch and downloads a ~2 GB model checkpoint on first use).

Usage

Command line

# import sensor data
fundayao import-s2 S2C_MSIL1C_....SAFE products/
fundayao import-svn1 SVN1-01_..._01/ products/
fundayao import-wh1 /path/to/WH-1/ products/

# radiometric correction chain
fundayao toa products/S2C_T36RUU_20260815_L2 products/ --quantity reflectance
fundayao dos products/S2C_T36RUU_20260815_L2_TOA products/ --percentile 1

# indices and custom formulas
fundayao index ndvi products/S2C_T36RUU_20260815_L2 products/
fundayao band-math --name ndwi \
    --formula "(green - nir) / (green + nir)" \
    --band green=560 --band nir=842 \
    products/S2C_T36RUU_20260815_L2 products/

# subset an area of interest (map coords, or pixel coords for RPC products)
fundayao subset products/S2C_T36RUU_20260815_L2 products/ \
    --bbox 300000 3350000 320000 3370000
fundayao subset products/SVN101_20241203_MUX1_L1 products/ \
    --bbox 0 0 2000 2000 --coords pixel

# statistics and quicklooks
fundayao stats products/S2C_T36RUU_20260815_L2 --calibrated
fundayao quicklook products/S2C_T36RUU_20260815_L2 rgb.png
fundayao quicklook products/S2C_T36RUU_20260815_L2 cir.png --cir
fundayao quicklook products/S2C_T36RUU_20260815_L2_NDVI ndvi.png --band NDVI

# SAM segmentation (requires fundayao[sam])
fundayao segment-sam products/S2C_T36RUU_20260815_L2 products/
fundayao segment-sam products/S2C_T36RUU_20260815_L2 products/ --binary --scale 2
fundayao segment-sam products/S2C_T36RUU_20260815_L2 products/ \
    --model vit_l --device cuda --vector segments.geojson

# unsupervised classification
fundayao classify kmeans products/S2C_T36RUU_20260815_L2 products/ --clusters 6
fundayao classify isodata products/S2C_T36RUU_20260815_L2 products/ \
    --clusters 8 --max-clusters 16 --max-std 0.02 --min-distance 0.05

# supervised classification (training labels from a vector file)
fundayao classify nearest-neighbour products/S2C_T36RUU_20260815_L2 products/ \
    --labels training_polygons.shp --field label
fundayao classify box products/S2C_T36RUU_20260815_L2 products/ \
    --labels training_polygons.geojson --resolution 20 --box-std 2.0
fundayao classify max-likelihood products/S2C_T36RUU_20260815_L2 products/ \
    --labels training_polygons.gpkg --max-per-class 5000
fundayao classify sam products/S2C_T36RUU_20260815_L2 products/ \
    --labels training_polygons.shp
fundayao classify rf products/S2C_T36RUU_20260815_L2 products/ \
    --labels training_polygons.shp --trees 200 --depth 20

# accuracy assessment against independent reference polygons
fundayao accuracy products/S2C_T36RUU_20260815_L2_ML \
    --labels validation_polygons.shp

Python API

from fundayao.io import (
    import_sentinel2_l1c, import_superview_neo1, import_wh1)
from fundayao.radiometry import toa_reflectance, dos
from fundayao.indices import ndvi, mndwi, band_math
from fundayao.segment import sam_segment
from fundayao.classify import (kmeans, isodata, nearest_neighbour, box,
                               maximum_likelihood, spectral_angle_mapper,
                               random_forest, accuracy_assessment)
from fundayao.subset import subset
from fundayao.stats import band_statistics
from fundayao.visualize import (
    rgb_composite, plot_band, spectral_profile, band_scatter)

product = import_sentinel2_l1c("S2C_MSIL1C_....SAFE", "products")
boa = dos(toa_reflectance(product, "products"), "products")
ndvi_product = ndvi(boa, "products")

table = band_statistics(product, apply_calibration=True)
sam_mask = sam_segment(product, "products", unique=False, scale=2)
classes = kmeans(product, "products", n_clusters=6)
classes = isodata(product, "products", n_clusters=8, max_clusters=16)
# supervised: train on polygons from any geopandas-readable vector file
classes = nearest_neighbour(product, "products", "training_polygons.shp")
classes = box(product, "products", "training_polygons.shp", box_std=2.0)
classes = maximum_likelihood(product, "products", "training_polygons.shp",
                             resolution=20)
classes = spectral_angle_mapper(product, "products", "training_polygons.shp")
classes = random_forest(product, "products", "training_polygons.shp",
                        n_estimators=200)
# accuracy assessment against independent reference polygons
report = accuracy_assessment(classes, "validation_polygons.shp")
print(report["overall"], report["kappa"])
fig = rgb_composite(product, out_path="rgb.png")
fig = plot_band(ndvi_product, "NDVI", cmap="RdYlGn", out_path="ndvi.png")
fig = spectral_profile(product, [(305100.0, 3356200.0)], out_path="profile.png")
fig = band_scatter(product, 665, 842, out_path="red_nir.png")

# sensor-geometry data (SuperView Neo-1 / WH-1): pixel-coordinate subset, RPCs refit
svn_products = import_superview_neo1("SVN1-01_..._01/", "products")
sub = subset(svn_products[0], "products", (0, 0, 2000, 2000), coords="pixel")
wh1_products = import_wh1("/path/to/WH-1/", "products")
sub = subset(wh1_products[0], "products", (0, 0, 2000, 2000), coords="pixel")

Project layout

├── docs/file-format.md      # fundayao product format specification
├── src/fundayao/
│   ├── cli.py               # command line interface (thin wrapper)
│   ├── io/
│   │   ├── sentinel2.py     # Sentinel-2 L1C importer
│   │   ├── superview.py     # SuperView Neo-1 L1B importer
│   │   └── wh1.py           # WH-1 / LJ-3 L1A importer
│   ├── radiometry.py        # TOA / sun-elevation / DOS corrections
│   ├── indices.py           # spectral indices + band math
│   ├── subset.py            # AOI subsetting (+ RPC re-estimation)
│   ├── segment.py           # SAM segmentation via segment-geospatial
│   ├── classify.py          # classification: kmeans/isodata (unsupervised),
│   │                        # nearest_neighbour/box/maximum_likelihood/
│   │                        # spectral_angle_mapper/random_forest
│   │                        # (supervised) + accuracy_assessment
│   ├── stats.py             # per-band statistics
│   ├── visualize.py         # composites, maps, profiles, scatterplots
│   └── _rgb.py              # internal RGB GeoTIFF builder
└── tests/                   # pytest suite (synthetic fixtures + integration)

Testing

.venv/bin/python -m pytest

The unit tests run on small synthetic products. Additional integration tests run against real data when pointed at it via environment variables:

FUNDAO_S2_TEST_DATA=/path/to/S2 \
FUNDAO_SVN1_TEST_DATA=/path/to/SVN1 \
FUNDAO_WH1_TEST_DATA=/path/to/WH-1 \
FUNDAO_SEGMENT_SAM_TEST_DATA=/path/to/fundayao/product \
FUNDAO_S2_CLASSIFY_PRODUCT=/path/to/imported/fundayao/product \
FUNDAO_S2_CLASSIFY_LABELS=/path/to/labels.shp \
.venv/bin/python -m pytest

AI-generated code disclaimer

This repository was created by AI vibe-coding tools. The code, documentation, and other materials are provided without any warranty and may contain errors. No guarantee is made that the contents are free of third-party intellectual-property rights, including copyright. Use this software entirely at your own risk; verify its correctness and legal status for your jurisdiction before relying on it.

License

Unlicense (public domain dedication) — see LICENSE.

Metadata

Release files for fundayao 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fundayao 0.2.0
File Size Uploaded Provenance Actions
fundayao-0.2.0.tar.gz 103.0 kB Without provenance Details for fundayao-0.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for fundayao 0.2.0
File Interpreter ABI Platform Actions
fundayao-0.2.0-py3-none-any.whl Python 3 none any Details for fundayao-0.2.0-py3-none-any.whl

Total release size: 177.8 kB

Release files / fundayao-0.2.0.tar.gz

Download URL fundayao-0.2.0.tar.gz
Size 103.0 kB
Tags Source
SHA-256 checksum
How to use checksums
95516fef7c6b9566d307e4c2e09ca6d607494958ef7ce616ea010800772c8b12
BLAKE2b-256 checksum
How to use checksums
2f36fba59e08ff41827f39a4967b47310686797bab1c7e59b4f3f8a1f27e4906
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.13

Release files / fundayao-0.2.0-py3-none-any.whl

Download URL fundayao-0.2.0-py3-none-any.whl
Size 74.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5cc852d52c7fb486c15a908a9da9ec3dee12deb5d5ab541230772cfe8637a802
BLAKE2b-256 checksum
How to use checksums
0084b2dcea02b15f57ea30ab81bd6c8056135f13bbee1553ff66c02a2504b9f2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.13

Security for fundayao 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page