2

I have recently been playing around with Bicubic Interpolation, as I am wanting to generate the earth, based on real heightmaps inside Minecraft. The reason I am using the interpolation, is because I would like to make the world have more detail. After a lot of research, and a lot of trial and error, I decided to come ask here. :)

Because of limited memory, I can't scale the image on startup, and keep that loaded, I have to do the interpolation on the fly.

I seem to have gotten Cubic Interpolation to work, as seen here: Visualisation of the interpolation However, I can not get Bicubic Interpolation to work. For testing purposes, I am using a small image, and scaling it by 4. This is what the code does: Input -> Output

This is my current code:

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

Thank you for your help :)

2 Answers2

2

To my understanding, your implementaion treats the given x and y coordinates in a totally different way, which does not lead to the desired result. You should basically do the following.

First, you need to identify the four points (coordinate pairs) in the grid which will form the basis of the interpolation, as well as the distances in both directions from the grid to to the interpolation. This can be done as follows.

int xfloor = (int)x;
int yfloor = (int)y;
int xdelta = x - (double)xfloor;
int ydelta = y - (double)yfloor;

The desired coordinate pairs are then (depending on the orientation of the axes)

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

and finally you wouöd first interpolate along parallel axes and then in the middle, which can be done as follows using intermediate values.

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

Interpolation methods are also discussed here.

Codor
  • 17,447
  • 9
  • 29
  • 56
0

In your bicubic-interpolation method you write:

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

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

As you can easily see, inBetweenPoint will be in the interval [0, 1) at the call to cubicInterpolate. This means that interpolation will be between beforePoint1 and point1. not, as wanted, between point1 and point2.

The simple fix is writing

return cubicInterpolate(new double[]{beforePoint1, point1, point2, afterPoint2}, inBetweenPoint + 1, scale);
WorldSEnder
  • 4,875
  • 2
  • 28
  • 64
  • Hi! Thanks for you help, but I am still having problems with the output image, this is the image I am now getting: http://prntscr.com/9990d6 –  Dec 01 '15 at 21:38
  • That might be a problem with the code generating the image, not the interpolation itself. Can you post the relevant code? – WorldSEnder Dec 01 '15 at 21:43