In ENVI there's a Majority/Minority Analysis function that allows you to to change spurious/"wrongly classified" pixels within a large single class to that class (it also allows you to enter kernel size and the weight of the center pixel in the kernel).

I have a classified image but I want to fix the "salt-and-pepper" effect of pixels the output image has.

Is there a Majority analysis function post-classification in Google Earth Engine?

What are sample scripts, if ever? And/or where would I start reading up on it? I can't seem to figure out where it is in the Earth Engine tutorial.

If there isn't are there any work-arounds to it? I'm trying to only use freely available software. Is there a function in QGIS perhaps?

1 Answer 1


Here is an article by the Earth Engine team that does a little explaining on morphological operations within Earth Engine

Fo your case, you may be able to get away with using image.focal_mode() (or some combination of morphological ops) for a straightforward clean up of your classes, the Earth Engine team provide a great example of how to do this for land cover image cleanup.

However, it sounds like you may want to do some more advanced neighborhood operations by using a filter weight. Here is an example of how you can use weights to clean up a land cover classification:

// Force projection of 500 meters/pixel, which is the native MODIS resolution.
var SCALE = 500;

// Load a 2001 MODIS land cover image and
// select the classification band of interest.
var lc = ee.Image('MODIS/051/MCD12Q1/2001_01_01')

// Smooth with a mode filter.
// and force operations to be done at native scale
var mode = lc.focal_mode().reproject('EPSG:4326', null, SCALE);

// Weighted smoothing 
// using a 3x3 window
// euclidean distance weighting from corners
var weights = [[1,2,1],

// create a 3x3 kernel with the weights
// kernel W and H must equal weight H and H
var kernel = ee.Kernel.fixed(3,3,weights);

// apply mode on neightborhood using weights
// and force operations to be done at native scale
var weighted_mode = lc.reduceNeighborhood({
  reducer: ee.Reducer.mode(),
  kernel: kernel
}).reproject('EPSG:4326', null, SCALE);

// Define display paramaters with appropriate colors for the MODIS
// land cover classification image.
var PALETTE = [
    'aec3d4', // water
    '152106', '225129', '369b47', '30eb5b', '387242', // forest
    '6a2325', 'c3aa69', 'b76031', 'd9903d', '91af40', // shrub, grass, savannah
    '111149', // wetlands
    'cdb33b', // croplands
    'cc0013', // urban
    '33280d', // crop mosaic
    'd7cdcc', // snow and ice
    'f7e084', // barren
    '6f6f6f'  // tundra

var vis_params = {min: 0, max: 17, palette: PALETTE};

// Display each step of the computation.
Map.setCenter(-121.9122, 37.7299, 10);
Map.addLayer(lc, vis_params, 'IGBP classification');
Map.addLayer(mode, vis_params, 'Mode');
Map.addLayer(weighted_mode, vis_params, 'Weighted Mode')

As you can see, you just create a kernel using whichever weights you want as a list and then apply it on the image using .reduceNeighborhood(). I hope this helps!

  • Thank you very much for your reply as well as script! My problem though is I'm using Landsat data and I don't think it has a built in band for Land Cover. So I can't just use, "ee.Image('LANDSAT').select(['Land_Cover_Type_1'])". Also the image I'm classifying is an image collection composite (if that helps to be specific). I'm trying to figure out now if I can add the classified land cover values(?) as a band to the composite image but I'm unsure how to do that or if that's at all possible. Again, thank you for your help!
    – Linus AG
    Commented Jun 8, 2020 at 13:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.