How to filter a Google Earth Engine Image Collection by crs? - projection

I have a script to download Sentinel-1 images from Google Earth Engine, which works perfectly over UK regions and other parts of Europe. However, when I try to run it for a region of Norway, the image returned is blurred. I think this is because within the ee.imagecollection some of the images have a different crs projection.
Hence, my question is how do I filter the images to remove images with the other crs? Here is an example of how it looks in Google Earth Engine:
Sentinel-1 image of area of Norway in Google Earth Engine
and here is how a print out of the image collection looks like in Google Earth Engine showing the two projections (see features 0 and 3 showing EPSG: 32632 and EPSG 32633):
Print out in Google Earth Engine of Norway image collection
My Google Earth Engine Script is included below. To replicate the problem replace the Norway geometry with a drawn polygon.
var year = 2021;
var region = 9;
var mth = 'October';
var mthno1 = 10;
var mthno2 = 11;
var endday1 = 18;
var endday2 = 18;
var geometry = ee.FeatureCollection("users/nfigbfr/Norway");
var s1c = ee.ImageCollection('COPERNICUS/S1_GRD')
.filterBounds(geometry)
.filterDate(year+'-'+mthno1+'-'+endday1,year+'-'+mthno2+'-'+endday2)
.filter(ee.Filter.eq('transmitterReceiverPolarisation', ['VV','VH']))
.filter(ee.Filter.eq('instrumentMode', 'IW'))
.map(function(image) {
var edge = image.lt(-30.0);
var maskedImage = image.mask().and(edge.not());
return image.updateMask(maskedImage);
});
print(s1c)
var img = s1c.mean();
print(img)
var img = img.addBands(img.select('VV').subtract(img.select('VH')).rename('Ratio'));
var img = img.select(['VV','VH','Ratio']).toFloat();
print(img);
var img_display = img.select(['VV','VH','Ratio']).clip(geometry);
Map.centerObject(geometry);
Map.addLayer(img_display, {min: -25, max: 0});
Export.image.toDrive({
image: img,
description: 'Norway_mean_'+mth+year,
folder: 'Sentinel_1',
crs: 'EPSG:32632',
scale: 10,
maxPixels: 1e13,
region: geometry
});

The crs is a property of individual bands, not the images. I also haven't been able to find out if/how we can access the band properties for filtering.
However, here is a workaround:
var target_crs = 'EPSG:32671'
var s1c = ee.ImageCollection('COPERNICUS/S1_GRD')
.filterBounds(point)
.filterDate(year+'-'+mthno1+'-'+endday1,year+'-'+mthno2+'-'+endday2)
.filter(ee.Filter.eq('transmitterReceiverPolarisation', ['VV','VH']))
.filter(ee.Filter.eq('instrumentMode', 'IW'))
.map(function(image) {
var edge = image.lt(-30.0);
var maskedImage = image.mask().and(edge.not());
return image.updateMask(maskedImage);
})
.map(function(img){
var crs = img.select(['VV']).projection().crs()
var myImageWithProperties = x.set({
crs: crs})
return ee.Image(myImageWithProperties)
;})
.filter(ee.Filter.eq('crs', target_crs));
I added a .map() function that grabs the projection code (EPSG) from the VV band and sets it as an image property. Then we can filter the collection based on this property.
I've tried this on Sentinel-2 and it works fine. Still curious if there is a simpler way, though.
PS: this question is better suited for https://gis.stackexchange.com

Related

recursive function on each pixel in google earth engine

I want to filter time series in the google earth engine which requires two for loops over time-series of a single pixel. I searched around and not found any example related to this. I know about .map function and I am using it for the generation of RVI on the earth engine. I found about .toArray function but not found any example related to my problem.
I will appreciate any help in this regard. Also, I am new to the earth engine so this may be a trivial question for others.
This is the code that I have. I took it from a blog and modified it according to my need. I am stuck after this.
var sentinel1 = ee.ImageCollection('COPERNICUS/S1_GRD_FLOAT');
// Filter VH, IW
var vh = sentinel1
// Filter to get images with VV and VH dual polarization.
//.filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VH'))
// Filter to get images collected in interferometric wide swath mode.
.filter(ee.Filter.eq('instrumentMode', 'IW'))
// reduce to VH polarization
//.select('VH')
// filter 10m resolution
.filter(ee.Filter.eq('resolution_meters', 10));
// Filter to orbitdirection Descending
var vhDescending = vh.filter(ee.Filter.eq('orbitProperties_pass', 'DESCENDING'));
// Filter time 2015
var vhDesc2015 = vhDescending.filterDate(ee.Date('2021-01-01'), ee.Date('2021-04-30'));
// Filter to MKD roi
var s1_mkd = vhDesc2015.filterBounds(roi);
print('All metadata:', s1_mkd);
var count = s1_mkd.size();
print('Count: ', count);
//var dates = s1_mkd.aggregate_array("system:time_start")
//print('dates: ', dates);
var dates = s1_mkd
.map(function(image) {
return ee.Feature(null, {'date': image.date().format('YYYY-MM-dd')})
})
.distinct('date')
.aggregate_array('date')
print('dates: ', dates);
var featureCollection = ee.FeatureCollection(dates
.map(function(element){
return ee.Feature(null,{prop:element})}))
//Export a .csv table of date, mean NDVI for watershed
Export.table.toDrive({
collection: featureCollection,
description: 'Timeseries',
folder: 'WC_raw',
fileFormat: 'CSV',
});
var rvi4s1 = function(img){
var vh = img.select('VH');
var vv = img.select('VV');
var col = vv.divide(vv.add(vh)).sqrt().rename('dop');
var dop = col.select('dop')
var value = dop.multiply(vh.multiply(4).divide(vv.add(vh))).rename('rvi4s1');
return value;
};
var rvi = s1_mkd.map(rvi4s1);
print(rvi);

Google Earth Engine: Image intersection and inverse intersection

I am new to Google Earth Enginge and I struggle to bring together two images in Google Earth Engine to get the areas which are in both images and the areas which are only part of one image to show forest cover change (loss, gain, no change).
My code so far which seems to at least display what I want by stacking the images above each other:
var treeCanopyCoverVis = {
min: 0.0,
max: 100.0,
palette: ['ffffff', 'afce56', '5f9c00', '0e6a00', '003800'],
};
var forest2000 = ee.ImageCollection('NASA/MEASURES/GFCC/TC/v3')
.filterDate('2000-01-01', '2000-12-31')
.select('tree_canopy_cover')
.reduce(ee.Reducer.mean());
var forest2000_ab60 = forest2000.gt(60).selfMask();
Map.addLayer(forest2000_ab60, {palette: '#d80078'}, 'Loss');
var forest2015 = ee.ImageCollection('NASA/MEASURES/GFCC/TC/v3')
.filterDate('2015-01-01', '2015-12-31')
.select('tree_canopy_cover')
.reduce(ee.Reducer.mean());
var forest2015_ab60 = forest2015.gt(60).selfMask();
Map.addLayer(forest2015_ab60, {palette: '#ebb13a'}, 'Gain');
// var loss = forest2015_ab60.intersection(forest2000_ab60);
print(forest2015_ab60);
print(forest2000_ab60);
var remain = forest2015_ab60.and(forest2000_ab60);
Map.addLayer(remain, {palette: '#746d75'}, 'Remain');
With this code the gain still includes the remain part and the loss part also still includes the remain part. I need kind of the subtraction. All functions I now tried result in errors. I appreciate any help!
How my current result looks:
I could somehow solve it with try and error.
The code:
var forest2000 = ee.ImageCollection('NASA/MEASURES/GFCC/TC/v3')
.filterDate('2000-01-01', '2000-12-31')
.select('tree_canopy_cover')
.reduce(ee.Reducer.mean());
var forest2015 = ee.ImageCollection('NASA/MEASURES/GFCC/TC/v3')
.filterDate('2015-01-01', '2015-12-31')
.select('tree_canopy_cover')
.reduce(ee.Reducer.median());
var gain = forest2000.lt(60).and(forest2015.gt(60));
Map.addLayer(gain.selfMask(), {palette: '#ebb13a'}, 'gain');
var loss = forest2000.gt(60).and(forest2015.lt(60));
Map.addLayer(loss.selfMask(), {palette: '#d80078'}, 'loss');
var nochange = forest2000.gt(60).and(forest2015.gt(60));
Map.addLayer(nochange.selfMask(), {palette: '#746d75'}, 'no change');

"The service is currently unavailable" Google earth engine

I am trying to produce some Landsat images which are intersecting large rivers. The output of the code is ImageID. However, when I run the code, it takes about 5 mins and shows "The service is currently unavailable" or "User memory limit exceeded". I guess too many images are selected and sorted. Please help. Any suggestions would be truly appreciated.
https://code.earthengine.google.com/1167e0c6656b0e99a345d15643a671b7
var table2 = ee.FeatureCollection("users/bo_wang1/Yukon_River");
//1. Display the shapefile into the interactive map
//Display the view to the center of the screen and scale the view
Map.centerObject(table2,10);
//Define styling and determine the color of the shapefile
var styling = {color: 'red', fillColor: '00000000'};
Map.addLayer(table.style(styling));
//2. Loading L8 image collection (TOA reflectance)
var l8_collection= ee.ImageCollection('LANDSAT/LC08/C01/T1_SR');
//3. Filter by time window
var x1= l8_collection.filterBounds(table2)
.filterDate('2019-05-01', '2019-09-30')
.sort('CLOUD_COVER');
print ('L8 2019 image collection:',x1);
print('# images', x1.size());
// extract the different rows and paths
var distinctRows = x1.distinct(['WRS_ROW']).aggregate_array('WRS_ROW');
var distinctPaths = x1.distinct(['WRS_PATH']).aggregate_array('WRS_PATH');
print(distinctRows, distinctPaths)
//Extract least cloudy L8 scene in each tile
var imagePerPath = distinctPaths.map(function(path){
var imagePerRow = distinctRows.map(function(row){
var images = x1.filter(ee.Filter.and(ee.Filter.eq('WRS_ROW', row), ee.Filter.eq('WRS_PATH', path)));
return images.sort('CLOUD_COVER').first();
});
return imagePerRow;
});
var leastCloud = ee.ImageCollection.fromImages(imagePerPath.flatten());
// print and add the geometries of the images to the map
Map.addLayer(ee.FeatureCollection(leastCloud.map(function(image){return image.geometry()})))
print('leastCloud',leastCloud);
//Get the number of images
var count = leastCloud.size();
print('Count:', count);
//Get and print property and ImageID
print(leastCloud.first().propertyNames());
var imageID = leastCloud.aggregate_array('LANDSAT_ID');
print(imageID);
//Export Landsat_ID to CSV
Export.table.toDrive({
collection: leastCloud,
description: 'Get_ImageID',
folder: 'Shapefile from GEE',
fileFormat: 'CSV',
selectors: ['LANDSAT_ID'],
});

How to increase resolution of exported image in Google Earth Engine?

I have some code to export an LS8 image to Drive using GEE. Somehow, the resolution of the image seems to be lower (larger pixels) than what I am able to see on the browser. How can I increase the resolution? This is the code I´ve been using, with two different options.
I attempted to use .resample() as a solution but it produced a single band image that did not look good.
geometry2 = /* color: #57d64b */ee.Geometry.Polygon(
[[[-78.2812086867645, 2.3386717366200585],
[-77.56984394067075, 2.3729749945579948],
[-77.72227924340513, 2.776314152654142],
[-78.20842426293638, 2.725560942159387]]]);
function maskL8sr(image)
{
// Bits 3 and 5 are cloud shadow and cloud, respectively.
var cloudShadowBitMask = ee.Number(2).pow(3).int();
var cloudsBitMask = ee.Number(2).pow(5).int();
// Get the pixel QA band.
var qa = image.select('pixel_qa');
// Both flags should be set to zero, indicating clear conditions.
var mask = qa.bitwiseAnd(cloudShadowBitMask).eq(0)
.and(qa.bitwiseAnd(cloudsBitMask).eq(0));
// Return the masked image, scaled to TOA reflectance, without the QA bands.
return image.updateMask(mask).divide(10000)
.select("B[0-9]*")
.copyProperties(image, ["system:time_start"]);
}
// Map the function over one year of data.
var collection = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR')
.filterDate('2016-04-01', '2018-7-31')
.map(maskL8sr)
var composite = collection.median();
var VIS = {bands: ['B5', 'B6', 'B4'], min: 0, max: 0.47};
// Display the results.
Map.addLayer(composite,VIS ,"compt2");
var params ={
crs: 'EPSG:4326',
maxPixels: 1e12,
region:geometry2
}
Export.image(composite,'Guapi',params);
Export.image.toDrive({
image: composite,
description: 'Guapi',
scale: 30,
region: geometry2,
maxPixels: 1000000000
});

Google Maps JS API Fit Bounds Not Working

I'm having a very strange problem with my Google Maps implementation. I am getting back an array from a REST service that gives me lat/lng and I am in turn using that information to put markers on the map and implement functionality.
That part works fine, it's when it comes to taking the markers output on the page and getting their bounds and zooming the map to them that I get to the problem. I have read several solutions and I have attempted implementing them to the best of my ability.
Here's my implementation:
// Reset the maps bounds
MapView.bounds = new google.maps.LatLngBounds(null);
// Get the new map bounds
for (var i=0, j=MapView.markers.length; i<j; i++){
var marker = MapView.markers[i],
lat = marker.position.lat(),
lng = marker.position.lng(),
latlng = new google.maps.LatLng(lat, lng);
MapView.bounds.extend(latlng);
};
// Set the map bounds to the new bounds
MapView.map.fitBounds(MapView.bounds);
Here is a list of the coordinates being used:
21.245445,-105.167631
41.887668,-87.622522
49.817492,15.472962
50.075538,14.4378
33.951611,-118.387578
41.887668,-87.622522
14.782827,-90.793702
33.741973,-78.817013
45.922225,-95.408973
28.320306,-81.422964
36.166667,-86.783333
-17.82922,31.053961
-8.708704,115.169616
41.901514,12.460774
-34.013717,23.054811
20.483443,-86.971039
34.933333,34.083333
6.428055,-9.429499
38.79142,-95.960607
43.771033,11.248001
46.271588,13.95641
33.773,-78.779504
40.789342,-3.249749
20.926822,-156.695125
46.271588,13.95641
18.853921,-71.300939
36.462205,-5.011611
25.788969,-80.226439
50.36809,8.73632
37.540667,126.948346
45.495992,-121.5879
14.782827,-90.793701
0,0
13,-76
20.431006,-86.908065
40.75694,-73.984872
64.143935,-21.934099
-17.816667,25.15
12.879721,121.774017
32.640054,-117.084196
-16.522046,28.850942
40.280559,22.50584
39.202686,-106.831683
36.122611,-115.170973
38.79142,-95.960607
18.126285,-65.440099
22.876396,-109.918562
30.36884,-86.324846
36.076518,-115.153343
36.0443,14.251222
41.894809,-87.624214
36.0443,14.251222
-34.035086,23.046469
36.42,25.431667
-17.82922,31.053961
20.696686,-105.292631
18.533333,-68.366667
42.407211,-71.382437
21.158964,-86.845937
9.748917,-83.753428
14.782827,-90.793701
34.852965,32.361479
34.939737,32.461585
34.052234,-118.243685
64.143935,-21.934099
35.369598,24.482727
52.407927,3.222711
47.497912,19.040235
21.158964,-86.845937
37.446719,25.328862
21.160386,-86.843338
39.770247,21.182861
36.124253,-115.168476
46.421684,15.856075
116.468401,39.947856
41.553221,-70.608589
43.706449,7.292265
39.415044,21.737618
21.158964,-86.845937
20.629559,-87.126904
36.832012,25.897065
50.075538,14.4378
8.87509,98.352656
57.702051,11.982304
-24.183889,29.012778
38.904253,-77.047904
0,0
-25.360413,27.09947
55.940209,-3.225319
36.286023,-5.27918
-3.386069,39.971999
20.749045,-105.31098
17.280151,-62.689038
21.040195,-104.358146
14.782827,-90.793702
20.696686,-105.292631
50.071287,14.397221
51.891877,-8.493827
Then I used those bounds to create a poly line to try and find out where the problem was, and the wierd part is even that is wrong, but the map isn't even zooming/panning to THOSE bounds.
Code for poly line:
var ne = MapView.bounds.getNorthEast();
var sw = MapView.bounds.getSouthWest();
var boundingBoxPoints = [
ne, new google.maps.LatLng(ne.lat(), sw.lng()),
sw, new google.maps.LatLng(sw.lat(), ne.lng()), ne
];
var boundingBox = new google.maps.Polyline({
path: boundingBoxPoints,
strokeColor: '#FF0000',
strokeOpacity: 1.0,
strokeWeight: 2
});
boundingBox.setMap(MapView.map);
And a picture of the result (this is as the map loads, un-altered):
It will either load like that (if I'm lucky) or load with most of the trips out of the top of the map with only a couple showing and most of the map canvas gray.
I am a total loss right now, could somebody please point me in the right direction?

Resources