sen2p 0.0.1__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.
- sen2p/__init__.py +1 -0
- sen2p/download.py +157 -0
- sen2p-0.0.1.dist-info/METADATA +78 -0
- sen2p-0.0.1.dist-info/RECORD +6 -0
- sen2p-0.0.1.dist-info/WHEEL +5 -0
- sen2p-0.0.1.dist-info/top_level.txt +1 -0
sen2p/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .download import download
|
sen2p/download.py
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import List, Optional, Dict, Any, Union
|
|
3
|
+
from tqdm import tqdm
|
|
4
|
+
import xarray as xr
|
|
5
|
+
import rioxarray as rxr
|
|
6
|
+
import geopandas as gpd
|
|
7
|
+
from shapely.geometry import mapping, Point
|
|
8
|
+
from pystac_client import Client
|
|
9
|
+
import planetary_computer as pc
|
|
10
|
+
from rasterio.enums import Resampling
|
|
11
|
+
|
|
12
|
+
def download(
|
|
13
|
+
start_date: str,
|
|
14
|
+
end_date: str,
|
|
15
|
+
location: Union[List[float], Dict[str, Any], str],
|
|
16
|
+
bands: Optional[List[str]] = None,
|
|
17
|
+
output_dir: Optional[str] = None,
|
|
18
|
+
show_progress: bool = True,
|
|
19
|
+
merge_bands: bool = False,
|
|
20
|
+
merged_filename: Optional[str] = None,
|
|
21
|
+
overwrite: bool = False,
|
|
22
|
+
cell_size: Optional[float] = None,
|
|
23
|
+
max_items: int = 10,
|
|
24
|
+
collection: str = "sentinel-2-l2a"
|
|
25
|
+
) -> List[Dict[str, Any]]:
|
|
26
|
+
'''
|
|
27
|
+
Download Sentinel-2 data from Planetary Computer using search parameters.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
start_date (str): Start date (e.g., "2023-06-01").
|
|
31
|
+
end_date (str): End date (e.g., "2023-06-30").
|
|
32
|
+
location (list, dict, or str): [lon, lat], GeoJSON geometry, or path to shapefile.
|
|
33
|
+
bands (list, optional): List of bands to download (e.g., ["B02", "B03"]).
|
|
34
|
+
output_dir (str, optional): Where to save output files.
|
|
35
|
+
show_progress (bool): Show download progress.
|
|
36
|
+
merge_bands (bool): Merge into single file.
|
|
37
|
+
merged_filename (str, optional): Filename for merged file.
|
|
38
|
+
overwrite (bool): Overwrite existing files.
|
|
39
|
+
cell_size (float, optional): Target resolution.
|
|
40
|
+
max_items (int): How many items to fetch.
|
|
41
|
+
collection (str): STAC collection name.
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
List of result dicts, one per STAC item.
|
|
45
|
+
'''
|
|
46
|
+
|
|
47
|
+
catalog = Client.open("https://planetarycomputer.microsoft.com/api/stac/v1", modifier=pc.sign_inplace)
|
|
48
|
+
|
|
49
|
+
if isinstance(location, list):
|
|
50
|
+
geometry = mapping(Point(location[0], location[1]))
|
|
51
|
+
elif isinstance(location, dict):
|
|
52
|
+
geometry = location
|
|
53
|
+
elif isinstance(location, str) and location.endswith(".shp"):
|
|
54
|
+
gdf = gpd.read_file(location)
|
|
55
|
+
geometry = mapping(gdf.unary_union)
|
|
56
|
+
else:
|
|
57
|
+
raise ValueError("Location must be [lon, lat], GeoJSON geometry, or shapefile path")
|
|
58
|
+
|
|
59
|
+
search = catalog.search(
|
|
60
|
+
collections=[collection],
|
|
61
|
+
intersects=geometry,
|
|
62
|
+
datetime=f"{start_date}/{end_date}",
|
|
63
|
+
max_items=max_items,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
items = list(search.get_items())
|
|
67
|
+
if not items:
|
|
68
|
+
raise ValueError("No Sentinel-2 items found for the given location and time range.")
|
|
69
|
+
|
|
70
|
+
all_results = []
|
|
71
|
+
|
|
72
|
+
for item in items:
|
|
73
|
+
item_id = item.id
|
|
74
|
+
available_assets = list(item.assets.keys())
|
|
75
|
+
|
|
76
|
+
if bands is None:
|
|
77
|
+
bands_to_download = [asset for asset in available_assets if asset.startswith("B")]
|
|
78
|
+
else:
|
|
79
|
+
missing_bands = [band for band in bands if band not in available_assets]
|
|
80
|
+
if missing_bands:
|
|
81
|
+
print(f"Skipping {item_id}: Missing bands {missing_bands}")
|
|
82
|
+
continue
|
|
83
|
+
bands_to_download = bands
|
|
84
|
+
|
|
85
|
+
item_output_dir = os.path.join(output_dir, item_id) if output_dir else None
|
|
86
|
+
if item_output_dir and not os.path.exists(item_output_dir):
|
|
87
|
+
os.makedirs(item_output_dir)
|
|
88
|
+
|
|
89
|
+
result = {}
|
|
90
|
+
band_data_arrays = []
|
|
91
|
+
resampled_arrays = []
|
|
92
|
+
band_names = []
|
|
93
|
+
progress_iter = tqdm(bands_to_download, desc=f"{item_id}") if show_progress else bands_to_download
|
|
94
|
+
|
|
95
|
+
for band in progress_iter:
|
|
96
|
+
band_url = item.assets[band].href
|
|
97
|
+
file_path = os.path.join(item_output_dir, f"{item.id}_{band}.tif") if item_output_dir else None
|
|
98
|
+
|
|
99
|
+
if file_path and os.path.exists(file_path) and not overwrite:
|
|
100
|
+
if show_progress:
|
|
101
|
+
progress_iter.write(f"{file_path} exists, skipping.")
|
|
102
|
+
if merge_bands:
|
|
103
|
+
band_data = rxr.open_rasterio(file_path)
|
|
104
|
+
band_data_arrays.append((band, band_data))
|
|
105
|
+
band_names.append(band)
|
|
106
|
+
result[band] = file_path
|
|
107
|
+
continue
|
|
108
|
+
|
|
109
|
+
if show_progress:
|
|
110
|
+
progress_iter.set_description(f"{item_id}: {band}")
|
|
111
|
+
|
|
112
|
+
band_data = rxr.open_rasterio(band_url)
|
|
113
|
+
if merge_bands:
|
|
114
|
+
band_data_arrays.append((band, band_data))
|
|
115
|
+
band_names.append(band)
|
|
116
|
+
|
|
117
|
+
if item_output_dir:
|
|
118
|
+
band_data.rio.to_raster(file_path)
|
|
119
|
+
result[band] = file_path
|
|
120
|
+
else:
|
|
121
|
+
result[band] = band_data
|
|
122
|
+
|
|
123
|
+
if merge_bands and item_output_dir:
|
|
124
|
+
merged_path = os.path.join(item_output_dir, merged_filename or f"{item.id}_merged.tif")
|
|
125
|
+
if os.path.exists(merged_path) and not overwrite:
|
|
126
|
+
if show_progress:
|
|
127
|
+
print(f"Merged file {merged_path} exists, skipping.")
|
|
128
|
+
result["merged"] = merged_path
|
|
129
|
+
else:
|
|
130
|
+
if cell_size is None and band_data_arrays:
|
|
131
|
+
cell_size = abs(band_data_arrays[0][1].rio.transform()[0])
|
|
132
|
+
elif cell_size is None:
|
|
133
|
+
cell_size = 10
|
|
134
|
+
|
|
135
|
+
for band_name, data_array in band_data_arrays:
|
|
136
|
+
current_res = abs(data_array.rio.transform()[0])
|
|
137
|
+
if abs(current_res - cell_size) > 0.01:
|
|
138
|
+
resampling_method = Resampling.bilinear if current_res < cell_size else Resampling.nearest
|
|
139
|
+
resampled = data_array.rio.reproject(
|
|
140
|
+
data_array.rio.crs,
|
|
141
|
+
resolution=(cell_size, cell_size),
|
|
142
|
+
resampling=resampling_method,
|
|
143
|
+
)
|
|
144
|
+
resampled_arrays.append(resampled)
|
|
145
|
+
else:
|
|
146
|
+
resampled_arrays.append(data_array)
|
|
147
|
+
|
|
148
|
+
merged_data = xr.concat(resampled_arrays, dim="band")
|
|
149
|
+
merged_data.attrs["description"] = f"Merged bands: {', '.join(band_names)}"
|
|
150
|
+
merged_data.rio.to_raster(merged_path, tags={"BAND_NAMES": ",".join(band_names)}, descriptions=band_names)
|
|
151
|
+
result["merged"] = merged_path
|
|
152
|
+
if show_progress:
|
|
153
|
+
print(f"Merged file written: {merged_path}")
|
|
154
|
+
|
|
155
|
+
all_results.append(result)
|
|
156
|
+
|
|
157
|
+
return all_results
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sen2p
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Download Sentinel-2 data from Microsoft Planetary Computer
|
|
5
|
+
Home-page: https://github.com/tnmthai/sen2p
|
|
6
|
+
Author: Thai Tran
|
|
7
|
+
Author-email: ThaiTran@outlook.co.nz
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
13
|
+
Requires-Python: >=3.8
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
Requires-Dist: planetary-computer
|
|
16
|
+
Requires-Dist: pystac-client
|
|
17
|
+
Requires-Dist: rioxarray
|
|
18
|
+
Requires-Dist: xarray
|
|
19
|
+
Requires-Dist: tqdm
|
|
20
|
+
Requires-Dist: geopandas
|
|
21
|
+
Requires-Dist: shapely
|
|
22
|
+
Dynamic: author
|
|
23
|
+
Dynamic: author-email
|
|
24
|
+
Dynamic: classifier
|
|
25
|
+
Dynamic: description
|
|
26
|
+
Dynamic: description-content-type
|
|
27
|
+
Dynamic: home-page
|
|
28
|
+
Dynamic: requires-dist
|
|
29
|
+
Dynamic: requires-python
|
|
30
|
+
Dynamic: summary
|
|
31
|
+
|
|
32
|
+
# Sentinel Downloader
|
|
33
|
+
|
|
34
|
+
This Python library allows you to download Sentinel-2 data from Microsoft Planetary Computer.
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install -e .
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Usage
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from sen2p import download
|
|
46
|
+
|
|
47
|
+
location = [172.1, -43.5]
|
|
48
|
+
|
|
49
|
+
results = download(
|
|
50
|
+
start_date="2023-06-01",
|
|
51
|
+
end_date="2023-06-10",
|
|
52
|
+
location=location,
|
|
53
|
+
bands=["B02", "B03", "B04"],
|
|
54
|
+
output_dir="test_outputs",
|
|
55
|
+
merge_bands=True,
|
|
56
|
+
max_items=3 # download up to 3 images
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
for r in results:
|
|
60
|
+
print("Downloaded:", r)
|
|
61
|
+
```
|
|
62
|
+
```python
|
|
63
|
+
from sen2p import download
|
|
64
|
+
|
|
65
|
+
# Path to your shapefile
|
|
66
|
+
shapefile_path = "Site.shp" # Update with your actual shapefile path
|
|
67
|
+
|
|
68
|
+
# Call the function
|
|
69
|
+
results = download(
|
|
70
|
+
start_date="2023-06-01",
|
|
71
|
+
end_date="2023-06-30",
|
|
72
|
+
location=shapefile_path,
|
|
73
|
+
bands=["B02", "B03", "B04"],
|
|
74
|
+
output_dir="test_output",
|
|
75
|
+
merge_bands=True,
|
|
76
|
+
max_items=5 # Download up to 5 matching images
|
|
77
|
+
)
|
|
78
|
+
```
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
sen2p/__init__.py,sha256=uHbP27YsU5dG2fGH97zyc_kzdTGKCPcAY9m2j0i7Wnw,31
|
|
2
|
+
sen2p/download.py,sha256=WjTuhc_EyKeRk_jpJwxBYupLZIqp4LKp-AEShUcy4is,6308
|
|
3
|
+
sen2p-0.0.1.dist-info/METADATA,sha256=43qaqMDVhtHfQ1bpNuRATwVfId0CS8CcpsD8WP6wX40,1825
|
|
4
|
+
sen2p-0.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
5
|
+
sen2p-0.0.1.dist-info/top_level.txt,sha256=iI3IMU2lB-xjusho-zqzlRXWCF4uBRNhI8lnqixO3bo,6
|
|
6
|
+
sen2p-0.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
sen2p
|