1. Load Landsat Collection
Landsat, a joint program of the USGS and NASA, has been observing the Earth continuously from 1972 through the present day. Today the Landsat satellites image the entire Earth’s surface at a 30-meter resolution about once every two weeks, including multispectral and thermal data.
Landsat data is available in Earth Engine in its raw form, as Surface Reflectance, TOA-corrected reflectance, and in various ready-to-use computed products such as NDVI and EVI vegetation indices.
In this course we will only work with Landsat Collection 2 that marks the second major reprocessing effort on the Landsat archive by the USGS that results in several data product improvements over Collection 1 that harness recent advancements in data processing and algorithm development.
Satellite | Landsat 5 | Landsat 7 | Landsat 8 | Landsat 9 |
---|---|---|---|---|
Instrument | Multispectral Scanner (MSS), Thematic Mapper (TM) |
Enhanced Thematic Mapper (ETM+) |
Operational Land Imager (OLI), Thermal Infrared Sensor (TIRS) |
OLI-2, TIRS-2 |
Number of bands | 10 | 10 | 10 | 10 |
Spatial resolution | 30m x 30m | 30m x 30m | 30m x 30m | 30m x 30m |
Temporal resolution | 16 days | 16 days | 16 days | 16 days |
Temporal range | 1984 - 2012 | 1999 - Present | 2013 - Present | 2021 - Present |
Google Earth Engine collection | Dataset | Dataset | Dataset | Not available |
Let’s define which datasets we will work with.
// Load USGS Landsat 5 Level 2, Collection 2, Tier 1
var landsat_5 = ee.ImageCollection("LANDSAT/LT05/C02/T1_L2")
// Load USGS Landsat 7 Level 2, Collection 2, Tier 1
var landsat_7 = ee.ImageCollection("LANDSAT/LE07/C02/T1_L2")
// Load USGS Landsat 8 Level 2, Collection 2, Tier 1
var landsat_8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
1.1 Filter Landsat data
// Define time period
var startDate = '2019-01-01'
var endDate = '2019-12-31'
// Select Landsat 8 images in area of interest and time period
var l8_filter = landsat_8
.filterDate(startDate, endDate)
.filterBounds(roi)
1.2 Apply scaling factors
A scale factor must be applied to both Collection 1 and Collection 2 Landsat Level-2 surface reflectance and surface temperature products before using the data.
Landsat Collection 2 have the following scale factors, fill values, data type, and valid range.
Science Product | Scale Factor | Fill Value | Data Type | Valid Range |
---|---|---|---|---|
Surface Reflectance | 0.0000275 + -0.2 | 0 | Unsigned 16-bit integer | 1-65455 |
Surface Temperature | 0.00341802 + 149.0 | 0 | Unsigned 16-bit integer | 1-65455 |
Examples for scaling Landsat Collection 2 Level-2 science products
Landsat Collection 2 surface reflectance has a scale factor of 0.0000275 and an additional offset of -0.2 per pixel.
For example, a pixel value of 18,639 is multiplied by 0.0000275 for the scale factor and then -0.2 is added for the additional offset to get a reflectance value of 0.313 after the scale factor is applied.
// Applies scaling factors.
function applyScaleFactors(image) {
var opticalBands = image.select('SR_B.').multiply(0.0000275).add(-0.2)
var thermalBands = image.select('ST_B.*').multiply(0.00341802).add(149.0)
return image.addBands(opticalBands, null, true)
.addBands(thermalBands, null, true)
}
var l8_filter = l8_filter.map(applyScaleFactors)
2. Cloud Mask
Most optical satellite imagery products come with one or more QA-bands that allows the user to assess quality of each pixel and extract pixels that meet their requirements. The most common application for QA-bands is to extract information about cloudy pixels and mask them. But the QA bands contain a wealth of other information that can help you remove low quality data from your analysis. Typically the information contained in QA bands is stored as Bitwise Flags. More info about bitmasks
In Landsat imagery, pixel quality assessment (QA_PIXEL) bands are generated by the CFMask algorithm. Different bit definitions are used because the cirrus band is only available on Landsat 8 and 9. This band is relevant to both Surface Reflectance and Surface Temperature products.
Bit | Landat 5 & 7 | Landsat 8 & 9 |
---|---|---|
0 | Fill | Fill |
1 | Dilated Cloud | Dilated Cloud |
2 | Unused | Cirrus |
3 | Cloud | Cloud |
4 | Cloud Shadow | Cloud Shadow |
5 | Snow | Snow |
6 | Clear | Clear |
7 | Water | Water |
8-9 | Cloud Confidence | Cloud Confidence |
10-11 | Cloud Shadow Confidence | Cloud Shadow Confidence |
12-13 | Snow/Ice Confidence | Snow/Ice Confidence |
14-15 | Unused | Cirrus Confidence |
The two following functions will be used to mask clouds, cloud shadows, … on everny images of an ImageCollection
.
/**
* Utility to extract bitmask values.
* Look up the bit-ranges in the catalog.
*
* value - ee.Number or ee.Image to extract from.
* fromBit - int or ee.Number with the first bit.
* toBit - int or ee.Number with the last bit (inclusive).
* Defaults to fromBit.
*/
function bitwiseExtract(value, fromBit, toBit) {
if (toBit === undefined) toBit = fromBit
var maskSize = ee.Number(1).add(toBit).subtract(fromBit)
var mask = ee.Number(1).leftShift(maskSize).subtract(1)
return value.rightShift(fromBit).bitwiseAnd(mask)
}
var maskClouds = function(image) {
var QA = image.select('QA_PIXEL');
var clouds = bitwiseExtract(QA, 3).eq(0)
var cloud_shadows = bitwiseExtract(QA, 4).eq(0)
var mask = clouds
.and(cloud_shadows)
var maskedImage = image.updateMask(mask)
return maskedImage
}
3. Composites
3.1 Single period composite
var l8_composite = l8_filter
.map(maskClouds)
.median()
3.2 Multiple period composites
// List of months
var months = ee.List.sequence(1, 12)
print("Months : ",months)
// List of years
var years = ee.List.sequence(2019, 2019)
print("Years : ",years)
var l8_monthly_mean = ee.ImageCollection.fromImages(
years.map(function (y) {
return months.map(function (m) {
return l8_filter
.filter(ee.Filter.calendarRange(y, y, 'year'))
.filter(ee.Filter.calendarRange(m, m, 'month'))
.map(maskClouds)
.median()
.set('year',y)
.set('month',m);
});
})
.flatten())
.map(function(image){return image.clip(roi)})
print("Monthly mean : ",l8_monthly_mean)
4. Visualization
var visParams = {
bands: ['SR_B4', 'SR_B3', 'SR_B2'],
min: 0.0,
max: 0.3,
}
4.1 Visualize single image
Map.centerObject(roi, 8)
Map.addLayer(l8_composite, visParams, 'True Color (432) - Mask - Median')
4.2 Visualize Image Collection
// Create RGB visualization images for use as animation frames.
var rgbVis = l8_monthly_mean.map(function(img) {
return img.visualize(visParams);
})
// Define GIF visualization arguments.
var gifParams = {
region: roi.geometry(),
dimensions: 1000,
crs: 'EPSG:3857',
framesPerSecond: 1,
format: 'gif'
}
// Print the GIF URL to the console.
print(rgbVis.getVideoThumbURL(gifParams))
// Render the GIF animation in the console.
print(ui.Thumbnail(rgbVis, gifParams))