Extract pixel values from image collection to make composite in google earth engine

2.1k Views Asked by At

I am trying to make a cloud-free landsat composite in Google Earth Engine in an area with a lot of clouds (Indonesian cloud-forest). Previously, I accomplished this successfully by making a greenest pixel composite, in which I used the pixel with the highest NDVI value to make sure I was using non-cloud pixels in my composite image.

//Filter landsat 8 image collection by date, area
var collection = landsat
.filterBounds(bounds)
.filterDate(2016-08-01, 2016-10-31);

// Sort from least to most cloudy and get first (least cloudy) image
var sorted = collection.sort('CLOUD_COVER');
var image = ee.Image(sorted.first());

//Function to get NDVI 
var addNDVI = function(image) {
var ndvi = image.normalizedDifference(['B5', 'B4']).rename('NDVI');
return image.addBands(ndvi);
};

//Add NDVI bands to image collection
var withNDVI = landsat.map(addNDVI);

// Make a "greenest" pixel composite using NDVI
var greenest = withNDVI.qualityMosaic('NDVI');
Map.addLayer(greenest, {bands: ['B4', 'B3', 'B2'], max: 0.15}, 'greenest');

The code works fine, however, I am concerned using the highest NDVI pixels to make my composite is over-representing forested area. Therefore, I am looking for a method to extract the pixels with the highest NDVI (to get rid of the clouds), and then using all 7 other bands of that pixel in my composite (instead of using the NDVI band itself). My questions are: would this even get rid of forest over-representation, or would I still have the same problem? Second, if this method does seem like a legitimate way to get rid clouds while making a composite that does not over-represent forest, how can I extract pixels of a high NDVI, and then use their other bands to make a composite?

1

There are 1 best solutions below

0
On

It seems like however you do a quality mosaic with the greenest pixel it will almost always accentuate the forest in tropical regions (because forests are really green). I suggest you use the Landsat simple cloud score algorithm to find pixels that are least likely to be cloudy and then do your compositing based on that. Here is some code that gives you two options to make a composite. One is based on masking cloudy pixels and taking the median, another is based on the qualityMosaic() function while using the likelihood of cloud band.

var bounds = /* color: #d63000 */ee.Geometry.Polygon(
    [[[94.93602603806119, -12.072520735360198],
      [141.8696197880612, -13.187431968041206],
      [142.3969635380612, 6.019400576838261],
      [94.67235416306119, 6.456250813337956]]]),
    landsat = ee.ImageCollection("LANDSAT/LC08/C01/T1_RT_TOA");

//Filter landsat 8 image collection by date, area
var collection = landsat
 .filterBounds(bounds)
 .filterDate('2016-08-01', '2016-10-31');

//Function to get Inverse Cloud Score
var addCloud = function(image) {
var cloudImg = ee.Algorithms.Landsat.simpleCloudScore(image);
var clouds = cloudImg.select('cloud');
var inverseClouds = ee.Image(100).subtract(clouds).rename('inverse_cloud');
return image.addBands(inverseClouds);
};

//Add cloud bands to image collection
var withCloudBand = landsat.map(addCloud);

// Option 1: Median composite after masking clouds
var noCloudsMedian = withCloudBand.map(function(img){
  return img.updateMask(img.select('inverse_cloud').gt(90));
}).median();
Map.addLayer(noCloudsMedian, {bands: ['B4', 'B3', 'B2'], max: 0.30}, 'Option 1');

// Option 2: Quality mosaic based on least cloudy pixel
var noCloudQualityMosaic = withCloudBand.qualityMosaic('inverse_cloud');
Map.addLayer(noCloudQualityMosaic, {bands: ['B4', 'B3', 'B2'], max: 0.30}, 'Option 2');

Here is a link to the code to view the results: https://code.earthengine.google.com/7ea8e59b5c72340c6d784d850db856f4