I am using GraphicsMagick to colorize multiple layers of images and composing it to form single image and returning it.
On local it was taking around 30ms to process single layer (1000 x 1000).
Following is the image.
Following is my colorization code:
var colorizeImage = function(imageName, hex, callback) {
//Setting image path.
var sourceImgSrc = getSourceImgSrc(imageName); //Source image path
var convertedImgSrc = getConvertedImgSrc(imageName); // New image path
var hslObj = getConvertedHSLFromHex(hex);
var hue = hslObj.h;
var saturation = hslObj.s;
var lightness = hslObj.l;
try{
//Query
var modulateImg = "gm convert -resize 500 "+sourceImgSrc+" -modulate "+lightness+","+saturation+","+hue+" -limit memory 100KB "+convertedImgSrc;
exec(modulateImg, function(err) {
if (err) {
callback('', err);
}
else{
callback(convertedImgSrc);
}
});
}
catch(err){
callback('', err);
}
}
But, When I have hosted this to my server and performed load testing with only 50 concurrent users load. Performance for single layer gets degraded to around 250ms for single layer.
Following is my Server Config:
GraphicsMagick: 1.3.26
OS: Window server 2012
Processor: Intel(R) Xeon(R) 2.40 GHz (2 Processors)
RAM: 128GB
Please help me to improve performance so that it can handle huge load easily.
Thanks.
Related
I want to combine all the Landsat sensors from 1985 up today in Google Earth Engine, remove the clouds and calculate the time-series of the NBR index. As a new GEE user I have the following:
// find all data and filter them by date
var lst5 = ee.ImageCollection('LANDSAT/LT5_SR').filterDate('1984-10-01', '2011-10-01');
var lst7 = ee.ImageCollection('LANDSAT/LE7_SR').filterDate('2011-10-01', '2013-04-07');
var lst8 = ee.ImageCollection('LANDSAT/LC8_SR').filterDate('2013-04-07', '2018-05-01');
var lst7_08 = ee.ImageCollection('LANDSAT/LE7_SR').filterDate('2007-12-01', '2008-02-01');
var lst7_92 = ee.ImageCollection('LANDSAT/LT4_SR').filterDate('1992-01-02', '1992-04-01');
// Combine all landsat data, 1985 through 2015
var everything = ee.ImageCollection(lst5.merge(lst7));
everything = everything.merge(lst8);
everything = everything.merge(lst7_08);
everything = everything.merge(lst7_92);
var alltogether = ee.ImageCollection(everything.filterDate('1984-01-01', '2018-05-01'));
From this point, I do not know how to remove the clouds and calculate the NBR index (NBR index here) for every image in my final collection.
Can anyone help me?
Thank you.
EDIT:
I think that I need to map a normalizedDifference function over my collection in order to get the NBR index but I am not sure how to do this for my collection with the different sensors.
You've got quite a lot going on here, but here's what I think you want. You should check this very carefully to ensure it's behaving as intended:
// Function to cloud mask Landsat 8.
var maskL8SR = function(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 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 image
// Scale the data to reflectance and temperature.
.select(['B5', 'B7'], ['NIR', 'SWIR']).multiply(0.0001)
.addBands(image.select(['B11'], ['Thermal']).multiply(0.1))
.updateMask(mask);
};
// Function to cloud mask Landsats 5-7
var maskL57SR = function(image) {
var qa = image.select('pixel_qa');
// Second bit must be zero, meaning none to low cloud confidence.
var mask1 = qa.bitwiseAnd(ee.Number(2).pow(7).int()).eq(0).and(
qa.bitwiseAnd(ee.Number(2).pow(3).int()).lte(0)); // cloud shadow
// This gets rid of irritating fixed-pattern noise at the edge of the images.
var mask2 = image.select('B.*').gt(0).reduce('min');
return image
.select(['B4', 'B7'], ['NIR', 'SWIR']).multiply(0.0001)
.addBands(image.select(['B6'], ['Thermal']).multiply(0.1))
.updateMask(mask1.and(mask2));
};
// find all data and filter them by date
var lst5 = ee.ImageCollection('LANDSAT/LT05/C01/T1_SR')
.filterDate('1984-10-01', '2011-10-01')
.map(maskL57SR)
var lst7 = ee.ImageCollection('LANDSAT/LE07/C01/T1_SR')
.filterDate('2011-10-01', '2013-04-07')
.map(maskL57SR)
var lst8 = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR')
.filterDate('2013-04-07', '2018-05-01')
.map(maskL8SR)
var lst7_08 = ee.ImageCollection('LANDSAT/LE07/C01/T1_SR')
.filterDate('2007-12-01', '2008-02-01')
.map(maskL57SR)
var lst7_92 = ee.ImageCollection('LANDSAT/LT04/C01/T1_SR')
.filterDate('1992-01-02', '1992-04-01')
.map(maskL57SR)
// Combine all landsat data, 1985 through 2015
var everything = ee.ImageCollection(lst5.merge(lst7));
everything = everything.merge(lst8);
everything = everything.merge(lst7_08);
everything = everything.merge(lst7_92);
// NBR:
var nbrFunction = function(image) {
image = ee.Image(image)
return image.addBands(image.expression(
'(nir - 0.0001 * swir * thermal) / ' +
'(nir + 0.0001 * swir * thermal)', {
nir: image.select(['NIR']),
swir: image.select(['SWIR']),
thermal: image.select(['Thermal'])
}).rename('NBR').clamp(-1, 1));
};
everything = everything.map(nbrFunction);
var check = ee.Image(everything.first());
Map.centerObject(check);
Map.addLayer(check);
The answer works great for SR imagery! Thanks! Sorry I can't just comment because I don't have 50 reputation yet, but I saw #Abhilash Singh Chauhan's question about why ee.Number(2).pow(3)... is used for the variables cloudshadow and clouds. I had the same question and I wanted to answer that it's because of the fact that the QA Pixel bands are Decimal integers that contain Binary information. So for example band 3 for surface reflectance LANDSAT products indicates the band for cloud shadow but the values are in binary. To get the values you need to convert the band to binary, hence 2^3 and similarly 2^5 for cloud values. I hope that clarifies the comment. you can check this here: https://www.usgs.gov/landsat-missions/landsat-4-7-surface-reflectance-quality-assessment
I am using EmguCV to create a capture from a video file stored on disk. I set the capture property for frame position and then perform a QueryFrame. On certain frames from the video, when I go to process the Mat further I get the error '{"OpenCV: Unrecognized or unsupported array type"}'. This doesn't happen on all frames of the video but when I run it for the same video it happens for the same frames in the video. If I save the Mat to disk the image looks perfectly fine and saves without error. Here is the code for loading and processing the image:
Capture cap = new Capture(movieLocation);
int framePos = 0;
while (reading)
{
cap.SetCaptureProperty(CapProp.PosFrames, framePos);
using (var frame = cap.QueryFrame())
{
if (frame != null)
{
try
{
var fm = Rotate(frame); // Works fine
// Other Processing including classifier.DetectMultiScale -- Error occurs here
frameMap.Add(framePos, r);
}
catch (Exception ex)
{
var s = ""; // Done to just see the error
}
framePos = framePos + 2;
}
else
{
reading = false;
}
}
}
Line of code which throws exception in further processing
var r = _classifier.DetectMultiScale(matIn, 1.1, 2, new Size(200, 200), new Size(375, 375));
As I said, this does not fail for every frame of the video.
I'm trying to solve this because sometimes it skips 1 frame but at other times it will skip whole blocks of frames which is causing me to miss important events in the video.
After a bit more working on it, I figured out that the Mat had a ROI set on it before going to the cascade classifier. In the instances where the mat was failing the ROI was set to 0 height and 0 width. This caused the issue.
Im developing an iOS app which allows users to take a sequence of photos - afterwards the photos are put in an animation and exported as MP4 and GIF.
While the MP4 presents the source quality, the GIF color grades are visible.
Here the visual comparison:
GIF:
MP4
The code I use for exporting as GIF:
var dictFile = new NSMutableDictionary();
var gifDictionaryFile = new NSMutableDictionary();
gifDictionaryFile.Add(ImageIO.CGImageProperties.GIFLoopCount, NSNumber.FromFloat(0));
dictFile.Add(ImageIO.CGImageProperties.GIFDictionary, gifDictionaryFile);
var dictFrame = new NSMutableDictionary();
var gifDictionaryFrame = new NSMutableDictionary();
gifDictionaryFrame.Add(ImageIO.CGImageProperties.GIFDelayTime, NSNumber.FromFloat(0f));
dictFrame.Add(ImageIO.CGImageProperties.GIFDictionary, gifDictionaryFrame);
InvokeOnMainThread(() =>
{
var imageDestination = CGImageDestination.Create(fileURL, MobileCoreServices.UTType.GIF, _images.Length);
imageDestination.SetProperties(dictFile);
for (int i = 0; i < this._images.Length; i++)
{
imageDestination.AddImage(this._images[i].CGImage, dictFrame);
}
imageDestination.Close();
});
The code I use for exporting as MP4:
var videoSettings = new NSMutableDictionary();
videoSettings.Add(AVVideo.CodecKey, AVVideo.CodecH264);
videoSettings.Add(AVVideo.WidthKey, NSNumber.FromNFloat(images[0].Size.Width));
videoSettings.Add(AVVideo.HeightKey, NSNumber.FromNFloat(images[0].Size.Height));
var videoWriter = new AVAssetWriter(fileURL, AVFileType.Mpeg4, out nsError);
var writerInput = new AVAssetWriterInput(AVMediaType.Video, new AVVideoSettingsCompressed(videoSettings));
var sourcePixelBufferAttributes = new NSMutableDictionary();
sourcePixelBufferAttributes.Add(CVPixelBuffer.PixelFormatTypeKey, NSNumber.FromInt32((int)CVPixelFormatType.CV32ARGB));
var pixelBufferAdaptor = new AVAssetWriterInputPixelBufferAdaptor(writerInput, sourcePixelBufferAttributes);
videoWriter.AddInput(writerInput);
if (videoWriter.StartWriting())
{
videoWriter.StartSessionAtSourceTime(CMTime.Zero);
for (int i = 0; i < images.Length; i++)
{
while (true)
{
if (writerInput.ReadyForMoreMediaData)
{
var frameTime = new CMTime(1, 10);
var lastTime = new CMTime(1 * i, 10);
var presentTime = CMTime.Add(lastTime, frameTime);
var pixelBufferImage = PixelBufferFromCGImage(images[i].CGImage, pixelBufferAdaptor);
Console.WriteLine(pixelBufferAdaptor.AppendPixelBufferWithPresentationTime(pixelBufferImage, presentTime));
break;
}
}
}
writerInput.MarkAsFinished();
await videoWriter.FinishWritingAsync();
I would appreciate for your help!
Kind regards,
Andre
This is just summarization of mine comments...
I do not code on your platform so I only provide generic answer (and insights from mine own GIF encoder/decoder coding experience).
GIF image format supports up to 8bit per pixel leading to max 256 colors per pixel with naive encoding. Cheap encoders just truncates input image to 256 or less colors usually leading to ugly pixelated results. To increase coloring quality of GIF there are 3 approaches I know of:
Multiple frames covering screen with own palettes
Simply you divide image into overlays each with its own palette. This is slow (in therm of decoding as you need to process more frames per single image which can cause sync errors with some viewers and you need to process all frame related chunks multiple times per single image). The encoding itself is fast as you just either separate the frames based on colors or region/position to multiple frames. Here (region/position based) example:
The sample image is taken from here: Wiki
The GIF supports transparency so the sub frames can overlap ... This approach physically increase the colors per pixel possible to N*256 (or N*255 for transparent frames) where N is the number of frames or palettes used per single image.
Dithering
Dithering is technique that approximate color of area to match colors as closely as possible while using only specified colors (from palette) only. This is fast and easily implementable but the result is kind of noisy. For more info see some related answers of mine:
Converting BMP image to set of instructions for a plotter?
c# image dithering routine that accepts an amount of dithering?
Better color quantization method
Cheap encoders just truncate the colors to predefined palette. Much better results are obtained by clustering the used colors based on histogram. For example see:
Effective gif/image color quantization?
The result is usually much better then dithering but the encoding time is huge in comparison to dithering...
The #1 and #3 can be used together to enhance quality even more ...
If you do not have access to the encoding code or pipeline you still can transform image itself before encoding doing the quantization and palette computation instead and load the result directly to GIF encoder which should be possible (if the GIF encoder you are using is at least a bit sophisticated ...)
Loading 256x256 textures into Three.js materials, which are then used for planegeometry deformation. Encountering a bottleneck at 15th texture. Chrome apparently crashes at the render call. When each mesh is added to scene, I call the renderer.render call, but the sequence is pretty tight, so I believe, the gpu bus may be overwhelmed. It is hard to believe that a small number of such small textures is enough to cause this. Cpu memory is not a problem, as textures are loaded into cpu and if meshes are not added to scene, there is no crash. Also, there is a significant delay while the textures are being copied from cpu to gpu.
function loadTexture(texture) {
var x = 512;
var y = 512;
var dx = 256;
var dy = 256;
var geometry = new THREE.PlaneGeometry(x, y, dx, dy);
var material = new THREE.ShaderMaterial({
side: THREE.DoubleSide,
uniforms: {
heightMap: {
type: "t",
value: texture
}
},
vertexShader: vertexShader,
fragmentShader: fragmentShader
});
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
this.renderer.render(scene, camera);
}
PlaneGeometries are turning out to be expensive in Three.js r76. I cannot create more than 14 of these (at mentioned resolution of 256x256 data points). I happen to need many but a limited amount of plane geometries, so I can continue to push against this limit but eventually I will need more memory for the PlaneGeometries. This bottleneck is GPU only, as this happens only on renderer.render call.
i have so many columns in my shp,
i use data from my shp to show vector layer,
and i did it but sometimes take a long time even unresponsive script
can anyone help me how to show vector layers from shp in geoserver faster
this is my code that im using
var hitungJumlah = vectorSource.getFeatures();
for(var k=0;k<hitungJumlah.length;k++){
var id = vectorSource.getFeatures()[k].getId();
var feature = vectorSource.getFeatureById(id);
if(feature.get('klas')!=null){
var a = feature.get('klas');
}else{
a = "";
}
if(a=="Utama"){
//warna is my ol.layer.Vector
warna.getSource().addFeature(feature);
}
}