Skip to content

Commit a0053fa

Browse files
committed
added example notebooks
1 parent 938106f commit a0053fa

File tree

5 files changed

+327
-78
lines changed

5 files changed

+327
-78
lines changed

CHANGELOG.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ Changelog
55
--------------------
66
Added
77
*******
8-
-support for L2A product level
8+
- support for L2A product level
9+
- example notebooks
910

1011
Changed
1112
*******

README.md

+4-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ If you use ukis-csmask in your work, please consider citing one of the above pub
2323

2424
![Examples](img/examples.png)
2525

26-
## Example (Sentinel-2 Level-1C)
26+
## Example
2727
Here's an example on how to compute a cloud and cloud shadow mask from an image. Please note that here we use [ukis-pysat](https://github.com/dlr-eoc/ukis-pysat) for convencience image handling, but you can also work directly with [numpy](https://numpy.org/) arrays. Further examples can be found [here](examples).
2828

2929
````python
@@ -32,8 +32,9 @@ from ukis_pysat.raster import Image, Platform
3232

3333
# read Level-1C image from file, convert digital numbers to TOA reflectance
3434
# and make sure resolution is 30 m to get best performance
35+
band_order = ["blue", "green", "red", "nir", "swir16", "swir22"]
3536
img = Image(data="sentinel2.tif", dimorder="last")
36-
img.dn2toa(platform=Platform.Sentinel2)
37+
img.dn2toa(platform=Platform.Sentinel2, wavelength=band_order)
3738
img.warp(
3839
resampling_method=0,
3940
resolution=30,
@@ -45,7 +46,7 @@ img.warp(
4546
# make sure to use these six spectral bands to get best performance
4647
csmask = CSmask(
4748
img=img.arr,
48-
band_order=["blue", "green", "red", "nir", "swir16", "swir22"],
49+
band_order=band_order,
4950
nodata_value=0,
5051
)
5152

examples/landsat8_l1c.ipynb

+158
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"# Segment clouds and cloud shadows in Landsat-8 images (L1C)\n",
8+
"This notebook shows an example on how to use [ukis-csmask](https://github.com/dlr-eoc/ukis-csmask) to segment clouds and cloud shadows in Level-1C images from Landsat-8. Images are loaded from local file system. Here we use [ukis-pysat](https://github.com/dlr-eoc/ukis-pysat) for convencience image handling, but you can also work directly with [numpy](https://numpy.org/) arrays.\n",
9+
"\n",
10+
"> NOTE: to run this notebook, we first need to install some additional dependencies for image handling\n",
11+
"```shell\n",
12+
"pip install ukis-pysat[complete]\n",
13+
"```"
14+
]
15+
},
16+
{
17+
"cell_type": "code",
18+
"execution_count": null,
19+
"id": "703f3744-902d-470b-a80f-9a8d3ea08dfa",
20+
"metadata": {},
21+
"outputs": [],
22+
"source": [
23+
"import rasterio\n",
24+
"import numpy as np\n",
25+
"\n",
26+
"from pathlib import Path\n",
27+
"from ukis_csmask.mask import CSmask\n",
28+
"from ukis_pysat.raster import Image, Platform"
29+
]
30+
},
31+
{
32+
"cell_type": "code",
33+
"execution_count": null,
34+
"id": "c9cd86e4",
35+
"metadata": {},
36+
"outputs": [],
37+
"source": [
38+
"# user settings\n",
39+
"data_path = \"/your_data_path/\"\n",
40+
"L8_file_prefix = \"LC08_L1TP_191015_20210428_20210507_02_T1\"\n",
41+
"product_level = \"l1c\"\n",
42+
"band_order = [\"blue\", \"green\", \"red\", \"nir\", \"swir16\", \"swir22\"]\n",
43+
"providers = [\"CUDAExecutionProvider\"]\n",
44+
"out_dir = \"ukis-csmask/examples\""
45+
]
46+
},
47+
{
48+
"cell_type": "code",
49+
"execution_count": null,
50+
"id": "8ca03c78-1e24-479c-9786-a1b43206a08b",
51+
"metadata": {},
52+
"outputs": [],
53+
"source": [
54+
"# set Landsat 8 source path and prefix (example)\n",
55+
"data_path = data_path + L8_file_prefix + \"/\"\n",
56+
"mtl_file = data_path + L8_file_prefix + \"_MTL.txt\"\n",
57+
"\n",
58+
"# stack [B2:'Blue', B3:'Green', B4:'Red', B5:'NIR', B6:'SWIR1', B7:'SWIR2'] as numpy array\n",
59+
"L8_band_files = [data_path + L8_file_prefix + \"_B\" + x + \".TIF\" for x in [str(x + 2) for x in range(6)]]\n",
60+
"\n",
61+
"# >> adopted from https://gis.stackexchange.com/questions/223910/using-rasterio-or-gdal-to-stack-multiple-bands-without-using-subprocess-commands\n",
62+
"# read metadata of first file\n",
63+
"with rasterio.open(L8_band_files[0]) as src0:\n",
64+
" meta = src0.meta\n",
65+
"# update meta to reflect the number of layers\n",
66+
"meta.update(count=len(L8_band_files))\n",
67+
"# read each layer and append it to numpy array\n",
68+
"L8_bands = []\n",
69+
"for id, layer in enumerate(L8_band_files, start=1):\n",
70+
" with rasterio.open(layer) as src1:\n",
71+
" L8_bands.append(src1.read(1))\n",
72+
"L8_bands = np.stack(L8_bands, axis=2)\n",
73+
"# <<\n",
74+
"\n",
75+
"img = Image(data=L8_bands, crs=meta[\"crs\"], transform=meta[\"transform\"], dimorder=\"last\")\n",
76+
"img.dn2toa(platform=Platform.Landsat8, mtl_file=mtl_file, wavelengths=band_order)\n",
77+
"img.warp(resampling_method=0, resolution=30, dst_crs=img.dataset.crs)"
78+
]
79+
},
80+
{
81+
"cell_type": "code",
82+
"execution_count": null,
83+
"id": "7b568942-84e6-4baf-b490-a213b3787f80",
84+
"metadata": {},
85+
"outputs": [],
86+
"source": [
87+
"# compute cloud and cloud shadow mask\n",
88+
"csmask = CSmask(\n",
89+
" img=img.arr,\n",
90+
" band_order=band_order,\n",
91+
" product_level=product_level,\n",
92+
" nodata_value=0,\n",
93+
" invalid_buffer=4,\n",
94+
" intra_op_num_threads=0,\n",
95+
" inter_op_num_threads=0,\n",
96+
" providers=providers,\n",
97+
" batch_size=1,\n",
98+
")\n",
99+
"\n",
100+
"# access cloud and cloud shadow mask as numpy array\n",
101+
"csm = csmask.csm\n",
102+
"\n",
103+
"# access valid mask as numpy array\n",
104+
"valid = csmask.valid"
105+
]
106+
},
107+
{
108+
"cell_type": "code",
109+
"execution_count": null,
110+
"id": "68eb9c30-06f7-409e-914d-21e00f45de99",
111+
"metadata": {},
112+
"outputs": [],
113+
"source": [
114+
"# convert results to ukis-pysat Image\n",
115+
"# this assigns back the georeference\n",
116+
"csm = Image(csm, transform=img.dataset.transform, crs=img.dataset.crs, dimorder=\"last\")\n",
117+
"valid = Image(valid, transform=img.dataset.transform, crs=img.dataset.crs, dimorder=\"last\")\n",
118+
"\n",
119+
"# write results to file\n",
120+
"csm.write_to_file(\n",
121+
" path_to_file=Path(out_dir) / Path(f\"{L8_file_prefix}_csm.tif\"),\n",
122+
" dtype=csm.dtype,\n",
123+
" driver=\"COG\",\n",
124+
" compress=\"LZW\",\n",
125+
" kwargs={\"BLOCKSIZE\": 512, \"BIGTIFF\": \"IF_SAFER\"},\n",
126+
")\n",
127+
"valid.write_to_file(\n",
128+
" path_to_file=Path(out_dir) / Path(f\"{L8_file_prefix}_valid.tif\"),\n",
129+
" dtype=valid.dtype,\n",
130+
" driver=\"COG\",\n",
131+
" compress=\"LZW\",\n",
132+
" kwargs={\"BLOCKSIZE\": 512, \"BIGTIFF\": \"IF_SAFER\"},\n",
133+
")"
134+
]
135+
}
136+
],
137+
"metadata": {
138+
"kernelspec": {
139+
"display_name": "Python 3 (ipykernel)",
140+
"language": "python",
141+
"name": "python3"
142+
},
143+
"language_info": {
144+
"codemirror_mode": {
145+
"name": "ipython",
146+
"version": 3
147+
},
148+
"file_extension": ".py",
149+
"mimetype": "text/x-python",
150+
"name": "python",
151+
"nbconvert_exporter": "python",
152+
"pygments_lexer": "ipython3",
153+
"version": "3.11.10"
154+
}
155+
},
156+
"nbformat": 4,
157+
"nbformat_minor": 5
158+
}

examples/landsat_l2a.ipynb

+28-74
Original file line numberDiff line numberDiff line change
@@ -5,66 +5,62 @@
55
"metadata": {},
66
"source": [
77
"# Segment clouds and cloud shadows in Landsat images (L2A)\n",
8-
"This notebook shows an example on how to use [ukis-csmask]() to segment clouds and cloud shadows in Level-2A images from Landsat-9, Landsat-8, Landsat-7 and Landsat-5 satellites. Images are acquired from [Planetary Computer]() and are prepared according to [ukis-csmask]() requirements.\n",
8+
"This notebook shows an example on how to use [ukis-csmask](https://github.com/dlr-eoc/ukis-csmask) to segment clouds and cloud shadows in Level-2A images from Landsat-9, Landsat-8, Landsat-7 and Landsat-5 satellites. Images are acquired from [Planetary Computer](https://planetarycomputer.microsoft.com) and are preprocessed.\n",
99
"\n",
1010
"> NOTE: to run this notebook, we first need to install some additional dependencies for work with Planetary Computer\n",
1111
"```shell\n",
12-
"pip install planetary_computer pystac-client odc-stac tqdm\n",
13-
"pip install -e git+https://github.com/dlr-eoc/ukis-csmask/tree/l2a#egg=ukis-csmask[gpu]\n",
12+
"$ pip install planetary_computer rioxarray pystac-client odc-stac tqdm\n",
1413
"```"
1514
]
1615
},
1716
{
1817
"cell_type": "code",
19-
"execution_count": 1,
18+
"execution_count": null,
2019
"id": "703f3744-902d-470b-a80f-9a8d3ea08dfa",
2120
"metadata": {},
2221
"outputs": [],
2322
"source": [
2423
"import numpy as np\n",
2524
"import planetary_computer as pc\n",
25+
"import rioxarray\n",
2626
"\n",
2727
"from odc.stac import load\n",
28+
"from pathlib import Path\n",
2829
"from pystac_client import Client\n",
2930
"from tqdm import tqdm\n",
30-
"from ukis_csmask.mask import CSmask"
31+
"from ukis_csmask.mask import CSmask\n",
32+
"from xarray import DataArray"
3133
]
3234
},
3335
{
3436
"cell_type": "code",
35-
"execution_count": 13,
37+
"execution_count": null,
3638
"id": "8ca03c78-1e24-479c-9786-a1b43206a08b",
3739
"metadata": {},
3840
"outputs": [],
3941
"source": [
42+
"# user settings\n",
4043
"stac_api_endpoint = \"https://planetarycomputer.microsoft.com/api/stac/v1\"\n",
4144
"collections = [\"landsat-c2-l2\"]\n",
4245
"ids = [\n",
43-
" \"LC09_L2SP_194027_20240604_02_T1\",\n",
44-
" \"LC08_L2SP_191027_20240607_02_T1\",\n",
45-
" \"LE07_L2SP_192027_20050805_02_T1\",\n",
46-
" \"LT05_L2SP_192026_20100726_02_T1\",\n",
46+
" \"LC09_L2SP_192027_20240403_02_T2\",\n",
47+
" \"LC08_L2SP_192027_20240801_02_T1\",\n",
48+
" \"LE07_L2SP_192027_20000722_02_T1\",\n",
49+
" \"LT05_L2SP_192027_20100726_02_T1\",\n",
4750
"]\n",
48-
"bbox = [11.016, 47.666, 12.238, 48.472]\n",
51+
"bbox = [11.540, 47.463, 12.117, 47.872]\n",
4952
"product_level = \"l2a\"\n",
5053
"band_order = [\"blue\", \"green\", \"red\", \"nir\", \"swir16\", \"swir22\"]\n",
51-
"providers = [\"CUDAExecutionProvider\"]"
54+
"providers = [\"CUDAExecutionProvider\"]\n",
55+
"out_dir = \"ukis-csmask/examples\""
5256
]
5357
},
5458
{
5559
"cell_type": "code",
56-
"execution_count": 15,
60+
"execution_count": null,
5761
"id": "7b568942-84e6-4baf-b490-a213b3787f80",
5862
"metadata": {},
59-
"outputs": [
60-
{
61-
"name": "stdout",
62-
"output_type": "stream",
63-
"text": [
64-
"Search returned 4 item(s)\n"
65-
]
66-
}
67-
],
63+
"outputs": [],
6864
"source": [
6965
"# search catalog by scene id\n",
7066
"catalog = Client.open(stac_api_endpoint)\n",
@@ -76,54 +72,11 @@
7672
},
7773
{
7874
"cell_type": "code",
79-
"execution_count": 18,
75+
"execution_count": null,
8076
"id": "68eb9c30-06f7-409e-914d-21e00f45de99",
8177
"metadata": {},
82-
"outputs": [
83-
{
84-
"name": "stderr",
85-
"output_type": "stream",
86-
"text": [
87-
"Predict images: 0%| | 0/4 [00:00<?, ?it/s]"
88-
]
89-
},
90-
{
91-
"name": "stderr",
92-
"output_type": "stream",
93-
"text": [
94-
"Predict images: 0%| | 0/4 [02:25<?, ?it/s]"
95-
]
96-
},
97-
{
98-
"name": "stdout",
99-
"output_type": "stream",
100-
"text": [
101-
"(6, 6038, 7076) float32\n"
102-
]
103-
},
104-
{
105-
"name": "stderr",
106-
"output_type": "stream",
107-
"text": [
108-
"\n"
109-
]
110-
},
111-
{
112-
"ename": "FileNotFoundError",
113-
"evalue": "[Errno 2] No such file or directory: '/mnt/data1/Workspace/python/ukis-csmask/src/ukis-csmask/ukis_csmask/model_6b_l2a.json'",
114-
"output_type": "error",
115-
"traceback": [
116-
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
117-
"\u001b[0;31mFileNotFoundError\u001b[0m Traceback (most recent call last)",
118-
"Cell \u001b[0;32mIn[18], line 33\u001b[0m\n\u001b[1;32m 30\u001b[0m \u001b[38;5;28mprint\u001b[39m(arr\u001b[38;5;241m.\u001b[39mshape, arr\u001b[38;5;241m.\u001b[39mdtype)\n\u001b[1;32m 32\u001b[0m \u001b[38;5;66;03m# compute cloud and cloud shadow mask\u001b[39;00m\n\u001b[0;32m---> 33\u001b[0m csmask \u001b[38;5;241m=\u001b[39m \u001b[43mCSmask\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 34\u001b[0m \u001b[43m \u001b[49m\u001b[43mimg\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mnp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmoveaxis\u001b[49m\u001b[43m(\u001b[49m\u001b[43marr\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mto_numpy\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 35\u001b[0m \u001b[43m \u001b[49m\u001b[43mband_order\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mband_order\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 36\u001b[0m \u001b[43m \u001b[49m\u001b[43mproduct_level\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mproduct_level\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 37\u001b[0m \u001b[43m \u001b[49m\u001b[43mnodata_value\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 38\u001b[0m \u001b[43m \u001b[49m\u001b[43minvalid_buffer\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m4\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 39\u001b[0m \u001b[43m \u001b[49m\u001b[43mintra_op_num_threads\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 40\u001b[0m \u001b[43m \u001b[49m\u001b[43minter_op_num_threads\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 41\u001b[0m \u001b[43m \u001b[49m\u001b[43mproviders\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mproviders\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 42\u001b[0m \u001b[43m \u001b[49m\u001b[43mbatch_size\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 43\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 45\u001b[0m \u001b[38;5;66;03m# access cloud and cloud shadow mask\u001b[39;00m\n\u001b[1;32m 46\u001b[0m csmask_csm \u001b[38;5;241m=\u001b[39m csmask\u001b[38;5;241m.\u001b[39mcsm\n",
119-
"File \u001b[0;32m/mnt/data1/Workspace/python/ukis-csmask/src/ukis-csmask/ukis_csmask/mask.py:90\u001b[0m, in \u001b[0;36mCSmask.__init__\u001b[0;34m(self, img, band_order, product_level, nodata_value, invalid_buffer, intra_op_num_threads, inter_op_num_threads, providers, batch_size)\u001b[0m\n\u001b[1;32m 85\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 86\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(\n\u001b[1;32m 87\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mband_order must contain at least \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mblue\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mgreen\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mred\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mnir\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 88\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mand for better performance also \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mswir16\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m and \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mswir22\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 89\u001b[0m )\n\u001b[0;32m---> 90\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28;43mopen\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mPath\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmodel_file\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mwith_suffix\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m.json\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m f:\n\u001b[1;32m 91\u001b[0m model_dict \u001b[38;5;241m=\u001b[39m json\u001b[38;5;241m.\u001b[39mload(f)\n\u001b[1;32m 93\u001b[0m \u001b[38;5;66;03m# start onnx inference session and load model\u001b[39;00m\n",
120-
"\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: '/mnt/data1/Workspace/python/ukis-csmask/src/ukis-csmask/ukis_csmask/model_6b_l2a.json'"
121-
]
122-
}
123-
],
78+
"outputs": [],
12479
"source": [
125-
"import rioxarray\n",
126-
"\n",
12780
"for item in tqdm(items, total=items_cnt, desc=\"Predict images\"):\n",
12881
" # near infrared band has different alias in landsat collections\n",
12982
" bands = [b.replace(\"nir\", \"nir08\") for b in band_order]\n",
@@ -143,15 +96,13 @@
14396
" .drop_vars(\"time\")\n",
14497
" )\n",
14598
" arr = arr.rename({\"variable\": \"band\"})\n",
146-
" arr.rio.to_raster(raster_path=\"l8.tif\", driver=\"COG\")\n",
14799
"\n",
148100
" # use band-specific rescale factors to convert DN to reflectance\n",
149101
" for idx, band_name in enumerate(bands):\n",
150102
" band_info = item.assets[band_name].extra_fields[\"raster:bands\"][0]\n",
151103
" arr[idx, :, :] = arr.sel(band=str(band_name)).astype(np.float32) * band_info[\"scale\"]\n",
152104
" arr[idx, :, :] += band_info[\"offset\"]\n",
153105
" arr[idx, :, :] = arr[idx, :, :].clip(min=0.0, max=1.0)\n",
154-
" print(arr.shape, arr.dtype)\n",
155106
"\n",
156107
" # compute cloud and cloud shadow mask\n",
157108
" csmask = CSmask(\n",
@@ -166,11 +117,14 @@
166117
" batch_size=1,\n",
167118
" )\n",
168119
"\n",
169-
" # access cloud and cloud shadow mask\n",
170-
" csmask_csm = csmask.csm\n",
171-
"\n",
172-
" # access valid mask\n",
173-
" csmask_valid = csmask.valid"
120+
" # write image, csm and valid mask to file\n",
121+
" arr.rio.to_raster(raster_path=Path(out_dir) / Path(f\"{item.id}.tif\"), driver=\"COG\")\n",
122+
" DataArray(np.squeeze(np.moveaxis(csmask.csm, -1, 0)), coords=arr.sel(band=arr[\"band\"][0]).coords).rio.to_raster(\n",
123+
" raster_path=Path(out_dir) / Path(f\"{item.id}_csm.tif\"), driver=\"COG\"\n",
124+
" )\n",
125+
" DataArray(np.squeeze(np.moveaxis(csmask.valid, -1, 0)), coords=arr.sel(band=arr[\"band\"][0]).coords).rio.to_raster(\n",
126+
" raster_path=Path(out_dir) / Path(f\"{item.id}_valid.tif\"), driver=\"COG\"\n",
127+
" )"
174128
]
175129
}
176130
],

0 commit comments

Comments
 (0)