Skip to main content

Convert raster imagery (orthomosaic, NDVI, NDRE) to PMTiles

Project description

raster2pm 🛰️

PyPI version Python 3.8+ License: MIT

raster → PMTiles — Convert any GeoTIFF to web-optimized map tiles in one command.

Convert orthomosaics, NDVI, NDRE, and any raster imagery to PMTiles with automatic colormap application for vegetation indices.


📦 Installation

From PyPI

\\ash pip install raster2pm \\

From Source

\\ash git clone https://github.com/samuelappiah/raster2pm.git cd raster2pm pip install -e . \\

With Development Dependencies

\\ash pip install raster2pm[dev] \\


🚀 Quick Start

Basic RGB Orthomosaic

\\ash raster2pm ortho.tif -o tiles.pmtiles \\

NDVI with Auto-Stretch

\\ash raster2pm ndvi.tif --ndvi --auto-stretch -o ndvi.pmtiles \\

NDRE with Custom Colormap

\\ash raster2pm ndre.tif --ndre --colormap RdYlGn -o ndre.pmtiles \\


📖 Complete Usage Guide

Command-Line Interface

\\ash raster2pm INPUT_FILE [OPTIONS] \\

Input/Output Options

Option Description Default
-o, --output PATH\ Output PMTiles file \output.pmtiles\

Tiling Options

Option Description Default
--min-zoom INT\ Minimum zoom level \5\
--max-zoom INT\ Maximum zoom level \20\
--format FORMAT\ Tile format: PNG, JPEG, WEBP \PNG\
--tile-size INT\ Tile size in pixels \256\
--resampling METHOD\ Resampling: nearest, bilinear, cubic, cubic_spline, lanczos, average \cubic\
--quality INT\ JPEG/WEBP quality (0-100) \75\
--workers INT\ Number of parallel workers \4\

Metadata Options

Option Description Default
--name TEXT\ Layer name "Raster Layer"\
--description TEXT\ Layer description "Converted from GeoTIFF"\

Behavior Options

Option Description
--overlay / --no-overlay\ Create overlay tiles (default: overlay)
--exclude-empty / --no-exclude-empty\ Exclude empty tiles (default: exclude)

Vegetation Index Options

Option Description Default
--ndvi\ Input is NDVI raster -
--ndre\ Input is NDRE raster -
--colormap NAME\ Matplotlib colormap: viridis, plasma, inferno, magma, RdYlGn, RdBu, ndvi_custom \RdYlGn\
--min-value FLOAT\ Minimum value for colormap -1.0\
--max-value FLOAT\ Maximum value for colormap \1.0\
--auto-stretch\ Auto-stretch to p2-p98 data range -
--stretch-percentile FLOAT\ Percentile to clip at tails \2.0\

Diagnostic Options

Option Description
--stats-only\ Print statistics and exit
--keep-temp\ Keep temporary files
-v, --verbose\ Increase verbosity
--version\ Show version

📚 Examples

Example 1: Convert RGB Orthomosaic

\\ash raster2pm farm_ortho.tif -o farm_tiles.pmtiles \\

Example 2: NDVI with Auto-Stretch

\\ash

Automatically stretches colormap to actual data range

raster2pm ndvi_map.tif --ndvi --auto-stretch -o ndvi_tiles.pmtiles \\

Example 3: High-Quality WEBP Output

\\ash raster2pm ortho.tif --format WEBP --quality 90 -o tiles.pmtiles \\

Example 4: Custom Zoom Levels

\\ash

Only generate zoom levels 12-18 (faster, smaller file)

raster2pm ortho.tif --min-zoom 12 --max-zoom 18 -o tiles.pmtiles \\

Example 5: NDRE with Viridis Colormap

\\ash raster2pm ndre_map.tif --ndre --colormap viridis --auto-stretch -o ndre_tiles.pmtiles \\

Example 6: Check Statistics Before Converting

\\ash

See data distribution before choosing colormap range

raster2pm ndvi.tif --ndvi --stats-only \\

Output: \
📈 Computing data statistics (sampling ~2000 rows)... Valid pixels (sample) : 98.5% (196,834 pixels) Range : [-0.45, 0.92] Mean ± std : 0.34 ± 0.28 Percentiles p2=-0.32 p10=-0.05 p25=0.12 p50=0.34 p75=0.56 p90=0.72 p98=0.85 Value distribution: [-0.45 → -0.31] ███ 2.3% [-0.31 → -0.18] ██████ 5.1% ... \\

Example 7: Manual Colormap Range

\\ash

Use statistics from above to set optimal range

raster2pm ndvi.tif --ndvi --min-value -0.32 --max-value 0.85 -o ndvi_tiles.pmtiles \\

Example 8: JPEG Output for Smaller Files

\\ash raster2pm ortho.tif --format JPEG --quality 75 -o tiles_jpg.pmtiles \\

Example 9: Parallel Processing

\\ash

Use 8 CPU cores for faster conversion

raster2pm large_ortho.tif --workers 8 -o tiles.pmtiles \\

Example 10: Custom Metadata

\\ash raster2pm field.tif \ --name "Farm Field 42 - July 2024" \ --description "RGB orthomosaic, 2cm/pixel, DJI Phantom 4" \ -o farm_july.pmtiles \\


🐍 Python API

Basic Usage

\\python from raster2pm import convert_to_pmtiles

Basic RGB conversion

convert_to_pmtiles("ortho.tif", "output.pmtiles") \\

NDVI with Auto-Stretch

\\python from raster2pm import convert_to_pmtiles

convert_to_pmtiles( "ndvi.tif", "ndvi.pmtiles", is_ndvi=True, auto_stretch=True, colormap="RdYlGn", ) \\

Custom Settings

\\python from raster2pm import convert_to_pmtiles

convert_to_pmtiles( input_file="large_ortho.tif", output_file="tiles.pmtiles", min_zoom=12, max_zoom=22, tile_format="WEBP", quality=85, resampling="lanczos", workers=8, name="Farm Orthomosaic", description="2cm resolution, captured July 2024", ) \\

Using Individual Components

\\python from raster2pm import get_raster_info, compute_vegetation_stats

Get raster metadata

info = get_raster_info("ndvi.tif") print(f"Size: {info['size']}") print(f"Bands: {info['bands']}") print(f"CRS: {info['crs']}")

Compute NDVI statistics

stats = compute_vegetation_stats("ndvi.tif") print(f"NDVI range: [{stats['min']:.2f}, {stats['max']:.2f}]") print(f"Mean NDVI: {stats['mean']:.2f}") print(f"P50 NDVI: {stats['p50']:.2f}") \\

Apply Colormap Manually

\\python from raster2pm import apply_colormap_to_rgb

Convert single-band NDVI to RGB GeoTIFF

rgb_file = apply_colormap_to_rgb( "ndvi.tif", colormap_name="RdYlGn", vmin=-1.0, vmax=1.0, ) print(f"RGB file created: {rgb_file}") \\


🎨 Available Colormaps

Colormap Description Best For
\RdYlGn\ Red-Yellow-Green NDVI/NDRE (default)
\
dvi_custom\ Red → Yellow → Green NDVI (custom gradient)
\ iridis\ Blue-Green-Yellow General scientific
\plasma\ Purple-Orange-Yellow Elevation/heat
\inferno\ Black-Red-Yellow Intensity
\magma\ Black-Purple-White Topography
\RdBu\ Red-White-Blue Anomaly detection

📊 Understanding the Output

Statistics

When using --stats-only\ or --ndvi/--ndre, raster2pm computes:

  • Min/Max: Data range
  • Mean ± Std: Central tendency and spread
  • Percentiles: p2, p10, p25, p50 (median), p75, p90, p98
  • Valid pixels: Percentage of non-NoData pixels
  • ASCII histogram: Visual distribution

Colormap Warnings

If your data range doesn't match the colormap range, raster2pm warns you:

\
⚠️ Data spans 0.35 but colormap range is 2.00 — only 18% of colours used. The map will look nearly one colour! 👉 Run with --auto-stretch or set: --min-value -0.32 --max-value 0.85 \\

Auto-Stretch

--auto-stretch\ automatically sets the colormap range to your data's p2-p98 range, ensuring vibrant, informative visualizations.


🌐 Viewing PMTiles

Online (Easiest)

Drag and drop your .pmtiles\ file to pmtiles.io

Local Server

\\ash

Install pmtiles CLI

npm install -g pmtiles

Serve locally

pmtiles serve output.pmtiles

Open http://localhost:8081

\\

Web Maps

\\javascript // MapLibre GL JS const map = new maplibregl.Map({ container: 'map', style: { sources: { 'raster': { type: 'pmtiles', url: 'https://example.com/tiles.pmtiles', } } } }); \\


🔧 How It Works

  1. Reads GeoTIFF metadata (CRS, bounds, bands)
  2. For vegetation indices: Computes statistics, applies colormap
  3. Processes block-by-block for memory efficiency
  4. Builds overview pyramids for smooth zooming
  5. Converts to PMTiles using rio-pmtiles
  6. Outputs a single .pmtiles\ file

⚙️ Requirements

  • Python 3.8+
  • rio-pmtiles
  • rasterio
  • numpy
  • matplotlib

All installed automatically with \pip install raster2pm.


🧪 Development

\\ash

Clone

git clone https://github.com/samuelappiah/raster2pm.git cd raster2pm

Install dev dependencies

pip install -e ".[dev]"

Run tests

pytest -v

Format code

black raster2pm/ ruff check raster2pm/

Type check

mypy raster2pm/ \\


🤝 Contributing

Contributions welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Add tests
  4. Submit a pull request

📄 License

MIT © 2024 Samuel Appiah Kubi


🔗 Links

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

raster2pm-0.1.1.tar.gz (24.2 kB view details)

Uploaded Source

Built Distribution

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

raster2pm-0.1.1-py3-none-any.whl (19.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: raster2pm-0.1.1.tar.gz
  • Upload date:
  • Size: 24.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.1

File hashes

Hashes for raster2pm-0.1.1.tar.gz
Algorithm Hash digest
SHA256 acfe81bfc76f5f9200df0b704e330fb9ff8711c199a0bc789d0b498c0acb0da8
MD5 b91b8aaaac1333382588c5b1097724e8
BLAKE2b-256 52521ed1e72aac11e01494413b68c737c63b3e250dc731841299a5603254e289

See more details on using hashes here.

File details

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

File metadata

  • Download URL: raster2pm-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 19.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.1

File hashes

Hashes for raster2pm-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 6bb4c39825ef7e3a844ef5fd23e4192a92cac2a71f41a40ecd18499833cf47eb
MD5 7fa09cba2d666f65a08dd3fa03a838d9
BLAKE2b-256 2da34535c944d3816cb745715780ea86d23ceb4bfbd84a9f9cd02992fb4b0077

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