{ "cells": [ { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "tXmKdAR44woN" }, "source": [ "\n", "\n", "\n", "\n", "\n", ">> *This notebook is part of the free course [EEwPython](https://colab.research.google.com/github/csaybar/EEwPython/blob/master/index.ipynb); the content is available [on GitHub](https://github.com/csaybar/EEwPython)* and released under the [Apache 2.0 License](https://www.gnu.org/licenses/gpl-3.0.en.html). 99% of this material has been adapted from [Google Earth Engine Guides](https://developers.google.com/earth-engine/)." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "VxoENq0D4yOU" }, "source": [ "\n", " < [Image](2_eeImage.ipynb) | [Contents](index.ipynb) | [Geometry, Feature and FeatureCollection](4_features.ipynb)>\n", "\n", "\"Open" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "c1tBPR2840vC" }, "source": [ "
\n", "

Google Earth Engine with Python

\n", "

ee.ImageCollection

\n", "
\n", "

Topics:

\n", "\n", "1. ImageCollection Overview\n", "2. ImageCollection Information and Metadata\n", "3. Filtering and ImageCollection\n", "4. Mapping over an ImageCollection\n", "5. Reducing an ImageCollection\n", "6. Compositing and Mosaicking\n", "7. Iterating over an ImageCollection\n", "\n", "\n", "An **ImageCollection** is a stack or time series of images. In addition to loading an **ImageCollection** using an Earth Engine collection ID, Earth Engine has methods to create image collections. The constructor **ee.ImageCollection()** or the convenience method **ee.ImageCollection.fromImages()** create image collections from lists of images. You can also create new image collections by merging existing collections." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "WZzMDoNFMQqj" }, "source": [ "## Connecting GEE with Google Services" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "yg5yf4UeMUNp" }, "source": [ "- **Authenticate to Earth Engine**" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "yjagNoA5MVyu" }, "outputs": [], "source": [ "!pip install earthengine-api #earth-engine Python API" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "WJ12x_C7-50C" }, "outputs": [], "source": [ "!earthengine authenticate " ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "HytVVE3PMYYB" }, "source": [ "- **Authenticate to Google Drive (OPTIONAL)**" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "Lb1cz-lZMaYB" }, "outputs": [], "source": [ "from google.colab import drive\n", "drive.mount('/content/drive')" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "soMXU2b_-_Ld" }, "source": [ "- **Authenticate to Google Cloud (OPTIONAL)**" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "s3wGdcS6Mdui" }, "outputs": [], "source": [ "from google.colab import auth\n", "auth.authenticate_user()" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "D7oVKyC9_Df8" }, "source": [ "## Testing the software setup\n", "\n", "\n" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "6qMxZxObMjhj" }, "outputs": [], "source": [ "# Earth Engine Python API\n", "import ee\n", "ee.Initialize()" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 34 }, "colab_type": "code", "id": "GNl2kZtm_JA6", "outputId": "5959e4a7-8136-4d7d-bb2d-287719a41908" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Folium version: 0.8.3\n" ] } ], "source": [ "import folium\n", "\n", "# Define the URL format used for Earth Engine generated map tiles.\n", "EE_TILES = 'https://earthengine.googleapis.com/map/{mapid}/{{z}}/{{x}}/{{y}}?token={token}'\n", "\n", "print('Folium version: ' + folium.__version__)" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "cellView": "form", "colab": {}, "colab_type": "code", "id": "t2tnEtGVMk2y" }, "outputs": [], "source": [ "#@title Mapdisplay: Display GEE objects using folium.\n", "def Mapdisplay(center, dicc, Tiles=\"OpensTreetMap\",zoom_start=10):\n", " '''\n", " :param center: Center of the map (Latitude and Longitude).\n", " :param dicc: Earth Engine Geometries or Tiles dictionary\n", " :param Tiles: Mapbox Bright,Mapbox Control Room,Stamen Terrain,Stamen Toner,stamenwatercolor,cartodbpositron.\n", " :zoom_start: Initial zoom level for the map.\n", " :return: A folium.Map object.\n", " '''\n", " mapViz = folium.Map(location=center,tiles=Tiles, zoom_start=zoom_start)\n", " for k,v in dicc.items():\n", " if ee.image.Image in [type(x) for x in v.values()]:\n", " folium.TileLayer(\n", " tiles = v[\"tile_fetcher\"].url_format,\n", " attr = 'Google Earth Engine',\n", " overlay =True,\n", " name = k\n", " ).add_to(mapViz)\n", " else:\n", " folium.GeoJson(\n", " data = v,\n", " name = k\n", " ).add_to(mapViz)\n", " mapViz.add_child(folium.LayerControl())\n", " return mapViz" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "46iNcZViMhuq" }, "source": [ "# 1. Image Collection Overview\n", "\n", "An `ImageCollection` is a **stack or time series of images**. In addition to loading an `ImageCollection` using an Earth Engine collection ID, Earth Engine has methods to create image collections. The constructor `ee.ImageCollection()` or the convenience method `ee.ImageCollection.fromImages()` create image collections from lists of images. You can also create new image collections by merging existing collections. For example:\n" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "2MAaHWtYM20R" }, "outputs": [], "source": [ "# Create arbitrary constant images.\n", "constant1 = ee.Image(1)\n", "constant2 = ee.Image(2)\n", "\n", "# Create a collection by giving a list to the constructor.\n", "collectionFromConstructor = ee.ImageCollection([constant1, constant2])\n", "print('collectionFromConstructor: ')\n", "collectionFromConstructor.getInfo()" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "zq-2wOYAM7bw" }, "outputs": [], "source": [ "# Create a collection with fromImages().\n", "collectionFromImages = ee.ImageCollection.fromImages([ee.Image(3), ee.Image(4)])\n", "print('collectionFromImages: ')\n", "collectionFromImages.getInfo()" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "Rz3D_elIM8tA" }, "outputs": [], "source": [ "# Merge two collections.\n", "mergedCollection = collectionFromConstructor.merge(collectionFromImages)\n", "print('mergedCollection: ')\n", "mergedCollection.getInfo()" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "f1geuu5fM-Eg" }, "outputs": [], "source": [ "# Create a toy FeatureCollection\n", "features = ee.FeatureCollection(\n", " [ee.Feature(None, {'foo': 1}), ee.Feature(None, {'foo': 2})])\n", "\n", "# Create an ImageCollection from the FeatureCollection\n", "# by mapping a function over the FeatureCollection.\n", "images = features.map(lambda feature:ee.Image(ee.Number(feature.get('foo'))))\n", "\n", "# Print the resultant collection.\n", "print('Image collection: ')\n", "images.getInfo()" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "WdRjFVu_M_4f" }, "source": [ "Note that in this example an `ImageCollection` is created by mapping a function that returns an `Image` over a `FeatureCollection`. Learn more about mapping in the [Mapping over an ImageCollection section](https://developers.google.com/earth-engine/ic_mapping). Learn more about feature collections from the [FeatureCollection section](https://developers.google.com/earth-engine/feature_collections)." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "SRN5w_VqNRUU" }, "source": [ "# 2. ImageCollection Information and Metadata\n", "\n", "As with Images, there are a variety of ways to get information about an ImageCollection. The collection can be printed directly to the console, but the console printout is **limited to 5000 elements**. Collections larger than 5000 images will need to be filtered before printing. Printing a large collection will be correspondingly slower. The following example shows various ways of getting information about image collections programmatically." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "nxPzqAbzM9-O" }, "outputs": [], "source": [ "# Load a Landsat 8 ImageCollection for a single path-row.\n", "collection = ee.ImageCollection('LANDSAT/LC08/C01/T1_TOA')\\\n", " .filter(ee.Filter.eq('WRS_PATH', 44))\\\n", " .filter(ee.Filter.eq('WRS_ROW', 34))\\\n", " .filterDate('2014-03-01', '2014-08-01')\n", "print('Collection: ')\n", "collection.getInfo()" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "zaAPnGOmNQFx" }, "outputs": [], "source": [ "# Get the number of images.\n", "count = collection.size()\n", "print('Count: ', count.getInfo())" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "rPeedHOqNas0" }, "outputs": [], "source": [ "from datetime import datetime as dt\n", "# Get the date range of images in the collection.\n", "rango = collection.reduceColumns(ee.Reducer.minMax(), [\"system:time_start\"])\n", "\n", "# Passing numeric date to standard\n", "init_date = ee.Date(rango.get('min')).getInfo()['value']/1000.\n", "init_date_f = dt.utcfromtimestamp(init_date).strftime('%Y-%m-%d %H:%M:%S')\n", "\n", "last_date = ee.Date(rango.get('max')).getInfo()['value']/1000.\n", "last_date_f = dt.utcfromtimestamp(last_date).strftime('%Y-%m-%d %H:%M:%S')\n", "\n", "print('Date range: ',init_date_f,' - ',last_date_f)" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "wLR8A8MTNb8D" }, "outputs": [], "source": [ "# Get statistics for a property of the images in the collection.\n", "sunStats = collection.aggregate_stats('SUN_ELEVATION')\n", "print('Sun elevation statistics: ')\n", "sunStats.getInfo()" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "tYTTGwxPNdH8" }, "outputs": [], "source": [ "# Sort by a cloud cover property, get the least cloudy image.\n", "image = ee.Image(collection.sort('CLOUD_COVER').first())\n", "print('Least cloudy image: ', )\n", "image.getInfo()" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "6N9uTHsnNeGU" }, "outputs": [], "source": [ "# Limit the collection to the 10 most recent images.\n", "recent = collection.sort('system:time_start', False).limit(10)\n", "print('Recent images: ')\n", "recent.getInfo()" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "ufMTpJqnOWM5" }, "source": [ "# 3. Filtering an ImageCollection\n", "\n", "As illustrated in the Get Started section and the ImageCollection Information section, Earth Engine provides a variety of convenience methods for filtering image collections. Specifically, many common use cases are handled by **imageCollection.filterDate()**, and **imageCollection.filterBounds()**. For general purpose filtering, use **imageCollection.filter()** with an **ee.Filter** as an argument. The following example demonstrates both convenience methods and **filter()** to identify and remove images with bad registration from an **ImageCollection**." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 690 }, "colab_type": "code", "id": "gtahWxaDPN8W", "outputId": "ce981d7d-39ac-4f28-bcb4-5089bb40fcbf" }, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 7, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "# Load Landsat 5 data, filter by date and bounds.\n", "collection = ee.ImageCollection('LANDSAT/LT05/C01/T2').filterDate('1987-01-01', '1990-05-01').filterBounds(ee.Geometry.Point(25.8544, -18.08874))\n", "\n", "# Also filter the collection by the IMAGE_QUALITY property.\n", "filtered = collection.filterMetadata('IMAGE_QUALITY', 'equals', 9)\n", "\n", "# Create two composites to check the effect of filtering by IMAGE_QUALITY.\n", "badComposite = ee.Algorithms.Landsat.simpleComposite(collection, 75, 3)\n", "goodComposite = ee.Algorithms.Landsat.simpleComposite(filtered, 75, 3)\n", "\n", "dicc = {\n", " 'Bad composite' : badComposite.getMapId({'bands': ['B3', 'B2', 'B1'], 'gain': 3.5}),\n", " 'Good composite': goodComposite.getMapId({'bands': ['B3', 'B2', 'B1'], 'gain': 3.5})\n", "}\n", "\n", "# Display the results\n", "center = [-18.08874, 25.8544]\n", "Mapdisplay(center, dicc, zoom_start= 13)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "YO-IRM-nRDAa" }, "source": [ "# 4. Mapping over an ImageCollection\n", "\n", "To apply a function to every Image in an ImageCollection use imageCollection.map(). The only argument to map() is a function which takes one parameter: an ee.Image. For example, the following code adds a timestamp band to every image in the collection." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "YV008t1pRIoT" }, "outputs": [], "source": [ "from pprint import pprint\n", "# Load a Landsat 8 collection for a single path-row.\n", "collection = ee.ImageCollection('LANDSAT/LC08/C01/T1_TOA').filter(ee.Filter.eq('WRS_PATH', 44)).filter(ee.Filter.eq('WRS_ROW', 34))\n", "\n", "# This function adds a band representing the image timestamp.\n", "def addTime(image):\n", "\treturn image.addBands(image.metadata('system:time_start'))\n", "\n", "# Map the function over the collection and display the result.\n", "pprint(collection.map(addTime).limit(3).getInfo())" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "ZXxc82LqRq0B" }, "source": [ "Note that in the predefined function, the **metadata()** method is used to create a new Image from the value of a property. As discussed in the *Reducing* and *Compositing* sections, having that time band is useful for the linear modeling of change and for making composites.\n", "\n", "The mapped function is limited in the operations it can perform. Specifically, it can’t modify variables outside the function; it can’t print anything; it can’t use JavaScript ‘if’ or ‘for’ statements. However, you can use **ee.Algorithms.If()** to perform conditional operations in a mapped function." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "FBhel41HR02L" }, "outputs": [], "source": [ "# Load a Landsat 8 collection for a single path-row.\n", "collection = ee.ImageCollection('LANDSAT/LC8_L1T_TOA').filter(ee.Filter.eq('WRS_PATH', 44)).filter(ee.Filter.eq('WRS_ROW', 34))\n", "\n", "# This function uses a conditional statement to return the image if\n", "# the solar elevation > 40 degrees. Otherwise it returns a zero image.\n", "def conditional(image):\n", "\treturn ee.Algorithms.If(ee.Number(image.get('SUN_ELEVATION')).gt(40), image, ee.Image(0))\n", "\n", "# Map the function over the collection, convert to a List and print the result.\n", "print('Expand this to see the result: ')\n", "pprint(collection.map(conditional).limit(3).getInfo())" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "jsp-ucH2Sna6" }, "source": [ "Inspect the list of images in the output ImageCollection and note that the when the condition evaluated by the **If()** algorithm is true, the output contains a constant image. Although this demonstrates a server-side conditional function (learn more about client vs. server in Earth Engine on this page), avoid **If()** in general and use filters instead." ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "3SWzt2T0S5Jt" }, "source": [ "# 5. Reducing an ImageCollection\n", "\n", "To composite images in an **ImageCollection**, use **imageCollection.reduce()**. This will composite all the images in the collection to a single image representing, for example, the min, max, mean or standard deviation of the images. (See the Reducers section for more information about reducers). For example, to create a median value image from a collection:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 690 }, "colab_type": "code", "id": "odhdIiJ7TDzP", "outputId": "ff87449e-fb1a-4a8c-93ec-c3af680385d4" }, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 8, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "# Load a Landsat 8 collection for a single path-row.\n", "collection = ee.ImageCollection('LANDSAT/LC08/C01/T1_TOA').filter(ee.Filter.eq('WRS_PATH', 44)).filter(ee.Filter.eq('WRS_ROW', 34)).filterDate('2014-01-01', '2015-01-01')\n", "\n", "# Compute a median image and display.\n", "median = collection.median()\n", "\n", "dicc = {\n", " 'median' : median.getMapId({'bands': ['B4', 'B3', 'B2'], 'max': 0.3})\n", "}\n", "\n", "# Display the results\n", "center = [37.7726, -122.3578]\n", "Mapdisplay(center, dicc, zoom_start= 12)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "wPMy5STKTjmN" }, "source": [ "At each location in the output image, in each band, the pixel value is the median of all unmasked pixels in the input imagery (the images in the collection). In the previous example, median() is a convenience method for the following call:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 690 }, "colab_type": "code", "id": "UJc6NK2AT8I5", "outputId": "17c71ef8-36a1-4fd7-ddad-77bd9ab54145" }, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 18, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "# Reduce the collection with a median reducer.\n", "median = collection.reduce(ee.Reducer.median())\n", "\n", "# Display the median image.\n", "dicc = {'also median' : median.getMapId({'bands': ['B4_median', 'B3_median', 'B2_median'], 'max': 0.3})}\n", "\n", "# Display the results\n", "center = [37.7726, -122.3578]\n", "Mapdisplay(center, dicc, zoom_start= 12)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "PLEcUs_vUI9L" }, "source": [ "Note that the band names differ as a result of using reduce() instead of the convenience method. Specifically, the names of the reducer have been appended to the band names.\n", "\n", "More complex reductions are also possible using reduce(). For example, to compute the long term linear trend over a collection, use one of the linear regression reducers. The following code computes the linear trend of MODIS Enhanced Vegetation Index (EVI)." ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 690 }, "colab_type": "code", "id": "d_3oQp-fUK3l", "outputId": "dada076a-bba2-49a6-ac6c-3a59150eb30c" }, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 19, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "# This function adds a band representing the image timestamp.\n", "def addTime(image):\n", " return image.addBands(image.metadata('system:time_start').divide(1000 * 60 * 60 * 24 * 365))\n", "\n", "# Load a MODIS collection, filter to several years of 16 day mosaics, and map the time band function over it.\n", "collection = ee.ImageCollection('MODIS/006/MYD13A1').filterDate('2004-01-01', '2010-10-31').map(addTime)\n", "\n", "# Select the bands to model with the independent variable first.\n", "# Compute the linear trend over time.\n", "trend = collection.select(['system:time_start', 'EVI']).reduce(ee.Reducer.linearFit())\n", "\n", "# Display the trend with increasing slopes in green, decreasing in red.\n", "dicc = {\n", " 'EVI trend' : trend.getMapId({'min': 0, 'max': [-100, 100, 10000], 'bands': ['scale', 'scale', 'offset']})\n", "}\n", "\n", "# Display the results\n", "center = [39.436, -96.943]\n", "Mapdisplay(center, dicc, zoom_start= 5)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "WdSBilTMVhVh" }, "source": [ "Note that the output of the reduction in this example is a two banded image with one band for the slope of a linear regression (**scale**) and one band for the intercept (**offset**). Explore the API documentation to see a list of the reducers that are available to reduce an **ImageCollection** to a single Image. See the **ImageCollection.reduce()** section for more information about reducing image collections.\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "_2V04dYAPKQ-" }, "source": [ "# 6. Compositing and Mosaicking\n", "\n", "In general, compositing refers to the process of combining spatially overlapping images into a single image based on an aggregation function. Mosaicking refers to the process of spatially assembling image datasets to produce a spatially continuous image. In Earth Engine, these terms are used interchangeably, though both compositing and mosaicking are supported. For example, consider the task of compositing multiple images in the same location. For example, using one National Agriculture Imagery Program (NAIP) Digital Orthophoto Quarter Quadrangle (DOQQ) at different times, the following example demonstrates making a maximum value composite:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 690 }, "colab_type": "code", "id": "etFzTV26C4nK", "outputId": "cff85610-14fb-4a7a-b7dd-a377f3e5a087" }, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 22, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "# Load three NAIP quarter quads in the same location, different times.\n", "naip2004_2012 = ee.ImageCollection('USDA/NAIP/DOQQ')\\\n", " .filterBounds(ee.Geometry.Point(-71.08841, 42.39823))\\\n", " .filterDate('2004-07-01', '2012-12-31')\\\n", " .select(['R', 'G', 'B'])\n", "\n", "# Temporally composite the images with a maximum value function.\n", "composite = naip2004_2012.max()\n", "center = [42.3712, -71.12532]\n", "Mapdisplay(center, {'max value composite':composite.getMapId()},zoom_start=12)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "xffZMit6DjAq" }, "source": [ "Consider the need to mosaic four different DOQQs at the same time, but different locations. The following example demonstrates that using **imageCollection.mosaic()**:\n", "\n" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 690 }, "colab_type": "code", "id": "jyr0erpiDmP0", "outputId": "96198434-0990-475c-bfbf-35cf1e68a29e" }, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 23, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "# Load four 2012 NAIP quarter quads, different locations.\n", "naip2012 = ee.ImageCollection('USDA/NAIP/DOQQ')\\\n", " .filterBounds(ee.Geometry.Rectangle(-71.17965, 42.35125, -71.08824, 42.40584))\\\n", " .filterDate('2012-01-01', '2012-12-31')\n", "\n", "# Spatially mosaic the images in the collection and display.\n", "mosaic = naip2012.mosaic()\n", "center = [42.3712,-71.12532]\n", "Mapdisplay(center,{'spatial mosaic':mosaic.getMapId()},zoom_start=12)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "P-gUjGwpD8S1" }, "source": [ "Note that there is some overlap in the DOQQs in the previous example. The **mosaic()** method composites overlapping images according to their order in the collection (last on top). To control the source of pixels in a mosaic (or a composite), use image masks. For example, the following uses thresholds on spectral indices to mask the image data in a mosaic:\n", "\n" ] }, { "cell_type": "code", "execution_count": 49, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 700 }, "colab_type": "code", "id": "0j_e-HVpEAi2", "outputId": "5de4b747-e90e-456d-e7e3-ff9c924332ba" }, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 49, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "# Load a NAIP quarter quad, display.\n", "naip = ee.Image('USDA/NAIP/DOQQ/m_4207148_nw_19_1_20120710')\n", "\n", "# Create the NDVI and NDWI spectral indices.\n", "ndvi = naip.normalizedDifference(['N', 'R'])\n", "ndwi = naip.normalizedDifference(['G', 'N'])\n", "\n", "# Create some binary images from thresholds on the indices.\n", "# This threshold is designed to detect bare land.\n", "bare1 = ndvi.lt(0.2).And(ndwi.lt(0.3))\n", "# This detects bare land with lower sensitivity. It also detects shadows.\n", "bare2 = ndvi.lt(0.2).And(ndwi.lt(0.8));\n", "\n", "# Define visualization parameters for the spectral indices.\n", "ndviViz = {'min': -1, 'max': 1, 'palette': ['FF0000', '00FF00']}\n", "ndwiViz = {'min': 0.5, 'max': 1, 'palette': ['00FFFF', '0000FF']}\n", "\n", "# Mask and mosaic visualization images. The last layer is on top.\n", "mosaic = ee.ImageCollection([\n", " # NDWI > 0.5 is water. Visualize it with a blue palette.\n", " ndwi.updateMask(ndwi.gte(0.5)).visualize(**ndwiViz),\n", " # NDVI > 0.2 is vegetation. Visualize it with a green palette.\n", " ndvi.updateMask(ndvi.gte(0.2)).visualize(**ndviViz),\n", " # Visualize bare areas with shadow (bare2 but not bare1) as gray.\n", " bare2.updateMask(bare2.And(bare1.Not())).visualize(**{'palette': ['AAAAAA']}),\n", " # Visualize the other bare areas as white.\n", " bare1.updateMask(bare1).visualize(**{'palette': ['FFFFFF']}),\n", "]).mosaic()\n", "\n", "center = [42.3443, -71.0915]\n", "dicc = {'NAIP DOQQ':naip.getMapId(),\n", " 'Visualization mosaic':mosaic.getMapId()}\n", "Mapdisplay(center,dicc,zoom_start=14) " ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "BcKLdbV6HkG1" }, "source": [ "To make a composite which maximizes an arbitrary band in the input, use **imageCollection.qualityMosaic()**. The **qualityMosaic()** method sets each pixel in the composite based on which image in the collection has a maximum value for the specified band. For example, the following code demonstrates making a greenest pixel composite and a recent value composite:" ] }, { "cell_type": "code", "execution_count": 52, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 700 }, "colab_type": "code", "id": "7-n5llfgHrfN", "outputId": "e7fb1e1c-047b-43a7-c874-63b870b3cce7" }, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 52, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "# This function masks clouds in Landsat 8 imagery.\n", "def maskClouds(img):\n", " scored = ee.Algorithms.Landsat.simpleCloudScore(img)\n", " return img.updateMask(scored.select(['cloud']).lt(20))\n", "\n", "\n", "# This function masks clouds and adds quality bands to Landsat 8 images.\n", "def addQualityBands(img):\n", " return maskClouds(img).addBands(img.normalizedDifference(['B5', 'B4']))\\\n", " .addBands(img.metadata('system:time_start')) # time in days\n", "\n", "\n", "# Load a 2014 Landsat 8 ImageCollection.\n", "# Map the cloud masking and quality band function over the collection.\n", "collection = ee.ImageCollection('LANDSAT/LC08/C01/T1_TOA')\\\n", " .filterDate('2014-06-01', '2014-12-31')\\\n", " .map(addQualityBands)\n", "\n", "# Create a cloud-free, most recent value composite.\n", "recentValueComposite = collection.qualityMosaic('system:time_start')\n", "\n", "# Create a greenest pixel composite.\n", "greenestPixelComposite = collection.qualityMosaic('nd')\n", "\n", "\n", "# Create a cloudy image in the collection.\n", "cloudy = ee.Image('LANDSAT/LC08/C01/T1_TOA/LC08_044034_20140825');\n", "\n", "# Display the results.\n", "center = [37.8239, -122.374] # San Francisco Bay\n", "vizParams = {'bands': ['B5', 'B4', 'B3'], 'min': 0, 'max': 0.4}\n", "dicc = {'recent value composite':recentValueComposite.getMapId(vizParams),\n", " 'greenest pixel composite':greenestPixelComposite.getMapId(vizParams),\n", " 'cloudy':cloudy.getMapId(vizParams)}\n", "\n", "Mapdisplay(center,dicc,zoom_start=12)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "V-F1RE7bKvaw" }, "source": [ "# 7. Iterating over an ImageCollection\n", "\n", "Although `map()` applies a function to every image in a collection, the function visits every image in the collection independently. For example, suppose you want to compute a cumulative anomaly ($A_t$) at time t from a time series. To obtain a recursively defined series of the form $A_t = f(Image_t, A_{t-1})$, mapping won't work because the function (f) depends on the previous result ($A{t-1}$). \n", "\n", "For example, suppose you want to compute a series of cumulative Normalized Difference Vegetation Index (NDVI) anomaly images relative to a baseline. Let $A_0 = 0$ and $f(Image_t, A_{t-1}) = Image_t + A_{t-1}$ where $A_{t-1}$ is the cumulative anomaly up to time $t-1$ and Image_t is the anomaly at time t. Use **imageCollection.iterate()** to make this recursively defined ImageCollection. In the following example, the function **accumulate()** takes two parameters: an image in the collection, and a list of all the previous outputs. With each call to **iterate()**, the anomaly is added to the running sum and the result is added to the list. The final result is passed to the **ImageCollection** constructor to get a new sequence of images:\n" ] }, { "cell_type": "code", "execution_count": 54, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 700 }, "colab_type": "code", "id": "EdSJozzrL5-n", "outputId": "3365f0e7-b850-47e8-cb8d-c28c40a0b076" }, "outputs": [ { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "execution_count": 54, "metadata": { "tags": [] }, "output_type": "execute_result" } ], "source": [ "# Load MODIS EVI imagery.\n", "collection = ee.ImageCollection('MODIS/006/MYD13A1').select('EVI');\n", "\n", "# Define reference conditions from the first 10 years of data.\n", "reference = collection.filterDate('2001-01-01', '2010-12-31')\\\n", " .sort('system:time_start', False) # Sort chronologically in descending order.\n", "\n", "# Compute the mean of the first 10 years.\n", "mean = reference.mean()\n", "\n", "# Compute anomalies by subtracting the 2001-2010 mean from each image in a\n", "# collection of 2011-2014 images. Copy the date metadata over to the\n", "# computed anomaly images in the new collection.\n", "series = collection.filterDate('2011-01-01', '2014-12-31')\\\n", " .map(lambda img: img.subtract(mean).set('system:time_start', img.get('system:time_start')))\n", "\n", "# Display cumulative anomalies.\n", "center = [40.2,-100.811]\n", "vizParams = {'min': -60000, 'max': 60000, 'palette': ['FF0000', '000000', '00FF00']}\n", "dicc = {'EVI anomaly':series.sum().getMapId(vizParams)}\n", "Mapdisplay(center,dicc,zoom_start=5)" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "lLmjL0bdMvOE" }, "outputs": [], "source": [ "# Get the timestamp from the most recent image in the reference collection.\n", "time0 = reference.first().get('system:time_start')\n", "\n", "# Use imageCollection.iterate() to make a collection of cumulative anomaly over time.\n", "# The initial value for iterate() is a list of anomaly images already processed.\n", "# The first anomaly image in the list is just 0, with the time0 timestamp.\n", "first = ee.List([ee.Image(0).set('system:time_start', time0).select([0], ['EVI'])]) # Rename the first band 'EVI'.\n", "\n", "# This is a function to pass to Iterate().\n", "# As anomaly images are computed, add them to the list.\n", "def accumulate(img,lista):\n", " # Get the latest cumulative anomaly image from the end of the list with\n", " # get(-1). Since the type of the list argument to the function is unknown,\n", " # it needs to be cast to a List. Since the return type of get() is unknown,\n", " # cast it to Image.\n", " img = ee.Image(img)\n", " previous = ee.Image(ee.List(lista).get(-1))\n", " # Add the current anomaly to make a new cumulative anomaly image.\n", " added = img.add(previous)\\\n", " .set('system:time_start', img.get('system:time_start')) # Propagate metadata to the new image.\n", " # Return the list with the cumulative anomaly inserted.\n", " return ee.List(lista).add(added)\n", "\n", "# Create an ImageCollection of cumulative anomaly images by iterating.\n", "# Since the return type of iterate is unknown, it needs to be cast to a List.\n", "cumulative = ee.ImageCollection(ee.List(series.iterate(accumulate, first)))" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab": {}, "colab_type": "code", "id": "TOOglazRMxnr" }, "outputs": [], "source": [ "def stackCollection(collection):\n", " # Create an initial image.\n", " first = ee.Image(collection.first()).select([])\n", "\n", " # Write a function that appends a band to an image.\n", " def appendBands(image, previous):\n", " return ee.Image(previous).addBands(image)\n", " return ee.Image(collection.iterate(appendBands, first))" ] }, { "cell_type": "code", "execution_count": 58, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 269 }, "colab_type": "code", "id": "cM9Qg9iTM0o6", "outputId": "bf76bdca-4937-4e48-ad00-02e12565991d" }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "tags": [] }, "output_type": "display_data" } ], "source": [ "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", "# Chart some interesting locations.\n", "pt1 = ee.Geometry.Point(116.4647, 40.1054)\n", "\n", "# ee.ImageCollection to ee.Image\n", "img_cumulative = stackCollection(cumulative)\n", "\n", "\n", "series = img_cumulative.reduceRegions(collection=pt1,\n", " reducer=ee.Reducer.mean(),\n", " scale=500)\n", "\n", "dic_series = series.getInfo()\n", "EVI_anom = np.array(list(dic_series['features'][0]['properties'].values()))\n", "\n", "plt.plot(EVI_anom)\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "yS9KAy82NQqK" }, "source": [ "\n", " < [Image](2_eeImage.ipynb) | [Contents](index.ipynb) | [Geometry, Feature and FeatureCollection](4_features.ipynb)>\n", "\n", "\"Open" ] } ], "metadata": { "colab": { "collapsed_sections": [ "wn46CWeD1fj8", "WZzMDoNFMQqj", "46iNcZViMhuq", "SRN5w_VqNRUU", "ufMTpJqnOWM5", "_2V04dYAPKQ-" ], "name": "ee_ImageCollection.ipynb", "provenance": [], "toc_visible": true, "version": "0.3.2" }, "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.6.8" } }, "nbformat": 4, "nbformat_minor": 1 }