Error in Google Earth Engine: Computed value is too large - classification
I'm trying to achieve classification for image collection over 30 years as the code shows below:
var roi = ee.FeatureCollection("users/471033961/YellowRiver");
var empty = ee.Image().toByte();
var outline = empty.paint({
featureCollection:roi,
color:0,
width:3
});
Map.addLayer(outline, {palette: "ff0000"}, "outline");
//////////////////////////////landsat 5,7
function l57class(year){
var startDate = ee.Date.fromYMD(year, 1, 1);
var endDate = ee.Date.fromYMD(year+1, 1, 1);
var LC57_BANDS = ['B1', 'B2', 'B3', 'B4', 'B5', 'B7']; //Landsat57
var STD_NAMES = ['B2', 'B3', 'B4', 'B5', 'B6', 'B7'];
var cloudMaskL457 = function(image) {
var qa = image.select('pixel_qa');
// If the cloud bit (5) is set and the cloud confidence (7) is high
// or the cloud shadow bit is set (3), then it's a bad pixel.
var cloud = qa.bitwiseAnd(1 << 5)
.and(qa.bitwiseAnd(1 << 7))
.or(qa.bitwiseAnd(1 << 3));
// Remove edge pixels that don't occur in all bands
var mask2 = image.mask().reduce(ee.Reducer.min());
return image.updateMask(cloud.not()).updateMask(mask2);
}
var collection1 = ee.ImageCollection("LANDSAT/LE07/C01/T1_SR")
.filterDate(startDate, endDate)
.filterBounds(roi)
.filter(ee.Filter.lte('CLOUD_COVER',10))
.map(cloudMaskL457)
var collection2 = ee.ImageCollection("LANDSAT/LT05/C01/T1_SR")
.filterDate(startDate, endDate)
.filterBounds(roi)
.filter(ee.Filter.lte('CLOUD_COVER',10))
.map(cloudMaskL457)
var collection = collection1.merge(collection2).select(LC57_BANDS, STD_NAMES)
var image=collection.mosaic().clip(roi)
function NDWI(img){
var nir = img.select('B4');
var green = img.select('B2');
var ndwi = img.expression(
'(B3-B5)/(B3+B5)',
{
'B5':nir,
'B3':green
});
return ndwi;
}
function EWI(img){
var swir1 = img.select('B6')
var nir = img.select('B5');
var green = img.select('B3');
var ewi = img.expression(
'(B3-B5-B6)/(B3+B5+B6)',
{
'B6':swir1,
'B5':nir,
'B3':green
});
return ewi;
}
var MNDWI = image.normalizedDifference(['B3', 'B6']).rename('MNDWI');
var ndbi = image.normalizedDifference(['B6', 'B5']).rename('NDBI');
var ndvi = image.normalizedDifference(['B5', 'B4']).rename('NDVI');
var ewi = EWI(image).rename('EWI');
var ndwi = NDWI(image).rename('NDWI');
var lswi = image.normalizedDifference(['B5','B6']).rename('LSWI')
var nbr2 = image.normalizedDifference(["B6", "B7"]).rename("NBR2")
var awei = image.expression(
'4*(green-SWIR1)-(0.25*NIR+2.75*SWIR2)',{
green:image.select('B3'),
NIR:image.select('B5'),
SWIR1:image.select('B6'),
SWIR2:image.select('B7'),
}).float().rename('AWEI')
image=image
.addBands(ndvi)
.addBands(ndbi)
.addBands(MNDWI)
.addBands(ndwi)
.addBands(ewi)
.addBands(lswi)
.addBands(awei)
.addBands(nbr2)
var classNames = city.merge(water).merge(tree).merge(crop).merge(bare);
var bands = ['B2', 'B3', 'B4', 'B5', 'B6', 'B7','MNDWI','NDBI','NDVI','EWI','NDWI','AWEI','LSWI',"NBR2"];
var training = image.select(bands).sampleRegions({
collection: classNames,
properties: ['landcover'],
scale: 30
});
var withRandom = training.randomColumn('random');
var split = 0.8;
var trainingPartition = withRandom.filter(ee.Filter.lt('random', split));
var testingPartition = withRandom.filter(ee.Filter.gte('random', split));
var classProperty = 'landcover';
var classifier = ee.Classifier.smileRandomForest(100).train({
features: trainingPartition,
classProperty: 'landcover',
inputProperties: bands
});
var classified = image.select(bands).classify(classifier);
var test = testingPartition.classify(classifier);
var confusionMatrix = test.errorMatrix('landcover', 'classification');
print(year)
print('confusionMatrix',confusionMatrix);
print('overall accuracy', confusionMatrix.accuracy());
print('kappa accuracy', confusionMatrix.kappa());
Map.addLayer(classified,{}, "classified"+year);
Export.image.toDrive({
image: classified,
description: 'YR_cart'+year,
folder: 'YR_cart'+year,
scale: 30,
region: roi,
maxPixels:34e10
});
}
////////////////////////////////////////////////////////////////////////////////
function l8class(year){
var startDate = ee.Date.fromYMD(year, 1, 1);
var endDate = ee.Date.fromYMD(year+1, 1, 1);
var collection = ee.ImageCollection("LANDSAT/LC08/C01/T1_RT")
.filterDate(startDate, endDate)
.filterBounds(roi)
.filter(ee.Filter.lte('CLOUD_COVER',20))
var remove_cloud=function(collection)
{
var fun_calCloudScore = function(image) {
return ee.Algorithms.Landsat.simpleCloudScore(ee.Image(image));
};
var calCloudScore = ee.ImageCollection(collection)
.map(fun_calCloudScore)
;
var fun_maskCloud = function(image) {
var mask = image.select(['cloud']).lte(10);
return image.updateMask(mask);
};
var vsParam={band:['B2', 'B3', 'B4', 'B5', 'B6', 'B7'],min:0,max:0.3};
var maskCloud = ee.ImageCollection(calCloudScore)
.map(fun_maskCloud) ;
var maskCloud2=maskCloud.mean()
return maskCloud;
}
var image=remove_cloud(collection).mosaic().clip(roi);
function NDWI(img){
var nir = img.select('B4');
var green = img.select('B2');
var ndwi = img.expression(
'(B3-B5)/(B3+B5)',
{
'B5':nir,
'B3':green
});
return ndwi;
}
function EWI(img){
var swir1 = img.select('B6')
var nir = img.select('B5');
var green = img.select('B3');
var ewi = img.expression(
'(B3-B5-B6)/(B3+B5+B6)',
{
'B6':swir1,
'B5':nir,
'B3':green
});
return ewi;
}
var MNDWI = image.normalizedDifference(['B3', 'B6']).rename('MNDWI');
var ndbi = image.normalizedDifference(['B6', 'B5']).rename('NDBI');
var ndvi = image.normalizedDifference(['B5', 'B4']).rename('NDVI');
var ewi = EWI(image).rename('EWI');
var ndwi = NDWI(image).rename('NDWI');
var lswi = image.normalizedDifference(['B5','B6']).rename('LSWI')
var nbr2 = image.normalizedDifference(["B6", "B7"]).rename("NBR2")
var awei = image.expression(
'4*(green-SWIR1)-(0.25*NIR+2.75*SWIR2)',{
green:image.select('B3'),
NIR:image.select('B5'),
SWIR1:image.select('B6'),
SWIR2:image.select('B7'),
}).float().rename('AWEI')
image=image
.addBands(ndvi)
.addBands(ndbi)
.addBands(MNDWI)
.addBands(ndwi)
.addBands(ewi)
.addBands(lswi)
.addBands(awei)
.addBands(nbr2)
var classNames = city.merge(water).merge(tree).merge(crop).merge(bare);
var bands = ['B2', 'B3', 'B4', 'B5', 'B6', 'B7','MNDWI','NDBI','NDVI','EWI','NDWI','AWEI','LSWI',"NBR2"];
var training = image.select(bands).sampleRegions({
collection: classNames,
properties: ['landcover'],
scale: 30
});
var withRandom = training.randomColumn('random');
var split = 0.9;
var trainingPartition = withRandom.filter(ee.Filter.lt('random', split));
var testingPartition = withRandom.filter(ee.Filter.gte('random', split));
var classProperty = 'landcover';
var classifier = ee.Classifier.libsvm().train({
features: trainingPartition,
classProperty: 'landcover',
inputProperties: bands
});
var classified = image.select(bands).classify(classifier);
var test = testingPartition.classify(classifier);
var confusionMatrix = test.errorMatrix('landcover', 'classification');
print(year)
print('confusionMatrix',confusionMatrix);
print('overall accuracy', confusionMatrix.accuracy());
print('kappa accuracy', confusionMatrix.kappa());
Map.addLayer(classified,{}, "classified"+year);
Export.image.toDrive({
image: classified,
description: 'YR_cart'+year,
folder: 'YR_cart'+year,
scale: 30,
region: roi,
maxPixels:34e10
});
}
function main() {
var startYear = 2022;
var endYear = 2022;
for (var year=startYear; year<=endYear; year++) {
if (year >2012){l8class(year)}else{l57class(year)}
}
}
main();
I knew the study area was too big which lead to an error: "computed value is too large". Does anyone know how to solve this problem? better to revise based on this code if so.
Really appreciate it in advance!
To be honest I checked too many ideas but one of the effective ways I thought is to "break your study area into a bunch of tiles to calculate first, then combine all the results to get the final. However, It's just initial thinking that I didn't test.
Here is the link(you can ignore the comment in Chinese): https://code.earthengine.google.com/5d362229b959d96b9e4017571ba11a75
Related
I want to calculate and output the area of a year, but I keep showing the date
enter code here function processS2Collection(year,month, region) { var startDate = ee.Date.fromYMD(year, month, 1); var endDate = ee.Date.fromYMD(year, month+1, 1); var collection = ee.ImageCollection("COPERNICUS/S2") .filterDate('startDate, endDate') .filterBounds(roi) .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 80)) //.map(scaleS2Image) .map(maskS2clouds) .map(removeShadow) .map(addSnowIce) .map(addS2VIs) .median() ; var MNDWI_S2=collection.select('mNDWI'); var histogram = MNDWI_S2.reduceRegion({ reducer: ee.Reducer.histogram(), geometry: roi, scale: 30, maxPixels: 1e13, tileScale: 8 }); var threshold_S2 = otsu(histogram.get("mNDWI")); var threshold = ee.Number(threshold_S2); var mask = MNDWI_S2.gte(threshold); print(threshold,'threshold') var water_S2 = mask.updateMask(mask).rename("water"); var waterarea_S2_based=ee.Number((((water_S2.multiply(0.000001).multiply(ee.Image.pixelArea())) .reduceRegion({ reducer: ee.Reducer.sum(), geometry: roi, scale: 30, maxPixels: 1e13,})).get('water'))) Map.addLayer(water_S2.clip(table),{min:0,max:1,palette:['#DDDDDD','#FF3300']},'water_S2_otsu_based'); print('waterarea_S2_based',waterarea_S2_based) } for (var i=1; i<=11; i++) { var month=i; processS2Collection(2017,month, roi); } //I want to calculate and output the area of a year, but I keep showing the date //Source code link:https://code.earthengine.google.com/51a90e5845e6732d0f241fa4fda64c8a Anyone has a solution?
How to generate leaflet control from database
I wish to generate a custom dropdown filter, based on categories from a database. How is this achieved? In my example, this is (poorly) implemented with some hard coding and duplication. var serviceOverlays = [ {name:"Cardiology", value:"cardiology"}, {name:"Opthamology", value:"opthamology"} ]; var oSelect = L.control({position : 'topright'}); oSelect.onAdd = function (map) { var overlayParent = document.getElementById('new-parent'); // overlays div var node = L.DomUtil.create('select', 'leaflet-control'); node.innerHTML = '<option value="cardiologist">Cardioligist</option><option value="opthamology">Opthamology</option>'; overlayParent.appendChild(node); L.DomEvent.disableClickPropagation(node); L.DomEvent.on(node,'change',function(e){ var select = e.target; for(var name in serviceOverlays){ serviceOverlays[name].removeFrom(map); } serviceOverlays[select.value].addTo(map); }); Fiddle
I created a Control for you: L.Control.Select = L.Control.extend({ options: { position : 'topright' }, initialize(layers,options) { L.setOptions(this,options); this.layers = layers; }, onAdd(map) { this.overlayParent = L.DomUtil.create('div', 'leaflet-control select-control'); this.node = L.DomUtil.create('select', 'leaflet-control',this.overlayParent); L.DomEvent.disableClickPropagation(this.node); this.updateSelectOptions(); L.DomEvent.on(this.node,'change',(e)=>{ var select = e.target; for(var value in this.layers){ this.layers[value].layer.removeFrom(map); } this.layers[select.value].layer.addTo(map); }); return this.overlayParent; }, updateSelectOptions(){ var options = ""; if(this.layers){ for(var value in this.layers){ var layer = this.layers[value]; options += '<option value="'+value+'">'+layer.name+'</option>'; } } this.node.innerHTML = options; }, changeLayerData(layers){ this.layers = layers; this.updateSelectOptions(); } }); var oSelect = new L.Control.Select(serviceOverlays,{position : 'topright'}).addTo(map); The data structure have to be: var serviceOverlays = { "cardiology": {name:"Cardiology", layer: cities}, "opthamology": {name:"Opthamology", layer: badCities} }; Demo: https://jsfiddle.net/falkedesign/1rLntbo5/ You can also change the data dynamicl< with oSelect.changeLayerData(serviceOverlays2)
Google Sheets: Automated email when cell value is less than another
I am trying to make an inventory sheet where an automated email will be sent out when the inventory falls below a specific limit. I have set it so B2 is < C2, but I am not getting an email. function sendEmailAlert() { var sheet = SpreadsheetApp.getActiveSpreadsheet(); var rangeA = sheet.getRange('A2:A8'); var item = rangeA.getValues(); var rangeB = sheet.getRange('B2:B8'); var inventory = rangeB.getValues(); var rangeC = sheet.getRange('C2:C8'); var limit = rangeC.getValues(); var toEmail = 'XX#XX.com'; var subject = 'Inventory to Order'; var body = 'Item:' + item + 'needs to be ordered'; for (i in item){ if(inventory <= limit ) { MailApp.sendEmail(toEmail,subject, body); } } }
Try this: function sendEmailAlert() { var sheet=SpreadsheetApp.getActiveSpreadsheet(); var rangeA=sheet.getRange('A2:A8'); var item=rangeA.getValues(); var rangeB=sheet.getRange('B2:B8'); var inventory=rangeB.getValues(); var rangeC=sheet.getRange('C2:C8'); var limit=rangeC.getValues(); var toEmail='XX#XX.com'; var subject='Inventory to Order'; for (var i=0;i<item.length;i++){ if(inventory[i][0]<=limit[i][0]) { var body='Item:' + item[i][0] + 'needs to be ordered'; MailApp.sendEmail(toEmail,subject, body); } } } You could also add something like this if you want to avoid sending duplicates function sendEmailAlert() { var sheet=SpreadsheetApp.getActiveSpreadsheet(); var rangeA=sheet.getRange('A2:A8'); var item=rangeA.getValues(); var rangeB=sheet.getRange('B2:B8'); var inventory=rangeB.getValues(); var rangeC=sheet.getRange('C2:C8'); var limit=rangeC.getValues(); var rangeD=sheet.getRange('D2:D8'); var sent=rangeD.getValues(); var toEmail='XX#XX.com'; var subject='Inventory to Order'; for (var i=0;i<item.length;i++){ if(inventory[i][0]<=limit[i][0] && sent[i][0]!="sent") { var body='Item:' + item[i][0] + 'needs to be ordered'; MailApp.sendEmail(toEmail,subject, body); sent[i][0]="sent"; } } rangeD.setValues(sent); }
Sending multiple attachments using Google Spreadsheet and Google Script
Im trying to send multiple attachments using Google Spreadsheet but I get the following error "Cannot retrieve the next object: iterator has reached the end." It does work, because it sends the e-mail to the first email-address in the list, but it fails for the second one. I have seen similar questions here about it, but no solutions resolve my issue. Here is the script: function sendEmails() { var sheet = SpreadsheetApp.getActiveSheet(); var startRow = 1; var numRows = 2; var dataRange = sheet.getRange(startRow, 1, numRows, 2); var file1 = DriveApp.getFilesByName('Maandbrief December.pdf'); var file2 = DriveApp.getFilesByName('Weekendbrief 7-9 december.pdf'); var data = dataRange.getValues(); for (i in data) { var row = data[i]; var emailAddress = row[0]; var message = row[1]; var subject = "Maandbrief December en weekendbrief 7-9 december"; MailApp.sendEmail({to:emailAddress, subject:subject, body:message, attachments: [file1.next(), file2.next()]}) }} Thank you for your help.
Try this: function sendEmails() { var sheet = SpreadsheetApp.getActiveSheet(); var startRow = 1; var numRows = 2; var dataRange = sheet.getRange(startRow, 1, numRows, 2); var files1 = DriveApp.getFilesByName('Maandbrief December.pdf'); while(files1.hasNext()){var file1=files1.next();} var files2 = DriveApp.getFilesByName('Weekendbrief 7-9 december.pdf'); while(files2.hasNext()){var file2=files2.next();} var data = dataRange.getValues(); for (var i=0;i<data.length;i++) { var row = data[i]; var emailAddress = row[0]; var message = row[1]; var subject = "Maandbrief December en weekendbrief 7-9 december"; MailApp.sendEmail({to:emailAddress, subject:subject, body:message, attachments: [file1, file2]}) } } or this: function sendEmails() { var sheet = SpreadsheetApp.getActiveSheet(); var startRow = 1; var numRows = 2; var dataRange = sheet.getRange(startRow, 1, numRows, 2); var n1=0; var n2=0; var files1 = DriveApp.getFilesByName('Maandbrief December.pdf'); while(files1.hasNext()){var file1=files1.next();n1++;} var files2 = DriveApp.getFilesByName('Weekendbrief 7-9 december.pdf'); while(files2.hasNext()){var file2=files2.next();n2++} var data = dataRange.getValues(); if(n1==1 && n2==1){ for (var i=0;i<data.length;i++) { var row = data[i]; var emailAddress = row[0]; var message = row[1]; var subject = "Maandbrief December en weekendbrief 7-9 december"; MailApp.sendEmail({to:emailAddress, subject:subject, body:message, attachments: [file1, file2]}); } }else{ throw('More than one file with given name.'); } }
How Use GeoWithin with mongodb C# Driver 2.4
I need to use GeoWithin to find nearly point to the user after I take his location, did any body used before?
By the way This is a sample for near and GeoWithin: var point = GeoJson.Point(GeoJson.Geographic(-73.97, 40.77)); var filter = Builders<BsonDocument>.Filter.Near("location", point, 10); var a = collection.Find(filter1).Any(); var filter2 = Builders<BsonDocument>.Filter.GeoWithin("location", point); var b = collection.Find(filter2).Any(); you can also use GeoWithinPolygon and GeoWithinCenter. double[,] polygon = new double[,] { { -73.97, 40.77 }, { -73.9928, 40.7193 }, { -73.9375, 40.8303 }, { -73.97, 40.77 } }; var filter3 = Builders<BsonDocument>.Filter.GeoWithinPolygon("location", polygon); var c = collection.Find(filter3).Any(); var filter4 = Builders<BsonDocument>.Filter.GeoWithinCenter("location", -73.97, 40.77, 10); var d = collection.Find(filter4).Any(); Hope it helps.