UavPy is an open-source Python package for processing and analyzing UAV imagery. It provides a small, high-level API for loading orthomosaics, stacking raster bands, computing spectral indices, extracting plot-level regions of interest, and visualizing geospatial raster data.
The package builds on established geospatial and scientific Python libraries, including GDAL, rasterio, Fiona, NumPy, SciPy, and scikit-image.
- Raster artifact API: Load GeoTIFF orthomosaics and keep raster metadata through lazy
rioxarrayartifacts. - Band stacking: Combine multiple single-band rasters into a multi-band orthomosaic.
- Spectral indices: Compute NDVI, NDRE, EVI, SAVI, or custom band math expressions such as
B1/(B1+B2+B3). - Plot extraction: Crop orthomosaics into feature-level regions of interest from vector geometry.
- Map integration: Display saved GeoTIFFs and vector boundaries with
mapwidgetsraster and vector layers. - Visualization helpers: Stretch, colormap, and render single-band or RGB raster data for quick inspection.
UavPy requires Python 3.10 or newer.
GDAL is a native dependency. The Python GDAL binding must match the installed native GDAL library. In this checkout, pyproject.toml pins:
gdal==3.13.1On macOS with Homebrew GDAL, make sure gdal-config is on PATH before syncing:
PATH="/opt/homebrew/bin:$PATH" uv syncuv syncIf uv sync cannot find gdal-config, install GDAL development headers and ensure the matching gdal-config executable is on PATH.
Install the optional map viewer dependencies when using mapwidgets.MapViewer:
uv sync --extra widgetsfrom uavpy.artifacts import Orthomosaic, DSM, DTM
from uavpy.tools import SpectralIndex
from uavpy.util import VisualizationUtil as vis, MiscUtilmosaic = Orthomosaic.from_path("./data/orthomosaic.tif")
await mosaic.load()
print(mosaic.shape)
print(mosaic.band_info)Band indexes are one-based in the public plotting and spectral-index APIs. Check the raster metadata before choosing display bands or index formulas:
for band in mosaic.band_info:
print(band)ndvi = await SpectralIndex.ndvi(nir=4, red=1)(mosaic)
print(ndvi.min(), ndvi.max())
index = SpectralIndex("B1/(B1+B2+B3)")
result = await index(mosaic)Spectral index computation returns a single-band Orthomosaic, which can be
plotted, saved, or passed to downstream geospatial workflows.
UavPy uses the external mapwidgets package for interactive maps and GeoTIFF
tile generation. Save or point to a GeoTIFF, then create a RasterLayer with
the backend that fits the raster:
from pathlib import Path
import sys
from mapwidgets import MapViewer, RasterLayer
from PySide6.QtWidgets import QApplication
tile_layer = RasterLayer.from_tiled_geotiff(
"./data/rgb_orthomosaic.tif",
output_dir=Path(".uavpy_tiles/rgb_orthomosaic"),
bands=(1, 2, 3),
zoom_levels=range(18, 22),
backend="gdal",
overwrite=True,
)
app = QApplication.instance() or QApplication(sys.argv[:1])
viewer = MapViewer(backend="maplibre").resize(1200, 800).show()
viewer.add_layer(tile_layer, zoom_to=True)
viewer.wait_for_map_ready()
app.exec()Use backend="gdal" for normal source-order RGB GeoTIFFs. Use
backend="python" for arbitrary band selections, colormaps, or transparency
masks:
tile_layer = RasterLayer.from_tiled_geotiff(
"./data/multispectral_orthomosaic.tif",
output_dir=Path(".uavpy_tiles/false_color"),
bands=(6, 4, 2),
zoom_levels=range(18, 22),
backend="python",
overwrite=True,
)See the mapwidgets documentation for the full raster tiling API.
Very large orthomosaics need a different preparation step before tile generation. A 10 GB raster that is stored as scanline strips and has no internal overviews can be extremely slow because every map tile may require expensive random reads from the original image.
Before tiling huge rasters, convert them to a Cloud Optimized GeoTIFF (COG) from Python:
from uavpy.artifacts import Orthomosaic
raster = Orthomosaic.from_path("input_orthomosaic.tif")
optimized = raster.save_cog(
"input_orthomosaic_cog.tif",
overwrite=True,
)This is equivalent to running gdal_translate -of COG with practical defaults:
BIGTIFF=YESallows output files larger than 4 GB.COMPRESS=DEFLATEapplies lossless compression. This preserves pixel values but may take longer thanLZW.BLOCKSIZE=512stores the raster in 512 x 512 internal tiles instead of long scanline strips. This makes map-tile reads much faster.OVERVIEWS=AUTObuilds lower-resolution internal pyramids so low and medium zoom levels do not need to read full-resolution pixels.NUM_THREADS=ALL_CPUSlets GDAL use all CPU cores during conversion.
These parameters are defaults, not fixed rules. Keep lossless compression such
as DEFLATE, LZW, or ZSTD for analytical rasters. For visual-only RGB
products, lossy compression such as JPEG may be acceptable if smaller files
matter more than exact pixel values.
This conversion does not reduce the native orthomosaic resolution. Pixel size,
width, height, CRS, bounds, and bands are preserved unless you explicitly pass
resampling options such as -tr or -outsize.
To inspect whether a raster is already tiled and has overviews:
gdalinfo input_orthomosaic.tifLook for Block=512x512 or similar tiled blocks and an Overviews: section.
shape_file = ShapeFile("./data/plots.shp")
plots = await mosaic.extract_plots(shape_file, plot_id_field="plot_id")
for plot in plots:
plot_ndvi = await ndvi(plot)
print(plot.attrs["plot_id"], plot.attrs, plot_ndvi.min(), plot_ndvi.max())mkdocs/- Editable documentation source.docs/- Generated static documentation output.uavpy/- Root library folderartifacts- Processing artifactsdecor- Internal decoratorsmap- Convenience re-exports for mapwidgets schemas and layerstools- Spectral index and expression parsing toolsutil- Raster, array, math, and visualization utilities
uv sync- Install the project and development dependencies.uv run pytest- Run the test suite.uv run mkdocs serve- Start the live-reloading docs server.uv run mkdocs build- Build the documentation site.uv run python examples/demo.py- List the focused runnable examples.
To cite this project: BibTeX
@software{uavpy,
author = {Henry Ruiz},
title = {UavPy: High level Python API for UAV imagery data processing},
url = {https://github.com/haruiz/uavpy},
version = {0.1.0},
year = {2020},
}
