1

I am a beginner in GEE. I am trying to do the random forest classification for the GEDI datasets (rh13 and rh99) in Google Earth Engine. I want to do the classification of each point of the GEDI datasets and then interpolate for all the images (because the GEDI datasets are data points).

I'm getting this error and do not how to fix it:

Classified: Layer error: Property 'Relative Height' of feature '0_0' is missing

var Paracou = 
/* color: #d63000 */
/* displayProperties: [
  {
    "type": "rectangle"
  }
] */
ee.Geometry.Polygon(
    [[[-52.992228448173776, 5.3639624330339855],
      [-52.992228448173776, 5.216962579558439],
      [-52.898158013603464, 5.216962579558439],
      [-52.898158013603464, 5.3639624330339855]]], null, false);
var qualityMask = function(im) {
  return im.updateMask(im.select('quality_flag').eq(1))
      .updateMask(im.select('degrade_flag').eq(0));
};
var img = ee.ImageCollection('LARSE/GEDI/GEDI02_A_002_MONTHLY')
                  .filterBounds(Paracou)
                  .map(qualityMask)
                  .select('rh13','rh99')
                  .median();
var gediVis = {
  min: 1,
  max: 60,
};

var img = img.clip(Paracou);
Map.centerObject(Paracou,12);
Map.addLayer(img, gediVis, 'rh13-99');
print(img.getInfo());

var points = img.sample({
  'region': Paracou,
  'scale' : 30,
  'numPixels' : 200000,
  'seed' : 0,
  'geometries': true
});
Map.addLayer(points,{},'training',true);
print(points.size().getInfo());
print(points.first().getInfo());
//SPLIT AND TRAINING
// Use these bands for prediction
var bands = ['rh13','rh99'];

var label = 'Relative Height';

var sample = img.select(bands).sampleRegions({
    collection: points,
    properties : [label],
    scale : 30
  });
var sample = sample.randomColumn();
var split = 0.7;
var training = sample.filter(ee.Filter.lt('random',split));
var validation = sample.filter(ee.Filter.gte('random',split));
print(training.first().getInfo());
print(validation.first().getInfo());
var classifier = ee.Classifier.smileRandomForest(10).train(training,label,bands);
// Classification
var result = img.select(bands).classify(classifier);
Map.addLayer(result.randomVisualizer(),{},'classified');

https://code.earthengine.google.com/37d6104d659f4dc63f36baccde372a16

1 Answer 1

0

I don't follow how you want this to work. What are the classes you want in your classification? Nevertheless, the reason for your error is this:

var label = 'Relative Height'
var sample = img.select(bands).sampleRegions({
  collection: points,
  properties: [label],
  scale: 30
})

The points collection doesn't contain any Relative Height property. Even if it did, I don't think this quite makes sense.

You could maybe try something like the below. Note that I've never used the GEDI data, and have very limited knowledge of it. So take this approach with a grain of salt. I'd very much appreciate someone with more knowledge on this to jump in and comment.

I'm extracting reference data from the GEDI collection, create Landsat 8/Sentinel 1 composites for the corresponding month, and sample it for training data. A classifier is trained, then finally applied to a composite for a date range of your choosing.

var aoi = ee.Geometry.Polygon([[
  [-52.992228448173776, 5.3639624330339855],
  [-52.992228448173776, 5.216962579558439],
  [-52.898158013603464, 5.216962579558439],
  [-52.898158013603464, 5.3639624330339855]
]]).buffer(1e4)

var heightBand = 'rh95'

var gedi = ee.ImageCollection('LARSE/GEDI/GEDI02_A_002_MONTHLY')
  .filterBounds(aoi)
  .map(function (image) {
    return image
      .updateMask(image.select('quality_flag').eq(1))
      .updateMask(image.select('degrade_flag').eq(0))
      .select(heightBand)
  })
var referenceData = gedi
  .map(toReferenceData)  
  .filterMetadata('count', 'not_equals', 0)
var trainingData = referenceData
  .map(toTrainingData)
  .flatten()

var composite = toComposite('2021-01-01', '2022-01-01')
var classifier = ee.Classifier.smileRandomForest(25)
  .train(trainingData, heightBand, composite.bandNames())
  .setOutputMode('REGRESSION')
var classification = composite.classify(classifier)


print('trainingData', trainingData)
print('classifier', classifier.explain())
Map.addLayer(referenceData.flatten(), null, 'reference data', false)
Map.addLayer(gedi.mosaic().clip(aoi), {bands: heightBand, min: 0, max: 40, palette: '#fffdcd, #e1cd73, #aaac20, #5f920c, #187328, #144b2a, #172313'}, heightBand)
Map.addLayer(composite, {bands: 'red,green,blue', min: 0, max: 2000, gamma: 1.6}, 'optical')
Map.addLayer(composite, {bands: 'VV,VH,ratio_VV_VH', min: [-20, -25, 3], max: [0, -5, 14]}, 'sar')
Map.addLayer(classification, {min: 0, max: 40, palette: '#fffdcd, #e1cd73, #aaac20, #5f920c, #187328, #144b2a, #172313'}, 'height')
Map.centerObject(aoi, 12)


function toReferenceData(gedi) {
  var referenceData = gedi
    .sample({
      region: aoi,
      scale : 25,
      numPixels : 200000,
      geometries: true
    })
    .map(function (feature) {
      // Can only use ints as classes
      return feature.set('rh99', feature.getNumber('rh99').round())
    })
  return referenceData
    .set({
      year: gedi.getNumber('year'),
      month: gedi.getNumber('month'),
      count: referenceData.size()
    })
}


function toTrainingData(referenceData) {
  var year = referenceData.getNumber('year')
  var month = referenceData.getNumber('month')
  var fromDate = ee.Date.fromYMD(year, month, 1)
  var toDate = fromDate.advance(1, 'month')
  var composite = toComposite(fromDate, toDate)
  return composite.sampleRegions({
    collection: referenceData,
    properties : [heightBand],
    scale : 30
  })  
}


function toComposite(fromDate, toDate) {
  return toOpticalComposite(fromDate, toDate)
    .addBands(toSarComposite(fromDate, toDate))
}

function toSarComposite(fromDate, toDate) {  
  var composite = ee.ImageCollection('COPERNICUS/S1_GRD_FLOAT')
    .filter(ee.Filter.and(
      ee.Filter.bounds(aoi),
      ee.Filter.date(fromDate, toDate),
      ee.Filter.eq('instrumentMode', 'IW'),
      ee.Filter.listContains('transmitterReceiverPolarisation', 'VV'),
      ee.Filter.listContains('transmitterReceiverPolarisation', 'VH')
    ))
    .map(function (image) {
      return maskBorder(
        toDb(
          toGamma0(image)
        )
      ).select(['VV', 'VH'])
    })
    .median()
  return composite
    .addBands(
      composite.select('VV').divide(composite.select('VH')).rename('ratio_VV_VH')
    )
    

  function toGamma0(image) {
    var gamma0 = image.expression('i/(cos(angle * pi / 180))', {
      'i': image.select(['VV', 'VH']),
      'angle': image.select('angle'),
      'pi': Math.PI
    })
    return image.addBands(gamma0, null, true)    
  }
  
  function toDb(image) {
    return image.addBands(
      image.select(['VV', 'VH']).log10().multiply(10), null, true
    )    
  }
    
  function maskBorder(image) {
    var angle = image.select('angle')
    return image
      .updateMask(
        angle.gt(31).and(angle.lt(45))
      )    
  }    
}


function toOpticalComposite(fromDate, toDate) {
  return ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
    .filterDate(fromDate, toDate)
    .filterBounds(aoi)
    .map(function (image) {
      var qa = image.select('QA_PIXEL')
      var cloudShadow = bitwiseExtract(qa, 4)
      var snow = bitwiseExtract(qa, 5).rename('snow')
      var cloud = bitwiseExtract(qa, 6).not().rename('cloud')
      return image
        .updateMask(
          cloudShadow.not()
            .and(snow.not())
            .and(cloud.not())
        )
        .select(
          ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'],
          ['blue', 'green', 'red', 'nir', 'swir1', 'swir2']
        )
        .multiply(2.75e-05)
        .add(-0.2)
        .multiply(10000)
        .int16()
    })
    .median()
}

function bitwiseExtract(value, fromBit, toBit) {
  if (toBit === undefined)
    toBit = fromBit
  var maskSize = ee.Number(1).add(toBit).subtract(fromBit)
  var mask = ee.Number(1).leftShift(maskSize).subtract(1)
  return value.rightShift(fromBit).bitwiseAnd(mask)
}

https://code.earthengine.google.com/52f8f4ee6d2ab759e4f0fd1acb1ea2a9

13
  • Thank you for your comment. I actually want to classify the height at each point of the datasets (the value of rh99 for example). Which way should I follow? Mar 23, 2022 at 13:17
  • I've updated my answer. Mar 23, 2022 at 14:47
  • Thank you so much for this great work. I really need a tutorial for doing that. Mar 23, 2022 at 15:11
  • Just as an experiment, I updated the answer to include Sentinel 1 in the composites. Mar 23, 2022 at 16:05
  • Yess, Thank you. So for the Outofbag error, It's reduced a bit Mar 24, 2022 at 9:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.