I came across the custom script for fAPAR, which is really nice: https://github.com/sentinel-hub/custom-scripts/tree/master/sentinel-2/fapar
Does anyone have the alternative for fCOVER? It’s from the same SNAP toolbox, just different neural network. Could try to find out myself, but should someone have done this already, would be nice to know
Hi,
we do no have a custom script for fCOVER (yet).
If you decide to implement it, we would be happy to help and would encourage you to then share it
There are other existing scripts, which also implement NN algorithms (although I am not really familiar with fCOVER algorithm) and can thus be helpful:
Best
Hi,
Ok so the fCOVER algorithm is actually very similar to the fAPAR one, implemented in the same SNAP biopar toolbox. It’s based on INRA’s neural network. So I took the fAPAR algorithm and updated all biases, weights and normalization scales, and at first sight it looks already quite good, though it would be good if you could give it a try in a custom layer as well, to verify empirically if this gives realistic results. fCOVER is also supposed to be between 0 and 1.
As soon as we decide this is useful, it would be great to share it as a custom script for everyone to use
var degToRad = Math.PI / 180;
function evaluatePixel(samples) {
var sample = sampless0];
var b03_norm = normalize(sample.B03, 0, 0.253061520472);
var b04_norm = normalize(sample.B04, 0, 0.290393577911);
var b05_norm = normalize(sample.B05, 0, 0.305398915249);
var b06_norm = normalize(sample.B06, 0.00663797254225, 0.608900395798);
var b07_norm = normalize(sample.B07, 0.0139727270189, 0.753827384323);
var b8a_norm = normalize(sample.B8A, 0.0266901380821, 0.782011770669);
var b11_norm = normalize(sample.B11, 0.0163880741923, 0.493761397883);
var b12_norm = normalize(sample.B12, 0, 0.49302598446);
var viewZen_norm = normalize(Math.cos(sample.viewZenithMean * degToRad), 0.918595400582, 0.999999999991);
var sunZen_norm = normalize(Math.cos(sample.sunZenithAngles * degToRad), 0.342022871159, 0.936206429175);
var relAzim_norm = Math.cos((sample.sunAzimuthAngles - sample.viewAzimuthMean) * degToRad)
var n1 = neuron1(b03_norm,b04_norm,b05_norm,b06_norm,b07_norm,b8a_norm,b11_norm,b12_norm, viewZen_norm,sunZen_norm,relAzim_norm);
var n2 = neuron2(b03_norm,b04_norm,b05_norm,b06_norm,b07_norm,b8a_norm,b11_norm,b12_norm, viewZen_norm,sunZen_norm,relAzim_norm);
var n3 = neuron3(b03_norm,b04_norm,b05_norm,b06_norm,b07_norm,b8a_norm,b11_norm,b12_norm, viewZen_norm,sunZen_norm,relAzim_norm);
var n4 = neuron4(b03_norm,b04_norm,b05_norm,b06_norm,b07_norm,b8a_norm,b11_norm,b12_norm, viewZen_norm,sunZen_norm,relAzim_norm);
var n5 = neuron5(b03_norm,b04_norm,b05_norm,b06_norm,b07_norm,b8a_norm,b11_norm,b12_norm, viewZen_norm,sunZen_norm,relAzim_norm);
var l2 = layer2(n1, n2, n3, n4, n5);
var fcover = denormalize(l2, 0.000181230723879, 0.999638214715);
return {
default: ffcover]
}
}
function neuron1(b03_norm,b04_norm,b05_norm,b06_norm,b07_norm,b8a_norm,b11_norm,b12_norm, viewZen_norm,sunZen_norm,relAzim_norm) {
var sum =
- 1.45261652206
- 0.156854264841 * b03_norm
+ 0.124234528462 * b04_norm
+ 0.235625516229 * b05_norm
- 1.8323910258 * b06_norm
- 0.217188969888 * b07_norm
+ 5.06933958064 * b8a_norm
- 0.887578008155 * b11_norm
- 1.0808468167 * b12_norm
- 0.0323167041864 * viewZen_norm
- 0.224476137359 * sunZen_norm
- 0.195523962947 * relAzim_norm;
return tansig(sum);
}
function neuron2(b03_norm,b04_norm,b05_norm,b06_norm,b07_norm,b8a_norm,b11_norm,b12_norm, viewZen_norm,sunZen_norm,relAzim_norm) {
var sum =
-1.70417477557
- 0.220824927842 * b03_norm
+ 1.28595395487 * b04_norm
+ 0.703139486363 * b05_norm
- 1.34481216665 * b06_norm
- 1.96881267559 * b07_norm
- 1.45444681639 * b8a_norm
+ 1.02737560043 * b11_norm
- 0.12494641532 * b12_norm
+ 0.0802762437265 * viewZen_norm
- 0.198705918577 * sunZen_norm
+ 0.108527100527 * relAzim_norm;
return tansig(sum);
}
function neuron3(b03_norm,b04_norm,b05_norm,b06_norm,b07_norm,b8a_norm,b11_norm,b12_norm, viewZen_norm,sunZen_norm,relAzim_norm) {
var sum =
+ 1.02168965849
- 0.409688743281 * b03_norm
+ 1.08858884766 * b04_norm
+ 0.36284522554 * b05_norm
+ 0.0369390509705 * b06_norm
- 0.348012590003 * b07_norm
- 2.0035261881 * b8a_norm
+ 0.0410357601757 * b11_norm
+ 1.22373853174 * b12_norm
+ -0.0124082778287 * viewZen_norm
- 0.282223364524 * sunZen_norm
+ 0.0994993117557 * relAzim_norm;
return tansig(sum);
}
function neuron4(b03_norm,b04_norm,b05_norm,b06_norm,b07_norm,b8a_norm,b11_norm,b12_norm, viewZen_norm,sunZen_norm,relAzim_norm) {
var sum =
- 0.498002810205
- 0.188970957866 * b03_norm
- 0.0358621840833 * b04_norm
+ 0.00551248528107 * b05_norm
+ 1.35391570802 * b06_norm
- 0.739689896116 * b07_norm
- 2.21719530107 * b8a_norm
+ 0.313216124198 * b11_norm
+ 1.5020168915 * b12_norm
+ 1.21530490195 * viewZen_norm
- 0.421938358618 * sunZen_norm
+ 1.48852484547 * relAzim_norm;
return tansig(sum);
}
function neuron5(b03_norm,b04_norm,b05_norm,b06_norm,b07_norm,b8a_norm,b11_norm,b12_norm, viewZen_norm,sunZen_norm,relAzim_norm) {
var sum =
- 3.88922154789
+ 2.49293993709 * b03_norm
- 4.40511331388 * b04_norm
- 1.91062012624 * b05_norm
- 0.703174115575 * b06_norm
- 0.215104721138 * b07_norm
- 0.972151494818 * b8a_norm
- 0.930752241278 * b11_norm
+ 1.2143441876 * b12_norm
- 0.521665460192 * viewZen_norm
- 0.445755955598 * sunZen_norm
+ 0.344111873777 * relAzim_norm;
return tansig(sum);
}
function layer2(neuron1, neuron2, neuron3, neuron4, neuron5) {
var sum =
- 0.0967998147811
+ 0.23080586765 * neuron1
- 0.333655484884 * neuron2
- 0.499418292325 * neuron3
+ 0.0472484396749 * neuron4
- 0.0798516540739 * neuron5;
return sum;
}
function normalize(unnormalized, min, max) {
return 2 * (unnormalized - min) / (max - min) - 1;
}
function denormalize(normalized, min, max) {
return 0.5 * (normalized + 1) * (max - min) + min;
}
function tansig(input) {
return 2 / (1 + Math.exp(-2 * input)) - 1;
}
function setup(ds) {
return {
components: nds.B03, ds.B04, ds.B05, ds.B06, ds.B07, ds.B8A, ds.B11, ds.B12, ds.viewZenithMean, ds.viewAzimuthMean, ds.sunZenithAngles, ds.sunAzimuthAngles],
output: u
{
id: "default",
sampleType: SampleType.AUTO,
componentCount: 1
}
]
}
}
Hi,
nice!
I’ve checked quickly and it looks good. At least from the technical view, I would not dare to interpret the results. The only thing I had to add to the script was “//VERSION=2” in the first line.
When you are happy with the script you can add it our github repository yourself https://github.com/sentinel-hub/custom-scripts (instructions: https://github.com/sentinel-hub/custom-scripts/tree/master/example) or, if you do not want to bother with this, let me know and we will push it to the repository.
P.S.: I have heard rumors that Sentinel Hub custom scripts contest, edition 2 will start soon. A script like this can take you far
To the interested reader: after almost a one-year delay, this stuff is finally officially integrated in the custom-scripts library
github.com
custom-scripts/sentinel-2/fcover at master · sentinel-hub/custom-scripts
A repository of custom scripts to be used with Sentinel Hub
Hi,
It looks like that custom script for FAPAR
was committed to custom script GitHub repo instead of fCover
: https://github.com/sentinel-hub/custom-scripts/blob/master/sentinel-2/fcover/script.js.
Could you check and commit the correct version? If the fCover
script posted above is up-to-date, I can do it as well, if you wish.
Thanks,
Wow that’s bad! Apologies, that shouldn’t have happened. I opened a new PR with the correct version. Please double-check that I did it right this time. This whole process was my first experience with forking and creating PRs, so it’s a learning curve
Wow. That was fast. Thank you again!
Reply
Enter your E-mail address. We'll send you an e-mail with instructions to reset your password.