我最近一直在玩Bicubic Interpolation,因为我想根据Minecraft中的真实高度图来生成地球。我使用插值的原因是因为我想让世界有更多的细节。经过大量的研究,以及大量的反复试验,我决定来这里问一下。 :)
由于内存有限,我无法在启动时缩放图像,并保持加载,我必须动态插值。
我似乎已经进行了Cubic插值工作,如下所示: Visualisation of the interpolation 但是,我不能让Bicubic Interpolation工作。出于测试目的,我使用的是一个小图像,并将其缩放为4.这就是代码的作用:Input -> Output
这是我目前的代码:
public static double cubicInterpolate(double[] points, double x, double scale)
{
x /= scale;
double inBetweenPoint = x;
int xInHeightmap = (int) x;
inBetweenPoint -= xInHeightmap;
double beforePoint1 = safe(points, xInHeightmap - 1);
double point1 = safe(points, xInHeightmap);
double point2 = safe(points, xInHeightmap + 1);
double afterPoint2 = safe(points, xInHeightmap + 2);
double p = (afterPoint2 - point2) - (beforePoint1 - point1);
double q = (beforePoint1 - point1) - p;
double r = point2 - beforePoint1;
double s = point1;
return (p * Math.pow(inBetweenPoint, 3)) + (q * Math.pow(inBetweenPoint, 2)) + (r * inBetweenPoint) + s;
}
public static double bicubicInterpolate(double[][] points, double x, double y, double scale)
{
x /= scale;
double inBetweenPoint = x;
int xInHeightmap = (int) x;
inBetweenPoint -= xInHeightmap;
double beforePoint1 = cubicInterpolate(safe(points, xInHeightmap - 1), y, scale);
double point1 = cubicInterpolate(safe(points, xInHeightmap), y, scale);
double point2 = cubicInterpolate(safe(points, xInHeightmap + 1), y, scale);
double afterPoint2 = cubicInterpolate(safe(points, xInHeightmap + 2), y, scale);
return cubicInterpolate(new double[]{beforePoint1, point1, point2, afterPoint2}, inBetweenPoint + 1, scale);
}
public static double[] safe(double[][] p, int i)
{
return p[Math.max(0, Math.min(i, p.length - 1))];
}
public static double safe(double[] p, int i)
{
return p[Math.max(0, Math.min(i, p.length - 1))];
}
感谢您的帮助:)
答案 0 :(得分:3)
据我了解,您的实现以完全不同的方式处理给定的x
和y
坐标,这不会产生预期的结果。您基本上应该执行以下操作。
首先,您需要确定网格中的四个点(坐标对),它们将构成插值的基础,以及从网格到插值的两个方向上的距离。这可以按如下方式完成。
int xfloor = (int)x;
int yfloor = (int)y;
int xdelta = x - (double)xfloor;
int ydelta = y - (double)yfloor;
然后是所需的坐标对(取决于轴的方向)
P1 = (xfloor, yfloor ) // left upper corner
P2 = (xfloor, yfloor + 1) // left lower corner
P3 = (xfloor + 1 ,yfloor + 1) // right lower corner
P4 = (xfloor + 1, yfloor ) // left upper corner
最后你首先要沿平行轴插入,然后在中间插入,可以使用中间值按如下方式进行插补。
val1 = cubic(value(P1), value(P2), deltay) // interpolate cubically on the left edge
val2 = cubic(value(P4), value(P3), deltay) // interpolate cubically on the right edge
val = cubic (val1, val2, deltax) // interpolate cubically between the intermediates
还讨论了插值方法here。
答案 1 :(得分:0)
在您的双三次插值方法中,您可以写:
//double inBetweenPoint = x;
//int xInHeightmap = (int) x;
//inBetweenPoint -= xInHeightmap;
return cubicInterpolate(new double[]{beforePoint1, point1, point2, afterPoint2}, inBetweenPoint, scale);
正如您可以轻松看到的那样,inBetweenPoint
会在[0, 1)
来电时间隔cubicInterpolate
。这意味着插值将在before1和point1之间。不需要,在point1和point2之间。
简单的解决方法是写
return cubicInterpolate(new double[]{beforePoint1, point1, point2, afterPoint2}, inBetweenPoint + 1, scale);