Exceptional rainfall in May caused heavy flooding in the Paris region. Newspapers and TVs reported that the Seine flood forced the Louvre staff to move away from rising waters the art pieces that were stored in their cellar. But they did not tell you that about 50 km east of the Louvre museum, the flood of the Grand Morin river in Coulommiers also inundated the cellar of my parents-in-law. I’m really concerned about this cellar because I care about my parents-in-law of course, and also because I have let some of my bottles of wine in their cellar.

 The theory tells us that the backscatter intensity received by a radar satellite drops over flooded soil because the emitted electromagnetic waves are specularly reflected off the water surface and thus does not return to the antenna (see e.g. slide 86 of this course on Radar Measurements by Chris Allen). In forest areas the opposite happens because reflections from the water surface will hit the trunks and canopy and thus enhance backscatter.

I used a simple demonstration script provided by the Google Earth Engine team to see if I can map flooded areas based on Sentinel-1 data. The algorithm takes two Sentinel-1 images that were pre-processed to backscatter coefficient in decibels after thermal noise removal, radiometric calibration and terrain correction.

This is the study area : the villages along the Grand Morin river near Coulommiers city are the most exposed to flooding in the area (click to zoom):

 This S1 image acquired on 14-May-2016 can be used as a reference image « before flooding »:

 Luckily there is an S1 image acquired on 31-May-2016 when the flood reached its maximum in the area (my mother-in-law, personal communication).

 The script computes the difference between both images and then applies a smoothing filter to reduce the effect of the speckle noise.

 Then this smoothed image is thresholded to identify potential « flooded » areas

 The same map with the « satellite » image as background:

 It shows that the largest differences between both S1 images are located in the meanders near the Grand Morin river, in open areas (without forest), which seems very plausible. I did not find good validation data, only some hints from the local newspaper « Le Pays Briard » that Pommeuse was severely hit by the flood..

I’m a newbie in radar remote sensing. These maps may be wrong, or at least taken with caution. If you are looking for accurate flood detection maps you should rather have a look to Copernicus Emergency website. There are many professional flood maps generated by the SERTIT using Sentinel-1, Radarsat-2 and Pléiades… I always thought that using radar imagery could be a very cumbersome process. Google Earth Engine was a great tool to overcome this idea. I wish space agencies provide a similar service. In the meantime… Deal with the devil?

The GEE script below generates the maps presented above

// Load Sentinel-1 images to map Seine-et-Marne flooding, France, May-June 2016.
// This script was originally written by Simon Ilyushchenko (GEE team)

// Default location
var pt = ee.Geometry.Point(3.02,48.82);
// Grand Morin near Coulommiers

// Load Sentinel-1 C-band SAR Ground Range collection (log scaling, VV co-polar)
var collection = ee.ImageCollection('COPERNICUS/S1_GRD')
.filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VV'))

// Filter by date
var before = collection.filterDate('2016-05-01', '2016-05-17').mosaic();
var after = collection.filterDate('2016-05-30', '2016-06-01').mosaic();

// Threshold smoothed radar intensities to identify "flooded" areas.
var diff_smoothed = after.focal_median(SMOOTHING_RADIUS, 'circle', 'meters')
.subtract(before.focal_median(SMOOTHING_RADIUS, 'circle', 'meters'));
var diff_thresholded = diff_smoothed.lt(DIFF_UPPER_THRESHOLD);

// Display map

Map.centerObject(pt, 13);
Map.addLayer(before, {min:-30,max:0}, 'Before flood');
Map.addLayer(after, {min:-30,max:0}, 'After flood');
Map.addLayer(after.subtract(before), {min:-10,max:10}, 'After - before', 0);
Map.addLayer(diff_smoothed, {min:-10,max:10}, 'diff smoothed', 0);
Map.addLayer(diff_thresholded.updateMask(diff_thresholded, {palette:"0000FF"},'flooded areas - blue',1);


Nota bene: I deliberately choose the simplest method to illustrate this post although we have tried a lot of different filters and options with my colleague Michel Le Page. For instance one can mask out slopes that are greater than 5 degrees using the hydroSHEDS digital elevation model:

var hydrosheds = ee.Image('WWF/HydroSHEDS/03VFDEM');
var terrain = ee.Algorithms.Terrain(hydrosheds);
var slope = terrain.select('slope');
before = before.mask(slope.lt(5));
after = after.mask(slope.lt(5));

You may also want to select only descending orbits:

var before = collection.filterDate('2016-05-15', '2016-05-22')
.filter(ee.Filter.eq('orbitProperties_pass', 'DESCENDING'))

etc…, etc…

39 thoughts on “Mapping flooded areas using Sentinel-1 in Google Earth Engine

  1. Yep! there is no doubt that GEE is an incredible platform for exploring satellite imagery datasets in a fast and easy way. But contrary to Google Earth and Maps, this time most of the data comes from public agencies (ESA, NASA…), meaning that the data was produced with public money.Yes, it’s true that this data is made public by those public agencies, and that anybody can use it even Google. And it’s true that Google has built an incredible computing power so it is legitimate for them to combine their calculation power with 30+ years of images, to finally maybe earn more money. After all, the original idea of putting the data free and public was to facilitate the growth of the private sector in the area of spatial imagery. Yet, it still makes me feel unconfortable that it is an already IT giant that is doing this step forward.Anyway… :DIn GEE, adding more filters with logical combinations is easy. For example, you can ensure that the initial pixel is not already covered with water with:var diff_thresholded = diff_smoothed.lt(DIFF_UPPER_THRESHOLD).and(before.gt(-15));It is also quite easy to export the result of your script to a GeoTiff file. Simply use the Export.image() function.

  2. What is really evil is using a median filter instead of a real anti-speckle one and then perfoming a difference instead of a ratio.But, hey, if it is convenient and doable on an iPad from Starbucks, why not?You’ve got my +1.

    1. Thank you for your feedback and the +1! Are you the author of the Lee filter for speckle noise reduction?

    2. I just figured out that an implementation of the Lee filter for S1 was posted on GEE forum recently. I have tested it and there is no big differences with the median filter on this example. But it does give sharper flooded areas.

      1. Great article! I’m also looking into doing a Lee filter within GEE, but haven’t been able to find the forum post you’ve mentioned, is it possible for you to post the link please? Thanks!

          1. HI, sorry for the javascript ignorance!I tried to run the script https://code.earthengine.google.com/2ef38463ebaf5ae133a478f173fd0ab5but I get the following errors: Original VV stack: Layer error: Image.addBands: Parameter ‘dstImg’ is required.Boxcar 3×3 filtered VV stack 2014-2015: Layer error: Image.select: Parameter ‘input’ is required.Refined Lee filtered VV stack 2014-2015: Layer error: Image.select: Parameter ‘input’ is required.any suggestion?Thanks

          2. there was an error in the collection filtering, therefore the im1 im2 were empty. I corrected your script now it works:\nhttps://code.earthengine.google.com/99ca40bd011ed06dd3e92808919c2f4a

  3. You did’nt not finish your story and you mis the most important: what happened to your bottles of wine ?

    1. You’re right! The cellar and the bottles were flooded. I will have to conduct an empirical analysis and taste them ..

      1. My advice, don’t do that with GEE, test it with a real panel made with colleagues from your lab.

  4. Hi:I would like to compute |VV|/|VH| from the sentinel 1 bands. How do you compute the absolute value i.e |VV|?ThanksDee

    1. You can append « .abs() » to your image\n\nSee the documentation:\nComputes the absolute value of the input.\nArguments:\nthis:value (Image):\n The image to which the operation is applied.\nReturns: Image

  5. I am doing the inundation mapping for a village which has an area of 376.47 hectares .How to find the inundated areas in google earth and how to link the sentinel data with the google earth.

    1. Hi Divya, it is not « Google Earth » but « Google Earth Engine ». Try to have a look at the documentation on their website!

  6. I am new to SAR image. This post of yours is very helpful for me. Merci.I understand what you do but I wonder how you select the threshold (DIFF_UPPER_THRESHOLD = -3). Do you use histogram or is there any method for choosing the threshold?

    1. I’m not a radar expert neither, this value was taken as a first guess by looking at the images (some would it call it expert choice). It’s often used as is, check in the peer-review scientific literature. I think an histogram approach is a good idea, and ideally you would like to test the sensitivity of the results to this threshold.

  7. I am a new to GEE and SAR, I want to know what’s the meaning of the result after processing a sentinel data with your method. If I use the same method to process a cropland image, if the result can show the real height of the crops? the unit of each value is m or cm?

  8. Hi Simon, its a nice script, thank you. Although, the speckle effect of SAR imagery can not be completely removed by filtering, without losing spatial information. It is better proved, as scientific method, that Object Oriented Classification techniques are more effective for SAR imagery classification. For SENTINEL-1, you could simply use a conditional threshold for the VV and VH polarisations to classify the image objects created. But bear in mind that C band sensors can not detect water under dense vegetation. For this purpose you should use a L-band sensor, eg. ALOS/PALSAR. https://vertex.daac.asf.alaska.edu/#I am trying to segment the SENTINEL-1 in GEE, but still don’t know how to create the polygons (image objects), to extract the mean and standard deviation for each object and classify them.If someone has a similar script, please send a feedback.rodrigonunessousa@gmail.com

    1. Hi Rodrigo, thanks. I don’t think it’s possible yet to assign a statistic in each patch e.g. from connectedComponents. As a turn-around I would try reduceToVectors with a mean or std reducer for each polygon but it might quickly hit the GEE memory limit. Otherwise try the GEE user forum or mailing list!

    1. there was a parenthesis error in the last line
      Map.addLayer(diff_thresholded.updateMask(diff_thresholded), {palette: »0000FF »},’flooded areas – blue’,1);

  9. Hi! i like your post. i wanna ask something, i didnt understand why should mask out slopes that are greater than 5 degrees?

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.