简体   繁体   English

如何让我的 JavaScript 程序运行得更快?

[英]How can I make my JavaScript programs run faster?

Ok, so I am working on a sort of detection system where I will be pointing the camera at a screen, and it will have to find the red object.好的,所以我正在研究一种检测系统,我会将相机指向屏幕,它必须找到红色物体。 I can successfully do this, with pictures, but the problem is that it takes several seconds to load.我可以用图片成功地做到这一点,但问题是加载需要几秒钟。 I want to be able to do this to live videos, so I need it to find the object immediately.我希望能够对实时视频执行此操作,因此我需要它立即找到对象。 Here is my code:这是我的代码:

video.addEventListener('pause', function () {

let reds = [];

for(x=0; x<= canvas.width; x++){
for(y=0; y<= canvas.height; y++){

let data = ctx.getImageData(x, y, 1, 1).data;
let rgb = [ data[0], data[1], data[2] ];

if (rgb[0] >= rgb[1] && rgb[0] >=rgb[2] && !(rgb[0]>100 && rgb[1]>100 && rgb[2]>100) && rgb[1]<100 && rgb[2]<100 && rgb[0]>150){
reds[reds.length] = [x, y]
}

let addedx = 0
let addedy = 0

for(i=0; i<reds.length; i++){
    addedx = addedx + reds[i][0]
    addedy = addedy + reds[i][1]
}

let center = [addedx/reds.length, addedy/reds.length]

ctx.rect(center[0]-5, center[1]-5, 10, 10)
ctx.stroke() 

}, 0);

Ya, I know its messy.是的,我知道它很乱。 Is there something about the for loops that are slow?有没有关于 for 循环很慢的东西? I know I'm looping through thousands of pixels but that's the only way I can think of to do it.我知道我正在遍历数千个像素,但这是我能想到的唯一方法。

I would run the detection algorithm in a webassembly module.我会在 webassembly 模块中运行检测算法。 Since it is just pixel data, thats right up its alley.由于它只是像素数据,这就是它的胡同。

You could then pass individual frames to a different instance of the wasm module.然后,您可以将单个帧传递给 wasm 模块的不同实例。

As far as answering your question directly, I would grab the whole frame, not 1 pixel at a time, or you might get pixels sampled from different frames.就直接回答您的问题而言,我会抓取整个帧,而不是一次抓取 1 个像素,否则您可能会从不同帧中采样像素。 You can then submit that frame to a worker, you could even divide up the frame and send them to different workers (or as previously mentioned a wasm module)然后您可以将该框架提交给工作人员,您甚至可以将框架分开并将它们发送给不同的工作人员(或如前所述的 wasm 模块)

Also since you have an array you can use Arrray.map and Array.reduce to get you to just the red values, and how big they are by testing for adjacent pixels, instead of all the comparison.此外,由于您有一个数组,您可以使用 Arrray.map 和 Array.reduce 来获取红色值,以及通过测试相邻像素而不是所有比较来获取它们的大小。 Not sure if it will be faster but worth a try.不确定它是否会更快但值得一试。

For the speed, you should consider all your process:对于速度,您应该考虑所有过程:

  • more your language is near the machine language, better your result will be.你的语言越接近机器语言,你的结果就会越好。 Saying so, C++ is better for the algorithm.这么说吧,C++更适合算法。
  • CPU speed is your friend. CPU 速度是您的朋友。 Launching your code on an Atom processor or on an i7 processor, is like night and day.在 Atom 处理器或 i7 处理器上启动您的代码就像白天和黑夜。 Moreover, some type of processor is dedicated for vision like VPU此外,某些类型的处理器专用于视觉,如VPU

For your code:对于您的代码:

Hope it help you :)希望对你有帮助:)

As it has been said, Javascript is not the most performant for this task.如前所述,Javascript 并不是这项任务的最佳性能。 However, here are some things I noticed, which could slow you down.但是,这里有一些我注意到的事情,这可能会减慢您的速度。

  1. You grab the image data one pixel at a time.您一次获取一个像素的图像数据。 Since this method can return the whole frame, you can do this once.由于此方法可以返回整个帧,因此您可以执行一次。

  2. Optimize your isRed condition:优化你的isRed条件:

rgb[0] >= rgb[1] &&                                // \
rgb[0] >= rgb[2] &&                                //  >-- This is useless
!(rgb[0] > 100 && rgb[1] > 100 && rgb[2] > 100) && // /
rgb[1] < 100 && // \
rgb[2] < 100 && //  >-- These 3 conditions imply the others
rgb[0] > 150    // /
  1. You calculate the center inside your for loop after each pixel, but it would only make sense after processing the whole frame.您在每个像素之后计算for循环内的center ,但只有在处理整个帧后才有意义。

  2. Since the video feed is coming from a camera, maybe you don't need to look at every single pixel.由于视频源来自相机,因此您可能不需要查看每个像素。 Maybe every 5 pixels is enough?也许每 5 个像素就足够了? That's what the example below does.这就是下面的例子所做的。 Tweak this.调整这个。

Demo including these optimizations演示包括这些优化

Node: This demo includes an adaptation of the code from this answer , to copy the video onto the canvas .节点:此演示包括对此答案中代码的改编,以将视频复制到画布上

 const video = document.getElementById("video"), canvas = document.getElementById("canvas"), ctx = canvas.getContext("2d"); let width, height; // To make this demo work video.crossOrigin = "Anonymous"; // Set canvas to video size when known video.addEventListener("loadedmetadata", function() { width = canvas.width = video.videoWidth; height = canvas.height = video.videoHeight; }); video.addEventListener("play", function() { const $this = this; // Cache (function loop() { if (!$this.paused && !$this.ended) { ctx.drawImage($this, 0, 0); const reds = [], data = ctx.getImageData(0, 0, width, height).data, len = data.length; for (let i = 0; i < len; i += 5 * 4) { // 4 because data is made of RGBA values const rgb = data.slice(i, i + 3); if (rgb[0] > 150 && rgb[1] < 100 && rgb[2] < 100) { reds.push([i / 4 % width, Math.floor(i / 4 / width)]); // Get [x,y] from i } } if (reds.length) { // Can't divide by 0 const sums = reds.reduce(function (res, point) { return [res[0] + point[0], res[1] + point[1]]; }, [0,0]); const center = [ Math.round(sums[0] / reds.length), Math.round(sums[1] / reds.length) ]; ctx.strokeStyle = "blue"; ctx.lineWidth = 10; ctx.beginPath(); ctx.rect(center[0] - 5, center[1] - 5, 10, 10); ctx.stroke(); } setTimeout(loop, 1000 / 30); // Drawing at 30fps } })(); }, 0);
 video, canvas { width: 250px; height: 180px; background: #eee; }
 <video id="video" src="https://shrt-statics.s3.eu-west-3.amazonaws.com/redball.mp4" controls></video> <canvas id="canvas"></canvas>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM