2015-12-01 3 views
2

Я недавно играл с Bicubic Interpolation, так как я хочу генерировать землю, основываясь на реальных картах высот внутри Minecraft. Причина, по которой я использую интерполяцию, заключается в том, что я хотел бы сделать мир более подробным. После много исследований и много проб и ошибок, я решил обратиться сюда. :)Java 2D-массив Бикубическая интерполяция

Из-за ограниченной памяти я не могу масштабировать изображение при запуске и сохранять его загруженным, я должен сделать интерполяцию «на лету».

Я, кажется, получил кубическую интерполяцию к работе, как показано здесь: Visualisation of the 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))]; 
} 

Спасибо за вашу помощь :)

ответ

2

Насколько я понимаю, ваша реализация обрабатывает заданные координаты 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 

и, наконец, вы wouöd первый интерполировать вдоль параллельных осей, а затем в середине, что может быть сделано следующим образом используя промежуточные значения.

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.

0

В вашем методе бикубическое-интерполяции вы пишете:

//double inBetweenPoint = x; 
//int xInHeightmap = (int) x; 
//inBetweenPoint -= xInHeightmap; 

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

Как вы можете легко увидеть, inBetweenPoint будет находиться в интервале [0, 1) при вызове cubicInterpolate. Это означает, что интерполяция будет находиться между beforePoint1 и point1. по желанию, между точками 1 и 2.

Простое исправление написания

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

Привет! Спасибо за помощь, но у меня все еще возникают проблемы с выходным изображением, это изображение, которое я получаю сейчас: http://prntscr.com/9990d6 – gegy1000

+0

Это может быть проблема с кодом, генерирующим изображение, а не с интерполяцией сам. Можете ли вы разместить соответствующий код? – WorldSEnder

+0

О, это вы! : P Вот он: http://pastebin.com/SuK05s7p – gegy1000

Смежные вопросы