Javascript ';油嘴滑舌';使用双三次插值旋转时的图像

Javascript ';油嘴滑舌';使用双三次插值旋转时的图像,javascript,image-processing,interpolation,image-rotation,Javascript,Image Processing,Interpolation,Image Rotation,我正在开发一个node.js程序,该程序可以自动化一些图像处理,现在我在实现图像旋转时遇到了一些奇怪的结果。我首先尝试了线性插值,得到了“锯齿状”结果: 然后,我实现了双三次插值,得到如下结果: 我得到了边缘周围的“随机彩色像素”(橙色表示透明),但我不知道这些瑕疵是否是预期的(我已经了解到可能会出现一些重影),或者我的实现存在问题 所以我的问题是,这些“小故障”是算法的缺陷还是我的代码有问题?(我敢打赌是后者)另外,我对图像处理知之甚少,所以,我是在使用正确的算法,还是有更适合我需要的算法

我正在开发一个node.js程序,该程序可以自动化一些图像处理,现在我在实现图像旋转时遇到了一些奇怪的结果。我首先尝试了线性插值,得到了“锯齿状”结果:

然后,我实现了双三次插值,得到如下结果:

我得到了边缘周围的“随机彩色像素”(橙色表示透明),但我不知道这些瑕疵是否是预期的(我已经了解到可能会出现一些重影),或者我的实现存在问题

所以我的问题是,这些“小故障”是算法的缺陷还是我的代码有问题?(我敢打赌是后者)另外,我对图像处理知之甚少,所以,我是在使用正确的算法,还是有更适合我需要的算法

这是我的实现,很抱歉代码太多,但我认为如果我发布所有内容,会更容易理解:

var cubicInterpolation=函数(x,p0,p1,p2,p3){
返回(-0.5*p0+1.5*p1-1.5*p2+0.5*p3)*数学功率(x,3)+(p0-2.5*p1+2*p2-0.5*p3)*数学功率(x,2)+(-0.5*p0+0.5*p2)*x+p1;
};
var bicubicInterpolation=功能(x、y、p00、p01、p02、p03、p10、p11、p12、p13、p20、p21、p22、p23、p30、p31、p32、p33){
返回立方体插值(x,立方体插值(y,p00,p01,p02,p03),立方体插值(y,p10,p11,p12,p13),立方体插值(y,p20,p21,p22,p23),立方体插值(y,p30,p31,p32,p33));
};
//预先计算角度的正反方向
var sin=Math.sin(2*Math.PI*-旋转/360);
var cos=Math.cos(2*Math.PI*-旋转/360);
//图像将围绕该点旋转
xpivot=+(xpivot | |(Math.round(frag.w/2)+frag.x));
ypivot=+(ypivot | |(Math.round(frag.h/2)+frag.y));
//对于输出图像中的每个像素(命名帧)
对于(变量i=0;i<+帧$.w;i++){
对于(变量j=0;j<+帧$.h;j++){
//计算源图像中的坐标,并将轴计算在内
var i0=i-xpivot+frag.x;
var j0=j-ypivot+frag.y;
//计算旋转坐标
var xo=(i0*cos-j0*sin)+xpivot;
var-yo=(i0*sin+j0*cos)+ypivot;
//获取坐标周围4x4像素网格中的像素值
var val00=像素值(数学地板(yo)-1,数学地板(xo)-1,原始像素值);
var val01=像素值(数学地板(yo)-1,数学地板(xo),原始值);
var val02=像素值(数学楼层(yo)-1,数学单元(xo),原始值);
var val03=像素值(数学楼层(yo)-1,数学单元(xo)+1,原始值);
var val10=像素值(数学地板(yo)、数学地板(xo)-1、原始像素值);
var val11=像素值(数学地板(yo)、数学地板(xo)、原始像素值);
var val12=像素值(数学地板(yo)、数学天花板(xo)、原始像素值);
var val13=像素值(数学楼层(yo)、数学单元(xo)+1、原始值);
var val20=像素值(Math.ceil(yo)、Math.floor(xo)-1、originalpng);
var val21=像素值(Math.ceil(yo)、Math.floor(xo)、Originalng);
var val22=像素值(Math.ceil(yo)、Math.ceil(xo)、originalpng);
var val23=像素值(Math.ceil(yo),Math.ceil(xo)+1,originalpng);
var val30=像素值(Math.ceil(yo)+1,Math.floor(xo)-1,原始值);
var val31=像素值(Math.ceil(yo)+1,Math.floor(xo),原始值);
var val32=像素值(Math.ceil(yo)+1,Math.ceil(xo),originalpng);
var val33=像素值(Math.ceil(yo)+1,Math.ceil(xo)+1,originalpng);
//如果未定义,则值应为r=g、g=0、b=0、a=0或相邻像素
val11=val11[0]!=未定义?val11:[0,0,0,0];
val12=val12[0]!=未定义?val12:[0,0,0,0];
val21=val21[0]!=未定义?val21:[0,0,0,0];
val22=val22[0]!=未定义?val22:[0,0,0,0];
val10=val10[0]!=未定义?val10:val11;
val13=val13[0]!=未定义?val13:val12;
val20=val20[0]!=未定义?val20:val21;
val23=val23[0]!=未定义?val23:val22;
val01=val01[0]!=未定义?val01:val11;
val02=val02[0]!=未定义?val02:val12;
val31=val31[0]!=未定义?val31:val21;
val32=val32[0]!=未定义?val32:val22;
val00=val00[0]!=未定义?val00:val01;
val03=val03[0]!=未定义?val03:val02;
val30=val30[0]!=未定义?val30:val31;
val33=val33[0]!=未定义?val33:val32;
//得到适合双三次插值的x,y
var fx=xo-数学下限(xo);
var fy=yo-数学地板(yo);
//对alpha值执行双三次插值
var a=双三次插值(外汇,财政年度,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]);
//如果alpha!=0且源坐标为i,则为所需的范围
如果(a!=0&&xo=y+frag.y){
//对r、g、b值执行双三次插值
var r=双三次插值(外汇,财政年度,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=双三次插值(外汇,财政年度,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=双三次插值(外汇,财政年度,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]);
//绘制像素
paintPixel(+frame.$.x+i,+frame.$.y+j,Math.round(r),Math.round(g)