插值二维点数组

Posted

技术标签:

【中文标题】插值二维点数组【英文标题】:Interpolating 2d array of points 【发布时间】:2022-01-05 17:24:55 【问题描述】:

我有一个二维点数组(每个点都存储在我的 Points 结构中,它只包含 3 个属性:X Y Z),大小为 128x128。我想将这个二维数组插入(拉伸)到更大的尺寸(例如 132x132)。到目前为止,我已经设法使用线性插值对每个点的 X 和 Y 坐标进行插值(只需将坐标放入 double 数组,对其进行插值,然后将其返回到新的 Points 二维数组)。下面是线性插值的代码:

private double[] InterpolateArray(double[] array, int newLength)

    double[] result = new double[newLength];
    result[0] = array[0];
    result[newLength - 1] = array[array.Length - 1];

    for (int i = 1; i < newLength - 1; i++)
    
        double jd = ((double)i * (double)(array.Length - 1) / (double)(newLength - 1));
        int j = (int)jd;
        result[i] = array[j] + (array[j + 1] - array[j]) * (jd - (double)j);
    

    return result;

问题是我不知道如何插入每个点的 Z 坐标。可以像 X 和 Y 坐标那样以同样的方式完成吗?还是需要完全不同的方法?

编辑:我的 Points 结构的代码:

public struct Points

    public double X  get; set; 
    public double Y  get; set; 
    public double Z  get; set; 
    public Points(double X, double Y, double Z)
    
        this.X = X;
        this.Y = Y;
        this.Z = Z;
    

以及进行插值的代码(或至少应该这样做):

public Points[,] Interpolate(Points[,] array, int newWidth, int newHeight)

    Points[,] result = new Points[newWidth, newHeight];

    double[] bufferBefore = new double[domes.GetLength(0)];
    double[] bufferAfter = new double[newWidth];
            
    for (int i = 0; i < domes.GetLength(1); i++)
    
        for (int j = 0; j < domes.GetLength(0); j++)
        
            bufferBefore[j] = domes[j, i].X;
        

        bufferAfter = InterpolateArray(bufferBefore, newWidth);

        for (int j = 0; j < newWidth; j++)
        
            result[j, i].X = bufferAfter[j];
        
    

    bufferBefore = new double[domes.GetLength(1)];
    bufferAfter = new double[newHeight];

    for (int i = 0; i < newWidth; i++)
    
        for (int j = 0; j < domes.GetLength(1); j++)
        
            bufferBefore[j] = result[i, j].Y;
        

        bufferAfter = InterpolateArray(bufferBefore, newHeight);

        for (int j = 0; j < newHeight; j++)
        
            result[i, j].Y = bufferAfter[j];
        
    

    return result;

【问题讨论】:

1) 您提到了Point,但该示例没有显示任何内容。 2)你提到了一个二维数组,但代码只是在一维中插值。 3) 如果您的 Points 代表一个方向,您可能会遇到插值问题。那么,您真正想做的是什么? @JonasH 我编辑了问题并添加了缺少的代码 sn-ps。关于第三个问题:我需要将我的二维数组拉伸到新尺寸:假设它的初始尺寸是 128x128,我需要将它拉伸到 148x128(例如)。因为我得到了实际的点,我需要正确地对它们进行插值以获得新的大小。 【参考方案1】:

我看不出您当前的代码是正确的。在第二部分中,您正在做bufferBefore[j] = result[i, j].Y;,但据我所知,这在之前的任何地方都没有设置。

因此,在插值时,您需要对 所有 值进行插值。因此,您需要为每个方向的每个 x/y/z 重复插值。

但是,通过为您的点结构实现乘法运算符,这会更简单一些。这可以让您同时对 x/y 进行插值,代码如下所示:

public static Vector3 BilinearSample(this Vector3[,] self, in Vector2 point)

    var xi = (int)Math.Floor(point.X);
    var xi1 = xi + 1;
    var xf = point.X - xi;
    var yi = (int)Math.Floor(point.Y);
    var yi1 = yi + 1;
    var yf = point.Y - yi;

    // You might need to add checks to ensure the sample is fully inside the image etc.

    var v1 = self[xi, yi];
    var v2 = self[xi1, yi];
    var v3 = self[xi, yi1];
    var v4 = self[xi1, yi1];

    // Do the bilinear sample
    var xfn1 = 1 - xf;
    var v5 = v1 * xfn1 + v2 * xf;
    var v6 = v3 * xfn1 + v4 * xf;
    var result = v5 * (1 - yf) + v6 * yf;
    return result;

我使用 System.Numerics 而不是 Point ,但原理是一样的。请注意,如果您将输入/输出类型更改为 Vector2 或 double,上述代码将是相同的。

还要注意,如果这些值代表方向或旋转,则需要小心,因为插值后生成的方向可能不会被归一化,甚至可能为零。

【讨论】:

以上是关于插值二维点数组的主要内容,如果未能解决你的问题,请参考以下文章

Python - 使用样条线插值二维点云

两条曲线之间的二维插值(长度不等的数组)

气象 python 二维线性插值

拟合函数:线性插值_样条插值(一维,二维,三维)_最小二乘拟合

matlab 如何用插值给NAN赋值

图像的降采样与升采样(二维插值)----转自LOFTER-gengjiwen