6
6
7
7
import numpy as np
8
8
import rasterio
9
+ from affine import Affine
9
10
from loguru import logger
10
11
from osgeo import gdal
11
12
from osgeo import osr
13
+ from rasterio import warp
14
+ from rasterio .crs import CRS
15
+ from rasterio .enums import Resampling
12
16
from rasterio .merge import merge as riomerge
13
17
from satextractor .models import ExtractionTask
14
18
from satextractor .models import Tile
15
19
16
20
21
+ def get_window_union (
22
+ tiles : List [Tile ],
23
+ ds : rasterio .io .DatasetReader ,
24
+ ) -> rasterio .windows .Window :
25
+
26
+ """Get the window union to read all tiles from the geotiff.
27
+
28
+ Args:
29
+ tiles (List[Tile]): the tiles
30
+ ds (rasterio.io.DatasetReader): the rasterio dataset to read (for the transform)
31
+
32
+ Returns:
33
+ rasterio.windows.Window: The union of all tile windows.
34
+ """
35
+
36
+ windows = []
37
+
38
+ for tile in tiles :
39
+
40
+ bounds_arr_tile_crs = tile .bbox
41
+ bounds_arr_rast_crs = warp .transform_bounds (
42
+ CRS .from_epsg (tile .epsg ),
43
+ ds .crs ,
44
+ * bounds_arr_tile_crs ,
45
+ )
46
+
47
+ window = rasterio .windows .from_bounds (* bounds_arr_rast_crs , ds .transform )
48
+
49
+ windows .append (window )
50
+
51
+ return rasterio .windows .union (windows )
52
+
53
+
17
54
def get_proj_win (tiles : List [Tile ]) -> Tuple [int , int , int , int ]:
18
55
"""Get the projection bounds window of the tiles.
19
56
@@ -48,6 +85,69 @@ def get_tile_pixel_coords(tiles: List[Tile], raster_file: str) -> List[Tuple[int
48
85
return list (zip (rows , cols ))
49
86
50
87
88
+ def download_and_extract_tiles_window_COG (
89
+ fs : Any ,
90
+ task : ExtractionTask ,
91
+ resolution : int ,
92
+ ) -> List [str ]:
93
+ """Download and extract from the task assets the data for the window from each asset.
94
+
95
+ Args:
96
+ task (ExtractionTask): The extraction task
97
+ resolution (int): The target resolution
98
+
99
+ Returns:
100
+ List[str]: A list of files that store the crops of the original assets
101
+ """
102
+
103
+ # task tiles all have same CRS, so get their max extents and crs
104
+ left , top , right , bottom = get_proj_win (task .tiles )
105
+ epsg = task .tiles [0 ].epsg
106
+
107
+ # set the transforms for the output file
108
+ dst_transform = Affine (resolution , 0.0 , left , 0.0 , - resolution , top )
109
+ out_shp = (int ((right - left ) / resolution ), int ((top - bottom ) / resolution ))
110
+
111
+ outfiles = []
112
+
113
+ band = task .band
114
+ urls = [item .assets [band ].href for item in task .item_collection .items ]
115
+
116
+ for ii , url in enumerate (urls ):
117
+ with fs .open (url ) as f :
118
+ with rasterio .open (f ) as ds :
119
+ window = get_window_union (task .tiles , ds )
120
+
121
+ rst_arr = ds .read (
122
+ 1 ,
123
+ window = window ,
124
+ out_shape = out_shp ,
125
+ fill_value = 0 ,
126
+ boundless = True ,
127
+ resampling = Resampling .bilinear ,
128
+ )
129
+
130
+ out_f = f"{ task .task_id } _{ ii } .tif"
131
+
132
+ with rasterio .open (
133
+ out_f ,
134
+ "w" ,
135
+ driver = "GTiff" ,
136
+ count = 1 ,
137
+ width = out_shp [0 ],
138
+ height = out_shp [1 ],
139
+ transform = dst_transform ,
140
+ crs = CRS .from_epsg (epsg ),
141
+ dtype = rst_arr .dtype ,
142
+ ) as dst :
143
+
144
+ dst .write (rst_arr , indexes = 1 )
145
+
146
+ outfiles .append (out_f )
147
+
148
+ return outfiles
149
+
150
+
51
151
def download_and_extract_tiles_window (
52
152
download_f : Callable ,
53
153
task : ExtractionTask ,
@@ -112,7 +212,7 @@ def task_mosaic_patches(
112
212
cloud_fs : Any ,
113
213
download_f : Callable ,
114
214
task : ExtractionTask ,
115
- method : str = "first " ,
215
+ method : str = "max " ,
116
216
resolution : int = 10 ,
117
217
dst_path = "merged.jp2" ,
118
218
) -> List [np .ndarray ]:
@@ -121,14 +221,18 @@ def task_mosaic_patches(
121
221
Args:
122
222
download_f (Callable): The function to download the task assets
123
223
task (ExtractionTask): The task
124
- method (str, optional): The method to use while merging the assets. Defaults to "first ".
224
+ method (str, optional): The method to use while merging the assets. Defaults to "max ".
125
225
resolution (int, optional): The target resolution. Defaults to 10.
126
226
dst_path (str): path to store the merged files
127
227
128
228
Returns:
129
229
List[np.ndarray]: The tile patches as numpy arrays
130
230
"""
131
- out_files = download_and_extract_tiles_window (download_f , task , resolution )
231
+
232
+ if task .constellation == "sentinel-2" :
233
+ out_files = download_and_extract_tiles_window (download_f , task , resolution )
234
+ else :
235
+ out_files = download_and_extract_tiles_window_COG (cloud_fs , task , resolution )
132
236
133
237
out_f = f"{ task .task_id } _{ dst_path } "
134
238
datasets = [rasterio .open (f ) for f in out_files ]
0 commit comments