#GISStackExchange
Google Earth Engine: Filtering feature collection with algorithms.If dictionary value checks
I've extracted a ton of pixel-value data for numerous study sites, across numerous days. I couldn't figure out how to do a precise extraction, so I just settled on extracting from all sites on ALL days at once. However, my goal is to compare against on-site measurements that were taken on certain days at each study site, so most of my extracted data won't match and is thus useless. I've gone through numerous iterations of this by now before always hitting dead-ends, but figured I'd give this one last attempt before just settling on manually filtering the CSV export outside of GEE. So, my GEE approach was to try and filter the otherwise final featureCollection by means of an algorithm.if, which tries to check each entry of the feature collection, and confirm if it matches exactly to an entry in a separate dictionary variable that lists when and where the on-site sampling happened. Sample of the erroneous function in question: var targetsDict = ee.Dictionary({ 'Brevard+Forest+2013-9-3': ee.Geometry.Point(-80.7987,28.3573), 'Citrus+Spivey+2013-7-1': ee.Geometry.Point(-82.3034,28.8322), // etc... 'Lake+Unity+2013-9-3': ee.Geometry.Point(-81.8796,28.8743), 'Lake+Winona+2013-4-12': ee.Geometry.Point(-81.7696,28.5482) }); // Function for checking if every feature in the feature collection has a match somewhere in the target list. // If it does match, do nothing. If it doesn't match and is thus unwanted data, change band 1 value to -9999 to later filter out var targetMatcher = function(feature) { // First pull the properties from the Feature such that it matches the name from the targetsDict var sampleName = feature.get("county") + "+" + feature.get("name") + "+" + feature.get("year") + "-" + feature.get("month") + "-" + feature.get("day"); // Then create a copy of the point feature by again reading the properties of the Feature var sampleLocation = ee.Geometry.Point(feature.get("long"),feature.get("lat")); ( // Confirm if there's a match between a target site and the feature class entry - lookup the name, then check the location ee.Algorithms.If(( // I've tested this comparison method on a separate script, and it did seem to work fine there at least ( targetsDict.getGeometry( sampleName ).distance( {'right': sampleLocation, 'maxError' : 1 } ).abs().lte( 0.01 ) )), // No idea though if just setting correct option to do nothing will work: (""), (feature.set("B1", -9999))) ); return feature; }; // Map the function over the post-cloud-filtered FeatureCollection. var targetFiltered = cloudFiltered.map(targetMatcher); // Filter out data that didn't pass the target-list check, AKA had it's band1 value set to -9999 // This SHOULD rule be ruling out a LOT of data... var fullyFiltered = outputData.filter(ee.Filter.gte("B1", -999)); print("This next featureCollection SHOULD be smaller"); print(fullyFiltered); Full script: https://code.earthengine.google.com/d789ba1c1310c248b73c5393f0eec9e3 Line 129 on is where this sample comes from. I'm brand new to all of this so I'm probably doing a lot wrong here. Basically, my idea was to just change the band1 value to -9999 if it fails the algorithm.if check, and then filter out any entries afterwards that have that low band 1 value. The dictionary check itself should work since I did test it here at least: https://code.earthengine.google.com/5daa191a96def560bf960a7d43a743b2 However, the final featureCollection is the same size as the one before it (should be WAY smaller), and doesn't appear to have changed any values. So, I've messed something up somewhere. Any ideas what I've done wrong, or what a better approach might be? Any advice welcome.
gis.stackexchange.com
September 8, 2025 at 8:05 PM
gdalwarp leaves black boundary of cropped GeoTIFF with cutline
This is a new question based on a response on the thread white page border when converting geoPDF to geoTiff with gdal_translate I am using gdalwarp as described to do a cutline of GeoTIFF images that have been rendered from geospatial PDFs. The neatline in the PDFs is not accurate but I can easily create UTM coordinates and adjust them accordingly to get the GeoTIFF image that I desire. This is the CSV file. The coordinates are not square id,WKT 1,"POLYGON ((410290.5552 4025996.01,410434.6684 4039895.26,421656.358 4039786.037,421530.3048 4025886.935,410290.5552 4025996.01))" This is the command line: gdalwarp original.tif original.crop.tif -cutline mycutline.csv -crop_to_cutline The new image is square and the cropped image is canted inside as is expected. The problem is that the outer crop area is showing up as black. When I tile the image and display it on top of a map base layer, it aligns perfectly except that it has a black edge around it. If the edging was transparent then it would be fine, but the when tiled, it definitely retains the black color. Here is a sample image http://www.appalachianbiketrails.org/images/resized.tif Here is the tile example http://www.appalachianbiketrails.org/tiles/openlayers.html I have tried adding the -dstalpha flag as mentioned in other posts and shown in the code snippet below, but that gives the error "Cannot compute bounding box of cutline." gdalwarp original.tif original.crop.tif -cutline mycutline.csv -crop_to_cutline -dstalpha On a side note, I found that the direction of the coordinates in my CSV file determined whether the crop was inside or outside of the coordinates.
gis.stackexchange.com
September 8, 2025 at 3:09 PM
Layer error in Google Earth Engine
I've had this error in Google Earth Engine trying to correct for sunglint in order to remote sense seagrass. The error reads as such: Sunglint Corrected: Layer error: Image.reduceRegion: Too many pixels in the region. Found 2048511108, but maxPixels allows only 10000000. Ensure that you are not aggregating at a higher resolution than you intended; that is a frequent cause of this error. If not, then you may set the 'maxPixels' argument to a limit suitable for your computation; set 'bestEffort' to true to aggregate at whatever scale results in 'maxPixels' total pixels; or both I've tried changing maxpixels, changing best effort to true, but so far I've had no luck. Here is my code. Here is also a link to it: https://code.earthengine.google.com/72ce8a26fa1d08d3f2c58d5da89e46d6 var dataset = ee.ImageCollection('COPERNICUS/S2_SR') .filterDate('2021-02-12', '2021-07-25') .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE',20)) .filterBounds(roi) .select(['B2','B3','B4','B1', 'B8']); var rgbVis = { min: 0.0, max: 1000, bands: ['B3', 'B2', 'B4'], }; Map.addLayer(dataset, rgbVis, 'Filtered Collection'); var mosaic = dataset.mosaic(); var medianComposite = dataset.min(); Map.addLayer(medianComposite, rgbVis, 'Median Composite', 0); var hansenImage = ee.Image('UMD/hansen/global_forest_change_2015'); var datamask = hansenImage.select('datamask'); var mask = datamask.eq(2); var maskedComposite = medianComposite.updateMask(mask); Map.addLayer(maskedComposite, rgbVis, 'masked'); Map.addLayer(maskedComposite, { bands: ['B4', 'B3', 'B2',], min: 0, max: 1000, scale:16, }, 'BOA'); var B2 = maskedComposite.select(['B8', 'B2']); var B3 = maskedComposite.select(['B8', 'B3']); var B4 = maskedComposite.select(['B8', 'B4']); var lfitB2 = B2.reduceRegion({ reducer: ee.Reducer.linearFit(), geometry: glint, scale: 5, tileScale: 16, maxPixels: 40e9, bestEffort: true }); var lfitB3 = B3.reduceRegion({ reducer: ee.Reducer.linearFit(), geometry: glint, scale: 5, tileScale: 16, maxPixels: 40e9, bestEffort: true, }); var lfitB4 = B4.reduceRegion({ reducer: ee.Reducer.linearFit(), geometry: glint, scale: 5, tileScale: 16, maxPixels: 40e9, bestEffort: true, }); print(lfitB4) //print('B2 OLS estimates:', lfitB2); //print('B2 y-intercept:', lfitB2.get('offset')); //print('B2 Slope:', lfitB2.get('scale')); //print('B3 Slope:', lfitB3.get('scale')); //print('B4 Slope:', lfitB4.get('scale')); var slope_B2 = ee.Image.constant(lfitB2.get('scale')).clip(roi).rename('slope_B2'); var slope_B3 = ee.Image.constant(lfitB3.get('scale')).clip(roi).rename('slope_B3'); var slope_B4 = ee.Image.constant(lfitB4.get('scale')).clip(roi).rename('slope_B4'); var min_B8 = ee.Image.constant(maskedComposite.select('B8').reduceRegion(ee.Reducer.min(),roi, 3).get('B8')).rename('min_B8'); var glint_factors = ee.Image([slope_B2, slope_B3, slope_B4, min_B8]); var S2 = maskedComposite.addBands(glint_factors); /*var deglint_B2 = S2.select('B8').subtract(min_B8); var deglint_B2 = slope_B2.multiply(deglint_B2); var deglint_B2 = S2.select('B2').subtract(deglint_B2); Map.addLayer(deglint_B2);*/ var deglint_B2 = S2.expression( 'Blue - (Slope * (NIR - MinNIR))', { 'Blue': S2.select('B2'), 'NIR': S2.select('B8'), 'MinNIR': S2.select('min_B8'), 'Slope': S2.select('slope_B2') }).rename('B2'); var deglint_B3 = S2.expression( 'Green - (Slope * (NIR - MinNIR))', { 'Green': S2.select('B3'), 'NIR': S2.select('B8'), 'MinNIR': S2.select('min_B8'), 'Slope': S2.select('slope_B3') }).rename('B3'); var deglint_B4 = S2.expression( 'Red - (Slope * (NIR - MinNIR))', { 'Red': S2.select('B4'), 'NIR': S2.select('B8'), 'MinNIR': S2.select('min_B8'), 'Slope': S2.select('slope_B4') }).rename('B4'); var S2_deglint = ee.Image([deglint_B2, deglint_B3, deglint_B4]); Map.addLayer(S2_deglint, { bands: ['B4', 'B3', 'B2'], min: 0.0, max: 40e9, scale: 5, tileScale: 16, bestEffort: true }, 'Sunglint Corrected'); var linkedMap = ui.Map(); Map.addLayer(S2, { bands: ['B4', 'B3', 'B2'], min: 0.0, max: 40e9, }, 'Top-of-Atmosphere Reflectance'); Map.addLayer(S2_deglint, {bands: ['B4', 'B3', 'B2'], min: 0.0, max: 0.2, scale: 16}, 'Sunglint Corrected'); var linker = ui.Map.Linker([ui.root.widgets().get(0), linkedMap]); var b2b3 = S2_deglint.select(['B2', 'B3']); var b2b4 = S2_deglint.select(['B2', 'B4']); var b3b4 = S2_deglint.select(['B3', 'B4']); var lfitb2b3 = b2b3.reduceRegion({ reducer: ee.Reducer.linearFit(), geometry: sand, scale: 16, bestEffort: true }); var lfitb2b4 = b2b4.reduceRegion({ reducer: ee.Reducer.linearFit(), geometry: sand, scale: 16, }); var lfitb3b4 = b3b4.reduceRegion({ reducer: ee.Reducer.linearFit(), geometry: sand, scale: 16, }); var slope_b2b3 = ee.Image.constant(lfitb2b3.get('scale')).clip(roi).rename('slope_b2b3'); var slope_b2b4 = ee.Image.constant(lfitb2b4.get('scale')).clip(roi).rename('slope_b2b4'); var slope_b3b4 = ee.Image.constant(lfitb3b4.get('scale')).clip(roi).rename('slope_b3b4'); var dii_slopes = ee.Image([slope_b2b3, slope_b2b4, slope_b3b4]); var S2_deglint = S2_deglint.addBands(dii_slopes); var dii_b2b3 = S2_deglint.expression( 'log(b2) - abs(slope * log(b3))', { 'b2': S2_deglint.select('B2'), 'b3': S2_deglint.select('B3'), 'slope': S2_deglint.select('slope_b2b3') }).rename('DII_b2b3'); var dii_b2b4 = S2_deglint.expression( 'log(b2) - abs(slope * log(b4))', { 'b2': S2_deglint.select('B2'), 'b4': S2_deglint.select('B4'), 'slope': S2_deglint.select('slope_b2b4') }).rename('DII_b2b4'); var dii_b3b4 = S2_deglint.expression( 'log(b3) - abs(slope * log(b4))', { 'b3': S2_deglint.select('B3'), 'b4': S2_deglint.select('B4'), 'slope': S2_deglint.select('slope_b3b4') }).rename('DII_b3b4'); var DII = ee.Image([dii_b2b3, dii_b2b4, dii_b3b4]) Map.addLayer(DII, { bands: ['DII_b2b4', 'DII_b3b4', 'DII_b2b3'], min: -7, max: -3 }, 'Depth-Invariant Index'); var training = maskedComposite.sample({ region: roi, scale: 5, tileScale: 16, numPixels: 3000 }); // Instantiate the clusterer and train it. var clusterer = ee.Clusterer.wekaKMeans(5).train(training); // Cluster the input using the trained clusterer. var result = maskedComposite.cluster(clusterer); // Display the clusters with random colors. Map.addLayer(result.randomVisualizer(), {}, 'clusters');
gis.stackexchange.com
September 8, 2025 at 2:12 PM
Mapping a function to an image collection, then displaying specific images from new collection Google Earth Engine
I'm trying to extract fires from a collection of Landsat images. I have this function that can process a single image, but when I try to use the Map function to map it onto a collection it doesn't seem to work. I think I'm also limited in my understanding of what the function is actually doing when I get the map function to work. After passing the collection through the function, is the collection just a new set of altered images? Or are the altered images stored somewhere else? var collection = ee.ImageCollection('LANDSAT/LC08/C01/T1_TOA') .filter(ee.Filter.eq('WRS_PATH', 100)) .filter(ee.Filter.eq('WRS_ROW', 49)); var point = ee.Geometry.Point([145.74720448921903,15.185623803783308]); var image = ee.Image( l8.filterBounds(point) .filterDate('2019-05-01', '2019-05-30') .sort('CLOUD_COVER') .first() ); var fullfunction = function(image){ var nir = image.select('B5'); var red = image.select('B7'); var burnindex = nir.subtract(red).divide(nir.add(red)); var saipan = burnindex.clip(boundary); var impervious2 = impervious.multiply(500); var saipan1 = saipan.subtract(impervious2); var mask2 = saipan1.gte(-1).and(saipan1.lt(0.15)); var secondmask = saipan1.updateMask(mask2); return secondmask; }; var finalimage = fullfunction(image); Map.addLayer(finalimage,{},'asdf'); //this works collection.map(fullfunction); //this doesn't
gis.stackexchange.com
September 8, 2025 at 12:06 PM