I am carrying out a hybrid classification based on OBIA, following the magnificent code that Noel Gorelick and company developed:
https://code.earthengine.google.com/?scriptPath=users%2Fnclinton%2FEE101%3A14%20-%20OBIA
It is just a trial but I would like to see the differences between a hybrid classification considering OBIA and without considering OBIA.
When I run the code, I get the following error: Output of image computation is too large (8 bands for 3733050 pixels = 113.9 MiB > 80.0 MiB). If this is a reduction, try specifying a larger 'tileScale' parameter.
I am confused, I do not really understand where to specify the 'tileScale' parameter.
The code is the following:
https://code.earthengine.google.com/5bb30c868bb6442b60bc688acdf6ae96
var region = geometry
/////////////////////////////// SENTINEL 1///////////////////////////////////////////
// Get the VV collection.
var collectionVV = ee.ImageCollection('COPERNICUS/S1_GRD')
.filterBounds(geometry)
.select('VV','VH')
// Create a 3 band stack by selecting from different periods (months)
var im1 = ee.Image(collectionVV.filterDate('2020-05-15', '2020-05-19').mean().divide(100));
print(im1)
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);
}
//////////////////////SENTINEL 2/////////////////////////////////////////////////
// Map the function over one year of data and take the median.
// Load Sentinel-2 TOA reflectance data.
var col = ee.ImageCollection('COPERNICUS/S2')
.filterDate('2020-05-01', '2020-05-30')
// Pre-filter to get less cloudy granules.
.filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 20))
.map(maskS2clouds)
.filterBounds(geometry)
print(col)
//// PALETTE /////
var rgbVis = {
min: 0.0,
max: 0.3,
bands: ['B4', 'B3', 'B2'],
};
///////////////////////////////ADD BANDS TOGETHER/////////////////////////////////////
// Function to add an NDVI band, treat as above function
var addNDVI = function(image) {
return image
.addBands(image.normalizedDifference(['B5', 'B4'])
.rename('NDVI'))
.float();
};
// Function to add an NDVI band, treat as above function
var addSAVI = function(image) {
return image
.addBands(image.expression(
'(1 + L) * float(nir - red)/ (nir + red + L)',
{
'nir': image.select('B8'),
'red': image.select('B4'),
'L': 0.2
})
.rename('SAVI'))
.float();
};
var addSENTINEL1 = function(image) {
return image
.addBands(im1.select('VV','VH'))
.float();
};
var dataset = col.map(addSAVI).map(addNDVI).map(addSENTINEL1);
var sentinel = dataset.median().select("B2",'B3','B4','B8', 'NDVI', 'SAVI', 'VV', 'VH').clip(geometry)
var addSENTINEL1 = function(image) {
return image
.addBands(im1.select('VV','VH'))
.float();
};
print(sentinel)
////////////////// SEGMENTATION ///////////////////////////
////Cada seed inicia un objeto nuevo
//Malla de puntos. A partir de estos puntos los clusteres se desarrollaran.
//El numero de seeds ha de ser acorde a los objetos que se quieren encontrar.
//Para encontrar carreteras u objetos mas pequenyos que los crops, se necesitaria una malla con mas seeds
var seeds = ee.Algorithms.Image.Segmentation.seedGrid(15);
//Map.addLayer(seeds)
// Run SNIC on the regular square grid. (re-name the bands)
var segmentation = ee.Algorithms.Image.Segmentation.SNIC({
image: sentinel,
size: 5,
compactness: 5,
connectivity: 8,
neighborhoodSize:256,
seeds: seeds
}).select(["B2_mean",'B3_mean','B4_mean','B8_mean', 'NDVI_mean', 'SAVI_mean', 'VV_mean', 'VH_mean', 'clusters'], ["B2",'B3','B4','B8', 'NDVI', 'SAVI', 'VV', 'VH', 'clusters'])
print(segmentation)
var clusters = segmentation.select('clusters')
//Map.addLayer(segmentation)
//Map.addLayer(sentinel, rgbVis, 'RGB');
////// REDUCE COMPONENTS in order to get OBJECT VARIABLES //////////////////
//.reduceConnectedComponents (reduce todos los componentes de un cluster a un valor)
// Compute per-cluster stdDev. Indicador de buenos clusters y malos clusters (setdDev alta representa peores clusters)
var stdDev = sentinel.addBands(clusters).reduceConnectedComponents(ee.Reducer.stdDev(), 'clusters', 256)
//Map.addLayer(stdDev, {min:0, max:0.1}, 'StdDev', false)
// Area, Perimeter, Width and Height (cada valor dle pixel representa el area, perimetro y medidas de todo el cluster.
//todos los pixeles tienen el mismo valor dentro del cluster)
var area = ee.Image.pixelArea().addBands(clusters).reduceConnectedComponents(ee.Reducer.sum(), 'clusters', 256)
//Map.addLayer(area, {min:50000, max: 500000}, 'Cluster Area', false)
var minMax = clusters.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)
.reduceConnectedComponents(ee.Reducer.sum(), 'clusters', 256);
//Map.addLayer(perimeter, {min: 100, max: 400}, 'Perimeter size', false);
var sizes = ee.Image.pixelLonLat().addBands(clusters).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)
//////// PUT ALL BANDS TOGETHER (Concatenate) ///////////////
var objectPropertiesImage = ee.Image.cat([
segmentation,
stdDev,
area,
perimeter,
width,
height
]).float();
print(objectPropertiesImage, 'ObjectProperties')
////////////////////// UNSUPERVISED CLASSIFICATION ////////////////////
// training region is the full image
var training = objectPropertiesImage.sample({
region: geometry,
scale: 10,
numPixels: 1000
})
print( objectPropertiesImage.reduceRegion({
reducer: ee.Reducer.count(),
geometry: geometry,
scale: 10,
maxPixels: 1e13
})
)
// train cluster on image
var clusterer = ee.Clusterer.wekaKMeans(60).train(training)
// cluster the complete image
var result_unsupervised = objectPropertiesImage.cluster(clusterer)
////////////////////// SUPERVISED CLASSIFICATION RANDOM FORESTS based on properties image /////////////////////////
////// creating training data and test data ////////////
var TrainingData = urban.merge(water).merge(crops1).merge(bare_crops).merge(roads).randomColumn("random");
print(TrainingData)
var trainingData = TrainingData.filter(ee.Filter.lt("random",0.8))
var testData = TrainingData.filter(ee.Filter.gt("random",0.8))
///// blending training data into the Image /////////////
var TrainingSample = result_unsupervised.sampleRegions(trainingData,["land_class"],10);
var TestSample = result_unsupervised.sampleRegions(testData,["land_class"],10);
var bandNames = result_unsupervised.bandNames()
print(TrainingSample)
var classifier = ee.Classifier.randomForest(20,0).train(TrainingSample,"land_class",bandNames);
var classification = result_unsupervised.classify(classifier);
print(classification);
Map.addLayer(classification.randomVisualizer())