forked from sentinel-hub/custom-scripts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathL2A-first_quartille.js
125 lines (111 loc) · 3.52 KB
/
L2A-first_quartille.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//VERSION=3 (auto-converted from 1)
/*
Script works on Sentinel-2 L2A data and requires scene classification (SCL) band.
It takes one year of data, which is quite compute and time intensive, which is why it is recommended to run it on small area (e.g. 256x256 px).
An example of the results is New Zealand's cloudless mosaic, available here: https://data.linz.govt.nz/layer/93652-nz-10m-satellite-imagery-2017/
For the output value for each pixel it uses the first quartile value of valid values, each band separately. If there are none it uses invalid values instead.
When using SCL its very important to use nearest neighbor resampling with a resolution of about 20m/px or more.
*/
function setup() {
return {
input: [{
bands: [
"B04",
"B03",
"B02",
"SCL"
]
}],
output: { bands: 3 }
}
}
function filterScenes (scenes, inputMetadata) {
return scenes.filter(function (scene) {
return scene.date.getTime()>=(inputMetadata.to.getTime()-12*31*24*3600*1000) ;
});
}
function getValue(values) {
values.sort( function(a,b) {return a - b;} );
return getFirstQuartile(values);
}
function getFirstQuartile(sortedValues) {
var index = Math.floor(sortedValues.length / 4);
return sortedValues[index];
}
function getDarkestPixel(sortedValues) {
return sortedValues[0]; // darkest pixel
}
function getSecondDarkestPixel(sortedValues) {
if (sortedValues.length > 1) { // second darkest pixel
return sortedValues[1];
}
return sortedValues[0]; // darkest pixel
}
function validate (samples) {
var scl = Math.round(samples.SCL);
if (scl == 3) { // SC_CLOUD_SHADOW
return false;
} else if (scl == 9) { // SC_CLOUD_HIGH_PROBA
return false;
} else if (scl == 8) { // SC_CLOUD_MEDIUM_PROBA
return false;
} else if (scl == 7) { // SC_CLOUD_LOW_PROBA / UNCLASSIFIED
// return false;
} else if (scl == 10) { // SC_THIN_CIRRUS
return false;
} else if (scl == 11) { // SC_SNOW_ICE
return false;
} else if (scl == 1) { // SC_SATURATED_DEFECTIVE
return false;
} else if (scl == 2) { // SC_DARK_FEATURE_SHADOW
// return false;
}
return true;
}
function evaluatePixelOrig(samples, scenes) {
var clo_b02 = [];var clo_b03 = [];
var clo_b04 = [];var clo_b08 = [];
var clo_b02_invalid = [];var clo_b03_invalid = [];
var clo_b04_invalid = [];var clo_b08_invalid = [];
var a = 0;
var a_invalid = 0;
var BRIGHTNESS = 1;
for (var i = 0; i < samples.length; i++) {
if (samples[i].B02 > 0 && samples[i].B03 > 0 && samples[i].B04 > 0) {
var isValid = validate(samples[i]);
if (isValid) {
clo_b02[a] = samples[i].B02;
clo_b03[a] = samples[i].B03;
clo_b04[a] = samples[i].B04;
a = a + 1;
} else {
clo_b02_invalid[a_invalid] = samples[i].B02;
clo_b03_invalid[a_invalid] = samples[i].B03;
clo_b04_invalid[a_invalid] = samples[i].B04;
a_invalid = a_invalid + 1;
}
}
}
var rValue;
var gValue;
var bValue;
if (a > 0) {
rValue = getValue(clo_b04)*BRIGHTNESS;
gValue = getValue(clo_b03)*BRIGHTNESS;
bValue = getValue(clo_b02)*BRIGHTNESS;
} else if (a_invalid > 0) {
rValue = getValue(clo_b04_invalid)*BRIGHTNESS;
gValue = getValue(clo_b03_invalid)*BRIGHTNESS;
bValue = getValue(clo_b02_invalid)*BRIGHTNESS;
} else {
rValue = 0;
gValue = 0;
bValue = 0;
}
return [rValue,
gValue,
bValue];
}
function evaluatePixel(sample, scene, metadata, customData, outputMetadata) {
return evaluatePixelOrig([sample], [scene], metadata, customData, outputMetadata);
}