我编写了以下网络工作者,它将处理图像并将双线性插值添加到放大版本。
这对于使图像变大非常有用,但是我现在需要使图像变小。
我的理解是插值是为了放大而不是缩小。
this.addEventListener('message', function(event) {
var src = event.data.imageData,
dest = event.data.imageDataNew
postMessage({
'imageData':bilinear(src, dest, scale)
});
}, false);
function ivect(ix, iy, w) {
// byte array, r,g,b,a
return((ix + w * iy) * 4);
}
function bilinear(srcImg, destImg, scale) {
// c.f.: wikipedia english article on bilinear interpolation
// taking the unit square, the inner loop looks like this
// note: there's a function call inside the double loop to this one
// maybe a performance killer, optimize this whole code as you need
function inner(f00, f10, f01, f11, x, y) {
var un_x = 1.0 - x; var un_y = 1.0 - y;
return (f00 * un_x * un_y + f10 * x * un_y + f01 * un_x * y + f11 * x * y);
}
var i, j;
var iyv, iy0, iy1, ixv, ix0, ix1;
var idxD, idxS00, idxS10, idxS01, idxS11;
var dx, dy;
var r, g, b, a;
for (i = 0; i < destImg.height; ++i) {
iyv = i / scale;
iy0 = Math.floor(iyv);
// Math.ceil can go over bounds
iy1 = ( Math.ceil(iyv) > (srcImg.height-1) ? (srcImg.height-1) : Math.ceil(iyv) );
for (j = 0; j < destImg.width; ++j) {
ixv = j / scale;
ix0 = Math.floor(ixv);
// Math.ceil can go over bounds
ix1 = ( Math.ceil(ixv) > (srcImg.width-1) ? (srcImg.width-1) : Math.ceil(ixv) );
idxD = ivect(j, i, destImg.width);
// matrix to vector indices
idxS00 = ivect(ix0, iy0, srcImg.width);
idxS10 = ivect(ix1, iy0, srcImg.width);
idxS01 = ivect(ix0, iy1, srcImg.width);
idxS11 = ivect(ix1, iy1, srcImg.width);
// overall coordinates to unit square
dx = ixv - ix0; dy = iyv - iy0;
// I let the r, g, b, a on purpose for debugging
r = inner(srcImg.data[idxS00], srcImg.data[idxS10],
srcImg.data[idxS01], srcImg.data[idxS11], dx, dy);
destImg.data[idxD] = r;
g = inner(srcImg.data[idxS00+1], srcImg.data[idxS10+1],
srcImg.data[idxS01+1], srcImg.data[idxS11+1], dx, dy);
destImg.data[idxD+1] = g;
b = inner(srcImg.data[idxS00+2], srcImg.data[idxS10+2],
srcImg.data[idxS01+2], srcImg.data[idxS11+2], dx, dy);
destImg.data[idxD+2] = b;
a = inner(srcImg.data[idxS00+3], srcImg.data[idxS10+3],
srcImg.data[idxS01+3], srcImg.data[idxS11+3], dx, dy);
destImg.data[idxD+3] = a;
}
}
return destImg;
}
我还写了一个 Lancosz webworker,它产生了很好的结果,但速度很慢。我正在寻找的是介于两者之间的东西。
有谁知道双线性/双三次缩小过滤器的合理快速的 JavaScript 实现?
我将要处理的图像类型可能大到 5000x5000,并且会缩小到 1000x1000。
只要性能小于 10 秒左右就可以了。