├── Results ├── Code ├── README.md └── Complete code /Results: -------------------------------------------------------------------------------- 1 | | Change\_Type | Area\_ha | 2 | | ------------ | -------- | 3 | | Erosion | 128.74 | 4 | | Accretion | 53.21 | 5 | -------------------------------------------------------------------------------- /Code: -------------------------------------------------------------------------------- 1 | import ee 2 | import geemap 3 | import matplotlib.pyplot as plt 4 | 5 | # Initialize Earth Engine 6 | ee.Initialize() 7 | 8 | # Define Area of Interest (e.g., Lagos coastline) 9 | aoi = ee.Geometry.Rectangle([3.2, 6.3, 3.8, 6.6]) 10 | 11 | # Function to calculate NDWI 12 | def get_ndwi(image): 13 | ndwi = image.normalizedDifference(['B3', 'B8']).rename('NDWI') # For Sentinel-2 14 | return image.addBands(ndwi) 15 | 16 | # Load and filter Sentinel-2 images for two different years 17 | def get_sentinel_image(year): 18 | start = f'{year}-01-01' 19 | end = f'{year}-12-31' 20 | image = (ee.ImageCollection('COPERNICUS/S2_SR') 21 | .filterBounds(aoi) 22 | .filterDate(start, end) 23 | .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 10)) 24 | .median() 25 | .clip(aoi)) 26 | return get_ndwi(image) 27 | 28 | # Get NDWI images for two years 29 | image_2016 = get_sentinel_image(2016).select('NDWI') 30 | image_2024 = get_sentinel_image(2024).select('NDWI') 31 | 32 | # Apply threshold to extract water masks 33 | def extract_water_mask(ndwi_image, threshold=0.3): 34 | return ndwi_image.gt(threshold) 35 | 36 | water_mask_2016 = extract_water_mask(image_2016) 37 | water_mask_2024 = extract_water_mask(image_2024) 38 | 39 | # Visualize NDWI and shoreline changes 40 | Map = geemap.Map(center=[6.5, 3.5], zoom=10) 41 | Map.addLayer(image_2016, {'min': 0, 'max': 1, 'palette': ['white', 'blue']}, 'NDWI 2016') 42 | Map.addLayer(image_2024, {'min': 0, 'max': 1, 'palette': ['white', 'green']}, 'NDWI 2024') 43 | Map.addLayer(water_mask_2016.updateMask(water_mask_2016), {'palette': ['blue']}, 'Water 2016') 44 | Map.addLayer(water_mask_2024.updateMask(water_mask_2024), {'palette': ['green']}, 'Water 2024') 45 | Map.add_legend(title="Coastal Change NDWI", legend_dict={'2016 Water': 'blue', '2024 Water': 'green'}) 46 | Map 47 | 48 | # Optional: Export the change detection image 49 | change = water_mask_2024.subtract(water_mask_2016).rename('Change') 50 | export_image = change.visualize(min=-1, max=1, palette=['red', 'white', 'green']) 51 | 52 | task = ee.batch.Export.image.toDrive( 53 | image=export_image, 54 | description='Coastal_Erosion_Change_2016_2024', 55 | folder='CoastalErosion', 56 | fileNamePrefix='coastal_change', 57 | region=aoi, 58 | scale=10 59 | ) 60 | task.start() 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🌊 Coastal Erosion Detection with Satellite Imagery 2 | 3 | This project detects and quantifies shoreline erosion and accretion over time using **Sentinel-2 satellite imagery**, the **Normalized Difference Water Index (NDWI)**, and **Google Earth Engine (GEE)**. It focuses on identifying changes along coastal zones—e.g., Lagos, Nigeria—between 2016 and 2024. 4 | 5 | --- 6 | 7 | ## 📌 Objectives 8 | 9 | - Detect shoreline position changes using NDWI. 10 | - Identify areas of **erosion** and **accretion**. 11 | - Estimate and export affected areas (in hectares) to CSV. 12 | - Visualize changes on an interactive map using `geemap`. 13 | 14 | --- 15 | 16 | ## 📊 Methodology 17 | 18 | 1. **Data Source**: 19 | - Sentinel-2 Surface Reflectance (`COPERNICUS/S2_SR`) 20 | 21 | 2. **Area of Interest (AOI)**: 22 | - Lagos coastline (modifiable) 23 | 24 | 3. **Index Used**: 25 | - NDWI = (Green - NIR) / (Green + NIR) 26 | 27 | 4. **Processing Steps**: 28 | - Compute NDWI for years 2016 and 2024 29 | - Extract water masks using a threshold (NDWI > 0.3) 30 | - Compare binary water masks to detect: 31 | - `-1` → **Erosion** 32 | - `+1` → **Accretion** 33 | - Calculate area in hectares using `ee.Image.pixelArea()` 34 | - Export results to CSV 35 | 36 | --- 37 | 38 | ## 🖥️ Installation 39 | 40 | ### Python Requirements 41 | 42 | ```bash 43 | pip install earthengine-api geemap pandas 44 | 45 | Earth Engine Authentication 46 | 47 | import ee 48 | ee.Authenticate() 49 | ee.Initialize() 50 | 51 | 📁 Files in Repository 52 | File Description 53 | coastal_erosion_detection.py Main script for shoreline change detection 54 | coastal_erosion_accretion_area.csv Output CSV with area (ha) of erosion/accretion 55 | README.md Project overview and setup guide 56 | 🗺️ Visualization Example 57 | 58 | Blue: Water in 2016 59 | 60 | Green: Water in 2024 61 | 62 | Red: Erosion (water encroached land) 63 | 64 | Green (in change map): Accretion (land gain) 65 | 66 | Interactive map is built using geemap. 67 | 📤 Output Example 68 | 69 | Change_Type,Area_ha 70 | Erosion,128.74 71 | Accretion,53.21 72 | 73 | 🧠 Future Improvements 74 | 75 | Integrate Landsat time series for long-term shoreline dynamics. 76 | 77 | Classify shoreline types (sandy, rocky, mangroves). 78 | 79 | Validate results with UAV or field data. 80 | 81 | Extend to global coastlines using batch AOI loops. 82 | 83 | 👨‍💻 Author 84 | 85 | Akajiku 86 | Geospatial Analyst & Earth Observation Specialist 87 | 📜 License 88 | 89 | This project is licensed under the MIT License. 90 | 91 | 92 | --- 93 | 94 | Would you like me to bundle this into a GitHub repository structure with folders like `/notebooks`, `/data`, and `/scripts`? 95 | 96 | -------------------------------------------------------------------------------- /Complete code: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------- 2 | # COASTAL EROSION DETECTION WITH SATELLITE IMAGERY (NDWI) 3 | # -------------------------------------------------------- 4 | 5 | import ee 6 | import geemap 7 | import matplotlib.pyplot as plt 8 | 9 | # Authenticate and initialize Earth Engine 10 | try: 11 | ee.Initialize() 12 | except Exception as e: 13 | ee.Authenticate() 14 | ee.Initialize() 15 | 16 | # Define the Area of Interest (AOI) — Example: Lagos Coastline 17 | aoi = ee.Geometry.Rectangle([3.2, 6.3, 3.8, 6.6]) # You can modify this for your region 18 | 19 | # -------------------------- 20 | # NDWI Calculation Function 21 | # -------------------------- 22 | def get_ndwi(image): 23 | # NDWI = (Green - NIR) / (Green + NIR) 24 | ndwi = image.normalizedDifference(['B3', 'B8']).rename('NDWI') # Sentinel-2 bands 25 | return image.addBands(ndwi) 26 | 27 | # ----------------------------- 28 | # Load Sentinel-2 Image by Year 29 | # ----------------------------- 30 | def get_sentinel_ndwi_image(year): 31 | start_date = f'{year}-01-01' 32 | end_date = f'{year}-12-31' 33 | image = (ee.ImageCollection('COPERNICUS/S2_SR') 34 | .filterBounds(aoi) 35 | .filterDate(start_date, end_date) 36 | .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 10)) 37 | .median() 38 | .clip(aoi)) 39 | return get_ndwi(image).select('NDWI') 40 | 41 | # -------------------------------- 42 | # Extract Water Masks via NDWI 43 | # -------------------------------- 44 | def extract_water_mask(ndwi_image, threshold=0.3): 45 | return ndwi_image.gt(threshold) 46 | 47 | # -------------------------- 48 | # Load Images for Two Years 49 | # -------------------------- 50 | ndwi_2016 = get_sentinel_ndwi_image(2016) 51 | ndwi_2024 = get_sentinel_ndwi_image(2024) 52 | 53 | water_2016 = extract_water_mask(ndwi_2016) 54 | water_2024 = extract_water_mask(ndwi_2024) 55 | 56 | # ------------------------------- 57 | # Change Detection: Erosion Map 58 | # ------------------------------- 59 | change_map = water_2024.subtract(water_2016).rename('Shoreline_Change') 60 | 61 | # -------------------------------- 62 | # Visualization with geemap 63 | # -------------------------------- 64 | Map = geemap.Map(center=[6.5, 3.5], zoom=10) 65 | 66 | Map.addLayer(ndwi_2016, {'min': 0, 'max': 1, 'palette': ['white', 'blue']}, 'NDWI 2016') 67 | Map.addLayer(ndwi_2024, {'min': 0, 'max': 1, 'palette': ['white', 'green']}, 'NDWI 2024') 68 | 69 | Map.addLayer(water_2016.updateMask(water_2016), {'palette': ['blue']}, 'Water 2016') 70 | Map.addLayer(water_2024.updateMask(water_2024), {'palette': ['green']}, 'Water 2024') 71 | 72 | Map.addLayer(change_map.updateMask(change_map), 73 | {'min': -1, 'max': 1, 'palette': ['red', 'white', 'green']}, 74 | 'Coastal Change (Red=Erosion, Green=Accretion)') 75 | 76 | # Add legend 77 | legend_dict = { 78 | '2016 Water': 'blue', 79 | '2024 Water': 'green', 80 | 'Erosion': 'red', 81 | 'No Change': 'white', 82 | 'Accretion': 'green' 83 | } 84 | Map.add_legend(title="Shoreline Change Map", legend_dict=legend_dict) 85 | 86 | Map 87 | --------------------------------------------------------------------------------