satcube 0.1.13__py3-none-any.whl → 0.1.15__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.

Potentially problematic release.


This version of satcube might be problematic. Click here for more details.

satcube/main.py DELETED
@@ -1,453 +0,0 @@
1
- import pathlib
2
- from typing import Optional, Tuple, Union
3
- from datetime import datetime
4
-
5
- import fastcubo
6
- import pandas as pd
7
- import torch
8
-
9
- from satcube.dataclass import Sensor
10
- from satcube.utils_old import (aligned_s2, cloudmasking_s2, display_images,
11
- gapfilling_s2, intermediate_process, interpolate_s2,
12
- metadata_s2, monthly_composites_s2, smooth_s2, super_s2)
13
-
14
-
15
- class SatCube:
16
- """Satellite cube class to create datacubes from a specific sensor."""
17
-
18
- def __init__(
19
- self,
20
- sensor: Sensor,
21
- output_dir: str,
22
- max_workers: int,
23
- coordinates: Tuple[float, float],
24
- device: Union[str, torch.device],
25
- ):
26
- """Create a new instance of the Satellite Cube class.
27
-
28
- Args:
29
- coordinates (Tuple[float, float]): The coordinates of the
30
- location to download the data.
31
- sensor (Sensor): The sensor object with all the information
32
- to download and preprocess the data.
33
- output_dir (str): The output directory to save the data.
34
- max_workers (int): The maximum number of workers to use in the
35
- download process.
36
- device (Union[str, torch.device]): The device to use in the
37
- cloud removal process.
38
- """
39
- self.device = device
40
- self.sensor = sensor
41
- self.output_dir = pathlib.Path(output_dir)
42
- self.max_workers = max_workers
43
- self.lon, self.lat = coordinates
44
-
45
- # If the output directory does not exist, create it
46
- self.output_dir.mkdir(parents=True, exist_ok=True)
47
-
48
- def metadata_s2(
49
- self,
50
- out_csv: Optional[pathlib.Path] = None,
51
- quiet: Optional[pathlib.Path] = False,
52
- force: Optional[bool] = False,
53
- ) -> pd.DataFrame:
54
- """Create a pd.DataFrame with the images to download and their
55
- cloud cover percentage. The table is saved in a CSV file.
56
-
57
- Args:
58
- force (Optional[bool], optional): If True, the query
59
- process is done again. Defaults to False.
60
- out_csv (Optional[pathlib.Path], optional): The path to the
61
- CSV file with the query table. Defaults to None.
62
- quiet (Optional[bool], optional): If True, no message is
63
- displayed. Defaults to False.
64
- force (Optional[bool], optional): If True, the query process
65
- is done again. Defaults to False.
66
-
67
- Returns:
68
- pd.DataFrame: The table with the images to download.
69
- """
70
-
71
- if out_csv is None:
72
- out_csv: pathlib.Path = self.output_dir / "s2_01_gee_query.csv"
73
-
74
- if not out_csv.exists() or force:
75
- query_table: pd.DataFrame = metadata_s2(
76
- lon=self.lon,
77
- lat=self.lat,
78
- range_date=(self.sensor.start_date, self.sensor.end_date),
79
- edge_size=self.sensor.edge_size,
80
- quiet=quiet
81
- )
82
- query_table.to_csv(out_csv, index=False)
83
- else:
84
- query_table = pd.read_csv(out_csv)
85
-
86
- return query_table
87
-
88
- def download_s2_image(
89
- self,
90
- table: pd.DataFrame,
91
- out_folder: Optional[pathlib.Path] = None,
92
- quiet: Optional[bool] = False,
93
- force: Optional[bool] = False,
94
- ) -> pathlib.Path:
95
- """Download the images from the query table.
96
-
97
- Args:
98
- table (pd.DataFrame): The table with the images to download.
99
- out_csv (Optional[pathlib.Path], optional): The path to the
100
- CSV file with the query table. Defaults to None.
101
- quiet (Optional[bool], optional): If True, the download
102
- process is not displayed. Defaults to False.
103
- force (Optional[bool], optional): If True, the download
104
- process is done again. Defaults to False.
105
-
106
- Returns:
107
- pathlib.Path: The path to the folder with the downloaded images.
108
- """
109
-
110
- # Create the output directory if it does not exist
111
- if out_folder is None:
112
- output_path: pathlib.Path = self.output_dir / "s2_01_raw"
113
-
114
- # Download the selected images
115
- if not output_path.exists() or force:
116
- if not quiet:
117
- print(f"Saving the images in the directory {output_path}")
118
-
119
- fastcubo.getPixels(
120
- table=table, nworkers=self.max_workers, output_path=output_path
121
- )
122
-
123
- # Add folder path
124
- table["folder"] = output_path
125
-
126
- return table
127
-
128
- def cloudmasking_s2(
129
- self,
130
- table: pd.DataFrame,
131
- out_folder: Optional[pathlib.Path] = None,
132
- quiet: Optional[bool] = False,
133
- force: Optional[bool] = False,
134
- ) -> pathlib.Path:
135
- """Remove the clouds from the data.
136
-
137
- Args:
138
- table (pd.DataFrame): The table with the images to remove
139
- the clouds.
140
- out_csv (Optional[pathlib.Path], optional): The path to the
141
- CSV file with the query table. Defaults to None.
142
- quiet (Optional[bool], optional): If True, the messages
143
- are not displayed. Defaults to False.
144
- force (Optional[bool], optional): If True, the cloud removal
145
- is done again. Defaults to False.
146
-
147
- Returns:
148
- pathlib.Path: The path to the folder with the
149
- data without clouds.
150
- """
151
-
152
- if out_folder is None:
153
- out_folder: pathlib = self.output_dir / "s2_02_nocloud"
154
-
155
- # Apply the cloud removal
156
- out_table = intermediate_process(
157
- table=table,
158
- out_folder=out_folder,
159
- process_function=cloudmasking_s2,
160
- process_function_args=dict(
161
- device=self.device,
162
- sensor=self.sensor,
163
- quiet=quiet
164
- ),
165
- force=force,
166
- )
167
-
168
- # Change the folder path
169
- out_table["folder"] = out_folder
170
-
171
- # Sort by cloud cover
172
- out_table = out_table.sort_values(by="cloud_cover", ascending=False)
173
- out_table.reset_index(drop=True, inplace=True)
174
-
175
- return out_table
176
-
177
- def gapfilling_s2(
178
- self,
179
- table: pd.DataFrame,
180
- method: Optional[str] = "linear",
181
- out_folder: Optional[pathlib.Path] = None,
182
- quiet: Optional[bool] = False,
183
- force: Optional[bool] = False,
184
- ) -> pathlib.Path:
185
- """Fill the gaps in the data.
186
-
187
- Args:
188
- force (Optional[bool], optional): If True, the gap filling
189
- is done again. Defaults to False.
190
- histogram_match_error (float, optional): If the error in the
191
- histogram matching is greater than this value, the image
192
- is not filled and therefore, it is removed. Defaults
193
- to 0.10.
194
-
195
- Returns:
196
- pathlib.Path: The path to the folder with the
197
- data without gaps.
198
- """
199
-
200
- if out_folder is None:
201
- out_folder: pathlib = self.output_dir / "s2_03_nogaps"
202
-
203
- # Apply the cloud removal
204
- out_table = intermediate_process(
205
- table=table,
206
- out_folder=out_folder,
207
- process_function=gapfilling_s2,
208
- process_function_args={"method": method, "quiet": quiet},
209
- force=force,
210
- )
211
-
212
- # Change the folder path
213
- out_table["folder"] = out_folder
214
-
215
- # Sort by the matching error
216
- out_table = out_table.sort_values(by="match_error", ascending=False)
217
-
218
- return out_table
219
-
220
- def align_s2(
221
- self,
222
- table: pd.DataFrame,
223
- out_folder: Optional[pathlib.Path] = None,
224
- quiet: Optional[bool] = False,
225
- force: Optional[bool] = False,
226
- ) -> pathlib.Path:
227
- """Align all the images in the data cube.
228
-
229
- Args:
230
- table (pd.DataFrame): The table with the images to align.
231
- force (Optional[bool], optional): If True, the alignment
232
- is done again. Defaults to False.
233
-
234
- Returns:
235
- pathlib.Path: The path to the folder with the
236
- aligned images.
237
- """
238
-
239
- if out_folder is None:
240
- out_folder: pathlib = self.output_dir / "s2_04_aligned"
241
-
242
- # Apply the cloud removal
243
- out_table = intermediate_process(
244
- table=table,
245
- out_folder=out_folder,
246
- process_function=aligned_s2,
247
- process_function_args={"quiet": quiet},
248
- force=force,
249
- )
250
-
251
- # Change the folder path
252
- out_table["folder"] = out_folder
253
-
254
- return out_table
255
-
256
- def monthly_composites_s2(
257
- self,
258
- table: Optional[pd.DataFrame],
259
- out_folder: Optional[pathlib.Path] = None,
260
- agg_method: Optional[str] = "median",
261
- date_range: Tuple[str, str] = ("2016-01-01", datetime.now().strftime("%Y-%m-%d")),
262
- quiet: Optional[bool] = False,
263
- force: Optional[bool] = False,
264
- ) -> pathlib.Path:
265
- """Smooth the data considering the temporal dimension.
266
-
267
- Args:
268
- force (Optional[bool], optional): If True, the interpolation
269
- is done again. Defaults to False.
270
-
271
- Returns:
272
- xr.Dataset: The interpolated data.
273
- """
274
-
275
- if out_folder is None:
276
- out_folder: pathlib = self.output_dir / "s2_05_monthlycomposites"
277
-
278
- # Prepare the composites
279
- out_table = intermediate_process(
280
- table=table,
281
- out_folder=out_folder,
282
- process_function=monthly_composites_s2,
283
- process_function_args=dict(
284
- agg_method=agg_method,
285
- date_range=date_range,
286
- quiet=quiet
287
- ),
288
- force=force
289
- )
290
-
291
- # Change the folder path
292
- out_table["folder"] = out_folder
293
-
294
- return out_table
295
-
296
- def interpolate_s2(
297
- self,
298
- table: pd.DataFrame,
299
- out_folder: Optional[pathlib.Path] = None,
300
- quiet: Optional[bool] = False,
301
- force: Optional[bool] = False,
302
- ) -> pathlib.Path:
303
- """Interpolate the data.
304
-
305
- Args:
306
- force (Optional[bool], optional): If True, the interpolation
307
- is done again. Defaults to False.
308
-
309
- Returns:
310
- xr.Dataset: The interpolated data.
311
- """
312
-
313
- if out_folder is None:
314
- out_folder: pathlib = self.output_dir / "s2_06_interpolation"
315
-
316
- # Apply the cloud removal
317
- out_table = intermediate_process(
318
- table=table,
319
- out_folder=out_folder,
320
- process_function=interpolate_s2,
321
- process_function_args=dict(
322
- quiet=quiet
323
- ),
324
- force=force,
325
- )
326
-
327
- # Change the folder path
328
- out_table["folder"] = out_folder
329
-
330
- return out_table
331
-
332
- def smooth_s2(
333
- self,
334
- table: pd.DataFrame,
335
- out_folder: Optional[pathlib.Path] = None,
336
- smooth_w: Optional[int] = 7,
337
- smooth_p: Optional[int] = 1,
338
- device: Union[str, torch.device, None] = None,
339
- quiet: Optional[bool] = False,
340
- force: Optional[bool] = False,
341
- ) -> pd.DataFrame:
342
- """Interpolate the data.
343
-
344
- Args:
345
- force (Optional[bool], optional): If True, the interpolation
346
- is done again. Defaults to False.
347
-
348
- Returns:
349
- xr.Dataset: The interpolated data.
350
- """
351
- if out_folder is None:
352
- out_folder: pathlib = self.output_dir / "s2_07_smoothed"
353
-
354
- # Apply the cloud removal
355
- out_table = intermediate_process(
356
- table=table,
357
- out_folder=out_folder,
358
- process_function=smooth_s2,
359
- process_function_args=dict(
360
- quiet=quiet,
361
- smooth_w=smooth_w,
362
- smooth_p=smooth_p,
363
- device=device if device is not None else self.device
364
- ),
365
- force=force,
366
- )
367
-
368
- # Change the folder path
369
- out_table["folder"] = out_folder
370
-
371
- return out_table
372
-
373
-
374
- def super_s2(
375
- self,
376
- table: pd.DataFrame,
377
- out_folder: Optional[pathlib.Path] = None,
378
- quiet: Optional[bool] = False,
379
- force: Optional[bool] = False,
380
- ) -> pd.DataFrame:
381
- """Superresolution to the Sentinel-2 image cube.
382
-
383
- Args:
384
- table (pd.DataFrame): The table with the images to
385
- superresolve.
386
- out_folder (Optional[pathlib.Path], optional): The path to the
387
- CSV file with the query table. Defaults to None.
388
- quiet (Optional[bool], optional): If True, the messages
389
- are not displayed. Defaults to False.
390
- force (Optional[bool], optional): If True, the superresolution
391
- is done again. Defaults to False.
392
-
393
- Returns:
394
- pd.DataFrame: The table with the superresolved images.
395
- """
396
-
397
- if out_folder is None:
398
- out_folder: pathlib.Path = self.output_dir / "s2_08_superresolution"
399
-
400
- # Apply the Superresolution process
401
- out_table = intermediate_process(
402
- table=table,
403
- out_folder=out_folder,
404
- process_function=super_s2,
405
- process_function_args=dict(
406
- device=self.device,
407
- sensor=self.sensor,
408
- quiet=quiet
409
- ),
410
- force=force,
411
- )
412
-
413
- # Change the folder path
414
- out_table["folder"] = out_folder
415
-
416
- return out_table
417
-
418
- def display_images(
419
- self,
420
- table: pd.DataFrame,
421
- out_folder: Optional[pathlib.Path] = None,
422
- bands: Optional[list[str]] = [2, 1, 0],
423
- ratio: Optional[int] = 3000,
424
- ) -> pathlib.Path:
425
- """ Display the images in the table.
426
-
427
- Args:
428
- table (pd.DataFrame): The table with the images to display.
429
- out_folder (Optional[pathlib.Path], optional): The path to the
430
- CSV file with the query table. Defaults to None.
431
- bands (Optional[list[str]], optional): The bands to display.
432
- Defaults to [2, 1, 0].
433
- ratio (Optional[int], optional): The ratio to divide the
434
- image. Defaults to 3000. The larger the number, the
435
- darker the image.
436
-
437
- Returns:
438
- pathlib.Path: The path to the folder with the
439
- displayed images.
440
- """
441
-
442
- # Create the output folder
443
- out_folder = (
444
- self.output_dir / ("z_" + table["folder"].iloc[0].name + "_png")
445
- )
446
- out_folder.mkdir(exist_ok=True, parents=True)
447
-
448
- return display_images(
449
- table=table,
450
- out_folder=out_folder,
451
- bands=bands,
452
- ratio=ratio,
453
- )