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.
My code is below:
//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')