I have a large three dimensional array corresponding to a hyperspectral cube in spatRaster format. I also have two smaller ones (smaller area) that correspond to reference images (dark and white) used to correct values in the pixels of the cube. The smaller ones only have one line of pixels and were originally spatRasters but were transformed to array format to do some calculations. Lastly, I have a couple of constants.
For each line in the sample image, I need to subtract the line of pixels in dark image from the line of pixels in the sample image and then divide it by the line of pixels in the white image. Then, multiply by the constants and store the corrected line in a new array that eventually becomes a corrected spatRaster.
I wrote a script that does this as follows:
#hyperspectral cube
nlines_s <- 1412 #number of lines of pixels in the image
npixels_s <- 1024 #number of pixels within each line
nbands_s <- 448 #number of spectral bands within each pixel
sample_image <- terra::rast(array(runif(1),dim = c(nlines_s ,npixels_s ,nbands_s )))
# spatRasters already transformed to array type
dark_current <- array(runif(1),dim = c(1024,448))
white_reference <- array(runif(1),dim = c(1024,448))
#integration time constants
t_s <- 13
t_w <- 13
int_time <- t_w/t_s
#reflectance of reference material
R_ref <- 0.99
#Process that needs to be speed up
reflectance_image <- array(0, c(nlines_s,npixels_s,nbands_s ))
for (fr in 1:nlines_s) {
reflectance_image[fr, , ] <- as.matrix(R_ref * int_time * ((sample_image[fr, ,]-dark_current)/white_reference) )
print(paste0("Calculating reflectance: ",round((fr/nlines_s)*100,2), "%"))
}
ri_r <- terra::rast(reflectance_image)
names(ri_r) <- names(sample_image)
The code works as is, but it takes a long time because of the sequential nature of the for loop. I suspect this can be optimized by applying the calculation to all the lines (rows) of the image at the same time. I've been trying to do so using apply functions but I have not succeeded (might have done it wrong, though).
What would be the solution that would speed up the processing time the most?
This may not be the absolute most optimal, but a simple RcppArmadillo function that takes base R arrays instead of SpatRaster objects speeds it up by almost an order of magnitude. Using @RoberHijmans larger dataset (with 448 bands) and
f3
:Note that the two solutions will be very slightly different due to the different order of the multiplications.