From 8cd1dbbd5d09a48f0b20fed5b69526a10d7f053f Mon Sep 17 00:00:00 2001 From: collinsowusu <59980223+collinsowusu@users.noreply.github.com> Date: Mon, 7 Jun 2021 23:00:33 -0500 Subject: [PATCH] Uploaded the toolbox jupyter notebook --- PyGEE_SWToolbox.ipynb | 1362 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1362 insertions(+) create mode 100644 PyGEE_SWToolbox.ipynb diff --git a/PyGEE_SWToolbox.ipynb b/PyGEE_SWToolbox.ipynb new file mode 100644 index 0000000..c886170 --- /dev/null +++ b/PyGEE_SWToolbox.ipynb @@ -0,0 +1,1362 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Main toolbox" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "5219b2e707f8424fbae226b05b9012b2", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(HTML(value=\"

Python-GEE Surface Water Analyzer Too…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "3e47c6f36b2e414ab36012d1ec9a924b", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Map(center=[40, -100], controls=(WidgetControl(options=['position'], widget=HBox(children=(ToggleButton(value=…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "dac8a24b985c438c9d2bb2dbb6c8930c", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(Output(), Output()))" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "\"\"\" Import the libraries required by the program\"\"\"\n", + "#------------------------------------------------------------------------------------------------------\n", + "\n", + "# GEE Python API\n", + "import ee\n", + "\n", + "# geemap:A Python package for interactive mapping with Google Earth Engine, ipyleaflet, and ipywidgets\n", + "# Documentation: https://geemap.org\n", + "import geemap\n", + "from geemap import ee_basemaps\n", + "\n", + "# geetols: Google earth engine tools\n", + "# https://github.com/gee-community/gee_tools\n", + "import geetools\n", + "from geetools import tools\n", + "\n", + "# hydrafloods: Hydrologic Remote Sensing Analysis for Floods\n", + "#https://github.com/Servir-Mekong/hydra-floods\n", + "import hydrafloods as hf\n", + "from hydrafloods import geeutils\n", + "\n", + "# Ipywidgets for GUI design\n", + "import ipywidgets as ipw\n", + "from IPython.display import display\n", + "from ipywidgets import HBox, VBox, Layout\n", + "\n", + "# A simple Python file chooser widget for use in Jupyter/IPython in conjunction with ipywidgets\n", + "# https://pypi.org/project/ipyfilechooser/\n", + "from ipyfilechooser import FileChooser\n", + "\n", + "# Plotly Python API for interactive graphing\n", + "import plotly\n", + "import plotly.express as px\n", + "import plotly.graph_objs as go\n", + "\n", + "# Pandas - Python Data Analysis Library for data analysis and manipulation\n", + "import pandas as pd\n", + "\n", + "# Miscellaneous Python modules\n", + "from datetime import datetime, timedelta\n", + "import os\n", + "\n", + "#----------------------------------------------------------------------------------------------------\n", + "\n", + "\n", + "\n", + "\"\"\" UI Design\"\"\"\n", + "#---------------------------------------------------------------------------------------------------\n", + "# Program Title\n", + "Title_text = ipw.HTML(\n", + " \"

Python-GEE Surface Water Analyzer Toolbox v.1.0.0\")\n", + "style = {'description_width': 'initial'}\n", + "\n", + "\n", + "# Image Processing Tab\n", + "#************************************************************************************************\n", + "# Image Parameters UI\n", + "dataset_description = ipw.Label('Satellite Imagery Parameters')\n", + "dataset_Label = ipw.Label('Select Dataset:', layout=Layout(margin='5px 0 0 5px')) #top right bottom left\n", + "DatasetType_options = ['Landsat', 'Sentinel-1', 'Sentinel-2', 'USDA NAIP' ]\n", + "DatasetType_dropdown = ipw.Dropdown(options = DatasetType_options, value = None,\n", + " layout=Layout(width='150px', margin='5px 0 0 5px'))\n", + "datasetType = HBox([dataset_Label, DatasetType_dropdown])\n", + "\n", + "# Study period definition\n", + "#************************************************************************************************\n", + "# Start date picker\n", + "lbl_start_date = ipw.Label('Start Date:', layout=Layout(margin='5px 0 0 5px'))\n", + "start_date = ipw.DatePicker(value = datetime.now()-timedelta(7), disabled=False, \n", + " layout=Layout(width='150px', margin='5px 0 0 30px'))\n", + "start_date_box = HBox([lbl_start_date, start_date])\n", + "\n", + "# End date picker\n", + "lbl_end_date = ipw.Label('End Date:', layout=Layout(margin='5px 0 0 5px'))\n", + "end_date = ipw.DatePicker(value = datetime.now(), disabled=False, \n", + " layout=Layout(width='150px', margin='5px 0 0 34px'))\n", + "end_date_box = HBox([lbl_end_date, end_date])\n", + "\n", + "datePickers = VBox([start_date_box, end_date_box])\n", + "\n", + "\n", + "# Cloud threshold for filtering data\n", + "#************************************************************************************************\n", + "# Set cloud threshold\n", + "cloud_threshold = ipw.IntSlider(description = 'Cloud Threshold:',\n", + " orientation = 'horizontal',\n", + " value = 50,\n", + " step = 5,\n", + " style = style)\n", + "\n", + "imageParameters = VBox([dataset_description, datasetType, datePickers, cloud_threshold], \n", + " layout=Layout(width='305px', border='solid 2px black'))\n", + "\n", + "\n", + "# Study Area definition\n", + "#************************************************************************************************\n", + "# Option to use a map drawn boundary or upload shapefile\n", + "StudyArea_description = ipw.Label('Study Area Definition')\n", + "user_preference = ipw.RadioButtons(options=['Upload shapefile', 'Map drawn boundary'], value='Upload shapefile')\n", + "file_selector = FileChooser(description = 'Upload', filter_pattern = \"*.shp\", use_dir_icons = True)\n", + "\n", + "# Retrieve and process satellite images\n", + "#***********************************************************************************************\n", + "# Button to retrieve and process satellite images from the GEE platform\n", + "imageProcessing_Button = ipw.Button(description = 'Process images',\n", + " tooltip='Click to process images', button_style = 'info',\n", + " layout=Layout(width='150px', margin='5px 0 0 50px'))\n", + "\n", + "# Study area UI and process button container\n", + "# ************************************************************************************************\n", + "StudyArea = VBox(children = [StudyArea_description, user_preference, file_selector, imageProcessing_Button], \n", + " layout=Layout(width='300px', border='solid 2px black', margin='0 0 0 10px'))\n", + "\n", + "\n", + "\n", + "# Results UI for displaying number and list of files\n", + "#*****************************************************************************************************\n", + "lbl_results = ipw.Label('Processing Results')\n", + "lbl_images = ipw.Label('No. of processed images:')\n", + "lbl_RetrievedImages = ipw.Label()\n", + "display_no_images = HBox([lbl_images, lbl_RetrievedImages])\n", + "lbl_files = ipw.Label('List of files:')\n", + "lst_files = ipw.Select(layout=Layout(width='360px', height='100px'))\n", + "\n", + "image_Results = VBox([lbl_results, display_no_images, lbl_files, lst_files], \n", + " layout=Layout(width='400px', border='solid 2px black', margin='0 0 0 10px'))\n", + "\n", + "\n", + "# Container for Image Processing Tab\n", + "#************************************************************************************************\n", + "imageProcessing_tab = HBox([imageParameters, StudyArea, image_Results])\n", + "\n", + "\n", + "# Water Extraction Tab\n", + "#*************************************************************************************************\n", + "# Water extraction indices\n", + "water_index_options = ['NDWI','MNDWI','DSWE', 'AWEInsh', 'AWEIsh']\n", + "lbl_indices = ipw.Label('Water Index:', layout=Layout(margin='5px 0 0 5px'))\n", + "water_indices = ipw.Dropdown(options = water_index_options,\n", + " value = 'NDWI',\n", + " layout=Layout(width='100px', margin='5px 0 0 26px'))\n", + "display_indices = HBox([lbl_indices, water_indices])\n", + "\n", + "# Color widget for representing water\n", + "lbl_color = ipw.Label('Color:', layout=Layout(margin='5px 0 0 5px'))\n", + "index_color = ipw.ColorPicker(concise = False,\n", + " value = 'blue',\n", + " layout=Layout(width='100px', margin='5px 0 0 64px'))\n", + "display_color_widget = HBox([lbl_color, index_color])\n", + "\n", + "# Water index threshold selection\n", + "lbl_threshold = ipw.Label('Index threshold:', layout=Layout(margin='5px 0 5px 5px'))\n", + "index_threshold = ipw.BoundedFloatText(value=0.0, min = -1.0, max = 1.0, step = 0.1,\n", + " layout=Layout(width='100px', margin='5px 0 0 5px'))\n", + "\n", + "display_threshold_widget = HBox([lbl_threshold, index_threshold])\n", + "\n", + "water_index_Box = VBox([display_indices, display_color_widget, display_threshold_widget],\n", + " layout=Layout(width='220px', border='solid 2px black'))\n", + "\n", + "extractWater_Button = ipw.Button(description = 'Extract Water',\n", + " tooltip='Click to extract surface water', \n", + " button_style = 'info',\n", + " layout=Layout(width='150px', margin='5px 0 0 20px'))\n", + "\n", + "Extraction_tab = HBox([water_index_Box, extractWater_Button])\n", + "\n", + "\n", + "# Spatial Analysis Tab\n", + "#**************************************************************************************************\n", + "\n", + "water_Frequency_button = ipw.Button(description = 'Compute Water Frequency',\n", + " tooltip='Click to compute water occurence frequency',\n", + " button_style = 'info', layout=Layout(width='200px'))\n", + "\n", + "sharpenImage_Button = ipw.Button(description = 'Pan Sharpening',\n", + " tooltip='Click to sharpen image', button_style = 'info',\n", + " layout=Layout(width='200px'))\n", + "\n", + "removeCloud_Button = ipw.Button(description = 'Remove Clouds',\n", + " tooltip='Click to remove clouds', button_style = 'info',\n", + " layout=Layout(width='200px'))\n", + "\n", + "Spatial_Analysis_Tab = VBox([water_Frequency_button, sharpenImage_Button, removeCloud_Button])\n", + "\n", + "\n", + "# Ploting and Statistics Tab\n", + "#***************************************************************************************************\n", + "area_unit = ipw.Dropdown(options = ['Square Km', 'Hectares', 'Acre'],\n", + " value = 'Square Km',\n", + " description = 'Unit for water surface area:',\n", + " style=style,\n", + " tooltip='Select unit for areas')\n", + "\n", + "plot_button = ipw.Button(description = 'Plot',\n", + " tooltip='Click to plot graph', button_style = 'info')\n", + "plotting_box = VBox([area_unit, plot_button], layout=Layout(width='310px', border='solid 2px black'))\n", + "\n", + "folder_selector1 = FileChooser(description = 'Select Folder', show_only_dirs = True, use_dir_icons = True)\n", + "folder_selector1.title = 'Select a folder'\n", + "folder_selector1.default_path = os.getcwd()\n", + "\n", + "saveFile_name = ipw.Text(description='File Name:', layout=Layout(width='200px'))\n", + "save_data_button = ipw.Button(description = 'Save Data',\n", + " tooltip='Click to save computed areas to file', button_style = 'info')\n", + "\n", + "\n", + "save_box = VBox(children=[folder_selector1, saveFile_name, save_data_button],\n", + " layout=Layout(width='310px', border='solid 2px black', margin='0 0 0 10px'))\n", + "plot_stats_tab = HBox(children=[plotting_box, save_box])\n", + "\n", + "# Downloads Tab\n", + "#***************************************************************************************************\n", + "files_to_download = ipw.RadioButtons(options=['Satellite Images', 'Water Mask', 'Water Frequency'], \n", + " value='Satellite Images', description='Files to download:', style = style)\n", + "\n", + "download_location = ipw.RadioButtons(options=['Google Drive', 'Local Disk'], \n", + " value='Google Drive', description='Download Location:', style = style)\n", + "\n", + "folder_name = ipw.Text(description='Folder Name:')\n", + "\n", + "folder_selector = FileChooser(description = 'Select Folder', show_only_dirs = True, use_dir_icons = True)\n", + "folder_selector.title = 'Select a folder'\n", + "folder_selector.default_path = os.getcwd()\n", + "\n", + "download_button = ipw.Button(description = 'Download',\n", + " tooltip='Click to plot download water images', button_style = 'info')\n", + "\n", + "\n", + "download_settings = VBox(children=[files_to_download, download_location, folder_name])\n", + "\n", + "download_tab = HBox([download_settings, download_button])\n", + "\n", + "# Functions to control UI changes and parameter settings\n", + "#****************************************************************************************************\n", + "\n", + "def datatype_index_change(change):\n", + " \"\"\"\n", + " Function to set image visualization parameters, hide or show some UI componets and\n", + " show water indices that are applicable to the type of satellite image selected\n", + " \n", + " args:\n", + " None\n", + "\n", + " returns:\n", + " None\n", + " \"\"\"\n", + " try:\n", + " global img_type\n", + " global visParams\n", + " global cloud_metadata\n", + " global water_index_options\n", + " if DatasetType_dropdown.value == 'Landsat':\n", + " visParams = {'bands': ['red', 'green', 'blue'],\n", + " 'min': 0,\n", + " 'max': 3000,\n", + " 'gamma': [0.95, 1.1, 1]}\n", + " cloud_threshold.disabled = False\n", + " water_indices.disabled = False\n", + " index_color.disabled = False\n", + " cloud_metadata = 'CLOUD_COVER'\n", + " index_threshold.disabled = False\n", + " water_indices.options = ['NDWI','MNDWI','DSWE','AWEInsh', 'AWEIsh']\n", + " elif DatasetType_dropdown.value == 'Sentinel-1':\n", + " visParams = {'min': -25,'max': 5}\n", + " cloud_threshold.disabled = True\n", + " water_indices.disabled = True\n", + " index_color.disabled = True\n", + " index_threshold.disabled = True\n", + " elif DatasetType_dropdown.value == 'Sentinel-2':\n", + " visParams = {'bands': ['red', 'green', 'blue'],\n", + " 'min': 0.0,\n", + " 'max': 3000}\n", + " cloud_threshold.disabled = False\n", + " water_indices.disabled = False\n", + " index_color.disabled = False\n", + " cloud_metadata = 'CLOUDY_PIXEL_PERCENTAGE'\n", + " index_threshold.disabled = False\n", + " water_indices.options = ['NDWI','MNDWI','AWEInsh', 'AWEIsh']\n", + " elif DatasetType_dropdown.value == 'USDA NAIP':\n", + " visParams = {'bands': ['R', 'G','B'],\n", + " 'min': 0.0,\n", + " 'max': 255.0}\n", + " index_threshold.disabled = False\n", + " water_indices.disabled = False\n", + " index_color.disabled = False\n", + " water_indices.options = ['NDWI']\n", + " \n", + " except Exception as e:\n", + " print(e)\n", + "\n", + "DatasetType_dropdown.observe(datatype_index_change, 'value')\n", + "\n", + "\n", + "def showFileSelector(button):\n", + " \"\"\"\n", + " Function to show or hide shapefile upload widget\n", + " \n", + " args:\n", + " None\n", + "\n", + " returns:\n", + " None\n", + " \"\"\"\n", + " if button['new']:\n", + " StudyArea.children = [StudyArea_description, user_preference,imageProcessing_Button]\n", + " else:\n", + " StudyArea.children = [StudyArea_description, user_preference, file_selector, imageProcessing_Button]\n", + "\n", + "# Link widget to file selector function\n", + "user_preference.observe(showFileSelector, names='index')\n", + "\n", + "\n", + "def showLocationSelector(button):\n", + " \"\"\"\n", + " Function to show or hide folder selector\n", + " \n", + " args:\n", + " None\n", + "\n", + " returns:\n", + " None\n", + " \"\"\"\n", + " if button['new']:\n", + " download_settings.children = [files_to_download, download_location, folder_selector]\n", + " else:\n", + " download_settings.children = [files_to_download, download_location, folder_name]\n", + " \n", + "# Link widget to folder selector function\n", + "download_location.observe(showLocationSelector, names='index')\n", + "\n", + "# Full UI\n", + "#***************************************************************************************************\n", + "tab_children = [imageProcessing_tab, Extraction_tab, Spatial_Analysis_Tab, plot_stats_tab, download_tab]\n", + "\n", + "tab = ipw.Tab()\n", + "tab.children = tab_children\n", + "\n", + "# changing the title of the first and second window\n", + "tab.set_title(0, 'Image Processing')\n", + "tab.set_title(1, 'Water Extraction')\n", + "tab.set_title(2, 'Spatial Analysis')\n", + "tab.set_title(3, 'Plotting & Stats')\n", + "tab.set_title(4, 'Download Images')\n", + "\n", + "GUI = VBox([Title_text,tab])\n", + "\n", + "# Plotting outputs and feedback to user\n", + "#***************************************************************************************************\n", + "plot_output = ipw.Output()\n", + "feedback = ipw.Output()\n", + "OUTPUTS = VBox([plot_output, feedback])\n", + "\n", + "# create map instance\n", + "Map = geemap.Map()\n", + "old_basemap = Map.layers[-1] \n", + "Map.substitute_layer(old_basemap, ee_basemaps['HYBRID'])\n", + "\n", + "\n", + "def reset_map(self):\n", + " Map.clear_layers()\n", + " Map.add_basemap(basemap=\"ROADMAP\")\n", + "\n", + "def load_shapefile():\n", + " \"\"\"\n", + " Function to laod shapefile\n", + " \n", + " args:\n", + " None\n", + "\n", + " returns:\n", + " ee user boundary\n", + " \"\"\"\n", + " file = file_selector.selected \n", + " user_boundary = geemap.shp_to_ee(file)\n", + " Map.addLayer(user_boundary, {}, 'User boundary')\n", + " Map.center_object(user_boundary, 15)\n", + " return user_boundary\n", + "\n", + "def maskS2clouds(image):\n", + " \"\"\"\n", + " Function to mask out clouds from Sentinel-2 images\n", + " \n", + " args:\n", + " Sentinel-2 image\n", + "\n", + " returns:\n", + " Cloud masked image\n", + " \"\"\"\n", + " qa = image.select('pixel_qa')\n", + " cloudBitMask = 1 << 10\n", + " cirrusBitMask = 1 << 11\n", + " mask = qa.bitwiseAnd(cloudBitMask).eq(0) \\\n", + " .And(qa.bitwiseAnd(cirrusBitMask).eq(0))\n", + " return (image.updateMask(mask).copyProperties(image, ['system:time_start']))\n", + "\n", + "def maskLandsatclouds(image):\n", + " \"\"\"\n", + " Function to mask out clouds from Landsat images\n", + " \n", + " args:\n", + " Landsat image\n", + "\n", + " returns:\n", + " Cloud masked image\n", + " \"\"\"\n", + " qa = image.select('pixel_qa')\n", + " #cloudsShadowBitMask = 1 << 7\n", + " cloudsBitMask = 1 << 4\n", + " mask = qa.bitwiseAnd(cloudsBitMask).eq(0) # \\\n", + " #.And(qa.bitwiseAnd(cloudsBitMask).eq(0))\n", + " return (image.updateMask(mask).copyProperties(image, ['system:time_start'])) \n", + " \n", + "def process_images(self):\n", + " \"\"\"\n", + " Function to retrieve and process satellite images from GEE platform\n", + " \n", + " args:\n", + " None\n", + "\n", + " returns:\n", + " None\n", + " \"\"\"\n", + " with plot_output:\n", + " plot_output.clear_output()\n", + " try:\n", + " global filtered_Collection\n", + " global filtered_landsat\n", + " global clipped_images\n", + " global imageType\n", + " global dates\n", + " global site\n", + " global img_scale\n", + " global file_list\n", + " global StartDate\n", + " global EndDate\n", + "\n", + "\n", + " # Reset map\n", + " #Map.clear_layers()\n", + " #Map.add_basemap(basemap = \"ROADMAP\")\n", + "\n", + " lbl_RetrievedImages.value = 'Processing....'\n", + " cloud_thresh = cloud_threshold.value\n", + "\n", + " # Define study area based on user preference\n", + " if user_preference.index == 0:\n", + " site = load_shapefile()\n", + " else:\n", + " site = ee.FeatureCollection(Map.draw_last_feature)\n", + "\n", + " # get widget values\n", + " imageType = DatasetType_dropdown.value\n", + " StartDate = ee.Date.fromYMD(start_date.value.year,start_date.value.month,start_date.value.day)\n", + " EndDate = ee.Date.fromYMD(end_date.value.year,end_date.value.month,end_date.value.day)\n", + "\n", + " # Function to clip images\n", + " def clipImages(img):\n", + " \"\"\"\n", + " Function to clip images\n", + "\n", + " args:\n", + " Image\n", + "\n", + " returns:\n", + " Clipped image\n", + " \"\"\"\n", + " clipped_image = img.clip(site).copyProperties(img, ['system:time_start', 'system:id'])\n", + " return clipped_image\n", + "\n", + " def load_Sentinel1():\n", + " \"\"\"\n", + " Function to retrieve and filter Sentinel-1 images\n", + "\n", + " args:\n", + " None\n", + "\n", + " returns:\n", + " Image collection of Sentinel-1 images\n", + " \"\"\"\n", + " filtered_col = ee.ImageCollection('COPERNICUS/S1_GRD')\\\n", + " .filterDate(StartDate,EndDate)\\\n", + " .filter(ee.Filter.eq('instrumentMode', 'IW'))\\\n", + " .filterMetadata('transmitterReceiverPolarisation', 'equals',['VV','VH'])\\\n", + " .filterMetadata('resolution_meters', 'equals', 10)\\\n", + " .filterBounds(site)\\\n", + " .sort('system:time_start')\n", + " return filtered_col\n", + "\n", + " def load_Sentinel2():\n", + " \"\"\"\n", + " Function to retrieve and filter Sentinel-2 images\n", + "\n", + " args:\n", + " None\n", + "\n", + " returns:\n", + " Image collection of Sentinel-2 images\n", + " \"\"\"\n", + " filtered_col = ee.ImageCollection('COPERNICUS/S2')\\\n", + " .filterDate(StartDate,EndDate)\\\n", + " .filterBounds(site)\\\n", + " .filter(ee.Filter.lt(cloud_metadata, cloud_thresh))\\\n", + " .sort('system:time_start')\\\n", + " .select(['B2','B3','B4','B8','B11','B12','QA60'], ['blue','green','red','nir','swir1','swir2','pixel_qa'])\n", + " return filtered_col\n", + "\n", + " def load_Landsat():\n", + " \"\"\"\n", + " Function to retrieve and filter Landsat images\n", + "\n", + " args:\n", + " None\n", + "\n", + " returns:\n", + " Image collection of Landsat images\n", + " \"\"\"\n", + " # Define Landsat surface reflectance bands\n", + " sensor_band_dict = ee.Dictionary({\n", + " 'l8' : ee.List([1,2,3,4,5,6,10]),\n", + " 'l7' : ee.List([0,1,2,3,4,6,9]),\n", + " 'l5' : ee.List([0,1,2,3,4,6,9]),\n", + " 'l4' : ee.List([0,1,2,3,4,6,9])\n", + " })\n", + " # Sensor band names corresponding to selected band numbers\n", + " bandNames = ee.List(['blue','green','red','nir','swir1','swir2','pixel_qa'])\n", + " # ------------------------------------------------------\n", + " # Landsat 4 - Data availability Aug 22, 1982 - Dec 14, 1993\n", + " ls4 = ee.ImageCollection('LANDSAT/LT04/C01/T1_SR') \\\n", + " .filterBounds(site.geometry()) \\\n", + " .select(sensor_band_dict.get('l4'), bandNames)\n", + "\n", + " # Landsat 5 - Data availability Jan 1, 1984 - May 5, 2012\n", + " ls5 = ee.ImageCollection('LANDSAT/LT05/C01/T1_SR') \\\n", + " .filterBounds(site.geometry()) \\\n", + " .select(sensor_band_dict.get('l5'), bandNames)\n", + "\n", + " # Landsat 7 - Data availability Jan 1, 1999 - Aug 9, 2016\n", + " # SLC-off after 31 May 2003\n", + " ls7 = ee.ImageCollection('LANDSAT/LE07/C01/T1_SR') \\\n", + " .filterDate('1999-01-01', '2003-05-31') \\\n", + " .filterBounds(site.geometry()) \\\n", + " .select(sensor_band_dict.get('l7'), bandNames)\n", + "\n", + " # Post SLC-off; fill the LS 5 gap\n", + " # -------------------------------------------------------\n", + " # Landsat 7 - Data availability Jan 1, 1999 - Aug 9, 2016\n", + " # SLC-off after 31 May 2003\n", + " ls7_2 = ee.ImageCollection('LANDSAT/LE07/C01/T1_SR') \\\n", + " .filterDate('2012-05-05', '2014-04-11') \\\n", + " .filterBounds(site.geometry()) \\\n", + " .select(sensor_band_dict.get('l7'), bandNames)\n", + "\n", + " # --------------------------------------------------------\n", + " # Landsat 8 - Data availability Apr 11, 2014 - present\n", + " ls8 = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR') \\\n", + " .filterBounds(site.geometry()) \\\n", + " .select(sensor_band_dict.get('l8'), bandNames)\n", + "\n", + " # Merge landsat collections\n", + " l4578 = ee.ImageCollection(ls4 \\\n", + " .merge(ls5) \\\n", + " .merge(ls7) \\\n", + " .merge(ls7_2) \\\n", + " .merge(ls8).sort('system:time_start')) \\\n", + " .filterDate(StartDate, EndDate)\\\n", + " .filter(ee.Filter.lt('CLOUD_COVER', cloud_thresh))\n", + "\n", + " return l4578\n", + "\n", + " def load_NAIP():\n", + " \"\"\"\n", + " Function to retrieve and filter NAIP images\n", + "\n", + " args:\n", + " None\n", + "\n", + " returns:\n", + " Image collection of NAIP images\n", + " \"\"\"\n", + " filtered_col = ee.ImageCollection('USDA/NAIP/DOQQ')\\\n", + " .filterDate(StartDate,EndDate)\\\n", + " .filterBounds(site)\\\n", + " .sort('system:time_start')\n", + " return filtered_col\n", + "\n", + " def smooth(img):\n", + " \"\"\"\n", + " Function to smoothen Sentinel-1 images based on focal median\n", + "\n", + " args:\n", + " None\n", + "\n", + " returns:\n", + " Image collection of NAIP images\n", + " \"\"\"\n", + " #smoothed_image = img.focal_median(float('50'),'circle', 'meters')\n", + " return img.addBands(img.select('VV').focal_median(float('50'),'circle', 'meters'))#.rename('VV_smoothed'))\n", + "\n", + " # filter image collection based on date, study area and cloud threshold(depends of datatype)\n", + " if imageType == 'Landsat':\n", + " filtered_landsat = load_Landsat()\n", + " filtered_Collection = filtered_landsat.map(maskLandsatclouds)\n", + " elif imageType == 'Sentinel-2':\n", + " Collection_before = load_Sentinel2()\n", + " filtered_Collection = Collection_before.map(maskS2clouds)\n", + " elif imageType == 'Sentinel-1':\n", + " Collection_before = load_Sentinel1()\n", + " # apply speckle filter algorithm or smoothing\n", + " filtered_Collection = Collection_before.map(hf.lee_sigma)\n", + " #filtered_Collection = Collection_before.map(smooth)\n", + " elif imageType == 'USDA NAIP':\n", + " filtered_Collection = load_NAIP()\n", + "\n", + " # Clip images to study area\n", + " clipped_images = filtered_Collection.map(clipImages)\n", + " # Mosaic same day images\n", + " clipped_images = tools.imagecollection.mosaicSameDay(clipped_images)\n", + "\n", + "\n", + " # Add images to map\n", + " # Add first image in collection to Map\n", + " first_image = clipped_images.first()\n", + " if imageType == 'Sentinel-1':\n", + " img_scale = 10\n", + " else:\n", + " bandNames = first_image.bandNames().getInfo()\n", + " img_scale = first_image.select(str(bandNames[0])).projection().nominalScale().getInfo()\n", + "\n", + " Map.addLayer(clipped_images, visParams, imageType)\n", + "\n", + " # Get no. of processed images\n", + " no_of_images = filtered_Collection.size().getInfo()\n", + "\n", + " # Display number of images\n", + " lbl_RetrievedImages.value = str(no_of_images)\n", + "\n", + " # List of files\n", + " file_list = filtered_Collection.aggregate_array('system:id').getInfo()\n", + " # display list of files\n", + " lst_files.options = file_list\n", + "\n", + " except Exception as e:\n", + " print(e)\n", + " print('An error occurred during processing.')\n", + " \n", + "\n", + "\n", + "# Return the DN that maximizes interclass variance in the region \n", + "def otsu(histogram):\n", + " \"\"\"\n", + " Function to use Otsu algorithm to compute DN that maximizes interclass variance in the region \n", + "\n", + " args:\n", + " Histogram\n", + "\n", + " returns:\n", + " Otsu's threshold\n", + " \"\"\"\n", + " counts = ee.Array(ee.Dictionary(histogram).get('histogram'))\n", + " means = ee.Array(ee.Dictionary(histogram).get('bucketMeans'))\n", + " size = means.length().get([0])\n", + " total = counts.reduce(ee.Reducer.sum(), [0]).get([0])\n", + " sum = means.multiply(counts).reduce(ee.Reducer.sum(), [0]).get([0])\n", + " mean = sum.divide(total)\n", + " indices = ee.List.sequence(1, size)\n", + " \n", + " # Compute between sum of squares, where each mean partitions the data.\n", + " def func_bss(i):\n", + " aCounts = counts.slice(0, 0, i)\n", + " aCount = aCounts.reduce(ee.Reducer.sum(), [0]).get([0])\n", + " aMeans = means.slice(0, 0, i)\n", + " aMean = aMeans.multiply(aCounts) \\\n", + " .reduce(ee.Reducer.sum(), [0]).get([0]) \\\n", + " .divide(aCount)\n", + " bCount = total.subtract(aCount)\n", + " bMean = sum.subtract(aCount.multiply(aMean)).divide(bCount)\n", + " return aCount.multiply(aMean.subtract(mean).pow(2)).add(\n", + " bCount.multiply(bMean.subtract(mean).pow(2)))\n", + " \n", + " bss = indices.map(func_bss)\n", + " return means.sort(bss).get([-1])\n", + "\n", + "\n", + "\n", + "def Water_Extraction(self):\n", + " \"\"\"\n", + " Function to extract surface water from satellite images\n", + "\n", + " args:\n", + " None\n", + "\n", + " returns:\n", + " None\n", + " \"\"\"\n", + " try:\n", + " global water_images\n", + " nd_threshold = index_threshold.value\n", + " color_palette = index_color.value \n", + " # Function to extract water using NDWI or MNDWI from multispectral images\n", + " def extract_water(img):\n", + " \"\"\"\n", + " Function to extract surface water from Landsat and Sentinel-2 images using\n", + " water extraction indices: NDWI, MNDWI, and AWEI\n", + "\n", + " args:\n", + " Image\n", + "\n", + " returns:\n", + " Image with water mask\n", + " \"\"\"\n", + " index_image = ee.Image(1)\n", + " if water_indices.value == 'NDWI':\n", + " if imageType == 'Landsat':\n", + " bands = ['green', 'nir']\n", + " elif imageType == 'Sentinel-2':\n", + " bands = ['green', 'nir']\n", + " elif imageType == 'USDA NAIP':\n", + " bands = ['G', 'N']\n", + " index_image = img.normalizedDifference(bands).rename('waterMask')\n", + " water_image = index_image.gt(nd_threshold).selfMask().copyProperties(img, ['system:time_start'])\n", + " elif water_indices.value == 'MNDWI':\n", + " if imageType == 'Landsat':\n", + " bands = ['green', 'swir1']\n", + " elif imageType == 'Sentinel-2':\n", + " bands = ['green', 'swir1']\n", + " index_image = img.normalizedDifference(bands).rename('waterMask')\n", + " water_image = index_image.gt(nd_threshold).selfMask().copyProperties(img, ['system:time_start'])\n", + " elif water_indices.value == 'AWEInsh':\n", + " if imageType == 'Landsat':\n", + " index_image = img.expression(\n", + " '(4 * (GREEN - SWIR1)) - ((0.25 * NIR)+(2.75 * SWIR2))', {\n", + " 'NIR': img.select('nir'),\n", + " 'GREEN': img.select('green'),\n", + " 'SWIR1': img.select('swir1'),\n", + " 'SWIR2': img.select('swir2')\n", + " }).rename('waterMask')\n", + " elif imageType == 'Sentinel-2':\n", + " index_image = img.expression(\n", + " '(4 * (GREEN - SWIR1)) - ((0.25 * NIR)+(2.75 * SWIR2))', {\n", + " 'NIR': img.select('nir'),\n", + " 'GREEN': img.select('green'),\n", + " 'SWIR1': img.select('swir1'),#.resample('bilinear')\\\n", + " #.reproject(crs= img.select('B11').projection().crs().getInfo()[\"crs\"],scale= 10),\n", + " 'SWIR2': img.select('swir2')#.resample('bilinear')#\\\n", + " #.reproject(crs= img.select('B12').projection().crs().getInfo()[\"crs\"],scale= 10)\n", + " }).rename('waterMask')\n", + " water_image = index_image.gt(nd_threshold).selfMask().copyProperties(img, ['system:time_start'])\n", + " elif water_indices.value == 'AWEIsh':\n", + " if imageType == 'Landsat':\n", + " index_image = img.expression(\n", + " '(BLUE + (2.5 * GREEN) - (1.5 * (NIR + SWIR1)) - (0.25 * SWIR2))', {\n", + " 'BLUE':img.select('blue'),\n", + " 'NIR': img.select('nir'),\n", + " 'GREEN': img.select('green'),\n", + " 'SWIR1': img.select('swir1'),\n", + " 'SWIR2': img.select('swir2')\n", + " }).rename('waterMask')\n", + " elif imageType == 'Sentinel-2':\n", + " index_image = img.expression(\n", + " '(BLUE + (2.5 * GREEN) - (1.5 * (NIR + SWIR1)) - (0.25 * SWIR2))', {\n", + " 'BLUE':img.select('blue'),\n", + " 'NIR': img.select('nir'),\n", + " 'GREEN': img.select('green'),\n", + " 'SWIR1': img.select('swir1'),#.resample('bilinear')\\\n", + " #.reproject(crs= img.select('B11').projection().crs().getInfo()[\"crs\"],scale= 10),\n", + " 'SWIR2': img.select('swir2')#.resample('bilinear')#\\\n", + " #.reproject(crs= img.select('B12').projection().crs().getInfo()[\"crs\"],scale= 10)\n", + " }).rename('waterMask')\n", + " water_image = index_image.gt(nd_threshold).selfMask().copyProperties(img, ['system:time_start']) \n", + " \n", + " return water_image\n", + " \n", + " \n", + " # Function to extract water from SAR Sentinel 1 images\n", + " def add_S1_waterMask(img):\n", + " \"\"\"\n", + " Function to extract surface water from Sentinel-1 images Otsu algorithm\n", + "\n", + " args:\n", + " Image\n", + "\n", + " returns:\n", + " Image with water mask\n", + " \"\"\"\n", + " # Compute histogram\n", + " reducers = ee.Reducer.histogram(255,2).combine(reducer2=ee.Reducer.mean(), sharedInputs=True)\\\n", + " .combine(reducer2=ee.Reducer.variance(), sharedInputs= True)\n", + " histogram = img.select('VV').reduceRegion(\n", + " reducer=reducers,\n", + " geometry=site.geometry(),\n", + " scale=10,\n", + " bestEffort=True)\n", + "\n", + " # Calculate threshold via function otsu (see before)\n", + " threshold = otsu(histogram.get('VV_histogram'))\n", + " \n", + " # get watermask\n", + " waterMask = img.select('VV').lt(threshold).rename('waterMask')\n", + " waterMask = waterMask.updateMask(waterMask) #Remove all pixels equal to 0\n", + " return img.addBands(waterMask)\n", + " \n", + " \n", + " if imageType == 'Sentinel-1':\n", + " water_images = clipped_images.map(add_S1_waterMask).select('waterMask')\n", + " visParams = {'min': 0,'max': 1, 'palette': color_palette}\n", + " Map.addLayer(water_images.first(), visParams, 'Water')\n", + " elif imageType == 'Landsat':\n", + " if water_indices.value == 'DSWE':\n", + " DSWE()\n", + " else:\n", + " water_images = clipped_images.map(extract_water)\n", + " Map.addLayer(water_images.first(), {'palette': color_palette}, 'Water')\n", + " else:\n", + " water_images = clipped_images.map(extract_water)\n", + " Map.addLayer(water_images.first(), {'palette': color_palette}, 'Water')\n", + "\n", + " #ndwi_palette = ['#ece7f2', '#d0d1e6', '#a6bddb', '#74a9cf', '#3690c0', '#0570b0', '#045a8d', '#023858']\n", + " \n", + " except Exception as e:\n", + " print(e)\n", + " print('An error occurred during computation.')\n", + "\n", + "index_threshold.observe(Water_Extraction, 'value')\n", + " \n", + "def Sharpen_Image(self):\n", + " \"\"\"\n", + " Function to pansharpen Landsat and Sentinel-2 images\n", + " Sentinel-2 image pansharpening algorithm yet to be implemented\n", + "\n", + " args:\n", + " None\n", + "\n", + " returns:\n", + " None\n", + " \"\"\"\n", + " try: \n", + " # function to sharpen Landsat images\n", + " def sharpen_Landsat(img):\n", + " \"\"\"\n", + " Function to pansharpen Landsat images\n", + " \n", + " args:\n", + " Image\n", + "\n", + " returns:\n", + " Sharpened image\n", + " \"\"\"\n", + " hsv = img.select(['B4', 'B3', 'B2']).rgbToHsv()\n", + " sharpened_img = ee.Image.cat([hsv.select('hue'), hsv.select('saturation'), img.select('B8')]).hsvToRgb()\n", + " return sharpened_img\n", + " \n", + " if imageType == 'Landsat':\n", + " visParams = {\n", + " 'min': 0,\n", + " 'max': 0.25,\n", + " 'gamma': [1.1, 1.1, 1.1]}\n", + " sharpened_images = clipped_images.map(sharpen_Landsat)\n", + " Map.addLayer(sharpened_images, visParams, 'L8 Sharpened')\n", + " else:\n", + " # function to sharpen Sentinel-2 images yet to be added\n", + " pass\n", + " \n", + " except Exception as e:\n", + " print(e)\n", + " print('An error occurred during computation.')\n", + " \n", + "def maskclouds(self):\n", + " \"\"\"\n", + " Function to mask clouds from Landsat and Sentinel-2 images\n", + " \n", + " args:\n", + " None\n", + "\n", + " returns:\n", + " None\n", + " \"\"\"\n", + " try: \n", + " \n", + " if imageType == 'Landsat':\n", + " cloudRemovedImages = clipped_images.map(maskLandsatclouds)\n", + " #cloudRemovedImages = clipped_images.map(cloud_mask.landsatSR())\n", + " # Visualization for TOA\n", + " visParams = {'bands': ['B4', 'B3', 'B2'],\n", + " 'min': 0,\n", + " 'max': 0.25,\n", + " 'gamma': [1.1, 1.1, 1]}\n", + " Map.addLayer(cloudRemovedImages, visParams, 'L8 Cloud Masked')\n", + " \n", + " elif imageType == 'Sentinel-2':\n", + " cloudRemovedImages = clipped_images.map(maskS2clouds)\n", + " visParams = {'bands': ['B4', 'B3', 'B2'],\n", + " 'min': 0.0,\n", + " 'max': 3000}\n", + " Map.addLayer(cloudRemovedImages, visParams, 'S2 Cloud Masked')\n", + " else:\n", + " pass\n", + " \n", + " except Exception as e:\n", + " print(e)\n", + " print('An error occurred during computation.')\n", + " \n", + "def calc_area(img):\n", + " \"\"\"\n", + " Function to calculate area of water pixels\n", + "\n", + " args:\n", + " Water mask image\n", + "\n", + " returns:\n", + " Water image with calculated total area of water pixels\n", + " \"\"\"\n", + " global unit_symbol\n", + " unit = area_unit.value\n", + " divisor = 1\n", + " if unit =='Square Km':\n", + " divisor = 1e6\n", + " unit_symbol = 'Sqkm'\n", + " elif unit =='Hectares':\n", + " divisor = 1e4\n", + " unit_symbol = 'Ha'\n", + " else:\n", + " divisor = 4047\n", + " unit_symbol = 'acre'\n", + " \n", + " pixel_area = img.multiply(ee.Image.pixelArea()).divide(divisor)\n", + " img_area = pixel_area.reduceRegion(**{\n", + " 'geometry': site.geometry(),\n", + " 'reducer': ee.Reducer.sum(),\n", + " 'scale': img_scale,\n", + " 'maxPixels': 1e13\n", + " })\n", + " return img.set({'water_area': img_area})\n", + "\n", + "def plot_areas(self):\n", + " \"\"\"\n", + " Function to plot a time series of calculated water area for each water image\n", + " \n", + " args:\n", + " None\n", + "\n", + " returns:\n", + " None\n", + " \"\"\"\n", + " try:\n", + " global df\n", + " # Compute water areas\n", + " water_areas = water_images.map(calc_area)\n", + " water_stats = water_areas.aggregate_array('water_area').getInfo()\n", + "\n", + " dates = water_images.aggregate_array('system:time_start')\\\n", + " .map(lambda d: ee.Date(d).format('YYYY-MM-dd')).getInfo()\n", + " \n", + "\n", + " with plot_output:\n", + " plot_output.clear_output()\n", + " dates_lst = [datetime.strptime(i, '%Y-%m-%d') for i in dates]\n", + " y = [item.get('waterMask') for item in water_stats]\n", + " df = pd.DataFrame(list(zip(dates_lst,y)), columns=['Date','Area'])\n", + "\n", + " \n", + " fig = go.Figure([go.Scatter(x=df['Date'], y=df['Area'], name='Water Hydrograph', \n", + " mode='lines+markers', line=dict(dash = 'solid', color ='Black', width = 0.5))])\n", + "\n", + " # plotly figure layout\n", + " fig.update_layout(title = 'Surface Water Area Hydrograph', \n", + " title_x = 0.5, title_y = 0.90, title_font=dict(family=\"Arial\",size=24),\n", + " template = \"plotly_white\",\n", + " xaxis =dict(title ='Date', linecolor = 'Black'),\n", + " yaxis=dict(title='Area ('+unit_symbol+')', linecolor = 'Black'),\n", + " font_family=\"Arial\")\n", + " fig.show()\n", + " \n", + " except Exception as e:\n", + " print(e)\n", + " print('An error occurred during computation.')\n", + "\n", + "def save_data(self):\n", + " file = str(saveFile_name.value)\n", + " filename = file + \".csv\"\n", + " df.to_csv(filename, index=False)\n", + "\n", + "def dowload_water_images(self):\n", + " with feedback:\n", + " try:\n", + " path = folder_selector.selected_path\n", + " folder = folder_name.value\n", + " name_Pattern = '{sat}_{system_date}_{imgType}'\n", + " date_pattern = 'ddMMMy'\n", + " extra = dict(sat=imageType, imgType = 'Water')\n", + " if files_to_download.index == 0:\n", + " download_images = clipped_images\n", + " extra = dict(sat=imageType, imgType = 'Satellite')\n", + " elif files_to_download.index == 1:\n", + " download_images = water_images\n", + " extra = dict(sat=imageType, imgType = 'Water')\n", + " else:\n", + " download_images = ee.ImageCollection([water_frequency])\n", + " name_Pattern = '{sat}_{start}_{end}_{imgType}'\n", + " extra = dict(sat=imageType, imgType = 'Frequency', start=start_date.value.strftime(\"%x\"),\n", + " end=end_date.value.strftime(\"%x\"))\n", + "\n", + " \n", + " if download_location.index == 0:\n", + " task = geetools.batch.Export.imagecollection.toDrive(\n", + " collection = download_images,\n", + " folder = folder,\n", + " region = site.geometry(),\n", + " namePattern = name_Pattern,\n", + " scale = img_scale,\n", + " datePattern=date_pattern,\n", + " extra = extra,\n", + " verbose=True,\n", + " maxPixels = int(1e13))\n", + " task\n", + " #geemap.ee_export_image_collection(clipped_images, out_dir=path, file_per_band=False)\n", + " #geemap.ee_export_image_collection_to_drive(clipped_images, folder=folder, scale=img_scale)\n", + " else:\n", + " geemap.ee_export_image_collection(download_images, out_dir=path)\n", + "\n", + " feedback.clear_output()\n", + " print(\"Download complete\")\n", + "\n", + " except Exception as e:\n", + " print(e)\n", + " print('Download could not be completed')\n", + " \n", + "def water_frequency(self):\n", + " with feedback:\n", + " try:\n", + " global water_frequency\n", + " water_occurence = water_images.reduce(ee.Reducer.sum())\n", + " water_frequency = water_occurence.divide(water_images.size()).multiply(100)\n", + " visParams = {'min':0, 'max':100, 'palette': ['orange','yellow','blue','darkblue']}\n", + " Map.addLayer(water_frequency, visParams, 'Water Occurence')\n", + " except Exception as e:\n", + " print(e)\n", + " print('Frequecy computation could not be completed')\n", + " \n", + "def get_dates(col):\n", + " dates = ee.List(col.toList(col.size()).map(lambda img: ee.Image(img).date().format()))\n", + " return dates\n", + "\n", + "def DSWE():\n", + " global dswe_Coll_Clipped\n", + " global water_images\n", + " color_palette = index_color.value\n", + " dem = ee.Image('USGS/NED')\n", + " aoi = site\n", + " cloud_thresh = cloud_threshold.value\n", + " \n", + " def clipImages(img):\n", + " clipped_image = img.clip(aoi).copyProperties(img, ['system:time_start'])\n", + " return clipped_image\n", + " \n", + " \n", + " # Mask clouds, cloud shadows, and snow\n", + " def maskClouds(img):\n", + " qa = img.select(['pixel_qa'])\n", + " clouds = qa.bitwiseAnd(8).neq(0).Or(qa.bitwiseAnd(16).neq(0)).Or(qa.bitwiseAnd(32).neq(0)) # Cloud\n", + " return img.addBands(clouds.rename('clouds')) # Add band of contaminated pixels\n", + " \n", + " # Apply mask\n", + " img_masked = filtered_landsat.map(maskClouds)\n", + " \n", + " # ----------------------------------------------------------------------\n", + " # Calculate hillshade mask\n", + " # ----------------------------------------------------------------------\n", + " def addHillshade(img):\n", + " solar_azimuth = img.get('SOLAR_AZIMUTH_ANGLE')\n", + " solar_zenith = img.get('SOLAR_ZENITH_ANGLE'); # solar altitude = 90-zenith\n", + " solar_altitude = ee.Number(90).subtract(ee.Number(solar_zenith))\n", + " return img.addBands(ee.Terrain.hillshade(dem, solar_azimuth, solar_altitude).rename('hillshade'))\n", + "\n", + " # Add hillshade bands\n", + " img_hillshade = img_masked.map(addHillshade)\n", + " # ----------------------------------------------------------------------\n", + " # Calculate DSWE indices\n", + " # ----------------------------------------------------------------------\n", + " def addIndices(img):\n", + " # NDVI\n", + " img = img.addBands(img.normalizedDifference(['nir', 'red']).select([0], ['ndvi']))\n", + " # MNDWI (Modified Normalized Difference Wetness Index) = (Green - SWIR1) / (Green + SWIR1)\n", + " img = img.addBands(img.normalizedDifference(['green', 'swir1']).select([0], ['mndwi']))\n", + " # MBSRV (Multi-band Spectral Relationship Visible) = Green + Red\n", + " img = img.addBands(img.select('green').add(img.select('red')).select([0], ['mbsrv'])).toFloat()\n", + " # MBSRN (Multi-band Spectral Relationship Near-Infrared) = NIR + SWIR1\n", + " img = img.addBands(img.select('nir').add(img.select('swir1')).select([0], ['mbsrn']).toFloat())\n", + " # AWEsh (Automated Water Extent Shadow) = Blue + (2.5 * Green) + (-1.5 * mbsrn) + (-0.25 * SWIR2)\n", + " img = img.addBands(img.expression('blue + (2.5 * green) + (-1.5 * mbsrn) + (-0.25 * swir2)', {\n", + " 'blue': img.select('blue'),\n", + " 'green': img.select('green'),\n", + " 'mbsrn': img.select('mbsrn'),\n", + " 'swir2': img.select('swir2')\n", + " }).select([0], ['awesh'])).toFloat()\n", + " return img\n", + "\n", + " # Add indices\n", + " img_indices = img_hillshade.map(addIndices)\n", + " # ----------------------------------------------------------------------\n", + " # ----------------------------------------------------------------------\n", + " # DSWE parameter testing\n", + " # ----------------------------------------------------------------------\n", + " # 1. ========== Function: test MNDWI ===========\n", + " # If (MNDWI > 0.124) set the ones digit (i.e., 00001)\n", + " def test_mndwi(img):\n", + " mask = img.select('mndwi').gt(0.124)\n", + " return img.addBands(mask \\\n", + " .bitwiseAnd(0x1F) \\\n", + " .rename('mndwi_bit'))\n", + "\n", + " # 2. ======== Function: compare MBSRV and MBSRN ========\n", + " # If (MBSRV > MBSRN) set the tens digit (i.e., 00010)\n", + " def test_mbsrv_mbsrn(img):\n", + " mask = img.select('mbsrv').gt(img.select('mbsrn'))\n", + " return img.addBands(mask \\\n", + " .bitwiseAnd(0x1F) \\\n", + " .leftShift(1) \\\n", + " .rename('mbsrn_bit'))\n", + "\n", + " # 3. ======== Function: test AWEsh ========\n", + " # If (AWEsh > 0.0) set the hundreds digit (i.e., 00100)\n", + " def test_awesh(img):\n", + " mask = img.select('awesh').gt(0.0)\n", + " return img.addBands(mask \\\n", + " .bitwiseAnd(0x1F) \\\n", + " .leftShift(2) \\\n", + " .rename('awesh_bit'))\n", + "\n", + " # 4. ======= Function: test PSW1 ========\n", + " # If (MNDWI > -0.44 && SWIR1 < 900 && NIR < 1500 & NDVI < 0.7) set the thousands digit (i.e., 01000)\n", + " def test_mndwi_swir1_nir(img):\n", + " mask = img.select('mndwi').gt(-0.44) \\\n", + " .And(img.select('swir1').lt(900)) \\\n", + " .And(img.select('nir').lt(1500)) \\\n", + " .And(img.select('ndvi').lt(0.7))\n", + " return img.addBands(mask \\\n", + " .bitwiseAnd(0x1F) \\\n", + " .leftShift(3) \\\n", + " .rename('swir1_bit'))\n", + "\n", + " # 5. ======= Function: test PSW2 =========\n", + " # If (MNDWI > -0.5 && SWIR1 < 3000 && SWIR2 < 1000 && NIR < 2500 && Blue < 1000) set the ten-thousands digit (i.e., 10000)\n", + " def test_mndwi_swir2_nir(img):\n", + " mask = img.select('mndwi').gt(-0.5) \\\n", + " .And(img.select('swir1').lt(3000)) \\\n", + " .And(img.select('swir2').lt(1000)) \\\n", + " .And(img.select('nir').lt(2500)) \\\n", + " .And(img.select('blue').lt(1000))\n", + " return img.addBands(mask \\\n", + " .bitwiseAnd(0x1F) \\\n", + " .leftShift(4) \\\n", + " .rename('swir2_bit'))\n", + "\n", + " # Add all bitwise bands to image collection\n", + " img_indices_bit = ee.ImageCollection(img_indices) \\\n", + " .map(test_mndwi) \\\n", + " .map(test_mbsrv_mbsrn) \\\n", + " .map(test_awesh) \\\n", + " .map(test_mndwi_swir1_nir) \\\n", + " .map(test_mndwi_swir2_nir)\n", + " \n", + " # Function: consolidate individual bit bands\n", + " def sum_bit_bands(img):\n", + " bands = img.select(['mndwi_bit', 'mbsrn_bit', 'awesh_bit', 'swir1_bit', 'swir2_bit'])\n", + " summed_bands = bands.reduce(ee.Reducer.bitwiseOr())\n", + " return img.addBands(summed_bands.rename('summed_bit_band'))\n", + " \n", + " # Add individual bit bands to image collection and summarize\n", + " img_indices_bit = ee.ImageCollection(img_indices) \\\n", + " .map(test_mndwi) \\\n", + " .map(test_mbsrv_mbsrn) \\\n", + " .map(test_awesh) \\\n", + " .map(test_mndwi_swir1_nir) \\\n", + " .map(test_mndwi_swir2_nir) \\\n", + " .map(sum_bit_bands)\n", + " # --------------------------------------------------------\n", + " # Produce DSWE layers\n", + " # ----------------------------------------------------------------------\n", + " # Construct slope image from DEM\n", + " #dem = dem.clip(aoi); # removed clipping in an attempt to speed up script\n", + " slope = ee.Terrain.slope(dem)\n", + " # Convert binary code into 4 DSWE categories\n", + " def convert_bin_dswe(img):\n", + " reclass = img.select('summed_bit_band').remap([0, 1, 2, 3, 4, 5, 6, 7, 8, 9,\n", + " 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,\n", + " 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,\n", + " 30, 31],\n", + "\n", + " [0, 0, 0, 4, 0, 4, 4, 2, 0, 4,\n", + " 4, 2, 4, 2, 2, 1, 4, 4, 4, 2,\n", + " 4, 2, 2, 1, 3, 2, 2, 1, 2, 1,\n", + " 1, 1]).rename('dswe')\n", + " # ID cloud-contaminated pixels\n", + " reclass = reclass.where(img.select('clouds').eq(1), 9)\n", + " # ID shaded areas\n", + " reclass = reclass.where(img.select('hillshade').lte(110), 8)\n", + " # ID slopes\n", + " reclass = reclass.where(img.select('dswe').eq(4) and slope.gte(5.71).Or # 10% slope = 5.71°\n", + " (img.select('dswe').eq(3) and slope.gte(11.31)).Or # 20% slope = 11.31°\n", + " (img.select('dswe').eq(2) and slope.gte(16.7)).Or # 30% slope = 16.7°\n", + " (img.select('dswe').eq(1) and slope.gte(16.7)), 0); # 30% slope = 16.7°\n", + "\n", + " return img.addBands(reclass).select('dswe')\n", + " \n", + " img_indices_all = img_indices_bit.map(convert_bin_dswe)\n", + " \n", + "\n", + " # Viz parameters: classes: 0, 1, 2, 3, 4, 9\n", + " dswe_viz = {'min':0, 'max': 9, 'palette': ['000000', '002ba1', '6287ec', '77b800', 'c1bdb6', '000000', '000000',\n", + " '000000', '000000', 'ffffff']}\n", + " \n", + " dswe_Coll_Clipped = img_indices_all.select('dswe').map(clipImages)\n", + " dswe_Coll_Clipped = tools.imagecollection.mosaicSameDay(dswe_Coll_Clipped)\n", + " \n", + " def maskDSWE_Water(img):\n", + " waterImage = img.select('dswe').rename('waterMask')\n", + " watermask = waterImage.gt(0).And(waterImage.lte(4)).selfMask().copyProperties(img, ['system:time_start'])\n", + " return watermask\n", + " \n", + " water_images = dswe_Coll_Clipped.map(maskDSWE_Water)\n", + " water_images = tools.imagecollection.mosaicSameDay(water_images)\n", + " # DSWE image (not composited)\n", + " Map.addLayer(dswe_Coll_Clipped.first(), dswe_viz, \"DSWE\")\n", + " Map.addLayer(water_images.first(), {'palette': color_palette}, 'Water')\n", + " #Map.addLayer(ee.Image(img_indices_all.select('dswe').first()), dswe_viz, \"DSWE\")\n", + " # DSWE monthly composite image (from image collection)\n", + " #Map.addLayer(dswe_ic.first().select('dswe'), dswe_viz, \"DSWE composite\")\n", + " # Landsat Data\n", + " #Map.addLayer(ee.Image(img_indices.first()), ls_viz, 'Landsat')\n", + "\n", + " \n", + " \n", + "imageProcessing_Button.on_click(process_images)\n", + "extractWater_Button.on_click(Water_Extraction)\n", + "sharpenImage_Button.on_click(Sharpen_Image)\n", + "removeCloud_Button.on_click(maskclouds)\n", + "plot_button.on_click(plot_areas)\n", + "download_button.on_click(dowload_water_images)\n", + "water_Frequency_button.on_click(water_frequency)\n", + "save_data_button.on_click(save_data)\n", + "\n", + "display(GUI)\n", + "display(Map)\n", + "display(OUTPUTS)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Download DSWE data only" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "name_Pattern = '{sat}_{system_date}_{imgType}'\n", + "date_pattern = 'ddMMMy'\n", + "extra = dict(sat=imageType, imgType = 'DSWE')\n", + "\n", + "task = geetools.batch.Export.imagecollection.toDrive(\n", + " collection = dswe_Coll_Clipped,\n", + " folder = 'DSWE',\n", + " region = site.geometry(),\n", + " namePattern = name_Pattern,\n", + " scale = img_scale,\n", + " datePattern=date_pattern,\n", + " extra = extra,\n", + " verbose=True,\n", + " crs = 'EPSG:5070',\n", + " crsTransform = [30, 0, -2214330, 0, -30, 2091360],\n", + " maxPixels = int(1e13))\n", + "task" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.5" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}