Local-first image processing, variational reconstruction, and geospatial raster analysis with inspectable numerical methods and reproducible synthetic scenes.
The project keeps the numerical core independent from cloud platforms and paid services while covering both classical image processing and remote-sensing workflows.
- ROF total-variation denoising with an explicit primal-dual solver
- masked TV reconstruction / inpainting with explicit fidelity masking
- FFT phase-correlation registration
- bounded local sub-pixel translation refinement
- RMSE and PSNR diagnostics
- reproducible numerical benchmarks
- normalized-difference indices such as NDVI
- two-date vegetation/change detection
- CRS/transform/nodata-preserving GeoTIFF I/O
- edge-safe raster tiling for large scenes
- SAR amplitude, intensity, wrapped phase, interferogram formation, and local coherence
- deterministic synthetic optical and complex-SAR scenes
src/geoimage_lab/
├── image/
│ ├── registration.py
│ └── variational.py
├── remote_sensing/
│ ├── change.py
│ ├── indices.py
│ ├── io.py
│ ├── sar.py
│ └── tiles.py
└── metrics.py
examples/
├── generate_demo.py
└── run_benchmarks.py
tests/
docs/
Build the image:
docker build -t geospatial-image-lab:latest .Run the fully synthetic demo. --network none is optional but demonstrates that runtime execution does not require network access:
docker run --rm --network none \
-v "$(pwd)/docs:/app/docs" \
geospatial-image-lab:latestThe demo generates its own synthetic optical and complex-SAR inputs inside the container and writes docs/demo_overview.png to the mounted local docs/ directory. No example GeoTIFF needs to be downloaded first.
Run the deterministic test suite:
docker run --rm --network none \
geospatial-image-lab:latest \
pytest -qRun the numerical benchmark and write the figure/report into docs/:
docker run --rm --network none \
-v "$(pwd)/docs:/app/docs" \
geospatial-image-lab:latest \
python examples/run_benchmarks.pyInspect the CLI:
docker run --rm --network none \
-v "$(pwd)/data:/app/data" \
-v "$(pwd)/outputs:/app/outputs" \
geospatial-image-lab:latest \
geoimage-lab --helpFor commands operating on real GeoTIFFs, place local files in data/ and mount both data/ and outputs/ as shown above. The paths in the examples below are placeholders for those local files; the repository does not ship third-party satellite imagery.
python -m venv .venv
source .venv/bin/activate
pip install -e '.[dev]'
pytest
python examples/generate_demo.py
python examples/run_benchmarks.pyNo remote API, cloud account, authentication token, telemetry service, or paid dataset is needed. Default runtime workflows operate only on local files and deterministic synthetic inputs. Building the environment can still download the public base image and Python packages from their normal package registries.
The masked reconstruction solver minimizes approximately
0.5 * || M (u - f) ||_2^2 + lambda * TV(u)
where M is one on observed pixels and zero on missing pixels. The discrete gradient, divergence, dual projection, and pointwise proximal update are implemented directly in image/variational.py so the numerical method remains inspectable.
Example using locally supplied GeoTIFFs:
docker run --rm --network none \
-v "$(pwd)/data:/app/data" \
-v "$(pwd)/outputs:/app/outputs" \
geospatial-image-lab:latest \
geoimage-lab inpaint \
--input data/image_with_gaps.tif \
--mask data/known_pixels.tif \
--weight 0.18 \
--iterations 400 \
--output outputs/reconstructed.tifTranslation is estimated from the normalized cross-power spectrum. Integer peak detection is available as a baseline, while --subpixel adds a bounded local refinement of normalized image correlation around the phase-correlation peak.
docker run --rm --network none \
-v "$(pwd)/data:/app/data" \
-v "$(pwd)/outputs:/app/outputs" \
geospatial-image-lab:latest \
geoimage-lab register \
--reference data/reference.tif \
--moving data/moving.tif \
--subpixel \
--output outputs/aligned.tifThis is intentionally a compact translation model rather than a full feature/affine registration framework.
Compute NDVI from separate files:
docker run --rm --network none \
-v "$(pwd)/data:/app/data" \
-v "$(pwd)/outputs:/app/outputs" \
geospatial-image-lab:latest \
geoimage-lab ndvi \
--nir data/nir.tif \
--red data/red.tif \
--output outputs/ndvi.tifOr select different bands from one multiband GeoTIFF:
docker run --rm --network none \
-v "$(pwd)/data:/app/data" \
-v "$(pwd)/outputs:/app/outputs" \
geospatial-image-lab:latest \
geoimage-lab ndvi \
--nir data/scene.tif --nir-band 2 \
--red data/scene.tif --red-band 1 \
--output outputs/ndvi.tifTwo-date change detection:
docker run --rm --network none \
-v "$(pwd)/outputs:/app/outputs" \
geospatial-image-lab:latest \
geoimage-lab change \
--before outputs/ndvi_before.tif \
--after outputs/ndvi_after.tif \
--threshold 0.12 \
--delta outputs/ndvi_delta.tif \
--mask outputs/change_mask.tifremote_sensing/sar.py contains dependency-light array kernels for complex SAR data:
from geoimage_lab.remote_sensing.sar import interferogram, local_coherence, wrapped_phase
ifg = interferogram(master_slc, slave_slc)
phase = wrapped_phase(ifg)
coh = local_coherence(master_slc, slave_slc, window=9)The coherence estimator uses local box expectations of the complex cross product and individual powers. It is a transparent baseline for numerical inspection and testing, not a substitute for mission-specific focusing, calibration, orbit correction, ionospheric correction, or full InSAR processing.
examples/run_benchmarks.py performs two deterministic studies:
- TV denoising across increasing Gaussian-noise levels.
- Integer vs sub-pixel translation estimation across several known synthetic shifts.
It writes a compact JSON report and docs/numerical_benchmarks.png. These are regression-style numerical checks, not claims of state-of-the-art performance.
The library operates on local GeoTIFF arrays and is provider-agnostic. Public Sentinel-2, Landsat, airborne, or derived rasters can be placed locally and processed without changing the numerical code.
Data acquisition is deliberately kept outside the default workflow so running the repository does not contact remote catalogues, create accounts, or incur service charges. For Sentinel-2, the usual local preparation is:
- download public Level-2A bands from a provider of your choice;
- resample chosen bands to a common grid if required;
- retain CRS/transform metadata in GeoTIFF;
- run the local CLI or Python kernels on those files.
For large scenes, remote_sensing.tiles.iter_windows provides edge-safe windows for block-wise processing.
- registration is translation-only; no rotation, affine, or non-rigid model
- sub-pixel refinement is a bounded local correlation optimization, not a full multiscale optimizer
- TV inpainting is a compact convex baseline and can oversmooth fine texture
- change detection is a transparent NDVI-difference baseline rather than a learned classifier
- SAR examples begin from complex arrays; raw focusing and mission-specific calibration are outside scope
- atmospheric correction and cloud detection are intentionally not duplicated here
See design notes for numerical assumptions and project boundaries.
MIT

