bleutner/RStoolbox

rescaleImage ignoring ymin and ymax?

Opened this issue · 7 comments

Doing:

> ima <- raster(matrix(rnorm(n=10^4,m=0,sd=2)))
> cellStats(ima,range)
[1] -7.437958  7.845097
> q <- quantile(ima,probs=c(0.02,0.98))
> q
       2%       98% 
-4.168026  4.168633 
> ima2 <- rescaleImage(ima,xmin=q[1],xmax=q[2],ymin=0,ymax=255,forceMinMax = TRUE)
> cellStats(ima2,range)
[1] -100.0200  367.4549

I was expecting ima2 to be rescaled from range -7.437958 , 7.845097 -4.168026, 4.168633 to 0, 255
Am I misunderstanding the doc or is there an error?

rescaleImage is working correctly.
xmin and xmax are only needed if the values in the input raster do not contain the theoretical min and max values. As documented, this could be the case if you have NDVI values ranging from -0.2 to 0.6, for example, but the theoretical value range is -1 to 1. In this case you would want to specify xmin and xmax.

In your example, the data values exceed the theoretical min and max you provide and the rescaling is ill-defined and will inevitably result in values outside of the specified ymin:ymax range.
I guess what you actually wanted to accomplish is this:

imc  <- clamp(ima, lower=q[1],upper=q[2])  # check ?raster::clamp for the useValues argument
ima2 <- rescaleImage(imc, xmin=q[1], xmax=q[2], ymin=0, ymax=255, forceMinMax = TRUE)
cellStats(ima2,range)
#> 0 255

It is not inevitable, it just needs to clamp the output to conform to the specified ymin, ymax range.
In effect, what I want to do is what you do in the 2 commands: I expected the clamp was done by default to conform to the specified ymin, ymax range.
I understand the same result can be obtained with
clamp(rescaleImage(ima, xmin=q[1], xmax=q[2], ymin=0, ymax=255, forceMinMax = TRUE), lower=0,upper=255)

but including the clamp as an option within rescaleImage() would be more efficient for large raster brick objects and certainly easier for the user.

That is correct of course. Yet, if you clamp beforehand, you have the choice to set all values exceeding the quantiles to NA, if you so wish. But I agree, that option can be added to rescaleImage.

Good we finally agree! Should I fill another ticket with that request or is this one sufficient?
Agus

No, this one is sufficient.

I've deleted my last comment, I was mixing things up with raster::stretch() (which works now, see
rspatial/raster#70 )

Thanks to a recent improvemnt of raster::clamp(),
rspatial/raster#120

r <- raster(ncols=12, nrows=12)
values(r) <- 1:ncell(r)
b <- brick(r,r*2,r/2)
q <- quantile(b,probs=c(0.02,0.98))

> q
          2%    98%
layer.1 3.86 141.14
layer.2 7.72 282.28
layer.3 1.93  70.57
b2 <- clamp(b,lower=q[,1], upper=q[,2],useValue=TRUE)
cellStats(b2,range)
     layer.1 layer.2 layer.3
[1,]    3.86    7.72    1.93
[2,]  141.14  282.28   70.57

b4 <- rescaleImage(clamp(b,lower=q[,1], upper=q[,2],useValue=TRUE),
+                    xmin=q[,1], xmax=q[,2], ymin=1, ymax=255, forceMinMax = TRUE)
cellStats(b4,range)
     layer.1 layer.2 layer.3
[1,]       1       1       1
[2,]     255     255     255