【发布时间】:2018-02-14 21:37:00
【问题描述】:
我正在用 JavaScript 做一些图像处理项目,我需要遍历每个图像像素并进行一些其他处理以实现我的目标。
我正在使用画布获取图像像素数据数组。
对于尺寸为 500x300 像素的小图像,它可以正常工作并花费可接受的时间。但是对于大型图像,例如 3000x3000 像素的尺寸,迭代过程正在成为瓶颈并且需要很长时间,例如 10-12 秒。
那么有什么方法或技巧可以用来减少迭代步骤中使用的时间吗?
这是我的想法:我正在尝试使用并行网络工作者(假设为 4)来遍历图像数据的相等部分:(例如 0-[len/4]、[len/4]+1-[len/2]、[len/2]+1 - [len*3/4]、 [len*3/4]+1 - len) 其中len是图像数据数组的大小。
我怀疑这种方法会更省时,因为 Javascript 是单线程的。
function rgb2grey(pix,offset){
return (0.2989*pix[offset] + 0.5870*pix[offset+1] +
0.1140*pix[offset+2]);
}
function imgcompare(fileData1,fileData2,targetpix){
var len = pix.length;
for (var j = 0; j <len; j+=4) {
var grey1 = rgb2grey(fileData1,j);
var grey2 = rgb2grey(fileData2,j);
if(grey1!=grey2){
targetpix[j] = 255;
targetpix[j+1] = targetpix[j+2] = 0;
}
else{
targetpix[j] = fileData1[j];
targetpix[j+1] = fileData1[j+1];
targetpix[j+2] = fileData1[j+2];
}
targetpix[j+3] = fileData1[j+3];
}
}
【问题讨论】:
-
在所有情况下,尝试尾调用优化循环。网络工作者将允许您将工作委托给其他线程,或使用类似 gpujs 的东西;如果这是在服务器端完成的,请考虑将这项工作委托给具有更好并行编程支持的其他语言。
-
@flamelite:如果您不发布minimal reproducible example,我们将无法帮助您。问题很可能不在于您迭代每个像素这一事实,而在于您每次迭代所做的事情。
-
@flamelite 然后我会避免对网络工作者和 gpujs 发狂,因为它会显着降低用户的计算机速度;仅使用一个或最多两个 web worker 可以帮助减轻主 ui 线程上的负载,从而改善 UX。但是,我会尝试制作某种排队机制,以免一次处理太多图像。您需要避免阻塞用户的 GUI(例如这里的 promises)。
-
我也会避免在每次迭代时计算数组长度,而是这样做:
for (var j=0, jmax=pix.length ; j<jmax ; j+=4) { ... } -
确保 rgb2grey 使用 Math.floor() 返回一个整数值或在末尾添加一个 shift-0 OP(浏览器优化器和比较器都会为此感到高兴)。使用 !== 比较严格。对于网络工作者,您可以使用 SharedTypedArrays(仅限较新的浏览器)。迭代时转换为 Uint32Array(shift + 和 mask 通常比查找更大的数组更快)。根据您需要亮度(灰色)值的准确程度,您还可以将其转换为完整整数或平均值(无论如何,您都希望使用 rec.709 来获得准确度)。
标签: javascript image-processing canvas multidimensional-array web-worker