C#中的双三次插值有点错误
我有一个代码,我在互联网上找到的,用于图像大小调整,但有一个问题。我得到它的宽度和高度偏移量为-1px 我试着加上偏移量,但它只是擦除第一行,然后是1像素C#中的双三次插值有点错误,c#,image,interpolation,bicubic,C#,Image,Interpolation,Bicubic,我有一个代码,我在互联网上找到的,用于图像大小调整,但有一个问题。我得到它的宽度和高度偏移量为-1px 我试着加上偏移量,但它只是擦除第一行,然后是1像素 private byte[] BicubicResize(byte[] Data, int w, int h, double scalex, double scaley) { int w_new = (int)(w * scalex); int h_new = (int)(h * scaley)
private byte[] BicubicResize(byte[] Data, int w, int h, double scalex, double scaley)
{
int w_new = (int)(w * scalex);
int h_new = (int)(h * scaley);
byte[] NewData = new byte[w_new * h_new * 4];
byte c;
int x, y;
BicubicInterpolation interpolation = new BicubicInterpolation(scalex, scaley, w_new, h_new);
for (c = 0; c < 4; c++)
for (y = 0; y < h_new; y++)
for (x = 0; x < w_new; x++)
NewData[((x + y * w_new) << 2) | c] = interpolation.Bicubic(x, y, c, Data);
return NewData;
}
public class BicubicInterpolation
{
double dx;
double dy;
double p0;
double p1;
double p2;
double p3;
double[] Rdx;
double[] Rdy;
double s;
byte k;
byte i;
long pix0;
long pix1;
double[][] p;
double scalex;
double scaley;
int w;
int h;
public BicubicInterpolation(double scalex = 1, double scaley = 1, int w = 0, int h = 0)
{
p = new double[4][];
p[0] = new double[4];
p[1] = new double[4];
p[2] = new double[4];
p[3] = new double[4];
pix0 = 0;
pix1 = 0;
this.scalex = scalex;
this.scaley = scaley;
this.w = w;
this.h = h;
}
public byte Bicubic(int x, int y, byte c, byte[] Data)
{
pix0 = (long)(x / scalex) + (long)(y / scaley) * (long)(w / scalex);
for (k = 0; k < 4; k++)
for (i = 0; i < 4; i++)
{
pix1 = ((long)(pix0 + i + k * (w / scalex)) << 2) | c;
if (pix1 < Data.LongLength) p[i][k] = Data[pix1];
else p[i][k] = 0;
}
//Temp = BicubicInterpolate(p, x - (long)(x / scalex), y - (long)(y / scaley));
return (byte)Interpolation(x, y, p);
}
private double Interpolation(double tx, double ty, double[][] P)
{
dx = F(tx);
dy = F(ty);
Rdx = new double[4];
Rdy = new double[4];
for (int n = 0; n < 4; n++)
{
Rdx[n] = R(n - 1 - dx);
Rdy[n] = R(n - 1 - dy);
}
s = 0;
for (byte k = 0; k < 4; k++)
for (byte i = 0; i < 4; i++)
s += P[k][i] * Rdx[i] * Rdy[k];
return s;
}
private double F(double x) => x - Math.Floor(x);
private double P(double x) => (x > 0.0) ? x : 0.0;
private double R(double x)
{
//return (Math.Pow(P(x + 2), 3) - 4 * Math.Pow(P(x + 1), 3) +
// 6 * Math.Pow(P(x), 3) - 4 * Math.Pow(P(x - 1), 3)) / 6;
p0 = P(x + 2);
p1 = P(x + 1);
p2 = P(x );
p3 = P(x - 1);
return ((p0 * p0 * p0) - 4 * (p1 * p1 * p1) + 6 * (p2 * p2 * p2) - 4 * (p3 * p3 * p3)) / 6.0;
}
}
private byte[]BicubicResize(byte[]Data,int w,int h,double scalex,double scaley)
{
int w_new=(int)(w*scalex);
int h_new=(int)(h*scaley);
byte[]NewData=新字节[w_new*h_new*4];
字节c;
int x,y;
双三次插值=新的双三次插值(scalex、scaley、w_new、h_new);
对于(c=0;c<4;c++)
对于(y=0;y0.0)?x:0.0;
私人双R(双x)
{
//返回(数学功率(P(x+2),3)-4*数学功率(P(x+1),3)+
//6*数学功率(P(x),3)-4*数学功率(P(x-1),3))/6;
p0=P(x+2);
p1=P(x+1);
p2=P(x);
p3=P(x-1);
返回值((p0*p0*p0)-4*(p1*p1*p1)+6*(p2*p2*p2)-4*(p3*p3*p3))/6.0;
}
}
我期待着得到这样的东西:
但我得到的这张图像在宽度和高度上都有一个有问题的偏移量-1px:我用另一种方法找到了答案。这种方法更快
public byte[,,] BicubicResize(byte[,,] Data, int w, int h, int w_new, int h_new, double scalex, double scaley)
{
byte[,,] NewData = new byte[w_new, h_new, 4];
byte c;
int x, y;
double j, l;
byte k, i;
double[][] p = new double[4][];
p[0] = new double[4];
p[1] = new double[4];
p[2] = new double[4];
p[3] = new double[4];
double result = 0;
for (c = 0; c < 4; c++)
for (y = 0; y < h_new; y++)
for (x = 0; x < w_new; x++)
{
for (k = 0; k < 4; k++)
for (i = 0; i < 4; i++)
{
j = x / scalex + i - 1;
l = y / scaley + k - 1;
while (j < 0) j++;
while (l < 0) l++;
while (j >= w) j--;
while (l >= h) l--;
p[i][k] = Data[(int)j, (int)l, c];
}
result = BicubicInterpolate(p, x % scalex / scalex, y % scaley / scaley);
NewData[x, y, c] = CDTB(result);
}
return NewData;
}
private readonly double[] arr = new double[4];
private double result = 0;
private double BicubicInterpolate(double[][] p, double x, double y)
{
arr[0] = CubicInterpolate(p[0], y);
arr[1] = CubicInterpolate(p[1], y);
arr[2] = CubicInterpolate(p[2], y);
arr[3] = CubicInterpolate(p[3], y);
result = CubicInterpolate(arr, x);
return result;
}
private double CubicInterpolate(double[] p, double x) => p[1] + 0.5 * x * (p[2] - p[0] + x *
(2.0 * p[0] - 5.0 * p[1] + 4.0 * p[2] - p[3] + x * (3.0 * (p[1] - p[2]) + p[3] - p[0])));
public static byte CDTB(double c)
{
if (c * 10 % 10 > 5) c = Math.Ceiling(c);
else c = Math.Floor (c);
if (c > 0xFF) c = 0xFF;
else if (c < 0x00) c = 0x00;
return (byte)c;
}
public byte[,]双三次方(byte[,]Data,int w,int h,int w_new,int h_new,double scalex,double scaley)
{
字节[,]新数据=新字节[w_new,h_new,4];
字节c;
int x,y;
双j,l;
字节k,i;
double[]p=新的double[4][];
p[0]=新的双精度[4];
p[1]=新的双精度[4];
p[2]=新的双精度[4];
p[3]=新的双精度[4];
双结果=0;
对于(c=0;c<4;c++)
对于(y=0;y=w)j--;
而(l>=h)l--;
p[i][k]=数据[(int)j,(int)l,c];
}
结果=BicubicInterpolate(p,x%scalex/scalex,y%scaley/scaley);
NewData[x,y,c]=CDTB(结果);
}
返回新数据;
}
私有只读双精度[]arr=新双精度[4];
私有双结果=0;
专用双双三次方(双[]p,双x,双y)
{
arr[0]=CubicInterpolate(p[0],y);
arr[1]=CubicInterpolate(p[1],y);
arr[2]=CubicInterpolate(p[2],y);
arr[3]=立方三极体(p[3],y);
结果=CubicInterpolate(arr,x);
返回结果;
}
私人双立方三极管(双[]p,双x)=>p[1]+0.5*x*(p[2]-p[0]+x*
(2.0*p[0]-5.0*p[1]+4.0*p[2]-p[3]+x*(3.0*(p[1]-p[2])+p[3]-p[0]);
公共静态字节CDTB(双c)
{
如果(c*10%10>5)c=数学上限(c);
else c=数学楼层(c);
如果(c>0xFF)c=0xFF;
否则,如果(c<0x00)c=0x00;
返回(字节)c;
}
有什么理由不使用可能已经为您轻松完成的NuGet软件包吗?您测试此代码的方式有点错误。始终从1x1位图开始,2x1下一个,2x2下一个,对3x3感觉良好。更简单的是,您可以预测应该发生什么,看到会发生什么,并且不会淹没在O中(n^2)数据。在较大的位图上发现更多问题的几率非常低。这并不能回答“为什么结果会有意外偏移”的问题