Skip to content

Spectral Indices

Spectral indices combine one or more raster bands into a derived raster. UavPy exposes built-in helpers for common indices and a safe expression parser for custom band math.

Index expressions use one-based band references. Check mosaic.band_info before choosing nir, red, red_edge, green, or blue band numbers.

Built-In Indices

NDVI:

1
2
3
4
5
from uavpy.tools import SpectralIndex

ndvi = SpectralIndex.ndvi(nir=4, red=1)
ndvi_map = await ndvi(mosaic)
ndvi_map.plot(band_index=1, cmap="jet")

WDVI:

1
2
3
wdvi = SpectralIndex.wdvi(nir=4, red=1)
wdvi_map = await wdvi(mosaic)
wdvi_map.plot(band_index=1, cmap="hsv")

Other built-in constructors include gndvi, ndre, ndwi, ndmi, savi, osavi, msavi2, evi, evi2, dvi, rvi, ci_green, ci_red_edge, mtci, and sipi.

Custom Expressions

Expressions reference bands with one-based names: B1, B2, B3, and so on.

1
2
3
custom = SpectralIndex("B1 / (B1 + B2 + B3)")
custom_map = await custom(mosaic)
custom_map.plot(band_index=1)

OSAVI-style expression:

1
2
3
osavi = SpectralIndex("(1.16 * (B4 - B3)) / (B4 + B3 + 0.16)")
osavi_map = await osavi(mosaic)
osavi_map.plot(band_index=1, cmap="jet")

Supported Expression Syntax

The parser supports:

  • Band references: B1, B2, B10
  • Numeric constants: 1, 0.16, .5
  • Operators: +, -, *, /, %
  • Exponentiation: ^ or **
  • Unary signs: -B1, +B2
  • Functions: sin, cos, ln, sqrt, min, max, mean, std, var, sum, abs

Examples:

1
2
3
4
SpectralIndex("sqrt(B4)")
SpectralIndex("B4^2 / (B1 + 1)")
SpectralIndex("abs(B4 - B1)")
SpectralIndex("mean(B4)")

Safe evaluation

Expressions are parsed with Python's AST module, but they are not evaluated with eval. UavPy validates every syntax node and only executes the supported arithmetic operations and functions listed above.

Band Index Rules

Band references are one-based and must exist in the raster array.

1
2
# Valid only if the mosaic has at least four bands.
SpectralIndex("B4 - B1")

If an expression references a band outside the raster's band count, UavPy raises a parser error.

Summarize And Save Results

The output of a spectral index is a single-band Orthomosaic, so it can be plotted, summarized through the wrapped DataArray, or saved as a GeoTIFF.

1
2
3
4
print(ndvi_map.shape)
print(ndvi_map.min(), ndvi_map.max())

ndvi_map.save("./data/outputs/ndvi.tif", overwrite=True)

Display Index Tiles

Save the index to a GeoTIFF and use the mapwidgets Python tile backend for colormaps and explicit value ranges.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from pathlib import Path
import sys

from mapwidgets import MapViewer, RasterLayer
from PySide6.QtWidgets import QApplication

ndvi_map.save("./data/ndvi.tif", overwrite=True)

tile_layer = RasterLayer.from_tiled_geotiff(
    "./data/ndvi.tif",
    output_dir=Path(".uavpy_tiles/ndvi"),
    bands=(1,),
    zoom_levels=range(18, 22),
    backend="python",
    colormap="RdYlGn",
    value_range=(-1.0, 1.0),
    transparent_ranges=((-1.0, 0.0),),
    transparent_values=None,
    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()