clip image results to a ROI in Google Earth Engine - mapping

I have developed a time series of sea surface temperatures for a specific region of interest in Google Earth Engine. Running the code below displays the sea surface temperatures from the entire data set
Map.addLayer(BIOT)
// Load an image.
var sst = ee.ImageCollection('NASA/OCEANDATA/MODIS-Aqua/L3SMI').select('sst')
.filterDate('2013-01-01', '2018-01-01')
.filterBounds(BIOT);
print('sst', sst)
var TS1 = Chart.image.series(sst, BIOT,  ee.Reducer.mean(),
1000, 'system:time_start').setOptions({title: 'BIOT SST',vAxis: {title: 'SST
Celsius'},
});
print(TS1);
Map.setCenter(72.25, -6.8, 7); //lat, long, zoom
Map.addLayer (sst, {'min': 23, 'max': 34, 'palette':"0000ff,32cd32,ffff00,ff8c00,ff0000"});
I tried to add the code:
Map.addLayer(sst.clip(BIOT))
To clip the data to a region I have already defined (BIOT) but the image still displays all the data for all regions, rather than the one I have specified. Any ideas? Any help appreciated!

sst is an ImageCollection, which can't be clipped this way. This also means, when you execute Map.addLayer(sst), you're mapping all images within the collection, if they are spatially overlapping, they will cover each other up.
If you still want to do that, and you only need the data from your AOI BIOT anyways, you can add .map(function(image){return image.clip(BIOT)}) when you create your ImageCollection.
// Load an image **collection**.
var sst = ee.ImageCollection('NASA/OCEANDATA/MODIS-Aqua/L3SMI').select('sst')
.filterDate('2013-01-01', '2018-01-01')
.filterBounds(BIOT)
.map(function(image){return image.clip(BIOT)}) ;
This will iterate over each image in the collection and clip it to BIOT.

Related

Efficient way of finding points in a hexgrid

I am displaying a 10km cell hexGrid overlay on a map (approx 1000km²).
I have a geoJSON file containing around 5000 coordinate points, along with a 'score' value for each point. I want to collect all the points that fall into each hex cell, and modify the cell colour based on the average of the score for all points in that cell.
My (simplified) code is as follows:
let map = L.map('map')
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png').addTo(map)
let hexgrid = turf.hexGrid(mapBound, cellSize, options)
L.geoJson(hexgrid, {onEachFeature: onEachHex}).addTo(map)
function onEachHex(feature, layer) {
// find all points within this hex
let found = turf.pointsWithinPolygon(pointsData, turf.polygon(feature.geometry.coordinates))
// hexStyle defines a colour from the average scores in 'found' properties
layer.setStyle(hexStyle)
}
The problem I am having is that with a 10km cell size, there are several thousand cells, and there are 5000 points to evaluate for each hex. This obviously takes a very long time to render.
Can anyone suggest a better way of achieving this? The best option I can think of so far is to throw away the found points from pointsData each time, but I don't fancy trying to unpick the geoJson manually to achieve this!
Any tips greatly appreciated!

How does one extract NDVI data from a band?

I am trying to look at the change in NDVI over time for a polygon, and I want to have access to the NDVI values themselves, rather than chart or map them. So far, all I seem to be able to do is select a single pixel, chart the NDVI and then export the data as a CSV. This method would be extremely impractical if I wanted to do this for a polygon instead of a pixel.
var chart = ui.Chart.image.series({
imageCollection: withNDVI.select('ndvi'),
region: Point,
reducer: ee.Reducer.max(),
scale: 30
}).setOptions({title: 'NDVI over time'});
print(chart);
I'm using the above code to plot NDVI over time.
"Have access to" is not really specific enough. You can check the getRegion() method on an image collection. You may also want to check the toCollection() reducer in order to turn the pixels into a FeatureCollection. For more complicated exports of time series in regions, this reference may help.

custom image filter

1.Introduction:
So I want to develop a special filter method for uiimages - my idea is to change from one picture all the colors to black except a certain color, which should keep their appearance.
Images are always nice, so look at this image to get what I'd like to achieve:
2.Explanation:
I'd like to apply a filter (algorithm) that is able to find specific colors in an image. The algorithm must be able to replace all colors that are not matching to the reference colors with e.g "black".
I've developed a simple code that is able to replace specific colors (color ranges with threshold) in any image.
But tbh this solution doesn't seems to be a fast & efficient way at all!
func colorFilter(image: UIImage, findcolor: String, threshold: Int) -> UIImage {
let img: CGImage = image.cgImage!
let context = CGContext(data: nil, width: img.width, height: img.height, bitsPerComponent: 8, bytesPerRow: 4 * img.width, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!
context.draw(img, in: CGRect(x: 0, y: 0, width: img.width, height: img.height))
let binaryData = context.data!.assumingMemoryBound(to: UInt8.self),
referenceColor = HEXtoHSL(findcolor) // [h, s, l] integer array
for i in 0..<img.height {
for j in 0..<img.width {
let pixel = 4 * (i * img.width + j)
let pixelColor = RGBtoHSL([Int(binaryData[pixel]), Int(binaryData[pixel+1]), Int(binaryData[pixel+2])]) // [h, s, l] integer array
let distance = calculateHSLDistance(pixelColor, referenceColor) // value between 0 and 100
if (distance > threshold) {
let setValue: UInt8 = 255
binaryData[pixel] = setValue; binaryData[pixel+1] = setValue; binaryData[pixel+2] = setValue; binaryData[pixel+3] = 255
}
}
}
let outputImg = context.makeImage()!
return UIImage(cgImage: outputImg, scale: image.scale, orientation: image.imageOrientation)
}
3.Code Information The code above is working quite fine but is absolutely ineffective. Because of all the calculation (especially color conversion, etc.) this code is taking a LONG (too long) time, so have a look at this screenshot:
My question I'm pretty sure there is a WAY simpler solution of filtering a specific color (with a given threshold #c6456f is similar to #C6476f, ...) instead of looping trough EVERY single pixel to compare it's color.
So what I was thinking about was something like a filter (CIFilter-method) as alternative way to the code on top.
Some Notes
So I do not ask you to post any replies that contain suggestions to use the openCV libary. I would like to develop this "algorithm" exclusively with Swift.
The size of the image from which the screenshot was taken over time had a resolution of 500 * 800px
Thats all
Did you really read this far? - congratulation, however - any help how to speed up my code would be very appreciated! (Maybe theres a better way to get the pixel color instead of looping trough every pixel) Thanks a million in advance :)
First thing to do - profile (measure time consumption of different parts of your function). It often shows that time is spent in some unexpected place, and always suggests where to direct your optimization effort. It doesn't mean that you have to focus on that most time consuming thing though, but it will show you where the time is spent. Unfortunately I'm not familiar with Swift so cannot recommend any specific tool.
Regarding iterating through all pixels - depends on the image structure and your assumptions about input data. I see two cases when you can avoid this:
When there is some optimized data structure built over your image (e.g. some statistics in its areas). That usually makes sense when you process the same image with same (or similar) algorithm with different parameters. If you process every image only once, likely it will not help you.
When you know that the green pixels always exist in a group, so there cannot be an isolated single pixel. In that case you can skip one or more pixels and when you find a green pixel, analyze its neighbourhood.
I do not code on your platform but...
Well I assume your masked areas (with the specific color) are continuous and large enough ... that means you got groups of pixels together with big enough areas (not just few pixels thick stuff). With this assumption you can create a density map for your color. What I mean if min detail size of your specific color stuff is 10 pixels then you can inspect every 8th pixel in each axis speeding up the initial scan ~64 times. And then use the full scan only for regions containing your color. Here is what you have to do:
determine properties
You need to set the step for each axis (how many pixels you can skip without missing your colored zone). Let call this dx,dy.
create density map
simply create 2D array that will hold info if center pixel of region is set with your specific color. so if your image has xs,ys resolution than your map will be:
int mx=xs/dx;
int my=ys/dy;
int map[mx][my],x,y,xx,yy;
for (yy=0,y=dy>>1;y<ys;y+=dy,yy++)
for (xx=0,x=dx>>1;x<xs;x+=dx,xx++)
map[xx][yy]=compare(pixel(x,y) , specific_color)<threshold;
enlarge map set areas
now you should enlarge the set areas in map[][] to neighboring cells because #2 could miss edge of your color region.
process all set regions
for (yy=0;yy<my;yy++)
for (xx=0;xx<mx;xx++)
if (map[xx][yy])
for (y=yy*dy,y<(yy+1)*dy;y++)
for (x=xx*dx,x<(xx+1)*dx;x++)
if (compare(pixel(x,y) , specific_color)>=threshold) pixel(x,y)=0x00000000;
If you want to speed up this even more than you need to detect set map[][] cells that are on edge (have at least one zero neighbor) you can distinquish the cells like:
0 - no specific color is present
1 - inside of color area
2 - edge of color area
That can be done by simply in O(mx*my). After that you need to check for color only the edge regions so:
for (yy=0;yy<my;yy++)
for (xx=0;xx<mx;xx++)
if (map[xx][yy]==2)
{
for (y=yy*dy,y<(yy+1)*dy;y++)
for (x=xx*dx,x<(xx+1)*dx;x++)
if (compare(pixel(x,y) , specific_color)>=threshold) pixel(x,y)=0x00000000;
} else if (map[xx][yy]==0)
{
for (y=yy*dy,y<(yy+1)*dy;y++)
for (x=xx*dx,x<(xx+1)*dx;x++)
pixel(x,y)=0x00000000;
}
This should be even faster. In case your image resolution xs,ys is not a multiple of region size mx,my you should handle the outer edge of image either by zero padding or by special loops for that missing part of image...
btw how long it takes to read and set your whole image?
for (y=0;y<ys;y++)
for (x=0;x<xs;x++)
pixel(x,y)=pixel(x,y)^0x00FFFFFF;
if this alone is slow than it means your pixel access is too slow and you should use different api for this. That is very common mistake on Windows GDI platform as people usually use Pixels[][] which is slower than crawling snail. there are other ways like bitlocking/blitting,ScanLine etc so in such case you need to look for something fast on your platform. If you are not able to speed even this stuff than you can not do anything else ... btw what HW is this run on?

Draw only part of data in Highcharts

I looking for a way to only draw part of the data set in area chart. There is a slider above the chart that can limit the range of one series in the chart while other stile rendered in whole. I wonder whats the best way to do this. The only idea at the moment is to redraw the chart every time the slider moves but I'm afraid this could result in worse performance. Maybe this could be done with something like mask on the SVG element.
I came up with a simple solution by just clipping the svg graph with an clip path:
//var chart is the actual HighChartsInstance;
var renderer = chart.renderer;
var group = renderer.g().add();
var clipPath = renderer.createElement("clipPath");
clipPath.element.id = 'clip';
var rect = renderer.rect(0, 0, 200, 400).add(clipPath);
this.clippingMask = rect.element; //reference to the clipping rect which width is changed by the slider
clipPath.add(group);
chart.series[1].group.element.setAttribute('clip-path', "url(#clip)");
chart.series[1].group.element.childNodes[0].setAttribute('clip-path', "url(#clip)");
You have a few ways
use highstock which contains "slider" http://www.highcharts.com/stock/demo/
use highstock.js and highcharts chart with scroller http://jsfiddle.net/UCmUx/
scrollbar:{
enabled:true
},
use highcharts chart without scroller http://jsfiddle.net/UCmUx/1/ and in case when you move your own scroller, then use setExtremes() http://api.highcharts.com/highcharts#Axis.setExtremes()
I think one option is to modify the series data which you want to restrict, and then call:
chart.series[n].setData(newData);
where 'n' is the number of the series you are truncating. newData is a copy of the series data with the unwanted points taken out. You will need to specify x and y values in the series in order for it to be plotted in the correct position.

mapping latitude and longitude values onto an image

i'm trying to geocode values and map them to a satellite image of a city (new york city to be precise). i've successfully done this before using a geospatial image of the world, and then mapped/scaled longitude and latitude values from the max lat/lng range (-90,90 & -180,180) to the max width and hight of the image (0,width & 0,height) which worked perfectly. i'm a bit confused how to do this to just a map of a city.
currently, i have a hi-res satellite image of new york city, and have positioned it so that it perfectly aligns with the map of new york city on Google Maps (i'm using their API to geocode my locations). i've attempted to get the top/bottom latitude values and left/right longitude values of the satellite image i'm using, and tried to scale any longitude/latitude values that needed to be mapped onto the image within this range. however, this didn't seem to work. is there another method i could use so that it would be possible to dynamically map lat/lng coordinates onto a satellite image of new york city?
this is essentially the image that i would like to map onto:
thanks.
If you know the image size and its geographic extent (lat/lon values), you can use something like:
x = imageWidth * ( pointLon - ImageExtentLeft ) / (ImageExtentRight - ImageExtentLeft);
y = imageHeight * ( 1 - ( pointLat - ImageExtentBottom) / (ImageExtentTop - mImageExtentBottom));
By the way, if you are using the Google Maps API to geocode your locations, why don't you use its functions to add markers directly to your map? (Maybe I didn't completely understand your case)
var latlng = new GLatLng(pointLat, pointLon);
map.addOverlay(new GMarker(latlng));
Hope it helps
You are engaging in a process called image registration or map rectification. There is a whole set of remote sensing dedicated to the equations for doing this.
Perhaps you can just start with this web site - it should basically do what you need
http://labs.metacarta.com/rectifier/ (dead link)
if not then maybe look at tools like QGIS or GRASS. If you have money and time you can also use ESRI ArcGIS desktop or ERDAS Imagine or IDRISI.

Resources