If the original data was rescaled to 8-bit it should be 0-255 and not 0-200. That aside you can take a normalization approach but shift the centrality over so the distribution will bound into the negative. Two normalization formulas that will do this are:
Formula 1: [(x - "x min") / ("x max" - "x min") - 0.5) * 2]
Formula 2: ["new min" + (x - "x min") * (("new max" - "new min") / ("x max" - "x min"))]
In R parlance these are easy formulas to translate to code. Here we create a random vector ranging 0-200 and plot the distribution.
x <- round(runif(100,0,200),0)
plot(density(x), xlim=c(0,200))
We then normalize the data, using the first formula, so it ranges -1 to 1 and check to make sure that the distribution did not change shape.
x.scale <- ((x - min(x)) / (max(x) - min(x)) - 0.5 ) * 2
plot(density(x.scale), xlim=c(-1,1))
To apply this to a raster we can use exactly the same logic and syntax. To pull the min and max raster values we use cellStats
.
library(raster)
r <- raster(nrows=100, ncols=100)
r[] <- round(runif(ncell(r), 0, 200),0)
r.min = cellStats(r, "min")
r.max = cellStats(r, "max")
r.scale <- ((r - r.min) / (r.max - r.min) - 0.5 ) * 2
r.scale
plot(r.scale)
Here is the second formula put into a rescale function that would work, given the correct arguments, if passed to calc
. It should work with a single value or a vector distribution. The examples illustrate normalizing single values into the expected distribution based on the definition of current and defined min and max values.
rescale <- function(x, x.min = NULL, x.max = NULL, new.min = 0, new.max = 1) {
if(is.null(x.min)) x.min = min(x)
if(is.null(x.max)) x.max = max(x)
new.min + (x - x.min) * ((new.max - new.min) / (x.max - x.min))
}
rescale(200, x.min = 0, x.max = 200, new.min = -1, new.max = 1)
rescale(100, x.min = 0, x.max = 200, new.min = -1, new.max = 1)
rescale(0, x.min = 0, x.max = 200, new.min = -1, new.max = 1)