Skip to main content

CUDA-accelerated raster algebra and reprojection library

Project description

cuRaster

Build and Publish Release PyPI - Version PyPI - Python Version

cuRaster is a high-performance Python library for GPU-accelerated raster processing. It reads GeoTIFF files (locally or directly from S3), executes band-math algebra on the GPU, and optionally reprojects, clips, and streams results — all through a clean, lazy pipeline API.


Table of Contents


Installation

pip install curaster

Wheels are pre-built for Linux and Windows, Python 3.9–3.13. A compatible NVIDIA GPU and driver must be present at runtime (the CUDA runtime is bundled in the wheel).


Requirements (building from source)

Requirement Notes
NVIDIA GPU CUDA Compute Capability ≥ 7.5 (Turing+)
CUDA Toolkit 12.5+ nvcc must be on PATH
GDAL 3.x libgdal-dev on Linux, gdal conda package on Windows
CMake 3.18+
OpenSSL + libcurl For direct S3 access
libzstd For ZSTD-compressed GeoTIFF tiles
pybind11 pip install pybind11
C++17 compiler GCC 11+, MSVC 2022+

Quick Start

import curaster

# Compute NDVI and save to a local GeoTIFF
curaster.open("landsat.tif") \
    .algebra("(B5 - B4) / (B5 + B4)") \
    .save_local("ndvi.tif")

API Reference

curaster.open(path)

Open a GeoTIFF and return a lazy Chain. No GPU work happens here.

chain = curaster.open("input.tif")
chain = curaster.open("s3://my-bucket/data/scene.tif")   # S3 direct-read
chain = curaster.open("/vsis3/my-bucket/data/scene.tif") # GDAL vsis3 URI
Parameter Type Description
path str Local file path or S3 URI (s3:// or /vsis3/)

Returns Chain


Chain.algebra(expression)

Append a band-math operation. Bands are referenced as B1, B2, … (1-indexed).

chain.algebra("(B5 - B4) / (B5 + B4)")      # NDVI
chain.algebra("B1 * 0.0001")                  # Scale factor
chain.algebra("(B3 + B2 + B1) / 3")          # Visible mean
chain.algebra("B4 > 0.3")                     # Boolean mask (1.0 or 0.0)
chain.algebra("(B4 > 0.2) * B4")             # Apply mask conditionally

Supported operators: + - * / > < >= <= == !=

Parameter Type Description
expression str Band-math expression string

Returns a new Chain (original is unmodified)


Chain.clip(geojson)

Clip the output to a polygon. Pixels outside the polygon are set to zero.

import json

aoi = json.dumps({
    "type": "Polygon",
    "coordinates": [[[10.0, 52.0], [11.0, 52.0], [11.0, 53.0], [10.0, 53.0], [10.0, 52.0]]]
})

chain.algebra("(B5 - B4) / (B5 + B4)").clip(aoi)
Parameter Type Description
geojson str GeoJSON string — Polygon or MultiPolygon

Returns a new Chain


Chain.reproject(target_crs, ...)

Reproject the output to a different coordinate reference system.

chain.reproject("EPSG:4326")                             # Auto pixel size
chain.reproject("EPSG:3857", res_x=10.0, res_y=10.0)   # Fixed 10 m resolution
chain.reproject("EPSG:4326", resampling="nearest")      # Nearest-neighbour

# Fixed output extent (in target CRS units)
chain.reproject(
    "EPSG:4326",
    res_x=0.0001, res_y=0.0001,
    te_xmin=9.5, te_ymin=51.5,
    te_xmax=10.5, te_ymax=52.5
)
Parameter Type Default Description
target_crs str required Any CRS string GDAL understands (EPSG code, WKT, PROJ string)
res_x float 0 Output pixel width in target CRS units (0 = auto-derive)
res_y float 0 Output pixel height in target CRS units (0 = auto-derive)
resampling str "bilinear" "bilinear" or "nearest"
nodata float -9999.0 Fill value for pixels outside the source extent
te_xmin float 0 Output extent — min X in target CRS
te_ymin float 0 Output extent — min Y in target CRS
te_xmax float 0 Output extent — max X in target CRS
te_ymax float 0 Output extent — max Y in target CRS

Returns a new Chain


Chain.get_info()

Return metadata for the output raster without executing the pipeline.

info = curaster.open("scene.tif").reproject("EPSG:4326").get_info()
print(info)
# {'width': 4096, 'height': 3072, 'geotransform': [...], 'crs': 'GEOGCS[...]'}

Returns dict with keys width, height, geotransform (list of 6 floats), crs (WKT string)


Chain.save_local(path, verbose=False)

Execute the pipeline and write a Float32 tiled GeoTIFF to disk.

curaster.open("scene.tif") \
    .algebra("(B5 - B4) / (B5 + B4)") \
    .save_local("ndvi.tif", verbose=True)
Parameter Type Default Description
path str required Output file path
verbose bool False Print a GDAL-style progress bar

Chain.save_s3(s3_path, verbose=False)

Execute the pipeline and upload the result directly to S3.
AWS credentials must be set via environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION).

curaster.open("scene.tif") \
    .algebra("(B5 - B4) / (B5 + B4)") \
    .save_s3("/vsis3/my-bucket/output/ndvi.tif")
Parameter Type Default Description
s3_path str required Upload destination (/vsis3/bucket/key)
verbose bool False Print a progress bar

Chain.to_memory(verbose=False)

Execute and return all pixels as a RasterResult object. Raises RuntimeError if the result would exceed 75 % of available RAM — use iter_begin() for large rasters.

result = curaster.open("scene.tif") \
    .algebra("B1 * 0.0001") \
    .to_memory()

import numpy as np
arr = result.data()          # numpy array, shape (height, width), dtype float32
print(arr.mean(), arr.std())
print(result.width, result.height, result.proj)

Returns RasterResult


Chain.iter_begin(buf_chunks=4)

Start background execution and return a ChunkQueue for memory-efficient streaming. Each chunk covers a horizontal strip of the output.

queue = curaster.open("huge_scene.tif") \
    .algebra("(B5 - B4) / (B5 + B4)") \
    .iter_begin(buf_chunks=8)

while True:
    chunk = queue.next()
    if chunk is None:
        break
    # chunk = {'y_offset': int, 'width': int, 'height': int, 'data': np.ndarray}
    process(chunk["data"], chunk["y_offset"])
Parameter Type Default Description
buf_chunks int 4 Number of completed chunks to buffer before backpressure

Returns ChunkQueue


RasterResult

Returned by to_memory().

Attribute / Method Type Description
.width int Output width in pixels
.height int Output height in pixels
.proj str WKT coordinate reference system
.data() np.ndarray float32 array of shape (height, width)

ChunkQueue

Returned by iter_begin(). Processing runs on a background thread.

Method Returns Description
.next() dict or None Pop the next chunk, or None on completion

Each chunk dict has keys: y_offset (int), width (int), height (int), data (np.ndarray float32).


Examples

NDVI — local file, save to disk

import curaster

curaster.open("landsat8_sr.tif") \
    .algebra("(B5 - B4) / (B5 + B4)") \
    .save_local("ndvi.tif", verbose=True)

S3 direct-read → S3 write

import curaster, os

# Credentials are read from the environment automatically
curaster.open("s3://my-bucket/scenes/LC08_2024_scene.tif") \
    .algebra("(B5 - B4) / (B5 + B4)") \
    .save_s3("/vsis3/my-bucket/output/ndvi.tif")

Clip to area of interest

import curaster, json

aoi = json.dumps({
    "type": "Polygon",
    "coordinates": [[[13.3, 52.4], [13.5, 52.4], [13.5, 52.6], [13.3, 52.6], [13.3, 52.4]]]
})

curaster.open("sentinel2.tif") \
    .algebra("(B8 - B4) / (B8 + B4)") \
    .clip(aoi) \
    .save_local("ndvi_berlin.tif")

Reproject to WGS84 with fixed resolution

import curaster

curaster.open("utm_scene.tif") \
    .algebra("(B4 - B3) / (B4 + B3)") \
    .reproject("EPSG:4326", res_x=0.0001, res_y=0.0001) \
    .save_local("ndvi_wgs84.tif")

Full pipeline: S3 → algebra → clip → reproject → S3

import curaster, json

aoi = json.dumps({
    "type": "Polygon",
    "coordinates": [[[10.0, 52.0], [11.0, 52.0], [11.0, 53.0], [10.0, 53.0], [10.0, 52.0]]]
})

curaster.open("s3://my-bucket/raw/sentinel2.tif") \
    .algebra("(B8 - B4) / (B8 + B4)") \
    .clip(aoi) \
    .reproject("EPSG:4326", res_x=0.0001, res_y=0.0001) \
    .save_s3("/vsis3/my-bucket/processed/ndvi_reprojected.tif")

Inspect output metadata before running

import curaster

info = curaster.open("scene.tif") \
    .reproject("EPSG:4326", res_x=0.0001) \
    .get_info()

print(f"Output will be {info['width']} × {info['height']} pixels")
print(f"CRS: {info['crs'][:60]}...")

Load into numpy / xarray

import curaster
import numpy as np
import xarray as xr

result = curaster.open("scene.tif") \
    .algebra("(B5 - B4) / (B5 + B4)") \
    .to_memory()

arr = result.data()   # shape (H, W), dtype float32
arr[arr == -9999.0] = np.nan

gt = curaster.open("scene.tif").get_info()["geotransform"]
xcoords = gt[0] + np.arange(result.width)  * gt[1]
ycoords = gt[3] + np.arange(result.height) * gt[5]

da = xr.DataArray(arr, dims=["y", "x"], coords={"x": xcoords, "y": ycoords})
print(da)

Streaming large rasters chunk-by-chunk

import curaster
import numpy as np

output = np.zeros((10000, 10000), dtype=np.float32)

queue = curaster.open("massive_scene.tif") \
    .algebra("(B5 - B4) / (B5 + B4)") \
    .iter_begin(buf_chunks=6)

while True:
    chunk = queue.next()
    if chunk is None:
        break
    y0 = chunk["y_offset"]
    h  = chunk["height"]
    output[y0 : y0 + h, :] = chunk["data"]

print("Done. Mean NDVI:", output.mean())

Boolean / conditional expression

import curaster

# Mask pixels where NIR reflectance > 0.3, zero elsewhere
curaster.open("scene.tif") \
    .algebra("(B5 > 0.3) * B5") \
    .save_local("nir_high_mask.tif")

# Multi-band composite score
curaster.open("scene.tif") \
    .algebra("(B5 - B4) / (B5 + B4) + (B3 - B2) / (B3 + B2)") \
    .save_local("composite_score.tif")

Building from Source

# 1. Install Python build dependencies
pip install build pybind11 scikit-build-core setuptools_scm

# 2. Install system libraries (Ubuntu/Debian)
sudo apt install libgdal-dev libzstd-dev libssl-dev libcurl4-openssl-dev libomp-dev

# 3. Build the wheel
python -m build --wheel

# 4. Install the built wheel
pip install wheelhouse/*.whl

Or build directly with CMake for development:

mkdir build && cd build
cmake .. -Dpybind11_DIR=$(python -c "import pybind11; print(pybind11.get_cmake_dir())")
make -j$(nproc)

# Copy the .so into your working directory
cp curaster*.so ..

License

See LICENSE 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 Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

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

curaster-0.5.0-cp313-cp313-win_amd64.whl (26.7 MB view details)

Uploaded CPython 3.13Windows x86-64

curaster-0.5.0-cp313-cp313-manylinux_2_35_x86_64.whl (58.4 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.35+ x86-64

curaster-0.5.0-cp312-cp312-win_amd64.whl (26.7 MB view details)

Uploaded CPython 3.12Windows x86-64

curaster-0.5.0-cp312-cp312-manylinux_2_35_x86_64.whl (58.4 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.35+ x86-64

curaster-0.5.0-cp311-cp311-win_amd64.whl (26.7 MB view details)

Uploaded CPython 3.11Windows x86-64

curaster-0.5.0-cp311-cp311-manylinux_2_35_x86_64.whl (58.4 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.35+ x86-64

curaster-0.5.0-cp310-cp310-win_amd64.whl (26.7 MB view details)

Uploaded CPython 3.10Windows x86-64

curaster-0.5.0-cp310-cp310-manylinux_2_35_x86_64.whl (58.4 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.35+ x86-64

curaster-0.5.0-cp39-cp39-win_amd64.whl (26.0 MB view details)

Uploaded CPython 3.9Windows x86-64

curaster-0.5.0-cp39-cp39-manylinux_2_35_x86_64.whl (58.4 MB view details)

Uploaded CPython 3.9manylinux: glibc 2.35+ x86-64

File details

Details for the file curaster-0.5.0-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: curaster-0.5.0-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 26.7 MB
  • Tags: CPython 3.13, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for curaster-0.5.0-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 8f388f14cce6a7ca814d0f9d9b2dad4472065e18522eb4104b8202010e5be4f8
MD5 9bb948e939286057028549a6c272c56a
BLAKE2b-256 0ef60f2d77bc93849a093c46b5425b74a51eeb7737e6e6eccfed51228b7bf945

See more details on using hashes here.

Provenance

The following attestation bundles were made for curaster-0.5.0-cp313-cp313-win_amd64.whl:

Publisher: release.yml on purijs/curaster

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file curaster-0.5.0-cp313-cp313-manylinux_2_35_x86_64.whl.

File metadata

File hashes

Hashes for curaster-0.5.0-cp313-cp313-manylinux_2_35_x86_64.whl
Algorithm Hash digest
SHA256 e23846b977ac31a8223473663e5fb9e897658ebbe88fb6cfd9ae67f29ab3204a
MD5 b514c1abc2bc9e27f44eabcc115fbe76
BLAKE2b-256 a3ed7ff71fc6769c38a9327a3cf194ba1b09f5777605adb548cab9c72cc0b0ef

See more details on using hashes here.

Provenance

The following attestation bundles were made for curaster-0.5.0-cp313-cp313-manylinux_2_35_x86_64.whl:

Publisher: release.yml on purijs/curaster

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file curaster-0.5.0-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: curaster-0.5.0-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 26.7 MB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for curaster-0.5.0-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 65a52ca265c50c1d260f13270fe1d94d07c1c64777f38b347790a00d2ada6ea5
MD5 465f48f30e39464f79a7ec9386dd3df5
BLAKE2b-256 1f5e9c1a738089061ba40668d422149f2acdd0be9ee51a168ec4515a80ae222c

See more details on using hashes here.

Provenance

The following attestation bundles were made for curaster-0.5.0-cp312-cp312-win_amd64.whl:

Publisher: release.yml on purijs/curaster

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file curaster-0.5.0-cp312-cp312-manylinux_2_35_x86_64.whl.

File metadata

File hashes

Hashes for curaster-0.5.0-cp312-cp312-manylinux_2_35_x86_64.whl
Algorithm Hash digest
SHA256 a52bb17799cc64774573fb8aee7a523c9e71029482cc50e33ff593a93f2bc941
MD5 3fb788fa32a76a18c9673e02c55699cc
BLAKE2b-256 4f90b4e4af6cf1e7e3973e12fbb71d8a1b209f08e26327926f6198af46b16a7d

See more details on using hashes here.

Provenance

The following attestation bundles were made for curaster-0.5.0-cp312-cp312-manylinux_2_35_x86_64.whl:

Publisher: release.yml on purijs/curaster

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file curaster-0.5.0-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: curaster-0.5.0-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 26.7 MB
  • Tags: CPython 3.11, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for curaster-0.5.0-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 70901b498a237d4ab2590d60bdf64059b1d768f9884841011c2fb394a8d3f6fe
MD5 b70af8b187e051af33bc4459cd5da161
BLAKE2b-256 c1ad16f046100a461c0a528ca11e8e36cf08db31fe3dc03d4999a3197d8a1cf2

See more details on using hashes here.

Provenance

The following attestation bundles were made for curaster-0.5.0-cp311-cp311-win_amd64.whl:

Publisher: release.yml on purijs/curaster

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file curaster-0.5.0-cp311-cp311-manylinux_2_35_x86_64.whl.

File metadata

File hashes

Hashes for curaster-0.5.0-cp311-cp311-manylinux_2_35_x86_64.whl
Algorithm Hash digest
SHA256 f0b3cae4bf934a73269365a2bfbc78ac60e67efde186c45b3c50e0141dcf1178
MD5 66e84f90403437e100997187493cd25f
BLAKE2b-256 cc91be66a4f925a0676386af164dbbb69166d59fbe9a7c99c5ef246aa7dd9af1

See more details on using hashes here.

Provenance

The following attestation bundles were made for curaster-0.5.0-cp311-cp311-manylinux_2_35_x86_64.whl:

Publisher: release.yml on purijs/curaster

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file curaster-0.5.0-cp310-cp310-win_amd64.whl.

File metadata

  • Download URL: curaster-0.5.0-cp310-cp310-win_amd64.whl
  • Upload date:
  • Size: 26.7 MB
  • Tags: CPython 3.10, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for curaster-0.5.0-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 94179983f9fbb3d923e764a21af9a01095a9901349ea5c8eafdc28ade9ad3535
MD5 23d6069cea20efd12230b6e50e98f8bb
BLAKE2b-256 665657092d6e608f23edd54fbb2e5a171ec2c3442f2b63ed8d4a6d79326d6565

See more details on using hashes here.

Provenance

The following attestation bundles were made for curaster-0.5.0-cp310-cp310-win_amd64.whl:

Publisher: release.yml on purijs/curaster

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file curaster-0.5.0-cp310-cp310-manylinux_2_35_x86_64.whl.

File metadata

File hashes

Hashes for curaster-0.5.0-cp310-cp310-manylinux_2_35_x86_64.whl
Algorithm Hash digest
SHA256 60e047f800e2823342ca41b733846a0cf437dc9314dfa744c01d0d4b5971edbe
MD5 78a603c48b7b4f64ede6413ee4079b35
BLAKE2b-256 99cfa19bb905ef6b2d6a14917ba597f402b2adbaeccab2aa856c909831dbc64f

See more details on using hashes here.

Provenance

The following attestation bundles were made for curaster-0.5.0-cp310-cp310-manylinux_2_35_x86_64.whl:

Publisher: release.yml on purijs/curaster

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file curaster-0.5.0-cp39-cp39-win_amd64.whl.

File metadata

  • Download URL: curaster-0.5.0-cp39-cp39-win_amd64.whl
  • Upload date:
  • Size: 26.0 MB
  • Tags: CPython 3.9, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for curaster-0.5.0-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 450ad85091a117934fe9730da0c7d6519e579eefc87bd458d8ba99c21629afe4
MD5 9924676ed94303d566701c4fa61cf554
BLAKE2b-256 3f7b64cd6ba57365cb200d12f5aa794a2354393c30504a4fc1323fa9e51cc4d4

See more details on using hashes here.

Provenance

The following attestation bundles were made for curaster-0.5.0-cp39-cp39-win_amd64.whl:

Publisher: release.yml on purijs/curaster

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file curaster-0.5.0-cp39-cp39-manylinux_2_35_x86_64.whl.

File metadata

File hashes

Hashes for curaster-0.5.0-cp39-cp39-manylinux_2_35_x86_64.whl
Algorithm Hash digest
SHA256 e2aa278ecb3acd3934e9a9da6e5fe87972ad4ac73128ec90fe3c498698490244
MD5 9d3aaf524f72d4219a429fa3dd738235
BLAKE2b-256 9f69bd76cdddf70bd0641dea941b82dee03300b17f7d9505316a35b395fdea9f

See more details on using hashes here.

Provenance

The following attestation bundles were made for curaster-0.5.0-cp39-cp39-manylinux_2_35_x86_64.whl:

Publisher: release.yml on purijs/curaster

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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