[GIS] Post-classification Majority Analysis feature on Google Earth Engine (Similar to ENVI)

classificationenvigoogle-earth-engineqgis

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?

Best Answer

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')
  .select(['Land_Cover_Type_1']);

// 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],
               [2,3,2],
               [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
].join(',');

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!

Related Question