GPU-first raster processing for vibeSpatial. Custom NVRTC kernels and CCCL primitives for every operation — algebra, focal, zonal stats, labeling, rasterize, polygonize — with CPU fallbacks via scipy and rasterio.
Warning
vibeSpatial-Raster is very early in development. Operations may be unoptimized or have multiple Host/Device transfers causing reduced performance. File an issue if you hit a problem!
| Category | Operations | GPU Backend |
|---|---|---|
| IO | GeoTIFF, COG, JPEG2000 read/write | nvImageCodec (zero-copy decode to device) |
| Algebra | add, subtract, multiply, divide, apply, where, classify | CuPy element-wise |
| Focal | convolution, Gaussian filter, slope, aspect | NVRTC shared-memory stencil kernels |
| Zonal | count, sum, mean, min, max, std, median | CCCL segmented reduce |
| Rasterize | vector-to-raster (point-in-polygon) | NVRTC per-pixel PIP kernel |
| Label | connected components (4/8 connectivity) | NVRTC union-find |
| Morphology | erode, dilate, open, close, sieve | NVRTC tiled kernels |
| Polygonize | raster-to-vector (marching squares) | NVRTC classify + emit edges |
pip install vibespatial-raster # core (CPU-only, scipy fallback)
pip install vibespatial-raster[io] # + rasterio for GeoTIFF/COG
pip install vibespatial-raster[cu12] # + CUDA 12, CuPy, nvImageCodec
pip install vibespatial-raster[cu13] # + CUDA 13, CuPy, nvImageCodecFor development:
uv sync --group devfrom vibespatial.raster import read_raster, raster_slope, zonal_stats
# Read a GeoTIFF (GPU-native decode when available, rasterio fallback)
raster = read_raster("elevation.tif")
# Terrain analysis — NVRTC stencil kernels on GPU
slope = raster_slope(raster)
# Per-zone statistics — CCCL segmented reduce on GPU
stats = zonal_stats(zones, slope, ["mean", "max", "std"])from vibespatial.raster import label_connected_components, sieve_filter, polygonize_to_gdf
labels = label_connected_components(binary_raster, connectivity=8)
labels = sieve_filter(labels, min_size=50)
gdf = polygonize_to_gdf(labels)OwnedRasterArray tracks HOST/DEVICE residency. Move data to GPU once, then all operations stay on device:
from vibespatial.raster import from_numpy, raster_add
a = from_numpy(data_a, affine=affine, crs="EPSG:4326")
b = from_numpy(data_b, affine=affine, crs="EPSG:4326")
a.move_to("DEVICE")
b.move_to("DEVICE")
result = raster_add(a, b) # no host-device round-tripWhen nvImageCodec is available, read_raster() decodes GeoTIFF and JPEG2000 directly to GPU memory — no host copy, no rasterio:
raster = read_raster("large_image.tif") # → OwnedRasterArray(DEVICE)- Namespace package — installs as
vibespatial.rasterviapkgutil.extend_path, independent release cadence from core - Zero-copy NVRTC kernels — no cuCIM, no CuPy ndimage; all GPU ops are custom CCCL/NVRTC
- OwnedRasterArray — mirrors core's
OwnedGeometryArray(HOST/DEVICE residency, diagnostic events, nodata mask) - Dual IO — HYBRID path (rasterio on CPU) + GPU_NATIVE path (nvImageCodec direct-to-device)
- CPU fallback — scipy.ndimage, rasterio.features for every operation; tests validate GPU against CPU
uv run pytest # all CPU tests
uv run pytest -m gpu # GPU kernel tests (requires CUDA)
uv run pytest tests/test_raster_algebra.py # specific moduleApache 2.0 — see LICENSE.