Java 2D数组双三次插值



我最近一直在玩Bicubic插值,因为我想根据《我的世界》中的真实高度图生成地球。我之所以使用插值,是因为我想让世界有更多的细节。经过大量的研究和尝试,我决定来这里询问

由于内存有限,我无法在启动时缩放图像,并保持加载状态,我必须在运行中进行插值。

我似乎已经使用了"三次插值",如下所示:插值的可视化然而,我无法使双三次插值工作。出于测试目的,我使用了一个小图像,并将其缩放4。这就是代码的作用:输入->输出

这是我当前的代码:

 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))];
}

感谢您的帮助:)

据我所知,您的实现以完全不同的方式处理给定的xy坐标,这不会产生所需的结果。你基本上应该做以下事情。

首先,您需要确定网格中的四个点(坐标对),这四个点将构成插值的基础,以及从网格到插值的两个方向上的距离。这可以按如下方式进行。

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

本文还讨论了插值方法。

在双三次插值方法中,您可以编写:

//double inBetweenPoint = x;
//int xInHeightmap = (int) x;
//inBetweenPoint -= xInHeightmap;
return cubicInterpolate(new double[]{beforePoint1, point1, point2, afterPoint2}, inBetweenPoint, scale);

您可以很容易地看到,在调用cubicInterpolate时,inBetweenPoint将处于[0, 1)的间隔中。这意味着插值将在beforePoint1和point1之间。而不是像所希望的那样,在点1和点2之间。

简单的修复方法是编写

return cubicInterpolate(new double[]{beforePoint1, point1, point2, afterPoint2}, inBetweenPoint + 1, scale);

相关内容

  • 没有找到相关文章

最新更新