Search code examples
javascriptgoogle-earth-engine

image.sampleRegions is not a function (supervised classification at google earth engine)


Hello I'm a beginner currently working on supervised classification in Google Earth Engine. I can't seem to get past the problem 'image.sampleRegions is not a function'. Here are the script that I use.

/**
 * 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('2019-09-01', '2019-10-01') //september
                  // Pre-filter to get less cloudy granules.
                  .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE',20))
                  .map(maskS2clouds);

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

Map.setCenter(101.68287285738528,0.6988384299139916, 16);
Map.addLayer(dataset.mean(), visualization, 'RGB');

// Use these bands for prediction.
var bands = ['B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B10', 'B11'];


// Make a FeatureCollection from the hand-made geometries.
var polygons = ee.FeatureCollection([
  ee.Feature(Kebun1, {'class': 0}),
  ee.Feature(Kebun2, {'class': 0}),
  ee.Feature(Kebun3, {'class': 0}),
  ee.Feature(Canal1, {'class': 1}),
  ee.Feature(Canal2, {'class': 1}),
]);

//Define the image aduh anjir salah dimana sih
var imageCollection = ee.ImageCollection("COPERNICUS/S2");
var geometry = ee.FeatureCollection(polygons);
var image = imageCollection
.filterDate('2019-09-01', '2019-10-1')
                  // Pre-filter to get less cloudy granules.
                  .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 20))
                  .map(maskS2clouds)
                  //filter according to drawn boundary
.filterBounds(geometry);

             

// Get the values for all pixels in each polygon in the training.
var training = image.sampleRegions({
  // Get the sample from the polygons FeatureCollection.
  collection: polygons,
  // Keep this list of properties from the polygons.
  properties: ['class'],
  // Set the scale to get Landsat pixels in the polygons.
  scale: 30
});

// Create an SVM classifier with custom parameters.
var classifier = ee.Classifier.libsvm({
  kernelType: 'RBF',
  gamma: 0.5,
  cost: 10
});

// Train the classifier.
var trained = classifier.train(training, 'class', bands);

// Classify the image.
var classified = image.classify(trained);

// Display the classification result and the input image.
Map.setCenter(101.68287285738528,0.6988384299139916,16);
Map.addLayer(image, {bands: ['B4', 'B3', 'B2'], max: 0.5, gamma: 2});
Map.addLayer(polygons, {}, 'training polygons');
Map.addLayer(classified,
             {min: 0, max: 1, palette: ['red', 'green']},
             'klasifikasi');


Solution

  • The problem is here:

    var image = imageCollection
        .filterDate(...)
        .filter(...)
        .map(...)
        .filterBounds(...);
    
    var training = image.sampleRegions(...);
    

    Everything you have done to imageCollection still returns an image collection, not an image. In order to apply an image operation like sampleRegions, you need to decide what you want to do.

    Do you want to take the latest pixel available in the filtered collection for each point? Then use .mosaic():

    var image = imageCollection
        .filterDate(...)
        .filter(...)
        .map(...)
        .filterBounds(...)
        .mosaic();
    

    Do you want the median of the time series for each pixel? Then use .median() instead of .mosaic(). (Or mean, min, max, etc. are also available)

    Do you want separate sampled points for every image in the collection at every region? Then map over it to sample each image:

    var trainingImages = imageCollection
        .filterDate(...)
        .filter(...)
        .map(...)
        .filterBounds(...);
    
    var trainingPoints = trainingImages.map(function (image) {
      return image.sampleRegions(...);
    }).flatten();
    

    (Note the .flatten() at the end; this is key because this produces a collection of points for each image in the collection of images, so it would be a collection of collections of points, and .flatten() turns it into a collection of points.)