Earth Engine

for Dummies

Part III

Michael A Menarguez

mamenarguez@ou.edu

Contents

1. Paddy rice mapping algorithm solution (1st part)
3. Powerful ee.Image.iterate for algorithms!
4. Guided exercise: LST > T for k days
1. ​Image
2. ImageCollection
3. FeatureCollection

1 - Obtain MODIS collection

``````var year = 2014 //Easy way to change year in the script
var modisCollection = ee.ImageCollection('MODIS/MOD09A1') //Load MOD09A1 Collecion
.filterDate(year+'-01-01',(year+1)+'-01-01') //Filter by year
print('Modis collection');
print(modisCollection);``````

2 - Calculate vegetation indices for every image

``````//This function receives a MOD09A1 image and returns ndvi, evi, and lswi
function getVegetationIndices(img){
var ndvi = img.normalizedDifference(['sur_refl_b02','sur_refl_b01'])
var lswi = img.normalizedDifference(['sur_refl_b02','sur_refl_b06'])
var evi = img.expression(
'2.5 * (nir - red) / (nir + 6 * red - 7.5 * blue + 1000)',
{
red: img.select('sur_refl_b01'),    // 620-670nm, RED
nir: img.select('sur_refl_b02'),    // 841-876nm, NIR
blue: img.select('sur_refl_b03')    // 459-479nm, BLUE
});
return img.select([]) // Implementation improvement. Need to return same image
.select([0,1,2],['ndvi','evi','lswi']) //Rename bands
.copyProperties(img,img.propertyNames())
}
// Previous CODE from slide 1 ...
var modisViCollection = modisCollection.map(getVegetationIndices)
print('Modis VI collection');print(modisViCollection);``````

3 - Obtain flooding condition for every image

``````function getFlooding(img){
// Extract VI bands to variables for legibility
var ndvi = img.select('ndvi'), evi = img.select('evi'), lswi =img.select('lswi');
// Calculate flooding mask [(lswi>ndvi or lswi>evi)] = [(lswi>min(ndvi,evi))]
return img.select([])
.copyProperties(img,img.propertyNames())
}
// Previous code here ...
var floodingCollection = modisViCollection.map(getFlooding)
print('Flooding collection');
print(floodingCollection);``````

4 - Fast visualization of results:

``````// Visual representation using median values for each vegetation index
var palette = ['FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163', '99B718',
'74A901', '66A000', '529400', '3E8601', '207401', '056201',
'004C00', '023B01', '012E01', '011D01', '011301'];
var studyRegion = /* color: 98ff00 */ee.Geometry.Polygon(
[[[117.333984375, 54.97761367069625],
[109.3359375, 47.398349200359256],
[96.240234375, 31.353636941500987],
[101.337890625, 18.729501999072138],
[119.00390625, 17.811456088564483],
[144.931640625, 32.32427558887655],
[153.017578125, 52.3755991766591],
[139.482421875, 54.059387886623576]]]);

5 - All together:

**Note that we did not use day of the year filtering to identify the transplanting season yet,we will use LST for this soon... BE PATIENT!

Use MOD09A1 StateQA band and remove cloud, cloud shadow, and snow pixels

1. Test algorithm on a single image
2. Test algorithm on Image collection

Create a function to extract bits from a position i to j

``````//Extracted from GEE examples
var getQABits = function(image, start, end, newName) {
// Compute the bits we need to extract.
var pattern = 0;
for (var i = start; i <= end; i++) {
pattern += Math.pow(2, i);
}
// Return a single band image of the extracted QA bits, giving the band
// a new name.
return image.select([0], [newName])
.bitwiseAnd(pattern)
.rightShift(start);
};
``````

``````var filterBadObs = function(image){
// [bit 0-1] MOD35 cloud 0:clear 1:cloudy 2:mixed 3:not set, assumed clear
// [bit 2]   Cloud shadow 0: no 1: yes
// [bit 15]  Snow 0:no 1:yes
var cloudQA = getQABits(image.select('StateQA'),0,1,'cloud')
var snow = getQABits(image.select('StateQA'),15,15,'snow')
.and(cloudQA.eq(0).or(cloudQA.eq(3))) // Clear or unset
.and(snow.eq(0))// No snow
,1);   //Put a 1 on good pixels
}``````

Test a single image

``````//---------------------------------------------------
// 1 Test a single image for bad observation filtering
//---------------------------------------------------
var sampleImg = ee.Image('MODIS/MOD09A1/MOD09A1_005_2010_01_09')

Test image collection

``````//---------------------------------------------------
// 2 Test a complete collection for bad observation filtering
//---------------------------------------------------
var year = 2010
var col = ee.ImageCollection('MODIS/MOD09A1')
.filterDate(year+'-01-01',(year+1)+'-01-01')
{min:100,max:8000},year+' Original collection')
{min:100,max:8000},year+ ' Filtered collection')``````

See the complete script results here

ee.Collection.iterate()

Sometimes, we just need to apply an algorithm to a collection IN ORDER

### Arguments:

1. algorithm (Function):The function to apply to each element. Must take two arguments: an element of the collection and the value from the previous iteration.
2. opt_first (Object, optional):The initial state.

### Examples:

1. Gap filling algorithm
2. LST > T for k consecutive days

ee.Collection.iterate()

``````function getMax(image,dict){
var currentMaxImage = ee.Image(ee.Dictionary(dict).get('currentMax'))
return ee.Dictionary({
currentMax: currentMaxImage.max(image)
})
}
var collection =  ee.ImageCollection('MODIS/MOD11A2')
.filterDate('2010-01-01','2011-01-01')
.select(['LST_Night_1km'])
.sort('system:time_start')

var iniDict = ee.Dictionary({
currentMax : ee.Image(Math.NEGATIVE_INFINITY)
})

var result = ee.Dictionary(collection.iterate(getMax,iniDict))
.get('currentMax')
print(result)``````

How to get the maximum value of a collection at the pixel level withouth using ee.ImageCollection.max()?

LST > T for K consecutive days (I)

1 - Create a single pixel solution

Make groups of 2 or 3.

You have 5 minutes to think about it!

LST > T for K consecutive days (II)

1. // Initialization:
1. t=0,k=3,contDaysGT0=0,firstDay=-1,fillValue=0;
2. // Iterate on every image in order
1. for (image in sorted(imageCollection)) do:
1. if contDaysGT0<k and LST>T and LST!=fillValue then:
1. if (contDaysGT0==0) then firstDay=doy(image);
2. contDaysGT0+=1;
2. else if contDaysGT0<k and (LST<=T or LST=fillValue )then:
1. contDaysGT0 = 0;
3. //Return results
1. return firstDay

1 - Create a single pixel solution

LST > T for K consecutive days (III)

2 - Adapt solution to raster (2d)

It is exactly the same approach but we need to change variable types to be in 2d too!

A float / integer variable becomes float / integer Image

LST > T for K consecutive days (IV)

``````function getFirstDay(k,temp){
return function getFirstDay(image,dict){
//Retrieve input parameters
dict = ee.Dictionary(dict)
var cont = ee.Image(dict.get('cont'));
var firstDoY = ee.Image(dict.get('firstDoY'));
var fillValue = 0
//1: Get pixels that meet [contDaysGT0<k] and [LST>T] and [LST!=fillValue]
var positiveCondition = image.select([0]).multiply(0).where(
image.gte(temp)
.and(image.neq(fillValue))
.and(cont.neq(k))
,1)
//1.a: Set to current doy where positiveCondition==1 and cont==0
firstDoY = firstDoY.where(positiveCondition.and(cont.eq(0)),doy)
//1.b Increment cont for obsGtY pixels
//2: Restart counter on pixels where [contDaysGT0<k] and ([LST<=T] or [LST=fillValue] )
// It is the same as multiplying positiveCondition to counter, making sure we do not
// touch pixels that were found, this is, cont==k
var negativeCondition = positiveCondition.or(cont.eq(k))
cont = cont.multiply(negativeCondition)
//Return values for next iteration
var newDict = ee.Dictionary({k:k,cont:cont,firstDoY:firstDoY})
return newDict;
};
}

var initialParams = ee.Dictionary({
cont:ee.Image(0),
firstDoY:ee.Image(-1),
})``````

LST > T for K consecutive days (V)