Skip to main content

Ultra-fast geospatial windowing with zero-copy memory mapping

Project description

GeoSlice

Ultra-fast geospatial windowing with zero-copy memory mapping.

CI PyPI Python

Performance

Head-to-Head: GeoSlice vs Rasterio

============================================================
COMPARISON: 100 x 512x512 windows (4096x4096 4-band image)
============================================================
Method               Time (s)     Ops/s        Speedup
------------------------------------------------------------
GeoSlice (mmap)      0.0003       305,737      154.6x
Rasterio             0.0506       1,977        1.0x
============================================================

Detailed Benchmarks

Test GeoSlice Rasterio Speedup
Single 512x512 window 1.4us (690k ops/s) 170us (5.9k ops/s) 117x
100 sequential windows 129us (7.7k ops/s) 16.6ms (60 ops/s) 128x
100 random windows 126us (8.0k ops/s) 30.4ms (33 ops/s) 241x
50-waypoint flight sim 24us (41k ops/s) 1.4ms (707 ops/s) 59x

Coordinate Transform Performance

Operation Time Throughput
latlon->pixel (x1000) 2.0ms 494 ops/s
FOV->pixels (x1000) 203us 4,937 ops/s

Install

pip install geoslice

For converting GeoTIFFs:

pip install geoslice[convert]
sudo apt install gdal-bin  # Linux

Supported Python: 3.8+ Supported OS: Linux, macOS

Quick Start

1. Convert GeoTIFF (one-time)

from geoslice import convert_tif_to_raw

convert_tif_to_raw("input.tif", "output_map")
# Creates: output_map.bin, output_map.json

Or via CLI:

gdal_translate -of ENVI -co INTERLEAVE=BSQ input.tif output_map.bin

2. Access Windows

from geoslice import FastGeoMap

loader = FastGeoMap("output_map")

# Zero-copy window access (~690k ops/s)
window = loader.get_window(x=100, y=100, width=512, height=512)
print(window.shape)  # (bands, height, width)

# Bounds-checked — raises ValueError if out of range
if loader.is_valid_window(x, y, w, h):
    window = loader.get_window(x, y, w, h)

3. Drone Simulation

from geoslice import FastGeoMap, GeoTransform, FlightPath

loader = FastGeoMap("output_map")
geo = GeoTransform(loader.meta.transform, utm_zone=36)

# Generate spiral flight path
path = FlightPath.spiral(
    center_lat=31.45,
    center_lon=34.80,
    num_waypoints=50,
    altitudes=[50, 100, 150, 200],
)

# Extract windows along path (~41k waypoints/sec)
for state in path:
    win = FlightPath.state_to_window(state, geo)
    if win.is_valid(loader.width, loader.height):
        data = loader.get_window(win.x, win.y, win.width, win.height)
        # Process frame...

API

FastGeoMap

FastGeoMap(base_name: str, use_cpp: bool = None)
  • get_window(x, y, width, height) -> np.ndarray (view, zero-copy). Raises ValueError if out of bounds.
  • get_window_copy(x, y, width, height) -> np.ndarray (copy, safe for modification)
  • is_valid_window(x, y, width, height) -> bool
  • .width, .height, .bands, .shape, .meta

GeoTransform

GeoTransform(transform: tuple, utm_zone: int = 36)
  • latlon_to_pixel(lat, lon) -> (px, py). Validates lat in [-80, 84] (UTM range).
  • pixel_to_latlon(px, py) -> (lat, lon)
  • fov_to_pixels(altitude_m, fov_deg) -> (width, height)

FlightPath

FlightPath.spiral(center_lat, center_lon, num_waypoints, altitudes, fov_deg)
FlightPath.linear(start_lat, start_lon, end_lat, end_lon, num_waypoints, altitude_m)
FlightPath.grid(min_lat, min_lon, max_lat, max_lon, rows, cols, altitude_m)
  • state_to_window(state, geo) -> WindowParams
  • compute_windows(geo) -> List[WindowParams]

How It Works

Rasterio (standard approach):

Seek -> Read -> Decompress -> Allocate -> Copy to RAM

GeoSlice (mmap approach):

Pointer arithmetic -> OS pages in 4KB chunks on-demand

The OS kernel handles caching, prefetching, and memory management. Random access is 241x faster because there's no decompression overhead.

Data Format

GeoSlice operates on pre-converted raw binary files (BSQ interleave) with JSON metadata sidecars:

  • .bin — Raw raster data in Band Sequential format (no compression)
  • .json — Metadata: dtype, dimensions, affine transform, CRS

The conversion step (convert_tif_to_raw or gdal_translate) is a one-time cost that enables all subsequent reads to be zero-copy via mmap.

Input Validation

The library validates inputs at system boundaries:

  • JSON metadata is checked for required fields and valid values
  • Binary file size is verified against metadata dimensions
  • Window coordinates are bounds-checked before access
  • UTM latitude range is validated in coordinate transforms
  • Cache keys use collision-resistant hashing with coordinate verification

C++ Usage

#include <geoslice/geoslice.hpp>

geoslice::MMapReader reader("processed_map");
auto view = reader.get_window(100, 100, 512, 512);

// Zero-copy access
uint8_t pixel = view.at<uint8_t>(0, 0, 0);  // band, y, x

WindowCache

Thread-safe LRU cache with shared_ptr semantics — cached data stays valid even after eviction as long as you hold a reference:

geoslice::WindowCache cache(64 * 1024 * 1024); // 64MB

cache.put(x, y, w, h, data_ptr, size);

auto entry = cache.get(x, y, w, h); // shared_ptr<const CachedWindow>
if (entry) {
    // Safe to use entry->data even if cache evicts this slot later
    process(entry->data.data(), entry->data.size());
}

Development

Setup

git clone https://github.com/PavelGuzenfeld/geoslice
cd geoslice

# Create venv
python3 -m venv .venv
source .venv/bin/activate

# Install with dev dependencies
pip install -e ".[dev]"

Run Tests

# All tests
pytest -v

# Benchmarks with comparison table
pytest tests/test_benchmark.py -v -s

# Just the comparison report
pytest tests/test_benchmark.py::TestDirectComparison -v -s

# Detailed benchmark stats
pytest tests/test_benchmark.py --benchmark-only --benchmark-columns=min,max,mean,ops

Build C++ (optional)

cmake -B build -DBUILD_PYTHON=OFF
cmake --build build
ctest --test-dir build --output-on-failure

Release

Releases are automated via GitHub Actions on version tags:

# Update version in pyproject.toml, setup.py, geoslice.hpp, __init__.py
git add -A
git commit -m "Release v0.1.0"
git tag v0.1.0
git push && git push --tags

License

MIT License. See LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

geoslice-0.1.1.tar.gz (28.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

geoslice-0.1.1-py3-none-any.whl (11.3 kB view details)

Uploaded Python 3

File details

Details for the file geoslice-0.1.1.tar.gz.

File metadata

  • Download URL: geoslice-0.1.1.tar.gz
  • Upload date:
  • Size: 28.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for geoslice-0.1.1.tar.gz
Algorithm Hash digest
SHA256 a23a0d6a9adc9b121043650a50ee1243eb2e163f2d61f1f9dfd8e4bf0ee08973
MD5 8868fb787d510619368f1ecc586fa450
BLAKE2b-256 4fbdc945bbfcb4193c25a090f50a47ccf6aaae1a0201f1ccde3f99782fb8d825

See more details on using hashes here.

File details

Details for the file geoslice-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: geoslice-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 11.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for geoslice-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 af96b3fd79e8e15bb2a2e3cf49e32eb335577c17d16d44ff19848356a3174bc6
MD5 b9926acda9e4dfb7fb6bf7b3365411c7
BLAKE2b-256 70b3039da25fac29fb44e730107bb1d49a0d6398de06a84b3b0773cf8feff44a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page