TOWARDSAI.NET
From Ashes to Algorithms: How GOES Satellites and Python Can Protect Wildlife and Communities
Author(s): Ruiz Rivera Originally published on Towards AI. Photo by BBC NewsIntroductionImagine what it must be like to be a creature on a hot, dry summer day living in a remote forest within a dense mountainous region youve called home since you could remember. Imagine youre a small, less mobile creature. Maybe youre thinking of a pup, a cub, a fawn, or a mouse. Take your pick.So far, nothing about this day seems to be any different than the last. That is until you smell an unfamiliar scent thats difficult to inhale at first. Youre not sure what it is but the scent continues to be more potent and its at this point that your instincts are telling you to flee. You start running towards a direction where you sense the air isnt as thick as before. Unfortunately, the limited size and strength of your legs neither allow you to travel very far or very quickly due to your small stature. Whats worse is that the scent is now overpowering at this point. Its nauseating. Choking. Stinging your eyes. And worse, the temperature around you is now increasing to the point that you find it unbearable.You look back and you see something menacing approaching. Its the orange hue of what we know to be flames swallowing the surrounding trees. You have never encountered anything like this before but your brain is frantically screaming at your legs to move, to escape. But all your senses are impaired, either from the scorch of the flames or the lack of oxygen from the smoke. Either way, you feel the heat from the fire surrounding you as you desperately struggle to breathe, see, or even flee to safety.And then it begins. The flames make contact with your skin and now every pore of your body is experiencing a scintillating, unimaginable pain. Tears flood your eyes and you scream in agony as your flesh blackens from the inferno for what seems to feel like an eternity.Suddenly, you experience a moment of tranquility like the kind you feel before falling into a deep, long, peaceful sleep. The pain has disappeared. Key memories you hold dear then start flashing rapidly as the world around you fades.While this may only be an approximation of what a creature with limited mobility experiences in their final moments during a wildfire, it doesnt take much reasoning to conclude that countless creatures once inhabiting a fire-ravaged forest undergo some version of this excruciating ending. Theres possibly no worse ending imaginable than the experience of writhing in anguish from being burnt alive.As elaborate as it was, this exposition is meant to illustrate how consequential it is to detect and respond to a wildfire as early as possible since it can be the difference between life and death for many of the creatures inhabiting the forest. With our purpose in mind, the work of Data Analytics professionals, Wildfire Researchers, and open-source developers who can bridge various domains to detect and forecast wildfires has never been more important in an age where mass summer burns are now a norm. With tools such as open-source access to near real-time satellite monitoring systems, developers can give emergency responders, First Nations leaders, government agencies, and community stakeholders an advantage in the damage control that wildfires cause. Thanks to the countless scientists and engineers who have worked on developing the hardware for such systems and open-source algorithms to detect environmental anomalies, the tools to keep our ecosystems and communities safe have never been more accessible! In the following sections, well explore how to access NASAs GOES-16/17 satellites using nothing but Python and Googles Earth Engine API to build near real-time fire detection capabilities.Scoping GOES-16 and GOES-17In a previous article, we introduced the basics of remote sensing using the data captured by the Sentinel-2 satellites by highlighting its strengths and weaknesses, particularly in the use-case of building a wildfire perimeter. Luckily, we are not limited by a single source of failure as we have other systems to shore up the vulnerabilities of Sentinel-2, such as the aforementioned GOES-16 and GOES-17 satellites.Before we go further, lets quickly double click on how these satellites work and how they differ from others that are currently in orbit. The Geostationary Operational Environmental Satellites (GOES) are a set of geostationary satellites which takes high temporal resolution images every 515 min, with each pixel having a resolution of about 0.5 to 2 km (NOAA & NASA, 2024). When we refer to a satellite as geostationary, it means that it orbits the Earth in the same direction about 35,000 km above the equator and at about the same speed so that from the perspective of a ground-bound observer, the satellite appears nearly stationary. Among the two satellites we mentioned earlier, GOES-16 does the majority of the image capture over the North and South American continent while GOES-17 functions as a ready spare when necessary (NOAA & NASA, 2024).On board each GOES satellite is the Advanced Baseline Imager (ABI) instrument for imaging the Earths weather, oceans, and environment through its 16 different spectral bands (NOAA & NASA, n.d.). While tracking the flow of wildfire is the use case were most interested in, these satellites can also provide independent data sources for monitoring things like cloud formation, land surface temperature, ocean dynamics, volcanic ash plumes, vegetative health and more. Because our GOES satellites can take snapshots every 515 minutes, decision-makers can rely on the monitoring and fire perimeter we build from this data to inform their emergency response. In contrast to Sentinel-2, GOES satellites are also capable of gathering data 24/7 through their thermal infrared bands which do not rely on sunlight (NOAA & NASA, n.d.). Additionally, it is also capable of penetrating cloud cover by snapping images during windows where the cover is less dense (NOAA & NASA, n.d.).Now that weve gotten the brief overview of the GOES-16/17 satellites out of the way, lets start extracting data again from the Earth Engine Data Catalog using the same parameters we used earlier to locate the Lytton Creek wildfire during the end of June 2021. As we can see, we extracted over 4,000 images from each satellite due to its ability to snap images in lightning-quick 515 minute intervals.import eeimport foliumimport geemap.core as geemapimport numpy as npimport pandas as pdimport pprintimport pytzimport matplotlib.pyplot as pltfrom IPython.display import Imagefrom datetime import datetime# Gathering satellite datagoes_16 = ee.ImageCollection("NOAA/GOES/16/FDCF").filterDate(start_date, end_date).filterBounds(poi)goes_17 = ee.ImageCollection("NOAA/GOES/17/FDCF").filterDate(start_date, end_date).filterBounds(poi)# Example: print the number of images in the collections (optional)print(f"Number of GOES-16 images: {goes_16.size().getInfo()}")print(f"Number of GOES-17 images: {goes_17.size().getInfo()}")# Getting a feel for the data we've extracted from the Earth Engine datasetpprint.pp(goes_17.first().getInfo())Lets also load the map_from_map_codes_to_confidence_values() and apply_scale_factors() functions the team at Google provided us to process our data.def map_from_mask_codes_to_confidence_values(image): return image.clip(poi).remap(fire_mask_codes, confidence_values, default_confidence_value)# Applies scaling factors.def apply_scale_factors(image): optical_bands = image.select("SR_B.").multiply(0.0000275).add(-0.2) thermal_bands = image.select("ST_B.*").multiply(0.00341802).add(149.0) return image.addBands(optical_bands, None, True).addBands( thermal_bands, None, True )Overview of the Fire Detection Characterization (FDC) AlgorithmNow that weve talked a little bit about the satellites used to generate the data, lets discuss how we are to detect the presence of wildfires based on these images. Luckily for us, Google makes this easy by giving developers easy access to the FDC Fire Detection algorithm which was developed by a research team at the University of Wisconsin-Madison.The primary objective of the FDC Fire Detection algorithm is to return the likelihood of a fire based on the pixel data of an input image (Restif & Hoffman, 2020). For those interested, below is a brief overview of the steps that the FDC Fire detection algorithm takes to accomplish this objective:1) First, the algorithm takes the data from the thermal infrared (TIR) band of the satellite sensor (band 14), as well as the shortwave infrared (SWIR) band (7), and converts the brightness of each pixel to a temperature;2) Next, it flags certain TIR pixels based on whether they exceed a certain threshold. Examples of such thresholds include:Absolute threshold based on a set temperature;Relative threshold based on the delta between a pixels temperature and its neighbours exceeding a set amount.3) If a pixel is flagged, it checks for false positives by evaluating the temperature of its neighbouring pixels just like in the previous step. When checking the temperature of the pixel, we can choose to apply a different threshold from step 2 if we wish. And in the case of our code example below, we do just that by applying a relative threshold instead.4) If our neighbouring pixel also exceeds the threshold, it will then apply one last check for false positives by evaluating whether the delta/difference between the pixel temperature produced by the TIR (band 14) and the SWIR (band 7) band exceeds a relative threshold.5) And if the difference between the TIR and SWIR pixel temperatures exceeds our relative threshold, the algorithm will return a 1 or a True result, confirming that the pixel in question is indeed a fire pixel.Our code below is a simplified demonstration of Steps 15 of the FDC algorithm. However, our explanation only covers the presence of a fire based on the pixels brightness so the final result of our simplified FDC algorithm is a binary True/False value.# Fire Detection Characterization (FDC) Algorithm example implementation# Simulated satellite image datadef create_simulated_data(width=50, height=50): # Create background temperature (avg 290 Kelvin or 16.85 degrees Celsius) background = np.random.normal(290, 2, (height, width)) # Add some hotter spots (potential fires) with temperatures between 310 to 330 Kelvins (i.e. 36.85 to 56.85 degrees Celsius) num_hotspots = 5 for _ in range(num_hotspots): x, y = np.random.randint(0, width), np.random.randint(0, height) hotspot_temp = np.random.uniform(310, 330) background[y, x] = hotspot_temp return background# Simplified FDC algorithm - our absolute thereshold is 310K or 36.85 degreesdef simplified_fdc(image_4um, image_11um, absolute_threshold=310, relative_threshold=10): height, width = image_4um.shape fire_mask = np.zeros((height, width), dtype=bool) for i in range(1, height-1): for j in range(1, width-1): # Step 1: Check absolute threshold if image_4um[i, j] > absolute_threshold: # Step 2: Calculate background background = np.mean(image_4um[i-1:i+2, j-1:j+2]) # Step 3: Check relative threshold if image_4um[i, j] - background > relative_threshold: # Step 4: Multi-channel confirmation if image_4um[i, j] - image_11um[i, j] > 10: fire_mask[i, j] = True return fire_mask# Create simulated dataimage_4um = create_simulated_data()image_11um = image_4um - np.random.normal(10, 2, image_4um.shape) # 11um channel is typically cooler# Apply simplified FDC algorithmfire_detections = simplified_fdc(image_4um, image_11um)# Visualize resultsfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))im1 = ax1.imshow(image_4um, cmap="hot")ax1.set_title("Simulated 4m Channel")plt.colorbar(im1, ax=ax1, label="Temperature (K)")ax2.imshow(image_4um, cmap="gray")ax2.imshow(fire_detections, cmap="Reds", alpha=0.5)ax2.set_title("FDC Algorithm Fire Detections")plt.tight_layout()plt.show()print(f"Number of fire pixels detected: {np.sum(fire_detections)}")Source: Image by the authorNumber of fire pixels detected: 4# Visualize resultsfig1, (ax3, ax4) = plt.subplots(1, 2, figsize=(12, 5))im2 = ax3.imshow(image_11um, cmap="hot")ax3.set_title("Simulated 11m Channel")plt.colorbar(im2, ax=ax3, label="Temperature (K)")ax4.imshow(image_11um, cmap="gray")ax4.imshow(fire_detections, cmap="Reds", alpha=0.5)ax4.set_title("FDC Algorithm Fire Detections")plt.tight_layout()plt.show()print(f"Number of fire pixels detected: {np.sum(fire_detections)}")Source: Image by the authorNumber of fire pixels detected: 4Applying the Fire Detection Algorithm (FDC)There are additional steps associated with the algorithm such as estimating its fire radiative power (FRP) which represents the brightness or intensity of a fire in the confirmed pixel. From there, the algorithm then assigns a confidence value towards the probability of an actual fire being reflected from the pixel and plots it on a map to build a fire perimeter.For the sake of brevity, we can cover the complexities behind these confidence values in a future article so for now, take these explanations at face value. At this point in the code, we are now assigning confidence_values between 50-100% to the outputs produced by the algorithm. With a single output, if the algorithm returns a value of 15, it's classifying it as a low probability fire pixel at 50% and in contrast, if it returns a value of 10, there's a near 100% probability that it is a processed fire pixel (Restif & Hoffman, 2020). The resulting values from this process are captured in the goes_16_confidence and goes_17_confidence objects in the following code.# Conversion from mask codes to confidence values.fire_mask_codes = [10, 30, 11, 31, 12, 32, 13, 33, 14, 34, 15, 35]confidence_values = [1.0, 1.0, 0.9, 0.9, 0.8, 0.8, 0.5, 0.5, 0.3, 0.3, 0.1, 0.1]default_confidence_value = 0# Processing the GOES-16 satellite imagesgoes_16_confidence = goes_16.select(["Mask"]).map(map_from_mask_codes_to_confidence_values)goes_16_max_confidence = goes_16_confidence.reduce(ee.Reducer.max())# Processing the GOES-17 satellite imagesgoes_17_confidence = goes_17.select(["Mask"]).map(map_from_mask_codes_to_confidence_values)goes_17_max_confidence = goes_17_confidence.reduce(ee.Reducer.max())Data VisualizationNow, one last thing. Since the satellites collect data over a specific time range, the probability of a fire in a given pixel may vary greatly due to the evolving nature of the on-ground event. Although the temporal aspect of the data itself contains plenty of valuable information, in this instance, were more concerned with generating a broad outline of the fire boundary. To do so, we can use the ee.Reducer.max() function to return the highest confidence value of each pixel within the specified time range (Restif & Hoffman, 2020). We'll apply this to both the goes_16_confidence and the goes_17_confidence objects before overlaying the specific pixel plots on our map below.# We can visualize that initial data processing step from each satellite, using:affected_area_palette = ["white", "yellow", "orange", "red", "purple"]earth_engine_viz = { "opacity": 0.3, "min": 0, "max": 1, "palette": affected_area_palette }# Create a map.Map = geemap.Map()Map.centerObject(poi, 9)Map.addLayer(poi, {"color": "green"}, "Area of interest", True, 0.2)Map.addLayer(goes_16_max_confidence, earth_engine_viz, "GOES-16 maximum confidence")Map.addLayer(goes_17_max_confidence, earth_engine_viz, "GOES-17 maximum confidence")MapSource: Image by the authorFrom our initial results, we can see two iterations of the FDC Algorithm layered over top of each other on the map. We can combine the results of our two satellite images to increase the spatial resolution of our wildfire perimeter using the ee.Reducer.min() function which returns the lesser of the two confidence values where the two layers intersect (Restif & Hoffman, 2020).# Combine the confidence values from both GOES-16 and GOES-17 using the minimum reducercombined_confidence = ee.ImageCollection([goes_16_max_confidence, goes_17_max_confidence]).reduce(ee.Reducer.min())# Create a mapMap = geemap.Map()Map.centerObject(poi, 9)Map.addLayer(poi, {"color": "green"}, "Area of interest", True, 0.2)Map.addLayer(combined_confidence, earth_engine_viz, "Combined confidence")# Display the mapMapSource: Image by the authorWith the results of our two satellites combined, notice how the generated boundary is highly pixelated due to the image quality of the satellites. One last thing we can do to our wildfire boundary is to smooth the boundaries between the combined fire masks using the ee.Image.reduceNeighborhood() function.# Define the kernel for smoothingkernel = ee.Kernel.square(2000, "meters", True)# Apply the smoothing using reduceNeighborhood with the mean reducersmoothed_confidence = combined_confidence.reduceNeighborhood( reducer=ee.Reducer.mean(), kernel=kernel, optimization="boxcar")# Create a mapMap = geemap.Map()Map.centerObject(poi, 9)Map.addLayer(poi, {"color": "green"}, "Area of interest", True, 0.2)Map.addLayer(smoothed_confidence, earth_engine_viz, "Smoothed confidence")# Display the mapMapSource: Image by the authorThere you have it! A near real-time wildfire boundary using Python to deploy the FDC Algorithm on GOES-16 and 17 satellite images from Googles Data Catalog platform. However, as with most technologies, the use of the FDC on GOES-16/17 images doesnt come without its weaknesses which well discuss to have a better understanding of the situations where other technologies would be more appropriate.One risk with using the FDC algorithm on GOES-16/17 images is its tendency to detect false positives with an image. For example, reflective surfaces from buildings in urban areas or lakes and dry vegetation in a forest may be misconstrued as a fire.Additionally, the image resolution from GOES-16/17 satellites is poorer compared to other data collection techniques. We saw this first-hand from the pixelated fire perimeter we produced in our initial effort applying the FDC algorithm. The reason why the wildfire perimeter was so pixelated is because each pixel captures anywhere between 436 squared kilometers depending on how far the area is from the centre of the image. Due to the spherical shape of the Earth and the satellites position, the farther an area is from the centre of an image, the lower its image quality. For wildfire detection, what this means is that activities smaller than the pixel size may either be mischaracterized or missed completely.Another aspect to consider is the terrain of the area of interest. This risk is mostly attributed to mountainous terrain where the lee ward side of a mountain may obfuscate a satellites view in that area.To mitigate these risks, we must use other imaging techniques and technologies alongside GOES-16/17 data to gain a clearer understanding of the ground situation. As weve previously discussed, high-resolution data from Sentinel-2 and Landsat satellites can be highly complementary when theyre available as it allows us to cross-validate our resulting wildfire boundaries. On top of that, ground observations and aerial drone surveys add another layer of validation to a highly dynamic event.By executing the FDC algorithm on GOES-16/17 data, theres little doubt that this approach can be a powerful asset in helping us build wildfire perimeters in real-time as part of a broader mitigation strategy with other sensory techniques.Thank you for taking the time to read through our work! If youre interested in learning more, please feel free to check out our open source repository where we continue to research ways to improve the Government of British Columbias (Canada) detection and response to wildfires across the province. Additionally, feel free to access notebook associated to this article if you would like to run the code in its entirety.See you in our next post ResourcesNational Oceananic and Atmospheric Association (NOAA) & National Aeronautics and Space Administration (NASA). (2024). Beginners guide to GOES-R series data: How to acquire, analyze, and visualize GOES-R Series data. https://www.goes-r.gov/downloads/resources/documents/Beginners_Guide_to_GOES-R_Series_Data.pdfNational Oceananic and Atmospheric Association (NOAA) & National Aeronautics and Space Administration (NASA). (n.d.). Instruments: Advanced baseline imager (ABI). https://www.goes-r.gov/spacesegment/abi.htmlRestif, C. & Hoffman, A. (2020, November 20). How to generate wildfire boundary maps with Earth Engine. Medium. https://medium.com/google-earth/how-to-generate-wildfire-boundary-maps-with-earth-engine-b38eadc97a38Schmidt, C., Hoffman, J., Prins, E., & Lindstrom, S. (2012, July 30). GOES-R Advanced Baseline Imager (ABI) algorithm theoretical basis document for fire / hot spot characterization. NOAA NESDIS Center for Satellite Applications and Research. https://www.star.nesdis.noaa.gov/goesr/docs/ATBD/Fire.pdfJoin thousands of data leaders on the AI newsletter. Join over 80,000 subscribers and keep up to date with the latest developments in AI. From research to projects and ideas. If you are building an AI startup, an AI-related product, or a service, we invite you to consider becoming asponsor. Published via Towards AI
0 Comentários 0 Compartilhamentos 26 Visualizações