Library
library(terra) # loads the terra library
## terra 1.7.78
library(rpart) # loasd the recursive partitioning and regression tree library
Upload TIF File
rawImage <- rast("C:/Users/154455/Dropbox/2.dAILYr/R terra/LC08_016028_20210824.TIF")
Data Structure
rawImage
## class : SpatRaster
## dimensions : 2169, 3545, 19 (nrow, ncol, nlyr)
## resolution : 30, 30 (x, y)
## extent : 369645, 475995, 4982775, 5047845 (xmin, xmax, ymin, ymax)
## coord. ref. : WGS 84 / UTM zone 18N (EPSG:32618)
## source : LC08_016028_20210824.TIF
## names : SR_B1, SR_B2, SR_B3, SR_B4, SR_B5, SR_B6, ...
Plot TIF File
plot(rawImage)

Plot grey TIF File
plot(rawImage$SR_B5, col=gray(0:255 / 255))

Plot RGB
plotRGB(c(rawImage$SR_B4, rawImage$SR_B3, rawImage$SR_B2), stretch="lin")

Calculation
NDVI <- ((rawImage$SR_B5 - rawImage$SR_B4)/ (rawImage$SR_B5 + rawImage$SR_B4))
NDVI
## class : SpatRaster
## dimensions : 2169, 3545, 1 (nrow, ncol, nlyr)
## resolution : 30, 30 (x, y)
## extent : 369645, 475995, 4982775, 5047845 (xmin, xmax, ymin, ymax)
## coord. ref. : WGS 84 / UTM zone 18N (EPSG:32618)
## source(s) : memory
## varname : LC08_016028_20210824
## name : SR_B5
## min value : -0.1436602
## max value : 0.9495935
Histogram
hist(NDVI, xlab="NDVI", ylab="Frequency")
## Warning: [hist] a sample of 13% of the cells was used (of which 20% was NA)

Plot NDVI
plot(NDVI, col=rev(terrain.colors(10)), main="NDVI")

Raster
rast_nbrhds <- rast(NDVI)
rast_nbrhds
## class : SpatRaster
## dimensions : 2169, 3545, 1 (nrow, ncol, nlyr)
## resolution : 30, 30 (x, y)
## extent : 369645, 475995, 4982775, 5047845 (xmin, xmax, ymin, ymax)
## coord. ref. : WGS 84 / UTM zone 18N (EPSG:32618)
CRS
crs(NDVI)
## [1] "PROJCRS[\"WGS 84 / UTM zone 18N\",\n BASEGEOGCRS[\"WGS 84\",\n DATUM[\"World Geodetic System 1984\",\n ELLIPSOID[\"WGS 84\",6378137,298.257223563,\n LENGTHUNIT[\"metre\",1]]],\n PRIMEM[\"Greenwich\",0,\n ANGLEUNIT[\"degree\",0.0174532925199433]],\n ID[\"EPSG\",4326]],\n CONVERSION[\"UTM zone 18N\",\n METHOD[\"Transverse Mercator\",\n ID[\"EPSG\",9807]],\n PARAMETER[\"Latitude of natural origin\",0,\n ANGLEUNIT[\"degree\",0.0174532925199433],\n ID[\"EPSG\",8801]],\n PARAMETER[\"Longitude of natural origin\",-75,\n ANGLEUNIT[\"degree\",0.0174532925199433],\n ID[\"EPSG\",8802]],\n PARAMETER[\"Scale factor at natural origin\",0.9996,\n SCALEUNIT[\"unity\",1],\n ID[\"EPSG\",8805]],\n PARAMETER[\"False easting\",500000,\n LENGTHUNIT[\"metre\",1],\n ID[\"EPSG\",8806]],\n PARAMETER[\"False northing\",0,\n LENGTHUNIT[\"metre\",1],\n ID[\"EPSG\",8807]]],\n CS[Cartesian,2],\n AXIS[\"(E)\",east,\n ORDER[1],\n LENGTHUNIT[\"metre\",1]],\n AXIS[\"(N)\",north,\n ORDER[2],\n LENGTHUNIT[\"metre\",1]],\n USAGE[\n SCOPE[\"Navigation and medium accuracy spatial referencing.\"],\n AREA[\"Between 78°W and 72°W, northern hemisphere between equator and 84°N, onshore and offshore. Bahamas. Canada - Nunavut; Ontario; Quebec. Colombia. Cuba. Ecuador. Greenland. Haiti. Jamaica. Panama. Turks and Caicos Islands. United States (USA). Venezuela.\"],\n BBOX[0,-78,84,-72]],\n ID[\"EPSG\",32618]]"
Vector
nbrhds <- vect("C:/Users/154455/Dropbox/2.dAILYr/R terra/NeighbourhoodNDVI.gpkg")
NBRHDS
nbrhds_proj <- terra::project(nbrhds, "EPSG:32618") # reproject Neighbourhoods to UTM 18N
nbrhdIDrast <- rasterize(nbrhds_proj, rast_nbrhds, "ONS_ID")
Plot NBRHDS
plot(nbrhdIDrast)
lines(nbrhds_proj)

Zonal
NDVIbyNbrhd <- zonal(NDVI, nbrhdIDrast, "mean", na.rm=TRUE)
zonal(NDVI, nbrhdIDrast, "mean", na.rm=TRUE)
## ONS_ID SR_B5
## 1 3001 0.2718333
## 2 3002 0.2549597
## 3 3003 0.1818396
## 4 3004 0.2005813
## 5 3005 0.2509934
## 6 3006 0.3060857
## 7 3007 0.2427334
## 8 3008 0.1789586
## 9 3009 0.2088654
## 10 3010 0.2776771
## 11 3011 0.2790439
## 12 3012 0.2314434
## 13 3013 0.2249226
## 14 3014 0.2197906
## 15 3015 0.2414667
## 16 3016 0.2422117
## 17 3017 0.3026289
## 18 3018 0.2158740
## 19 3019 0.1583075
## 20 3020 0.1855722
## 21 3021 0.3573304
## 22 3022 0.2200641
## 23 3023 0.2223734
## 24 3024 0.1176931
## 25 3025 0.2633298
## 26 3026 0.2779497
## 27 3027 0.1877151
## 28 3028 0.1984221
## 29 3029 0.1898260
## 30 3030 0.1498353
## 31 3031 0.1942585
## 32 3032 0.2432974
## 33 3033 0.3161335
## 34 3034 0.2319828
## 35 3035 0.2305140
## 36 3036 0.2744971
## 37 3037 0.3933624
## 38 3038 0.3104095
## 39 3039 0.3747193
## 40 3040 0.2396934
## 41 3041 0.2756470
## 42 3042 0.3246351
## 43 3043 0.2117383
## 44 3044 0.2881309
## 45 3045 0.2030530
## 46 3046 0.3420093
## 47 3047 0.1776597
## 48 3048 0.2187456
## 49 3049 0.3208577
## 50 3050 0.3539877
## 51 3051 0.3185859
## 52 3052 0.2385591
## 53 3053 0.2198501
## 54 3054 0.2020800
## 55 3055 0.1505994
## 56 3056 0.2066737
## 57 3057 0.1994933
## 58 3058 0.2072209
## 59 3059 0.2034846
## 60 3060 0.2510204
## 61 3061 0.2229429
## 62 3062 0.3766720
## 63 3063 0.1987518
## 64 3064 0.1552076
## 65 3065 0.2096238
## 66 3066 0.2268546
## 67 3067 0.1461444
## 68 3068 0.1250520
## 69 3069 0.2382274
## 70 3070 0.3486916
## 71 3071 0.3640045
## 72 3072 0.3247830
## 73 3073 0.3913914
## 74 3074 0.3748339
## 75 3075 0.3263166
## 76 3076 0.4126848
## 77 3077 0.2253755
## 78 3078 0.3917863
## 79 3079 0.1727064
## 80 3080 0.2459583
## 81 3081 0.2741774
## 82 3082 0.1721655
## 83 3083 0.2062937
## 84 3084 0.1282868
## 85 3085 0.2276173
## 86 3086 0.3894057
## 87 3087 0.1762890
## 88 3088 0.1913196
## 89 3089 0.2119673
## 90 3090 0.2432336
## 91 3091 0.2947103
## 92 3092 0.2309628
## 93 3093 0.2190038
## 94 3094 0.2669745
## 95 3095 0.2179608
## 96 3097 0.2084639
## 97 3098 0.2339770
## 98 3099 0.2794043
## 99 3100 0.3032717
## 100 3101 0.1792289
## 101 3102 0.2833546
## 102 3103 0.2429410
## 103 3104 0.1529106
## 104 3105 0.1674837
## 105 3106 0.2355038
## 106 3107 0.2232746
## 107 3108 0.2241174
## 108 3109 0.2225854
## 109 3110 0.2465480
## 110 3111 0.1778035
## 111 3112 0.1507260
## 112 3113 0.4059962
## 113 3114 0.2657269
## 114 3115 0.1236391
## 115 3116 0.2027260
## 116 3117 0.2162043
Data
names(NDVIbyNbrhd)[2] <- "NDVI"
names(NDVI) <- "NDVI"
newNbrhds <- merge(nbrhds_proj, NDVIbyNbrhd)
newNbrhds[newNbrhds$NDVI == max(newNbrhds$NDVI)]$ONS_Name
## [1] "NAVAN - SARSFIELD"
Upload vector
lcpolys <- vect("D:/ICT Backup_154455/Downloads/SpatialR_SMexamples.gpkg")
Plot RGB
plotRGB(c(rawImage$SR_B4, rawImage$SR_B3, rawImage$SR_B2), stretch="lin")
polys(lcpolys)
text(lcpolys, lcpolys$LandCover)

Subset
LS8Image <- subset(rawImage, 1:9) # use just the first 9 bands in the source file
LS8Image
## class : SpatRaster
## dimensions : 2169, 3545, 9 (nrow, ncol, nlyr)
## resolution : 30, 30 (x, y)
## extent : 369645, 475995, 4982775, 5047845 (xmin, xmax, ymin, ymax)
## coord. ref. : WGS 84 / UTM zone 18N (EPSG:32618)
## source : LC08_016028_20210824.TIF
## names : SR_B1, SR_B2, SR_B3, SR_B4, SR_B5, SR_B6, ...
Sample data plot
set.seed(1) # create a seed for random number generation
trainingSamples<-spatSample(lcpolys, 600, method="random") # Sample 600 points randomly from the polygon data
plot(trainingSamples)

table(trainingSamples$LandCover)
##
## Builtup Crops Parkland Residential Water Wetlands
## 40 133 208 28 128 63
sampledImage <- extract(LS8Image, trainingSamples, ID=FALSE)
head(sampledImage)
## SR_B1 SR_B2 SR_B3 SR_B4 SR_B5 SR_B6 SR_B7 SR_QA_AEROSOL ST_B10
## 1 8738 9005 9821 9783 15483 13011 10980 96 48595
## 2 8245 8227 8899 8214 19546 13068 9574 96 45097
## 3 7294 7432 7687 7567 7600 7552 7516 164 44357
## 4 8426 8564 9427 8815 23238 14026 10162 96 46170
## 5 8366 8447 9122 8754 20449 14078 10395 96 46425
## 6 7328 7469 7766 7656 7647 7591 7563 164 44290
sampData <- data.frame(class = trainingSamples$LandCover, sampledImage)
head(sampData)
## class SR_B1 SR_B2 SR_B3 SR_B4 SR_B5 SR_B6 SR_B7 SR_QA_AEROSOL ST_B10
## 1 Residential 8738 9005 9821 9783 15483 13011 10980 96 48595
## 2 Parkland 8245 8227 8899 8214 19546 13068 9574 96 45097
## 3 Water 7294 7432 7687 7567 7600 7552 7516 164 44357
## 4 Crops 8426 8564 9427 8815 23238 14026 10162 96 46170
## 5 Crops 8366 8447 9122 8754 20449 14078 10395 96 46425
## 6 Water 7328 7469 7766 7656 7647 7591 7563 164 44290
rpart
cartmodel <- rpart(as.factor(class)~., data=sampData, method='class', minsplit=5)
print(cartmodel)
## n= 600
##
## node), split, n, loss, yval, (yprob)
## * denotes terminal node
##
## 1) root 600 392 Parkland (0.067 0.22 0.35 0.047 0.21 0.1)
## 2) SR_B3>=8281 472 264 Parkland (0.085 0.28 0.44 0.059 0 0.13)
## 4) ST_B10< 45285 202 6 Parkland (0 0.03 0.97 0 0 0)
## 8) SR_B5>=26179.5 4 0 Crops (0 1 0 0 0 0) *
## 9) SR_B5< 26179.5 198 2 Parkland (0 0.01 0.99 0 0 0) *
## 5) ST_B10>=45285 270 143 Crops (0.15 0.47 0.044 0.1 0 0.23)
## 10) SR_B5>=18695.5 119 6 Crops (0.017 0.95 0.017 0.017 0 0) *
## 11) SR_B5< 18695.5 151 88 Wetlands (0.25 0.093 0.066 0.17 0 0.42)
## 22) SR_B2>=8319.5 74 36 Builtup (0.51 0.12 0.041 0.32 0 0)
## 44) ST_B10>=48752 37 0 Builtup (1 0 0 0 0 0) *
## 45) ST_B10< 48752 37 13 Residential (0.027 0.24 0.081 0.65 0 0)
## 90) SR_B6>=14142 10 1 Crops (0 0.9 0 0.1 0 0) *
## 91) SR_B6< 14142 27 4 Residential (0.037 0 0.11 0.85 0 0) *
## 23) SR_B2< 8319.5 77 14 Wetlands (0 0.065 0.091 0.026 0 0.82)
## 46) ST_B10< 46442.5 16 9 Parkland (0 0.31 0.44 0.063 0 0.19)
## 92) ST_B10< 45602.5 7 0 Parkland (0 0 1 0 0 0) *
## 93) ST_B10>=45602.5 9 4 Crops (0 0.56 0 0.11 0 0.33) *
## 47) ST_B10>=46442.5 61 1 Wetlands (0 0 0 0.016 0 0.98) *
## 3) SR_B3< 8281 128 0 Water (0 0 0 0 1 0) *
plot(cartmodel, uniform=TRUE, main="Classification Tree")
text(cartmodel, cex = 1)

Plot Classify
classify <- predict(LS8Image, cartmodel, na.rm=TRUE) # will take some time
## |---------|---------|---------|---------|=========================================
plot(classify)

Landcover
landcover <- which.max(classify)
landcover
## class : SpatRaster
## dimensions : 2169, 3545, 1 (nrow, ncol, nlyr)
## resolution : 30, 30 (x, y)
## extent : 369645, 475995, 4982775, 5047845 (xmin, xmax, ymin, ymax)
## coord. ref. : WGS 84 / UTM zone 18N (EPSG:32618)
## source(s) : memory
## name : which.max
## min value : 1
## max value : 6
Plot
myClasses <- c("Built-up", "Crops", "Parkland", "Residential", "Water", "Wetlands")
levels(landcover) <- data.frame(id = 1:6, class=myClasses)
mycolors <- c("red", "lightgreen","darkgreen","yellow","blue","brown")
plot(landcover, col=mycolors)

For value
k <- 10 # number of times to cross-validate (k-fold cross-validation)
j <- sample(rep(1:k, each = round(nrow(sampData))/k))
resultList <- list() # create a new empty list to hold each validation result
for (x in 1:k) {
train <- sampData[j != x, ]
validation <- sampData[j == x, ]
# Create a CART model as above but with new training subset
cartmodel <- rpart(as.factor(class)~., train, method = 'class', minsplit = 5)
pclass <- predict(cartmodel, validation, na.rm = TRUE)
# assign class to maximum probablity
pc <- apply(pclass, 1, which.max)
# use labels instead of numbers
pc <- colnames(pclass)[pc]
# create a data.frame using the reference and prediction
resultList[[x]] <- cbind(validation$class, pc)
}
# create a data.frame of results based on the lists we just created
resultDF <- do.call(rbind, resultList)
resultDF <- data.frame(resultDF)
colnames(resultDF) <- c('observed', 'predicted')
# confusion matrix
conmat <- table(resultDF)
print(conmat)
## predicted
## observed Builtup Crops Parkland Residential Water Wetlands
## Builtup 35 3 0 1 0 1
## Crops 0 121 7 1 0 4
## Parkland 0 4 202 2 0 0
## Residential 1 3 0 21 0 3
## Water 0 0 0 0 128 0
## Wetlands 0 4 0 4 0 55
Calculate overall accuracy
# Calculate overall accuracy
totalSamples <- sum(conmat)
diagonal <- diag(conmat)
overallAcc <- sum(diagonal) / totalSamples
Summary
summary(zonal(NDVI, classify, "mean", na.rm=TRUE))
## Builtup Crops Parkland Residential
## Min. :0.0000 Min. :0.000000 Min. :0.00000 Min. :0.000000
## 1st Qu.:0.0000 1st Qu.:0.000000 1st Qu.:0.00000 1st Qu.:0.000000
## Median :0.0000 Median :0.005051 Median :0.00000 Median :0.008197
## Mean :0.1054 Mean :0.341524 Mean :0.21178 Mean :0.109616
## 3rd Qu.:0.0126 3rd Qu.:0.813889 3rd Qu.:0.08754 3rd Qu.:0.079202
## Max. :1.0000 Max. :1.000000 Max. :1.00000 Max. :0.851852
## Water Wetlands NDVI
## Min. :0.0 Min. :0.0000 Min. :0.02458
## 1st Qu.:0.0 1st Qu.:0.0000 1st Qu.:0.25814
## Median :0.0 Median :0.0000 Median :0.32840
## Mean :0.1 Mean :0.1317 Mean :0.30390
## 3rd Qu.:0.0 3rd Qu.:0.0000 3rd Qu.:0.37446
## Max. :1.0 Max. :0.9836 Max. :0.52672