Colorblend relative to image values


#1

Hello! I have the code below, I am trying to get the colormap stretched to the min and max values of the queried image, but I can not figure out how to obtain those values.

The code below is for the non stretched image, if i dow the strectching the array of values in colorBlend should be something like this colorBlend(val,[min, min+step, min+step2,min+step3,min+step*4,max],…)

How can I obtain min and max?

Thanks!

function evaluatePixel(samples) {
let val = index(samples[0].B08, samples[0].B04);
return colorBlend(val,[0, 0.2, 0.4, 0.6, 0.8, 1],
[[0.815, 0.450, 0.345],
[0.815, 0.666, 0.345],
[0.815, 0.807, 0.345],
[0.745, 0.815, 0.345],
[0.549, 0.815, 0.345],
[0.439, 0.815, 0.345]]);;
}

function setup(ds) {
setInputComponents([ds.B04, ds.B08]);
setOutputComponentCount(3);
}


#2

Basic processing is done on the pixel level and during code execution the min and max of overall area (e.g. neighboring pixels) is not known.
What you can do is to do it in two steps:

  1. First you use statistical API to get min and max of the area
  2. Then you “encode” these min and max values in Custom script and pass it as an EVALSCRIPT parameter in the WMS/WCS request.

If you provide me an example of the URL request you would like to do with the script above (e.g. geometry, time parameters), I can write down these steps more concretely.


#3

Hello Grega!

That would be so nice, here is an example of the url query

https://services.sentinel-hub.com/ogc/wms/{INSTANCE_ID}?SERVICE=WMS&REQUEST=GetMap&VERSION=1.3.0&TIME=2018-09-10&LAYERS=RELATIVEEVI&RESX=10m&RESY=10m&CRS=EPSG:4326&TRANSPARENT=1&FORMAT=image/png&GEOMETRY=POLYGON((-32.28555%20-64.23295,-32.28555%20-64.22177,-32.29489%20-64.22177,-32.29489%20-64.23295,-32.28555%20-64.23295))

Edit 15:24 UTC-3

I made this url
http://services.sentinel-hub.com/ogc/fis/{INSTANCE_ID}?LAYER=EVIVALS&CRS=EPSG:4326&BINS=1&TIME=2018-09-10/2018-09-10&RESOLUTION=10m&GEOMETRY=POLYGON((-32.28555%20-64.23295,-32.28555%20-64.22177,-32.29489%20-64.22177,-32.29489%20-64.23295,-32.28555%20-64.23295))

there I get this
{“C0”:[{“date”:“2018-09-10”,“basicStats”:{“min”:0.06339102238416672,“max”:0.3025210201740265,“mean”:0.12271638319728684,“stDev”:0.019027570692743013},“histogram”:{“bins”:[{“value”:0.1212213374709167,“count”:10692.0},{“value”:0.16629620119929317,“count”:140.0},{“value”:0.23445159984731118,“count”:87.0},{“value”:0.28560692071914673,“count”:1.0}]}}]}

Now I have two questions, 1) how do I make this work within a layer in the instance for any date and 2) how I read the min and max values

Thanks!


#4

First note - whenever you work with TIME parameter, do use YYYY-MM-DD/YYYY-MM-DD value as TIME is interpreted as “FROM/TO”. If you only set one date, it will be interpreted as “FROM BEGINNING OF TIME/TO SET DATE”. If you use MAXCC=100 and PRIORITY=mostRecent, you should get the same result, in other cases not certain.

As I started to work with it before your edit, I created a new instance in your account called “TEST”, which has two layers - EVI-COLOR (for visualization, returning a combination of red, green, blue) and EVI-VALUE (returning actual value).

Basic visualization call:
https://services.sentinel-hub.com/ogc/wms/63f81d20-XYZ?SERVICE=WMS&REQUEST=GetMap&VERSION=1.3.0&TIME=2018-09-10&LAYERS=EVI-VALUE&RESX=10m&RESY=10m&CRS=EPSG:4326&TRANSPARENT=1&FORMAT=image/png&GEOMETRY=POLYGON((-32.28555%20-64.23295,-32.28555%20-64.22177,-32.29489%20-64.22177,-32.29489%20-64.23295,-32.28555%20-64.23295))

Statistical API call:
http://services.sentinel-hub.com/ogc/fis/63f81d20-XYZ?LAYER=EVI-VALUE&TIME=2018-09-10/2018-09-10&CRS=EPSG:4326&GEOMETRY=POLYGON((-32.28555%20-64.23295,-32.28555%20-64.22177,-32.29489%20-64.22177,-32.29489%20-64.23295,-32.28555%20-64.23295))&RESX=10m&RESY=10m

Returns:
{"C0":[{"date":"2018-09-10","basicStats":{"min":0.07955596596002579,"max":0.34055188298225403,"mean":0.1437222329933777,"stDev":0.021603603049859553}}]}

You need to call FIS from your application (or bash script) and then read the values with some JSON parser, getting min/max:
min = 0.07955596596002579;
max = 0.34055188298225403;

What you then need to do is to embed this value in custom script “template” as shown bellow. This step is also done in your application/bash script, for each call separately.

function evaluatePixel(samples) {
let val = index(samples[0].B08, samples[0].B04);
var min = 0.07955596596002579;
var max = 0.34055188298225403;
var step = (max-min)/5;

return colorBlend(val,[min, min +1*step, min +2*step, min +3*step, min +4*step, min +5*step],
[[0.815, 0.450, 0.345],
[0.815, 0.666, 0.345],
[0.815, 0.807, 0.345],
[0.745, 0.815, 0.345],
[0.549, 0.815, 0.345],
[0.439, 0.815, 0.345]]);;
}

function setup(ds) {
setInputComponents([ds.B04, ds.B08]);
setOutputComponentCount(3);
}

Once you have script prepared, you need to BASE64 encode it (there are usually standard functions available for that). For the purpose of this exercise I did it manually using on-line tool.
BASE64 encoded script looks like:
ZnVuY3Rpb24gZXZhbHVhdGVQaXhlbChzYW1wbGVzKSB7CmxldCB2YWwgPSBpbmRleChzYW1wbGVzWzBdLkIwOCwgc2FtcGxlc1swXS5CMDQpOwp2YXIgbWluID0gMC4wNzk1NTU5NjU5NjAwMjU3OTsKdmFyIG1heCA9IDAuMzQwNTUxODgyOTgyMjU0MDM7CnZhciBzdGVwID0gKG1heC1taW4pLzU7CgpyZXR1cm4gY29sb3JCbGVuZCh2YWwsW21pbiwgbWluICsxKnN0ZXAsIG1pbiArMipzdGVwLCBtaW4gKzMqc3RlcCwgbWluICs0KnN0ZXAsIG1pbiArNSpzdGVwXSwKW1swLjgxNSwgMC40NTAsIDAuMzQ1XSwKWzAuODE1LCAwLjY2NiwgMC4zNDVdLApbMC44MTUsIDAuODA3LCAwLjM0NV0sClswLjc0NSwgMC44MTUsIDAuMzQ1XSwKWzAuNTQ5LCAwLjgxNSwgMC4zNDVdLApbMC40MzksIDAuODE1LCAwLjM0NV1dKTs7Cn0KCmZ1bmN0aW9uIHNldHVwKGRzKSB7CnNldElucHV0Q29tcG9uZW50cyhbZHMuQjA0LCBkcy5CMDhdKTsKc2V0T3V0cHV0Q29tcG9uZW50Q291bnQoMyk7Cn0=

Now you simply pass this value as EVALSCRIPT, overriding the default style:
https://services.sentinel-hub.com/ogc/wms/63f81d20-XYZ?SERVICE=WMS&REQUEST=GetMap&VERSION=1.3.0&TIME=2018-09-10&LAYERS=EVI-COLOR&RESX=10m&RESY=10m&CRS=EPSG:4326&TRANSPARENT=1&FORMAT=image/png&GEOMETRY=POLYGON((-32.28555%20-64.23295,-32.28555%20-64.22177,-32.29489%20-64.22177,-32.29489%20-64.23295,-32.28555%20-64.23295))&EVALSCRIPT=ZnVuY3Rpb24gZXZhbHVhdGVQaXhlbChzYW1wbGVzKSB7CmxldCB2YWwgPSBpbmRleChzYW1wbGVzWzBdLkIwOCwgc2FtcGxlc1swXS5CMDQpOwp2YXIgbWluID0gMC4wNzk1NTU5NjU5NjAwMjU3OTsKdmFyIG1heCA9IDAuMzQwNTUxODgyOTgyMjU0MDM7CnZhciBzdGVwID0gKG1heC1taW4pLzU7CgpyZXR1cm4gY29sb3JCbGVuZCh2YWwsW21pbiwgbWluICsxKnN0ZXAsIG1pbiArMipzdGVwLCBtaW4gKzMqc3RlcCwgbWluICs0KnN0ZXAsIG1pbiArNSpzdGVwXSwKW1swLjgxNSwgMC40NTAsIDAuMzQ1XSwKWzAuODE1LCAwLjY2NiwgMC4zNDVdLApbMC44MTUsIDAuODA3LCAwLjM0NV0sClswLjc0NSwgMC44MTUsIDAuMzQ1XSwKWzAuNTQ5LCAwLjgxNSwgMC4zNDVdLApbMC40MzksIDAuODE1LCAwLjM0NV1dKTs7Cn0KCmZ1bmN0aW9uIHNldHVwKGRzKSB7CnNldElucHV0Q29tcG9uZW50cyhbZHMuQjA0LCBkcy5CMDhdKTsKc2V0T3V0cHV0Q29tcG9uZW50Q291bnQoMyk7Cn0=

As mentioned, you need to do this as a two step process within your application.


#5

Thank you very much!