I am trying to combine the approaches suggested in the answers to this post – Google Engine – Make a greenest pixel composite for Sentinel 2 – to make a quality mosaic, based on the 95th percentile NDVI value, in order to reduce errors from using the max NDVI.
I've attempted to make a function to define the 95th percentile NDVI value using a reducer, then filter the image collection for values below this threshold. Then I make a qualityMosaic, based on the filtered image collection.
I suspect there are several problems here, possibly I am mixing functions for image vs image collection, and possibly it is not doing what I intend – i.e filtering by 95th percentile ndvi values for EACH pixel within the image collection. The image collection is the same after I apply my ndvi filter function, and the output image seems to be the same as a greenest-pixel composite.
My ultimate aim here is to give a good representation of both bare soil, and have the greenest values for the surrounding vegetation. You can see I get some strange effects for bare soil using greenest pixel quality mosaic – this is what I'm hoping to improve by using the 95th percentile.
// Area of interest
var x1 = 5.8; //West longitude bound
var x2 = 6.45; //East longitude bound
var y1 = 61.7; //North latitude bound
var y2 = 61.4; //South latitude bound
var area =ee.Geometry.Polygon([[x1, y1], [x2, y1], [x2, y2], [x1, y2]]);
//////////////// Functions ////////////////
//add NDVI
function addNDVI(image) {
var ndvi = image.normalizedDifference(['B8', 'B4']);
return image.addBands(ndvi.rename('ndvi'));
}
//filter by 95th percentile
function filter_ndvi95(image){
var lte_ndvi95 = image.select('ndvi').lte(ndvi_95);
return image
}
//////////////// Analysis ////////////////
var filtered = ee.ImageCollection("COPERNICUS/S2").
filterDate('2020-01-01', '2020-12-31').
filterBounds(area);
var with_ndvi = filtered.map(addNDVI);
print(with_ndvi)
var ndvi_95 = with_ndvi.reduce(ee.Reducer.percentile([95]));
//filter image collection by NDVI 95th percentile
var filtered_ndvi95 = with_ndvi.map(filter_ndvi95);
print(filtered_ndvi95)
// create greenest pixel quality mosaic
var greenest = filtered_ndvi95.qualityMosaic('ndvi').clip(area);
//////////////// User Interface ////////////////
var rgb_vis = {min: 0, max: 3000, gamma: 1.5, bands: ['B4', 'B3', 'B2']};
Map.addLayer(greenest, rgb_vis, 'RGB (greenest pixel)');
Map.centerObject(area);
Best Answer
Your original script has some errors so it is not functioning as you intend. This part of your script returns the original image because you returned image and not lte_ndvi95. There are other issues here that would cause your script to error which I will address later, but that is primary reason why you don't see any changes in the resulting mosaic.
From the way your script is written, I assume you are trying to:
Here is the edited function that accomplishes those goals:
You can see from an image of the unfiltered image minus the filtered image that the function is working as written and that there are some differences between the filtered and unfiltered pixels (darker red means more different) but not all pixels are different.
However, I'm not sure that this is what you want, since the pixels being removed are more likely to be areas of high vegetation, which doesn't necessarily make your bare soil more clear. See the 2 clippings below.
Unfiltered
Filtered
If you are looking to make cleaner mosaic images for visual purposes, I think that there are better methods out there. However, if you are trying to do analysis on NDVI, or band information, it would be helpful to know what question you are trying to solve for to be able to point you in the right direction. For example, if you were simply looking for the 95th highest NDVI value for every pixel in an ee.ImageCollection, that could be easily accomplished by using
unfiltered.reduce(ee.Reducer.percentile([95]))
.Full code: https://code.earthengine.google.com/4ef3e5d83ebb5694cca6064585b114b4