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
+}