# Classification of the Hyper-Spectral and LiDAR Imagery using R (mostly). Part 3: Shadow Removal

May 8, 2014
By

(This article was first published on Misanthrope's Thoughts, and kindly contributed to R-bloggers)

This is my third post in this series, here are the links to the Part 1 and Part 2. Sorry for the delay, but at that time I got completely consumed with my PhD thesis and this story just went out of my mind.

To the point. There were 2 types of shadows I had to deal with: cloud shadows and cast shadows (from building and trees). In scientific literature you can find several relatively complicated algorithms to deal with them (including DEM usage for cast shadow detection) and I definitely should have used some of them, but... I was too lazy to implement them when there were couple of quick'n'dirty workarounds available.

To remove cloud shadows I decided to calculate ratio between mean pixel value of the lighted up and shadowed parts of the raster for each band and multiply shadowed pixels by this ratio.  I manually created a mask for shadowed areas. There were 3 areas and their borders were quite distinct in NIR channels:

 Cloud shadows in one of the NIR bands

I drew several polygons over shadows in QGIS and converted them to raster (Raster -> Conversion -> Rasterise). Now everything was ready for patching:

library(raster)library(rgdal)# load rastersimage <- stack('2013_IEEE_GRSS_DF_Contest_CASI.tif') # hyper spectral imagerys_mask <- raster('shadow_mask.tif') # mask for cloud shadow# extract shadowed aream_cloud <- s_maskm_cloud[m_cloud < 1] <- NAshadowed <- mask(image, m_cloud)# calculate zonal statisticszd <- zonal(image, s_mask, fun = 'mean', na.rm = T)zd <- as.data.frame(zd)# calculate ratio between lighted up and shadowed zoneszd[3,] <- zd[1,] / zd[2,] # recalculae data in shadowsmultiplyer <- zd[3,]multiplyer <- multiplyer[,2:ncol(zd)]multiplyer <- as.numeric(multiplyer)enlight <- shadowed*multiplyer # patch layerrestored <- cover(enlight, image, progress = 'text')# save resultwr <- writeRaster(restored,                   filename = 'restored.tif',                   datatype = 'GTiff', overwrite = TRUE)

Now it's time to check out results:

 The same NIR band after cloud shadow removal
Yes, we can easily find patched areas, but overall result is good for such simple approach.

Shadows from buildings can be processed the same way as cloud shadows as shown above except mask creation approach is different. In case of cast shadows they have to be detected automatically (for there are a bit more than 3 as in case with clouds). Using one of the NIR bands I created a learning sample of points and passed it to Random Forest algorithm to classify imagery into shadowed and non-shadowed areas. I will not describe here this classification process for Random Forest was used for overall classification of the imagery and it is the subject of my next post of this series.