在主线程中:我通过getImageData方法获得源图像数组。它是一个uint8ClampedArray来记录我的图像数据。
以下是我在web worker中的代码:(这个代码会给我一个高分辨率的图像,但操作的结果太大了)
self.addEventListener('message', function(e){
var scale = e.data['scale'], cvWidth = e.data['width'], cvHeight = e.data['height'], sBufferData = e.data['sBuffer'].data;
var sq = scale*scale, //pixel of source within target
sw = cvWidth, sh = cvHeight,
sx = 0, sy = 0, sIdx = 0,
tw = Math.floor(sw * scale), th = Math.floor(sh * scale),
tx = 0, ty = 0, tIdx = 0,
TX = 0, TY = 0, yIdx = 0,
w = 0, nw = 0, wx = 0, nwx = 0, wy = 0, nwy = 0,
sR = 0, sG = 0, sB = 0,
crossX = false, crossY = false,
tBuffer = new Float32Array(3 * sw * sh);
for( sy=0; sy<sh; sy++ ) {
ty = sy * scale; TY = 0 | ty; yIdx = 3 * TY * tw; crossY = (TY != (0 | ty + scale));
if(crossY) { wy = (TY + 1 - ty); nwy = (ty + scale - TY - 1); }
for( sx=0; sx<sw; sx++, sIdx+=4 ) {
tx = sx * scale; TX = 0 | tx; tIdx = yIdx + TX * 3; crossX = (TX != (0 | tx + scale));
if(crossX) { wx = (TX + 1 - tx); nwx = (tx + scale - TX - 1); }
sR = sBufferData[sIdx+0]; sG = sBufferData[sIdx+1]; sB = sBufferData[sIdx+2];
if(!crossX && !crossY) {
tBuffer[tIdx+0] += sR * sq; tBuffer[tIdx+1] += sG * sq; tBuffer[tIdx+2] += sB * sq;
} else if(crossX && !crossY) {
w = wx * scale;
tBuffer[tIdx+0] += sR * w; tBuffer[tIdx+1] += sG * w; tBuffer[tIdx+2] += sB * w;
nw = nwx * scale
tBuffer[tIdx+3] += sR * nw; tBuffer[tIdx+4] += sG * nw; tBuffer[tIdx+5] += sB * nw;
} else if(crossY && !crossX) {
w = wy * scale;
tBuffer[tIdx+0] += sR * w; tBuffer[tIdx+1] += sG * w; tBuffer[tIdx+2] += sB * w;
nw = nwy * scale
tBuffer[tIdx+3 * tw+0] += sR * nw; tBuffer[tIdx+3 * tw+1] += sG * nw; tBuffer[tIdx+3 * tw+2] += sB * nw;
} else {
w = wx * wy;
tBuffer[tIdx+0] += sR * w; tBuffer[tIdx+1] += sG * w; tBuffer[tIdx+2] += sB * w;
nw = nwx * wy; //for TX + 1; TY px
tBuffer[tIdx+3] += sR * nw; tBuffer[tIdx+4] += sG * nw; tBuffer[tIdx+5] += sB * nw;
nw = nwy * wx;
tBuffer[tIdx+3 * tw+0] += sR * nw; tBuffer[tIdx+3 * tw+1] += sG * nw; tBuffer[tIdx+3 * tw+2] += sB * nw;
nw = nwx * nwy;
tBuffer[tIdx+3 * tw+3] += sR * nw; tBuffer[tIdx+3 * tw+4] += sG * nw; tBuffer[tIdx+3 * tw+5] += sB * nw;
}
}
}
var worker2Object = {'tBuffer': tBuffer}; //I guess tBuffer is too Large
tBuffer = undefined; e = undefined;
self.postMessage(worker2Object); //Return to Main Thread
}, false);
当我使用IE或FireFox时,web工作线程中的内存将不足(Chrome很好)。
但是当图像大小小于1MB时,在3个浏览器上工作是很好的。
因此,我怀疑问题在于操作(tBuffer)的结果过大。有人能帮我解决这个问题吗?谢谢你的帮助。
我需要将big-O(n^2)算法移动到网络工作者,这样它就不会阻止我的主线程执行其他脚本。
现在,我需要在5个web worker线程中缩放5规范图像。下方的程序代码
for( var i in 5 spec image size array ) { //LOOP 5 time and new 5 web workers
//get imageData of source image
sourceBuffer = canvas.getContext("2d").getImageData(0, 0, w, h);
//new Worker_1 to process spec_1 image and so on
Worker_1 = new Worker('myWebWorker.js');
Worker_1.postMessage(sourceBuffer);
Worker_1.onmessage = function(e){ get e.data }
}
好吧,这里有一个想法-当您使用Float32Array时,请记住每个颜色组件都从8位(1字节)大小转换为32位(4字节)大小。
因此,如果你的图像是,为了简单起见,比方说1000x1000,那么内存消耗将是:
Normal canvas:
1000 x 1000 x 4 = 4,000,000 bytes or 3.8 mb
在32位浮点数组的情况下,大小为:
Float32Array:
1000 x 1000 x 16 = 16,000,000 bytes or 15.3 mb
现在将其乘以5(假设每个都在图像或具有相同大小的图像上工作),使用float32,您的初始3.8mb画布(原始数据)将为76.5mb。
如果你的图像更多地位于2000 x 2000的通道中,那么你的画布是305 mb+15 mb,或者4000 x 4000然后1.2 gb(!)+61 mb,依此类推
此外:原始大小仅适用于您可以访问的缓冲区。浏览器可能有也可能没有该数据的后缓冲区,这意味着在后一种情况下,您将远远超过GB大小,这可以很容易地解释内存不足错误消息。
如果你需要高精度的颜色处理(我认为这是因为你使用的是浮动),一个替代方案可以是:
- 请改用16位无符号缓冲区。这将把尺寸缩小到你现在的50%
- 或者,如果可能的话,使用8位缓冲区,在将结果放回缓冲区之前,在浮点中脱机处理数据
- 或者使用浮动缓冲器进行分段处理,但每次只处理图像的几行
提示:如果你和工人一起使用可转移的物品,你会获得巨大的性能提升。