Skip to content
AI360XpertBeta

Interpolation Methods

Resizing an image asks for values between the pixels you have. Interpolation blends the neighbours by distance, so close points count more than far ones.

Four corners 10 20 30 40 blend to 25.0 at the centre by distance weights
Four corners 10 20 30 40 blend to 25.0 at the centre by distance weights

Why Does This Exist?

Resizing an image, warping it, or sampling a feature map at a fractional coordinate all ask the same impossible question: what is the value between the grid points you actually stored? There is no measured answer, so every renderer and every vision model must manufacture a plausible one from the neighbours.

The three standard answers form a ladder. Nearest neighbour copies the closest pixel, which is fast but blocky. Bilinear blends the 4 surrounding pixels by distance, which smooths edges. Bicubic fits a cubic surface through the 16 surrounding pixels, which preserves sharpness better but can overshoot. This page works the bilinear arithmetic by hand, because once its weights click, the other two are variations on the same idea. The warping that consumes these samples is in image transformations, and the filtering sibling that smooths grids instead of resampling them is convolution.

The one idea you need first

A weighted average blends values by weights that sum to one. At the centre of a square each corner is equally far, so each gets weight 0.250.25. Near one corner, that corner dominates. Bilinear interpolation is two weighted averages in sequence: blend along the top edge, blend along the bottom edge, then blend those two results vertically. The grid reasoning is the same one behind finite differences.

Think of It Like This

Blending paint by how close you stand

Four paint cans sit at the corners of a square, labelled 10, 20, 30 and 40. You stand somewhere inside and mix a colour from all four, pouring more from the cans nearest you. Dead centre you pour equally and get 25.0, the plain mean. One step from a corner and that can dominates the cup.

The analogy maps part for part: cans are pixels, distance sets the weights, the cup is the sampled value. Where it stops: paint mixes physically while interpolation is pure arithmetic, and no blend invents a colour no can holds, just as interpolation never recovers detail the grid never recorded.

How It Actually Works

Nearest copies the closest grid value: v=vnearestv = v_{\text{nearest}}. One memory read, zero blending, visible steps at edges.

Bilinear blends the 2×22 \times 2 neighbourhood. With corners v00=10v_{00} = 10 (top left), v10=20v_{10} = 20 (top right), v01=30v_{01} = 30 (bottom left), v11=40v_{11} = 40 (bottom right) and fractional position (x,y)(x, y) inside the square, first blend horizontally along each row, then vertically:

vtop=v00(1−x)+v10x,vbot=v01(1−x)+v11x,v=vtop(1−y)+vbotyv_{\text{top}} = v_{00}(1 - x) + v_{10}x, \quad v_{\text{bot}} = v_{01}(1 - x) + v_{11}x, \quad v = v_{\text{top}}(1 - y) + v_{\text{bot}}y

In plain words: xx is the distance from the left edge, yy the distance from the top, and each blend gives nearby corners proportionally more say. The surface between four corners is quadratic, not flat, which is why diagonal gradients look slightly curved.

Bicubic fits a cubic polynomial through the 4×44 \times 4 neighbourhood (16 pixels) instead. Cubic pieces join with matching slopes, so edges stay crisper than bilinear, at roughly four times the reads and a real risk of ringing past sharp steps.

Worked example

Sample the grid above at its centre (x,y)=(0.5,0.5)(x, y) = (0.5, 0.5). Top edge: 10×0.5+20×0.5=5+10=1510 \times 0.5 + 20 \times 0.5 = 5 + 10 = 15. Bottom edge: 30×0.5+40×0.5=15+20=3530 \times 0.5 + 40 \times 0.5 = 15 + 20 = 35. Vertical: 15×0.5+35×0.5=7.5+17.5=25.015 \times 0.5 + 35 \times 0.5 = 7.5 + 17.5 = 25.0. At the centre every corner carries weight 0.250.25, and 0.25×(10+20+30+40)=25.00.25 \times (10 + 20 + 30 + 40) = 25.0.

As a check, sample (x,y)=(0.25,0.75)(x, y) = (0.25, 0.75): top is 10×0.75+20×0.25=7.5+5=12.510 \times 0.75 + 20 \times 0.25 = 7.5 + 5 = 12.5, bottom is 30×0.75+40×0.25=22.5+10=32.530 \times 0.75 + 40 \times 0.25 = 22.5 + 10 = 32.5, and the result is 12.5×0.25+32.5×0.75=3.125+24.375=27.512.5 \times 0.25 + 32.5 \times 0.75 = 3.125 + 24.375 = 27.5. Closer to the heavy 30 and 40 corners, the answer leans their way, exactly as distance weighting promises.

Code

The point is the check: run the blend and confirm both hand computations land exactly.

def bilinear(grid: list[list[float]], x: float, y: float) -> float:    # grid: [[top_left, top_right], [bottom_left, bottom_right]]    top = grid[0][0] * (1 - x) + grid[0][1] * x    bot = grid[1][0] * (1 - x) + grid[1][1] * x    return top * (1 - y) + bot * y

grid = [[10.0, 20.0], [30.0, 40.0]]print(bilinear(grid, 0.5, 0.5))  # -> 25.0print(bilinear(grid, 0.25, 0.75))  # -> 27.5

Both outputs match the hand arithmetic, including the off-centre 27.5 that leans toward the larger corners.

Watch Out For

Expecting upsampling to restore lost detail

The symptom is a pipeline that downsamples aggressively and trusts bicubic to rebuild texture later: small text stays mush, thin lines stay broken, and no interpolation order fixes it. Interpolation blends recorded neighbours; it cannot recover frequencies the grid never captured. That is aliasing, not a settings bug.

Downsample less, capture at the working resolution, or reach for a learned super-resolution model whose prior supplies the missing texture. If edges look smooth but fine structure is gone, the information is gone, not the method.

Half pixel coordinate conventions going wrong

The symptom is a resized image shifted by half a pixel, or a warp that is inexplicably blurry on one side: corner-aligned versus centre-aligned coordinates disagree about where pixel zero lives. Libraries split on this (the classic align corners flag), and mixing conventions across resize, warp and loss silently offsets every sample.

Fix the convention once per pipeline and test it with an asymmetric grid like the one above: sample (0.0,0.0)(0.0, 0.0) must return exactly 10.010.0, and (1.0,1.0)(1.0, 1.0) exactly 40.040.0. If either endpoint drifts, the grid origin is off by half a step somewhere upstream.

The Quick Version

  • Interpolation manufactures values between stored grid points by blending neighbours.
  • Nearest copies one pixel; bilinear blends 4 by distance; bicubic fits 16 with cubics.
  • Corners 10, 20, 30, 40 read 25.0 at the centre and 27.5 at (0.25, 0.75).
  • Bilinear weights always sum to one, so flat regions pass through unchanged.
  • Upsampling smooths but never restores detail the grid never recorded.
  • Pin the pixel coordinate convention with exact endpoint samples before trusting a resize.