我正在使用node.js程序来自动执行某些图像处理,现在我在实现图像旋转时遇到了一些奇怪的结果。我首先尝试使用直线插值,然后我做了锯齿状的'结果:
我得到"随机彩色像素"在边缘附近(橙色意味着透明),但我不知道这些工件是否是预期的(我已经读过可能会出现一些重影)或者我的实现存在问题。
所以我的问题是,那些'故障'算法的缺陷还是我的代码有问题? (我打赌后者)另外,我不太了解图像处理,所以,我使用正确的算法,还是有更适合我需要的东西?
这是我的实现,对于大块代码感到抱歉,但我认为如果发布eveything更容易理解:
var cubicInterpolation = function (x, p0, p1, p2, p3) {
return (-0.5 * p0 + 1.5 * p1 - 1.5 * p2 + 0.5 * p3) * Math.pow(x, 3) + (p0 - 2.5 * p1 + 2 * p2 - 0.5 * p3) * Math.pow(x, 2) + (-0.5 * p0 + 0.5 * p2) * x + p1;
};
var bicubicInterpolation = function (x, y, p00, p01, p02, p03, p10, p11, p12, p13, p20, p21, p22, p23, p30, p31, p32, p33) {
return cubicInterpolation(x, cubicInterpolation(y, p00, p01, p02, p03), cubicInterpolation(y, p10, p11, p12, p13), cubicInterpolation(y, p20, p21, p22, p23), cubicInterpolation(y, p30, p31, p32, p33));
};
//precalculate the sin and cos of the angle
var sin = Math.sin(2 * Math.PI * -rotation / 360);
var cos = Math.cos(2 * Math.PI * -rotation / 360);
//the image will rotate around this point
xpivot = +(xpivot || (Math.round(frag.w / 2) + frag.x));
ypivot = +(ypivot || (Math.round(frag.h / 2) + frag.y));
//for each pixel in the ouput image (named frame)
for (var i = 0; i < +frame.$.w; i++) {
for (var j = 0; j < +frame.$.h; j++) {
//calculate the coordinates in the source image taking the pivot into ccount
var i0 = i - xpivot + frag.x;
var j0 = j - ypivot + frag.y;
//calculate the rotated coordinates
var xo = (i0 * cos - j0 * sin) + xpivot;
var yo = (i0 * sin + j0 * cos) + ypivot;
//get the values of the pixels in the 4x4 pixel grid around the coordinates
var val00 = pixelValue(Math.floor(yo) - 1, Math.floor(xo) - 1, originalpng);
var val01 = pixelValue(Math.floor(yo) - 1, Math.floor(xo), originalpng);
var val02 = pixelValue(Math.floor(yo) - 1, Math.ceil(xo), originalpng);
var val03 = pixelValue(Math.floor(yo) - 1, Math.ceil(xo) + 1, originalpng);
var val10 = pixelValue(Math.floor(yo), Math.floor(xo) - 1, originalpng);
var val11 = pixelValue(Math.floor(yo), Math.floor(xo), originalpng);
var val12 = pixelValue(Math.floor(yo), Math.ceil(xo), originalpng);
var val13 = pixelValue(Math.floor(yo), Math.ceil(xo) + 1, originalpng);
var val20 = pixelValue(Math.ceil(yo), Math.floor(xo) - 1, originalpng);
var val21 = pixelValue(Math.ceil(yo), Math.floor(xo), originalpng);
var val22 = pixelValue(Math.ceil(yo), Math.ceil(xo), originalpng);
var val23 = pixelValue(Math.ceil(yo), Math.ceil(xo) + 1, originalpng);
var val30 = pixelValue(Math.ceil(yo) + 1, Math.floor(xo) - 1, originalpng);
var val31 = pixelValue(Math.ceil(yo) + 1, Math.floor(xo), originalpng);
var val32 = pixelValue(Math.ceil(yo) + 1, Math.ceil(xo), originalpng);
var val33 = pixelValue(Math.ceil(yo) + 1, Math.ceil(xo) + 1, originalpng);
//if undefined, the values should be r=g,g=0,b=0,a=0, or the neighbour pixel
val11 = val11[0] != undefined ? val11 : [0, 0, 0, 0];
val12 = val12[0] != undefined ? val12 : [0, 0, 0, 0];
val21 = val21[0] != undefined ? val21 : [0, 0, 0, 0];
val22 = val22[0] != undefined ? val22 : [0, 0, 0, 0];
val10 = val10[0] != undefined ? val10 : val11;
val13 = val13[0] != undefined ? val13 : val12;
val20 = val20[0] != undefined ? val20 : val21;
val23 = val23[0] != undefined ? val23 : val22;
val01 = val01[0] != undefined ? val01 : val11;
val02 = val02[0] != undefined ? val02 : val12;
val31 = val31[0] != undefined ? val31 : val21;
val32 = val32[0] != undefined ? val32 : val22;
val00 = val00[0] != undefined ? val00 : val01;
val03 = val03[0] != undefined ? val03 : val02;
val30 = val30[0] != undefined ? val30 : val31;
val33 = val33[0] != undefined ? val33 : val32;
//get the x,y to fit in the bicubic interpolation
var fx = xo - Math.floor(xo);
var fy = yo - Math.floor(yo);
//perform the bicubic interpolation for the alpha values
var a = bicubicInterpolation(fx, fy, val00[3], val01[3], val02[3], val03[3], val10[3], val11[3], val12[3], val13[3], val20[3], val21[3], val22[3], val23[3], val30[3], val31[3], val32[3], val33[3]);
//if alpha!=0 and the source coordinates are i the range wanted
if (a != 0 && xo <= frag.w + frag.x + x && yo <= frag.h + +frag.y + y && xo >= x + frag.x && yo >= y + frag.y) {
//perform the bicubic interpolation for the r,g,b values
var r = bicubicInterpolation(fx, fy, val00[0], val01[0], val02[0], val03[0], val10[0], val11[0], val12[0], val13[0], val20[0], val21[0], val22[0], val23[0], val30[0], val31[0], val32[0], val33[0]);
var g = bicubicInterpolation(fx, fy, val00[1], val01[1], val02[1], val03[1], val10[1], val11[1], val12[1], val13[1], val20[1], val21[1], val22[1], val23[1], val30[1], val31[1], val32[1], val33[1]);
var b = bicubicInterpolation(fx, fy, val00[2], val01[2], val02[2], val03[2], val10[2], val11[2], val12[2], val13[2], val20[2], val21[2], val22[2], val23[2], val30[2], val31[2], val32[2], val33[2]);
//draw the pixel
paintPixel(+frame.$.x + i, +frame.$.y + j, Math.round(r), Math.round(g), Math.round(b), Math.round(a * alpha));
//console.log(Math.round(r), Math.round(g), Math.round(b), Math.round(a * alpha));
}
}
}