#####################################################################
## Image enhancement and jellyfish counting using drone imagery    ## 
## Heloise HAMEL & Sebastien LHOUMEAU                              ##
## Released : 20/04/2021                                           ##
#####################################################################
# REFERENCES:
# 
# Oles, A., Pau, G., Sklyar, O., Huber, W., 2015. Introduction to EBImage 13.
# Available online: https://bioconductor.riken.jp/packages/3.1/bioc/vignettes/EBImage/inst/doc/EBImage-introduction.pdf
# (accessed on 30-10-2020)
#
# Holmes, S., Huber, W., 2021. 11 Image data | Modern Statistics for Modern Biology.
# Available online: https://www.huber.embl.de/msmb/Chap-Images.html
# (accessed on 30-10-2020)
#
# Pau, G., Fuchs, F., Sklyar, O., Boutros, M., Huber, W., 2010. "EBImage-an R package for image processing with 
# applications to cellular phenotypes." Bioinformatics, 26(7), 979-981. doi: 10.1093/bioinformatics/btq046.
#
#####################################################################

# sessionInfo()
# # R version 3.6.3 (2020-02-29)
# # Platform: x86_64-w64-mingw32/x64 (64-bit)
# # Running under: Windows 10 x64 (build 19041)
# 
# ## Package installation EBIMAGE :
# if (!requireNamespace("BiocManager", quietly = TRUE))
#   install.packages("BiocManager")
# #BiocManager::install(version = "3.11")
# BiocManager::install("EBImage")

# ## Package installation Progress
# install.packages("progress")

library(EBImage)
library(progress)


## Loading image :
## EXAMPLE for STATION 1
station = "mydata/Station1"
# station = "mydata/Station2"
# station = "mydata/Station3"

## Read image
name = "DJI_0121-cut.JPG"
# name = "DJI_0144-cut.JPG"
# name = "DJI_0167-cut.JPG"

entry_path = paste(station,name, sep = "/")
file = readImage(entry_path, type = "jpeg")
file_save <- file #save original RVB image


##Automatic enhancement parameter determination:

gam0 <-exp(7.25*min(file) - 1.40) 
#Empirical relation between gamma and the minimum of greyscale value of the image.
#Based on the determination of the value of the gamma which provide the same counting result as observations, a linear regression has been made to obtain a formula to automatically determine the best gamma value to take.
#This regression has been showed to be the most significant between the log gamma value and the minimum of grayscale value with a multiple R-squared : 0.994.

##Repetition index initialisation:
res <- list() #result variable


##Definition base counting function
detection <- function(gam){
##Image enhancement :
file <- normalize(file_save, ft = c(0,1)) # normalize the histogram
file <- ((file)^gam)*3.5 #enhance contrast

#display(file, method = "raster")

## Segmentation of individuals using adaptive threshold

img_thr = thresh(file, w=15, h=15, offset=0.04) 
# adjust offset to reduce most of the noise
# w and h = Half width and height of the moving rectangular window
# offset = Thresholding offset from the averaged value
#display(img_thr, method = "raster")

#Cleaning signals:

kern <- makeBrush(5, shape='box') #Generate a brush to be used as structuring elements
mask <- opening(img_thr, kern)
#Two steps operation :
#1: applies the mask kern by positioning its center over every pixel of the image and setting it to background if any of the pixels covered by the mask is from the background
#2: applies the mask kern by positioning its center over every pixel of the image and setting it to foreground if any of the pixels covered by the mask is from the foreground

#display(mask, method = "raster")

## Distinction of single individuals
# The watershed algorithm uses a grayscale image as a heightmap depending on pixel intensity. 
# Objects that stand out of the background are identified and separated by flooding an inverted source image.

nmask = watershed(distmap(mask), ext=5 ) #ext = Radius of the neighborhood in pixels for the detection of neighboring objects


img_ws <- colorLabels(nmask, normalize=TRUE) #color scale only for visualization
#display(img_ws)

img_ws2 <- colorLabels(nmask, normalize=FALSE) #return to binary image for counting
#display(img_ws2)

# Counting of all objects
#cat('Number of jellies =', max(img_ws2), '\n')
max(img_ws2)
}

##Function repetition :
#100 replicates are performed by varying the gamma between -0.5 + gam0 and + 0.5 + gam0

#Initialisation
gam <- gam0 - 0.5

#Progress bar
#pb <- txtProgressBar(min = 1, max = 100, style = 3)
pb <- progress_bar$new(
  format = "  Completed [:bar] :percent in :elapsedfull",
  total = 100, clear = FALSE, width= 100)

#loop:
for (i in 1:100) {
  res <- append(res, detection(gam)) #Store result
  gam <- gam + 0.01 #increase gamma value
  pb$tick() #progress bar incrementation
}

##Displaying final result
#Results are a mean numbre of jelly fish detected in the image and a 95% confidence interval based on statistical analysis of 100 replicates
res <- as.data.frame(do.call("rbind", res))
int <- t.test(res$V1)

cat('Mean Number of jellies =', mean(res$V1), '\n','Confidence interval (95%) =', int$conf.int, '\n')