Skip to content

Commit be308fc

Browse files
committed
clean up and final push
1 parent c51878f commit be308fc

4 files changed

+91
-107
lines changed

README.md

+25-9
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ Project funded by NASA Applied Sciences Program and developed by ESOC and Earth
1111
Our project aims to extende the EarthLab’s "Fire Event Delineation for Python (FIREDpy)" library by updating it for Near-Real-Time (NRT) fire event perimeter mapping through the fusion of optical and radar remote sensing data. Our main motivations are twofold: to achieve closer-to-real-time temporal resolution and to improve the spatial resolution of the FIREDpy outputs.
1212

1313
In the first stage of the project, we focused on answering two questions:
14-
- Is applying BRDF correction necessary to generated NRT fire perimeters?
15-
- How does fire affect the signal in Sentinel-2 and Landsat-8 images and how do these satellites compare?
14+
- __Q1.__ Is applying BRDF correction necessary to generated NRT fire perimeters?
15+
- __Q2.__ How does fire affect the signal in Sentinel-2 and Landsat-8 images and how do these satellites compare?
1616

17-
### BERDF Correction
17+
Below, I will explain how I approached each question. To run the scripts in this repository, you should create a conda environment using the `environment.yml` file. Follow the instructions provided [here](https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#creating-an-environment-from-an-environment-yml-file) to do so.
18+
19+
### Q1. BERDF Correction
1820
The flowchart below demonstrates the steps I took to answer the first question, with the caveat that I only tested BRDF on Sentinel-2 images (using the Sen2nbar package) since I couldn't find any python implementation of this correction for Landsat images.
1921

2022
<img src="./images/Flowchart.jpg" width=800>
@@ -33,22 +35,36 @@ or alternatively,
3335

3436
In these commands, the value of the `event_id` (or `id`) argument must be the ID of the fire event for which satellite images are to be searched. This comes from the id field of the [fire events shapefile](./fire_events/Fire_events.zip). The value of the `satellite` (or `s`) argument must be the name of the satellite, either "sentinel" or "landsat".
3537

38+
#### Important Note:
39+
Before running the `optical_scenes.py` script, you should create separate accounts for Landsat and Sentinel API and set your username and password in the corresponidng variables in the `config.py` file.
40+
3641
You can set or change the search criteria in the `config.py` file. These parameters are:
3742
- `max_cloud_cover`: Maximum cloud cover percentage. default: 40%.
3843
- `delta_days_landsat`: The number of days to use as a buffer before and after the fire event when searching for Landsat images. default: 70 days.
3944
- `delta_days_sentinel`: The number of days to use as a buffer before and after the fire event when searching for Sentinel-2 images. default: 40 days.
40-
- `download_scenes`: Whether to download images or not. default: False. __CAUTION: depending on the number of the images found, this could take a long time and might reqiure a huge amount of storage__
41-
- `save_footprints`: Whether to save image footprints or not. default: False.
45+
- `download_scenes`: Whether to download images or not. default: False. __CAUTION: depending on the number of the images found, this could take a long time and might reqiure a huge amount of storage__.
46+
- `save_footprints`: Whether to save image footprints or not. default: True.
4247
- `update_json`: deprecated.
4348
- `data_dir`: The directory where the images and/or their footprints will be saved. See below for more information.
4449

50+
My suggestion is to first run the script with the default values for `download_scenes` and `save_footprints`. This will give you the footprints and all the available metadata of all the images that satisfy the search criteria in a geojson format. You can then look at the image footprint and metadata, decide which images you'd like to download, and then run the script again to download only those images (with `download_scenes=True`). However, if you decide to do so, __you should remember to modify the `get_landsat()` and `get_sentinel()` functions inside `optical_scenes.py` following the instructions provided there__
51+
4552
#### Directory Organization
46-
`data_dir` is the directory where the you would want the images to be saved. Once you create this directory, extract (unzip) the `Fire_events.zip` there. This will (should) create a new subdirectory called Fire_events. Per each fire id you run the `optical_scenes.py` script for, a new subdirectory will be created within "Fire_events". Also, depending on what the `-s` parameter is, the corresponding subdirectory will be created within the fire_id folder where the footprints and images will be saved.
53+
`data_dir` is the directory where the you would want the images to be saved. Once you create this directory, extract (unzip) the "Fire_events.zip" there. This will (should) create a new subdirectory called Fire_events. Per each fire id you run the `optical_scenes.py` script for, a new subdirectory will be created within "Fire_events". Also, depending on what the `-s` parameter is, the corresponding subdirectory will be created within the fire_id folder where the footprints and images will be saved.
4754

4855
<img src="./images/directory_tree.png" width="300">
4956

5057

51-
#### Important Note:
52-
Before running the `optical_scenes.py` script, you should create separate accounts for Landsat and Sentinel API and set your username and password in the corresponidng variables in the `config.py` file.
5358

54-
### Optical Signal Evaluation
59+
### Q2. Optical Signal Evaluation
60+
To perform the optical signal evaluation and visualize the results, you can use the jupyter notebooks provided here: One for Sentinel-2 ([Sentinel Image Analysis.ipynb](./scripts/Sentinel%20Image%20Analysis.ipynb)) images, and one for Landsat-8 images ([Landsat Image Analysis.ipynb](./scripts/Landsat%20Image%20Analysis.ipynb)). These notebooks are designed in a modular fashion, meaning that the functions used in these notebooks can be used outside of the notebooks for further investivation and analysis. They should be self-explanatory given the docstrings and comments provided. If you have any questions, please contact Behzad.
61+
62+
Assuming that you have already downlaoded the pre- and post-fire images for that fire in the previous step, to run these notebooks, you should:
63+
1. Change `fire_id` in cell #3 to the fire ID of your interest
64+
2. Change `image_dir` in cell #4 to the directory where your images are located.
65+
3. Change `fire_events` to reflect the directory where your fire shapefile is saved (assuming you have followed the directory structure explained above).
66+
4. The `MASK_IMAGES` variable in these notebooks determines whether the calculations should be masked to the perimeter of the fire or not. Recommended values: `True` when calculating dNBR or applying BRDF, `False` when you want to create and RGB or false color composite image.
67+
5. These notebooks assume _exactly one_ image before the fire and _exactly one_ image after the fire. If you have more images, you should modify the notebooks.
68+
69+
You should run the notebooks once per fire event.
70+

environment.yml

14.2 KB
Binary file not shown.

scripts/Landsat Images - signal evaluation.ipynb scripts/Landsat Image Analysis.ipynb

+37-87
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,8 @@
1717
"from glob import glob\n",
1818
"import os\n",
1919
"from matplotlib.colors import ListedColormap, BoundaryNorm\n",
20-
"from utils import draw_legend"
21-
]
22-
},
23-
{
24-
"cell_type": "code",
25-
"execution_count": 2,
26-
"id": "bb4b746e",
27-
"metadata": {},
28-
"outputs": [],
29-
"source": [
20+
"from utils import draw_legend\n",
21+
"from config import Config\n",
3022
"from rasterio.enums import Resampling"
3123
]
3224
},
@@ -38,7 +30,9 @@
3830
"outputs": [],
3931
"source": [
4032
"import warnings\n",
41-
"warnings.filterwarnings('ignore')"
33+
"warnings.filterwarnings('ignore')\n",
34+
"config = Config()\n",
35+
"dir_separator = config.dir_sep"
4236
]
4337
},
4438
{
@@ -51,6 +45,17 @@
5145
"fire_id = \"202\""
5246
]
5347
},
48+
{
49+
"cell_type": "code",
50+
"execution_count": 13,
51+
"id": "66357e9e",
52+
"metadata": {},
53+
"outputs": [],
54+
"source": [
55+
"image_dir = f\"E:/Projects/UCB/FiredPy/data/Fire_events/{fire_id}/Landsat/\"\n",
56+
"file_address = glob(os.path.join(image_dir, '*_T1'))"
57+
]
58+
},
5459
{
5560
"cell_type": "code",
5661
"execution_count": 5,
@@ -145,7 +150,7 @@
145150
" xarray.DataArray: The multi-band image with the NIR and SWIR bands.\n",
146151
" \"\"\"\n",
147152
" bands = [] \n",
148-
" image_path = image_dir.split(\"\\\\\")[-1]\n",
153+
" image_path = image_dir.split(dir_separator)[-1]\n",
149154
" \n",
150155
" if MASK_IMAGES:\n",
151156
" nir = rioxarray.open_rasterio(f\"{image_dir}/{image_path}_B5.{ext}\").rio.clip(mask_geom, fire_events.crs)\n",
@@ -205,7 +210,7 @@
205210
" Returns:\n",
206211
" xarray.DataArray: The RGB image with the red, green, and blue bands.\n",
207212
" \"\"\"\n",
208-
" image_path = image_dir.split(\"\\\\\")[-1]\n",
213+
" image_path = image_dir.split(dir_separator)[-1]\n",
209214
" \n",
210215
" if MASK_IMAGES:\n",
211216
" rgb = [rioxarray.open_rasterio(f\"{image_dir}/{image_path}_B{x}.{ext}\").rio.clip(mask_geom, fire_events.crs) for x in [4,3,2]]\n",
@@ -249,7 +254,7 @@
249254
" Returns:\n",
250255
" xarray.DataArray: The false-color image with the shortwave infrared, near-infrared, and red bands.\n",
251256
" \"\"\" \n",
252-
" image_path = image_dir.split(\"\\\\\")[-1]\n",
257+
" image_path = image_dir.split(dir_separator)[-1]\n",
253258
" \n",
254259
" if MASK_IMAGES:\n",
255260
" image = [rioxarray.open_rasterio(f\"{image_dir}/{image_path}_B{x}.{ext}\").rio.clip(mask_geom, fire_events.crs) for x in [7,5,4]]\n",
@@ -297,17 +302,6 @@
297302
" return NBR"
298303
]
299304
},
300-
{
301-
"cell_type": "code",
302-
"execution_count": 13,
303-
"id": "66357e9e",
304-
"metadata": {},
305-
"outputs": [],
306-
"source": [
307-
"image_dir = f\"E:/Projects/UCB/FiredPy/data/Fire_events/{fire_id}/Landsat/\"\n",
308-
"file_address = glob(os.path.join(image_dir, '*_T1'))"
309-
]
310-
},
311305
{
312306
"cell_type": "code",
313307
"execution_count": 14,
@@ -340,6 +334,7 @@
340334
]
341335
},
342336
{
337+
"attachments": {},
343338
"cell_type": "markdown",
344339
"id": "b5684035",
345340
"metadata": {},
@@ -542,15 +537,25 @@
542537
"fig.savefig(f'images/masked/Landsat/classified_dNBR_event_{fire_id}.png', dpi=300, bbox_inches='tight')"
543538
]
544539
},
540+
{
541+
"attachments": {},
542+
"cell_type": "markdown",
543+
"id": "faa6b451",
544+
"metadata": {},
545+
"source": [
546+
"### Save Tiff files"
547+
]
548+
},
545549
{
546550
"cell_type": "code",
547551
"execution_count": 20,
548552
"id": "74677997",
549553
"metadata": {},
550554
"outputs": [],
551555
"source": [
556+
"# save pre and postfire NBRs as tiff files\n",
552557
"for image_dir, label in zip(file_address, labels):\n",
553-
" f_name = os.path.join(image_dir.split(\"\\\\\")[0], f'NBR_{label}.tif')\n",
558+
" f_name = os.path.join(image_dir.split(dir_separator)[0], f'NBR_{label}.tif')\n",
554559
" nbr_raws[label].rio.to_raster(f_name)"
555560
]
556561
},
@@ -561,7 +566,8 @@
561566
"metadata": {},
562567
"outputs": [],
563568
"source": [
564-
"f_name_diff = os.path.join(image_dir.split(\"\\\\\")[0], f'dNBR pre-post fire.tif')\n",
569+
"# save dNBR as tiff file\n",
570+
"f_name_diff = os.path.join(image_dir.split(dir_separator)[0], f'dNBR pre-post fire.tif')\n",
565571
"dNBR_post_raw.rio.to_raster(f_name_diff)"
566572
]
567573
},
@@ -582,11 +588,12 @@
582588
"metadata": {},
583589
"outputs": [],
584590
"source": [
591+
"# Save pre and postfire RGB images as tiff files\n",
585592
"rgb_images = dict.fromkeys(labels, None)\n",
586593
"for image_dir, label in zip(file_address, labels):\n",
587594
" rgb = open_RGB(image_dir, \"TIF\", False, False)\n",
588595
" rgb_images[label] = rgb\n",
589-
" f_name = os.path.join(image_dir.split(\"\\\\\")[0], f'RGB_{label}.tif')\n",
596+
" f_name = os.path.join(image_dir.split(dir_separator)[0], f'RGB_{label}.tif')\n",
590597
" rgb_images[label].rio.to_raster(f_name)"
591598
]
592599
},
@@ -597,57 +604,16 @@
597604
"metadata": {},
598605
"outputs": [],
599606
"source": [
607+
"# Save pre and postfire false color composite image as tiff\n",
600608
"fcc_images = dict.fromkeys(labels, None)\n",
601609
"\n",
602610
"for image_dir, label in zip(file_address, labels):\n",
603611
" rgb = open_false_color(image_dir, \"TIF\", False, False)\n",
604612
" fcc_images[label] = rgb\n",
605-
" f_name = os.path.join(image_dir.split(\"\\\\\")[0], f'false_color_{label}.tif')\n",
613+
" f_name = os.path.join(image_dir.split(dir_separator)[0], f'false_color_{label}.tif')\n",
606614
" fcc_images[label].rio.to_raster(f_name)"
607615
]
608616
},
609-
{
610-
"cell_type": "code",
611-
"execution_count": 17,
612-
"id": "89b08c77",
613-
"metadata": {},
614-
"outputs": [
615-
{
616-
"data": {
617-
"text/plain": [
618-
"((23223, 16350), (23193, 16590))"
619-
]
620-
},
621-
"execution_count": 17,
622-
"metadata": {},
623-
"output_type": "execute_result"
624-
}
625-
],
626-
"source": [
627-
"nir_pre.shape, nir_post.shape"
628-
]
629-
},
630-
{
631-
"cell_type": "code",
632-
"execution_count": 18,
633-
"id": "2fa3701c",
634-
"metadata": {},
635-
"outputs": [
636-
{
637-
"data": {
638-
"text/plain": [
639-
"((23223, 16350), (23193, 16590))"
640-
]
641-
},
642-
"execution_count": 18,
643-
"metadata": {},
644-
"output_type": "execute_result"
645-
}
646-
],
647-
"source": [
648-
"swir_pre.shape, swir_post.shape"
649-
]
650-
},
651617
{
652618
"cell_type": "code",
653619
"execution_count": 15,
@@ -716,22 +682,6 @@
716682
"# fig.savefig(f'images/masked/Landsat/NIR_and_SWIR_difference_event_{fire_id}.png', dpi=300)"
717683
]
718684
},
719-
{
720-
"cell_type": "code",
721-
"execution_count": null,
722-
"id": "769be370",
723-
"metadata": {},
724-
"outputs": [],
725-
"source": []
726-
},
727-
{
728-
"cell_type": "code",
729-
"execution_count": null,
730-
"id": "230c2f51",
731-
"metadata": {},
732-
"outputs": [],
733-
"source": []
734-
},
735685
{
736686
"cell_type": "code",
737687
"execution_count": 20,

0 commit comments

Comments
 (0)