Introduction
One of the simplest and common operations to be performed on raster
objects is computation. This is used to extract specific details about
the dataset by using the various aspects of the bands.
In this notebook, I will explore how to perform this computations,
which is fairly is easy. I will be using the Normalized Difference
Vegetation Index (NDVI). This is a basic index for getting the
vegetative cover of anb area by using the surface reflectance of Near
Infrared Band and Red Band that is band 5 and 4 respectively.
NDVI
The NDVI can be expressed in a mathematical formula that is :
\[
ndvi = (nir-red)/(nir+red)
\]
Libraries
As established the three packages required are terra,
tidyverse and sf.
library(terra)
library(tidyverse)
── Attaching core tidyverse packages ─────────────────────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.2 ✔ readr 2.1.4
✔ forcats 1.0.0 ✔ stringr 1.5.0
✔ ggplot2 3.4.3 ✔ tibble 3.2.1
✔ lubridate 1.9.2 ✔ tidyr 1.3.0
✔ purrr 1.0.2 ── Conflicts ───────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ tidyr::extract() masks terra::extract()
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
library(sf)
Linking to GEOS 3.11.2, GDAL 3.6.2, PROJ 9.2.0; sf_use_s2() is TRUE
sceneDir <- "C:/Users/roywa/Data/LST/LC09_L2SP_168061_20230204_20230311_02_T1/NORMALISED/"
kiambu_stack <- rast(paste0(sceneDir, "KIAMBU_SUBSET_STACK.TIF"))
This is a plot to see how, if at all, the data has been loaded.
Though it is unnecessary. I prefer the assurance that is the plot
rendering without any skirmishes.
kiambu_stack$`B3` %>%
plot()

NDVI function
This is a function that I will use to perform the NDVI calculations.
I prefere this method since the function can be reused multiple times
without error or failure.
calc_ndvi <- function(nir, red){
ndvi <- (nir-red)/(nir+red)
return(ndvi)
}
For instance: This here is the performance of the NDVI for the image
subset. The function returns a raster with the values defined.
kiambu_ndvi <- lapp(c(kiambu_stack$B5, kiambu_stack$B4), fun=calc_ndvi)
In my case, I have used the data to plot the raster as well as a
histogram to see distribution of the various data points.
par(mfrow=c(1,2))
kiambu_ndvi%>%
plot(main="NDVI OF KIAMBU COUNTY")
kiambu_ndvi%>%
hist(main = "NDVI values", xlab = "NDVI", ylab= "Frequency",
col = "wheat", xlim = c(-0.5, 1), breaks = 30, xaxt = "n"
)%>%
axis(side=1, at = seq(-0.6, 1, 0.2), labels = seq(-0.6, 1, 0.2))
This is a threshold cut. I am taking in the values above 0.4 only
while the rest are interprated as Null values. This is benefitial if you
want to show a specific phenomena that occurs above a certain range of
the dataset.
kiambu_ndvi %>%
clamp(0.4, values=FALSE)%>%
plot()
Alternatively you can select a spefific range by changing the ranges
into a matrix.
m <- c(-Inf, 0.25, NA, 0.25, 0.4, 1, 0.4, Inf, NA)
rcl <- matrix(m, ncol=3, byrow=TRUE)
land <- classify(kiambu_ndvi, rcl)
land %>%
plot(col="brown")
Finally, the data can also be classified using a vector.
m <- c(-1,0.25, 0.3, 0.4, 0.6, 1)
vegc <- classify(kiambu_ndvi, m)
plot(vegc, col = c("red","brown","orange", "yellow", "green"), main = 'NDVI based thresholding')
Conclusion
This is a very small subset of the indices that are used with
remotely sensed images. There are a number of indiced that are way more
complicated than the NDVI. However, all the indices that you choose
should have a theoretical backing so that you understand eh innner
working of these indices.
LS0tDQp0aXRsZTogIkNyZWF0aW5nIGFuIE5EVkkgb2YgYSByYXN0ZXIiDQphdXRob3I6ICJSb3kgV2Fzd2EiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIyBJbnRyb2R1Y3Rpb24NCg0KT25lIG9mIHRoZSBzaW1wbGVzdCBhbmQgY29tbW9uIG9wZXJhdGlvbnMgdG8gYmUgcGVyZm9ybWVkIG9uIHJhc3RlciBvYmplY3RzIGlzIGNvbXB1dGF0aW9uLiBUaGlzIGlzIHVzZWQgdG8gZXh0cmFjdCBzcGVjaWZpYyBkZXRhaWxzIGFib3V0IHRoZSBkYXRhc2V0IGJ5IHVzaW5nIHRoZSB2YXJpb3VzIGFzcGVjdHMgb2YgdGhlIGJhbmRzLg0KDQpJbiB0aGlzIG5vdGVib29rLCBJIHdpbGwgZXhwbG9yZSBob3cgdG8gcGVyZm9ybSB0aGlzIGNvbXB1dGF0aW9ucywgd2hpY2ggaXMgZmFpcmx5IGlzIGVhc3kuIEkgd2lsbCBiZSB1c2luZyB0aGUgTm9ybWFsaXplZCBEaWZmZXJlbmNlIFZlZ2V0YXRpb24gSW5kZXggKE5EVkkpLiBUaGlzIGlzIGEgYmFzaWMgaW5kZXggZm9yIGdldHRpbmcgdGhlIHZlZ2V0YXRpdmUgY292ZXIgb2YgYW5iIGFyZWEgYnkgdXNpbmcgdGhlIHN1cmZhY2UgcmVmbGVjdGFuY2Ugb2YgTmVhciBJbmZyYXJlZCBCYW5kIGFuZCBSZWQgQmFuZCB0aGF0IGlzIGJhbmQgNSBhbmQgNCByZXNwZWN0aXZlbHkuDQoNCiMjIE5EVkkNCg0KVGhlIE5EVkkgY2FuIGJlIGV4cHJlc3NlZCBpbiBhIG1hdGhlbWF0aWNhbCBmb3JtdWxhIHRoYXQgaXMgOg0KDQokJA0KbmR2aSA9IChuaXItcmVkKS8obmlyK3JlZCkNCiQkDQoNCiMjIExpYnJhcmllcw0KDQpBcyBlc3RhYmxpc2hlZCB0aGUgdGhyZWUgcGFja2FnZXMgcmVxdWlyZWQgYXJlIGB0ZXJyYWAsIGB0aWR5dmVyc2VgIGFuZCBgc2ZgLg0KDQpgYGB7ciBsaWJyYXJpZXN9DQpsaWJyYXJ5KHRlcnJhKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHNmKQ0KDQpgYGANCg0KYGBge3IgZGF0YX0NCnNjZW5lRGlyIDwtICJDOi9Vc2Vycy9yb3l3YS9EYXRhL0xTVC9MQzA5X0wyU1BfMTY4MDYxXzIwMjMwMjA0XzIwMjMwMzExXzAyX1QxL05PUk1BTElTRUQvIg0Ka2lhbWJ1X3N0YWNrIDwtIHJhc3QocGFzdGUwKHNjZW5lRGlyLCAiS0lBTUJVX1NVQlNFVF9TVEFDSy5USUYiKSkNCmBgYA0KDQpUaGlzIGlzIGEgcGxvdCB0byBzZWUgaG93LCBpZiBhdCBhbGwsIHRoZSBkYXRhIGhhcyBiZWVuIGxvYWRlZC4gVGhvdWdoIGl0IGlzIHVubmVjZXNzYXJ5LiBJIHByZWZlciB0aGUgYXNzdXJhbmNlIHRoYXQgaXMgdGhlIHBsb3QgcmVuZGVyaW5nIHdpdGhvdXQgYW55IHNraXJtaXNoZXMuDQoNCmBgYHtyIHJhbmRvbSBwbG90fQ0Ka2lhbWJ1X3N0YWNrJGBCM2AgJT4lDQogIHBsb3QoKQ0KYGBgDQoNCiMjIE5EVkkgZnVuY3Rpb24NCg0KVGhpcyBpcyBhIGZ1bmN0aW9uIHRoYXQgSSB3aWxsIHVzZSB0byBwZXJmb3JtIHRoZSBORFZJIGNhbGN1bGF0aW9ucy4gSSBwcmVmZXJlIHRoaXMgbWV0aG9kIHNpbmNlIHRoZSBmdW5jdGlvbiBjYW4gYmUgcmV1c2VkIG11bHRpcGxlIHRpbWVzIHdpdGhvdXQgZXJyb3Igb3IgZmFpbHVyZS4NCg0KYGBge3J9DQpjYWxjX25kdmkgPC0gZnVuY3Rpb24obmlyLCByZWQpew0KICBuZHZpIDwtIChuaXItcmVkKS8obmlyK3JlZCkNCiAgcmV0dXJuKG5kdmkpDQp9DQpgYGANCg0KRm9yIGluc3RhbmNlOiBUaGlzIGhlcmUgaXMgdGhlIHBlcmZvcm1hbmNlIG9mIHRoZSBORFZJIGZvciB0aGUgaW1hZ2Ugc3Vic2V0LiBUaGUgZnVuY3Rpb24gcmV0dXJucyBhIHJhc3RlciB3aXRoIHRoZSB2YWx1ZXMgZGVmaW5lZC4NCg0KYGBge3J9DQpraWFtYnVfbmR2aSA8LSBsYXBwKGMoa2lhbWJ1X3N0YWNrJEI1LCBraWFtYnVfc3RhY2skQjQpLCBmdW49Y2FsY19uZHZpKQ0KYGBgDQoNCkluIG15IGNhc2UsIEkgaGF2ZSB1c2VkIHRoZSBkYXRhIHRvIHBsb3QgdGhlIHJhc3RlciBhcyB3ZWxsIGFzIGEgaGlzdG9ncmFtIHRvIHNlZSBkaXN0cmlidXRpb24gb2YgdGhlIHZhcmlvdXMgZGF0YSBwb2ludHMuDQoNCmBgYHtyfQ0KcGFyKG1mcm93PWMoMSwyKSkNCmtpYW1idV9uZHZpJT4lDQogIHBsb3QobWFpbj0iTkRWSSBPRiBLSUFNQlUgQ09VTlRZIikNCg0Ka2lhbWJ1X25kdmklPiUNCiAgaGlzdChtYWluID0gIk5EVkkgdmFsdWVzIiwgeGxhYiA9ICJORFZJIiwgeWxhYj0gIkZyZXF1ZW5jeSIsDQogICAgY29sID0gIndoZWF0IiwgeGxpbSA9IGMoLTAuNSwgMSksICBicmVha3MgPSAzMCwgeGF4dCA9ICJuIg0KICAgICklPiUNCiAgYXhpcyhzaWRlPTEsIGF0ID0gc2VxKC0wLjYsIDEsIDAuMiksIGxhYmVscyA9IHNlcSgtMC42LCAxLCAwLjIpKQ0KYGBgDQoNClRoaXMgaXMgYSB0aHJlc2hvbGQgY3V0LiBJIGFtIHRha2luZyBpbiB0aGUgdmFsdWVzIGFib3ZlIDAuNCBvbmx5IHdoaWxlIHRoZSByZXN0IGFyZSBpbnRlcnByYXRlZCBhcyBOdWxsIHZhbHVlcy4gVGhpcyBpcyBiZW5lZml0aWFsIGlmIHlvdSB3YW50IHRvIHNob3cgYSBzcGVjaWZpYyBwaGVub21lbmEgdGhhdCBvY2N1cnMgYWJvdmUgYSBjZXJ0YWluIHJhbmdlIG9mIHRoZSBkYXRhc2V0Lg0KDQpgYGB7cn0NCmtpYW1idV9uZHZpICU+JQ0KICBjbGFtcCgwLjQsIHZhbHVlcz1GQUxTRSklPiUNCiAgcGxvdCgpDQpgYGANCg0KXA0KQWx0ZXJuYXRpdmVseSB5b3UgY2FuIHNlbGVjdCBhIHNwZWZpZmljIHJhbmdlIGJ5IGNoYW5naW5nIHRoZSByYW5nZXMgaW50byBhIG1hdHJpeC4NCg0KYGBge3J9DQptIDwtIGMoLUluZiwgMC4yNSwgTkEsICAwLjI1LCAwLjQsIDEsICAwLjQsIEluZiwgTkEpDQpyY2wgPC0gbWF0cml4KG0sIG5jb2w9MywgYnlyb3c9VFJVRSkNCmxhbmQgPC0gY2xhc3NpZnkoa2lhbWJ1X25kdmksIHJjbCkNCmxhbmQgJT4lDQogIHBsb3QoY29sPSJicm93biIpDQpgYGANCg0KRmluYWxseSwgdGhlIGRhdGEgY2FuIGFsc28gYmUgY2xhc3NpZmllZCB1c2luZyBhIHZlY3Rvci4NCg0KYGBge3J9DQptIDwtIGMoLTEsMC4yNSwgMC4zLCAwLjQsIDAuNiwgMSkNCnZlZ2MgPC0gY2xhc3NpZnkoa2lhbWJ1X25kdmksIG0pDQpwbG90KHZlZ2MsIGNvbCA9IGMoInJlZCIsImJyb3duIiwib3JhbmdlIiwgInllbGxvdyIsICJncmVlbiIpLCBtYWluID0gJ05EVkkgYmFzZWQgdGhyZXNob2xkaW5nJykNCmBgYA0KDQojIyBDb25jbHVzaW9uDQoNClRoaXMgaXMgYSB2ZXJ5IHNtYWxsIHN1YnNldCBvZiB0aGUgaW5kaWNlcyB0aGF0IGFyZSB1c2VkIHdpdGggcmVtb3RlbHkgc2Vuc2VkIGltYWdlcy4gVGhlcmUgYXJlIGEgbnVtYmVyIG9mIGluZGljZWQgdGhhdCBhcmUgd2F5IG1vcmUgY29tcGxpY2F0ZWQgdGhhbiB0aGUgTkRWSS4gSG93ZXZlciwgYWxsIHRoZSBpbmRpY2VzIHRoYXQgeW91IGNob29zZSBzaG91bGQgaGF2ZSBhIHRoZW9yZXRpY2FsIGJhY2tpbmcgc28gdGhhdCB5b3UgdW5kZXJzdGFuZCBlaCBpbm5uZXIgd29ya2luZyBvZiB0aGVzZSBpbmRpY2VzLg0K