I want to make supervised classification of Sentinel-2 data-set. The algorithm is:
// Define periods of analysis
var startdate1 = '2017-10-01';
var enddate1 = '2017-11-30';
var startdate2 = '2018-04-01';
var enddate2 = '2018-05-31';
var startdate3 = '2018-06-01';
var enddate3 = '2018-07-31';
// Define geograpic domain
var geometry = Knezha.geometry();
///////////////////////////////////////////////////////////////////////////
// Preprocess Sentinel-2 data
///////////////////////////////////////////////////////////////////////////
// cloud function to remove clouds
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);
}
//////////////////PERIOD1-OCT-NOV 2017////////////////////////////////////
// filter Sentinel-2 data
var Sentinel2_period1 = S2.filterBounds(geometry).filterDate(startdate1, enddate1)
// Pre-filter to get less cloudy granules.
.filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 10));
// remove the clouds
var S2_nocloud_period1 = Sentinel2_period1.map(maskS2clouds);
// take the median
var st2median_period1 = S2_nocloud_period1.median();
// select only bands B2-B8, B11 and B12
var S2_period1 = st2median_period1.select('B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B11', 'B12');
//////////////////PERIOD2-APR-MAY 2018////////////////////////////////////
// filter Sentinel-2 data
var Sentinel2_period2 = S2.filterBounds(geometry).filterDate(startdate2, enddate2)
// Pre-filter to get less cloudy granules.
.filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 10));
// remove the clouds
var S2_nocloud_period2 = Sentinel2_period2.map(maskS2clouds);
// take the median
var st2median_period2 = S2_nocloud_period2.median();
// select only bands B2-B8, B11 and B12
var S2_period2 = st2median_period2.select('B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B11', 'B12')
//////////////////PERIOD3-JUN-JUL 2018////////////////////////////////////
// filter Sentinel-2 data
var Sentinel2_period3 = S2.filterBounds(geometry).filterDate(startdate3, enddate3)
// Pre-filter to get less cloudy granules.
.filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 10));
// remove the clouds
var S2_nocloud_period3 = Sentinel2_period3.map(maskS2clouds);
// take the median
var st2median_period3 = S2_nocloud_period3.median();
// select only bands B2-B8, B11 and B12
var S2_period3 = st2median_period3.select('B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B11', 'B12');
// Combine the bands from the three periods
// into one image and clip over geometry
var input_img_S2 = S2_period1.addBands([S2_period2, S2_period3])
.rename(['P1_B2', 'P1_B3', 'P1_B4', 'P1_B5', 'P1_B6', 'P1_B7', 'P1_B8', 'P1_B11',
'P1_B12', 'P2_B2', 'P2_B3', 'P2_B4', 'P2_B5', 'P2_B6', 'P2_B7', 'P2_B8', 'P2_B11',
'P2_B12', 'P3_B2', 'P3_B3', 'P3_B4', 'P3_B5', 'P3_B6', 'P3_B7', 'P3_B8', 'P3_B11',
'P3_B12'])
.clip(geometry);
// Add to the map
var visParams = {bands: ['P1_B8', 'P2_B8', 'P3_B8'], max: 0.5}
Map.addLayer(input_img_S2, visParams, 'Sentinel-2 data', false);
Map.addLayer(S2_period1, {bands: ['B4', 'B3', 'B2'], max: 0.3}, 'median RBG period 1', false);
Map.addLayer(S2_period2, {bands: ['B4', 'B3', 'B2'], max: 0.3}, 'median RBG period 2', false);
Map.addLayer(S2_period3, {bands: ['B4', 'B3', 'B2'], max: 0.3}, 'median RBG period 3', false);
//////////////////////////////////////////////////////////////////////////
// Now the real classification
//////////////////////////////////////////////////////////////////////////
// Extract spectral data from the input image for training points
var training = input_img_S2.sampleRegions({
// Get the sample from the point FeatureCollection.
collection: training_points,
// We'll classify on 'Level_2"
properties: ['Level_2'],
// Set the scale to get Sentinel-2 pixels in the polygons.
scale: 20,
tileScale: 4
});
// Make a Random Forest classifier (10 trees) and train it.
var classifier = ee.Classifier.randomForest(10)
.train(training, 'Level_2');
// Classify the image with the trained classifier
var classified = input_img_S2.classify(classifier);
// Create a palette to display the classes.
var palette =['#deebab', '#aeee98', '#8cb3d1', '#e3df51',
'#cb50c7', '#8b8c53', '#8cce21', '#1f8a1d',
'#5c305e', '#074ec9'];
// Add classification to the map
Map.addLayer(classified, {min: 0, max: 9, palette: palette}, 'Classification', false);
//////////////////////////////////////////////////////////////////////////
// Accuracy assessment
//////////////////////////////////////////////////////////////////////////
// Create 1000 random points in the val polygons.
var randomPoints = ee.FeatureCollection.randomPoints(val_poly, 1000, 0, 1)
// Property Level_2 not attached to points, so we need
// Spatial join
var randomPoints_new = val_poly.map(function(feat){
feat = ee.Feature(feat);
var covertype = feat.get('Level_2');
var randomPoints_filtered = randomPoints.filterBounds(feat.geometry()).map(function(point){
return ee.Feature(point).set('Level_2', covertype);
});
return randomPoints_filtered;
}).flatten();
// Extract spectral data from the input image for validation points
var validation = input_img_S2.sampleRegions({
// Get the sample from the point FeatureCollection.
collection: randomPoints_new,
// We'll classify on 'Level_2"
properties: ['Level_2'],
// Set the scale to get Sentinel-2 pixels at the points.
scale: 20,
tileScale: 4
})
.filter(ee.Filter.neq('P1_B2', null));
// Classify the validation data.
var validated = validation.classify(classifier);
// Get a confusion matrix representing expected accuracy.
var testAccuracy = validated.errorMatrix('Level_2', 'classification');
// Еxport error matrix
var exportAccuracy = ee.Feature(null, {matrix: testAccuracy.array()})
Export.table.toDrive({
collection: ee.FeatureCollection(exportAccuracy),
description: 'Error_matrix',
fileFormat: 'CSV'
});
Everything seems to be successful until I came to the accuracy assessment. When I run the entire script, including the accuracy assessment part, I get this error:
Error: User memory limit exceeded.
I reduced the number of validation points to only 1000, just for initial experiment. I actually would prefer something like 100 000 points for the assessment. But I get memory limit exceeded even with 1000 points.
Maybe the problem is not in the number of validation points at all. But it is definitely in the accuracy assessment because I was able to export the classification raster to Google Drive and the problems start when I continue from there onwards.
What do I need to change?
Link to the code: https://code.earthengine.google.com/6a0b69b4a0442253639a667ff856fb17
Links to the vector assets: https://code.earthengine.google.com/?asset=users/petarkirilov/Zlatia_test_site_34
https://code.earthengine.google.com/?asset=users/petarkirilov/training_points
https://code.earthengine.google.com/?asset=users/petarkirilov/validation_polygons