插值二维点数组
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,上述代码将是相同的。
还要注意,如果这些值代表方向或旋转,则需要小心,因为插值后生成的方向可能不会被归一化,甚至可能为零。
【讨论】:
以上是关于插值二维点数组的主要内容,如果未能解决你的问题,请参考以下文章