Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/image/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#中的双三次插值有点错误_C#_Image_Interpolation_Bicubic - Fatal编程技术网

C#中的双三次插值有点错误

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)

我有一个代码,我在互联网上找到的,用于图像大小调整,但有一个问题。我得到它的宽度和高度偏移量为-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);
        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)数据。在较大的位图上发现更多问题的几率非常低。这并不能回答“为什么结果会有意外偏移”的问题