Load Libraries and Images

## Libraries
library(raster)
library(rgdal)
library(rgeos)
library(randomForest)
library(dismo)
library(tidyverse)

## load functions
source("functions.r")

## Load snow image
snow <- brick("images//JumpingPound2012.tif")
plotRGB(snow, stretch = "lin")

## Load meadows
meadows <- readOGR("data//shapeFile//meadowOutline.shp")
## OGR data source with driver: ESRI Shapefile 
## Source: "D:\RStudio\AlpineSnowClassifier\data\shapeFile\meadowOutline.shp", layer: "meadowOutline"
## with 20 features
## It has 2 fields
## Integer64 fields read as strings:  id
## reproject meadows to be same CRS as raster
meadows <- spTransform(meadows, crs(snow))


## create butter around meadows to capture entire area
# plot(meadows)
buffMeadow <- gBuffer(meadows, byid=T,  width=10)
plot(buffMeadow)
plot(meadows, add=T)

## Convert meadow names to characters
buffMeadow$meadow <- as.character(buffMeadow$meadow)
buffMeadow$meadow[buffMeadow$meadow=="g"] <- "littleg"
meadowList <- buffMeadow$meadow
meadowList <- meadowList[!meadowList %in% c("E","D","C")] ## drop Lusk

Example of classifying an individual pixel as snow, forest, rock/bare ground

## Extract a meadow
i=1 ## meadow Z
meadowList[i]
## [1] "Z"
snowMeadow <- crop(snow, buffMeadow[buffMeadow$meadow == meadowList[i],])
snowMeadow <- mask(snowMeadow, buffMeadow[buffMeadow$meadow == meadowList[i],])



## Place 100 random samples to classify
set.seed(11)
spTrain <- sampleRandom(snowMeadow, 100, sp=T)

## Plot locations of pixel
plotRGB(snowMeadow, stretch = "lin")
text(x=coordinates(spTrain)[,1], y=coordinates(spTrain)[,2], labels=1:100)

## Zoom in on a single pixel to classify
j = 1
range = 30 ## range of plot in metres

plotRGB(crop(snowMeadow, extent(
  coordinates(spTrain)[j,1]-range,  ## xmin
  coordinates(spTrain)[j,1]+range,  ## xmax
  coordinates(spTrain)[j,2]-range,  ## ymin
  coordinates(spTrain)[j,2]+range)))  ## ymax
plot(spTrain[j,], add=T)

## Create datatable based on classifications

Apply classified data using Random Forest

### Load classified data
meadowFiles <- list.files("data//snowClass//", pattern=".csv", full.names=T)
trainData <- data.frame()
for(i in 1:length(meadowFiles)){
  temp <- read.table(meadowFiles[i],  header=T, sep=",")
  trainData <- rbind(trainData, temp)
}

## Conduct random forest on RGB values
rf1 <- randomForest(class ~ JumpingPound2012.1 + JumpingPound2012.2 + JumpingPound2012.3, data=trainData)
rf1
## 
## Call:
##  randomForest(formula = class ~ JumpingPound2012.1 + JumpingPound2012.2 +      JumpingPound2012.3, data = trainData) 
##                Type of random forest: classification
##                      Number of trees: 500
## No. of variables tried at each split: 1
## 
##         OOB estimate of  error rate: 20%
## Confusion matrix:
##        forest rock snow class.error
## forest     63   14   13  0.30000000
## rock       15   52   27  0.44680851
## snow       16   15  285  0.09810127
## Predict the land cover based on random forest
landCover <- predict(snowMeadow, rf1)

## Plot output with map
par(mfrow=c(1,2))
plotRGB(snowMeadow)
plot(landCover, col=c("green","grey50","white"))

## Determine percent cover of snow
length(landCover[landCover==3])/sum( ## Percent snow cover = snow pixels / (snow pixels + bare ground pixels)
length(landCover[landCover==2]),
length(landCover[landCover==3]))
## [1] 0.6917295

Model validation for snow only

## create snow vs no snow
trainData[,"snowPA"] <- ifelse(trainData$class=="snow",1,0)
colnames(trainData)[3:5] <- c("Red","Green","Blue") ## revise names to RGB

 ## withhold 20% for sample testing
pres <- trainData[trainData$snowPA==1,]
abs <- trainData[trainData$snowPA==0,]
fold.p <- kfold(pres, k=5)
occtest.p <- pres[fold.p == 4, ]
occtrain.p <- pres[fold.p != 4, ]
fold.a <- kfold(abs, k=5)
occtest.a <-abs[fold.a == 4, ]
occtrain.a <- abs[fold.a != 4, ]
    
## Combine training
trainAll <- rbind(occtrain.p,occtrain.a)
testAll <- rbind(occtest.p,occtest.a)

## Evaluate the random forest
rf2 <- randomForest(snowPA ~ Red + Green + Blue, data=trainAll, importance=T)
rf2
## 
## Call:
##  randomForest(formula = snowPA ~ Red + Green + Blue, data = trainAll,      importance = T) 
##                Type of random forest: regression
##                      Number of trees: 500
## No. of variables tried at each split: 1
## 
##           Mean of squared residuals: 0.1069126
##                     % Var explained: 54
varImpPlot(rf2)

eval1 <- evaluate(occtest.p, occtest.a, rf2)
eval1
## class          : ModelEvaluation 
## n presences    : 63 
## n absences     : 37 
## AUC            : 0.9086229 
## cor            : 0.7028173 
## max TPR+TNR at : 0.8067667
eval1@pcor
## [1] 3.625944e-16
## Determine threshold value
specSens <- threshold(eval1, stat="spec_sens")
specSens
## [1] 0.8067667
## confusion matrix
predictTest <- ifelse(predict(rf2, newdata =testAll)>specSens, 1,0)

conTable <- table(predicted = predictTest, observed = testAll$snowPA)
conTable
##          observed
## predicted  0  1
##         0 34 14
##         1  3 49
accuracy <- sum(diag(conTable))/nrow(testAll)
accuracy
## [1] 0.83

Compare estimated percentages with visual and snow pillow

## Rename raster
names(snow) <-  c("Red","Green","Blue") ## revise names to RGB

## set up Random forest
rf1 <- randomForest(class ~ Red + Green + Blue, data=trainAll, importance=T)
rf1
## 
## Call:
##  randomForest(formula = class ~ Red + Green + Blue, data = trainAll,      importance = T) 
##                Type of random forest: classification
##                      Number of trees: 500
## No. of variables tried at each split: 1
## 
##         OOB estimate of  error rate: 21.5%
## Confusion matrix:
##        forest rock snow class.error
## forest     53   12    8   0.2739726
## rock       15   35   24   0.5270270
## snow       11   16  226   0.1067194
## Extract meadow cover for each meadow
getSnow <- function(j){
  meadowTemp <- crop(snow, j)  ## mask meadow from larger image
  meadowTemp <- mask(meadowTemp, j)
  meadowSnow <- predict(meadowTemp, rf1)
  ## Determine percent cover of snow
  snowPer <- freq(meadowSnow, value=3)/(freq(meadowSnow, value=3) + freq(meadowSnow, value=2)) ## snow / (snow+rock) i.e. omit forest
  return(snowPer)
}

## Snow percent
library(foreach)
library(doParallel)

cl <- makeCluster(6, type="PSOCK")
registerDoParallel(cores = cl)
meadowCover <- foreach(j = 1:17, .combine=c, .packages=c("raster","rgdal","randomForest")) %dopar% {
  getSnow(buffMeadow[buffMeadow$meadow == meadowList[j],])
}

## Snow cover
estSnow <- data.frame(year = 2012,  meadow = meadowList, snowCover=meadowCover)

## Compare with visual data

## Load visual data
Tempdata <- read.csv("data//snowData.csv", stringsAsFactors = F)
visual2012 <- Tempdata  %>% filter(year==2012) %>% select(meadow, percent) 
visual2012[visual2012$meadow=="g1","meadow"] <- "littleg"

## Join with modelled cover
bothEstimates <- merge(estSnow, visual2012, by="meadow")

## determine correlation
corVal <- cor(bothEstimates$snowCover, bothEstimates$percent)
corVal
## [1] 0.588996
## Plot patterns
ggplot(bothEstimates, aes(x=snowCover*100, y=percent)) + geom_point(size=3) + theme_Publication() + xlab("Random forest predicted snow cover (%)") + ylab("Visual estimate snow cover (%)") + annotate("text", x = 55, y = 95, label = "Meadows in 2012", size=8, hjust = 0) + annotate("text", x = 55, y = 90, label = paste0("cor = ",round(corVal,2)), size=6, hjust = 0)