Here is a script that you might find useful:
/**
* @license
* Copyright 2020 Google LLC.
* SPDX-License-Identifier: Apache-2.0
*
* @description
* This script calculates image statistics from the 9 pixels surrounding points
* in a feature collection for all images in a Landsat surface reflectance
* collection (TM, ETM+, OLI). Images are cloud masked using CFmask. All images
* dates are included. The result is a featureCollection; essentially a table
* with one row per unique observation defined by combinations of image and
* point. Columns include the image statistic per band, point ID, and image
* properties (ID, date, satellite).
*/
// #############################################################################
// ### POINT FEATURE COLLECTION SETUP ###
// #############################################################################
// `pts` is a FeatureCollection import from drawing tools.
pts = pts
// Add a buffer to each point (result is a 90x90m square around each point).
.map(function(pt){
return pt.buffer(45).bounds();
});
// Display the points to the Map.
print(pts.limit(5));
Map.centerObject(pts);
Map.addLayer(pts);
// #############################################################################
// ### DEFINE FUNCTIONS TO PREPARE THE LANDSAT IMAGE COLLECTION ###
// #############################################################################
// Define function to mask cloud and shadow pixels out of images using CFmask.
function fmask(img) {
var cloudShadowBitMask = 1 << 3;
var cloudsBitMask = 1 << 5;
var qa = img.select('pixel_qa');
var mask = qa.bitwiseAnd(cloudShadowBitMask).eq(0)
.and(qa.bitwiseAnd(cloudsBitMask).eq(0));
return img.updateMask(mask)}
// Function to get and rename bands of interest from OLI.
function renameOli(img) {
return img.select(
['B2', 'B3', 'B4', 'B5', 'B6', 'B7'],
['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2'])}
// Function to get and rename bands of interest from TM/ETM+.
function renameEtm(img) {
return img.select(
['B1', 'B2', 'B3', 'B4', 'B5', 'B7'],
['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2'])}
// Define function to prepare (cloud mask and rename) OLI images.
function prepOli(img) {
img = fmask(img);
img = renameOli(img);
return img}
// Define function to prepare (cloud mask and rename) TM/ETM+ images.
function prepEtm(img) {
img = fmask(img);
img = renameEtm(img);
return img}
// #############################################################################
// ### FILTER AND PREPARE LANDSAT IMAGE COLLECTIONS ###
// #############################################################################
// Get Landsat surface reflectance collections for OLI, ETM+ and TM sensors.
// filter them by the bounds of the point feature collection and apply the
// relevant image preparation function to each image.
var LC08col = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR')
.filterBounds(pts)
.map(prepOli);
var LE07col = ee.ImageCollection('LANDSAT/LE07/C01/T1_SR')
.filterBounds(pts)
.map(prepEtm);
var LT05col = ee.ImageCollection('LANDSAT/LT05/C01/T1_SR')
.filterBounds(pts)
.map(prepEtm);
// Merge the prepared sensor collections.
var col = LC08col.merge(LE07col).merge(LT05col);
// #############################################################################
// ### REDUCE REGION: FOR EACH IMAGE AROUND EACH POINT ###
// #############################################################################
// Map over the image collection; for each image find the intersecting points
// and do a region reduction at each point.
var statCol = col.map(function(img) {
// Get metadata for the image.
var imgDate = img.date().format('YYYY-MM-dd');
var imgId = img.getString('LANDSAT_ID');
var imgSat = img.getString('SATELLITE');
// Filter the points to those that intersect the image.
var thesePts = pts.filterBounds(img.geometry());
// Reduce the image by mean for the points that intersect it.
var bandStats = img.reduceRegions({
collection: thesePts,
reducer: ee.Reducer.mean(),
scale: 30,
crs: 'EPSG:5070'
})
// Add metadata to each point.
.map(function(pt) {
return pt.set({
'imgDate': imgDate,
'imgId': imgId,
'imgSat': imgSat,
'plotId': pt.getString('PlotID')
});
});
// Return the featureCollection.
return bandStats;
});
// Flatten the collection of collections; result is a featureCollection. Think
// of it as a table with one row per unique observation defined by combinations
// of image and point. Columns include the image region statistic per band and
// image properties.
statCol = statCol.flatten();
// Filter out observations where bands stats are null (point fell on masked
// pixels);
statCol = statCol.filter(
ee.Filter.notNull(['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2']));
// Print a sample of the points.
print(statCol.limit(10));
// #############################################################################
// ### BATCH TASK - EXPORT AS ASSET OR GOOGLE DRIVE FILE ###
// #############################################################################
// It's quite likely that for point feature collections that
// cover a large area or contain many points, you'll need to complete this
// operation as a batch task by either exporting the final feature collection as
// an asset or as a CSV/Shapefile/GeoJSON to Google Drive. If your browser
// times out, definitely try exporting the results.
// Export as asset option.
Export.table.toAsset({
collection: statCol,
description: 'point_summary_table_asset',
assetId: 'point_summary_table'
});
// Export to Google Drive option.
Export.table.toDrive({
collection: statCol,
description: 'point_summary_table_gdrive',
fileFormat: 'CSV'});
Code Editor link