Land cover classification using supervised learning method in Google Earth EngineΒΆ


cover

Overview

In this project, I try to classify the land use land cover using Random Forest Classifier in Google Earth Engine by:

  • using the images from Sentinel-2 satellite in January 2022

  • using Random Forest Classifier with parameter of 300 trees

  • using the training data from 1000 random points with the label from ESA WorldCover dataset.

Objective

  • Classify land use and land cover in Google Earth Engine and then visualize it in GEE App.

Code

The script to classify the land cover type is detailed as follows:

var roi = ee.Geometry.Polygon([[[103.63665096774587, 13.584793535905758],
        [103.63665096774587, 13.264209644744009],
        [104.07061092868337, 13.264209644744009],
        [104.07061092868337, 13.584793535905758]]], null, false);

var baseChange = [{featureType: 'all', stylers: [{invert_lightness: true}]}];

Map.setOptions('baseChange', {'baseChange': baseChange});
Map.centerObject(roi, 10)

/**
* Function to mask clouds using the Sentinel-2 QA band
* @param {ee.Image} image Sentinel-2 image
* @return {ee.Image} cloud masked Sentinel-2 image
*/
function maskS2clouds(image) {
var qa = image.select('QA60');

// Bits 10 and 11 are clouds and cirrus, respectively.
var cloudBitMask = 1 << 10;
var cirrusBitMask = 1 << 11;

// Both flags should be set to zero, indicating clear conditions.
var mask = qa.bitwiseAnd(cloudBitMask).eq(0)
    .and(qa.bitwiseAnd(cirrusBitMask).eq(0));

return image.updateMask(mask).divide(10000);
}

var dataset = ee.ImageCollection('COPERNICUS/S2_SR')
                .filterDate('2022-01-01', '2022-01-30')
                // Pre-filter to get less cloudy granules.
                .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE',5))
                .map(maskS2clouds);

var visualization = {
min: 0.0,
max: 0.3,
bands: ['B4', 'B3', 'B2'],
};

var img = ee.Image(dataset.mean()).select('B.*');

// ESA WorldCover land cover map, used as label source in classifier training.
var lc = ee.Image('ESA/WorldCover/v100/2020');

// Remap the land cover class values to a 0-based sequential series.
var classValues = [10, 20, 30, 40, 50, 60, 70, 80, 90, 95, 100];
var remapValues = ee.List.sequence(0, 10);
var label = 'lc';
lc = lc.remap(classValues, remapValues).rename(label).toByte();

// Add land cover as a band of the reflectance image and sample 100 pixels at
// 10 m scale from each land cover class within a region of interest.

var sample = img.addBands(lc).stratifiedSample({
numPoints: 1000,
classBand: label,
region: roi,
scale: 10,
geometries: true
});

// Add a random value field to the sample and use it to approximately split 80%
// of the features into a training set and 20% into a validation set.
sample = sample.randomColumn();
var trainingSample = sample.filter('random <= 0.8');
var validationSample = sample.filter('random > 0.8');

// Train a 10-tree random forest classifier from the training sample.
var trainedClassifier = ee.Classifier.smileRandomForest(300).train({
features: trainingSample,
classProperty: label,
inputProperties: img.bandNames()
});

// Get information about the trained classifier.
print('Results of trained classifier', trainedClassifier.explain());

// Get a confusion matrix and overall accuracy for the training sample.
var trainAccuracy = trainedClassifier.confusionMatrix();
print('Training error matrix', trainAccuracy);
print('Training overall accuracy', trainAccuracy.accuracy());

// Get a confusion matrix and overall accuracy for the validation sample.
validationSample = validationSample.classify(trainedClassifier);
var validationAccuracy = validationSample.errorMatrix(label, 'classification');
print('Validation error matrix', validationAccuracy);
print('Validation accuracy', validationAccuracy.accuracy());

// Classify the reflectance image from the trained classifier.
var imgClassified = img.classify(trainedClassifier);

// Add the layers to the map.
var classVis = {
min: 0,
max: 10,
palette: ['006400' ,'b59475', '77a123', '9b7653', 'fa0000', 'c3d593',
            'f0f0f0', '0064c8', '0096a0', '00cf75', 'fae6a0']
};


Map.addLayer(img.clip(roi), {bands: ['B11', 'B8', 'B3'], min: 0, max: 0.5}, 'img');
Map.addLayer(lc.clip(roi), classVis, 'lc', false);
Map.addLayer(imgClassified.clip(roi), classVis, 'Classified');
Map.addLayer(roi, {color: 'white'}, 'ROI', false, 0.5);
Map.addLayer(trainingSample, {color: 'yellow'}, 'Training sample', false);
Map.addLayer(validationSample, {color: 'white'}, 'Validation sample', false);

//----------------------------- Display legend on the map --------------------------//
var panel = ui.Panel({
style: {
    position: 'bottom-left',
    padding: '5px;'
}
})

var title = ui.Label({
value: 'Classification',
style: {
    fontSize: '14px',
    fontWeight: 'bold',
    margin: '0px;'
}
})

panel.add(title)

var color = ['006400' ,'b59475', '77a123', '9b7653', 'fa0000', 'c3d593',
            'f0f0f0', '0064c8', '0096a0', '00cf75', 'fae6a0']
var lc_class = ['Trees', 'Shrubland', 'Grassland', 'Cropland', 'Built-up',
            'Barren / sparse vegetation', 'Snow and ice', 'Open water', 'Herbaceous wetland',
            'Mangroves', 'Moss and lichen']

var list_legend = function(color, description) {

var c = ui.Label({
    style: {
    backgroundColor: color,
    padding: '10px',
    margin: '4px'
    }
})

var ds = ui.Label({
    value: description,
    style: {
    margin: '5px'
    }
})

return ui.Panel({
    widgets: [c, ds],
    layout: ui.Panel.Layout.Flow('horizontal')
})
}

for(var a = 0; a < 11; a++){
panel.add(list_legend(color[a], lc_class[a]))
}

Map.add(panel)

Result in GEE App

Open in full screen