Skip to main content
Bumped by Community user
Bumped by Community user
Bumped by Community user
Bumped by Community user
deleted 1248 characters in body
Source Link

I am trying to run this code and keep getting the error: "Classified objects: Layer error: Collection.geometry: Unable to perform this geometry operation. Please specify a non-zero error margin". I assume it's because I the composite I used has some masked elements but I am not sure. The pixel-based classification works but not the OBIA.

//Retrieve image collection var collection = ee.ImageCollection("COPERNICUS/S2_SR")

//Draw the outline and clip the area of interest var states = ee.FeatureCollection("TIGER/2016/Counties");

//Choose the state of interest var states_outline = ee.FeatureCollection('TIGER/2018/States');

//Choose state code https://www.bls.gov/respondents/mwr/electronic-data-interchange/appendix-d-usps-state-abbreviations-and-fips-codes.htm //Choose county names of interest var state = states.filter(ee.Filter.eq('STATEFP', '48')); var county1 = state.filter(ee.Filter.eq('NAME', 'Lipscomb')); var county2 = state.filter(ee.Filter.eq('NAME', 'Ochiltree')); var county3 = state.filter(ee.Filter.eq('NAME', 'Hemphill')); var county4 = state.filter(ee.Filter.eq('NAME', 'Roberts')); var county5 = state.filter(ee.Filter.eq('NAME','Hutchinson')); var county6 = state.filter(ee.Filter.eq('NAME','Hansford')); var county7 = state.filter(ee.Filter.eq('NAME','Carson')); var county8 = state.filter(ee.Filter.eq('NAME','Gray')); var county9 = state.filter(ee.Filter.eq('NAME','Wheeler')); var county10 = state.filter(ee.Filter.eq('NAME','Denton')); var counties = county1.merge(county2).merge(county3).merge(county4).merge(county5) .merge(county6).merge(county7).merge(county8).merge(county9).merge(county10);

//Apply criteria var images = collection.filterBounds(counties) .filterDate('2022-04-01', '2022-09-15') .filterMetadata('CLOUDY_PIXEL_PERCENTAGE','less_than', 5) .sort("CLOUD_COVERAGE_ASSESSMENT") .map(maskS2clouds) .median() .clip(counties);

//Add visual parameters to the map - bands: natural colors var imageVisParam = {bands:['B4', 'B3', 'B2'], min:[0.10,0.10,0.10], max:[0.5,0.5,0.5]} Map.addLayer(images,imageVisParam,'Counties_clip');

//Calculate the ndvi

var ndvi = images.expression( ' ((NIR - RED) / (NIR + RED))', { 'NIR': images.select('B8'), 'RED': images.select('B4'),

}).rename('nd');

print(ndvi);

images = images.addBands(ndvi) print(images)

//var ndvi = images.normalizedDifference(['B4', 'B8']).rename('NDVI')

//var threshndvi = ndvi.gte(-0.057).and(ndvi.lte(0.004)) var threshndvi = ndvi.gte(-0.057).and(ndvi.lte(0.1)) var ndviVis = {min:0,max:1,palette:['white','green']} Map.addLayer(ndvi, ndviVis, "ndvi_treshold")

// Create a binary mask var mask = threshndvi.eq(1);

// Update the composite mask with the mask. var maskedcomposite = images.updateMask(mask); Map.addLayer(maskedcomposite, imageVisParam, "masked composite",true)

//Pixel-based classification

var SampleSize = 256 // You can reset SampleSize to other number; // The max here should be 2500, since you have only two class and so each of them could be half of 5000

var landcover_labels = 'landcover'

//combination of feature collections var combinedRoads = roads.merge(roads2).merge(roads3).merge(roads4);

var combinedGeometry = geometry.merge(polygons_DL)

var geometryCollection = combinedGeometry.limit(10);

var GeometryArea = ee.FeatureCollection. randomPoints(geometryCollection, SampleSize).map(function(i){ return i.set({'landcover': 1})})

var Nonfracking = ee.FeatureCollection. randomPoints(nonfracking, SampleSize).map(function(i){ return i.set({'landcover': 2})})

var RoadArea = ee.FeatureCollection. randomPoints(combinedRoads, SampleSize).map(function(i){ return i.set({'landcover': 3})})

// Train the feature collection containing my training sites (polygons) var trainingpoints = GeometryArea.merge(RoadArea).merge(Nonfracking);

print(trainingpoints)

//var newfc = geometry.merge(nonfracking).merge(roads2) var bands = ['nd']; var training = maskedcomposite.select(bands).sampleRegions({ collection: trainingpoints, properties: ['landcover'], scale: 20, geometries:true });

print(training,'training')

// Add a random column and split the GCPs into training and validation set var gcp = training.randomColumn() print(gcp,'gcp')

// We take the recommended ratio of 70% training, 30% validation var trainingGcp = gcp.filter(ee.Filter.gt('random', 0.3)); var validationGcp = gcp.filter(ee.Filter.lte('random', 0.3));

var classifier = ee.Classifier.smileRandomForest(50).train(trainingGcp, landcover_labels, bands //features: trainingGcp, landcover_labels, bands //classProperty: 'landcover', //inputProperties: bands );

var classified = maskedcomposite.select(bands).classify(classifier);

Map.addLayer(classified, {min: 0, max: 1, palette: ['#1e82ff', '#1c8b08', '#88ff72','#88ff72','#c2b2bc','#fbff2a','#008800']}, 'classification');

//Object-based classification var seeds = ee.Algorithms.Image.Segmentation.seedGrid(36);

print(maskedcomposite,'MC')

var snic = ee.Algorithms.Image.Segmentation.SNIC({ image: images, compactness: 0, connectivity: 8, neighborhoodSize: 64, size: 3, seeds: seeds });

print(snic,"snic");

Map.addLayer(snic.randomVisualizer(),{}, 'snic');

var clusters_snic = snic.select("clusters"); Map.addLayer(clusters_snic.randomVisualizer(),{}, 'clusters_snic'); print(clusters_snic,"clusters_snic");

// Compute per-cluster stdDev. var stdDev = images.addBands(clusters_snic).reduceConnectedComponents(ee.Reducer.stdDev(), 'clusters', 256) Map.addLayer(stdDev, {min:0, max:0.1}, 'StdDev', false)

// Area, Perimeter, Width and Height var area = ee.Image.pixelArea().addBands(clusters_snic).reduceConnectedComponents(ee.Reducer.sum(), 'clusters', 256) Map.addLayer(area, {min:50000, max: 500000}, 'Cluster Area', false)

var minMax = clusters_snic.reduceNeighborhood(ee.Reducer.minMax(), ee.Kernel.square(1)); var perimeterPixels = minMax.select(0).neq(minMax.select(1)).rename('perimeter'); Map.addLayer(perimeterPixels, {min: 0, max: 1}, 'perimeterPixels');

var perimeter = perimeterPixels.addBands(clusters_snic) .reduceConnectedComponents(ee.Reducer.sum(), 'clusters', 256); Map.addLayer(perimeter, {min: 100, max: 400}, 'Perimeter size', false);

var sizes = ee.Image.pixelLonLat().addBands(clusters_snic).reduceConnectedComponents(ee.Reducer.minMax(), 'clusters', 256) var width = sizes.select('longitude_max').subtract(sizes.select('longitude_min')).rename('width') var height = sizes.select('latitude_max').subtract(sizes.select('latitude_min')).rename('height') Map.addLayer(width, {min:0, max:0.02}, 'Cluster width', false) Map.addLayer(height, {min:0, max:0.02}, 'Cluster height', false)

var objectPropertiesImage = ee.Image.cat([ snic.select('nd_mean'), stdDev, area, perimeter, width, height ]).float();

print(objectPropertiesImage, 'opi')

var training_obia = objectPropertiesImage.addBands(classified.select('landcover')) .updateMask(seeds) .sample(geometry, 5) var classifier = ee.Classifier.smileRandomForest(10).train(training_obia, 'landcover') Map.addLayer(objectPropertiesImage.classify(classifier), {min:0, max:254}, 'Classified objects')


//Apply criteria
var images = collection.filterBounds(counties)
.filterDate('2022-04-01', '2022-09-15')
.filterMetadata('CLOUDY_PIXEL_PERCENTAGE','less_than', 5)
.sort("CLOUD_COVERAGE_ASSESSMENT")
.map(maskS2clouds)
.median()
.clip(counties);

//Add visual parameters to the map - bands: natural colors
var imageVisParam = {bands:['B4', 'B3', 'B2'], min:[0.10,0.10,0.10], max:[0.5,0.5,0.5]}
Map.addLayer(images,imageVisParam,'Counties_clip');

//Calculate the ndvi

var ndvi = images.expression(
   ' ((NIR - RED) / (NIR + RED))', {
     'NIR': images.select('B8'),
      'RED': images.select('B4'),
     
  }).rename('nd');

print(ndvi);

images = images.addBands(ndvi)
print(images)

//var ndvi = images.normalizedDifference(['B4', 'B8']).rename('NDVI')

//var threshndvi = ndvi.gte(-0.057).and(ndvi.lte(0.004))
var threshndvi = ndvi.gte(-0.057).and(ndvi.lte(0.1))
var ndviVis = {min:0,max:1,palette:['white','green']}
Map.addLayer(ndvi, ndviVis, "ndvi_treshold")

// Create a binary mask 
var mask = threshndvi.eq(1);

// Update the composite mask with the mask.
var maskedcomposite = images.updateMask(mask);
Map.addLayer(maskedcomposite, imageVisParam, "masked composite",true)

//Pixel-based classification

var SampleSize = 256 
// You can reset SampleSize to other number; 
// The max here should be 2500, since you have only two class and so each of them could be half of 5000

var landcover_labels = 'landcover'

//combination of feature collections
var combinedRoads = roads.merge(roads2).merge(roads3).merge(roads4);

var combinedGeometry = geometry.merge(polygons_DL)

var geometryCollection = combinedGeometry.limit(10);

var GeometryArea = ee.FeatureCollection.
                    randomPoints(geometryCollection, SampleSize).map(function(i){
  return i.set({'landcover': 1})})
  
var Nonfracking = ee.FeatureCollection.
                    randomPoints(nonfracking, SampleSize).map(function(i){
  return i.set({'landcover': 2})})

var RoadArea = ee.FeatureCollection.
                    randomPoints(combinedRoads, SampleSize).map(function(i){
  return i.set({'landcover': 3})})

// Train the feature collection containing my training sites (polygons)
var trainingpoints = GeometryArea.merge(RoadArea).merge(Nonfracking);

print(trainingpoints)

//var newfc = geometry.merge(nonfracking).merge(roads2)
  var bands = ['nd'];
    var training = maskedcomposite.select(bands).sampleRegions({
    collection: trainingpoints, 
    properties: ['landcover'], 
    scale: 20,
    geometries:true
    });
    
print(training,'training')

// Add a random column and split the GCPs into training and validation set
var gcp = training.randomColumn()
print(gcp,'gcp')

// We take the recommended ratio of 70% training, 30% validation
var trainingGcp = gcp.filter(ee.Filter.gt('random', 0.3));
var validationGcp = gcp.filter(ee.Filter.lte('random', 0.3));

var classifier = ee.Classifier.smileRandomForest(50).train(trainingGcp, landcover_labels, bands
  //features: trainingGcp, landcover_labels, bands
  //classProperty: 'landcover', 
  //inputProperties: bands
  );

var classified = maskedcomposite.select(bands).classify(classifier);

Map.addLayer(classified, 
{min: 0, max: 1, palette: ['#1e82ff', '#1c8b08', '#88ff72','#88ff72','#c2b2bc','#fbff2a','#008800']}, 
'classification');

//Object-based classification
var seeds = ee.Algorithms.Image.Segmentation.seedGrid(36);

print(maskedcomposite,'MC')

var snic = ee.Algorithms.Image.Segmentation.SNIC({
  image: images, 
  compactness: 0,
  connectivity: 8,
  neighborhoodSize: 64,
  size: 3,
  seeds: seeds
});

print(snic,"snic");

Map.addLayer(snic.randomVisualizer(),{}, 'snic');

var clusters_snic = snic.select("clusters");
Map.addLayer(clusters_snic.randomVisualizer(),{}, 'clusters_snic');
print(clusters_snic,"clusters_snic");

// Compute per-cluster stdDev.
var stdDev = images.addBands(clusters_snic).reduceConnectedComponents(ee.Reducer.stdDev(), 'clusters', 256)
Map.addLayer(stdDev, {min:0, max:0.1}, 'StdDev', false)

// Area, Perimeter, Width and Height
var area = ee.Image.pixelArea().addBands(clusters_snic).reduceConnectedComponents(ee.Reducer.sum(), 'clusters', 256)
Map.addLayer(area, {min:50000, max: 500000}, 'Cluster Area', false)

var minMax = clusters_snic.reduceNeighborhood(ee.Reducer.minMax(), ee.Kernel.square(1));
var perimeterPixels = minMax.select(0).neq(minMax.select(1)).rename('perimeter');
Map.addLayer(perimeterPixels, {min: 0, max: 1}, 'perimeterPixels');

var perimeter = perimeterPixels.addBands(clusters_snic)
    .reduceConnectedComponents(ee.Reducer.sum(), 'clusters', 256);
Map.addLayer(perimeter, {min: 100, max: 400}, 'Perimeter size', false);

var sizes = ee.Image.pixelLonLat().addBands(clusters_snic).reduceConnectedComponents(ee.Reducer.minMax(), 'clusters', 256)
var width = sizes.select('longitude_max').subtract(sizes.select('longitude_min')).rename('width')
var height = sizes.select('latitude_max').subtract(sizes.select('latitude_min')).rename('height')
Map.addLayer(width, {min:0, max:0.02}, 'Cluster width', false)
Map.addLayer(height, {min:0, max:0.02}, 'Cluster height', false)


var objectPropertiesImage = ee.Image.cat([
  snic.select('nd_mean'),
  stdDev,
  area,
  perimeter,
  width,
  height
]).float();

print(objectPropertiesImage, 'opi')

var training_obia = objectPropertiesImage.addBands(classified.select('landcover'))
    .updateMask(seeds)
    .sample(geometry, 5)
var classifier = ee.Classifier.smileRandomForest(10).train(training_obia, 'landcover')
Map.addLayer(objectPropertiesImage.classify(classifier), {min:0, max:254}, 'Classified objects')

I am trying to run this code and keep getting the error: "Classified objects: Layer error: Collection.geometry: Unable to perform this geometry operation. Please specify a non-zero error margin". I assume it's because I the composite I used has some masked elements but I am not sure.

//Retrieve image collection var collection = ee.ImageCollection("COPERNICUS/S2_SR")

//Draw the outline and clip the area of interest var states = ee.FeatureCollection("TIGER/2016/Counties");

//Choose the state of interest var states_outline = ee.FeatureCollection('TIGER/2018/States');

//Choose state code https://www.bls.gov/respondents/mwr/electronic-data-interchange/appendix-d-usps-state-abbreviations-and-fips-codes.htm //Choose county names of interest var state = states.filter(ee.Filter.eq('STATEFP', '48')); var county1 = state.filter(ee.Filter.eq('NAME', 'Lipscomb')); var county2 = state.filter(ee.Filter.eq('NAME', 'Ochiltree')); var county3 = state.filter(ee.Filter.eq('NAME', 'Hemphill')); var county4 = state.filter(ee.Filter.eq('NAME', 'Roberts')); var county5 = state.filter(ee.Filter.eq('NAME','Hutchinson')); var county6 = state.filter(ee.Filter.eq('NAME','Hansford')); var county7 = state.filter(ee.Filter.eq('NAME','Carson')); var county8 = state.filter(ee.Filter.eq('NAME','Gray')); var county9 = state.filter(ee.Filter.eq('NAME','Wheeler')); var county10 = state.filter(ee.Filter.eq('NAME','Denton')); var counties = county1.merge(county2).merge(county3).merge(county4).merge(county5) .merge(county6).merge(county7).merge(county8).merge(county9).merge(county10);

//Apply criteria var images = collection.filterBounds(counties) .filterDate('2022-04-01', '2022-09-15') .filterMetadata('CLOUDY_PIXEL_PERCENTAGE','less_than', 5) .sort("CLOUD_COVERAGE_ASSESSMENT") .map(maskS2clouds) .median() .clip(counties);

//Add visual parameters to the map - bands: natural colors var imageVisParam = {bands:['B4', 'B3', 'B2'], min:[0.10,0.10,0.10], max:[0.5,0.5,0.5]} Map.addLayer(images,imageVisParam,'Counties_clip');

//Calculate the ndvi

var ndvi = images.expression( ' ((NIR - RED) / (NIR + RED))', { 'NIR': images.select('B8'), 'RED': images.select('B4'),

}).rename('nd');

print(ndvi);

images = images.addBands(ndvi) print(images)

//var ndvi = images.normalizedDifference(['B4', 'B8']).rename('NDVI')

//var threshndvi = ndvi.gte(-0.057).and(ndvi.lte(0.004)) var threshndvi = ndvi.gte(-0.057).and(ndvi.lte(0.1)) var ndviVis = {min:0,max:1,palette:['white','green']} Map.addLayer(ndvi, ndviVis, "ndvi_treshold")

// Create a binary mask var mask = threshndvi.eq(1);

// Update the composite mask with the mask. var maskedcomposite = images.updateMask(mask); Map.addLayer(maskedcomposite, imageVisParam, "masked composite",true)

//Pixel-based classification

var SampleSize = 256 // You can reset SampleSize to other number; // The max here should be 2500, since you have only two class and so each of them could be half of 5000

var landcover_labels = 'landcover'

//combination of feature collections var combinedRoads = roads.merge(roads2).merge(roads3).merge(roads4);

var combinedGeometry = geometry.merge(polygons_DL)

var geometryCollection = combinedGeometry.limit(10);

var GeometryArea = ee.FeatureCollection. randomPoints(geometryCollection, SampleSize).map(function(i){ return i.set({'landcover': 1})})

var Nonfracking = ee.FeatureCollection. randomPoints(nonfracking, SampleSize).map(function(i){ return i.set({'landcover': 2})})

var RoadArea = ee.FeatureCollection. randomPoints(combinedRoads, SampleSize).map(function(i){ return i.set({'landcover': 3})})

// Train the feature collection containing my training sites (polygons) var trainingpoints = GeometryArea.merge(RoadArea).merge(Nonfracking);

print(trainingpoints)

//var newfc = geometry.merge(nonfracking).merge(roads2) var bands = ['nd']; var training = maskedcomposite.select(bands).sampleRegions({ collection: trainingpoints, properties: ['landcover'], scale: 20, geometries:true });

print(training,'training')

// Add a random column and split the GCPs into training and validation set var gcp = training.randomColumn() print(gcp,'gcp')

// We take the recommended ratio of 70% training, 30% validation var trainingGcp = gcp.filter(ee.Filter.gt('random', 0.3)); var validationGcp = gcp.filter(ee.Filter.lte('random', 0.3));

var classifier = ee.Classifier.smileRandomForest(50).train(trainingGcp, landcover_labels, bands //features: trainingGcp, landcover_labels, bands //classProperty: 'landcover', //inputProperties: bands );

var classified = maskedcomposite.select(bands).classify(classifier);

Map.addLayer(classified, {min: 0, max: 1, palette: ['#1e82ff', '#1c8b08', '#88ff72','#88ff72','#c2b2bc','#fbff2a','#008800']}, 'classification');

//Object-based classification var seeds = ee.Algorithms.Image.Segmentation.seedGrid(36);

print(maskedcomposite,'MC')

var snic = ee.Algorithms.Image.Segmentation.SNIC({ image: images, compactness: 0, connectivity: 8, neighborhoodSize: 64, size: 3, seeds: seeds });

print(snic,"snic");

Map.addLayer(snic.randomVisualizer(),{}, 'snic');

var clusters_snic = snic.select("clusters"); Map.addLayer(clusters_snic.randomVisualizer(),{}, 'clusters_snic'); print(clusters_snic,"clusters_snic");

// Compute per-cluster stdDev. var stdDev = images.addBands(clusters_snic).reduceConnectedComponents(ee.Reducer.stdDev(), 'clusters', 256) Map.addLayer(stdDev, {min:0, max:0.1}, 'StdDev', false)

// Area, Perimeter, Width and Height var area = ee.Image.pixelArea().addBands(clusters_snic).reduceConnectedComponents(ee.Reducer.sum(), 'clusters', 256) Map.addLayer(area, {min:50000, max: 500000}, 'Cluster Area', false)

var minMax = clusters_snic.reduceNeighborhood(ee.Reducer.minMax(), ee.Kernel.square(1)); var perimeterPixels = minMax.select(0).neq(minMax.select(1)).rename('perimeter'); Map.addLayer(perimeterPixels, {min: 0, max: 1}, 'perimeterPixels');

var perimeter = perimeterPixels.addBands(clusters_snic) .reduceConnectedComponents(ee.Reducer.sum(), 'clusters', 256); Map.addLayer(perimeter, {min: 100, max: 400}, 'Perimeter size', false);

var sizes = ee.Image.pixelLonLat().addBands(clusters_snic).reduceConnectedComponents(ee.Reducer.minMax(), 'clusters', 256) var width = sizes.select('longitude_max').subtract(sizes.select('longitude_min')).rename('width') var height = sizes.select('latitude_max').subtract(sizes.select('latitude_min')).rename('height') Map.addLayer(width, {min:0, max:0.02}, 'Cluster width', false) Map.addLayer(height, {min:0, max:0.02}, 'Cluster height', false)

var objectPropertiesImage = ee.Image.cat([ snic.select('nd_mean'), stdDev, area, perimeter, width, height ]).float();

print(objectPropertiesImage, 'opi')

var training_obia = objectPropertiesImage.addBands(classified.select('landcover')) .updateMask(seeds) .sample(geometry, 5) var classifier = ee.Classifier.smileRandomForest(10).train(training_obia, 'landcover') Map.addLayer(objectPropertiesImage.classify(classifier), {min:0, max:254}, 'Classified objects')

I am trying to run this code and keep getting the error: "Classified objects: Layer error: Collection.geometry: Unable to perform this geometry operation. Please specify a non-zero error margin". I assume it's because I the composite I used has some masked elements but I am not sure. The pixel-based classification works but not the OBIA.


//Apply criteria
var images = collection.filterBounds(counties)
.filterDate('2022-04-01', '2022-09-15')
.filterMetadata('CLOUDY_PIXEL_PERCENTAGE','less_than', 5)
.sort("CLOUD_COVERAGE_ASSESSMENT")
.map(maskS2clouds)
.median()
.clip(counties);

//Add visual parameters to the map - bands: natural colors
var imageVisParam = {bands:['B4', 'B3', 'B2'], min:[0.10,0.10,0.10], max:[0.5,0.5,0.5]}
Map.addLayer(images,imageVisParam,'Counties_clip');

//Calculate the ndvi

var ndvi = images.expression(
   ' ((NIR - RED) / (NIR + RED))', {
     'NIR': images.select('B8'),
      'RED': images.select('B4'),
     
  }).rename('nd');

print(ndvi);

images = images.addBands(ndvi)
print(images)

//var ndvi = images.normalizedDifference(['B4', 'B8']).rename('NDVI')

//var threshndvi = ndvi.gte(-0.057).and(ndvi.lte(0.004))
var threshndvi = ndvi.gte(-0.057).and(ndvi.lte(0.1))
var ndviVis = {min:0,max:1,palette:['white','green']}
Map.addLayer(ndvi, ndviVis, "ndvi_treshold")

// Create a binary mask 
var mask = threshndvi.eq(1);

// Update the composite mask with the mask.
var maskedcomposite = images.updateMask(mask);
Map.addLayer(maskedcomposite, imageVisParam, "masked composite",true)

//Pixel-based classification

var SampleSize = 256 
// You can reset SampleSize to other number; 
// The max here should be 2500, since you have only two class and so each of them could be half of 5000

var landcover_labels = 'landcover'

//combination of feature collections
var combinedRoads = roads.merge(roads2).merge(roads3).merge(roads4);

var combinedGeometry = geometry.merge(polygons_DL)

var geometryCollection = combinedGeometry.limit(10);

var GeometryArea = ee.FeatureCollection.
                    randomPoints(geometryCollection, SampleSize).map(function(i){
  return i.set({'landcover': 1})})
  
var Nonfracking = ee.FeatureCollection.
                    randomPoints(nonfracking, SampleSize).map(function(i){
  return i.set({'landcover': 2})})

var RoadArea = ee.FeatureCollection.
                    randomPoints(combinedRoads, SampleSize).map(function(i){
  return i.set({'landcover': 3})})

// Train the feature collection containing my training sites (polygons)
var trainingpoints = GeometryArea.merge(RoadArea).merge(Nonfracking);

print(trainingpoints)

//var newfc = geometry.merge(nonfracking).merge(roads2)
  var bands = ['nd'];
    var training = maskedcomposite.select(bands).sampleRegions({
    collection: trainingpoints, 
    properties: ['landcover'], 
    scale: 20,
    geometries:true
    });
    
print(training,'training')

// Add a random column and split the GCPs into training and validation set
var gcp = training.randomColumn()
print(gcp,'gcp')

// We take the recommended ratio of 70% training, 30% validation
var trainingGcp = gcp.filter(ee.Filter.gt('random', 0.3));
var validationGcp = gcp.filter(ee.Filter.lte('random', 0.3));

var classifier = ee.Classifier.smileRandomForest(50).train(trainingGcp, landcover_labels, bands
  //features: trainingGcp, landcover_labels, bands
  //classProperty: 'landcover', 
  //inputProperties: bands
  );

var classified = maskedcomposite.select(bands).classify(classifier);

Map.addLayer(classified, 
{min: 0, max: 1, palette: ['#1e82ff', '#1c8b08', '#88ff72','#88ff72','#c2b2bc','#fbff2a','#008800']}, 
'classification');

//Object-based classification
var seeds = ee.Algorithms.Image.Segmentation.seedGrid(36);

print(maskedcomposite,'MC')

var snic = ee.Algorithms.Image.Segmentation.SNIC({
  image: images, 
  compactness: 0,
  connectivity: 8,
  neighborhoodSize: 64,
  size: 3,
  seeds: seeds
});

print(snic,"snic");

Map.addLayer(snic.randomVisualizer(),{}, 'snic');

var clusters_snic = snic.select("clusters");
Map.addLayer(clusters_snic.randomVisualizer(),{}, 'clusters_snic');
print(clusters_snic,"clusters_snic");

// Compute per-cluster stdDev.
var stdDev = images.addBands(clusters_snic).reduceConnectedComponents(ee.Reducer.stdDev(), 'clusters', 256)
Map.addLayer(stdDev, {min:0, max:0.1}, 'StdDev', false)

// Area, Perimeter, Width and Height
var area = ee.Image.pixelArea().addBands(clusters_snic).reduceConnectedComponents(ee.Reducer.sum(), 'clusters', 256)
Map.addLayer(area, {min:50000, max: 500000}, 'Cluster Area', false)

var minMax = clusters_snic.reduceNeighborhood(ee.Reducer.minMax(), ee.Kernel.square(1));
var perimeterPixels = minMax.select(0).neq(minMax.select(1)).rename('perimeter');
Map.addLayer(perimeterPixels, {min: 0, max: 1}, 'perimeterPixels');

var perimeter = perimeterPixels.addBands(clusters_snic)
    .reduceConnectedComponents(ee.Reducer.sum(), 'clusters', 256);
Map.addLayer(perimeter, {min: 100, max: 400}, 'Perimeter size', false);

var sizes = ee.Image.pixelLonLat().addBands(clusters_snic).reduceConnectedComponents(ee.Reducer.minMax(), 'clusters', 256)
var width = sizes.select('longitude_max').subtract(sizes.select('longitude_min')).rename('width')
var height = sizes.select('latitude_max').subtract(sizes.select('latitude_min')).rename('height')
Map.addLayer(width, {min:0, max:0.02}, 'Cluster width', false)
Map.addLayer(height, {min:0, max:0.02}, 'Cluster height', false)


var objectPropertiesImage = ee.Image.cat([
  snic.select('nd_mean'),
  stdDev,
  area,
  perimeter,
  width,
  height
]).float();

print(objectPropertiesImage, 'opi')

var training_obia = objectPropertiesImage.addBands(classified.select('landcover'))
    .updateMask(seeds)
    .sample(geometry, 5)
var classifier = ee.Classifier.smileRandomForest(10).train(training_obia, 'landcover')
Map.addLayer(objectPropertiesImage.classify(classifier), {min:0, max:254}, 'Classified objects')
Source Link

GEE OBIA - Non-zero error margin

I am trying to run this code and keep getting the error: "Classified objects: Layer error: Collection.geometry: Unable to perform this geometry operation. Please specify a non-zero error margin". I assume it's because I the composite I used has some masked elements but I am not sure.

My code is below:

//Retrieve image collection var collection = ee.ImageCollection("COPERNICUS/S2_SR")

//Draw the outline and clip the area of interest var states = ee.FeatureCollection("TIGER/2016/Counties");

//Choose the state of interest var states_outline = ee.FeatureCollection('TIGER/2018/States');

//Choose state code https://www.bls.gov/respondents/mwr/electronic-data-interchange/appendix-d-usps-state-abbreviations-and-fips-codes.htm //Choose county names of interest var state = states.filter(ee.Filter.eq('STATEFP', '48')); var county1 = state.filter(ee.Filter.eq('NAME', 'Lipscomb')); var county2 = state.filter(ee.Filter.eq('NAME', 'Ochiltree')); var county3 = state.filter(ee.Filter.eq('NAME', 'Hemphill')); var county4 = state.filter(ee.Filter.eq('NAME', 'Roberts')); var county5 = state.filter(ee.Filter.eq('NAME','Hutchinson')); var county6 = state.filter(ee.Filter.eq('NAME','Hansford')); var county7 = state.filter(ee.Filter.eq('NAME','Carson')); var county8 = state.filter(ee.Filter.eq('NAME','Gray')); var county9 = state.filter(ee.Filter.eq('NAME','Wheeler')); var county10 = state.filter(ee.Filter.eq('NAME','Denton')); var counties = county1.merge(county2).merge(county3).merge(county4).merge(county5) .merge(county6).merge(county7).merge(county8).merge(county9).merge(county10);

//Apply criteria var images = collection.filterBounds(counties) .filterDate('2022-04-01', '2022-09-15') .filterMetadata('CLOUDY_PIXEL_PERCENTAGE','less_than', 5) .sort("CLOUD_COVERAGE_ASSESSMENT") .map(maskS2clouds) .median() .clip(counties);

//Add visual parameters to the map - bands: natural colors var imageVisParam = {bands:['B4', 'B3', 'B2'], min:[0.10,0.10,0.10], max:[0.5,0.5,0.5]} Map.addLayer(images,imageVisParam,'Counties_clip');

//Calculate the ndvi

var ndvi = images.expression( ' ((NIR - RED) / (NIR + RED))', { 'NIR': images.select('B8'), 'RED': images.select('B4'),

}).rename('nd');

print(ndvi);

images = images.addBands(ndvi) print(images)

//var ndvi = images.normalizedDifference(['B4', 'B8']).rename('NDVI')

//var threshndvi = ndvi.gte(-0.057).and(ndvi.lte(0.004)) var threshndvi = ndvi.gte(-0.057).and(ndvi.lte(0.1)) var ndviVis = {min:0,max:1,palette:['white','green']} Map.addLayer(ndvi, ndviVis, "ndvi_treshold")

// Create a binary mask var mask = threshndvi.eq(1);

// Update the composite mask with the mask. var maskedcomposite = images.updateMask(mask); Map.addLayer(maskedcomposite, imageVisParam, "masked composite",true)

//Pixel-based classification

var SampleSize = 256 // You can reset SampleSize to other number; // The max here should be 2500, since you have only two class and so each of them could be half of 5000

var landcover_labels = 'landcover'

//combination of feature collections var combinedRoads = roads.merge(roads2).merge(roads3).merge(roads4);

var combinedGeometry = geometry.merge(polygons_DL)

var geometryCollection = combinedGeometry.limit(10);

var GeometryArea = ee.FeatureCollection. randomPoints(geometryCollection, SampleSize).map(function(i){ return i.set({'landcover': 1})})

var Nonfracking = ee.FeatureCollection. randomPoints(nonfracking, SampleSize).map(function(i){ return i.set({'landcover': 2})})

var RoadArea = ee.FeatureCollection. randomPoints(combinedRoads, SampleSize).map(function(i){ return i.set({'landcover': 3})})

// Train the feature collection containing my training sites (polygons) var trainingpoints = GeometryArea.merge(RoadArea).merge(Nonfracking);

print(trainingpoints)

//var newfc = geometry.merge(nonfracking).merge(roads2) var bands = ['nd']; var training = maskedcomposite.select(bands).sampleRegions({ collection: trainingpoints, properties: ['landcover'], scale: 20, geometries:true });

print(training,'training')

// Add a random column and split the GCPs into training and validation set var gcp = training.randomColumn() print(gcp,'gcp')

// We take the recommended ratio of 70% training, 30% validation var trainingGcp = gcp.filter(ee.Filter.gt('random', 0.3)); var validationGcp = gcp.filter(ee.Filter.lte('random', 0.3));

var classifier = ee.Classifier.smileRandomForest(50).train(trainingGcp, landcover_labels, bands //features: trainingGcp, landcover_labels, bands //classProperty: 'landcover', //inputProperties: bands );

var classified = maskedcomposite.select(bands).classify(classifier);

Map.addLayer(classified, {min: 0, max: 1, palette: ['#1e82ff', '#1c8b08', '#88ff72','#88ff72','#c2b2bc','#fbff2a','#008800']}, 'classification');

//Object-based classification var seeds = ee.Algorithms.Image.Segmentation.seedGrid(36);

print(maskedcomposite,'MC')

var snic = ee.Algorithms.Image.Segmentation.SNIC({ image: images, compactness: 0, connectivity: 8, neighborhoodSize: 64, size: 3, seeds: seeds });

print(snic,"snic");

Map.addLayer(snic.randomVisualizer(),{}, 'snic');

var clusters_snic = snic.select("clusters"); Map.addLayer(clusters_snic.randomVisualizer(),{}, 'clusters_snic'); print(clusters_snic,"clusters_snic");

// Compute per-cluster stdDev. var stdDev = images.addBands(clusters_snic).reduceConnectedComponents(ee.Reducer.stdDev(), 'clusters', 256) Map.addLayer(stdDev, {min:0, max:0.1}, 'StdDev', false)

// Area, Perimeter, Width and Height var area = ee.Image.pixelArea().addBands(clusters_snic).reduceConnectedComponents(ee.Reducer.sum(), 'clusters', 256) Map.addLayer(area, {min:50000, max: 500000}, 'Cluster Area', false)

var minMax = clusters_snic.reduceNeighborhood(ee.Reducer.minMax(), ee.Kernel.square(1)); var perimeterPixels = minMax.select(0).neq(minMax.select(1)).rename('perimeter'); Map.addLayer(perimeterPixels, {min: 0, max: 1}, 'perimeterPixels');

var perimeter = perimeterPixels.addBands(clusters_snic) .reduceConnectedComponents(ee.Reducer.sum(), 'clusters', 256); Map.addLayer(perimeter, {min: 100, max: 400}, 'Perimeter size', false);

var sizes = ee.Image.pixelLonLat().addBands(clusters_snic).reduceConnectedComponents(ee.Reducer.minMax(), 'clusters', 256) var width = sizes.select('longitude_max').subtract(sizes.select('longitude_min')).rename('width') var height = sizes.select('latitude_max').subtract(sizes.select('latitude_min')).rename('height') Map.addLayer(width, {min:0, max:0.02}, 'Cluster width', false) Map.addLayer(height, {min:0, max:0.02}, 'Cluster height', false)

var objectPropertiesImage = ee.Image.cat([ snic.select('nd_mean'), stdDev, area, perimeter, width, height ]).float();

print(objectPropertiesImage, 'opi')

var training_obia = objectPropertiesImage.addBands(classified.select('landcover')) .updateMask(seeds) .sample(geometry, 5) var classifier = ee.Classifier.smileRandomForest(10).train(training_obia, 'landcover') Map.addLayer(objectPropertiesImage.classify(classifier), {min:0, max:254}, 'Classified objects')