mapping rice using Sentinel 1

in Can Tho

In this exercise we are going to map rice paddies in the Can Tho province using sentinel-2 data. We are going to create a binary sample for rice and other land cover classes and combine them to train a random forest classifier. We are going to look at the variable importance, the accuracy of the classifier and the accuracy of an independent sample.

Step 1: import the administrative boundaries of the provinces from the repository and filter for Can Tho and add the province to the map using the code below.

// import the provinces
var provinces = ee.FeatureCollection("projects/servir-mekong/admin/VNM_adm1");
// filter for Can Tho
var canTho = provinces.filter(ee.Filter.eq("VARNAME_1", "Can Tho"));
// add the layer to the map
Map.addLayer(canTho,{}, "Can Tho");

Step 2: now we import the sentinel 1 image collection and compute the mean for each month

var s1 = ee.ImageCollection("COPERNICUS/S1_GRD").filterBounds(canTho)

var s1Jan = ee.Image(s1.filterDate("2020-01-01","2020-01-31").mean()).select(["VV","VH"],["VVjan","VHjan"])
var s1Feb = ee.Image(s1.filterDate("2020-02-01","2020-02-28").mean()).select(["VV","VH"],["VVfeb","VHfeb"])
var s1Mar = ee.Image(s1.filterDate("2020-03-01","2020-03-31").mean()).select(["VV","VH"],["VVmar","VHmar"])
var s1Apr = ee.Image(s1.filterDate("2020-04-01","2020-04-30").mean()).select(["VV","VH"],["VVapr","VHapr"])
var s1May = ee.Image(s1.filterDate("2020-05-01","2020-05-31").mean()).select(["VV","VH"],["VVmay","VHmay"])
var s1Jun = ee.Image(s1.filterDate("2020-06-01","2020-06-30").mean()).select(["VV","VH"],["VVjun","VHjun"])
var s1Jul = ee.Image(s1.filterDate("2020-07-01","2020-07-31").mean()).select(["VV","VH"],["VVjul","VHjul"])
var s1Aug = ee.Image(s1.filterDate("2020-08-01","2020-08-31").mean()).select(["VV","VH"],["VVaug","VHaug"])
var s1Sep = ee.Image(s1.filterDate("2020-09-01","2020-09-30").mean()).select(["VV","VH"],["VVsep","VHsep"])
var s1Oct = ee.Image(s1.filterDate("2020-10-01","2020-10-31").mean()).select(["VV","VH"],["VVoct","VHoct"])
var s1Nov = ee.Image(s1.filterDate("2020-11-01","2020-11-30").mean()).select(["VV","VH"],["VVnov","VHnov"])
var s1Dec = ee.Image(s1.filterDate("2020-12-01","2020-12-31").mean()).select(["VV","VH"],["VVdec","VHdec"])

var image = s1Jan.addBands(s1Feb)
                 .addBands(s1Mar)
                 .addBands(s1Apr)
                 .addBands(s1May)
                 .addBands(s1Jun)
                 .addBands(s1Jul)
                 .addBands(s1Aug)
                 .addBands(s1Sep)
                 .addBands(s1Oct)
                 .addBands(s1Nov)
                 .addBands(s1Dec)

Map.addLayer(image.clip(canTho),{min:-25,max:0},"sentinel 1")

Step 3: create a new feature collection

Go to the layer properties

rename to rice, change geometry to feature collection and add a property for class

Add points to the map where we find rice

Step 4: Repeat the same as above for areas that do not contain rice. We set the class to 0

Step 5: add a random column to the two samples and divide them into a 70% training, 30% validation sample

// add a random column
var rice = rice.randomColumn("random");
var other = other.randomColumn("random");

// create a training sample
var riceTrain = rice.filter(ee.Filter.lt("random",0.7));
var otherTrain = other.filter(ee.Filter.lt("random",0.7));

// create a validation sample
var riceVal = rice.filter(ee.Filter.gt("random",0.7));
var otherVal = other.filter(ee.Filter.gt("random",0.7));

step 6: combine the data into a a training and validation dataset

// combine training data
var TrainingSample = riceTrain.merge(otherTrain);
// combine validation data
var validationSample = riceVal.merge(otherVal)

Step 7: Train the random forest classifier and print the variable importance

// sample the image
var trainingSample = image.sampleRegions({collection:TrainingSample,properties:["class"],scale:10});
 // create a list with bandNames
var bandNames = image.bandNames();
// train the random forest classifier
var classifier = ee.Classifier.smileRandomForest(10).train({features:trainingSample,classProperty:"class",inputProperties:bandNames});

// get info from classifier
var dict = classifier.explain();

// get the variable importance from dict
var variable_importance = ee.Feature(null, ee.Dictionary(dict).get('importance'));
 
// plot the variable importance
var chart =
ui.Chart.feature.byProperty(variable_importance)
  .setChartType('ColumnChart')
  .setOptions({
  title: 'Random Forest Variable Importance',
  legend: {position: 'none'},
  hAxis: {title: 'Bands'},
  vAxis: {title: 'Importance'}
});

print(chart);

Step 8: print the statistics of the classfier

// get the confustion matrix
var confMatrix = classifier.confusionMatrix();
 
var OA = confMatrix.accuracy();
var CA = confMatrix.consumersAccuracy();
var Kappa = confMatrix.kappa();
var Order = confMatrix.order();
var PA = confMatrix.producersAccuracy();
 
print(confMatrix,'Confusion Matrix');
print(OA,'Overall Accuracy');
print(CA,'Consumers Accuracy');
print(Kappa,'Kappa');
print(Order,'Order');
print(PA,'Producers Accuracy')

Step 9: Classify the image

// apply the classifier to the image
var classification = image.classify(classifier,'Mode');
// add the image to the map
Map.addLayer(classification.clip(canTho),{min:0,max:5,palette:"white,darkgreen"},"rice")
 

step 10: apply the independent validation

// sample the result using the validation sample
var validation = classification.sampleRegions(validationSample,["class"],10);

var confMatrix = validation.errorMatrix("class","Mode");
var OA = confMatrix.accuracy();
var CA = confMatrix.consumersAccuracy();
var Kappa = confMatrix.kappa();
var Order = confMatrix.order();
var PA = confMatrix.producersAccuracy();
 
print(confMatrix,'Confusion Matrix');
print(OA,'Overall Accuracy');
print(CA,'Consumers Accuracy');
print(Kappa,'Kappa');
print(Order,'Order');
print(PA,'Producers Accuracy');

find the full code here

Leave a Reply