Shaun Levick https://www.geospatialecology.com

Environmental Monitoring and Modelling

Lab 3 - Reducing and Applying functions to images


Objective

In Labs 1 and 2 we learnt how to search for images and display them in the map environment, and we ran some basic computations. Now we will go a step further and learn how to apply the computations over a full collection of images.


Acknowledgments

  • Google Earth Engine Team
  • Geospatial Analysis Lab, University of San Francisco (especially Nicholas Clinton and David Saah)

Load and filter an image collection

  • Search for “Landsat 8 TOA” and add the result to the imports section. Rename the collection "L8".
  • Apply a date filter to the image collection, using the filterDate() method.
var filtered = L8.filterDate('2018-04-01', '2018-04-10');
Map.addLayer(filtered);

Making use of image band combinations

  • With the default visualisation parameters, the data looks dark and the colors look washed out, as we still need to define visualisation parameters. Note that these differ from those we used with Sentinel-2.
var filtered = L8.filterDate('2018-04-01', '2018-04-10');
Map.addLayer(filtered, {min: 0, max: 0.3, bands:['B4', 'B3', 'B2']});
  • Next we will modify the bands to create the classic false­color look, with vegetation highlighted in red, and demonstrate giving each layer a human­ readable name. Paste this code over your existing code.
var filtered = L8.filterDate('2018-04-01', '2018-04-10');
Map.addLayer(filtered, {min: 0, max :0.3, bands:['B4', 'B3', 'B2']}, 'RGB');
Map.addLayer(filtered, {min: 0, max: 0.3, bands:['B5', 'B4', 'B3']}, 'False Color');
  • When you use the same visualization parameters frequently, its best to pull them out into a variable.
var rgb_vis = {min: 0, max: 0.3, bands:['B4', 'B3', 'B2']};
var filtered = L8.filterDate('2018-04-01', '2018-04-10');
Map.addLayer(filtered, rgb_vis, 'RGB');

Reducing image collections

  • Expand out the date range and the paste this code over your existing code. We are now looking at every image collected in 2018 over our study area.
var rgb_vis = {min: 0, max: 0.3, bands: ['B4', 'B3', 'B2']};
var filtered = L8.filterDate('2018-01-01', '2018-12-31');
Map.addLayer(filtered, rgb_vis, 'RGB');
  • We can use the median()reducer to drill down through each pixel and return the median value over the year.
var rgb_vis = {min: 0, max: 0.3, bands: ['B4', 'B3', 'B2']};
var filtered = L8.filterDate('2018-01-01', '2018-08-31');
Map.addLayer(filtered, rgb_vis, 'RGB');
Map.addLayer(filtered.median(), rgb_vis, 'RGB - median reducer');

Isolate an Image

  • Narrow the time range to a 7­-10 day window.
var rgb_vis = {min: 0, max: 0.3, bands: ['B4', 'B3', 'B2']};
var filtered = L8.filterDate('2018-09-01', '2018-09-20');
Map.addLayer(filtered, rgb_vis, 'RGB');
  • Add a Region of Interest (ROI) to the map, by using the point geometry tool. In the Imports section, rename the object to "roi".
  • Add an additional filter to limit it to images covering the ROI. Note that the resulting filtered object is an image collection which may contain one or more images.
var filtered = L8.filterDate('2018-09-01', '2018-09-20')
        .filterBounds(roi);
var rgb_vis = {min: 0, max: 0.3, bands: ['B4', 'B3', 'B2']};
Map.addLayer(filtered, rgb_vis, 'RGB');
  • Extract a sample image from the image collection, and add it as a layer.
var filtered = L8.filterDate('2018-09-01', '2018-09-20')
    .filterBounds(roi);
var image = ee.Image(filtered.first());
var rgb_vis = {min: 0, max: 0.3, bands: ['B4', 'B3', 'B2']};
Map.addLayer(image, rgb_vis, 'RGB');

Compute NDVI

  • Find the ee.Image.normalizedDifference() method in the docs. Use it to simplify the NDVI approach we've used previously.
var rgb_vis = {min: 0, max: 0.3, bands: ['B4', 'B3', 'B2']};
var filtered = L8.filterDate('2018-09-01', '2018-09-20')
.filterBounds(roi);
var image = ee.Image(filtered.first());
var ndvi = image.normalizedDifference(['B5', 'B4']);
Map.addLayer(image, rgb_vis, 'RGB');
Map.addLayer(ndvi, {min: 0, max: 1}, 'NDVI');

Writing a Function

  • Our next goal is to calculate NDVI for a collection of images. To do so, we first need to refactor our code to using a function, which can then be applied to all images in a collection.

  • Start by writing a function that adds a band with NDVI data to an image:

function addNDVI(image) {
  var ndvi = image.normalizedDifference(['B5', 'B4']);
  return image.addBands(ndvi);
    }
  • Test if your function works on a specific images
var filtered = L8.filterDate('2018-09-01','2018-09-20')
    .filterBounds(roi)
var image = ee.Image(filtered.first());
var ndvi = addNDVI(image);
Map.addLayer(image, rgb_vis, 'RGB');
Map.addLayer(ndvi, {min: 0, max: 1}, 'NDVI');
  • Click on the Inspector tab, then on the image. Look in the Inspector tab results to see that the code has added a band called “nd”.
  • Note that the image has changed, because the first band (B1) is being displayed by default, instead of the "nd" band. Add a visualization parameter to correct this:
Map.addLayer(ndvi, {bands: 'nd', min: 0, max: 1}, 'NDVI');

Map a Function over a Collection

  • Now that we have a working function, we will 'map' the function across the filtered Landsat 8 collection.
function addNDVI(image) {
    var ndvi = image.normalizedDifference(['B5', 'B4']);
    return image.addBands(ndvi);
        }
var filtered = L8.filterDate('2018-09-01','2018-09-01')
   .filterBounds(roi);
var with_ndvi = filtered.map(addNDVI);
var rgb_vis = {min: 0, max: 0.3, bands: ['B4', 'B3', 'B2']};
Map.addLayer(filtered, rgb_vis, 'RGB');
Map.addLayer(with_ndvi, {bands: 'nd', min: 0, max: 1}, 'NDVI');
  • Using the inspector tab, click on the map to show that each image now has an ‘nd’ band containing the NDVI.
  • Get rid of the bounds filter, so that all areas in the viewport are used.
  • To get rid of some clouds, expand out the time range and switch to using a median reducer.
function addNDVI(image) {
    var ndvi = image.normalizedDifference(['B5', 'B4']);
    return image.addBands(ndvi);
}
var filtered = L8.filterDate('2018-01-01','2018-10-30');
var with_ndvi = filtered.map(addNDVI);
var rgb_vis = {min: 0, max: 0.3, bands: ['B4', 'B3', 'B2']};
Map.addLayer(filtered.median(), rgb_vis, 'RGB');
Map.addLayer(with_ndvi.median(), {bands: 'nd', min: 0, max: 1}, 'NDVI');

Build a Greenest­ Pixel Composite

  • We will now work on an even better way to produce cloud­ free mosaics. The ee.ImageCollection.qualityMosaic() method can be used to order image bands, on a pixel­ by ­pixel basis, by a specified metric (we will use NDVI).
function addNDVI(image) {
        var ndvi = image.normalizedDifference(['B5', 'B4']);
    return image.addBands(ndvi);
        }
var filtered = L8.filterDate('2018-01-01', '2018-10-30');
var with_ndvi = filtered.map(addNDVI);
var rgb_vis = {min: 0, max: 0.3, bands: ['B4', 'B3', 'B2']};
Map.addLayer(filtered.median(), rgb_vis, 'RGB (median)');
var greenest = with_ndvi.qualityMosaic('nd');
Map.addLayer(greenest, rgb_vis, 'RGB (greenest pixel)');
  • If your chosen location doesn’t make for a decent max­NDVI composite, you can fly somewhere interesting - like a rainforest belt. Try the Daintree area in the vicinity of Cairns, Australia.

Charting NDVI over Time

  • Click on the ROI point that was added earlier, and then drag it to an agricultural field. Add the following line to make a chart of NDVI over time for your ROI.
function addNDVI(image) {
    var ndvi = image.normalizedDifference(['B5', 'B4']);
    return image.addBands(ndvi);
        }
var filtered = L8.filterDate('2018-01-01', '2018-10-30');
var with_ndvi = filtered.map(addNDVI);
var greenest = with_ndvi.qualityMosaic('nd');
var rgb_vis = {min: 0, max: 0.3, bands: ['B4', 'B3', 'B2']};
Map.addLayer(filtered.median(), rgb_vis, 'RGB (median)');
Map.addLayer(greenest, rgb_vis, 'RGB (greenest pixel)');
print(Chart.image.series(with_ndvi.select('nd'), roi));
  • Try out the interactivity of the chart by hovering, expand it to full screen, and testing out the SVG/PNG/CSV download buttons.

Export an RGB Image

The source data that you work with can have many different characteristics (single­band, multispectral, bit­depth, etc.), and the visualization tools in Earth Engine allow you to display the data in a variety of ways. You can also export the data in a variety of ways, such as a multi­band image. This section will demonstrate how to export a 3­band (RGB) 8­bit image that can be easily displayed in other tools outside of Earth Engine.

  • Start by creating an 8­bit RGB image object, using the ee.Image.visualize() command, and add it to the interactive map
var rgb_vis = {min: 0, max: 0.3, bands: ['B4', 'B3', 'B2']};
function addNDVI(image) {
    var ndvi = image.normalizedDifference(['B5', 'B4']);
    return image.addBands(ndvi);
        }
var filtered = L8.filterDate('2018-01-01', '2018-10-30');
var with_ndvi = filtered.map(addNDVI);
var greenest = with_ndvi.qualityMosaic('nd');
var rgb = greenest.visualize(rgb_vis);
Map.addLayer(rgb,{}, 'RGB');
  • Export the image (by default to your Google Drive account).
var rgb_vis = {min: 0, max: 0.3, bands: ['B4', 'B3', 'B2']};
function addNDVI(image) {
    var ndvi = image.normalizedDifference(['B5', 'B4']);
    return image.addBands(ndvi);
        }
var filtered = L8.filterDate('2018-01-01', '2018-10-30');
var with_ndvi = filtered.map(addNDVI);
var greenest = with_ndvi.qualityMosaic('nd');
var rgb = greenest.visualize(rgb_vis);
Map.addLayer(rgb, {}, 'RGB (greenest pixel)');
Export.image.toDrive(rgb, 'GreenestPixel');

Tidy up your code

  • Remember to save your code, and don't forget to go back and annotate your lines so that you can remember what you did, and so that others can understand your script.

GEARS - Geospatial Ecology and Remote Sensing lab - https://www.geospatialecology.com