diff --git a/code/end_to_end_gee/02-Earth-Engine-Intermediate/03b_Computation_on_Image_Collections_(complete) b/code/end_to_end_gee/02-Earth-Engine-Intermediate/03b_Computation_on_Image_Collections_(complete) index 14d6d484..f838863f 100644 --- a/code/end_to_end_gee/02-Earth-Engine-Intermediate/03b_Computation_on_Image_Collections_(complete) +++ b/code/end_to_end_gee/02-Earth-Engine-Intermediate/03b_Computation_on_Image_Collections_(complete) @@ -24,7 +24,7 @@ var withNdvi = filtered.map(addNDVI); var composite = withNdvi.median(); -var ndviComposite = composite.select('ndvi').clip(geometry); +var ndviComposite = composite.select('ndvi'); var palette = [ 'FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163', '99B718', @@ -32,4 +32,4 @@ var palette = [ '004C00', '023B01', '012E01', '011D01', '011301']; var ndviVis = {min:0, max:0.5, palette: palette }; -Map.addLayer(ndviComposite, ndviVis, 'ndvi'); +Map.addLayer(ndviComposite.clip(geometry), ndviVis, 'ndvi'); diff --git a/code/end_to_end_gee/02-Earth-Engine-Intermediate/03c_Computation_on_Image_Collections_(exercise) b/code/end_to_end_gee/02-Earth-Engine-Intermediate/03c_Computation_on_Image_Collections_(exercise) index 740b924c..28911c1a 100644 --- a/code/end_to_end_gee/02-Earth-Engine-Intermediate/03c_Computation_on_Image_Collections_(exercise) +++ b/code/end_to_end_gee/02-Earth-Engine-Intermediate/03c_Computation_on_Image_Collections_(exercise) @@ -25,10 +25,11 @@ function addIndices(image) { var withIndices = filtered.map(addIndices); // Composite -var composite = withIndices.median().clip(geometry); +var composite = withIndices.median(); print(composite); -// Extract the 'ndwi' band and display a NDWI map +// Extract the 'ndwi' band +// Clip and display a NDWI map // use the palette ['white', 'blue'] // Hint: Use .select() function to select a band diff --git a/code/end_to_end_gee/03-Supervised-Classification/01b_Basic_Supervised_Classification_(complete) b/code/end_to_end_gee/03-Supervised-Classification/01b_Basic_Supervised_Classification_(complete) index e4f706de..bd26c407 100644 --- a/code/end_to_end_gee/03-Supervised-Classification/01b_Basic_Supervised_Classification_(complete) +++ b/code/end_to_end_gee/03-Supervised-Classification/01b_Basic_Supervised_Classification_(complete) @@ -229,10 +229,10 @@ var filtered = s2 .filter(ee.Filter.bounds(geometry)) .select('B.*'); -var composite = filtered.median().clip(geometry) ; +var composite = filtered.median(); // Display the input composite. -Map.addLayer(composite, rgbVis, 'image'); +Map.addLayer(composite.clip(geometry), rgbVis, 'image'); var gcps = urban.merge(bare).merge(water).merge(vegetation); @@ -258,6 +258,6 @@ Map.centerObject(geometry); // Urban, Bare, Water, Vegetation var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; -Map.addLayer(classified, {min: 0, max: 3, palette: palette}, '2019'); +Map.addLayer(classified.clip(geometry), {min: 0, max: 3, palette: palette}, '2019'); diff --git a/code/end_to_end_gee/03-Supervised-Classification/01c_Basic_Supervised_Classification_(exercise) b/code/end_to_end_gee/03-Supervised-Classification/01c_Basic_Supervised_Classification_(exercise) index a80aabf7..f1afdb62 100644 --- a/code/end_to_end_gee/03-Supervised-Classification/01c_Basic_Supervised_Classification_(exercise) +++ b/code/end_to_end_gee/03-Supervised-Classification/01c_Basic_Supervised_Classification_(exercise) @@ -16,12 +16,12 @@ var filtered = s2 .filter(ee.Filter.bounds(geometry)) .select('B.*'); -var composite = filtered.median().clip(geometry); +var composite = filtered.median(); // Display the input composite. var rgbVis = {min: 0.0, max: 3000, bands: ['B4', 'B3', 'B2']}; -Map.addLayer(composite, rgbVis, 'image'); +Map.addLayer(composite.clip(geometry), rgbVis, 'image'); // Exercise // Add training points for 4 classes @@ -60,6 +60,6 @@ Map.addLayer(composite, rgbVis, 'image'); // // Urban, Bare, Water, Vegetation // var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; -// Map.addLayer(classified, {min: 0, max: 3, palette: palette}, '2019'); +// Map.addLayer(classified.clip(geometry), {min: 0, max: 3, palette: palette}, '2019'); diff --git a/code/end_to_end_gee/03-Supervised-Classification/01d_Basic_Supervised_Classification_(noimport) b/code/end_to_end_gee/03-Supervised-Classification/01d_Basic_Supervised_Classification_(noimport) index 625e958f..a0399a8e 100644 --- a/code/end_to_end_gee/03-Supervised-Classification/01d_Basic_Supervised_Classification_(noimport) +++ b/code/end_to_end_gee/03-Supervised-Classification/01d_Basic_Supervised_Classification_(noimport) @@ -15,7 +15,7 @@ var filtered = s2 .filter(ee.Filter.bounds(geometry)) .select('B.*'); -var composite = filtered.median().clip(geometry); +var composite = filtered.median(); // Display the input composite. var rgbVis = { @@ -23,7 +23,7 @@ var rgbVis = { max: 3000, bands: ['B4', 'B3', 'B2'], }; -Map.addLayer(composite, rgbVis, 'image'); +Map.addLayer(composite.clip(geometry), rgbVis, 'image'); var gcps = urban.merge(bare).merge(water).merge(vegetation); @@ -48,7 +48,7 @@ var classified = composite.classify(classifier); // Urban, Bare, Water, Vegetation var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; -Map.addLayer(classified, {min: 0, max: 3, palette: palette}, '2019'); +Map.addLayer(classified.clip(geometry), {min: 0, max: 3, palette: palette}, '2019'); // Display the GCPs // We use the style() function to style the GCPs var palette = ee.List(palette); diff --git a/code/end_to_end_gee/03-Supervised-Classification/02a_Accuracy_Assessment b/code/end_to_end_gee/03-Supervised-Classification/02a_Accuracy_Assessment index 3ee38ce6..65cfcaee 100644 --- a/code/end_to_end_gee/03-Supervised-Classification/02a_Accuracy_Assessment +++ b/code/end_to_end_gee/03-Supervised-Classification/02a_Accuracy_Assessment @@ -19,10 +19,10 @@ var filtered = s2 .filter(ee.Filter.bounds(geometry)) .select('B.*'); -var composite = filtered.median().clip(geometry); +var composite = filtered.median(); // Display the input composite. -Map.addLayer(composite, rgbVis, 'image'); +Map.addLayer(composite.clip(geometry), rgbVis, 'image'); // Overlay the point on the image to get training data. @@ -44,4 +44,4 @@ var classifier = ee.Classifier.smileRandomForest(50) var classified = composite.classify(classifier); var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; -Map.addLayer(classified, {min: 0, max: 3, palette: palette}, '2019'); \ No newline at end of file +Map.addLayer(classified.clip(geometry), {min: 0, max: 3, palette: palette}, '2019'); \ No newline at end of file diff --git a/code/end_to_end_gee/03-Supervised-Classification/02b_Accuracy_Assessment_(complete) b/code/end_to_end_gee/03-Supervised-Classification/02b_Accuracy_Assessment_(complete) index 6e35c908..49790ef2 100644 --- a/code/end_to_end_gee/03-Supervised-Classification/02b_Accuracy_Assessment_(complete) +++ b/code/end_to_end_gee/03-Supervised-Classification/02b_Accuracy_Assessment_(complete) @@ -18,10 +18,10 @@ var filtered = s2 .filter(ee.Filter.bounds(geometry)) .select('B.*'); -var composite = filtered.median().clip(geometry); +var composite = filtered.median(); // Display the input composite. -Map.addLayer(composite, rgbVis, 'image'); +Map.addLayer(composite.clip(geometry), rgbVis, 'image'); // Add a random column and split the GCPs into training and validation set @@ -53,7 +53,7 @@ var classifier = ee.Classifier.smileRandomForest(50) var classified = composite.classify(classifier); var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; -Map.addLayer(classified, {min: 0, max: 3, palette: palette}, '2019'); +Map.addLayer(classified.clip(geometry), {min: 0, max: 3, palette: palette}, '2019'); //************************************************************************** // Accuracy Assessment //************************************************************************** diff --git a/code/end_to_end_gee/03-Supervised-Classification/03a_Improving_the_Classification b/code/end_to_end_gee/03-Supervised-Classification/03a_Improving_the_Classification index 793be4af..37c8b838 100644 --- a/code/end_to_end_gee/03-Supervised-Classification/03a_Improving_the_Classification +++ b/code/end_to_end_gee/03-Supervised-Classification/03a_Improving_the_Classification @@ -20,10 +20,10 @@ var filtered = s2 .filter(ee.Filter.bounds(geometry)) .select('B.*'); -var composite = filtered.median().clip(geometry) +var composite = filtered.median(); // Display the input composite. -Map.addLayer(composite, rgbVis, 'image'); +Map.addLayer(composite.clip(geometry), rgbVis, 'image'); // Add a random column and split the GCPs into training and validation set @@ -55,7 +55,7 @@ var classifier = ee.Classifier.smileRandomForest(50) var classified = composite.classify(classifier); var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; -Map.addLayer(classified, {min: 0, max: 3, palette: palette}, '2019'); +Map.addLayer(classified.clip(geometry), {min: 0, max: 3, palette: palette}, '2019'); //************************************************************************** // Accuracy Assessment diff --git a/code/end_to_end_gee/03-Supervised-Classification/03b_Improving_the_Classification_(complete) b/code/end_to_end_gee/03-Supervised-Classification/03b_Improving_the_Classification_(complete) index 29b3ba71..cec7e292 100644 --- a/code/end_to_end_gee/03-Supervised-Classification/03b_Improving_the_Classification_(complete) +++ b/code/end_to_end_gee/03-Supervised-Classification/03b_Improving_the_Classification_(complete) @@ -35,7 +35,7 @@ var filtered = s2 .map(maskCloudAndShadowsSR) .select('B.*'); -var composite = filtered.median().clip(geometry); +var composite = filtered.median(); var addIndices = function(image) { @@ -62,7 +62,7 @@ var slope = ee.Terrain.slope(alos.select('AVE_DSM')).rename('slope'); var composite = composite.addBands(elev).addBands(slope); var visParams = {bands: ['B4', 'B3', 'B2'], min: 0, max: 3000, gamma: 1.2}; -Map.addLayer(composite, visParams, 'RGB'); +Map.addLayer(composite.clip(geometry), visParams, 'RGB'); // Normalize the image @@ -130,7 +130,7 @@ var classifier = ee.Classifier.smileRandomForest(50) var classified = composite.classify(classifier); var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; -Map.addLayer(classified, {min: 0, max: 3, palette: palette}, '2019'); +Map.addLayer(classified.clip(geometry), {min: 0, max: 3, palette: palette}, '2019'); //************************************************************************** // Accuracy Assessment diff --git a/code/end_to_end_gee/03-Supervised-Classification/04a_Exporting_Classification_Results b/code/end_to_end_gee/03-Supervised-Classification/04a_Exporting_Classification_Results index d9a39441..7c6cdce0 100644 --- a/code/end_to_end_gee/03-Supervised-Classification/04a_Exporting_Classification_Results +++ b/code/end_to_end_gee/03-Supervised-Classification/04a_Exporting_Classification_Results @@ -34,7 +34,7 @@ var filtered = s2 .map(maskCloudAndShadowsSR) .select('B.*'); -var composite = filtered.median().clip(geometry) ; +var composite = filtered.median(); var addIndices = function(image) { var ndvi = image.normalizedDifference(['B8', 'B4']).rename(['ndvi']); @@ -60,7 +60,7 @@ var slope = ee.Terrain.slope(alos.select('AVE_DSM')).rename('slope'); var composite = composite.addBands(elev).addBands(slope); var visParams = {bands: ['B4', 'B3', 'B2'], min: 0, max: 3000, gamma: 1.2}; -Map.addLayer(composite, visParams, 'RGB'); +Map.addLayer(composite.clip(geometry), visParams, 'RGB'); // Normalize the image @@ -129,7 +129,7 @@ var classifier = ee.Classifier.smileRandomForest(50) var classified = composite.classify(classifier); var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; -Map.addLayer(classified, {min: 0, max: 3, palette: palette}, '2019'); +Map.addLayer(classified.clip(geometry), {min: 0, max: 3, palette: palette}, '2019'); //************************************************************************** // Accuracy Assessment //************************************************************************** diff --git a/code/end_to_end_gee/03-Supervised-Classification/04b_Exporting_Classification_Results_(complete) b/code/end_to_end_gee/03-Supervised-Classification/04b_Exporting_Classification_Results_(complete) index 995ebdac..a62298de 100644 --- a/code/end_to_end_gee/03-Supervised-Classification/04b_Exporting_Classification_Results_(complete) +++ b/code/end_to_end_gee/03-Supervised-Classification/04b_Exporting_Classification_Results_(complete) @@ -34,7 +34,7 @@ var filtered = s2 .map(maskCloudAndShadowsSR) .select('B.*'); -var composite = filtered.median().clip(geometry) ; +var composite = filtered.median(); var addIndices = function(image) { var ndvi = image.normalizedDifference(['B8', 'B4']).rename(['ndvi']); @@ -60,7 +60,7 @@ var slope = ee.Terrain.slope(alos.select('AVE_DSM')).rename('slope'); var composite = composite.addBands(elev).addBands(slope); var visParams = {bands: ['B4', 'B3', 'B2'], min: 0, max: 3000, gamma: 1.2}; -Map.addLayer(composite, visParams, 'RGB'); +Map.addLayer(composite.clip(geometry), visParams, 'RGB'); // Normalize the image @@ -129,7 +129,7 @@ var classifier = ee.Classifier.smileRandomForest(50) var classified = composite.classify(classifier); var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; -Map.addLayer(classified, {min: 0, max: 3, palette: palette}, '2019'); +Map.addLayer(classified.clip(geometry), {min: 0, max: 3, palette: palette}, '2019'); //************************************************************************** // Accuracy Assessment diff --git a/code/end_to_end_gee/03-Supervised-Classification/04c_Exporting_Classification_Results_(exercise) b/code/end_to_end_gee/03-Supervised-Classification/04c_Exporting_Classification_Results_(exercise) index 199b0c62..37fa0767 100644 --- a/code/end_to_end_gee/03-Supervised-Classification/04c_Exporting_Classification_Results_(exercise) +++ b/code/end_to_end_gee/03-Supervised-Classification/04c_Exporting_Classification_Results_(exercise) @@ -34,7 +34,7 @@ var filtered = s2 .map(maskCloudAndShadowsSR) .select('B.*'); -var composite = filtered.median().clip(geometry) ; +var composite = filtered.median(); var addIndices = function(image) { var ndvi = image.normalizedDifference(['B8', 'B4']).rename(['ndvi']); @@ -60,7 +60,7 @@ var slope = ee.Terrain.slope(alos.select('AVE_DSM')).rename('slope'); var composite = composite.addBands(elev).addBands(slope); var visParams = {bands: ['B4', 'B3', 'B2'], min: 0, max: 3000, gamma: 1.2}; -Map.addLayer(composite, visParams, 'RGB'); +Map.addLayer(composite.clip(geometry), visParams, 'RGB'); // Normalize the image @@ -129,7 +129,7 @@ var classifier = ee.Classifier.smileRandomForest(50) var classified = composite.classify(classifier); var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; -Map.addLayer(classified, {min: 0, max: 3, palette: palette}, '2019'); +Map.addLayer(classified.clip(geometry), {min: 0, max: 3, palette: palette}, '2019'); // Exercise // Use the Export.image.toAsset() function to export the diff --git a/code/end_to_end_gee/04-Change-Detection/03a_Classifying_Change b/code/end_to_end_gee/04-Change-Detection/03a_Classifying_Change index 96879db5..b28a249e 100644 --- a/code/end_to_end_gee/04-Change-Detection/03a_Classifying_Change +++ b/code/end_to_end_gee/04-Change-Detection/03a_Classifying_Change @@ -188,15 +188,15 @@ var filtered = s2 .map(maskS2clouds); -var image2019 = filtered.median().clip(geometry); +var image2019 = filtered.median(); // Display the input composite. -Map.addLayer(image2019, rgbVis, '2019'); +Map.addLayer(image2019.clip(geometry), rgbVis, '2019'); var filtered = s2 .filter(ee.Filter.date('2020-01-01', '2020-02-01')) .filter(ee.Filter.bounds(bangalore)) .map(maskS2clouds) -var image2020 = filtered.median().clip(geometry); +var image2020 = filtered.median(); -Map.addLayer(image2020, rgbVis, '2020'); +Map.addLayer(image2020.clip(geometry), rgbVis, '2020'); diff --git a/code/end_to_end_gee/04-Change-Detection/03b_Classifying_Change_(complete) b/code/end_to_end_gee/04-Change-Detection/03b_Classifying_Change_(complete) index 3112faea..6fd62eaa 100644 --- a/code/end_to_end_gee/04-Change-Detection/03b_Classifying_Change_(complete) +++ b/code/end_to_end_gee/04-Change-Detection/03b_Classifying_Change_(complete) @@ -29,18 +29,18 @@ var filtered = s2 .map(maskS2clouds); -var image2019 = filtered.median().clip(geometry); +var image2019 = filtered.median(); // Display the input composite. -Map.addLayer(image2019, rgbVis, '2019'); +Map.addLayer(image2019.clip(geometry), rgbVis, '2019'); var filtered = s2 .filter(ee.Filter.date('2020-01-01', '2020-02-01')) .filter(ee.Filter.bounds(bangalore)) .map(maskS2clouds); -var image2020 = filtered.median().clip(geometry); +var image2020 = filtered.median(); -Map.addLayer(image2020, rgbVis, '2020'); +Map.addLayer(image2020.clip(geometry), rgbVis, '2020'); var stackedImage = image2019.addBands(image2020); @@ -60,4 +60,4 @@ var classifier = ee.Classifier.smileRandomForest(50).train({ // Classify the image. var classified = stackedImage.classify(classifier); -Map.addLayer(classified, {min: 0, max: 1, palette: ['white', 'red']}, 'change'); +Map.addLayer(classified.clip(geometry), {min: 0, max: 1, palette: ['white', 'red']}, 'change'); diff --git a/code/end_to_end_gee/04-Change-Detection/03c_Classifying_Change_(exercise) b/code/end_to_end_gee/04-Change-Detection/03c_Classifying_Change_(exercise) index 695d48b4..1fb6a974 100644 --- a/code/end_to_end_gee/04-Change-Detection/03c_Classifying_Change_(exercise) +++ b/code/end_to_end_gee/04-Change-Detection/03c_Classifying_Change_(exercise) @@ -30,18 +30,18 @@ var filtered = s2 .map(maskS2clouds); -var image2019 = filtered.median().clip(geometry); +var image2019 = filtered.median(); // Display the input composite. -Map.addLayer(image2019, rgbVis, '2019'); +Map.addLayer(image2019.clip(geometry), rgbVis, '2019'); var filtered = s2 .filter(ee.Filter.date('2020-01-01', '2020-02-01')) .filter(ee.Filter.bounds(bangalore)) .map(maskS2clouds); -var image2020 = filtered.median().clip(geometry); +var image2020 = filtered.median(); -Map.addLayer(image2020, rgbVis, '2020'); +Map.addLayer(image2020.clip(geometry), rgbVis, '2020'); // Exercise @@ -74,4 +74,4 @@ var classifier = ee.Classifier.smileRandomForest(50).train({ // Classify the image. var classified = stackedImage.classify(classifier); -Map.addLayer(classified, {min: 0, max: 1, palette: ['white', 'red']}, 'change'); +Map.addLayer(classified.clip(geometry), {min: 0, max: 1, palette: ['white', 'red']}, 'change'); diff --git a/code/end_to_end_gee/04-Change-Detection/04a_Post_Classification_Comparison b/code/end_to_end_gee/04-Change-Detection/04a_Post_Classification_Comparison index 0d240883..3c29b017 100644 --- a/code/end_to_end_gee/04-Change-Detection/04a_Post_Classification_Comparison +++ b/code/end_to_end_gee/04-Change-Detection/04a_Post_Classification_Comparison @@ -249,10 +249,9 @@ var filtered = s2 .filter(ee.Filter.bounds(geometry)) .select('B.*'); - -var before = filtered.median().clip(geometry); +var before = filtered.median(); // Display the input composite. -Map.addLayer(before, rgbVis, 'before'); +Map.addLayer(before.clip(geometry), rgbVis, 'before'); var training = urban.merge(bare).merge(water).merge(vegetation); @@ -274,7 +273,7 @@ var classifier = ee.Classifier.smileRandomForest(50).train({ var beforeClassified = before.classify(classifier); var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; var classifiedVis = {min: 0, max: 3, palette: palette}; -Map.addLayer(beforeClassified, classifiedVis, 'before_classified'); +Map.addLayer(beforeClassified.clip(geometry), classifiedVis, 'before_classified'); // 2020 Jan @@ -282,13 +281,12 @@ var after = s2 .filter(ee.Filter.date('2020-01-01', '2020-02-01')) .filter(ee.Filter.bounds(geometry)) .select('B.*') - .median() - .clip(geometry); - + .median(); + Map.addLayer(after, rgbVis, 'after'); // Classify the image. var afterClassified= after.classify(classifier); -Map.addLayer(afterClassified, classifiedVis, 'after_classified'); +Map.addLayer(afterClassified.clip(geometry), classifiedVis, 'after_classified'); diff --git a/code/end_to_end_gee/04-Change-Detection/04b_Post_Classification_Comparison_(complete) b/code/end_to_end_gee/04-Change-Detection/04b_Post_Classification_Comparison_(complete) index 17df822f..b10fefe9 100644 --- a/code/end_to_end_gee/04-Change-Detection/04b_Post_Classification_Comparison_(complete) +++ b/code/end_to_end_gee/04-Change-Detection/04b_Post_Classification_Comparison_(complete) @@ -23,7 +23,7 @@ var filtered = s2 var before = filtered.median().clip(geometry); // Display the input composite. -Map.addLayer(before, rgbVis, 'before'); +Map.addLayer(before.clip(geometry), rgbVis, 'before'); var training = urban.merge(bare).merge(water).merge(vegetation); @@ -45,21 +45,20 @@ var classifier = ee.Classifier.smileRandomForest(50).train({ var beforeClassified = before.classify(classifier); var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; var classifiedVis = {min: 0, max: 3, palette: palette}; -Map.addLayer(beforeClassified, classifiedVis, 'before_classified'); +Map.addLayer(beforeClassified.clip(geometry), classifiedVis, 'before_classified'); // 2020 Jan var after = s2 .filter(ee.Filter.date('2020-01-01', '2020-02-01')) .filter(ee.Filter.bounds(geometry)) .select('B.*') - .median() - .clip(geometry); + .median(); -Map.addLayer(after, rgbVis, 'after'); +Map.addLayer(after.clip(geometry), rgbVis, 'after'); // Classify the image. var afterClassified= after.classify(classifier); -Map.addLayer(afterClassified, classifiedVis, 'after_classified'); +Map.addLayer(afterClassified.clip(geometry), classifiedVis, 'after_classified'); // Reclassify from 0-3 to 1-4 @@ -68,7 +67,7 @@ var afterClasses = afterClassified.remap([0, 1, 2, 3], [1, 2, 3, 4]); // Show all changed areas var changed = afterClasses.subtract(beforeClasses).neq(0); -Map.addLayer(changed, {min:0, max:1, palette: ['white', 'red']}, 'Change'); +Map.addLayer(changed.clip(geometry), {min:0, max:1, palette: ['white', 'red']}, 'Change'); // We multiply the before image with 100 and add the after image // The resulting pixel values will be unique and will represent each unique transition diff --git a/code/end_to_end_gee/04-Change-Detection/04c_Post_Classification_Comparison_(exercise) b/code/end_to_end_gee/04-Change-Detection/04c_Post_Classification_Comparison_(exercise) index 7fd46931..1510b37f 100644 --- a/code/end_to_end_gee/04-Change-Detection/04c_Post_Classification_Comparison_(exercise) +++ b/code/end_to_end_gee/04-Change-Detection/04c_Post_Classification_Comparison_(exercise) @@ -22,9 +22,9 @@ var filtered = s2 .select('B.*'); -var before = filtered.median().clip(geometry); +var before = filtered.median(); // Display the input composite. -Map.addLayer(before, rgbVis, 'before'); +Map.addLayer(before.clip(geometry), rgbVis, 'before'); var training = urban.merge(bare).merge(water).merge(vegetation); @@ -47,7 +47,7 @@ var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; var classifiedVis = {min: 0, max: 3, palette: palette}; var beforeClassified= before.classify(classifier); -Map.addLayer(beforeClassified, classifiedVis, 'before_classified'); +Map.addLayer(beforeClassified.clip(geometry), classifiedVis, 'before_classified'); // 2020 Jan @@ -56,14 +56,13 @@ var after = s2 .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 30)) .filter(ee.Filter.bounds(geometry)) .select('B.*') - .median() - .clip(geometry); - + .median(); + Map.addLayer(after, rgbVis, 'after'); // Classify the image. var afterClassified= after.classify(classifier); -Map.addLayer(afterClassified, classifiedVis, 'after_classified'); +Map.addLayer(afterClassified.clip(geometry), classifiedVis, 'after_classified'); // Reclassify from 0-3 to 1-4 var beforeClasses = beforeClassified.remap([0, 1, 2, 3], [1, 2, 3, 4]); diff --git a/code/end_to_end_gee/05-Earth-Engine-Apps/05a_Split_Panel_App b/code/end_to_end_gee/05-Earth-Engine-Apps/05a_Split_Panel_App index b49e090f..b70e07dd 100644 --- a/code/end_to_end_gee/05-Earth-Engine-Apps/05a_Split_Panel_App +++ b/code/end_to_end_gee/05-Earth-Engine-Apps/05a_Split_Panel_App @@ -5,7 +5,7 @@ var selected = admin2 var geometry = selected.geometry(); Map.centerObject(geometry) -var s2 = ee.ImageCollection("COPERNICUS/S2"); +var s2 = ee.ImageCollection("COPERNICUS/S2_HARMONIZED"); // Write a function for Cloud masking var maskS2clouds = function(image) { diff --git a/code/end_to_end_gee/05-Earth-Engine-Apps/05b_Split_Panel_App_(complete) b/code/end_to_end_gee/05-Earth-Engine-Apps/05b_Split_Panel_App_(complete) index f67a5178..7a60cb82 100644 --- a/code/end_to_end_gee/05-Earth-Engine-Apps/05b_Split_Panel_App_(complete) +++ b/code/end_to_end_gee/05-Earth-Engine-Apps/05b_Split_Panel_App_(complete) @@ -5,7 +5,7 @@ var selected = admin2 var geometry = selected.geometry(); Map.centerObject(geometry) -var s2 = ee.ImageCollection("COPERNICUS/S2"); +var s2 = ee.ImageCollection("COPERNICUS/S2_HARMONIZED"); // Write a function for Cloud masking var maskS2clouds = function(image) { diff --git a/code/end_to_end_gee/05-Earth-Engine-Apps/05c_Split_Panel_App_(exercise) b/code/end_to_end_gee/05-Earth-Engine-Apps/05c_Split_Panel_App_(exercise) index 5754973a..9a93bd0c 100644 --- a/code/end_to_end_gee/05-Earth-Engine-Apps/05c_Split_Panel_App_(exercise) +++ b/code/end_to_end_gee/05-Earth-Engine-Apps/05c_Split_Panel_App_(exercise) @@ -5,7 +5,7 @@ var selected = admin2 var geometry = selected.geometry(); Map.centerObject(geometry) -var s2 = ee.ImageCollection("COPERNICUS/S2"); +var s2 = ee.ImageCollection("COPERNICUS/S2_HARMONIZED"); // Write a function for Cloud masking var maskS2clouds = function(image) { diff --git a/code/end_to_end_gee/Supplement/Image_Collections/Filter_by_Cloud_Cover_In_Region b/code/end_to_end_gee/Supplement/Image_Collections/Filter_by_Cloud_Cover_In_Region new file mode 100644 index 00000000..72759536 --- /dev/null +++ b/code/end_to_end_gee/Supplement/Image_Collections/Filter_by_Cloud_Cover_In_Region @@ -0,0 +1,75 @@ +var geometry = ee.Geometry.Polygon([[ + [77.4783, 13.0848], + [77.4783, 12.8198], + [77.7502, 12.8198], + [77.7502, 13.0848]] +]); + +var s2 = ee.ImageCollection('COPERNICUS/S2_HARMONIZED'); + +Map.addLayer(geometry, {color: 'red'}, 'Selected Region'); +Map.centerObject(geometry); + +var filtered = s2 + .filter(ee.Filter.date('2019-01-01', '2020-01-01')) + .filter(ee.Filter.bounds(geometry)); + +// Write a function for Cloud masking +function maskS2clouds(image) { + var qa = image.select('QA60'); + var cloudBitMask = 1 << 10; + var cirrusBitMask = 1 << 11; + var mask = qa.bitwiseAnd(cloudBitMask).eq(0).and( + qa.bitwiseAnd(cirrusBitMask).eq(0)); + return image.updateMask(mask) + .select('B.*') + .copyProperties(image, ['system:time_start']); +} + +print('Total images', filtered.size()); + +// Add a function that adds a property to each image +// with the cloud cover in the chosen geometry +var calculateCloudCover = function(image) { + // Apply the cloud mask function + var maskedImage = ee.Image(maskS2clouds(image)); + // The image now has some pixels that are masked + // We count the number of unmasked pixels + // Select any band, since all bands have the same mask + // Working with a single band maes the analysis simpler + var bandName = 'B1'; + var band = maskedImage.select(bandName); + var withMaskStats = band.reduceRegion({ + reducer: ee.Reducer.count(), + geometry: geometry, + scale: 10 + }); + var cloudFreePixels = withMaskStats.getNumber(bandName); + + // Remove the mask and count all pixels + var withoutMaskStats = band.unmask(0).reduceRegion({ + reducer: ee.Reducer.count(), + geometry: geometry, + scale: 10 + }); + + var totalPixels = withoutMaskStats.getNumber('B1'); + + var cloudCoverPercentage = ee.Number.expression( + '100*(totalPixels-cloudFreePixels)/totalPixels', { + totalPixels: totalPixels, + cloudFreePixels: cloudFreePixels + }); + return image.set({ + 'CLOUDY_PIXEL_PERCENTAGE_REGION': cloudCoverPercentage + }); +}; + +var filteredWithCount = filtered.map(calculateCloudCover); + +print(filteredWithCount.first()); + +// Filter using the newly created property +var cloudFreeImages = filteredWithCount + .filter(ee.Filter.eq('CLOUDY_PIXEL_PERCENTAGE_REGION', 0)); +print('Cloud Free Images in Region', cloudFreeImages.size()); diff --git a/docs/code/end_to_end_gee/02-Earth-Engine-Intermediate/03b_Computation_on_Image_Collections_(complete) b/docs/code/end_to_end_gee/02-Earth-Engine-Intermediate/03b_Computation_on_Image_Collections_(complete) index 14d6d484..f838863f 100644 --- a/docs/code/end_to_end_gee/02-Earth-Engine-Intermediate/03b_Computation_on_Image_Collections_(complete) +++ b/docs/code/end_to_end_gee/02-Earth-Engine-Intermediate/03b_Computation_on_Image_Collections_(complete) @@ -24,7 +24,7 @@ var withNdvi = filtered.map(addNDVI); var composite = withNdvi.median(); -var ndviComposite = composite.select('ndvi').clip(geometry); +var ndviComposite = composite.select('ndvi'); var palette = [ 'FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163', '99B718', @@ -32,4 +32,4 @@ var palette = [ '004C00', '023B01', '012E01', '011D01', '011301']; var ndviVis = {min:0, max:0.5, palette: palette }; -Map.addLayer(ndviComposite, ndviVis, 'ndvi'); +Map.addLayer(ndviComposite.clip(geometry), ndviVis, 'ndvi'); diff --git a/docs/code/end_to_end_gee/02-Earth-Engine-Intermediate/03c_Computation_on_Image_Collections_(exercise) b/docs/code/end_to_end_gee/02-Earth-Engine-Intermediate/03c_Computation_on_Image_Collections_(exercise) index 740b924c..28911c1a 100644 --- a/docs/code/end_to_end_gee/02-Earth-Engine-Intermediate/03c_Computation_on_Image_Collections_(exercise) +++ b/docs/code/end_to_end_gee/02-Earth-Engine-Intermediate/03c_Computation_on_Image_Collections_(exercise) @@ -25,10 +25,11 @@ function addIndices(image) { var withIndices = filtered.map(addIndices); // Composite -var composite = withIndices.median().clip(geometry); +var composite = withIndices.median(); print(composite); -// Extract the 'ndwi' band and display a NDWI map +// Extract the 'ndwi' band +// Clip and display a NDWI map // use the palette ['white', 'blue'] // Hint: Use .select() function to select a band diff --git a/docs/code/end_to_end_gee/03-Supervised-Classification/01b_Basic_Supervised_Classification_(complete) b/docs/code/end_to_end_gee/03-Supervised-Classification/01b_Basic_Supervised_Classification_(complete) index e4f706de..bd26c407 100644 --- a/docs/code/end_to_end_gee/03-Supervised-Classification/01b_Basic_Supervised_Classification_(complete) +++ b/docs/code/end_to_end_gee/03-Supervised-Classification/01b_Basic_Supervised_Classification_(complete) @@ -229,10 +229,10 @@ var filtered = s2 .filter(ee.Filter.bounds(geometry)) .select('B.*'); -var composite = filtered.median().clip(geometry) ; +var composite = filtered.median(); // Display the input composite. -Map.addLayer(composite, rgbVis, 'image'); +Map.addLayer(composite.clip(geometry), rgbVis, 'image'); var gcps = urban.merge(bare).merge(water).merge(vegetation); @@ -258,6 +258,6 @@ Map.centerObject(geometry); // Urban, Bare, Water, Vegetation var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; -Map.addLayer(classified, {min: 0, max: 3, palette: palette}, '2019'); +Map.addLayer(classified.clip(geometry), {min: 0, max: 3, palette: palette}, '2019'); diff --git a/docs/code/end_to_end_gee/03-Supervised-Classification/01c_Basic_Supervised_Classification_(exercise) b/docs/code/end_to_end_gee/03-Supervised-Classification/01c_Basic_Supervised_Classification_(exercise) index a80aabf7..f1afdb62 100644 --- a/docs/code/end_to_end_gee/03-Supervised-Classification/01c_Basic_Supervised_Classification_(exercise) +++ b/docs/code/end_to_end_gee/03-Supervised-Classification/01c_Basic_Supervised_Classification_(exercise) @@ -16,12 +16,12 @@ var filtered = s2 .filter(ee.Filter.bounds(geometry)) .select('B.*'); -var composite = filtered.median().clip(geometry); +var composite = filtered.median(); // Display the input composite. var rgbVis = {min: 0.0, max: 3000, bands: ['B4', 'B3', 'B2']}; -Map.addLayer(composite, rgbVis, 'image'); +Map.addLayer(composite.clip(geometry), rgbVis, 'image'); // Exercise // Add training points for 4 classes @@ -60,6 +60,6 @@ Map.addLayer(composite, rgbVis, 'image'); // // Urban, Bare, Water, Vegetation // var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; -// Map.addLayer(classified, {min: 0, max: 3, palette: palette}, '2019'); +// Map.addLayer(classified.clip(geometry), {min: 0, max: 3, palette: palette}, '2019'); diff --git a/docs/code/end_to_end_gee/03-Supervised-Classification/01d_Basic_Supervised_Classification_(noimport) b/docs/code/end_to_end_gee/03-Supervised-Classification/01d_Basic_Supervised_Classification_(noimport) index 625e958f..a0399a8e 100644 --- a/docs/code/end_to_end_gee/03-Supervised-Classification/01d_Basic_Supervised_Classification_(noimport) +++ b/docs/code/end_to_end_gee/03-Supervised-Classification/01d_Basic_Supervised_Classification_(noimport) @@ -15,7 +15,7 @@ var filtered = s2 .filter(ee.Filter.bounds(geometry)) .select('B.*'); -var composite = filtered.median().clip(geometry); +var composite = filtered.median(); // Display the input composite. var rgbVis = { @@ -23,7 +23,7 @@ var rgbVis = { max: 3000, bands: ['B4', 'B3', 'B2'], }; -Map.addLayer(composite, rgbVis, 'image'); +Map.addLayer(composite.clip(geometry), rgbVis, 'image'); var gcps = urban.merge(bare).merge(water).merge(vegetation); @@ -48,7 +48,7 @@ var classified = composite.classify(classifier); // Urban, Bare, Water, Vegetation var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; -Map.addLayer(classified, {min: 0, max: 3, palette: palette}, '2019'); +Map.addLayer(classified.clip(geometry), {min: 0, max: 3, palette: palette}, '2019'); // Display the GCPs // We use the style() function to style the GCPs var palette = ee.List(palette); diff --git a/docs/code/end_to_end_gee/03-Supervised-Classification/02a_Accuracy_Assessment b/docs/code/end_to_end_gee/03-Supervised-Classification/02a_Accuracy_Assessment index 3ee38ce6..65cfcaee 100644 --- a/docs/code/end_to_end_gee/03-Supervised-Classification/02a_Accuracy_Assessment +++ b/docs/code/end_to_end_gee/03-Supervised-Classification/02a_Accuracy_Assessment @@ -19,10 +19,10 @@ var filtered = s2 .filter(ee.Filter.bounds(geometry)) .select('B.*'); -var composite = filtered.median().clip(geometry); +var composite = filtered.median(); // Display the input composite. -Map.addLayer(composite, rgbVis, 'image'); +Map.addLayer(composite.clip(geometry), rgbVis, 'image'); // Overlay the point on the image to get training data. @@ -44,4 +44,4 @@ var classifier = ee.Classifier.smileRandomForest(50) var classified = composite.classify(classifier); var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; -Map.addLayer(classified, {min: 0, max: 3, palette: palette}, '2019'); \ No newline at end of file +Map.addLayer(classified.clip(geometry), {min: 0, max: 3, palette: palette}, '2019'); \ No newline at end of file diff --git a/docs/code/end_to_end_gee/03-Supervised-Classification/02b_Accuracy_Assessment_(complete) b/docs/code/end_to_end_gee/03-Supervised-Classification/02b_Accuracy_Assessment_(complete) index 6e35c908..49790ef2 100644 --- a/docs/code/end_to_end_gee/03-Supervised-Classification/02b_Accuracy_Assessment_(complete) +++ b/docs/code/end_to_end_gee/03-Supervised-Classification/02b_Accuracy_Assessment_(complete) @@ -18,10 +18,10 @@ var filtered = s2 .filter(ee.Filter.bounds(geometry)) .select('B.*'); -var composite = filtered.median().clip(geometry); +var composite = filtered.median(); // Display the input composite. -Map.addLayer(composite, rgbVis, 'image'); +Map.addLayer(composite.clip(geometry), rgbVis, 'image'); // Add a random column and split the GCPs into training and validation set @@ -53,7 +53,7 @@ var classifier = ee.Classifier.smileRandomForest(50) var classified = composite.classify(classifier); var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; -Map.addLayer(classified, {min: 0, max: 3, palette: palette}, '2019'); +Map.addLayer(classified.clip(geometry), {min: 0, max: 3, palette: palette}, '2019'); //************************************************************************** // Accuracy Assessment //************************************************************************** diff --git a/docs/code/end_to_end_gee/03-Supervised-Classification/03a_Improving_the_Classification b/docs/code/end_to_end_gee/03-Supervised-Classification/03a_Improving_the_Classification index 793be4af..37c8b838 100644 --- a/docs/code/end_to_end_gee/03-Supervised-Classification/03a_Improving_the_Classification +++ b/docs/code/end_to_end_gee/03-Supervised-Classification/03a_Improving_the_Classification @@ -20,10 +20,10 @@ var filtered = s2 .filter(ee.Filter.bounds(geometry)) .select('B.*'); -var composite = filtered.median().clip(geometry) +var composite = filtered.median(); // Display the input composite. -Map.addLayer(composite, rgbVis, 'image'); +Map.addLayer(composite.clip(geometry), rgbVis, 'image'); // Add a random column and split the GCPs into training and validation set @@ -55,7 +55,7 @@ var classifier = ee.Classifier.smileRandomForest(50) var classified = composite.classify(classifier); var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; -Map.addLayer(classified, {min: 0, max: 3, palette: palette}, '2019'); +Map.addLayer(classified.clip(geometry), {min: 0, max: 3, palette: palette}, '2019'); //************************************************************************** // Accuracy Assessment diff --git a/docs/code/end_to_end_gee/03-Supervised-Classification/03b_Improving_the_Classification_(complete) b/docs/code/end_to_end_gee/03-Supervised-Classification/03b_Improving_the_Classification_(complete) index 29b3ba71..cec7e292 100644 --- a/docs/code/end_to_end_gee/03-Supervised-Classification/03b_Improving_the_Classification_(complete) +++ b/docs/code/end_to_end_gee/03-Supervised-Classification/03b_Improving_the_Classification_(complete) @@ -35,7 +35,7 @@ var filtered = s2 .map(maskCloudAndShadowsSR) .select('B.*'); -var composite = filtered.median().clip(geometry); +var composite = filtered.median(); var addIndices = function(image) { @@ -62,7 +62,7 @@ var slope = ee.Terrain.slope(alos.select('AVE_DSM')).rename('slope'); var composite = composite.addBands(elev).addBands(slope); var visParams = {bands: ['B4', 'B3', 'B2'], min: 0, max: 3000, gamma: 1.2}; -Map.addLayer(composite, visParams, 'RGB'); +Map.addLayer(composite.clip(geometry), visParams, 'RGB'); // Normalize the image @@ -130,7 +130,7 @@ var classifier = ee.Classifier.smileRandomForest(50) var classified = composite.classify(classifier); var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; -Map.addLayer(classified, {min: 0, max: 3, palette: palette}, '2019'); +Map.addLayer(classified.clip(geometry), {min: 0, max: 3, palette: palette}, '2019'); //************************************************************************** // Accuracy Assessment diff --git a/docs/code/end_to_end_gee/03-Supervised-Classification/04a_Exporting_Classification_Results b/docs/code/end_to_end_gee/03-Supervised-Classification/04a_Exporting_Classification_Results index d9a39441..7c6cdce0 100644 --- a/docs/code/end_to_end_gee/03-Supervised-Classification/04a_Exporting_Classification_Results +++ b/docs/code/end_to_end_gee/03-Supervised-Classification/04a_Exporting_Classification_Results @@ -34,7 +34,7 @@ var filtered = s2 .map(maskCloudAndShadowsSR) .select('B.*'); -var composite = filtered.median().clip(geometry) ; +var composite = filtered.median(); var addIndices = function(image) { var ndvi = image.normalizedDifference(['B8', 'B4']).rename(['ndvi']); @@ -60,7 +60,7 @@ var slope = ee.Terrain.slope(alos.select('AVE_DSM')).rename('slope'); var composite = composite.addBands(elev).addBands(slope); var visParams = {bands: ['B4', 'B3', 'B2'], min: 0, max: 3000, gamma: 1.2}; -Map.addLayer(composite, visParams, 'RGB'); +Map.addLayer(composite.clip(geometry), visParams, 'RGB'); // Normalize the image @@ -129,7 +129,7 @@ var classifier = ee.Classifier.smileRandomForest(50) var classified = composite.classify(classifier); var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; -Map.addLayer(classified, {min: 0, max: 3, palette: palette}, '2019'); +Map.addLayer(classified.clip(geometry), {min: 0, max: 3, palette: palette}, '2019'); //************************************************************************** // Accuracy Assessment //************************************************************************** diff --git a/docs/code/end_to_end_gee/03-Supervised-Classification/04b_Exporting_Classification_Results_(complete) b/docs/code/end_to_end_gee/03-Supervised-Classification/04b_Exporting_Classification_Results_(complete) index 995ebdac..a62298de 100644 --- a/docs/code/end_to_end_gee/03-Supervised-Classification/04b_Exporting_Classification_Results_(complete) +++ b/docs/code/end_to_end_gee/03-Supervised-Classification/04b_Exporting_Classification_Results_(complete) @@ -34,7 +34,7 @@ var filtered = s2 .map(maskCloudAndShadowsSR) .select('B.*'); -var composite = filtered.median().clip(geometry) ; +var composite = filtered.median(); var addIndices = function(image) { var ndvi = image.normalizedDifference(['B8', 'B4']).rename(['ndvi']); @@ -60,7 +60,7 @@ var slope = ee.Terrain.slope(alos.select('AVE_DSM')).rename('slope'); var composite = composite.addBands(elev).addBands(slope); var visParams = {bands: ['B4', 'B3', 'B2'], min: 0, max: 3000, gamma: 1.2}; -Map.addLayer(composite, visParams, 'RGB'); +Map.addLayer(composite.clip(geometry), visParams, 'RGB'); // Normalize the image @@ -129,7 +129,7 @@ var classifier = ee.Classifier.smileRandomForest(50) var classified = composite.classify(classifier); var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; -Map.addLayer(classified, {min: 0, max: 3, palette: palette}, '2019'); +Map.addLayer(classified.clip(geometry), {min: 0, max: 3, palette: palette}, '2019'); //************************************************************************** // Accuracy Assessment diff --git a/docs/code/end_to_end_gee/03-Supervised-Classification/04c_Exporting_Classification_Results_(exercise) b/docs/code/end_to_end_gee/03-Supervised-Classification/04c_Exporting_Classification_Results_(exercise) index 199b0c62..37fa0767 100644 --- a/docs/code/end_to_end_gee/03-Supervised-Classification/04c_Exporting_Classification_Results_(exercise) +++ b/docs/code/end_to_end_gee/03-Supervised-Classification/04c_Exporting_Classification_Results_(exercise) @@ -34,7 +34,7 @@ var filtered = s2 .map(maskCloudAndShadowsSR) .select('B.*'); -var composite = filtered.median().clip(geometry) ; +var composite = filtered.median(); var addIndices = function(image) { var ndvi = image.normalizedDifference(['B8', 'B4']).rename(['ndvi']); @@ -60,7 +60,7 @@ var slope = ee.Terrain.slope(alos.select('AVE_DSM')).rename('slope'); var composite = composite.addBands(elev).addBands(slope); var visParams = {bands: ['B4', 'B3', 'B2'], min: 0, max: 3000, gamma: 1.2}; -Map.addLayer(composite, visParams, 'RGB'); +Map.addLayer(composite.clip(geometry), visParams, 'RGB'); // Normalize the image @@ -129,7 +129,7 @@ var classifier = ee.Classifier.smileRandomForest(50) var classified = composite.classify(classifier); var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; -Map.addLayer(classified, {min: 0, max: 3, palette: palette}, '2019'); +Map.addLayer(classified.clip(geometry), {min: 0, max: 3, palette: palette}, '2019'); // Exercise // Use the Export.image.toAsset() function to export the diff --git a/docs/code/end_to_end_gee/04-Change-Detection/03a_Classifying_Change b/docs/code/end_to_end_gee/04-Change-Detection/03a_Classifying_Change index 96879db5..b28a249e 100644 --- a/docs/code/end_to_end_gee/04-Change-Detection/03a_Classifying_Change +++ b/docs/code/end_to_end_gee/04-Change-Detection/03a_Classifying_Change @@ -188,15 +188,15 @@ var filtered = s2 .map(maskS2clouds); -var image2019 = filtered.median().clip(geometry); +var image2019 = filtered.median(); // Display the input composite. -Map.addLayer(image2019, rgbVis, '2019'); +Map.addLayer(image2019.clip(geometry), rgbVis, '2019'); var filtered = s2 .filter(ee.Filter.date('2020-01-01', '2020-02-01')) .filter(ee.Filter.bounds(bangalore)) .map(maskS2clouds) -var image2020 = filtered.median().clip(geometry); +var image2020 = filtered.median(); -Map.addLayer(image2020, rgbVis, '2020'); +Map.addLayer(image2020.clip(geometry), rgbVis, '2020'); diff --git a/docs/code/end_to_end_gee/04-Change-Detection/03b_Classifying_Change_(complete) b/docs/code/end_to_end_gee/04-Change-Detection/03b_Classifying_Change_(complete) index 3112faea..6fd62eaa 100644 --- a/docs/code/end_to_end_gee/04-Change-Detection/03b_Classifying_Change_(complete) +++ b/docs/code/end_to_end_gee/04-Change-Detection/03b_Classifying_Change_(complete) @@ -29,18 +29,18 @@ var filtered = s2 .map(maskS2clouds); -var image2019 = filtered.median().clip(geometry); +var image2019 = filtered.median(); // Display the input composite. -Map.addLayer(image2019, rgbVis, '2019'); +Map.addLayer(image2019.clip(geometry), rgbVis, '2019'); var filtered = s2 .filter(ee.Filter.date('2020-01-01', '2020-02-01')) .filter(ee.Filter.bounds(bangalore)) .map(maskS2clouds); -var image2020 = filtered.median().clip(geometry); +var image2020 = filtered.median(); -Map.addLayer(image2020, rgbVis, '2020'); +Map.addLayer(image2020.clip(geometry), rgbVis, '2020'); var stackedImage = image2019.addBands(image2020); @@ -60,4 +60,4 @@ var classifier = ee.Classifier.smileRandomForest(50).train({ // Classify the image. var classified = stackedImage.classify(classifier); -Map.addLayer(classified, {min: 0, max: 1, palette: ['white', 'red']}, 'change'); +Map.addLayer(classified.clip(geometry), {min: 0, max: 1, palette: ['white', 'red']}, 'change'); diff --git a/docs/code/end_to_end_gee/04-Change-Detection/03c_Classifying_Change_(exercise) b/docs/code/end_to_end_gee/04-Change-Detection/03c_Classifying_Change_(exercise) index 695d48b4..1fb6a974 100644 --- a/docs/code/end_to_end_gee/04-Change-Detection/03c_Classifying_Change_(exercise) +++ b/docs/code/end_to_end_gee/04-Change-Detection/03c_Classifying_Change_(exercise) @@ -30,18 +30,18 @@ var filtered = s2 .map(maskS2clouds); -var image2019 = filtered.median().clip(geometry); +var image2019 = filtered.median(); // Display the input composite. -Map.addLayer(image2019, rgbVis, '2019'); +Map.addLayer(image2019.clip(geometry), rgbVis, '2019'); var filtered = s2 .filter(ee.Filter.date('2020-01-01', '2020-02-01')) .filter(ee.Filter.bounds(bangalore)) .map(maskS2clouds); -var image2020 = filtered.median().clip(geometry); +var image2020 = filtered.median(); -Map.addLayer(image2020, rgbVis, '2020'); +Map.addLayer(image2020.clip(geometry), rgbVis, '2020'); // Exercise @@ -74,4 +74,4 @@ var classifier = ee.Classifier.smileRandomForest(50).train({ // Classify the image. var classified = stackedImage.classify(classifier); -Map.addLayer(classified, {min: 0, max: 1, palette: ['white', 'red']}, 'change'); +Map.addLayer(classified.clip(geometry), {min: 0, max: 1, palette: ['white', 'red']}, 'change'); diff --git a/docs/code/end_to_end_gee/04-Change-Detection/04a_Post_Classification_Comparison b/docs/code/end_to_end_gee/04-Change-Detection/04a_Post_Classification_Comparison index 0d240883..3c29b017 100644 --- a/docs/code/end_to_end_gee/04-Change-Detection/04a_Post_Classification_Comparison +++ b/docs/code/end_to_end_gee/04-Change-Detection/04a_Post_Classification_Comparison @@ -249,10 +249,9 @@ var filtered = s2 .filter(ee.Filter.bounds(geometry)) .select('B.*'); - -var before = filtered.median().clip(geometry); +var before = filtered.median(); // Display the input composite. -Map.addLayer(before, rgbVis, 'before'); +Map.addLayer(before.clip(geometry), rgbVis, 'before'); var training = urban.merge(bare).merge(water).merge(vegetation); @@ -274,7 +273,7 @@ var classifier = ee.Classifier.smileRandomForest(50).train({ var beforeClassified = before.classify(classifier); var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; var classifiedVis = {min: 0, max: 3, palette: palette}; -Map.addLayer(beforeClassified, classifiedVis, 'before_classified'); +Map.addLayer(beforeClassified.clip(geometry), classifiedVis, 'before_classified'); // 2020 Jan @@ -282,13 +281,12 @@ var after = s2 .filter(ee.Filter.date('2020-01-01', '2020-02-01')) .filter(ee.Filter.bounds(geometry)) .select('B.*') - .median() - .clip(geometry); - + .median(); + Map.addLayer(after, rgbVis, 'after'); // Classify the image. var afterClassified= after.classify(classifier); -Map.addLayer(afterClassified, classifiedVis, 'after_classified'); +Map.addLayer(afterClassified.clip(geometry), classifiedVis, 'after_classified'); diff --git a/docs/code/end_to_end_gee/04-Change-Detection/04b_Post_Classification_Comparison_(complete) b/docs/code/end_to_end_gee/04-Change-Detection/04b_Post_Classification_Comparison_(complete) index 17df822f..b10fefe9 100644 --- a/docs/code/end_to_end_gee/04-Change-Detection/04b_Post_Classification_Comparison_(complete) +++ b/docs/code/end_to_end_gee/04-Change-Detection/04b_Post_Classification_Comparison_(complete) @@ -23,7 +23,7 @@ var filtered = s2 var before = filtered.median().clip(geometry); // Display the input composite. -Map.addLayer(before, rgbVis, 'before'); +Map.addLayer(before.clip(geometry), rgbVis, 'before'); var training = urban.merge(bare).merge(water).merge(vegetation); @@ -45,21 +45,20 @@ var classifier = ee.Classifier.smileRandomForest(50).train({ var beforeClassified = before.classify(classifier); var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; var classifiedVis = {min: 0, max: 3, palette: palette}; -Map.addLayer(beforeClassified, classifiedVis, 'before_classified'); +Map.addLayer(beforeClassified.clip(geometry), classifiedVis, 'before_classified'); // 2020 Jan var after = s2 .filter(ee.Filter.date('2020-01-01', '2020-02-01')) .filter(ee.Filter.bounds(geometry)) .select('B.*') - .median() - .clip(geometry); + .median(); -Map.addLayer(after, rgbVis, 'after'); +Map.addLayer(after.clip(geometry), rgbVis, 'after'); // Classify the image. var afterClassified= after.classify(classifier); -Map.addLayer(afterClassified, classifiedVis, 'after_classified'); +Map.addLayer(afterClassified.clip(geometry), classifiedVis, 'after_classified'); // Reclassify from 0-3 to 1-4 @@ -68,7 +67,7 @@ var afterClasses = afterClassified.remap([0, 1, 2, 3], [1, 2, 3, 4]); // Show all changed areas var changed = afterClasses.subtract(beforeClasses).neq(0); -Map.addLayer(changed, {min:0, max:1, palette: ['white', 'red']}, 'Change'); +Map.addLayer(changed.clip(geometry), {min:0, max:1, palette: ['white', 'red']}, 'Change'); // We multiply the before image with 100 and add the after image // The resulting pixel values will be unique and will represent each unique transition diff --git a/docs/code/end_to_end_gee/04-Change-Detection/04c_Post_Classification_Comparison_(exercise) b/docs/code/end_to_end_gee/04-Change-Detection/04c_Post_Classification_Comparison_(exercise) index 7fd46931..1510b37f 100644 --- a/docs/code/end_to_end_gee/04-Change-Detection/04c_Post_Classification_Comparison_(exercise) +++ b/docs/code/end_to_end_gee/04-Change-Detection/04c_Post_Classification_Comparison_(exercise) @@ -22,9 +22,9 @@ var filtered = s2 .select('B.*'); -var before = filtered.median().clip(geometry); +var before = filtered.median(); // Display the input composite. -Map.addLayer(before, rgbVis, 'before'); +Map.addLayer(before.clip(geometry), rgbVis, 'before'); var training = urban.merge(bare).merge(water).merge(vegetation); @@ -47,7 +47,7 @@ var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ]; var classifiedVis = {min: 0, max: 3, palette: palette}; var beforeClassified= before.classify(classifier); -Map.addLayer(beforeClassified, classifiedVis, 'before_classified'); +Map.addLayer(beforeClassified.clip(geometry), classifiedVis, 'before_classified'); // 2020 Jan @@ -56,14 +56,13 @@ var after = s2 .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 30)) .filter(ee.Filter.bounds(geometry)) .select('B.*') - .median() - .clip(geometry); - + .median(); + Map.addLayer(after, rgbVis, 'after'); // Classify the image. var afterClassified= after.classify(classifier); -Map.addLayer(afterClassified, classifiedVis, 'after_classified'); +Map.addLayer(afterClassified.clip(geometry), classifiedVis, 'after_classified'); // Reclassify from 0-3 to 1-4 var beforeClasses = beforeClassified.remap([0, 1, 2, 3], [1, 2, 3, 4]); diff --git a/docs/code/end_to_end_gee/05-Earth-Engine-Apps/05a_Split_Panel_App b/docs/code/end_to_end_gee/05-Earth-Engine-Apps/05a_Split_Panel_App index b49e090f..b70e07dd 100644 --- a/docs/code/end_to_end_gee/05-Earth-Engine-Apps/05a_Split_Panel_App +++ b/docs/code/end_to_end_gee/05-Earth-Engine-Apps/05a_Split_Panel_App @@ -5,7 +5,7 @@ var selected = admin2 var geometry = selected.geometry(); Map.centerObject(geometry) -var s2 = ee.ImageCollection("COPERNICUS/S2"); +var s2 = ee.ImageCollection("COPERNICUS/S2_HARMONIZED"); // Write a function for Cloud masking var maskS2clouds = function(image) { diff --git a/docs/code/end_to_end_gee/05-Earth-Engine-Apps/05b_Split_Panel_App_(complete) b/docs/code/end_to_end_gee/05-Earth-Engine-Apps/05b_Split_Panel_App_(complete) index f67a5178..7a60cb82 100644 --- a/docs/code/end_to_end_gee/05-Earth-Engine-Apps/05b_Split_Panel_App_(complete) +++ b/docs/code/end_to_end_gee/05-Earth-Engine-Apps/05b_Split_Panel_App_(complete) @@ -5,7 +5,7 @@ var selected = admin2 var geometry = selected.geometry(); Map.centerObject(geometry) -var s2 = ee.ImageCollection("COPERNICUS/S2"); +var s2 = ee.ImageCollection("COPERNICUS/S2_HARMONIZED"); // Write a function for Cloud masking var maskS2clouds = function(image) { diff --git a/docs/code/end_to_end_gee/05-Earth-Engine-Apps/05c_Split_Panel_App_(exercise) b/docs/code/end_to_end_gee/05-Earth-Engine-Apps/05c_Split_Panel_App_(exercise) index 5754973a..9a93bd0c 100644 --- a/docs/code/end_to_end_gee/05-Earth-Engine-Apps/05c_Split_Panel_App_(exercise) +++ b/docs/code/end_to_end_gee/05-Earth-Engine-Apps/05c_Split_Panel_App_(exercise) @@ -5,7 +5,7 @@ var selected = admin2 var geometry = selected.geometry(); Map.centerObject(geometry) -var s2 = ee.ImageCollection("COPERNICUS/S2"); +var s2 = ee.ImageCollection("COPERNICUS/S2_HARMONIZED"); // Write a function for Cloud masking var maskS2clouds = function(image) { diff --git a/docs/code/end_to_end_gee/Supplement/Image_Collections/Filter_by_Cloud_Cover_In_Region b/docs/code/end_to_end_gee/Supplement/Image_Collections/Filter_by_Cloud_Cover_In_Region new file mode 100644 index 00000000..72759536 --- /dev/null +++ b/docs/code/end_to_end_gee/Supplement/Image_Collections/Filter_by_Cloud_Cover_In_Region @@ -0,0 +1,75 @@ +var geometry = ee.Geometry.Polygon([[ + [77.4783, 13.0848], + [77.4783, 12.8198], + [77.7502, 12.8198], + [77.7502, 13.0848]] +]); + +var s2 = ee.ImageCollection('COPERNICUS/S2_HARMONIZED'); + +Map.addLayer(geometry, {color: 'red'}, 'Selected Region'); +Map.centerObject(geometry); + +var filtered = s2 + .filter(ee.Filter.date('2019-01-01', '2020-01-01')) + .filter(ee.Filter.bounds(geometry)); + +// Write a function for Cloud masking +function maskS2clouds(image) { + var qa = image.select('QA60'); + var cloudBitMask = 1 << 10; + var cirrusBitMask = 1 << 11; + var mask = qa.bitwiseAnd(cloudBitMask).eq(0).and( + qa.bitwiseAnd(cirrusBitMask).eq(0)); + return image.updateMask(mask) + .select('B.*') + .copyProperties(image, ['system:time_start']); +} + +print('Total images', filtered.size()); + +// Add a function that adds a property to each image +// with the cloud cover in the chosen geometry +var calculateCloudCover = function(image) { + // Apply the cloud mask function + var maskedImage = ee.Image(maskS2clouds(image)); + // The image now has some pixels that are masked + // We count the number of unmasked pixels + // Select any band, since all bands have the same mask + // Working with a single band maes the analysis simpler + var bandName = 'B1'; + var band = maskedImage.select(bandName); + var withMaskStats = band.reduceRegion({ + reducer: ee.Reducer.count(), + geometry: geometry, + scale: 10 + }); + var cloudFreePixels = withMaskStats.getNumber(bandName); + + // Remove the mask and count all pixels + var withoutMaskStats = band.unmask(0).reduceRegion({ + reducer: ee.Reducer.count(), + geometry: geometry, + scale: 10 + }); + + var totalPixels = withoutMaskStats.getNumber('B1'); + + var cloudCoverPercentage = ee.Number.expression( + '100*(totalPixels-cloudFreePixels)/totalPixels', { + totalPixels: totalPixels, + cloudFreePixels: cloudFreePixels + }); + return image.set({ + 'CLOUDY_PIXEL_PERCENTAGE_REGION': cloudCoverPercentage + }); +}; + +var filteredWithCount = filtered.map(calculateCloudCover); + +print(filteredWithCount.first()); + +// Filter using the newly created property +var cloudFreeImages = filteredWithCount + .filter(ee.Filter.eq('CLOUDY_PIXEL_PERCENTAGE_REGION', 0)); +print('Cloud Free Images in Region', cloudFreeImages.size()); diff --git a/docs/end-to-end-gee-supplement.html b/docs/end-to-end-gee-supplement.html index 8a9f9615..3707afa8 100644 --- a/docs/end-to-end-gee-supplement.html +++ b/docs/end-to-end-gee-supplement.html @@ -427,6 +427,9 @@
This script shows how to calculate the cloud cover in a region, and +set an image property with the cloud cover for a given region. We can +then apply a filter to select images having no cloud cover in the +region. This is useful where you are working in a very cloudy region and +want to ensure that you are filtering for clouds in your region of +interest, instead of the whole scene.
// Script showing how to obtain a harmonized Landsat Time-Series
-// using Landsat Collection 2
-var geometry = ee.Geometry.Polygon([[
- [82.60642647743225, 27.16350437805251],
- [82.60984897613525, 27.1618529901377],
- [82.61088967323303, 27.163695288375266],
- [82.60757446289062, 27.16517483230927]
-]]);
+class="sourceCode js">var geometry = ee.Geometry.Polygon([[
+ [77.4783, 13.0848],
+ [77.4783, 12.8198],
+ [77.7502, 12.8198],
+ [77.7502, 13.0848]]
+]);
+
+var s2 = ee.ImageCollection('COPERNICUS/S2_HARMONIZED');
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Step 1: Select the Landsat dataset
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-// We use "Landsat Level 2 Collection 2 Tier-1 Scenes"
-
-// Collection 2 -->
-// Landsat Collection 2 algorithm has improved
-// geometric and radiometric calibration that makes
-// the collections interoperable.
-// Learn more at https://www.usgs.gov/landsat-missions/landsat-collection-2
-
-// Level 2 -->
-// This is a surface reflectance product and
-// have the highest level of interoperability through time.
-
-// Tier 1 -->
-// Highest quality scenes which are considered suitable
-// for time-series analysis
-var L5 = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2');
-var L7 = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2');
-var L8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2');
-
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Step 2: Data Pre-Processing and Cloud Masking
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-// Mapping of band-names to a uniform naming scheme
-var l5Bands = ['SR_B1','SR_B2','SR_B3','SR_B4','SR_B5','SR_B7'];
-var l5names = ['blue','green','red','nir','swir1','swir2'];
-
-var l7Bands = ['SR_B1','SR_B2','SR_B3','SR_B4','SR_B5','SR_B7'];
-var l7names = ['blue','green','red','nir','swir1','swir2'];
-
-var l8Bands = ['SR_B2','SR_B3','SR_B4','SR_B5','SR_B6','SR_B7'];
-var l8names = ['blue','green','red','nir','swir1','swir2'];
-
-// Cloud masking function for Landsat 4,5 and 7
-function maskL457sr(image) {
- var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', 2)).eq(0);
- var saturationMask = image.select('QA_RADSAT').eq(0);
-
- // Apply the scaling factors to the appropriate bands.
- var opticalBands = image.select('SR_B.').multiply(0.0000275).add(-0.2);
- var thermalBand = image.select('ST_B6').multiply(0.00341802).add(149.0);
-
- // Replace the original bands with the scaled ones and apply the masks.
- return image.addBands(opticalBands, null, true)
- .addBands(thermalBand, null, true)
- .updateMask(qaMask)
- .updateMask(saturationMask)
- .copyProperties(image, ['system:time_start']);
-}
-
-// Cloud masking function for Landsat 8
-function maskL8sr(image) {
- var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', 2)).eq(0);
- var saturationMask = image.select('QA_RADSAT').eq(0);
-
- // Apply the scaling factors to the appropriate bands.
- var opticalBands = image.select('SR_B.').multiply(0.0000275).add(-0.2);
- var thermalBands = image.select('ST_B.*').multiply(0.00341802).add(149.0);
-
- // Replace the original bands with the scaled ones and apply the masks.
- return image.addBands(opticalBands, null, true)
- .addBands(thermalBands, null, true)
- .updateMask(qaMask)
- .updateMask(saturationMask)
- .copyProperties(image, ['system:time_start']);
-}
-
-// Apply cloud-mask and rename bands
-var L5 = L5
- .map(maskL457sr)
- .select(l5Bands,l5names)
-
-var L7 = L7
- .map(maskL457sr)
- .select(l7Bands,l7names)
-
-var L8 = L8
- .map(maskL8sr)
- .select(l8Bands,l8names)
-
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Step 3a: Verify Radiometric Calibration
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// We plot band values from different satellites during
-// times when both were operational.
-
-// Compare L5 and L7
-var L5Filtered = L5
- .filter(ee.Filter.date('2005-01-01', '2006-01-01'))
- .select(['red', 'nir'], ['red_L5', 'nir_L5']);
-
-var L7Filtered = L7
- .filter(ee.Filter.date('2005-01-01', '2006-01-01'))
- .select(['red', 'nir'], ['red_L7', 'nir_L7']);
-
-var L5L7merged = L5Filtered.merge(L7Filtered)
-
-var chart = ui.Chart.image.series({
- imageCollection: L5L7merged,
- region: geometry,
- reducer: ee.Reducer.mean(),
- scale: 30
-}).setChartType('LineChart')
- .setOptions({
- title: 'Landsat 5 vs Landsat 7',
- interpolateNulls: true,
- vAxis: {title: 'Reflectance', viewWindow: {min: 0, max: 0.5}},
- hAxis: {title: '', format: 'YYYY-MM'},
- lineWidth: 1,
- pointSize: 4,
- lineDashStyle: [4, 4]
- })
-print(chart);
-
-// Compare L7 and L8
-var L7Filtered = L7
- .filter(ee.Filter.date('2016-01-01', '2017-01-01'))
- .select(['red', 'nir'], ['red_L7', 'nir_L7']);
-
-var L8Filtered = L8
- .filter(ee.Filter.date('2016-01-01', '2017-01-01'))
- .select(['red', 'nir'], ['red_L8', 'nir_L8']);
-
-var L7L8merged = L7Filtered.merge(L8Filtered)
-
-var chart = ui.Chart.image.series({
- imageCollection: L7L8merged,
- region: geometry,
- reducer: ee.Reducer.mean(),
- scale: 30
-}).setChartType('LineChart')
- .setOptions({
- title: 'Landsat 7 vs Landsat 8',
- interpolateNulls: true,
- vAxis: {title: 'Reflectance', viewWindow: {min: 0, max: 0.5}},
- hAxis: {title: '', format: 'YYYY-MM'},
- lineWidth: 1,
- pointSize: 4,
- lineDashStyle: [4, 4]
- })
-print(chart);
-
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Step 3b: Select Date Ranges, Filter and Merge
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// See the Landsat timeline for date ranges
-// https://www.usgs.gov/media/images/landsat-missions-timeline
-
-// Adjust the range depending on your
-// application and location
-var l5Start = ee.Date.fromYMD(1990, 1, 1);
-var l5End = ee.Date.fromYMD(1999, 1, 1);
-
-var l7Start = ee.Date.fromYMD(1999, 1, 1);
-var l7End = ee.Date.fromYMD(2014, 1, 1);
-
-var l8Start = ee.Date.fromYMD(2014, 1, 1);
-var l8End = ee.Date.fromYMD(2023, 1, 1);
-
-var L5 = L5
- .filter(ee.Filter.date(l5Start, l5End))
- .filter(ee.Filter.bounds(geometry));
-
-var L7 = L7
- .filter(ee.Filter.date(l7Start, l7End))
- .filter(ee.Filter.bounds(geometry));
-
-var L8 = L8
- .filter(ee.Filter.date(l8Start, l8End))
- .filter(ee.Filter.bounds(geometry));
-
-var merged = L5.merge(L7).merge(L8)
-
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Step 4: Create Annual Composites
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-var years = ee.List.sequence(1990, 2023);
-
-var compositeImages = years.map(function(year) {
- var startDate = ee.Date.fromYMD(year, 1, 1);
- var endDate = startDate.advance(1, 'year');
- var yearFiltered = merged.filter(ee.Filter.date(startDate, endDate));
- var composite = yearFiltered.median();
- return composite.set({
- 'year': year,
- 'system:time_start': startDate.millis(),
- 'system:time_end': endDate.millis(),
- })
-});
-
-var compositeCol = ee.ImageCollection.fromImages(compositeImages);
-print('Annual Landsat Composites', compositeCol);
// Exploring Composite Images
-// Example script showing
-// 1. How to visualize the DOY (day-of-year) of each pixel of a composite
-// 2. How to visualize count of images at each pixel of a composite
-var admin1 = ee.FeatureCollection('FAO/GAUL_SIMPLIFIED_500m/2015/level1');
-var karnataka = admin1.filter(ee.Filter.eq('ADM1_NAME', 'Karnataka'));
-var geometry = karnataka.geometry();
-
-var s2 =ee.ImageCollection('COPERNICUS/S2_HARMONIZED');
-
-var rgbVis = {
- min: 0.0,
- max: 3000,
- bands: ['B4', 'B3', 'B2'],
-};
-
-
-var filtered = s2.filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 30))
- .filter(ee.Filter.date('2019-01-01', '2020-01-01'))
- .filter(ee.Filter.bounds(geometry));
+class="sourceCode js">// Script showing how to obtain a harmonized Landsat Time-Series
+// using Landsat Collection 2
+var geometry = ee.Geometry.Polygon([[
+ [82.60642647743225, 27.16350437805251],
+ [82.60984897613525, 27.1618529901377],
+ [82.61088967323303, 27.163695288375266],
+ [82.60757446289062, 27.16517483230927]
+]]);
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Step 1: Select the Landsat dataset
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+// We use "Landsat Level 2 Collection 2 Tier-1 Scenes"
+
+// Collection 2 -->
+// Landsat Collection 2 algorithm has improved
+// geometric and radiometric calibration that makes
+// the collections interoperable.
+// Learn more at https://www.usgs.gov/landsat-missions/landsat-collection-2
-// Add a band to each image indicating the DOY of each image
-var filteredWithDoyBand = filtered.map(function(image) {
- // Create an image with day of the year as value
- var date = ee.Date(image.get('system:time_start'));
- var day = date.getRelative('day', 'year');
- var dayImage = ee.Image.constant(day).rename(['dayofyear']).int().clip(image.geometry());
- return image.addBands([dayImage]);
-});
-
-var composite = filteredWithDoyBand.median();
+// Level 2 -->
+// This is a surface reflectance product and
+// have the highest level of interoperability through time.
+
+// Tier 1 -->
+// Highest quality scenes which are considered suitable
+// for time-series analysis
+var L5 = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2');
+var L7 = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2');
+var L8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2');
-Map.centerObject(geometry, 8);
-Map.addLayer(composite.clip(geometry), rgbVis, '2019 Median Composite')
-
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Step 2: Data Pre-Processing and Cloud Masking
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Visualize which pixels contribute to the composite
-var dateImage = composite.select('dayofyear').int();
-
-var doyVis = {
- min:20,
- max: 100,
- palette: ['d7191c','fdae61','ffffbf','a6d96a','1a9641']
-}
-Map.addLayer(dateImage.clip(geometry), doyVis, 'DOY of Each Pixel in Composite');
+// Mapping of band-names to a uniform naming scheme
+var l5Bands = ['SR_B1','SR_B2','SR_B3','SR_B4','SR_B5','SR_B7'];
+var l5names = ['blue','green','red','nir','swir1','swir2'];
+
+var l7Bands = ['SR_B1','SR_B2','SR_B3','SR_B4','SR_B5','SR_B7'];
+var l7names = ['blue','green','red','nir','swir1','swir2'];
+
+var l8Bands = ['SR_B2','SR_B3','SR_B4','SR_B5','SR_B6','SR_B7'];
+var l8names = ['blue','green','red','nir','swir1','swir2'];
-// Visualize the number of images contributing to each pixel
-// of the composite
-// Select a single band and use count()
-var count = filtered.select(['B4']).count();
+// Cloud masking function for Landsat 4,5 and 7
+function maskL457sr(image) {
+ var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', 2)).eq(0);
+ var saturationMask = image.select('QA_RADSAT').eq(0);
-// show image count
-var countVis = {
- min: 50,
- max: 100,
- palette: ['#fee5d9','#fcae91','#fb6a4a','#de2d26','#a50f15']
-}
-Map.addLayer(count.clip(geometry), countVis, 'Number of S2 Scenes')
// Exploring Composite Images
+// Example script showing
+// 1. How to visualize the DOY (day-of-year) of each pixel of a composite
+// 2. How to visualize count of images at each pixel of a composite
+var admin1 = ee.FeatureCollection('FAO/GAUL_SIMPLIFIED_500m/2015/level1');
+var karnataka = admin1.filter(ee.Filter.eq('ADM1_NAME', 'Karnataka'));
+var geometry = karnataka.geometry();
+
+var s2 =ee.ImageCollection('COPERNICUS/S2_HARMONIZED');
+
+var rgbVis = {
+ min: 0.0,
+ max: 3000,
+ bands: ['B4', 'B3', 'B2'],
+};
+
+
+var filtered = s2.filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 30))
+ .filter(ee.Filter.date('2019-01-01', '2020-01-01'))
+ .filter(ee.Filter.bounds(geometry));
+
+// Add a band to each image indicating the DOY of each image
+var filteredWithDoyBand = filtered.map(function(image) {
+ // Create an image with day of the year as value
+ var date = ee.Date(image.get('system:time_start'));
+ var day = date.getRelative('day', 'year');
+ var dayImage = ee.Image.constant(day).rename(['dayofyear']).int().clip(image.geometry());
+ return image.addBands([dayImage]);
+});
+
+var composite = filteredWithDoyBand.median();
+
+Map.centerObject(geometry, 8);
+Map.addLayer(composite.clip(geometry), rgbVis, '2019 Median Composite')
+
+
+// Visualize which pixels contribute to the composite
+var dateImage = composite.select('dayofyear').int();
+
+var doyVis = {
+ min:20,
+ max: 100,
+ palette: ['d7191c','fdae61','ffffbf','a6d96a','1a9641']
+}
+Map.addLayer(dateImage.clip(geometry), doyVis, 'DOY of Each Pixel in Composite');
+
+// Visualize the number of images contributing to each pixel
+// of the composite
+// Select a single band and use count()
+var count = filtered.select(['B4']).count();
+
+// show image count
+var countVis = {
+ min: 50,
+ max: 100,
+ palette: ['#fee5d9','#fcae91','#fb6a4a','#de2d26','#a50f15']
+}
+Map.addLayer(count.clip(geometry), countVis, 'Number of S2 Scenes')
// Example script for calculating NDVI and EVI from Landsat Collection 2 images
-
-// Get Banglore boundary
-var admin2 = ee.FeatureCollection("FAO/GAUL_SIMPLIFIED_500m/2015/level2");
-
-var bangalore = admin2.filter(ee.Filter.eq('ADM2_NAME', 'Bangalore Urban'))
-var geometry = bangalore.geometry()
-
-// Applies cloud mask and scaling factors.
-function maskL8sr(image) {
- // Bit 0 - Fill
- // Bit 1 - Dilated Cloud
- // Bit 2 - Cirrus
- // Bit 3 - Cloud
- // Bit 4 - Cloud Shadow
- var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', 2)).eq(0);
- var saturationMask = image.select('QA_RADSAT').eq(0);
-
- // Apply the scaling factors to the appropriate bands.
- var opticalBands = image.select('SR_B.').multiply(0.0000275).add(-0.2);
- var thermalBands = image.select('ST_B.*').multiply(0.00341802).add(149.0);
-
- // Replace the original bands with the scaled ones and apply the masks.
- return image.addBands(opticalBands, null, true)
- .addBands(thermalBands, null, true)
- .updateMask(qaMask)
- .updateMask(saturationMask);
-}
-
-// Filter to 2021 Landsat 8 images over banglore.
-var dataset = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
- .filter(ee.Filter.date('2021-01-01', '2022-01-01'))
- .filter(ee.Filter.bounds(geometry))
- .map(maskL8sr);
-
-// Create a median composite
-var image = dataset.median();
-
-// Print to check the bands.
-print(image)
-
-// Create NDVI image.
-var ndvi = image.normalizedDifference(['SR_B5', 'SR_B4']).rename(['ndvi'])
-
-// Create MNDWI image.
-var mndwi = image.normalizedDifference(['SR_B3', 'SR_B6']).rename(['mndwi'])
-
-// Create EVI image
-// EVI = 2.5 * ((Band 5 – Band 4) / (Band 5 + 6 * Band 4 – 7.5 * Band 2 + 1)).
-var evi = image.expression(
- '2.5 * ( (NIR - RED) / (NIR + 6 * RED - 7.5 * BLUE + 1))', {
- 'BLUE': image.select('SR_B2'),
- 'RED': image.select('SR_B4'),
- 'NIR': image.select('SR_B5')
-}).rename('evi');
-
-// Create MNDWI image
-
-// Visualization parameter.
-var rgbVis = {min:0, max:0.3, bands:['SR_B4', 'SR_B3', 'SR_B2']}
-var ndviVis = {min:0, max:0.5, palette: ['white', 'green']}
-var ndwiVis = {min:0, max:0.5, palette: ['white', 'blue']}
-
-// Add EVI and NDVI images to Map.
-Map.centerObject(geometry)
-Map.addLayer(image.clip(geometry), rgbVis, 'Image')
-Map.addLayer(evi.clip(geometry), ndviVis, 'EVI')
-Map.addLayer(ndvi.clip(geometry), ndviVis, 'NDVI')
-Map.addLayer(mndwi.clip(geometry), ndwiVis, 'MNDWI')
// Example script for calculating NDVI and EVI from Landsat Collection 2 images
+
+// Get Banglore boundary
+var admin2 = ee.FeatureCollection("FAO/GAUL_SIMPLIFIED_500m/2015/level2");
+
+var bangalore = admin2.filter(ee.Filter.eq('ADM2_NAME', 'Bangalore Urban'))
+var geometry = bangalore.geometry()
+
+// Applies cloud mask and scaling factors.
+function maskL8sr(image) {
+ // Bit 0 - Fill
+ // Bit 1 - Dilated Cloud
+ // Bit 2 - Cirrus
+ // Bit 3 - Cloud
+ // Bit 4 - Cloud Shadow
+ var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', 2)).eq(0);
+ var saturationMask = image.select('QA_RADSAT').eq(0);
+
+ // Apply the scaling factors to the appropriate bands.
+ var opticalBands = image.select('SR_B.').multiply(0.0000275).add(-0.2);
+ var thermalBands = image.select('ST_B.*').multiply(0.00341802).add(149.0);
+
+ // Replace the original bands with the scaled ones and apply the masks.
+ return image.addBands(opticalBands, null, true)
+ .addBands(thermalBands, null, true)
+ .updateMask(qaMask)
+ .updateMask(saturationMask);
+}
+
+// Filter to 2021 Landsat 8 images over banglore.
+var dataset = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
+ .filter(ee.Filter.date('2021-01-01', '2022-01-01'))
+ .filter(ee.Filter.bounds(geometry))
+ .map(maskL8sr);
+
+// Create a median composite
+var image = dataset.median();
+
+// Print to check the bands.
+print(image)
+
+// Create NDVI image.
+var ndvi = image.normalizedDifference(['SR_B5', 'SR_B4']).rename(['ndvi'])
+
+// Create MNDWI image.
+var mndwi = image.normalizedDifference(['SR_B3', 'SR_B6']).rename(['mndwi'])
+
+// Create EVI image
+// EVI = 2.5 * ((Band 5 – Band 4) / (Band 5 + 6 * Band 4 – 7.5 * Band 2 + 1)).
+var evi = image.expression(
+ '2.5 * ( (NIR - RED) / (NIR + 6 * RED - 7.5 * BLUE + 1))', {
+ 'BLUE': image.select('SR_B2'),
+ 'RED': image.select('SR_B4'),
+ 'NIR': image.select('SR_B5')
+}).rename('evi');
+
+// Create MNDWI image
+
+// Visualization parameter.
+var rgbVis = {min:0, max:0.3, bands:['SR_B4', 'SR_B3', 'SR_B2']}
+var ndviVis = {min:0, max:0.5, palette: ['white', 'green']}
+var ndwiVis = {min:0, max:0.5, palette: ['white', 'blue']}
+
+// Add EVI and NDVI images to Map.
+Map.centerObject(geometry)
+Map.addLayer(image.clip(geometry), rgbVis, 'Image')
+Map.addLayer(evi.clip(geometry), ndviVis, 'EVI')
+Map.addLayer(ndvi.clip(geometry), ndviVis, 'NDVI')
+Map.addLayer(mndwi.clip(geometry), ndwiVis, 'MNDWI')
// Script showing how to obtain a Landsat LST Time-Series
-// over different land surfaces
-
-var metalroof = ee.Geometry.Point([72.8550936937685, 19.044646120301234]);
-var concreteroof = ee.Geometry.Point([72.85441764267667, 19.028290540890772]);
-var airport = ee.Geometry.Point([72.86249644714638, 19.09355985643176]);
-var water = ee.Geometry.Point([72.91107782264197, 19.152799035509638]);
-var mangrove = ee.Geometry.Point([72.8115905761819, 19.152316393168405]);
-
-// Use Mumbai city boundary
-var mumbai_wards = ee.FeatureCollection(
- 'users/ujavalgandhi/public/mumbai_bmc_wards_datameet');
-var geometry = mumbai_wards.geometry();
-Map.centerObject(geometry, 12);
-
-// Method 1
-// LST Computation code by Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia)
-
-// Ermida, S.L., Soares, P., Mantas, V., Göttsche, F.-M., Trigo, I.F., 2020.
-// Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series.
-// Remote Sensing, 12 (9), 1471; https://doi.org/10.3390/rs12091471
-var LandsatLST = require('users/sofiaermida/landsat_smw_lst:modules/Landsat_LST.js')
-
-// Set parameters to get Landsat 8 data
-var satellite = 'L8';
-var date_start = '2015-01-01';
-var date_end = '2016-01-01';
-var use_ndvi = true;
-
-// get landsat collection with added variables: NDVI, FVC, TPW, EM, LST
-var LandsatColl = LandsatLST.collection(satellite, date_start, date_end, geometry, use_ndvi)
-
-// Select LST band
-var lstK = LandsatColl.select('LST')
-
-// Convert to celsius
-var lstC = lstK.map(function(image){
- return image.subtract(273.15).copyProperties(image, image.propertyNames())
-})
-
-
-// Filter to May month image to visualize in map.
-var lstMay = lstC
- .filter(ee.Filter.date('2015-04-01', '2015-05-01'))
- .mean()
-
-Map.addLayer(lstMay.clip(geometry),
- {min:25, max:45, palette:['green','yellow','red']},
- 'Landsat-LST (Ermida, S.L)')
-
-// Create the LSt time series chart.
-var chart = ui.Chart.image.seriesByRegion({
- imageCollection:lstC,
- regions: [airport, metalroof, concreteroof, mangrove, water],
- reducer:ee.Reducer.mean(),
- band:['LST'],
- scale:30,
- xProperty:'system:time_start',
-}).setOptions({
- lineWidth: 1,
- title: 'Land Surface Temperature Time-Series (Ermida, S.L)',
- interpolateNulls: true,
- viewWindowMode:'explicit',
- viewWindow: {
- max:50,
- min:25
- },
- vAxis: {title: 'LST (°C)'},
- hAxis: {title: '', format: 'YYYY-MMM'},
- series: {
- 0: {color: 'red', labelInLegend: 'Airport Tarmac'},
- 1: {color: 'pink', labelInLegend: 'Residential-Slum (Metal Roof)'},
- 2: {color: 'grey', labelInLegend: 'Residential (Concrete Roof)'},
- 3: {color: 'green', labelInLegend: 'Mangrove'},
- 4: {color: 'blue', labelInLegend: 'Water'}
- }
- })
-
-print(chart);
-
-// Method 2
-// Landsat Collection 2 Level 2 LST
-
-var date_start = '2015-01-01';
-var date_end = '2016-01-01';
-
-var dataset = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
- .filterDate(date_start, date_end)
- .filter(ee.Filter.bounds(geometry))
-
-function maskL8sr(image) {
- // Bit 0 - Fill
- // Bit 1 - Dilated Cloud
- // Bit 2 - Cirrus
- // Bit 3 - Cloud
- // Bit 4 - Cloud Shadow
- var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', 2)).eq(0);
- var saturationMask = image.select('QA_RADSAT').eq(0);
-
- // Apply the scaling factors to the appropriate bands.
- var opticalBands = image.select('SR_B.').multiply(0.0000275).add(-0.2);
- var thermalBands = image.select('ST_B.*').multiply(0.00341802).add(149.0);
-
- // Replace the original bands with the scaled ones and apply the masks.
- return image.addBands(opticalBands, null, true)
- .addBands(thermalBands, null, true)
- .updateMask(qaMask)
- .updateMask(saturationMask);
-}
-
-
-dataset = dataset.map(maskL8sr)
-
-// Select B10 band and rename it to LST
-var lstK = dataset.select(['ST_B10'], ['LST'])
-
-// Convert to celsius
-var lstC = lstK.map(function(image){
- return image.subtract(273.15).copyProperties(image, image.propertyNames())
-})
-
-
-// Filter to May month image to visualize in map.
-var lstMay = lstC
- .filter(ee.Filter.date('2015-04-01', '2015-05-01')).mean()
-
-Map.addLayer(lstMay.clip(geometry),
- {min:25, max:45, palette:['green','yellow','red']},
- 'Landsat-LST (Landsat Collection 2)')
-
-// Create the LSt time series chart.
-var chart = ui.Chart.image.seriesByRegion({
- imageCollection:lstC,
- regions: [airport, metalroof, concreteroof, mangrove, water],
- reducer:ee.Reducer.mean(),
- band:['LST'],
- scale:30,
- xProperty:'system:time_start',
-}).setOptions({
- lineWidth: 1,
- title: 'Land Surface Temperature Time-Series (Landsat Collection 2)',
- interpolateNulls: true,
- viewWindowMode:'explicit',
- viewWindow: {
- max:50,
- min:25
- },
- vAxis: {title: 'LST (°C)'},
- hAxis: {title: '', format: 'YYYY-MMM'},
- series: {
- 0: {color: 'red', labelInLegend: 'Airport Tarmac'},
- 1: {color: 'pink', labelInLegend: 'Residential-Slum (Metal Roof)'},
- 2: {color: 'grey', labelInLegend: 'Residential (Concrete Roof)'},
- 3: {color: 'green', labelInLegend: 'Mangrove'},
- 4: {color: 'blue', labelInLegend: 'Water'}
- }
- })
-
-print(chart);
// Script showing how to obtain a Landsat LST Time-Series
+// over different land surfaces
+
+var metalroof = ee.Geometry.Point([72.8550936937685, 19.044646120301234]);
+var concreteroof = ee.Geometry.Point([72.85441764267667, 19.028290540890772]);
+var airport = ee.Geometry.Point([72.86249644714638, 19.09355985643176]);
+var water = ee.Geometry.Point([72.91107782264197, 19.152799035509638]);
+var mangrove = ee.Geometry.Point([72.8115905761819, 19.152316393168405]);
+
+// Use Mumbai city boundary
+var mumbai_wards = ee.FeatureCollection(
+ 'users/ujavalgandhi/public/mumbai_bmc_wards_datameet');
+var geometry = mumbai_wards.geometry();
+Map.centerObject(geometry, 12);
+
+// Method 1
+// LST Computation code by Sofia Ermida (sofia.ermida@ipma.pt; @ermida_sofia)
+
+// Ermida, S.L., Soares, P., Mantas, V., Göttsche, F.-M., Trigo, I.F., 2020.
+// Google Earth Engine open-source code for Land Surface Temperature estimation from the Landsat series.
+// Remote Sensing, 12 (9), 1471; https://doi.org/10.3390/rs12091471
+var LandsatLST = require('users/sofiaermida/landsat_smw_lst:modules/Landsat_LST.js')
+
+// Set parameters to get Landsat 8 data
+var satellite = 'L8';
+var date_start = '2015-01-01';
+var date_end = '2016-01-01';
+var use_ndvi = true;
+
+// get landsat collection with added variables: NDVI, FVC, TPW, EM, LST
+var LandsatColl = LandsatLST.collection(satellite, date_start, date_end, geometry, use_ndvi)
+
+// Select LST band
+var lstK = LandsatColl.select('LST')
+
+// Convert to celsius
+var lstC = lstK.map(function(image){
+ return image.subtract(273.15).copyProperties(image, image.propertyNames())
+})
+
+
+// Filter to May month image to visualize in map.
+var lstMay = lstC
+ .filter(ee.Filter.date('2015-04-01', '2015-05-01'))
+ .mean()
+
+Map.addLayer(lstMay.clip(geometry),
+ {min:25, max:45, palette:['green','yellow','red']},
+ 'Landsat-LST (Ermida, S.L)')
+
+// Create the LSt time series chart.
+var chart = ui.Chart.image.seriesByRegion({
+ imageCollection:lstC,
+ regions: [airport, metalroof, concreteroof, mangrove, water],
+ reducer:ee.Reducer.mean(),
+ band:['LST'],
+ scale:30,
+ xProperty:'system:time_start',
+}).setOptions({
+ lineWidth: 1,
+ title: 'Land Surface Temperature Time-Series (Ermida, S.L)',
+ interpolateNulls: true,
+ viewWindowMode:'explicit',
+ viewWindow: {
+ max:50,
+ min:25
+ },
+ vAxis: {title: 'LST (°C)'},
+ hAxis: {title: '', format: 'YYYY-MMM'},
+ series: {
+ 0: {color: 'red', labelInLegend: 'Airport Tarmac'},
+ 1: {color: 'pink', labelInLegend: 'Residential-Slum (Metal Roof)'},
+ 2: {color: 'grey', labelInLegend: 'Residential (Concrete Roof)'},
+ 3: {color: 'green', labelInLegend: 'Mangrove'},
+ 4: {color: 'blue', labelInLegend: 'Water'}
+ }
+ })
+
+print(chart);
+
+// Method 2
+// Landsat Collection 2 Level 2 LST
+
+var date_start = '2015-01-01';
+var date_end = '2016-01-01';
+
+var dataset = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
+ .filterDate(date_start, date_end)
+ .filter(ee.Filter.bounds(geometry))
+
+function maskL8sr(image) {
+ // Bit 0 - Fill
+ // Bit 1 - Dilated Cloud
+ // Bit 2 - Cirrus
+ // Bit 3 - Cloud
+ // Bit 4 - Cloud Shadow
+ var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', 2)).eq(0);
+ var saturationMask = image.select('QA_RADSAT').eq(0);
+
+ // Apply the scaling factors to the appropriate bands.
+ var opticalBands = image.select('SR_B.').multiply(0.0000275).add(-0.2);
+ var thermalBands = image.select('ST_B.*').multiply(0.00341802).add(149.0);
+
+ // Replace the original bands with the scaled ones and apply the masks.
+ return image.addBands(opticalBands, null, true)
+ .addBands(thermalBands, null, true)
+ .updateMask(qaMask)
+ .updateMask(saturationMask);
+}
+
+
+dataset = dataset.map(maskL8sr)
+
+// Select B10 band and rename it to LST
+var lstK = dataset.select(['ST_B10'], ['LST'])
+
+// Convert to celsius
+var lstC = lstK.map(function(image){
+ return image.subtract(273.15).copyProperties(image, image.propertyNames())
+})
+
+
+// Filter to May month image to visualize in map.
+var lstMay = lstC
+ .filter(ee.Filter.date('2015-04-01', '2015-05-01')).mean()
+
+Map.addLayer(lstMay.clip(geometry),
+ {min:25, max:45, palette:['green','yellow','red']},
+ 'Landsat-LST (Landsat Collection 2)')
+
+// Create the LSt time series chart.
+var chart = ui.Chart.image.seriesByRegion({
+ imageCollection:lstC,
+ regions: [airport, metalroof, concreteroof, mangrove, water],
+ reducer:ee.Reducer.mean(),
+ band:['LST'],
+ scale:30,
+ xProperty:'system:time_start',
+}).setOptions({
+ lineWidth: 1,
+ title: 'Land Surface Temperature Time-Series (Landsat Collection 2)',
+ interpolateNulls: true,
+ viewWindowMode:'explicit',
+ viewWindow: {
+ max:50,
+ min:25
+ },
+ vAxis: {title: 'LST (°C)'},
+ hAxis: {title: '', format: 'YYYY-MMM'},
+ series: {
+ 0: {color: 'red', labelInLegend: 'Airport Tarmac'},
+ 1: {color: 'pink', labelInLegend: 'Residential-Slum (Metal Roof)'},
+ 2: {color: 'grey', labelInLegend: 'Residential (Concrete Roof)'},
+ 3: {color: 'green', labelInLegend: 'Mangrove'},
+ 4: {color: 'blue', labelInLegend: 'Water'}
+ }
+ })
+
+print(chart);
// Moving-Window Temporal Smoothing
-var s2 = ee.ImageCollection('COPERNICUS/S2_HARMONIZED');
-var geometry = ee.Geometry.Point([74.80368345518073, 30.391793042969]);
-
-var startDate = ee.Date.fromYMD(2019, 1, 1);
-var endDate = ee.Date.fromYMD(2021, 1, 1);
-
-// Function to add a NDVI band to an image
-function addNDVI(image) {
- var ndvi = image.normalizedDifference(['B8', 'B4']).rename('ndvi');
- return image.addBands(ndvi);
-}
-
-// Function to mask clouds
-function maskS2clouds(image) {
- var qa = image.select('QA60')
- var cloudBitMask = 1 << 10;
- var cirrusBitMask = 1 << 11;
- var mask = qa.bitwiseAnd(cloudBitMask).eq(0).and(
- qa.bitwiseAnd(cirrusBitMask).eq(0))
- return image.updateMask(mask).divide(10000)
- .select("B.*")
- .copyProperties(image, ["system:time_start"])
-}
-
-var originalCollection = s2
- .filter(ee.Filter.date(startDate, endDate))
- .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 30))
- .filter(ee.Filter.bounds(geometry))
- .map(maskS2clouds)
- .map(addNDVI);
-
-// Display a time-series chart
-var chart = ui.Chart.image.series({
- imageCollection: originalCollection.select('ndvi'),
- region: geometry,
- reducer: ee.Reducer.mean(),
- scale: 20
-}).setOptions({
- title: 'Original NDVI Time Series',
- interpolateNulls: false,
- vAxis: {title: 'NDVI', viewWindow: {min: 0, max: 1}},
- hAxis: {title: '', format: 'YYYY-MM'},
- lineWidth: 1,
- pointSize: 4,
- series: {
- 0: {color: '#238b45'},
- },
-
- })
-print(chart);
-
-// Moving-Window Smoothing
-
-// Specify the time-window
-var days = 15;
-
-// Convert to milliseconds
-var millis = ee.Number(days).multiply(1000*60*60*24);
-
-// We use a 'save-all join' to find all images
-// that are within the time-window
-
-// The join will add all matching images into a
-// new property called 'images'
-var join = ee.Join.saveAll({
- matchesKey: 'images'
-});
-
-// This filter will match all images that are captured
-// within the specified day of the source image
-var diffFilter = ee.Filter.maxDifference({
- difference: millis,
- leftField: 'system:time_start',
- rightField: 'system:time_start'
-});
-
-
-var joinedCollection = join.apply({
- primary: originalCollection,
- secondary: originalCollection,
- condition: diffFilter
-});
-
-print('Joined Collection', joinedCollection);
-
-// Each image in the joined collection will contain
-// matching images in the 'images' property
-// Extract and return the mean of matched images
-var extractAndComputeMean = function(image) {
- var matchingImages = ee.ImageCollection.fromImages(image.get('images'));
- var meanImage = matchingImages.reduce(
- ee.Reducer.mean().setOutputs(['moving_average']))
- return ee.Image(image).addBands(meanImage)
-}
-
-var smoothedCollection = ee.ImageCollection(
- joinedCollection.map(extractAndComputeMean));
-
-print('Smoothed Collection', smoothedCollection)
-
-// Display a time-series chart
-var chart = ui.Chart.image.series({
- imageCollection: smoothedCollection.select(['ndvi', 'ndvi_moving_average']),
- region: geometry,
- reducer: ee.Reducer.mean(),
- scale: 20
-}).setOptions({
- title: 'NDVI Time Series',
- interpolateNulls: false,
- vAxis: {title: 'NDVI', viewWindow: {min: 0, max: 1}},
- hAxis: {title: '', format: 'YYYY-MM'},
- lineWidth: 1,
- pointSize: 4,
- series: {
- 0: {color: '#66c2a4', lineDashStyle: [1, 1], pointSize: 2}, // Original NDVI
- 1: {color: '#238b45', lineWidth: 2 }, // Smoothed NDVI
- },
-
- })
-print(chart);
-
-// Let's export the NDVI time-series as a video
-var palette = ['#d73027','#f46d43','#fdae61','#fee08b',
- '#ffffbf','#d9ef8b','#a6d96a','#66bd63','#1a9850'];
-var ndviVis = {min:-0.2, max: 0.8, palette: palette}
-
-Map.centerObject(geometry, 16);
-var bbox = Map.getBounds({asGeoJSON: true});
-
-var visualizeImage = function(image) {
- return image.visualize(ndviVis).clip(bbox).selfMask()
-}
-
-var visCollectionOriginal = originalCollection.select('ndvi')
- .map(visualizeImage)
-
-
-var visCollectionSmoothed = smoothedCollection.select('ndvi_moving_average')
- .map(visualizeImage)
-
-
-Export.video.toDrive({
- collection: visCollectionOriginal,
- description: 'Original_Time_Series',
- folder: 'earthengine',
- fileNamePrefix: 'original',
- framesPerSecond: 2,
- dimensions: 800,
- region: bbox})
-
-Export.video.toDrive({
- collection: visCollectionSmoothed,
- description: 'Smoothed_Time_Series',
- folder: 'earthengine',
- fileNamePrefix: 'smoothed',
- framesPerSecond: 2,
- dimensions: 800,
- region: bbox})
The code below shows how to do temporal gap-filling of time-series -data. A detailed explanation of the code and other examples are -described in our blog post Temporal Gap-Filling with Linear Interpolation in -GEE.
-// Temporal Interpolation (Gap-Filling Masked Pixels)
+class="sourceCode js">// Moving-Window Temporal Smoothing
var s2 = ee.ImageCollection('COPERNICUS/S2_HARMONIZED');
var geometry = ee.Geometry.Point([74.80368345518073, 30.391793042969]);
@@ -3790,230 +3710,402 @@ Temporal Interpolation
.map(maskS2clouds)
.map(addNDVI);
-
-// Display a time-series chart
-var chart = ui.Chart.image.series({
- imageCollection: originalCollection.select('ndvi'),
- region: geometry,
- reducer: ee.Reducer.mean(),
- scale: 20
-}).setOptions({
- title: 'Original NDVI Time Series',
- interpolateNulls: false,
- vAxis: {title: 'NDVI', viewWindow: {min: 0, max: 1}},
- hAxis: {title: '', format: 'YYYY-MM'},
- lineWidth: 1,
- pointSize: 4,
- series: {
- 0: {color: '#238b45'},
- },
-
- })
-print(chart);
-
-// Gap-filling
-
-// Add a band containing timestamp to each image
-// This will be used to do pixel-wise interpolation later
-var originalCollection = originalCollection.map(function(image) {
- var timeImage = image.metadata('system:time_start').rename('timestamp')
- // The time image doesn't have a mask.
- // We set the mask of the time band to be the same as the first band of the image
- var timeImageMasked = timeImage.updateMask(image.mask().select(0))
- return image.addBands(timeImageMasked).toFloat();
-})
-
-// For each image in the collection, we need to find all images
-// before and after the specified time-window
-
-// This is accomplished using Joins
-// We need to do 2 joins
-// Join 1: Join the collection with itself to find all images before each image
-// Join 2: Join the collection with itself to find all images after each image
-
-// We first define the filters needed for the join
-
-// Define a maxDifference filter to find all images within the specified days
-// The filter needs the time difference in milliseconds
-// Convert days to milliseconds
-
-// Specify the time-window to look for unmasked pixel
-var days = 45;
-var millis = ee.Number(days).multiply(1000*60*60*24)
-
-var maxDiffFilter = ee.Filter.maxDifference({
- difference: millis,
- leftField: 'system:time_start',
- rightField: 'system:time_start'
-})
-
-// We need a lessThanOrEquals filter to find all images after a given image
-// This will compare the given image's timestamp against other images' timestamps
-var lessEqFilter = ee.Filter.lessThanOrEquals({
- leftField: 'system:time_start',
- rightField: 'system:time_start'
-})
+// Display a time-series chart
+var chart = ui.Chart.image.series({
+ imageCollection: originalCollection.select('ndvi'),
+ region: geometry,
+ reducer: ee.Reducer.mean(),
+ scale: 20
+}).setOptions({
+ title: 'Original NDVI Time Series',
+ interpolateNulls: false,
+ vAxis: {title: 'NDVI', viewWindow: {min: 0, max: 1}},
+ hAxis: {title: '', format: 'YYYY-MM'},
+ lineWidth: 1,
+ pointSize: 4,
+ series: {
+ 0: {color: '#238b45'},
+ },
+
+ })
+print(chart);
+
+// Moving-Window Smoothing
+
+// Specify the time-window
+var days = 15;
+
+// Convert to milliseconds
+var millis = ee.Number(days).multiply(1000*60*60*24);
+
+// We use a 'save-all join' to find all images
+// that are within the time-window
+
+// The join will add all matching images into a
+// new property called 'images'
+var join = ee.Join.saveAll({
+ matchesKey: 'images'
+});
+
+// This filter will match all images that are captured
+// within the specified day of the source image
+var diffFilter = ee.Filter.maxDifference({
+ difference: millis,
+ leftField: 'system:time_start',
+ rightField: 'system:time_start'
+});
+
+
+var joinedCollection = join.apply({
+ primary: originalCollection,
+ secondary: originalCollection,
+ condition: diffFilter
+});
+
+print('Joined Collection', joinedCollection);
+
+// Each image in the joined collection will contain
+// matching images in the 'images' property
+// Extract and return the mean of matched images
+var extractAndComputeMean = function(image) {
+ var matchingImages = ee.ImageCollection.fromImages(image.get('images'));
+ var meanImage = matchingImages.reduce(
+ ee.Reducer.mean().setOutputs(['moving_average']))
+ return ee.Image(image).addBands(meanImage)
+}
-// We need a greaterThanOrEquals filter to find all images before a given image
-// This will compare the given image's timestamp against other images' timestamps
-var greaterEqFilter = ee.Filter.greaterThanOrEquals({
- leftField: 'system:time_start',
- rightField: 'system:time_start'
-})
-
-
-// Apply the joins
-
-// For the first join, we need to match all images that are after the given image.
-// To do this we need to match 2 conditions
-// 1. The resulting images must be within the specified time-window of target image
-// 2. The target image's timestamp must be lesser than the timestamp of resulting images
-// Combine two filters to match both these conditions
-var filter1 = ee.Filter.and(maxDiffFilter, lessEqFilter)
-// This join will find all images after, sorted in descending order
-// This will gives us images so that closest is last
-var join1 = ee.Join.saveAll({
- matchesKey: 'after',
- ordering: 'system:time_start',
- ascending: false})
-
-var join1Result = join1.apply({
- primary: originalCollection,
- secondary: originalCollection,
- condition: filter1
-})
-// Each image now as a property called 'after' containing
-// all images that come after it within the time-window
-print(join1Result.first())
-
-// Do the second join now to match all images within the time-window
-// that come before each image
-var filter2 = ee.Filter.and(maxDiffFilter, greaterEqFilter)
-// This join will find all images before, sorted in ascending order
-// This will gives us images so that closest is last
-var join2 = ee.Join.saveAll({
- matchesKey: 'before',
- ordering: 'system:time_start',
- ascending: true})
-
-var join2Result = join2.apply({
- primary: join1Result,
- secondary: join1Result,
- condition: filter2
-})
-
-var joinedCol = join2Result;
-
-// Each image now as a property called 'before' containing
-// all images that come after it within the time-window
-print(joinedCol.first())
-// Do the gap-filling
-
-// We now write a function that will be used to interpolate all images
-// This function takes an image and replaces the masked pixels
-// with the interpolated value from before and after images.
-
-var interpolateImages = function(image) {
- var image = ee.Image(image);
- // We get the list of before and after images from the image property
- // Mosaic the images so we a before and after image with the closest unmasked pixel
- var beforeImages = ee.List(image.get('before'))
- var beforeMosaic = ee.ImageCollection.fromImages(beforeImages).mosaic()
- var afterImages = ee.List(image.get('after'))
- var afterMosaic = ee.ImageCollection.fromImages(afterImages).mosaic()
-
- // Interpolation formula
- // y = y1 + (y2-y1)*((t – t1) / (t2 – t1))
- // y = interpolated image
- // y1 = before image
- // y2 = after image
- // t = interpolation timestamp
- // t1 = before image timestamp
- // t2 = after image timestamp
-
- // We first compute the ratio (t – t1) / (t2 – t1)
-
- // Get image with before and after times
- var t1 = beforeMosaic.select('timestamp').rename('t1')
- var t2 = afterMosaic.select('timestamp').rename('t2')
-
- var t = image.metadata('system:time_start').rename('t')
-
- var timeImage = ee.Image.cat([t1, t2, t])
-
- var timeRatio = timeImage.expression('(t - t1) / (t2 - t1)', {
- 't': timeImage.select('t'),
- 't1': timeImage.select('t1'),
- 't2': timeImage.select('t2'),
- })
- // You can replace timeRatio with a constant value 0.5
- // if you wanted a simple average
-
- // Compute an image with the interpolated image y
- var interpolated = beforeMosaic
- .add((afterMosaic.subtract(beforeMosaic).multiply(timeRatio)))
- // Replace the masked pixels in the current image with the average value
- var result = image.unmask(interpolated)
- return result.copyProperties(image, ['system:time_start'])
-}
-
-// map() the function to gap-fill all images in the collection
-var gapFilledCol = ee.ImageCollection(joinedCol.map(interpolateImages))
-
-// Display a time-series chart
-var chart = ui.Chart.image.series({
- imageCollection: gapFilledCol.select('ndvi'),
- region: geometry,
- reducer: ee.Reducer.mean(),
- scale: 20
-}).setOptions({
- title: 'Gap-Filled NDVI Time Series',
- interpolateNulls: false,
- vAxis: {title: 'NDVI', viewWindow: {min: 0, max: 1}},
- hAxis: {title: '', format: 'YYYY-MM'},
- lineWidth: 1,
- pointSize: 4,
- series: {
- 0: {color: '#238b45'},
- },
- })
-print(chart);
-
-// Let's visualize the NDVI time-series
-Map.centerObject(geometry, 16);
-var bbox = Map.getBounds({asGeoJSON: true});
-
-var palette = ['#d73027','#f46d43','#fdae61','#fee08b','#ffffbf','#d9ef8b','#a6d96a','#66bd63','#1a9850'];
-var ndviVis = {min:-0.2, max: 0.8, palette: palette}
-
-var visualizeImage = function(image) {
- return image.visualize(ndviVis).clip(bbox).selfMask()
-}
-
-var visCollectionOriginal = originalCollection.select('ndvi')
- .map(visualizeImage)
-
-var visualizeIGapFilled = gapFilledCol.select('ndvi')
- .map(visualizeImage)
-
-
-Export.video.toDrive({
- collection: visCollectionOriginal,
- description: 'Original_Time_Series',
- folder: 'earthengine',
- fileNamePrefix: 'original',
- framesPerSecond: 2,
- dimensions: 800,
- region: bbox})
-
-Export.video.toDrive({
- collection: visualizeIGapFilled,
- description: 'Gap_Filled_Time_Series',
- folder: 'earthengine',
- fileNamePrefix: 'gap_filled',
- framesPerSecond: 2,
- dimensions: 800,
- region: bbox})
The code below shows how to do temporal gap-filling of time-series +data. A detailed explanation of the code and other examples are +described in our blog post Temporal Gap-Filling with Linear Interpolation in +GEE.
+ +// Temporal Interpolation (Gap-Filling Masked Pixels)
+var s2 = ee.ImageCollection('COPERNICUS/S2_HARMONIZED');
+var geometry = ee.Geometry.Point([74.80368345518073, 30.391793042969]);
+
+var startDate = ee.Date.fromYMD(2019, 1, 1);
+var endDate = ee.Date.fromYMD(2021, 1, 1);
+
+// Function to add a NDVI band to an image
+function addNDVI(image) {
+ var ndvi = image.normalizedDifference(['B8', 'B4']).rename('ndvi');
+ return image.addBands(ndvi);
+}
+
+// Function to mask clouds
+function maskS2clouds(image) {
+ var qa = image.select('QA60')
+ var cloudBitMask = 1 << 10;
+ var cirrusBitMask = 1 << 11;
+ var mask = qa.bitwiseAnd(cloudBitMask).eq(0).and(
+ qa.bitwiseAnd(cirrusBitMask).eq(0))
+ return image.updateMask(mask).divide(10000)
+ .select("B.*")
+ .copyProperties(image, ["system:time_start"])
+}
+
+var originalCollection = s2
+ .filter(ee.Filter.date(startDate, endDate))
+ .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 30))
+ .filter(ee.Filter.bounds(geometry))
+ .map(maskS2clouds)
+ .map(addNDVI);
+
+
+// Display a time-series chart
+var chart = ui.Chart.image.series({
+ imageCollection: originalCollection.select('ndvi'),
+ region: geometry,
+ reducer: ee.Reducer.mean(),
+ scale: 20
+}).setOptions({
+ title: 'Original NDVI Time Series',
+ interpolateNulls: false,
+ vAxis: {title: 'NDVI', viewWindow: {min: 0, max: 1}},
+ hAxis: {title: '', format: 'YYYY-MM'},
+ lineWidth: 1,
+ pointSize: 4,
+ series: {
+ 0: {color: '#238b45'},
+ },
+
+ })
+print(chart);
+
+// Gap-filling
+
+// Add a band containing timestamp to each image
+// This will be used to do pixel-wise interpolation later
+var originalCollection = originalCollection.map(function(image) {
+ var timeImage = image.metadata('system:time_start').rename('timestamp')
+ // The time image doesn't have a mask.
+ // We set the mask of the time band to be the same as the first band of the image
+ var timeImageMasked = timeImage.updateMask(image.mask().select(0))
+ return image.addBands(timeImageMasked).toFloat();
+})
+
+// For each image in the collection, we need to find all images
+// before and after the specified time-window
+
+// This is accomplished using Joins
+// We need to do 2 joins
+// Join 1: Join the collection with itself to find all images before each image
+// Join 2: Join the collection with itself to find all images after each image
+
+// We first define the filters needed for the join
+
+// Define a maxDifference filter to find all images within the specified days
+// The filter needs the time difference in milliseconds
+// Convert days to milliseconds
+
+// Specify the time-window to look for unmasked pixel
+var days = 45;
+var millis = ee.Number(days).multiply(1000*60*60*24)
+
+var maxDiffFilter = ee.Filter.maxDifference({
+ difference: millis,
+ leftField: 'system:time_start',
+ rightField: 'system:time_start'
+})
+
+// We need a lessThanOrEquals filter to find all images after a given image
+// This will compare the given image's timestamp against other images' timestamps
+var lessEqFilter = ee.Filter.lessThanOrEquals({
+ leftField: 'system:time_start',
+ rightField: 'system:time_start'
+})
+
+// We need a greaterThanOrEquals filter to find all images before a given image
+// This will compare the given image's timestamp against other images' timestamps
+var greaterEqFilter = ee.Filter.greaterThanOrEquals({
+ leftField: 'system:time_start',
+ rightField: 'system:time_start'
+})
+
+
+// Apply the joins
+
+// For the first join, we need to match all images that are after the given image.
+// To do this we need to match 2 conditions
+// 1. The resulting images must be within the specified time-window of target image
+// 2. The target image's timestamp must be lesser than the timestamp of resulting images
+// Combine two filters to match both these conditions
+var filter1 = ee.Filter.and(maxDiffFilter, lessEqFilter)
+// This join will find all images after, sorted in descending order
+// This will gives us images so that closest is last
+var join1 = ee.Join.saveAll({
+ matchesKey: 'after',
+ ordering: 'system:time_start',
+ ascending: false})
+
+var join1Result = join1.apply({
+ primary: originalCollection,
+ secondary: originalCollection,
+ condition: filter1
+})
+// Each image now as a property called 'after' containing
+// all images that come after it within the time-window
+print(join1Result.first())
+
+// Do the second join now to match all images within the time-window
+// that come before each image
+var filter2 = ee.Filter.and(maxDiffFilter, greaterEqFilter)
+// This join will find all images before, sorted in ascending order
+// This will gives us images so that closest is last
+var join2 = ee.Join.saveAll({
+ matchesKey: 'before',
+ ordering: 'system:time_start',
+ ascending: true})
+
+var join2Result = join2.apply({
+ primary: join1Result,
+ secondary: join1Result,
+ condition: filter2
+})
+
+var joinedCol = join2Result;
+
+// Each image now as a property called 'before' containing
+// all images that come after it within the time-window
+print(joinedCol.first())
+// Do the gap-filling
+
+// We now write a function that will be used to interpolate all images
+// This function takes an image and replaces the masked pixels
+// with the interpolated value from before and after images.
+
+var interpolateImages = function(image) {
+ var image = ee.Image(image);
+ // We get the list of before and after images from the image property
+ // Mosaic the images so we a before and after image with the closest unmasked pixel
+ var beforeImages = ee.List(image.get('before'))
+ var beforeMosaic = ee.ImageCollection.fromImages(beforeImages).mosaic()
+ var afterImages = ee.List(image.get('after'))
+ var afterMosaic = ee.ImageCollection.fromImages(afterImages).mosaic()
+
+ // Interpolation formula
+ // y = y1 + (y2-y1)*((t – t1) / (t2 – t1))
+ // y = interpolated image
+ // y1 = before image
+ // y2 = after image
+ // t = interpolation timestamp
+ // t1 = before image timestamp
+ // t2 = after image timestamp
+
+ // We first compute the ratio (t – t1) / (t2 – t1)
+
+ // Get image with before and after times
+ var t1 = beforeMosaic.select('timestamp').rename('t1')
+ var t2 = afterMosaic.select('timestamp').rename('t2')
+
+ var t = image.metadata('system:time_start').rename('t')
+
+ var timeImage = ee.Image.cat([t1, t2, t])
+
+ var timeRatio = timeImage.expression('(t - t1) / (t2 - t1)', {
+ 't': timeImage.select('t'),
+ 't1': timeImage.select('t1'),
+ 't2': timeImage.select('t2'),
+ })
+ // You can replace timeRatio with a constant value 0.5
+ // if you wanted a simple average
+
+ // Compute an image with the interpolated image y
+ var interpolated = beforeMosaic
+ .add((afterMosaic.subtract(beforeMosaic).multiply(timeRatio)))
+ // Replace the masked pixels in the current image with the average value
+ var result = image.unmask(interpolated)
+ return result.copyProperties(image, ['system:time_start'])
+}
+
+// map() the function to gap-fill all images in the collection
+var gapFilledCol = ee.ImageCollection(joinedCol.map(interpolateImages))
+
+// Display a time-series chart
+var chart = ui.Chart.image.series({
+ imageCollection: gapFilledCol.select('ndvi'),
+ region: geometry,
+ reducer: ee.Reducer.mean(),
+ scale: 20
+}).setOptions({
+ title: 'Gap-Filled NDVI Time Series',
+ interpolateNulls: false,
+ vAxis: {title: 'NDVI', viewWindow: {min: 0, max: 1}},
+ hAxis: {title: '', format: 'YYYY-MM'},
+ lineWidth: 1,
+ pointSize: 4,
+ series: {
+ 0: {color: '#238b45'},
+ },
+ })
+print(chart);
+
+// Let's visualize the NDVI time-series
+Map.centerObject(geometry, 16);
+var bbox = Map.getBounds({asGeoJSON: true});
+
+var palette = ['#d73027','#f46d43','#fdae61','#fee08b','#ffffbf','#d9ef8b','#a6d96a','#66bd63','#1a9850'];
+var ndviVis = {min:-0.2, max: 0.8, palette: palette}
+
+var visualizeImage = function(image) {
+ return image.visualize(ndviVis).clip(bbox).selfMask()
+}
+
+var visCollectionOriginal = originalCollection.select('ndvi')
+ .map(visualizeImage)
+
+var visualizeIGapFilled = gapFilledCol.select('ndvi')
+ .map(visualizeImage)
+
+
+Export.video.toDrive({
+ collection: visCollectionOriginal,
+ description: 'Original_Time_Series',
+ folder: 'earthengine',
+ fileNamePrefix: 'original',
+ framesPerSecond: 2,
+ dimensions: 800,
+ region: bbox})
+
+Export.video.toDrive({
+ collection: visualizeIGapFilled,
+ description: 'Gap_Filled_Time_Series',
+ folder: 'earthengine',
+ fileNamePrefix: 'gap_filled',
+ framesPerSecond: 2,
+ dimensions: 800,
+ region: bbox})
// Aplying Savitzky-Golay Filter on a NDVI Time-Series
-// This script uses the OEEL library to apply a
-// Savitzky-Golay filter on a imagecollection
-
-// We require a regularly-spaced time-series without
-// any masked pixels. So this script applies
-// linear interpolation to created regularly spaced images
-// from the original time-series
-
-// Step-1: Prepare a NDVI Time-Series
-// Step-2: Create an empty Time-Series with images at n days
-// Step-3: Use Joins to find before/after images
-// Step-4: Apply linear interpolation to fill each image
-// Step-5: Apply Savitzky-Golay filter
-// Step-6: Visualize the results
-
-var s2 = ee.ImageCollection('COPERNICUS/S2_HARMONIZED');
-var geometry = ee.Geometry.Point([74.80368345518073, 30.391793042969]);
-
-var startDate = ee.Date.fromYMD(2019, 1, 1);
-var endDate = ee.Date.fromYMD(2021, 1, 1);
-
-// Function to add a NDVI band to an image
-function addNDVI(image) {
- var ndvi = image.normalizedDifference(['B8', 'B4']).rename('ndvi');
- return image.addBands(ndvi);
-}
-
-// Function to mask clouds
-function maskS2clouds(image) {
- var qa = image.select('QA60')
- var cloudBitMask = 1 << 10;
- var cirrusBitMask = 1 << 11;
- var mask = qa.bitwiseAnd(cloudBitMask).eq(0).and(
- qa.bitwiseAnd(cirrusBitMask).eq(0))
- return image.updateMask(mask).divide(10000)
- .select("B.*")
- .copyProperties(image, ["system:time_start"])
-}
-
-var originalCollection = s2
- .filter(ee.Filter.date(startDate, endDate))
- .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 30))
- .filter(ee.Filter.bounds(geometry))
- .map(maskS2clouds)
- .map(addNDVI);
-
-
-// Display a time-series chart
-var chart = ui.Chart.image.series({
- imageCollection: originalCollection.select('ndvi'),
- region: geometry,
- reducer: ee.Reducer.mean(),
- scale: 20
-}).setOptions({
- title: 'Original NDVI Time Series',
- interpolateNulls: false,
- vAxis: {title: 'NDVI', viewWindow: {min: 0, max: 1}},
- hAxis: {title: '', format: 'YYYY-MM'},
- lineWidth: 1,
- pointSize: 4,
- series: {
- 0: {color: '#238b45'},
- },
-
- })
-print(chart);
-
-// Prepare a regularly-spaced Time-Series
-
-// Generate an empty multi-band image matching the bands
-// in the original collection
-var bandNames = ee.Image(originalCollection.first()).bandNames();
-var numBands = bandNames.size();
-var initBands = ee.List.repeat(ee.Image(), numBands);
-var initImage = ee.ImageCollection(initBands).toBands().rename(bandNames)
-
-// Select the interval. We will have 1 image every n days
-var n = 5;
-var firstImage = ee.Image(originalCollection.sort('system:time_start').first())
-var lastImage = ee.Image(originalCollection.sort('system:time_start', false).first())
-var timeStart = ee.Date(firstImage.get('system:time_start'))
-var timeEnd = ee.Date(lastImage.get('system:time_start'))
-
-var totalDays = timeEnd.difference(timeStart, 'day');
-var daysToInterpolate = ee.List.sequence(0, totalDays, n)
-
-var initImages = daysToInterpolate.map(function(day) {
- var image = initImage.set({
- 'system:index': ee.Number(day).format('%d'),
- 'system:time_start': timeStart.advance(day, 'day').millis(),
- // Set a property so we can identify interpolated images
- 'type': 'interpolated'
- })
- return image
-})
-
-var initCol = ee.ImageCollection.fromImages(initImages)
-print('Empty Collection', initCol)
-
-// Merge original and empty collections
-var originalCollection = originalCollection.merge(initCol)
-
-// Interpolation
-
-// Add a band containing timestamp to each image
-// This will be used to do pixel-wise interpolation later
-var originalCollection = originalCollection.map(function(image) {
- var timeImage = image.metadata('system:time_start').rename('timestamp')
- // The time image doesn't have a mask.
- // We set the mask of the time band to be the same as the first band of the image
- var timeImageMasked = timeImage.updateMask(image.mask().select(0))
- return image.addBands(timeImageMasked).toFloat();
-})
-
-// For each image in the collection, we need to find all images
-// before and after the specified time-window
-
-// This is accomplished using Joins
-// We need to do 2 joins
-// Join 1: Join the collection with itself to find all images before each image
-// Join 2: Join the collection with itself to find all images after each image
-
-// We first define the filters needed for the join
-
-// Define a maxDifference filter to find all images within the specified days
-// The filter needs the time difference in milliseconds
-// Convert days to milliseconds
-
-// Specify the time-window to look for unmasked pixel
-var days = 45;
-var millis = ee.Number(days).multiply(1000*60*60*24)
-
-var maxDiffFilter = ee.Filter.maxDifference({
- difference: millis,
- leftField: 'system:time_start',
- rightField: 'system:time_start'
-})
-
-// We need a lessThanOrEquals filter to find all images after a given image
-// This will compare the given image's timestamp against other images' timestamps
-var lessEqFilter = ee.Filter.lessThanOrEquals({
- leftField: 'system:time_start',
- rightField: 'system:time_start'
-})
-
-// We need a greaterThanOrEquals filter to find all images before a given image
-// This will compare the given image's timestamp against other images' timestamps
-var greaterEqFilter = ee.Filter.greaterThanOrEquals({
- leftField: 'system:time_start',
- rightField: 'system:time_start'
-})
-
-
-// Apply the joins
-
-// For the first join, we need to match all images that are after the given image.
-// To do this we need to match 2 conditions
-// 1. The resulting images must be within the specified time-window of target image
-// 2. The target image's timestamp must be lesser than the timestamp of resulting images
-// Combine two filters to match both these conditions
-var filter1 = ee.Filter.and(maxDiffFilter, lessEqFilter)
-// This join will find all images after, sorted in descending order
-// This will gives us images so that closest is last
-var join1 = ee.Join.saveAll({
- matchesKey: 'after',
- ordering: 'system:time_start',
- ascending: false})
-
-var join1Result = join1.apply({
- primary: originalCollection,
- secondary: originalCollection,
- condition: filter1
-})
-// Each image now as a property called 'after' containing
-// all images that come after it within the time-window
-print(join1Result.first())
-
-// Do the second join now to match all images within the time-window
-// that come before each image
-var filter2 = ee.Filter.and(maxDiffFilter, greaterEqFilter)
-// This join will find all images before, sorted in ascending order
-// This will gives us images so that closest is last
-var join2 = ee.Join.saveAll({
- matchesKey: 'before',
- ordering: 'system:time_start',
- ascending: true})
-
-var join2Result = join2.apply({
- primary: join1Result,
- secondary: join1Result,
- condition: filter2
-})
-
-// Each image now as a property called 'before' containing
-// all images that come after it within the time-window
-print(join2Result.first())
-
-var joinedCol = join2Result;
-
-// Do the interpolation
-
-// We now write a function that will be used to interpolate all images
-// This function takes an image and replaces the masked pixels
-// with the interpolated value from before and after images.
-
-var interpolateImages = function(image) {
- var image = ee.Image(image);
- // We get the list of before and after images from the image property
- // Mosaic the images so we a before and after image with the closest unmasked pixel
- var beforeImages = ee.List(image.get('before'))
- var beforeMosaic = ee.ImageCollection.fromImages(beforeImages).mosaic()
- var afterImages = ee.List(image.get('after'))
- var afterMosaic = ee.ImageCollection.fromImages(afterImages).mosaic()
-
- // Interpolation formula
- // y = y1 + (y2-y1)*((t – t1) / (t2 – t1))
- // y = interpolated image
- // y1 = before image
- // y2 = after image
- // t = interpolation timestamp
- // t1 = before image timestamp
- // t2 = after image timestamp
-
- // We first compute the ratio (t – t1) / (t2 – t1)
-
- // Get image with before and after times
- var t1 = beforeMosaic.select('timestamp').rename('t1')
- var t2 = afterMosaic.select('timestamp').rename('t2')
-
- var t = image.metadata('system:time_start').rename('t')
-
- var timeImage = ee.Image.cat([t1, t2, t])
-
- var timeRatio = timeImage.expression('(t - t1) / (t2 - t1)', {
- 't': timeImage.select('t'),
- 't1': timeImage.select('t1'),
- 't2': timeImage.select('t2'),
- })
- // You can replace timeRatio with a constant value 0.5
- // if you wanted a simple average
-
- // Compute an image with the interpolated image y
- var interpolated = beforeMosaic
- .add((afterMosaic.subtract(beforeMosaic).multiply(timeRatio)))
- // Replace the masked pixels in the current image with the average value
- var result = image.unmask(interpolated)
- return result.copyProperties(image, ['system:time_start'])
-}
-
-// map() the function to interpolate all images in the collection
-var interpolatedCol = ee.ImageCollection(joinedCol.map(interpolateImages))
-
-// Once the interpolation are done, remove original images
-// We keep only the generated interpolated images
-var regularCol = interpolatedCol.filter(ee.Filter.eq('type', 'interpolated'))
-
-
-// Display a time-series chart
-var chart = ui.Chart.image.series({
- imageCollection: regularCol.select('ndvi'),
- region: geometry,
- reducer: ee.Reducer.mean(),
- scale: 20
-}).setOptions({
- title: 'Regular NDVI Time Series',
- interpolateNulls: false,
- vAxis: {title: 'NDVI', viewWindow: {min: 0, max: 1}},
- hAxis: {title: '', format: 'YYYY-MM'},
- lineWidth: 1,
- pointSize: 4,
- series: {
- 0: {color: '#238b45'},
- },
- })
-print(chart);
-
-
-// SavatskyGolayFilter
-// https://www.open-geocomputing.org/OpenEarthEngineLibrary/#.ImageCollection.SavatskyGolayFilter
-
-// Use the default distanceFunction
-var distanceFunction = function(infromedImage, estimationImage) {
- return ee.Image.constant(
- ee.Number(infromedImage.get('system:time_start'))
- .subtract(
- ee.Number(estimationImage.get('system:time_start')))
- );
- }
-
-// Apply smoothing
-
-var oeel=require('users/OEEL/lib:loadAll');
-
-var order = 3;
-
-var sgFilteredCol = oeel.ImageCollection.SavatskyGolayFilter(
- regularCol,
- maxDiffFilter,
- distanceFunction,
- order)
-
-print(sgFilteredCol.first())
-// Display a time-series chart
-var chart = ui.Chart.image.series({
- imageCollection: sgFilteredCol.select(['ndvi', 'd_0_ndvi'], ['ndvi', 'ndvi_sg']),
- region: geometry,
- reducer: ee.Reducer.mean(),
- scale: 20
-}).setOptions({
- lineWidth: 1,
- title: 'NDVI Time Series',
- interpolateNulls: false,
- vAxis: {title: 'NDVI', viewWindow: {min: 0, max: 1}},
- hAxis: {title: '', format: 'YYYY-MM'},
- lineWidth: 1,
- pointSize: 4,
- series: {
- 0: {color: '#66c2a4', lineDashStyle: [1, 1], pointSize: 2}, // Original NDVI
- 1: {color: '#238b45', lineWidth: 2 }, // Smoothed NDVI
- },
-
- })
-print(chart);
-
-
-// Let's visualize the NDVI time-series
-Map.centerObject(geometry, 16);
-var bbox = Map.getBounds({asGeoJSON: true});
-
-var palette = ['#d73027','#f46d43','#fdae61','#fee08b','#ffffbf','#d9ef8b','#a6d96a','#66bd63','#1a9850'];
-var ndviVis = {min:-0.2, max: 0.8, palette: palette}
-
-var visualizeImage = function(image) {
- return image.visualize(ndviVis).clip(bbox).selfMask()
-}
-
-var visCollectionRegular = regularCol.select('ndvi')
- .map(visualizeImage)
-
-var visualizeSgFiltered = sgFilteredCol.select('d_0_ndvi')
- .map(visualizeImage)
-
-
-Export.video.toDrive({
- collection: visCollectionRegular,
- description: 'Regular_Time_Series',
- folder: 'earthengine',
- fileNamePrefix: 'regular',
- framesPerSecond: 2,
- dimensions: 800,
- region: bbox})
-
-Export.video.toDrive({
- collection: visualizeSgFiltered,
- description: 'Filtered_Time_Series',
- folder: 'earthengine',
- fileNamePrefix: 'sg_filtered',
- framesPerSecond: 2,
- dimensions: 800,
- region: bbox})
// Aplying Savitzky-Golay Filter on a NDVI Time-Series
+// This script uses the OEEL library to apply a
+// Savitzky-Golay filter on a imagecollection
+
+// We require a regularly-spaced time-series without
+// any masked pixels. So this script applies
+// linear interpolation to created regularly spaced images
+// from the original time-series
+
+// Step-1: Prepare a NDVI Time-Series
+// Step-2: Create an empty Time-Series with images at n days
+// Step-3: Use Joins to find before/after images
+// Step-4: Apply linear interpolation to fill each image
+// Step-5: Apply Savitzky-Golay filter
+// Step-6: Visualize the results
+
+var s2 = ee.ImageCollection('COPERNICUS/S2_HARMONIZED');
+var geometry = ee.Geometry.Point([74.80368345518073, 30.391793042969]);
+
+var startDate = ee.Date.fromYMD(2019, 1, 1);
+var endDate = ee.Date.fromYMD(2021, 1, 1);
+
+// Function to add a NDVI band to an image
+function addNDVI(image) {
+ var ndvi = image.normalizedDifference(['B8', 'B4']).rename('ndvi');
+ return image.addBands(ndvi);
+}
+
+// Function to mask clouds
+function maskS2clouds(image) {
+ var qa = image.select('QA60')
+ var cloudBitMask = 1 << 10;
+ var cirrusBitMask = 1 << 11;
+ var mask = qa.bitwiseAnd(cloudBitMask).eq(0).and(
+ qa.bitwiseAnd(cirrusBitMask).eq(0))
+ return image.updateMask(mask).divide(10000)
+ .select("B.*")
+ .copyProperties(image, ["system:time_start"])
+}
+
+var originalCollection = s2
+ .filter(ee.Filter.date(startDate, endDate))
+ .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 30))
+ .filter(ee.Filter.bounds(geometry))
+ .map(maskS2clouds)
+ .map(addNDVI);
+
+
+// Display a time-series chart
+var chart = ui.Chart.image.series({
+ imageCollection: originalCollection.select('ndvi'),
+ region: geometry,
+ reducer: ee.Reducer.mean(),
+ scale: 20
+}).setOptions({
+ title: 'Original NDVI Time Series',
+ interpolateNulls: false,
+ vAxis: {title: 'NDVI', viewWindow: {min: 0, max: 1}},
+ hAxis: {title: '', format: 'YYYY-MM'},
+ lineWidth: 1,
+ pointSize: 4,
+ series: {
+ 0: {color: '#238b45'},
+ },
+
+ })
+print(chart);
+
+// Prepare a regularly-spaced Time-Series
+
+// Generate an empty multi-band image matching the bands
+// in the original collection
+var bandNames = ee.Image(originalCollection.first()).bandNames();
+var numBands = bandNames.size();
+var initBands = ee.List.repeat(ee.Image(), numBands);
+var initImage = ee.ImageCollection(initBands).toBands().rename(bandNames)
+
+// Select the interval. We will have 1 image every n days
+var n = 5;
+var firstImage = ee.Image(originalCollection.sort('system:time_start').first())
+var lastImage = ee.Image(originalCollection.sort('system:time_start', false).first())
+var timeStart = ee.Date(firstImage.get('system:time_start'))
+var timeEnd = ee.Date(lastImage.get('system:time_start'))
+
+var totalDays = timeEnd.difference(timeStart, 'day');
+var daysToInterpolate = ee.List.sequence(0, totalDays, n)
+
+var initImages = daysToInterpolate.map(function(day) {
+ var image = initImage.set({
+ 'system:index': ee.Number(day).format('%d'),
+ 'system:time_start': timeStart.advance(day, 'day').millis(),
+ // Set a property so we can identify interpolated images
+ 'type': 'interpolated'
+ })
+ return image
+})
+
+var initCol = ee.ImageCollection.fromImages(initImages)
+print('Empty Collection', initCol)
+
+// Merge original and empty collections
+var originalCollection = originalCollection.merge(initCol)
+
+// Interpolation
+
+// Add a band containing timestamp to each image
+// This will be used to do pixel-wise interpolation later
+var originalCollection = originalCollection.map(function(image) {
+ var timeImage = image.metadata('system:time_start').rename('timestamp')
+ // The time image doesn't have a mask.
+ // We set the mask of the time band to be the same as the first band of the image
+ var timeImageMasked = timeImage.updateMask(image.mask().select(0))
+ return image.addBands(timeImageMasked).toFloat();
+})
+
+// For each image in the collection, we need to find all images
+// before and after the specified time-window
+
+// This is accomplished using Joins
+// We need to do 2 joins
+// Join 1: Join the collection with itself to find all images before each image
+// Join 2: Join the collection with itself to find all images after each image
+
+// We first define the filters needed for the join
+
+// Define a maxDifference filter to find all images within the specified days
+// The filter needs the time difference in milliseconds
+// Convert days to milliseconds
+
+// Specify the time-window to look for unmasked pixel
+var days = 45;
+var millis = ee.Number(days).multiply(1000*60*60*24)
+
+var maxDiffFilter = ee.Filter.maxDifference({
+ difference: millis,
+ leftField: 'system:time_start',
+ rightField: 'system:time_start'
+})
+
+// We need a lessThanOrEquals filter to find all images after a given image
+// This will compare the given image's timestamp against other images' timestamps
+var lessEqFilter = ee.Filter.lessThanOrEquals({
+ leftField: 'system:time_start',
+ rightField: 'system:time_start'
+})
+
+// We need a greaterThanOrEquals filter to find all images before a given image
+// This will compare the given image's timestamp against other images' timestamps
+var greaterEqFilter = ee.Filter.greaterThanOrEquals({
+ leftField: 'system:time_start',
+ rightField: 'system:time_start'
+})
+
+
+// Apply the joins
+
+// For the first join, we need to match all images that are after the given image.
+// To do this we need to match 2 conditions
+// 1. The resulting images must be within the specified time-window of target image
+// 2. The target image's timestamp must be lesser than the timestamp of resulting images
+// Combine two filters to match both these conditions
+var filter1 = ee.Filter.and(maxDiffFilter, lessEqFilter)
+// This join will find all images after, sorted in descending order
+// This will gives us images so that closest is last
+var join1 = ee.Join.saveAll({
+ matchesKey: 'after',
+ ordering: 'system:time_start',
+ ascending: false})
+
+var join1Result = join1.apply({
+ primary: originalCollection,
+ secondary: originalCollection,
+ condition: filter1
+})
+// Each image now as a property called 'after' containing
+// all images that come after it within the time-window
+print(join1Result.first())
+
+// Do the second join now to match all images within the time-window
+// that come before each image
+var filter2 = ee.Filter.and(maxDiffFilter, greaterEqFilter)
+// This join will find all images before, sorted in ascending order
+// This will gives us images so that closest is last
+var join2 = ee.Join.saveAll({
+ matchesKey: 'before',
+ ordering: 'system:time_start',
+ ascending: true})
+
+var join2Result = join2.apply({
+ primary: join1Result,
+ secondary: join1Result,
+ condition: filter2
+})
+
+// Each image now as a property called 'before' containing
+// all images that come after it within the time-window
+print(join2Result.first())
+
+var joinedCol = join2Result;
+
+// Do the interpolation
+
+// We now write a function that will be used to interpolate all images
+// This function takes an image and replaces the masked pixels
+// with the interpolated value from before and after images.
+
+var interpolateImages = function(image) {
+ var image = ee.Image(image);
+ // We get the list of before and after images from the image property
+ // Mosaic the images so we a before and after image with the closest unmasked pixel
+ var beforeImages = ee.List(image.get('before'))
+ var beforeMosaic = ee.ImageCollection.fromImages(beforeImages).mosaic()
+ var afterImages = ee.List(image.get('after'))
+ var afterMosaic = ee.ImageCollection.fromImages(afterImages).mosaic()
+
+ // Interpolation formula
+ // y = y1 + (y2-y1)*((t – t1) / (t2 – t1))
+ // y = interpolated image
+ // y1 = before image
+ // y2 = after image
+ // t = interpolation timestamp
+ // t1 = before image timestamp
+ // t2 = after image timestamp
+
+ // We first compute the ratio (t – t1) / (t2 – t1)
+
+ // Get image with before and after times
+ var t1 = beforeMosaic.select('timestamp').rename('t1')
+ var t2 = afterMosaic.select('timestamp').rename('t2')
+
+ var t = image.metadata('system:time_start').rename('t')
+
+ var timeImage = ee.Image.cat([t1, t2, t])
+
+ var timeRatio = timeImage.expression('(t - t1) / (t2 - t1)', {
+ 't': timeImage.select('t'),
+ 't1': timeImage.select('t1'),
+ 't2': timeImage.select('t2'),
+ })
+ // You can replace timeRatio with a constant value 0.5
+ // if you wanted a simple average
+
+ // Compute an image with the interpolated image y
+ var interpolated = beforeMosaic
+ .add((afterMosaic.subtract(beforeMosaic).multiply(timeRatio)))
+ // Replace the masked pixels in the current image with the average value
+ var result = image.unmask(interpolated)
+ return result.copyProperties(image, ['system:time_start'])
+}
+
+// map() the function to interpolate all images in the collection
+var interpolatedCol = ee.ImageCollection(joinedCol.map(interpolateImages))
+
+// Once the interpolation are done, remove original images
+// We keep only the generated interpolated images
+var regularCol = interpolatedCol.filter(ee.Filter.eq('type', 'interpolated'))
+
+
+// Display a time-series chart
+var chart = ui.Chart.image.series({
+ imageCollection: regularCol.select('ndvi'),
+ region: geometry,
+ reducer: ee.Reducer.mean(),
+ scale: 20
+}).setOptions({
+ title: 'Regular NDVI Time Series',
+ interpolateNulls: false,
+ vAxis: {title: 'NDVI', viewWindow: {min: 0, max: 1}},
+ hAxis: {title: '', format: 'YYYY-MM'},
+ lineWidth: 1,
+ pointSize: 4,
+ series: {
+ 0: {color: '#238b45'},
+ },
+ })
+print(chart);
+
+
+// SavatskyGolayFilter
+// https://www.open-geocomputing.org/OpenEarthEngineLibrary/#.ImageCollection.SavatskyGolayFilter
+
+// Use the default distanceFunction
+var distanceFunction = function(infromedImage, estimationImage) {
+ return ee.Image.constant(
+ ee.Number(infromedImage.get('system:time_start'))
+ .subtract(
+ ee.Number(estimationImage.get('system:time_start')))
+ );
+ }
+
+// Apply smoothing
+
+var oeel=require('users/OEEL/lib:loadAll');
+
+var order = 3;
+
+var sgFilteredCol = oeel.ImageCollection.SavatskyGolayFilter(
+ regularCol,
+ maxDiffFilter,
+ distanceFunction,
+ order)
+
+print(sgFilteredCol.first())
+// Display a time-series chart
+var chart = ui.Chart.image.series({
+ imageCollection: sgFilteredCol.select(['ndvi', 'd_0_ndvi'], ['ndvi', 'ndvi_sg']),
+ region: geometry,
+ reducer: ee.Reducer.mean(),
+ scale: 20
+}).setOptions({
+ lineWidth: 1,
+ title: 'NDVI Time Series',
+ interpolateNulls: false,
+ vAxis: {title: 'NDVI', viewWindow: {min: 0, max: 1}},
+ hAxis: {title: '', format: 'YYYY-MM'},
+ lineWidth: 1,
+ pointSize: 4,
+ series: {
+ 0: {color: '#66c2a4', lineDashStyle: [1, 1], pointSize: 2}, // Original NDVI
+ 1: {color: '#238b45', lineWidth: 2 }, // Smoothed NDVI
+ },
+
+ })
+print(chart);
+
+
+// Let's visualize the NDVI time-series
+Map.centerObject(geometry, 16);
+var bbox = Map.getBounds({asGeoJSON: true});
+
+var palette = ['#d73027','#f46d43','#fdae61','#fee08b','#ffffbf','#d9ef8b','#a6d96a','#66bd63','#1a9850'];
+var ndviVis = {min:-0.2, max: 0.8, palette: palette}
+
+var visualizeImage = function(image) {
+ return image.visualize(ndviVis).clip(bbox).selfMask()
+}
+
+var visCollectionRegular = regularCol.select('ndvi')
+ .map(visualizeImage)
+
+var visualizeSgFiltered = sgFilteredCol.select('d_0_ndvi')
+ .map(visualizeImage)
+
+
+Export.video.toDrive({
+ collection: visCollectionRegular,
+ description: 'Regular_Time_Series',
+ folder: 'earthengine',
+ fileNamePrefix: 'regular',
+ framesPerSecond: 2,
+ dimensions: 800,
+ region: bbox})
+
+Export.video.toDrive({
+ collection: visualizeSgFiltered,
+ description: 'Filtered_Time_Series',
+ folder: 'earthengine',
+ fileNamePrefix: 'sg_filtered',
+ framesPerSecond: 2,
+ dimensions: 800,
+ region: bbox})
var classified = ee.Image("users/ujavalgandhi/e2e/bangalore_classified")
-Map.centerObject(classified)
-var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40'];
-Map.addLayer(classified, {min: 0, max: 3, palette: palette}, '2019');
-
-var legend = ui.Panel({style: {position: 'middle-right', padding: '8px 15px'}});
-
-var makeRow = function(color, name) {
- var colorBox = ui.Label({
- style: {color: '#ffffff',
- backgroundColor: color,
- padding: '10px',
- margin: '0 0 4px 0',
- }
- });
- var description = ui.Label({
- value: name,
- style: {
- margin: '0px 0 4px 6px',
- }
- });
- return ui.Panel({
- widgets: [colorBox, description],
- layout: ui.Panel.Layout.Flow('horizontal')}
-)};
-
-var title = ui.Label({
- value: 'Legend',
- style: {fontWeight: 'bold',
- fontSize: '16px',
- margin: '0px 0 4px 0px'}});
-
-legend.add(title);
-legend.add(makeRow('#cc6d8f','Built-up'))
-legend.add(makeRow('#ffc107','Bare Earth'))
-legend.add(makeRow('#1e88e5','Water'))
-legend.add(makeRow('#004d40','Vegetation'))
-
-Map.add(legend);
var classified = ee.Image("users/ujavalgandhi/e2e/bangalore_classified")
+Map.centerObject(classified)
+var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40'];
+Map.addLayer(classified, {min: 0, max: 3, palette: palette}, '2019');
+
+var legend = ui.Panel({style: {position: 'middle-right', padding: '8px 15px'}});
+
+var makeRow = function(color, name) {
+ var colorBox = ui.Label({
+ style: {color: '#ffffff',
+ backgroundColor: color,
+ padding: '10px',
+ margin: '0 0 4px 0',
+ }
+ });
+ var description = ui.Label({
+ value: name,
+ style: {
+ margin: '0px 0 4px 6px',
+ }
+ });
+ return ui.Panel({
+ widgets: [colorBox, description],
+ layout: ui.Panel.Layout.Flow('horizontal')}
+)};
+
+var title = ui.Label({
+ value: 'Legend',
+ style: {fontWeight: 'bold',
+ fontSize: '16px',
+ margin: '0px 0 4px 0px'}});
+
+legend.add(title);
+legend.add(makeRow('#cc6d8f','Built-up'))
+legend.add(makeRow('#ffc107','Bare Earth'))
+legend.add(makeRow('#1e88e5','Water'))
+legend.add(makeRow('#004d40','Vegetation'))
+
+Map.add(legend);
var s2 = ee.ImageCollection("COPERNICUS/S2");
-var admin2 = ee.FeatureCollection("FAO/GAUL_SIMPLIFIED_500m/2015/level2");
-
-var bangalore = admin2.filter(ee.Filter.eq('ADM2_NAME', 'Bangalore Urban'))
-var geometry = bangalore.geometry()
-
-var filtered = s2.filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 30))
- .filter(ee.Filter.date('2019-01-01', '2020-01-01'))
- .filter(ee.Filter.bounds(geometry))
-
-var image = filtered.median();
-
-// Calculate Normalized Difference Vegetation Index (NDVI)
-// 'NIR' (B8) and 'RED' (B4)
-var ndvi = image.normalizedDifference(['B8', 'B4']).rename(['ndvi']);
-
-var palette = ['#d7191c','#fdae61','#ffffbf','#a6d96a','#1a9641']
-var ndviVis = {min:0, max:0.5, palette: palette}
-Map.centerObject(geometry, 12)
-Map.addLayer(ndvi.clip(geometry), ndviVis, 'ndvi')
-
-
-function createColorBar(titleText, palette, min, max) {
- // Legend Title
- var title = ui.Label({
- value: titleText,
- style: {fontWeight: 'bold', textAlign: 'center', stretch: 'horizontal'}});
-
- // Colorbar
- var legend = ui.Thumbnail({
- image: ee.Image.pixelLonLat().select(0),
- params: {
- bbox: [0, 0, 1, 0.1],
- dimensions: '200x20',
- format: 'png',
- min: 0, max: 1,
- palette: palette},
- style: {stretch: 'horizontal', margin: '8px 8px', maxHeight: '40px'},
- });
-
- // Legend Labels
- var labels = ui.Panel({
- widgets: [
- ui.Label(min, {margin: '4px 10px',textAlign: 'left', stretch: 'horizontal'}),
- ui.Label((min+max)/2, {margin: '4px 20px', textAlign: 'center', stretch: 'horizontal'}),
- ui.Label(max, {margin: '4px 10px',textAlign: 'right', stretch: 'horizontal'})],
- layout: ui.Panel.Layout.flow('horizontal')});
-
- // Create a panel with all 3 widgets
- var legendPanel = ui.Panel({
- widgets: [title, legend, labels],
- style: {position: 'bottom-center', padding: '8px 15px'}
- })
- return legendPanel
-}
-// Call the function to create a colorbar legend
-var colorBar = createColorBar('NDVI Values', palette, 0, 0.5)
-
-Map.add(colorBar)
var s2 = ee.ImageCollection("COPERNICUS/S2");
+var admin2 = ee.FeatureCollection("FAO/GAUL_SIMPLIFIED_500m/2015/level2");
+
+var bangalore = admin2.filter(ee.Filter.eq('ADM2_NAME', 'Bangalore Urban'))
+var geometry = bangalore.geometry()
+
+var filtered = s2.filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 30))
+ .filter(ee.Filter.date('2019-01-01', '2020-01-01'))
+ .filter(ee.Filter.bounds(geometry))
+
+var image = filtered.median();
+
+// Calculate Normalized Difference Vegetation Index (NDVI)
+// 'NIR' (B8) and 'RED' (B4)
+var ndvi = image.normalizedDifference(['B8', 'B4']).rename(['ndvi']);
+
+var palette = ['#d7191c','#fdae61','#ffffbf','#a6d96a','#1a9641']
+var ndviVis = {min:0, max:0.5, palette: palette}
+Map.centerObject(geometry, 12)
+Map.addLayer(ndvi.clip(geometry), ndviVis, 'ndvi')
+
+
+function createColorBar(titleText, palette, min, max) {
+ // Legend Title
+ var title = ui.Label({
+ value: titleText,
+ style: {fontWeight: 'bold', textAlign: 'center', stretch: 'horizontal'}});
+
+ // Colorbar
+ var legend = ui.Thumbnail({
+ image: ee.Image.pixelLonLat().select(0),
+ params: {
+ bbox: [0, 0, 1, 0.1],
+ dimensions: '200x20',
+ format: 'png',
+ min: 0, max: 1,
+ palette: palette},
+ style: {stretch: 'horizontal', margin: '8px 8px', maxHeight: '40px'},
+ });
+
+ // Legend Labels
+ var labels = ui.Panel({
+ widgets: [
+ ui.Label(min, {margin: '4px 10px',textAlign: 'left', stretch: 'horizontal'}),
+ ui.Label((min+max)/2, {margin: '4px 20px', textAlign: 'center', stretch: 'horizontal'}),
+ ui.Label(max, {margin: '4px 10px',textAlign: 'right', stretch: 'horizontal'})],
+ layout: ui.Panel.Layout.flow('horizontal')});
+
+ // Create a panel with all 3 widgets
+ var legendPanel = ui.Panel({
+ widgets: [title, legend, labels],
+ style: {position: 'bottom-center', padding: '8px 15px'}
+ })
+ return legendPanel
+}
+// Call the function to create a colorbar legend
+var colorBar = createColorBar('NDVI Values', palette, 0, 0.5)
+
+Map.add(colorBar)
// On June 9, 2018 - A massive dust storm hit North India
-// This example shows before and after imagery from Sentinel-2
-
-// Display two visualizations of a map.
-
-// Set a center and zoom level.
-var center = {lon: 77.47, lat: 28.41, zoom: 12};
-
-// Create two maps.
-var leftMap = ui.Map(center);
-var rightMap = ui.Map(center);
-
-// Remove UI controls from both maps, but leave zoom control on the left map.
-leftMap.setControlVisibility(false);
-rightMap.setControlVisibility(false);
-leftMap.setControlVisibility({zoomControl: true});
-
-// Link them together.
-var linker = new ui.Map.Linker([leftMap, rightMap]);
-
-// Create a split panel with the two maps.
-var splitPanel = ui.SplitPanel({
- firstPanel: leftMap,
- secondPanel: rightMap,
- orientation: 'horizontal',
- wipe: true
-});
-
-// Remove the default map from the root panel.
-ui.root.clear();
-
-// Add our split panel to the root panel.
-ui.root.add(splitPanel);
-
-var rgb_vis = {min: 0, max: 3200, bands: ['B4', 'B3', 'B2']};
-
-var preStorm = ee.Image('COPERNICUS/S2/20180604T052651_20180604T053435_T43RGM')
-var postStorm = ee.Image('COPERNICUS/S2/20180614T052651_20180614T053611_T43RGM')
-
-// Add a RGB Landsat 8 layer to the left map.
-leftMap.addLayer(preStorm, rgb_vis);
-rightMap.addLayer(postStorm, rgb_vis);
// On June 9, 2018 - A massive dust storm hit North India
+// This example shows before and after imagery from Sentinel-2
+
+// Display two visualizations of a map.
+
+// Set a center and zoom level.
+var center = {lon: 77.47, lat: 28.41, zoom: 12};
+
+// Create two maps.
+var leftMap = ui.Map(center);
+var rightMap = ui.Map(center);
+
+// Remove UI controls from both maps, but leave zoom control on the left map.
+leftMap.setControlVisibility(false);
+rightMap.setControlVisibility(false);
+leftMap.setControlVisibility({zoomControl: true});
+
+// Link them together.
+var linker = new ui.Map.Linker([leftMap, rightMap]);
+
+// Create a split panel with the two maps.
+var splitPanel = ui.SplitPanel({
+ firstPanel: leftMap,
+ secondPanel: rightMap,
+ orientation: 'horizontal',
+ wipe: true
+});
+
+// Remove the default map from the root panel.
+ui.root.clear();
+
+// Add our split panel to the root panel.
+ui.root.add(splitPanel);
+
+var rgb_vis = {min: 0, max: 3200, bands: ['B4', 'B3', 'B2']};
+
+var preStorm = ee.Image('COPERNICUS/S2/20180604T052651_20180604T053435_T43RGM')
+var postStorm = ee.Image('COPERNICUS/S2/20180614T052651_20180614T053611_T43RGM')
+
+// Add a RGB Landsat 8 layer to the left map.
+leftMap.addLayer(preStorm, rgb_vis);
+rightMap.addLayer(postStorm, rgb_vis);
var geometry = ee.Geometry.Point([77.5979, 13.00896]);
-Map.centerObject(geometry, 10)
-
-var s2 = ee.ImageCollection("COPERNICUS/S2")
-var rgbVis = {
- min: 0.0,
- max: 0.3,
- bands: ['B4', 'B3', 'B2'],
-};
-
-var palette = [
- 'FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163', '99B718',
- '74A901', '66A000', '529400', '3E8601', '207401', '056201',
- '004C00', '023B01', '012E01', '011D01', '011301'];
-
-var ndviVis = {min:0, max:0.5, palette: palette }
-
-
-// Write a function for Cloud masking
-function maskS2clouds(image) {
- var qa = image.select('QA60')
- var cloudBitMask = 1 << 10;
- var cirrusBitMask = 1 << 11;
- var mask = qa.bitwiseAnd(cloudBitMask).eq(0).and(
- qa.bitwiseAnd(cirrusBitMask).eq(0))
- return image.updateMask(mask).divide(10000)
- .select("B.*")
- .copyProperties(image, ["system:time_start"])
-}
-
-
-// Write a function that computes NDVI for an image and adds it as a band
-function addNDVI(image) {
- var ndvi = image.normalizedDifference(['B8', 'B4']).rename('ndvi');
- return image.addBands(ndvi);
-}
-
-function getComposite(geometry) {
- var filtered = s2
- .filter(ee.Filter.date('2019-01-01', '2019-12-31'))
- .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 30))
- .filter(ee.Filter.bounds(geometry))
- .map(maskS2clouds)
- // Map the function over the collection
- var withNdvi = filtered.map(addNDVI);
-
- var composite = withNdvi.median()
- return composite
-}
-
-
-// Create UI Elements
-var title = ui.Label('Global NDVI Explorer');
-title.style().set({
- 'position': 'top-center',
- 'fontSize': '24px'
- });
-var resultsPanel = ui.Panel();
-var chartPanel = ui.Panel();
-var selectionPanel = ui.Panel({
- layout: ui.Panel.Layout.flow('horizontal'),
-});
-
-resultsPanel.style().set({
- width: '400px',
- position: 'bottom-right'
-});
-
-var resetPanel = ui.Panel();
-
-
-resultsPanel.add(selectionPanel)
-resultsPanel.add(chartPanel)
-resultsPanel.add(resetPanel)
-
-// Function to reset the app to initial state
-var resetEverything = function() {
- chartPanel.clear()
- selectionPanel.clear()
- resetPanel.clear()
-
- Map.clear()
-
- Map.add(title);
- Map.add(resultsPanel)
- Map.onClick(displayChart)
- // Use the current viewport
- var bounds = ee.Geometry.Rectangle(Map.getBounds())
- var composite = getComposite(bounds)
- Map.addLayer(composite, rgbVis, 'Sentinel-2 Composite')
- var label = ui.Label('Click anywhere to see the chart')
- resetPanel.add(label)
-
-}
-
-// Function to create and display NDVI time-series chart
-var displayChart = function(point) {
- resetPanel.clear()
- var button = ui.Button({
- label: 'Reset',
- onClick: resetEverything})
- resetPanel.add(button)
- var geometry = ee.Geometry.Point(point['lon'], point['lat']);
-
- var filtered = s2
- .filter(ee.Filter.date('2019-01-01', '2019-12-31'))
- .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 50))
- .map(maskS2clouds)
- .map(addNDVI)
- .filter(ee.Filter.bounds(geometry))
-
- var chart = ui.Chart.image.series({
- imageCollection: filtered.select('ndvi'),
- region: geometry,
- reducer: ee.Reducer.mean(),
- scale: 20}).setOptions({
- title: 'NDVI Time Series',
- vAxis: {title: 'NDVI'},
- hAxis: {title: 'Date', gridlines: {count: 12}}
- })
-
- chartPanel.clear()
- selectionPanel.clear()
- selectionPanel.add(ui.Label('Choose an image to display:'))
- chartPanel.add(chart)
-
-
- var addNdviLayer = function(dateString) {
- var date = ee.Date.parse('YYYY-MM-dd', dateString)
- var image = ee.Image(filtered.filter(ee.Filter.date(date, date.advance(1, 'day'))).mosaic())
- Map.addLayer(image.select('ndvi'), ndviVis, 'NDVI Image -' + dateString)
- }
-
-
- filtered.aggregate_array('system:time_start').evaluate(function(ids) {
- var dates = ee.List(ids).distinct().map(function(timestamp) {
- return ee.Date(timestamp).format('YYYY-MM-dd')
- })
- dates.evaluate(function(dateList){
- selectionPanel.add(ui.Select({
- items: dateList,
- onChange: addNdviLayer,
- placeholder: 'Select a date'
- }))
- })
-
-});
-
-}
-// Call the function to build the initial UI state.
-resetEverything();
var geometry = ee.Geometry.Point([77.5979, 13.00896]);
+Map.centerObject(geometry, 10)
+
+var s2 = ee.ImageCollection("COPERNICUS/S2")
+var rgbVis = {
+ min: 0.0,
+ max: 0.3,
+ bands: ['B4', 'B3', 'B2'],
+};
+
+var palette = [
+ 'FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163', '99B718',
+ '74A901', '66A000', '529400', '3E8601', '207401', '056201',
+ '004C00', '023B01', '012E01', '011D01', '011301'];
+
+var ndviVis = {min:0, max:0.5, palette: palette }
+
+
+// Write a function for Cloud masking
+function maskS2clouds(image) {
+ var qa = image.select('QA60')
+ var cloudBitMask = 1 << 10;
+ var cirrusBitMask = 1 << 11;
+ var mask = qa.bitwiseAnd(cloudBitMask).eq(0).and(
+ qa.bitwiseAnd(cirrusBitMask).eq(0))
+ return image.updateMask(mask).divide(10000)
+ .select("B.*")
+ .copyProperties(image, ["system:time_start"])
+}
+
+
+// Write a function that computes NDVI for an image and adds it as a band
+function addNDVI(image) {
+ var ndvi = image.normalizedDifference(['B8', 'B4']).rename('ndvi');
+ return image.addBands(ndvi);
+}
+
+function getComposite(geometry) {
+ var filtered = s2
+ .filter(ee.Filter.date('2019-01-01', '2019-12-31'))
+ .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 30))
+ .filter(ee.Filter.bounds(geometry))
+ .map(maskS2clouds)
+ // Map the function over the collection
+ var withNdvi = filtered.map(addNDVI);
+
+ var composite = withNdvi.median()
+ return composite
+}
+
+
+// Create UI Elements
+var title = ui.Label('Global NDVI Explorer');
+title.style().set({
+ 'position': 'top-center',
+ 'fontSize': '24px'
+ });
+var resultsPanel = ui.Panel();
+var chartPanel = ui.Panel();
+var selectionPanel = ui.Panel({
+ layout: ui.Panel.Layout.flow('horizontal'),
+});
+
+resultsPanel.style().set({
+ width: '400px',
+ position: 'bottom-right'
+});
+
+var resetPanel = ui.Panel();
+
+
+resultsPanel.add(selectionPanel)
+resultsPanel.add(chartPanel)
+resultsPanel.add(resetPanel)
+
+// Function to reset the app to initial state
+var resetEverything = function() {
+ chartPanel.clear()
+ selectionPanel.clear()
+ resetPanel.clear()
+
+ Map.clear()
+
+ Map.add(title);
+ Map.add(resultsPanel)
+ Map.onClick(displayChart)
+ // Use the current viewport
+ var bounds = ee.Geometry.Rectangle(Map.getBounds())
+ var composite = getComposite(bounds)
+ Map.addLayer(composite, rgbVis, 'Sentinel-2 Composite')
+ var label = ui.Label('Click anywhere to see the chart')
+ resetPanel.add(label)
+
+}
+
+// Function to create and display NDVI time-series chart
+var displayChart = function(point) {
+ resetPanel.clear()
+ var button = ui.Button({
+ label: 'Reset',
+ onClick: resetEverything})
+ resetPanel.add(button)
+ var geometry = ee.Geometry.Point(point['lon'], point['lat']);
+
+ var filtered = s2
+ .filter(ee.Filter.date('2019-01-01', '2019-12-31'))
+ .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 50))
+ .map(maskS2clouds)
+ .map(addNDVI)
+ .filter(ee.Filter.bounds(geometry))
+
+ var chart = ui.Chart.image.series({
+ imageCollection: filtered.select('ndvi'),
+ region: geometry,
+ reducer: ee.Reducer.mean(),
+ scale: 20}).setOptions({
+ title: 'NDVI Time Series',
+ vAxis: {title: 'NDVI'},
+ hAxis: {title: 'Date', gridlines: {count: 12}}
+ })
+
+ chartPanel.clear()
+ selectionPanel.clear()
+ selectionPanel.add(ui.Label('Choose an image to display:'))
+ chartPanel.add(chart)
+
+
+ var addNdviLayer = function(dateString) {
+ var date = ee.Date.parse('YYYY-MM-dd', dateString)
+ var image = ee.Image(filtered.filter(ee.Filter.date(date, date.advance(1, 'day'))).mosaic())
+ Map.addLayer(image.select('ndvi'), ndviVis, 'NDVI Image -' + dateString)
+ }
+
+
+ filtered.aggregate_array('system:time_start').evaluate(function(ids) {
+ var dates = ee.List(ids).distinct().map(function(timestamp) {
+ return ee.Date(timestamp).format('YYYY-MM-dd')
+ })
+ dates.evaluate(function(dateList){
+ selectionPanel.add(ui.Select({
+ items: dateList,
+ onChange: addNdviLayer,
+ placeholder: 'Select a date'
+ }))
+ })
+
+});
+
+}
+// Call the function to build the initial UI state.
+resetEverything();
var karnataka = ee.FeatureCollection("users/ujavalgandhi/public/karnataka");
-Map.addLayer(karnataka, {color: 'gray'}, 'State Boundary')
-var bounds = karnataka.geometry().bounds()
-var coords = ee.List(bounds.coordinates().get(0))
-var xmin = ee.List(coords.get(0)).get(0)
-var ymin = ee.List(coords.get(0)).get(1)
-var xmax = ee.List(coords.get(2)).get(0)
-var ymax = ee.List(coords.get(2)).get(1)
-// source code for the grid package:
-// https://code.earthengine.google.com/?accept_repo=users/gena/packages
-
-// Import the module to our script using 'require'
-var gridModule = require('users/gena/packages:grid')
-
-// Now we can run any function from the module
-// We try running the generateGrid function to create regularly spaced vector grid
-// generateGrid(xmin, ymin, xmax, ymax, dx, dy, marginx, marginy, opt_proj)
-
-var spacing = 0.5
-var gridVector = gridModule.generateGrid(xmin, ymin, xmax, ymax, spacing, spacing, 0, 0)
-Map.centerObject(gridVector)
-Map.addLayer(gridVector, {color: 'blue'}, 'Grids')
var karnataka = ee.FeatureCollection("users/ujavalgandhi/public/karnataka");
+Map.addLayer(karnataka, {color: 'gray'}, 'State Boundary')
+var bounds = karnataka.geometry().bounds()
+var coords = ee.List(bounds.coordinates().get(0))
+var xmin = ee.List(coords.get(0)).get(0)
+var ymin = ee.List(coords.get(0)).get(1)
+var xmax = ee.List(coords.get(2)).get(0)
+var ymax = ee.List(coords.get(2)).get(1)
+// source code for the grid package:
+// https://code.earthengine.google.com/?accept_repo=users/gena/packages
+
+// Import the module to our script using 'require'
+var gridModule = require('users/gena/packages:grid')
+
+// Now we can run any function from the module
+// We try running the generateGrid function to create regularly spaced vector grid
+// generateGrid(xmin, ymin, xmax, ymax, dx, dy, marginx, marginy, opt_proj)
+
+var spacing = 0.5
+var gridVector = gridModule.generateGrid(xmin, ymin, xmax, ymax, spacing, spacing, 0, 0)
+Map.centerObject(gridVector)
+Map.addLayer(gridVector, {color: 'blue'}, 'Grids')
Exercise var withIndices = filtered.map(addIndices); // Composite -var composite = withIndices.median().clip(geometry); +var composite = withIndices.median(); print(composite); -// Extract the 'ndwi' band and display a NDWI map -// use the palette ['white', 'blue'] -// Hint: Use .select() function to select a band
04. Post-classification Comparison
var before = filtered.median().clip(geometry);
// Display the input composite.
-Map.addLayer(before, rgbVis, 'before');
+Map.addLayer(before.clip(geometry), rgbVis, 'before');
var training = urban.merge(bare).merge(water).merge(vegetation);
@@ -3695,75 +3696,74 @@ 04. Post-classification Comparison
var beforeClassified = before.classify(classifier);
var palette = ['#cc6d8f', '#ffc107', '#1e88e5', '#004d40' ];
var classifiedVis = {min: 0, max: 3, palette: palette};
-Map.addLayer(beforeClassified, classifiedVis, 'before_classified');
+Map.addLayer(beforeClassified.clip(geometry), classifiedVis, 'before_classified');
// 2020 Jan
var after = s2
.filter(ee.Filter.date('2020-01-01', '2020-02-01'))
.filter(ee.Filter.bounds(geometry))
.select('B.*')
- .median()
- .clip(geometry);
-
-Map.addLayer(after, rgbVis, 'after');
-
-// Classify the image.
-var afterClassified= after.classify(classifier);
-Map.addLayer(afterClassified, classifiedVis, 'after_classified');
+ .median();
+
+Map.addLayer(after.clip(geometry), rgbVis, 'after');
+
+// Classify the image.
+var afterClassified= after.classify(classifier);
+Map.addLayer(afterClassified.clip(geometry), classifiedVis, 'after_classified');
+
-
-// Reclassify from 0-3 to 1-4
-var beforeClasses = beforeClassified.remap([0, 1, 2, 3], [1, 2, 3, 4]);
-var afterClasses = afterClassified.remap([0, 1, 2, 3], [1, 2, 3, 4]);
-
-// Show all changed areas
-var changed = afterClasses.subtract(beforeClasses).neq(0);
-Map.addLayer(changed, {min:0, max:1, palette: ['white', 'red']}, 'Change');
-
-// We multiply the before image with 100 and add the after image
-// The resulting pixel values will be unique and will represent each unique transition
-// i.e. 102 is urban to bare, 103 urban to water etc.
-var merged = beforeClasses.multiply(100).add(afterClasses).rename('transitions');
-
-// Use a frequencyHistogram to get a pixel count per class
-var transitionMatrix = merged.reduceRegion({
- reducer: ee.Reducer.frequencyHistogram(),
- geometry: geometry,
- maxPixels: 1e10,
- scale:10,
- tileScale: 16
-});
-// This prints number of pixels for each class transition
-print(transitionMatrix.get('transitions'));
-
-// If we want to calculate the area of each class transition
-// we can use a grouped reducer
-
-// Divide by 1e6 to get the area in sq.km.
-var areaImage = ee.Image.pixelArea().divide(1e6).addBands(merged);
-// Calculate Area by each Transition Class
-// using a Grouped Reducer
-var areas = areaImage.reduceRegion({
- reducer: ee.Reducer.sum().group({
- groupField: 1,
- groupName: 'transitions',
- }),
- geometry: geometry,
- scale: 100,
- tileScale: 4,
- maxPixels: 1e10
- });
-
-// Post-process the result to generate a clean output
-var classAreas = ee.List(areas.get('groups'));
-var classAreaLists = classAreas.map(function(item) {
- var areaDict = ee.Dictionary(item);
- var classNumber = ee.Number(areaDict.get('transitions')).format();
- var area = ee.Number(areaDict.get('sum')).round();
- return ee.List([classNumber, area]);
- });
-var classTransitionsAreaDict = ee.Dictionary(classAreaLists.flatten());
-print(classTransitionsAreaDict);