This is Words and Buttons Online — a collection of interactive #tutorials, #demos, and #quizzes about #mathematics, #algorithms and #programming.

A smooth and sharp image interpolation you probably haven't heard of

Image interpolation is guessing pixels between pixels. You can go without, but then when you upscale your image or do any other image transformation, you'll see square pixels.

Here is the image to play with. The thing is interactive, you can control the frame with your mouse or your fingers.



And here are the square pixels.

You can make the picture nice and smooth by employing an image interpolation.

Common interpolations for that are bilinear and bicubic. (see Bi-whatever transformations) The downside of the bilinear one is that it makes your image continuous, so no squares, but not smooth, so the upscale still looks unnatural. The downside of bicubic interpolation is that, while it does give you a nice and smooth picture, it smudges the thing a little so sharp features 1 pixel wide appear to be 3 pixels wide after the interpolation.

Here is another interpolation you probably haven't heard about before.

This is an inverse weight interpolation, a close relative of a SWInE, not to be confused with "spline". The whole inverse weight family is not highly popular partially due to its computational issues, and partially, because their localization for spatial applications is tricky. But here, for the image interpolation, the localization is not tricky at all.

Let's start with a simple 1D case. We have a pair of values and we want to interpolate between them.

F(x1) = y1
F(x2) = y2

Let's define the interpolating function as a weighted sum of values divided by the sum of weights, where each weight is the inverse square of the x-axis distance between the data point we have and the interpolating function argument.

∀ x, xi < x < xi+1   F(x) =   yi * k(x - xi) + yi+1 * k(xi+1 - x)
k(x - xi) + k(xi+1 - x)
k(x) =   1
x2

You probably noticed that when the argument coincides with one of the data points, we have a division by zero, so the formula doesn't work. Well, in the ideal world, it's okay, we do have a value for every data point anyway. We can join or values outside or on the data points with the interpolation function from within.

F(xi) = yi

In the real world, there are computationally problematic areas near the data points. Which would have been bad, but image interpolation is an inherently inaccurate problem to begin with. You have to guess color values in the 0..255 discrete range, so any computational error below 1/512 doesn't bother you at all.

Now, for the image interpolation, the data points are, of course, 2-dimensional.

F(xj, yi) = zij

And the formula is larger.

F(x) =   zij k(x - xj) k(y - yi) + zi(j+1) k(xj+1 - x) k(y - yi) + z(i+1)j k(x - xj) k(yi+1 - y) + z(i+1)(j+1) k(xj+1 - x) k(yi+1 - y)
k(x - xj) k(y - yi) + k(xj+1 - x) k(y - yi) + k(x - xj) k(yi+1 - y) + k(xj+1 - x) k(yi+1 - y)

We don't have to keep the inverse distance squared. We can chose any degree, the interpolation will still work. For this particular case, even simple inverse (power 1) will suffice.

k(x) =   1
x

But, generally, it's the same formula. The sum of weighted values divided by the sum of weights. The only non-obvious generalization here is that the weights for each axis contribute via a product and not a sum or anything else.

This interpolation gives us a continuous and smooth image, where every interpolated value only depends on the four neighboring pixel values. The image becomes smooth, but sharp features remain sharp.