Skip to contents

Calculate a suite of multispectral indices such as NDVI, SAVI etc. in an efficient way via C++.

Usage

spectralIndices(
  img,
  blue = NULL,
  green = NULL,
  red = NULL,
  nir = NULL,
  redEdge1 = NULL,
  redEdge2 = NULL,
  redEdge3 = NULL,
  swir1 = NULL,
  swir2 = NULL,
  swir3 = NULL,
  scaleFactor = 1,
  skipRefCheck = FALSE,
  indices = NULL,
  index = NULL,
  maskLayer = NULL,
  maskValue = 1,
  coefs = list(L = 0.5, G = 2.5, L_evi = 1, C1 = 6, C2 = 7.5, s = 1, swir2ccc = NULL,
    swir2coc = NULL),
  ...
)

Arguments

img

SpatRaster. Typically remote sensing imagery, which is to be classified.

blue

Character or integer. Blue band.

green

Character or integer. Green band.

red

Character or integer. Red band.

nir

Character or integer. Near-infrared band (700-1100nm).

redEdge1

Character or integer. Red-edge band (705nm)

redEdge2

Character or integer. Red-edge band (740nm)

redEdge3

Character or integer. Red-edge band (783nm)

swir1

not used

swir2

Character or integer. Short-wave-infrared band (1400-1800nm).

swir3

Character or integer. Short-wave-infrared band (2000-2500nm).

scaleFactor

Numeric. Scale factor for the conversion of scaled reflectances to [0,1] value range (applied as reflectance/scaleFactor) Neccesary for calculating EVI/EVI2 with scaled reflectance values.

skipRefCheck

Logical. When EVI/EVI2 is to be calculated there is a rough heuristic check, whether the data are inside [0,1]+/-0.5 (after applying a potential scaleFactor). If there are invalid reflectances, e.g. clouds with reflectance > 1 this check will result in a false positive and skip EVI calculation. Use this argument to skip this check in such cases *iff* you are sure the data and scaleFactor are valid.

indices

Character. One or more spectral indices to calculate (see Details). By default (NULL) all implemented indices given the spectral bands which are provided will be calculated.

index

Character. Alias for indices.

maskLayer

RasterLayer or SpatRaster containing a mask, e.g. clouds, for which pixels are set to NA. Alternatively a layername or -number can be provided if the mask is part of img.

maskValue

Integer. Pixel value in maskLayer which should be masked in output, i.e. will be set to NA in all calculated indices.

coefs

List of coefficients (see Details).

...

further arguments such as filename etc. passed to writeRaster

Value

SpatRaster

Details

spectralIndices calculates all indices in one go in C++, which is more efficient than calculating each index separately (for large rasters). By default all indices which can be calculated given the specified indices will be calculated. If you don't want all indices, use the indices argument to specify exactly which indices are to be calculated. See the table bellow for index names and required bands.

Index values outside the valid value ranges (if such a range exists) will be set to NA. For example a pixel with NDVI > 1 will be set to NA.

Index Description Source Bands Formula
CLGGreen-band Chlorophyll IndexGitelson2003redEdge3, green\(redEdge3/green - 1\)
CLRERed-edge-band Chlorophyll IndexGitelson2003redEdge3, redEdge1\(redEdge3/redEdge1 - 1\)
CTVICorrected Transformed Vegetation IndexPerry1984red, nir\((NDVI + 0.5)/sqrt(abs(NDVI + 0.5))\)
DVIDifference Vegetation IndexRichardson1977red, nir\(s * nir - red\)
EVIEnhanced Vegetation IndexHuete1999red, nir, blue\(G * ((nir - red)/(nir + C1 * red - C2 * blue + L_evi))\)
EVI2Two-band Enhanced Vegetation IndexJiang 2008red, nir\(G * (nir - red)/(nir + 2.4 * red + 1)\)
GEMIGlobal Environmental Monitoring IndexPinty1992red, nir\((((nir^2 - red^2) * 2 + (nir * 1.5) + (red * 0.5))/(nir + red + 0.5)) * (1 - ((((nir^2 - red^2) * 2 + (nir * 1.5) + (red * 0.5))/(nir + red + 0.5)) * 0.25)) - ((red - 0.125)/(1 - red))\)
GNDVIGreen Normalised Difference Vegetation IndexGitelson1998green, nir\((nir - green)/(nir + green)\)
KNDVIKernel Normalised Difference Vegetation IndexCamps-Valls2021red, nir\(tanh(((nir - red)/(nir + red)))^2\)
MCARIModified Chlorophyll Absorption Ratio IndexDaughtery2000green, red, redEdge1\(((redEdge1 - red) - (redEdge1 - green)) * (redEdge1/red)\)
MNDWIModified Normalised Difference Water IndexXu2006green, swir2\((green - swir2)/(green + swir2)\)
MSAVIModified Soil Adjusted Vegetation IndexQi1994red, nir\(nir + 0.5 - (0.5 * sqrt((2 * nir + 1)^2 - 8 * (nir - (2 * red))))\)
MSAVI2Modified Soil Adjusted Vegetation Index 2Qi1994red, nir\((2 * (nir + 1) - sqrt((2 * nir + 1)^2 - 8 * (nir - red)))/2\)
MTCIMERIS Terrestrial Chlorophyll IndexDashAndCurran2004red, redEdge1, redEdge2\((redEdge2 - redEdge1)/(redEdge1 - red)\)
NBRINormalised Burn Ratio IndexGarcia1991nir, swir3\((nir - swir3)/(nir + swir3)\)
NDREI1Normalised Difference Red Edge Index 1GitelsonAndMerzlyak1994redEdge2, redEdge1\((redEdge2 - redEdge1)/(redEdge2 + redEdge1)\)
NDREI2Normalised Difference Red Edge Index 2Barnes2000redEdge3, redEdge1\((redEdge3 - redEdge1)/(redEdge3 + redEdge1)\)
NDVINormalised Difference Vegetation IndexRouse1974red, nir\((nir - red)/(nir + red)\)
NDVICCorrected Normalised Difference Vegetation IndexNemani1993red, nir, swir2\((nir - red)/(nir + red) * (1 - ((swir2 - swir2ccc)/(swir2coc - swir2ccc)))\)
NDWINormalised Difference Water IndexMcFeeters1996green, nir\((green - nir)/(green + nir)\)
NDWI2Normalised Difference Water IndexGao1996nir, swir2\((nir - swir2)/(nir + swir2)\)
NRVINormalised Ratio Vegetation IndexBaret1991red, nir\((red/nir - 1)/(red/nir + 1)\)
REIPRed Edge Inflection PointGuyotAndBarnet1988red, redEdge1, redEdge2, redEdge3\(0.705 + 0.35 * ((red + redEdge3)/(2 - redEdge1))/(redEdge2 - redEdge1)\)
RVIRatio Vegetation Indexred, nir\(red/nir\)
SATVISoil Adjusted Total Vegetation IndexMarsett2006red, swir2, swir3\((swir2 - red)/(swir2 + red + L) * (1 + L) - (swir3/2)\)
SAVISoil Adjusted Vegetation IndexHuete1988red, nir\((nir - red) * (1 + L)/(nir + red + L)\)
SLAVISpecific Leaf Area Vegetation IndexLymburger2000red, nir, swir2\(nir/(red + swir2)\)
SRSimple Ratio Vegetation IndexBirth1968red, nir\(nir/red\)
TTVIThiam's Transformed Vegetation IndexThiam1997red, nir\(sqrt(abs((nir - red)/(nir + red) + 0.5))\)
TVITransformed Vegetation IndexDeering1975red, nir\(sqrt((nir - red)/(nir + red) + 0.5)\)
WDVIWeighted Difference Vegetation IndexRichardson1977red, nir\(nir - s * red\)
CUSTOMSuper custom indexMueller2024blue, red\(blue + red\)
CUSTOMSuper custom indexMueller2024blue, red\(blue + red\)

Some indices require additional parameters, such as the slope of the soil line which are specified via a list to the coefs argument. Although the defaults are sensible values, values like the soil brightnes factor L for SAVI should be adapted depending on the characteristics of the scene. The coefficients are:

CoefficientDescriptionAffected Indices
sslope of the soil lineDVI, WDVI
L_evi, C1, C2, GvariousEVI
Lsoil brightness factorSAVI, SATVI
swir2cccminimum swir2 value (completely closed forest canopy)NDVIC
swir2cocmaximum swir2 value (completely open canopy)NDVIC

The wavelength band names are defined following Schowengertd 2007, p10. The last column shows exemplarily which Landsat 5 TM bands correspond to which wavelength range definition.

Band Description Wavl_min Wavl_max Landsat5_Band Sentinel2_Band vis
visible4006801,2,32,3,4red-edge1red-edge1
680720-5red-edge2red-edge2720
760-6red-edge3red-edge3760800
-7nirnear infra-red80011004
8/8aswir1short-wave infra-red11001351-9,10
swir2short-wave infra-red14001800511swir3
short-wave infra-red20002500712mir1mid-wave infra-red
30004000--mir2mid-wave infra-red45000
5000--tir1thermal infra-red80009500
--tir2thermal infra-red100001400006

Examples

library(ggplot2)
library(terra)

## Calculate NDVI
ndvi <- spectralIndices(lsat, red = "B3_dn", nir = "B4_dn", indices = "NDVI")
ndvi
#> class       : SpatRaster 
#> dimensions  : 310, 287, 1  (nrow, ncol, nlyr)
#> resolution  : 30, 30  (x, y)
#> extent      : 619395, 628005, -419505, -410205  (xmin, xmax, ymin, ymax)
#> coord. ref. : +proj=utm +zone=22 +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
#> source(s)   : memory
#> name        :       NDVI 
#> min value   : -0.5789474 
#> max value   :  0.7629630 
ggR(ndvi, geom_raster = TRUE) +
        scale_fill_gradientn(colours = c("black", "white")) 


# \donttest{ 
## Calculate all possible indices, given the provided bands 
## Convert DNs to reflectance (required to calculate EVI and EVI2)
mtlFile  <- system.file("external/landsat/LT52240631988227CUB02_MTL.txt", package="RStoolbox")
lsat_ref <- radCor(lsat, mtlFile, method = "apref")
#> 17:03:36 | Bands to convert to reflectance: B1_dn, B2_dn, B3_dn, B4_dn, B5_dn, B7_dn
#> 17:03:36 | Thermal bands to convert to brightness temperature: B6_dn
#> 17:03:36 | Processing thermal band(s)
#> 17:03:36 | Processing radiance / reflectance

SI <- spectralIndices(lsat_ref, red = "B3_tre", nir = "B4_tre")
plot(SI)


## Custom Spectral Index Calculation (beta) (supports only bands right now...)
# Get all indices
idxdb <- getOption("RStoolbox.idxdb")

# Customize the RStoolbox index-database and overwrite the option
cdb <- c(idxdb, CUSTOM = list( list(c("Mueller2024", "Super custom index"),
        function(blue, red) {blue + red})))
rsOpts(idxdb = cdb)

# Calculate the custom index, (also together with the provided ones)
custom_ind <- spectralIndices(lsat, blue = 1, red = 3, nir = 4, indices = c("NDVI", "CUSTOM"))
# }