eotdl 2025.2.10__py3-none-any.whl → 2025.4.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- eotdl/__init__.py +1 -1
- eotdl/access/__init__.py +13 -3
- eotdl/access/download.py +47 -14
- eotdl/access/search.py +33 -5
- eotdl/access/sentinelhub/__init__.py +6 -2
- eotdl/access/sentinelhub/client.py +7 -6
- eotdl/access/sentinelhub/evalscripts.py +266 -0
- eotdl/access/sentinelhub/parameters.py +101 -23
- eotdl/access/sentinelhub/utils.py +54 -15
- eotdl/cli.py +2 -2
- eotdl/commands/datasets.py +28 -31
- eotdl/commands/models.py +27 -30
- eotdl/commands/stac.py +57 -0
- eotdl/curation/__init__.py +0 -8
- eotdl/curation/stac/__init__.py +1 -8
- eotdl/curation/stac/api.py +58 -0
- eotdl/curation/stac/stac.py +31 -341
- eotdl/datasets/__init__.py +2 -2
- eotdl/datasets/ingest.py +36 -161
- eotdl/datasets/retrieve.py +0 -9
- eotdl/datasets/stage.py +64 -0
- eotdl/files/__init__.py +0 -2
- eotdl/files/ingest.bck +178 -0
- eotdl/files/ingest.py +237 -166
- eotdl/{datasets → files}/metadata.py +16 -17
- eotdl/models/__init__.py +1 -1
- eotdl/models/ingest.py +35 -158
- eotdl/models/stage.py +63 -0
- eotdl/repos/APIRepo.py +1 -1
- eotdl/repos/DatasetsAPIRepo.py +56 -43
- eotdl/repos/FilesAPIRepo.py +260 -167
- eotdl/repos/ModelsAPIRepo.py +50 -42
- eotdl/repos/STACAPIRepo.py +40 -0
- eotdl/repos/__init__.py +1 -0
- eotdl/tools/time_utils.py +3 -3
- {eotdl-2025.2.10.dist-info → eotdl-2025.4.2.dist-info}/METADATA +1 -1
- eotdl-2025.4.2.dist-info/RECORD +66 -0
- eotdl/curation/stac/assets.py +0 -110
- eotdl/curation/stac/dataframe.py +0 -172
- eotdl/curation/stac/dataframe_bck.py +0 -253
- eotdl/curation/stac/dataframe_labeling.py +0 -63
- eotdl/curation/stac/extensions/__init__.py +0 -23
- eotdl/curation/stac/extensions/base.py +0 -30
- eotdl/curation/stac/extensions/dem.py +0 -18
- eotdl/curation/stac/extensions/eo.py +0 -117
- eotdl/curation/stac/extensions/label/__init__.py +0 -7
- eotdl/curation/stac/extensions/label/base.py +0 -136
- eotdl/curation/stac/extensions/label/image_name_labeler.py +0 -203
- eotdl/curation/stac/extensions/label/scaneo.py +0 -219
- eotdl/curation/stac/extensions/ml_dataset.py +0 -648
- eotdl/curation/stac/extensions/projection.py +0 -44
- eotdl/curation/stac/extensions/raster.py +0 -53
- eotdl/curation/stac/extensions/sar.py +0 -55
- eotdl/curation/stac/extent.py +0 -158
- eotdl/curation/stac/parsers.py +0 -61
- eotdl/datasets/download.py +0 -104
- eotdl/files/list_files.py +0 -13
- eotdl/models/metadata.py +0 -43
- eotdl-2025.2.10.dist-info/RECORD +0 -81
- {eotdl-2025.2.10.dist-info → eotdl-2025.4.2.dist-info}/WHEEL +0 -0
- {eotdl-2025.2.10.dist-info → eotdl-2025.4.2.dist-info}/entry_points.txt +0 -0
eotdl/__init__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "2025.02
|
1
|
+
__version__ = "2025.04.02"
|
eotdl/access/__init__.py
CHANGED
@@ -2,6 +2,16 @@
|
|
2
2
|
Data access module for eotdl package.
|
3
3
|
"""
|
4
4
|
|
5
|
-
from .download import
|
6
|
-
|
7
|
-
|
5
|
+
from .download import (
|
6
|
+
download_sentinel_imagery,
|
7
|
+
search_and_download_sentinel_imagery,
|
8
|
+
advanced_imagery_download,
|
9
|
+
)
|
10
|
+
from .search import search_sentinel_imagery, advanced_imagery_search
|
11
|
+
from .sentinelhub.parameters import (
|
12
|
+
SUPPORTED_COLLECTION_IDS,
|
13
|
+
DATA_COLLECTION_ID,
|
14
|
+
get_default_parameters,
|
15
|
+
OUTPUT_FORMAT,
|
16
|
+
)
|
17
|
+
from .sentinelhub.evalscripts import EvalScripts
|
eotdl/access/download.py
CHANGED
@@ -2,49 +2,82 @@
|
|
2
2
|
Download imagery
|
3
3
|
"""
|
4
4
|
|
5
|
-
from datetime import datetime
|
5
|
+
from datetime import datetime, timedelta
|
6
6
|
from typing import Union, List, Optional
|
7
7
|
|
8
8
|
from .sentinelhub import (
|
9
9
|
SHClient,
|
10
|
-
SH_PARAMETERS_DICT,
|
11
10
|
evaluate_sentinel_parameters,
|
12
11
|
imagery_from_tmp_to_dir,
|
12
|
+
get_default_parameters,
|
13
|
+
SHParameters,
|
14
|
+
filter_times,
|
13
15
|
)
|
14
|
-
from .search import
|
16
|
+
from .search import advanced_imagery_search
|
15
17
|
|
16
18
|
|
17
19
|
def download_sentinel_imagery(
|
18
20
|
output: str,
|
19
21
|
time_interval: Union[str, datetime, List[Union[str, datetime]]],
|
20
22
|
bounding_box: List[Union[int, float]],
|
21
|
-
|
23
|
+
collection_id: str,
|
22
24
|
name: Optional[str] = None,
|
23
25
|
) -> None:
|
24
26
|
"""
|
25
27
|
Download Sentinel imagery
|
26
28
|
"""
|
27
|
-
evaluate_sentinel_parameters(
|
29
|
+
evaluate_sentinel_parameters(time_interval, bounding_box, collection_id, output)
|
30
|
+
parameters = get_default_parameters(collection_id)
|
31
|
+
return advanced_imagery_download(
|
32
|
+
output, time_interval, bounding_box, parameters, name
|
33
|
+
)
|
34
|
+
|
28
35
|
|
29
|
-
|
30
|
-
|
36
|
+
def advanced_imagery_download(
|
37
|
+
output: str,
|
38
|
+
time_interval: Union[str, datetime, List[Union[str, datetime]]],
|
39
|
+
bounding_box: List[Union[int, float]],
|
40
|
+
parameters: SHParameters,
|
41
|
+
name: Optional[str] = None,
|
42
|
+
) -> None:
|
43
|
+
"""
|
44
|
+
Advanced imagery download
|
45
|
+
"""
|
46
|
+
evaluate_sentinel_parameters(
|
47
|
+
time_interval, bounding_box, output=output, parameters=parameters
|
48
|
+
)
|
49
|
+
client = SHClient(parameters.BASE_URL)
|
31
50
|
|
32
|
-
results =
|
33
|
-
timestamps =
|
51
|
+
results = advanced_imagery_search(time_interval, bounding_box, parameters)
|
52
|
+
timestamps = results.get_timestamps()
|
53
|
+
time_difference = timedelta(hours=1)
|
54
|
+
filtered_timestamps = filter_times(timestamps, time_difference)
|
34
55
|
|
35
56
|
requests_list = []
|
36
|
-
for date in
|
37
|
-
|
57
|
+
for date in filtered_timestamps:
|
58
|
+
timestamp_interval = (date - time_difference, date + time_difference)
|
59
|
+
requests_list.append(
|
60
|
+
client.request_data(timestamp_interval, bounding_box, parameters)
|
61
|
+
)
|
38
62
|
if len(requests_list) == 0:
|
39
|
-
print(
|
63
|
+
print(
|
64
|
+
f"No images found for {parameters.DATA_COLLECTION.api_id} in the specified time: {time_interval}"
|
65
|
+
)
|
40
66
|
return
|
41
67
|
elif len(requests_list) <= 2:
|
42
68
|
bulk = False
|
43
69
|
else:
|
44
70
|
bulk = True
|
45
71
|
|
46
|
-
|
47
|
-
imagery_from_tmp_to_dir(
|
72
|
+
client.download_data(requests_list)
|
73
|
+
imagery_from_tmp_to_dir(
|
74
|
+
output,
|
75
|
+
bounding_box,
|
76
|
+
client.tmp_dir,
|
77
|
+
name=name,
|
78
|
+
bulk=bulk,
|
79
|
+
output_format=parameters.OUTPUT_FORMAT.value,
|
80
|
+
)
|
48
81
|
|
49
82
|
|
50
83
|
def search_and_download_sentinel_imagery(
|
eotdl/access/search.py
CHANGED
@@ -5,20 +5,48 @@ Search imagery
|
|
5
5
|
from typing import Union, List
|
6
6
|
from datetime import datetime
|
7
7
|
|
8
|
-
from .sentinelhub import
|
8
|
+
from .sentinelhub import (
|
9
|
+
SHClient,
|
10
|
+
get_default_parameters,
|
11
|
+
evaluate_sentinel_parameters,
|
12
|
+
SHParameters,
|
13
|
+
supports_cloud_coverage,
|
14
|
+
)
|
9
15
|
|
10
16
|
|
11
17
|
def search_sentinel_imagery(
|
12
18
|
time_interval: Union[str, datetime, List[Union[str, datetime]]],
|
13
19
|
bounding_box: List[Union[int, float]],
|
14
|
-
|
20
|
+
collection_id: str,
|
15
21
|
) -> None:
|
16
22
|
"""
|
17
23
|
Search Sentinel imagery
|
18
24
|
"""
|
19
25
|
evaluate_sentinel_parameters(
|
20
|
-
|
26
|
+
time_interval, bounding_box, collection_id, output_needed=False
|
21
27
|
)
|
22
|
-
|
23
|
-
|
28
|
+
parameters = get_default_parameters(collection_id)
|
29
|
+
client = SHClient(parameters.BASE_URL)
|
30
|
+
return client.search_data(bounding_box, time_interval, parameters)
|
31
|
+
|
32
|
+
|
33
|
+
def advanced_imagery_search(
|
34
|
+
time_interval: Union[str, datetime, List[Union[str, datetime]]],
|
35
|
+
bounding_box: List[Union[int, float]],
|
36
|
+
parameters: SHParameters,
|
37
|
+
) -> None:
|
38
|
+
"""
|
39
|
+
Advanced imagery search
|
40
|
+
"""
|
41
|
+
evaluate_sentinel_parameters(
|
42
|
+
time_interval, bounding_box, output_needed=False, parameters=parameters
|
43
|
+
)
|
44
|
+
|
45
|
+
if (
|
46
|
+
supports_cloud_coverage(parameters.DATA_COLLECTION.api_id)
|
47
|
+
and parameters.MAX_CLOUD_COVERAGE
|
48
|
+
):
|
49
|
+
parameters.FILTER = "eo:cloud_cover < " + str(parameters.MAX_CLOUD_COVERAGE)
|
50
|
+
|
51
|
+
client = SHClient(parameters.BASE_URL)
|
24
52
|
return client.search_data(bounding_box, time_interval, parameters)
|
@@ -3,6 +3,10 @@ Sentinel-Hub data access module.
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
from .client import SHClient
|
6
|
-
from .parameters import
|
6
|
+
from .parameters import (
|
7
|
+
SHParameters,
|
8
|
+
supports_cloud_coverage,
|
9
|
+
get_default_parameters,
|
10
|
+
)
|
7
11
|
from .evalscripts import EvalScripts
|
8
|
-
from .utils import evaluate_sentinel_parameters, imagery_from_tmp_to_dir
|
12
|
+
from .utils import evaluate_sentinel_parameters, imagery_from_tmp_to_dir, filter_times
|
@@ -3,6 +3,7 @@ Module for managing the Sentinel Hub configuration and data access
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
import json
|
6
|
+
from datetime import datetime
|
6
7
|
from os import getenv
|
7
8
|
from os.path import exists
|
8
9
|
from sentinelhub import (
|
@@ -13,13 +14,11 @@ from sentinelhub import (
|
|
13
14
|
CRS,
|
14
15
|
SentinelHubRequest,
|
15
16
|
SentinelHubDownloadClient,
|
16
|
-
MimeType,
|
17
17
|
)
|
18
18
|
import uuid
|
19
19
|
|
20
20
|
from ...repos.AuthRepo import AuthRepo
|
21
21
|
from .parameters import SHParameters
|
22
|
-
from ...tools.time_utils import prepare_time_interval
|
23
22
|
from ...tools.geo_utils import compute_image_size
|
24
23
|
|
25
24
|
|
@@ -28,7 +27,7 @@ class SHClient:
|
|
28
27
|
Client class to manage the Sentinel Hub Python interface.
|
29
28
|
"""
|
30
29
|
|
31
|
-
def __init__(self) -> None:
|
30
|
+
def __init__(self, base_url) -> None:
|
32
31
|
""" """
|
33
32
|
self.config = SHConfig()
|
34
33
|
if getenv("SH_CLIENT_ID") and getenv("SH_CLIENT_SECRET"):
|
@@ -57,6 +56,7 @@ class SHClient:
|
|
57
56
|
else:
|
58
57
|
self.config.sh_client_id = creds["SH_CLIENT_ID"]
|
59
58
|
self.config.sh_client_secret = creds["SH_CLIENT_SECRET"]
|
59
|
+
self.config.sh_base_url = base_url
|
60
60
|
self.catalog = SentinelHubCatalog(config=self.config)
|
61
61
|
self.tmp_dir = "/tmp/sentinelhub/" + str(uuid.uuid4())
|
62
62
|
|
@@ -77,12 +77,11 @@ class SHClient:
|
|
77
77
|
return search_iterator
|
78
78
|
|
79
79
|
def request_data(
|
80
|
-
self, time_interval, bounding_box: list, parameters: SHParameters
|
80
|
+
self, time_interval: datetime, bounding_box: list, parameters: SHParameters
|
81
81
|
) -> list:
|
82
82
|
"""
|
83
83
|
Request data from Sentinel Hub
|
84
84
|
"""
|
85
|
-
time_interval = prepare_time_interval(time_interval)
|
86
85
|
bounding_box, _ = compute_image_size(bounding_box, parameters)
|
87
86
|
|
88
87
|
return SentinelHubRequest(
|
@@ -95,7 +94,9 @@ class SHClient:
|
|
95
94
|
mosaicking_order=parameters.MOSAICKING_ORDER,
|
96
95
|
)
|
97
96
|
],
|
98
|
-
responses=[
|
97
|
+
responses=[
|
98
|
+
SentinelHubRequest.output_response("default", parameters.OUTPUT_FORMAT)
|
99
|
+
],
|
99
100
|
bbox=bounding_box,
|
100
101
|
size=bbox_to_dimensions(bounding_box, parameters.RESOLUTION),
|
101
102
|
config=self.config,
|
@@ -27,6 +27,28 @@ class EvalScripts:
|
|
27
27
|
}
|
28
28
|
"""
|
29
29
|
|
30
|
+
SENTINEL_1_ENHANCED_VISUALIZATION = """
|
31
|
+
//VERSION=3
|
32
|
+
function setup() {
|
33
|
+
return {
|
34
|
+
input: ["VV", "VH", "dataMask"],
|
35
|
+
output: { bands: 4 }
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
function evaluatePixel(sample) {
|
40
|
+
var water_threshold = 25; //lower means more water
|
41
|
+
|
42
|
+
if (sample.VV / sample.VH > water_threshold) {
|
43
|
+
// watervis
|
44
|
+
return [sample.VV, 8 * sample.VV, 0.5 + 3 * sample.VV + 2000 * sample.VH, sample.dataMask];
|
45
|
+
} else {
|
46
|
+
// landvis
|
47
|
+
return [3 * sample.VV, 1.1 * sample.VV + 8.75 * sample.VH, 1.75 * sample.VH, sample.dataMask];
|
48
|
+
}
|
49
|
+
}
|
50
|
+
"""
|
51
|
+
|
30
52
|
SENTINEL_2_L1C = """
|
31
53
|
//VERSION=3
|
32
54
|
function setup() {
|
@@ -113,6 +135,26 @@ class EvalScripts:
|
|
113
135
|
}
|
114
136
|
"""
|
115
137
|
|
138
|
+
SENTINEL_2_L2A_TRUE_COLOR = """
|
139
|
+
//VERSION=3
|
140
|
+
let minVal = 0.0;
|
141
|
+
let maxVal = 0.4;
|
142
|
+
|
143
|
+
let viz = new HighlightCompressVisualizer(minVal, maxVal);
|
144
|
+
|
145
|
+
function setup() {
|
146
|
+
return {
|
147
|
+
input: ["B04", "B03", "B02","dataMask"],
|
148
|
+
output: { bands: 4 }
|
149
|
+
};
|
150
|
+
}
|
151
|
+
|
152
|
+
function evaluatePixel(samples) {
|
153
|
+
let val = [samples.B04, samples.B03, samples.B02,samples.dataMask];
|
154
|
+
return viz.processList(val);
|
155
|
+
}
|
156
|
+
"""
|
157
|
+
|
116
158
|
DEM = """
|
117
159
|
//VERSION=3
|
118
160
|
|
@@ -130,3 +172,227 @@ class EvalScripts:
|
|
130
172
|
return [sample.DEM]
|
131
173
|
}
|
132
174
|
"""
|
175
|
+
|
176
|
+
DEM_TOPOGRAPHIC = """
|
177
|
+
//VERSION=3
|
178
|
+
// To set custom max and min values, set
|
179
|
+
// defaultVis to false and choose your max and
|
180
|
+
// min values. The color map will then be scaled
|
181
|
+
// to those max and min values
|
182
|
+
const defaultVis = true
|
183
|
+
const max = 9000
|
184
|
+
const min = -9000
|
185
|
+
|
186
|
+
function setup() {
|
187
|
+
return {
|
188
|
+
input: ["DEM", "dataMask"],
|
189
|
+
output: [
|
190
|
+
{ id: "default", bands: 4, sampleTYPE: 'AUTO' },
|
191
|
+
{ id: "index", bands: 1, sampleType: 'FLOAT32' },
|
192
|
+
{ id: "dataMask", bands: 1 }
|
193
|
+
]
|
194
|
+
};
|
195
|
+
}
|
196
|
+
|
197
|
+
function updateMap(max, min) {
|
198
|
+
const numIntervals = map.length
|
199
|
+
const intervalLength = (max - min) / (numIntervals - 1);
|
200
|
+
for (let i = 0; i < numIntervals; i++) {
|
201
|
+
map[i][0] = max - intervalLength * i
|
202
|
+
}
|
203
|
+
}
|
204
|
+
|
205
|
+
const map = [
|
206
|
+
[8000, 0xffffff],
|
207
|
+
[7000, 0xf2f2f2],
|
208
|
+
[6000, 0xe5e5e5],
|
209
|
+
[5500, 0x493811],
|
210
|
+
[5000, 0x5e4c26],
|
211
|
+
[4500, 0x726038],
|
212
|
+
[4000, 0x87724c],
|
213
|
+
[3500, 0x998760],
|
214
|
+
[3000, 0xad9b75],
|
215
|
+
[2500, 0xc1af89],
|
216
|
+
[2000, 0xd6c49e],
|
217
|
+
[1500, 0xead8af],
|
218
|
+
[1000, 0xfcedbf],
|
219
|
+
[900, 0xaadda0],
|
220
|
+
[800, 0xa5d69b],
|
221
|
+
[700, 0x96ce8e],
|
222
|
+
[600, 0x84c17a],
|
223
|
+
[500, 0x7aba70],
|
224
|
+
[400, 0x72b266],
|
225
|
+
[300, 0x5ea354],
|
226
|
+
[200, 0x4c933f],
|
227
|
+
[100, 0x3d873d],
|
228
|
+
[75, 0x357c3a],
|
229
|
+
[50, 0x2d722d],
|
230
|
+
[25, 0x266821],
|
231
|
+
[10, 0x1e5e14],
|
232
|
+
[0.01, 0x165407]
|
233
|
+
];
|
234
|
+
|
235
|
+
if (!defaultVis) updateMap(max, min);
|
236
|
+
// add ocean color
|
237
|
+
map.push([-10000, 0x0f0f8c])
|
238
|
+
const visualizer = new ColorMapVisualizer(map);
|
239
|
+
|
240
|
+
function evaluatePixel(sample) {
|
241
|
+
let val = sample.DEM;
|
242
|
+
let imgVals = visualizer.process(val)
|
243
|
+
|
244
|
+
// Return the 4 inputs and define content for each one
|
245
|
+
return {
|
246
|
+
default: [...imgVals, sample.dataMask],
|
247
|
+
index: [val],
|
248
|
+
dataMask: [sample.dataMask]
|
249
|
+
};
|
250
|
+
}
|
251
|
+
"""
|
252
|
+
|
253
|
+
HLS_FALSE_COLOR = """
|
254
|
+
//VERSION=3
|
255
|
+
|
256
|
+
function setup() {
|
257
|
+
return {
|
258
|
+
input: ["NIR_Narrow", "Red", "Green", "dataMask"],
|
259
|
+
output: { bands: 3 }
|
260
|
+
};
|
261
|
+
}
|
262
|
+
|
263
|
+
function evaluatePixel(sample) {
|
264
|
+
return [2.5 * sample.NIR_Narrow, 2.5 * sample.Red, 2.5 * sample.Green, sample.dataMask];
|
265
|
+
}
|
266
|
+
"""
|
267
|
+
|
268
|
+
HLS_TRUE_COLOR = """
|
269
|
+
//VERSION=3
|
270
|
+
|
271
|
+
function setup() {
|
272
|
+
return {
|
273
|
+
input: ["Blue","Green","Red", "dataMask"],
|
274
|
+
output: { bands: 4 }
|
275
|
+
};
|
276
|
+
}
|
277
|
+
|
278
|
+
function evaluatePixel(sample) {
|
279
|
+
return [2.5 * sample.Red, 2.5 * sample.Green, 2.5 * sample.Blue, sample.dataMask];
|
280
|
+
}
|
281
|
+
"""
|
282
|
+
|
283
|
+
HLS_NDVI = """
|
284
|
+
//VERSION=3
|
285
|
+
|
286
|
+
function setup() {
|
287
|
+
return {
|
288
|
+
input: ["NIR_Narrow", "Red", "dataMask"],
|
289
|
+
output: { bands: 4 }
|
290
|
+
};
|
291
|
+
}
|
292
|
+
|
293
|
+
function evaluatePixel(sample) {
|
294
|
+
var ndvi = (sample.NIR_Narrow - sample.Red) / (sample.NIR_Narrow + sample.Red)
|
295
|
+
|
296
|
+
if (ndvi<-1.1) return [0,0,0, sample.dataMask];
|
297
|
+
else if (ndvi<-0.2) return [0.75,0.75,0.75, sample.dataMask];
|
298
|
+
else if (ndvi<-0.1) return [0.86,0.86,0.86, sample.dataMask];
|
299
|
+
else if (ndvi<0) return [1,1,0.88, sample.dataMask];
|
300
|
+
else if (ndvi<0.025) return [1,0.98,0.8, sample.dataMask];
|
301
|
+
else if (ndvi<0.05) return [0.93,0.91,0.71, sample.dataMask];
|
302
|
+
else if (ndvi<0.075) return [0.87,0.85,0.61, sample.dataMask];
|
303
|
+
else if (ndvi<0.1) return [0.8,0.78,0.51, sample.dataMask];
|
304
|
+
else if (ndvi<0.125) return [0.74,0.72,0.42, sample.dataMask];
|
305
|
+
else if (ndvi<0.15) return [0.69,0.76,0.38, sample.dataMask];
|
306
|
+
else if (ndvi<0.175) return [0.64,0.8,0.35, sample.dataMask];
|
307
|
+
else if (ndvi<0.2) return [0.57,0.75,0.32, sample.dataMask];
|
308
|
+
else if (ndvi<0.25) return [0.5,0.7,0.28, sample.dataMask];
|
309
|
+
else if (ndvi<0.3) return [0.44,0.64,0.25, sample.dataMask];
|
310
|
+
else if (ndvi<0.35) return [0.38,0.59,0.21, sample.dataMask];
|
311
|
+
else if (ndvi<0.4) return [0.31,0.54,0.18, sample.dataMask];
|
312
|
+
else if (ndvi<0.45) return [0.25,0.49,0.14, sample.dataMask];
|
313
|
+
else if (ndvi<0.5) return [0.19,0.43,0.11, sample.dataMask];
|
314
|
+
else if (ndvi<0.55) return [0.13,0.38,0.07, sample.dataMask];
|
315
|
+
else if (ndvi<0.6) return [0.06,0.33,0.04, sample.dataMask];
|
316
|
+
else return [0,0.27,0, sample.dataMask];
|
317
|
+
}
|
318
|
+
"""
|
319
|
+
|
320
|
+
LANDSAT_OT_L2_TRUE_COLOR = """
|
321
|
+
//VERSION=3
|
322
|
+
|
323
|
+
let minVal = 0.0;
|
324
|
+
let maxVal = 0.4;
|
325
|
+
|
326
|
+
let viz = new DefaultVisualizer(minVal, maxVal);
|
327
|
+
|
328
|
+
function evaluatePixel(samples) {
|
329
|
+
let val = [samples.B04, samples.B03, samples.B02, samples.dataMask];
|
330
|
+
return viz.processList(val);
|
331
|
+
}
|
332
|
+
|
333
|
+
function setup() {
|
334
|
+
return {
|
335
|
+
input: [{
|
336
|
+
bands: [ "B02", "B03", "B04", "dataMask" ]
|
337
|
+
}],
|
338
|
+
output: { bands: 4 } }
|
339
|
+
}
|
340
|
+
"""
|
341
|
+
LANDSAT_OT_L2_NDVI = """
|
342
|
+
//VERSION=3
|
343
|
+
|
344
|
+
function setup() {
|
345
|
+
return {
|
346
|
+
input: ["B03", "B04", "B05", "dataMask"],
|
347
|
+
output: [
|
348
|
+
{ id: "default", bands: 4 },
|
349
|
+
{ id: "index", bands: 1, sampleType: "FLOAT32" },
|
350
|
+
{ id: "eobrowserStats", bands: 2 },
|
351
|
+
{ id: "dataMask", bands: 1 },
|
352
|
+
],
|
353
|
+
};
|
354
|
+
}
|
355
|
+
|
356
|
+
function evaluatePixel(samples) {
|
357
|
+
let val = index(samples.B05, samples.B04);
|
358
|
+
let imgVals = null;
|
359
|
+
// The library for tiffs works well only if there is only one channel returned.
|
360
|
+
// So we encode the "no data" as NaN here and ignore NaNs on frontend.
|
361
|
+
const indexVal = samples.dataMask === 1 && val >= -1 && val <= 1 ? val : NaN;
|
362
|
+
|
363
|
+
if (val < -1.1) imgVals = [0, 0, 0, samples.dataMask];
|
364
|
+
else if (val < -0.2) imgVals = [0.75, 0.75, 0.75, samples.dataMask];
|
365
|
+
else if (val < -0.1) imgVals = [0.86, 0.86, 0.86, samples.dataMask];
|
366
|
+
else if (val < 0) imgVals = [1, 1, 0.88, samples.dataMask];
|
367
|
+
else if (val < 0.025) imgVals = [1, 0.98, 0.8, samples.dataMask];
|
368
|
+
else if (val < 0.05) imgVals = [0.93, 0.91, 0.71, samples.dataMask];
|
369
|
+
else if (val < 0.075) imgVals = [0.87, 0.85, 0.61, samples.dataMask];
|
370
|
+
else if (val < 0.1) imgVals = [0.8, 0.78, 0.51, samples.dataMask];
|
371
|
+
else if (val < 0.125) imgVals = [0.74, 0.72, 0.42, samples.dataMask];
|
372
|
+
else if (val < 0.15) imgVals = [0.69, 0.76, 0.38, samples.dataMask];
|
373
|
+
else if (val < 0.175) imgVals = [0.64, 0.8, 0.35, samples.dataMask];
|
374
|
+
else if (val < 0.2) imgVals = [0.57, 0.75, 0.32, samples.dataMask];
|
375
|
+
else if (val < 0.25) imgVals = [0.5, 0.7, 0.28, samples.dataMask];
|
376
|
+
else if (val < 0.3) imgVals = [0.44, 0.64, 0.25, samples.dataMask];
|
377
|
+
else if (val < 0.35) imgVals = [0.38, 0.59, 0.21, samples.dataMask];
|
378
|
+
else if (val < 0.4) imgVals = [0.31, 0.54, 0.18, samples.dataMask];
|
379
|
+
else if (val < 0.45) imgVals = [0.25, 0.49, 0.14, samples.dataMask];
|
380
|
+
else if (val < 0.5) imgVals = [0.19, 0.43, 0.11, samples.dataMask];
|
381
|
+
else if (val < 0.55) imgVals = [0.13, 0.38, 0.07, samples.dataMask];
|
382
|
+
else if (val < 0.6) imgVals = [0.06, 0.33, 0.04, samples.dataMask];
|
383
|
+
else imgVals = [0, 0.27, 0, samples.dataMask];
|
384
|
+
|
385
|
+
return {
|
386
|
+
default: imgVals,
|
387
|
+
index: [indexVal],
|
388
|
+
eobrowserStats: [val, isCloud(samples) ? 1 : 0],
|
389
|
+
dataMask: [samples.dataMask],
|
390
|
+
};
|
391
|
+
}
|
392
|
+
|
393
|
+
function isCloud(samples) {
|
394
|
+
const NGDR = index(samples.B03, samples.B04);
|
395
|
+
const bRatio = (samples.B03 - 0.175) / (0.39 - 0.175);
|
396
|
+
return bRatio > 1 || (bRatio > 0 && NGDR > 0);
|
397
|
+
}
|
398
|
+
"""
|