DOI: 10.7910/dvn/wotc7e
title: Replication Data for: Fast flood extent monitoring with SAR change detection using Google Earth Engine

description: &lt;b&gt;Fast flood extent monitoring with SAR change detection using Google Earth Engine&lt;/b&gt;
&lt;br&gt;&lt;br&gt;
This dataset develops a tool for near real-time flood monitoring through a novel combining of multi-temporal and multi-source remote sensing data. We use a SAR change detection and thresholding method, and apply sensitivity analytics and thresholding calibration, using SAR-based and optical-based indices in a format that is streamlined, reproducible, and geographically agile. We leverage the massive repository of satellite imagery and planetary-scale geospatial analysis tools of GEE to devise a flood inundation extent model that is both scalable and replicable. The flood extents from the 2021 Hurricane Ida and the 2017 Hurricane Harvey were selected to test the approach. The methodology provides a fast, automatable, and geographically reliable tool for assisting decision-makers and emergency planners using near real-time multi-temporal satellite SAR data sets.
&lt;br&gt;&lt;br&gt;
&lt;i&gt;GEE code was developed by Ebrahim Hamidi and reviewed by Brad G. Peter; Figures were created by Brad G. Peter.&lt;/i&gt;
&lt;br&gt;&lt;br&gt;
This tool accompanies a publication Hamidi et al., 2023: 
E. Hamidi, B. G. Peter, D. F. Muñoz, H. Moftakhari and H. Moradkhani, "Fast Flood Extent Monitoring with SAR Change Detection Using Google Earth Engine," in IEEE Transactions on Geoscience and Remote Sensing, doi: 10.1109/TGRS.2023.3240097.
&lt;br&gt;&lt;br&gt;
&lt;b&gt;GEE input datasets:&lt;/b&gt;
&lt;br&gt;
&lt;img src ="https://github.com/ebrahimhamidi/SAR-flood-monitoring/blob/180f67640a2dc9a4ad6544051f9472d0e857dcd6/Table_I.PNG?raw=true" width="1000" height="auto"&lt;/img&gt;
&lt;br&gt;&lt;br&gt;
&lt;img src ="https://github.com/ebrahimhamidi/SAR-flood-monitoring/blob/main/Figure1_StudyArea-v3_05312022.png?raw=true" width="1000" height="auto"&lt;/img&gt;
&lt;br&gt;&lt;br&gt;
&lt;img src ="https://github.com/ebrahimhamidi/SAR-flood-monitoring/blob/main/Figure3_Before-After-VH_05312022.png?raw=true" width="1000" height="auto"&lt;/img&gt;
&lt;br&gt;&lt;br&gt;
&lt;b&gt;Methodology flowchart:&lt;/b&gt;
&lt;br&gt;
&lt;img src ="https://github.com/ebrahimhamidi/SAR-flood-monitoring/blob/84a74a269353c0791ee442bbcc966e43fafd56cb/Figure2_MethodologyFlowchart.PNG?raw=true" width="1000" height="auto"&lt;/img&gt;
&lt;br&gt;&lt;br&gt;
&lt;b&gt;Sensitivity Analysis:&lt;/b&gt;
&lt;br&gt;
&lt;img src ="https://github.com/ebrahimhamidi/SAR-flood-monitoring/blob/47c15a03ce7c047fe92a4910df5d849023138647/Figure7_SensitivityAnalysis.PNG?raw=true" width="1000" height="auto"&lt;/img&gt;
&lt;br&gt;&lt;br&gt;
&lt;b&gt;GEE code (muti-source and multi-temporal flood monitoring): &lt;/b&gt;
&lt;br&gt;
https://code.earthengine.google.com/7f4942ab0c73503e88287ad7e9187150
&lt;br&gt;&lt;br&gt;
&lt;b&gt;The threshold sensitivity analysis is automated in the below GEE code:&lt;/b&gt;
&lt;br&gt;
https://code.earthengine.google.com/a3fbfe338c69232a75cbcd0eb6bc0c8e
&lt;br&gt;&lt;br&gt;
The above scripts can be run independently. The threshold automation code identifies the optimal threshold values for use in the flood monitoring procedure.
&lt;br&gt;&lt;br&gt;
&lt;b&gt;GEE code for Hurricane Harvey, east of Houston&lt;/b&gt; Java script: 
&lt;pre&gt;
// Study Area Boundaries
var bounds = /* color: #d63000 */ee.Geometry.Polygon(
 [[[-94.5214452285728, 30.165244882083663],
 [-94.5214452285728, 29.56024879238989],
 [-93.36650748443218, 29.56024879238989],
 [-93.36650748443218, 30.165244882083663]]], null, false);


// [before_start,before_end,after_start,after_end,k_ndfi,k_ri,k_diff,mndwi_threshold]
var params = ['2017-06-01','2017-06-15','2017-08-01','2017-09-10',1.0,0.25,0.8,0.4]

// SAR Input Data 
var before_start = params[0]
var before_end = params[1]

var after_start = params[2]
var after_end = params[3]

var polarization = "VH"
var pass_direction = "ASCENDING"

// k Coeficient Values for NDFI, RI and DII SAR Indices (Flooded Pixel Thresholding; Equation 4)
var k_ndfi = params[4]
var k_ri = params[5]
var k_diff = params[6]

// MNDWI flooded pixels Threshold Criteria
var mndwi_threshold = params[7]

// Datasets -----------------------------------
var dem = ee.Image("USGS/3DEP/10m").select('elevation')
var slope = ee.Terrain.slope(dem)
var swater = ee.Image('JRC/GSW1_0/GlobalSurfaceWater').select('seasonality')
var collection = ee.ImageCollection('COPERNICUS/S1_GRD')
 .filter(ee.Filter.eq('instrumentMode', 'IW'))
 .filter(ee.Filter.listContains('transmitterReceiverPolarisation', polarization))
 .filter(ee.Filter.eq('orbitProperties_pass', pass_direction)) 
 .filter(ee.Filter.eq('resolution_meters', 10))
 .filterBounds(bounds)
 .select(polarization)

var before = collection.filterDate(before_start, before_end)
var after = collection.filterDate(after_start, after_end)
print("before", before)
print("after", after)

// Generating Reference and Flood Multi-temporal SAR Data ------------------------
// Mean Before and Min After ------------------------
var mean_before = before.mean().clip(bounds)
var min_after = after.min().clip(bounds)
var max_after = after.max().clip(bounds)
var mean_after = after.mean().clip(bounds)

Map.addLayer(mean_before, {min: -29.264204107025904, max: -8.938093778644141, palette: []}, "mean_before",0)
Map.addLayer(min_after, {min: -29.29334290990966, max: -11.928313976797138, palette: []}, "min_after",1)

// Flood identification ------------------------
// NDFI ------------------------
var ndfi = mean_before.abs().subtract(min_after.abs())
 .divide(mean_before.abs().add(min_after.abs()))
var ndfi_filtered = ndfi.focal_mean({radius: 50, kernelType: 'circle', units: 'meters'})

// NDFI Normalization -----------------------
var ndfi_min = ndfi_filtered.reduceRegion({
 reducer: ee.Reducer.min(),
 geometry: bounds,
 scale: 10,
 maxPixels: 1e13
})
var ndfi_max = ndfi_filtered.reduceRegion({
 reducer: ee.Reducer.max(),
 geometry: bounds,
 scale: 10,
 maxPixels: 1e13
})

var ndfi_rang = ee.Number(ndfi_max.get('VH')).subtract(ee.Number(ndfi_min.get('VH')))
var ndfi_subtctMin = ndfi_filtered.subtract(ee.Number(ndfi_min.get('VH')))
var ndfi_norm = ndfi_subtctMin.divide(ndfi_rang)

Map.addLayer(ndfi_norm, {min: 0.3862747346632676, max: 0.7632898395906615}, "ndfi_norm",0)

var histogram = ui.Chart.image.histogram({
 image: ndfi_norm,
 region: bounds,
 scale: 10,
 maxPixels: 1e13
})
print("ndfi_norm Histogram", histogram)

// NDFI Thresholding ------------------------
var ndfi_mean = ndfi_norm.reduceRegion({
 reducer: ee.Reducer.mean(),
 geometry: bounds,
 scale: 10,
 maxPixels: 1e13
})

var ndfi_std = ndfi_norm.reduceRegion({
 reducer: ee.Reducer.stdDev(),
 geometry: bounds,
 scale: 10,
 maxPixels: 1e13
})

var ndfi_th = ee.Number(ndfi_mean.get('VH')).subtract(ee.Number(k_ndfi).multiply(ee.Number(ndfi_std.get('VH'))))
print('ndfi_th = ', ndfi_th)

// Apply Thresholding Value on NDFI
var ndfi_filtered = ndfi_norm.lt(ndfi_th)

// NDFI Masking -------------------------------------
var swater_mask = swater.gte(4)
var slope_mask = slope.lt(5)
var swater_clip = swater_mask.clip(bounds)

var ndfi_flooded_masked = ndfi_filtered.where(swater_mask, 0)
 .updateMask(slope_mask.eq(1))
var connections = ndfi_flooded_masked.connectedPixelCount().gte(25)
ndfi_flooded_masked = ndfi_flooded_masked.updateMask(connections.eq(1))
var ndfi_flood = ndfi_flooded_masked.updateMask(ndfi_flooded_masked.eq(1))

//------------------------------------------------------------------------
// RI ------------------------
var ri = min_after.abs().divide(mean_before.abs())
var ri_filtered = ri.focal_mean({radius: 50, kernelType: 'circle', units: 'meters'})

// RI Normalization -----------------------
var ri_min = ri_filtered.reduceRegion({
 reducer: ee.Reducer.min(),
 geometry: bounds,
 scale: 10,
 maxPixels: 1e13
})

var ri_max = ri_filtered.reduceRegion({
 reducer: ee.Reducer.max(),
 geometry: bounds,
 scale: 10,
 maxPixels: 1e13
})

var ri_rang = ee.Number(ri_max.get('VH')).subtract(ee.Number(ri_min.get('VH')))
var ri_subtctMin = ri_filtered.subtract(ee.Number(ri_min.get('VH')))
var ri_norm = ri_subtctMin.divide(ri_rang)

Map.addLayer(ri_norm, {min: 0.02946113630948349, max: 0.14605562985795736}, "ri_norm", 0)

var histogram = ui.Chart.image.histogram({
 image: ri_norm,
 region: bounds,
 scale: 10,
 maxPixels: 1e13
})
print("ri_norm Histogram", histogram)

// RI Thresholding ------------------------
var ri_mean = ri_norm.reduceRegion({
 reducer: ee.Reducer.mean(),
 geometry: bounds,
 scale: 10,
 maxPixels: 1e13
})

var ri_std = ri_norm.reduceRegion({
 reducer: ee.Reducer.stdDev(),
 geometry: bounds,
 scale: 10,
 maxPixels: 1e13
})

var ri_th = ee.Number(ri_mean.get('VH')).add(ee.Number(k_ri).multiply(ee.Number(ri_std.get('VH'))))
print('ri_th = ', ri_th)

// Apply Thresholding on RI
var ri_filtered = ri_norm.gt(ri_th)

// RI Masking -------------------------------------
var ri_masked = ri_filtered.where(swater_mask, 0)
 .updateMask(slope_mask.eq(1))
var ri_connections = ri_masked.connectedPixelCount().gte(25)
ri_masked = ri_masked.updateMask(ri_connections.eq(1))
var ri_flood = ri_masked.updateMask(ri_masked.eq(1))

//------------------------------------------------------------------------
// DII ------------------------
var diff_image = min_after.abs().subtract(mean_before.abs())
var diff_image_filtered = diff_image.focal_mean({radius: 50, kernelType: 'circle', units: 'meters'})

// DII Normalization
var diff_image_min = diff_image_filtered.reduceRegion({
 reducer: ee.Reducer.min(),
 geometry: bounds,
 scale: 10,
 maxPixels: 1e13
})

var diff_image_max = diff_image_filtered.reduceRegion({
 reducer: ee.Reducer.max(),
 geometry: bounds,
 scale: 10,
 maxPixels: 1e13
})

var diff_image_rang = ee.Number(diff_image_max.get('VH')).subtract(ee.Number(diff_image_min.get('VH')))
var diff_image_subtctMin = diff_image_filtered.subtract(ee.Number(diff_image_min.get('VH')))
var diff_image_norm = diff_image_subtctMin.divide(diff_image_rang)

Map.addLayer(diff_image_norm, {min: 0.1434809241093373, max: 0.7689478379887918}, "diff_image_norm", 0)

var histogram = ui.Chart.image.histogram({
 image: diff_image_norm,
 region: bounds,
 scale: 10,
 maxPixels: 1e13
})
print("diff_image_norm Histogram", histogram)

// DII Thresholding ------------------------
var diff_image_mean = diff_image_norm.reduceRegion({
 reducer: ee.Reducer.mean(),
 geometry: bounds,
 scale: 10,
 maxPixels: 1e13
})

var diff_image_std = diff_image_norm.reduceRegion({
 reducer: ee.Reducer.stdDev(),
 geometry: bounds,
 scale: 10,
 maxPixels: 1e13
})

var diff_image_th = ee.Number(diff_image_mean.get('VH')).add(ee.Number(k_diff).multiply(ee.Number(diff_image_std.get('VH'))))
print('diff_image_th = ', diff_image_th)

// Apply Thresholding on DII
var diff_image_filtered = diff_image_norm.gt(diff_image_th)

// DII Masking -------------------------------------
var diff_image_masked = diff_image_filtered.where(swater_mask, 0)
 .updateMask(slope_mask.eq(1))
var diff_image_connections = diff_image_masked.connectedPixelCount().gte(25)
diff_image_masked = diff_image_masked.updateMask(diff_image_connections.eq(1))
var diff_image_flood = diff_image_masked.updateMask(diff_image_masked.eq(1))

//-------------------------------------------------------------------------------------------------
// Validation Using Sentinel-2 Surface Reflectance Imagery Data -----------------------------------
var sentinel2_ref = ee.ImageCollection("COPERNICUS/S2")
 .filterBounds(bounds).filterDate('2017-04-20', '2017-04-30')
print(sentinel2_ref,"sentinel2_ref")
var sentinel2_ref_mosaic = sentinel2_ref.mosaic()
var sentinel2_ref_clip = sentinel2_ref_mosaic.clip(bounds)

var sentinel2_flood = ee.ImageCollection("COPERNICUS/S2")
 .filterBounds(bounds).filterDate('2017-09-02', '2017-09-11')
print(sentinel2_flood,"sentinel2_flood")
var sentinel2_flood_mosaic = sentinel2_flood.mosaic()
var sentinel2_flood_clip = sentinel2_flood_mosaic.clip(bounds)

Map.addLayer(sentinel2_ref_clip,{min:0,max:2500,bands:['B4','B3','B2']},'true color sentinel2_ref_clip',0)
Map.addLayer(sentinel2_flood_clip,{min:0,max:2500,bands:['B4','B3','B2']},'true color sentinel2_clip',0)

// Cloud Covers and Cloud Shadows Masks
var qa = sentinel2_flood_clip.select('QA60')
var radix = 2 
var cloudBit = 10 // this number can be found in the pixel_qa Bitmask metadata
var shadowBit = 11 
var clouds_1 = qa.bitwiseAnd(Math.pow(radix,cloudBit)).neq(0).rename('clouds')
var clouds_2 = qa.bitwiseAnd(Math.pow(radix,shadowBit)).neq(0).rename('shadows')

Map.addLayer(clouds_1.updateMask(clouds_1.eq(1)),{palette:'crimson'},'clouds [mc]',0)
Map.addLayer(clouds_2.updateMask(clouds_2.eq(1)),{palette:'gold'},'shadows [mc]',0)

var cloudsMasked = sentinel2_flood_clip.updateMask(clouds_1.eq(0).and(clouds_2.eq(0)))

// Calculating MNDWI for Optical imagery
var green_s2 = cloudsMasked.select('B3')
var swir1_s2 = cloudsMasked.select('B11') 
var swir2_s2 = cloudsMasked.select('B12') 

var mndwi_s2 = green_s2.subtract(swir1_s2).divide(green_s2.add(swir1_s2)).rename('mndwi_s2')

var mndwi_masked = mndwi_s2.where(swater_mask, 0)
Map.addLayer(mndwi_masked,{min:-0.5446808338165283,max:0.9092437028884888,palette:['02991c','37a3ff','ff822a']},'mndwi_masked',0)

var mndwi_filtered = mndwi_masked.gt(mndwi_threshold)
var mndwi_connections = mndwi_filtered.connectedPixelCount().gte(25)
mndwi_filtered = mndwi_filtered.updateMask(mndwi_connections.eq(1))

var mndwi_flood = mndwi_filtered.updateMask(mndwi_filtered.eq(1))

// Dispaly -----------------------------------
Map.addLayer(ndfi_flood, {palette: 'red'}, 'ndfi_flood',0)
Map.addLayer(ri_flood, {palette: '00bee9'}, "ri_flood",0)
Map.addLayer(diff_image_flood, {palette: 'brown'}, "diff_image_flood",0)
Map.addLayer(mndwi_flood, {palette: 'ff822a'}, "mndwi_flood", 0)
Map.addLayer(swater_clip, {palette: ['20cbdc']}, "Open Waters", 0)
Map.setOptions('HYBRID')
Map.centerObject(bounds)

// NDFI Pixel Analysis -----------------------------------
// Removing Cloud Covers and Cloud Shadows from NDFI flood inundation layers
var ndfi_flood_RemCloud = ndfi_flood.updateMask(clouds_1.eq(0).and(clouds_2.eq(0)))

var undcldfld_ndfi = ndfi_flood_RemCloud.mask().clip(bounds)
 .add(ndfi_flood.mask().remap([0,1],[0,5]))
 .rename('flood_compare')
undcldfld_ndfi = undcldfld_ndfi.remap([0,1,3,5,6,8,9],[0,1,2,3,4,5,6])
undcldfld_ndfi = undcldfld_ndfi.updateMask(undcldfld_ndfi.gt(0));

var undcldfld_ndfi_pixels = ndfi_flood.updateMask(undcldfld_ndfi.eq(3));
var num_undcldfld_ndfi_pixels = undcldfld_ndfi_pixels.reduceRegion({
 reducer: ee.Reducer.sum(), 
 geometry: bounds,
 scale: 10, // native resolution 
 //maxPixels: 1e9,
 bestEffort: true
 });

Map.addLayer(undcldfld_ndfi_pixels,{palette:['ceff0c']},'undcldfld_ndfi')
print("num_undcldfld_ndfi_pixels", num_undcldfld_ndfi_pixels)

var compare_ndfi = ndfi_flood_RemCloud.mask().clip(bounds)
 .add(mndwi_flood.mask().remap([0,1],[0,5]))
 .rename('flood_compare')
compare_ndfi = compare_ndfi.remap([0,1,3,5,6,8,9],[0,1,2,3,4,5,6])
compare_ndfi = compare_ndfi.updateMask(compare_ndfi.gt(0));
Map.addLayer(compare_ndfi,{min:0,max:4,palette:['dadada','0400ff','ff0000','fbff00']},'compare_ndfiANDmndwi')

var mndwi_pixels = mndwi_flood.updateMask(compare_ndfi.eq(3));

Map.addLayer(mndwi_pixels,{},'mndwi_pixels')
var num_mndwi_pixels = mndwi_pixels.reduceRegion({
 reducer: ee.Reducer.sum(), 
 geometry: bounds,
 scale: 10, // native resolution 
 //maxPixels: 1e9,
 bestEffort: true
 });
print("num_mndwi_pixels", num_mndwi_pixels)

var ndfi_pixels = ndfi_flood_RemCloud.updateMask(compare_ndfi.eq(1));
Map.addLayer(ndfi_pixels,{},'ndfi_pixels')
var num_ndfi_pixels = ndfi_pixels.reduceRegion({
 reducer: ee.Reducer.sum(), 
 geometry: bounds,
 scale: 10, // native resolution 
 //maxPixels: 1e9,
 bestEffort: true
 });
print("num_ndfi_pixels", num_ndfi_pixels)

var ndfiAndmndwi_pixels = ndfi_flood_RemCloud.updateMask(mndwi_flood);

Map.addLayer(ndfiAndmndwi_pixels,{},'ndfiAndmndwi_pixels')
var num_ndfiAndmndwi_pixels = ndfiAndmndwi_pixels.reduceRegion({
 reducer: ee.Reducer.sum(), 
 geometry: bounds,
 scale: 10, // native resolution 
 //maxPixels: 1e9,
 bestEffort: true
 });
print("num_ndfiAndmndwi_pixels", num_ndfiAndmndwi_pixels)

var ToAgre_Percent_ndfi = ee.Number(num_ndfiAndmndwi_pixels.get('VH')).divide(ee.Number(num_ndfiAndmndwi_pixels.get('VH')).add(ee.Number(num_ndfi_pixels.get('VH')).add(ee.Number(num_mndwi_pixels.get('mndwi_s2')))))
print("Total Agreement % NDFI", ToAgre_Percent_ndfi)

var Agr_Percentage_ndfi = ee.Number(num_ndfiAndmndwi_pixels.get("VH")).divide(ee.Number(num_mndwi_pixels.get("mndwi_s2")).add(ee.Number(num_ndfiAndmndwi_pixels.get("VH"))))
print("Agreement % NDFI = ", Agr_Percentage_ndfi)


// RI Pixel Analysis -----------------------------------
// Removing Cloud Covers and Cloud Shadows from RI flood inundation layers
var ri_flood_RemCloud = ri_flood.updateMask(clouds_1.eq(0).and(clouds_2.eq(0)))

var undcldfld_ri = ri_flood_RemCloud.mask().clip(bounds)
 .add(ri_flood.mask().remap([0,1],[0,5]))
 .rename('flood_compare')
undcldfld_ri = undcldfld_ri.remap([0,1,3,5,6,8,9],[0,1,2,3,4,5,6])
undcldfld_ri = undcldfld_ri.updateMask(undcldfld_ri.gt(0));

var undcldfld_ri_pixels = ri_flood.updateMask(undcldfld_ri.eq(3));
var num_undcldfld_ri_pixels = undcldfld_ri_pixels.reduceRegion({
 reducer: ee.Reducer.sum(), 
 geometry: bounds,
 scale: 10, // native resolution 
 //maxPixels: 1e9,
 bestEffort: true
 });

Map.addLayer(undcldfld_ri_pixels,{palette:['fbff00']},'undcldfld_ri')
print("num_undcldfld_ri_pixels", num_undcldfld_ri_pixels)

var compare_ri = ri_flood_RemCloud.mask().clip(bounds)
 .add(mndwi_flood.mask().remap([0,1],[0,5]))
 .rename('flood_compare')
compare_ri = compare_ri.remap([0,1,3,5,6,8,9],[0,1,2,3,4,5,6])
compare_ri = compare_ri.updateMask(compare_ri.gt(0));
Map.addLayer(compare_ri,{min:0,max:4,palette:['dadada','0400ff','ff0000','00d0ff']},'compare_riANDmndwi')

var ri_mndwi_pixels = mndwi_flood.updateMask(compare_ri.eq(3));
Map.addLayer(ri_mndwi_pixels,{},'ri_mndwi_pixels')
var num_ri_mndwi_pixels = ri_mndwi_pixels.reduceRegion({
 reducer: ee.Reducer.sum(), 
 geometry: bounds,
 scale: 10, // native resolution 
 //maxPixels: 1e9,
 bestEffort: true
 });
print("num_ri_mndwi_pixels", num_ri_mndwi_pixels)

var ri_pixels = ri_flood_RemCloud.updateMask(compare_ri.eq(1));
Map.addLayer(ri_pixels,{},'ri_pixels')
var num_ri_pixels = ri_pixels.reduceRegion({
 reducer: ee.Reducer.sum(), 
 geometry: bounds,
 scale: 10, // native resolution 
 //maxPixels: 1e9,
 bestEffort: true
 });
print("num_ri_pixels", num_ri_pixels)

var riAndmndwi_pixels = ri_flood_RemCloud.updateMask(mndwi_flood);

Map.addLayer(riAndmndwi_pixels,{},'riAndmndwi_pixels')
var num_riAndmndwi_pixels = riAndmndwi_pixels.reduceRegion({
 reducer: ee.Reducer.sum(), 
 geometry: bounds,
 scale: 10, // native resolution 
 //maxPixels: 1e9,
 bestEffort: true
 });
print("num_riAndmndwi_pixels", num_riAndmndwi_pixels)

var ToAgre_Percent_ri = ee.Number(num_riAndmndwi_pixels.get('VH')).divide(ee.Number(num_riAndmndwi_pixels.get('VH')).add(ee.Number(num_ri_pixels.get('VH')).add(ee.Number(num_ri_mndwi_pixels.get('mndwi_s2')))))
print("Total Agreement % RI", ToAgre_Percent_ri)

var Agr_Percentage_ri = ee.Number(num_riAndmndwi_pixels.get("VH")).divide(ee.Number(num_ri_mndwi_pixels.get("mndwi_s2")).add(ee.Number(num_riAndmndwi_pixels.get("VH"))))
print("Agreement % RI = ", Agr_Percentage_ri)

// DII Pixel Analysis -----------------------------------
// Removing Cloud Covers and Cloud Shadows from DII flood inundation layers
var diff_flood_RemCloud = diff_image_flood.updateMask(clouds_1.eq(0).and(clouds_2.eq(0)))

var undcldfld_diff = diff_flood_RemCloud.mask().clip(bounds)
 .add(diff_image_flood.mask().remap([0,1],[0,5]))
 .rename('flood_compare')
undcldfld_diff = undcldfld_diff.remap([0,1,3,5,6,8,9],[0,1,2,3,4,5,6])
undcldfld_diff = undcldfld_diff.updateMask(undcldfld_diff.gt(0));

var undcldfld_diff_pixels = diff_image_flood.updateMask(undcldfld_diff.eq(3));
var num_undcldfld_diff_pixels = undcldfld_diff_pixels.reduceRegion({
 reducer: ee.Reducer.sum(), 
 geometry: bounds,
 scale: 10, // native resolution 
 //maxPixels: 1e9,
 bestEffort: true
 });

Map.addLayer(undcldfld_diff_pixels,{palette:['ceff0c']},'undcldfld_diff_pixels')
print("num_undcldfld_diff_pixels", num_undcldfld_diff_pixels)

var compare_dii = diff_flood_RemCloud.mask().clip(bounds)
 .add(mndwi_flood.mask().remap([0,1],[0,5]))
 .rename('flood_compare')
compare_dii = compare_dii.remap([0,1,3,5,6,8,9],[0,1,2,3,4,5,6])
compare_dii = compare_dii.updateMask(compare_dii.gt(0));
Map.addLayer(compare_dii,{min:0,max:4,palette:['dadada','0400ff','ff0000','fbff00']},'compare_diiANDmndwi')

var dii_mndwi_pixels = mndwi_flood.updateMask(compare_dii.eq(3));
Map.addLayer(dii_mndwi_pixels,{},'dii_mndwi_pixels')
var num_dii_mndwi_pixels = dii_mndwi_pixels.reduceRegion({
 reducer: ee.Reducer.sum(), 
 geometry: bounds,
 scale: 10, // native resolution 
 //maxPixels: 1e9,
 bestEffort: true
 });
print("num_dii_mndwi_pixels", num_dii_mndwi_pixels)

var dii_pixels = diff_flood_RemCloud.updateMask(compare_dii.eq(1));
Map.addLayer(dii_pixels,{},'dii_pixels')
var num_dii_pixels = dii_pixels.reduceRegion({
 reducer: ee.Reducer.sum(), 
 geometry: bounds,
 scale: 10, // native resolution 
 //maxPixels: 1e9,
 bestEffort: true
 });
print("num_dii_pixels", num_dii_pixels)

var diiAndmndwi_pixels = diff_flood_RemCloud.updateMask(mndwi_flood);
Map.addLayer(diiAndmndwi_pixels,{},'diiAndmndwi_pixels')
var num_diiAndmndwi_pixels = diiAndmndwi_pixels.reduceRegion({
 reducer: ee.Reducer.sum(), 
 geometry: bounds,
 scale: 10, // native resolution 
 //maxPixels: 1e9,
 bestEffort: true
 });
print("num_diiAndmndwi_pixels", num_diiAndmndwi_pixels)

var ToAgre_percent_dii = ee.Number(num_diiAndmndwi_pixels.get('VH')).divide(ee.Number(num_diiAndmndwi_pixels.get('VH')).add(ee.Number(num_dii_pixels.get('VH')).add(ee.Number(num_dii_mndwi_pixels.get('mndwi_s2')))))
print("Total Agreeemnt % DII", ToAgre_percent_dii)

var Agr_Percentage_dii = ee.Number(num_diiAndmndwi_pixels.get("VH")).divide(ee.Number(num_dii_mndwi_pixels.get("mndwi_s2")).add(ee.Number(num_diiAndmndwi_pixels.get("VH"))))
print("Agreement % DII = ", Agr_Percentage_dii)

//------------------------------------------------------------------------
//Adding Legend -----------------------------------
// set position of panel
var legend = ui.Panel({
 style: {
 position: 'bottom-right',
 padding: '8px 15px'
 }
});

// Create legend title
var legendTitle = ui.Label({
// value: 'Legend',
 style: {
 fontWeight: 'bold',
 fontSize: '18px',
 margin: '0 0 4px 0',
 padding: '0'
 }
});

// Add the title to the panel
legend.add(legendTitle);

var makeRow = function(color, name) {

 // Create the label that is actually the colored box.
 var colorBox = ui.Label({
 style: {
 backgroundColor: '#' + color,
 // Use padding to give the box height and width.
 padding: '8px',
 margin: '0 0 4px 0'
 }
 });

 // Create the label filled with the description text.
 var description = ui.Label({
 value: name,
 style: {margin: '0 0 4px 6px'}
 });

 // return the panel
 return ui.Panel({
 widgets: [colorBox, description],
 layout: ui.Panel.Layout.Flow('horizontal')
 });
};

// Palette with the colors
var palette =['0400ff','fbff00','ff0000','00d0ff'];

// name of the legend
var names = ['Only RI','Under Cloud RI', 'Only MNDWI', 'Agreement' ];

// Add color and and names
for (var i = 0; i &lt; 4; i++) {
 legend.add(makeRow(palette[i], names[i]));
 } 

// add legend to map (alternatively you can also print the legend to the console)
Map.add(legend);
&lt;/pre&gt;

&lt;b&gt;Sample outputs:&lt;/b&gt;
&lt;img src ="https://github.com/ebrahimhamidi/SAR-flood-monitoring/blob/main/Figure9_SAR-MNDWI_05312022.png?raw=true" width="1000" height="auto"&lt;/img&gt;
&lt;img src ="https://github.com/ebrahimhamidi/SAR-flood-monitoring/blob/main/Figure10_SARvsOptical_Agreement.PNG?raw=true" width="1000" height="auto"&lt;/img&gt;
&lt;img src ="https://github.com/ebrahimhamidi/SAR-flood-monitoring/blob/main/Table2_Agreements.PNG?raw=true" width="1000" height="auto"&lt;/img&gt;
&lt;br&gt;
&lt;b&gt;Project information:&lt;/b&gt;&lt;br&gt;
&lt;br&gt;
This study is partially funded by the National Science Foundation INFEWS Program (award EAR-1856054). Also, partial support was provided by USACE contract #W912HZ2020055. Brad G. Peter was supported in part by the University of Alabama CyberSeed Program and the Alabama Water Institute—Project name: WaterServ: A Cyberinfrastructure for Analysis, Visualization and Sharing of Hydrological Data. Hamed Moftakhari is also partially supported by the National Academies-Gulf Research Program Early Career Fellowship Award Year 2020 – Grant# 2000011518.
description: Google Earth Engine Code:
<br>
https://code.earthengine.google.com/7f4942ab0c73503e88287ad7e9187150