DATE: 2018-09-07
AUTHOR: John L. Godlee
layout: post title: "A guide about processing hemispherical photos" date: 2018-09-07
I wrote a guide for some undergraduate students on a field course about hemispherical photography and calculating forest canopy traits. This is it. It's untested so far, so some parts may change depending on how well the field course goes. The guide may get updated, so the most up to date version can always be found here, on Github[1].
=> 1: https://github.com/johngodlee/hemi_photo_guide
A list of tips for taking good hemispherical photos:
The above process can be automated with a macro, but this assumes that the images are all uniformly exposed.
This is the macro, saved as a .ijm file. This is untested so use at your own risk:
// Automatically create a thresholded image for use in further analysis. Change the values of setThreshold to achieve different results. // Partially tested // Save as a Jpeg in the Batch macro dialog in ImageJ run("8-bit"); run("Threshold..."); setThreshold(0, 146); setOption("BlackBackground", false); run("Convert to Mask");
Open RStudio.
Open a new script (File -> New File -> R Script)
Save the script in a folder above the images folder:
Enter the following preamble into the R script:
# Set working directory to location of thresholded images setwd("LOCATION_OF_ANALYSIS") # Source the functions used to calculate stuff source("hemiphot.R") # Packages library(jpeg)
# List all images in the directory all_images <- list.files("img/", pattern = ".JPG") # How many images img_length = length(all_images) # Create empty dataframe, 6x7 and fill it with zeroes all_data = data.frame(matrix(data = 0, nrow = img_length, ncol = 7)) names(all_data) = c("File", "CanOpen", "LAI", "DirectAbove", "DiffAbove", "DirectBelow", "DiffBelow") # Fill first column with image names all_data[,1] = all_images
white_img <- readJPEG("img/white_image.jpg", native = F)
location.latitude = -15 location.altitude = 200 location.day = 30 location.days = seq(15,360,30) # roughly each mid of the 12 months
## Image parameters ### Drawing circles and identifying the image centre point hemi_dim <- dim(white_img) radius <- max(rowSums(white_img[,,1] > 0.4) / 2) ### determine using a single image and fill in here for batch processing location.cx = (hemi_dim[2] / 2) # x coordinate of center of image location.cy = (hemi_dim[1] / 2) # y coordinate of center image location.cr = radius # radius of circle location.threshold = 0.42 # Must get this to match all images, or maybe could use a lookup table / dictionary? Does R have dictionaries?
# atmospheric parameters ## Atmospheric transmissivity - Normally set at 0.6, but can vary between 0.4-0.6 in the tropics location.tau = 0.6 ## Amount of direct light that is used as diffuse light in the Uniform Ovecast Sky (UOC) location.uoc = 0.15
for(i in 1:img_length){ ## read file image <- readJPEG(paste("test_img/", all_images[i], sep = ""), native = F) ## conver to Hemi image image <- Image2Hemiphot(image) ## set cirlce parameters image <- SetCircle(image, cx = location.cx, cy = location.cy, cr = location.cr) ## select blue channel image <- SelectRGB(image, "B") #threshold image <- ThresholdImage(im = image, th = location.threshold, draw.image = F) # canopy openness gap.fractions <- CalcGapFractions(image) all_data[i,2] = CalcOpenness(fractions = gap.fractions) ## calculate LAI according to Licor's LAI Analyzer all_data[i,3] = CalcLAI(fractions = gap.fractions) ## Photosynthetic Photon Flux Density (PPDF, umol m-1 s-1) P rad <- CalcPAR.Day(im = image, lat = location.latitude, d = location.days, tau = location.tau, uoc = location.uoc, draw.tracks = F, full.day = F) all_data[i,4] = rad[1] all_data[i,5] = rad[2] all_data[i,6] = rad[3] all_data[i,7] = rad[4] }
all_data
The hemiphot.R source file comes from here[2].
=> 2: https://github.com/naturalis/Hemiphot This content has been proxied by September (3851b).Proxy Information
text/gemini