This document examines a common
image resizing algorithm that doesn’t
seem to have a standardized name. It’s sometimes called
*pixel mixing*, *pixel averaging*, or *area map*, among
other things. I’ll follow **netpbm**’s terminology, and call it
*pixel mixing*.

It can be confused with a *box filter* or with *linear
interpolation*, but it is not the same as either of them.

It is an easy algorithm to understand. Start with the original image (an 8×8 image in this example):

Treat the pixels as square tiles with no space between them, and imagine overlaying them with a grid having as many tiles as you want pixels in the resized image.

→ |

Assign each new pixel the average color of the section of the original image visible in the corresponding opening in the grid, and you’re done.

→ | → |

Enlarging an image works the same way:

→ | → |

- Simple, well-defined, and easy to understand.
- Closely approximates what you actually see if you move closer to or farther away from an image.
- Relatively fast.
- Keeps the brightness of the image exactly the same. Every source pixel has exactly the same amount of influence on the resized image.
- Reasonably good quality when reducing image size, or slightly enlarging it.
- Works with
*any*image, even an image made of randomly colored pixels. Most algorithms assume that adjacent pixels are related. Pixel mixing makes no such assumptions.

- Not useful for increasing image size by more than a small amount, unless a pixelated look is what you want.
- Causes a moderate amount of “aliasing”: can cause moiré patterns in images containing small repetetive details.
- Does not do much to anti-alias images that start out aliased.
- Treats pixels as if they were
*little squares*, which gets on some experts’ nerves.

When using it to reduce an image, pixel mixing has, to some degree,
a weakness known as *aliasing*.

If we significantly reduce the size of the image below, some of the black and white arcs will be too thin to be represented as arcs.

The best thing to do in this situation is probably to use a solid average color. So, as we get farther from the top-left corner, we should see the arcs decreasing in width, and then at some point merging into a solid gray background. Something like this:

But with pixel mixing, when the lines are very thin, we see extraneous artifacts:

Most real-world images won’t exhibit such a problem, but it’s worth being aware of this.

Here’s a related problem. If the original image is severely aliased, like this one:

pixel mixing will do very little to anti-alias it:

Most other algorithms, such as Lanczos resampling, will anti-alias such images to a much larger degree:

When enlarging or reducing by an integral factor, pixel mixing is exactly the same as a box filter. In all other cases, it is not.

A box filter uses an imaginary grid similar to pixel mixing, but instead of a source pixel’s color covering a square tile, its color is contained only in a tiny point at its center.

Or, to look at it a different way, the grid lines you use
with a box filter
are only allowed to be placed *between* the source pixels,
and not pass through them.

(Note that the grid analogy doesn’t work so well here when the image is being enlarged. But the algorithm still works.)

Here’s a way to use a box filter to approximate pixel mixing:

- Use a nearest-neighbor algorithm or a box filter to increase the size of the image by some fixed factor (say, 8). The larger the factor, the better the approximation.
- Use a box filter to resize the enlarged image to the desired final size.

If you’re writing a computer program to (in effect) do this, it can be faster than true pixel mixing.

Pixel mixing can be implemented using a typical filter-based algorithm, but the shape of the filter is not fixed – it must be adapted to the scale factor.

Analyzing pixel mixing using ResampleScope or a similar utility, we see that for large upscales, it looks just about like a box filter:

But for smallish upscales, it takes different shapes. For example, this is what it looks like when the size is doubled:

*(Note that, to get a good picture of a filter, I sometimes have to
avoid scale factors that are a simple exact fraction (like 2, or 1/2,
or 3/5).
They can cause the filter to degenerate to a few isolated points. That’s
also the reason that two different filters can sometimes produce the
exact same image:
the only points that are used happen to be where the filter functions
intersect.)*

As the scale factor approaches 1, the filter looks less and less like a box filter, and more like a triangle filter.

As the factor gets below 1, the trend reverses, and it become more and more like a box filter again. In fact, the filter for scale factor N looks exactly like it does for scale factor 1/N.

Putting this all together, pixel mixing may be implemented using a filter function similar to this pseudocode:

function pixel_mix_filter(scale_factor, x) { if scale_factor < 1 p:= scale_factor else p:= 1/scale_factor if x < 0.5-p/2 return 1 else if x < 0.5+p/2 return 0.5-(x-0.5)/p else return 0 }

Another way to think of pixel mixing is as the integral of a nearest-neighbor function.

For simplicity, consider resizing an 8×1 grayscale image to 5×1.

Plot the continuous function representing the intensity of the nearest pixel to every point:

Partition the region under this curve
(between the *x*-axis and the nearest-neighbor
function)
into five sections of equal
width.

If we were using a standard resampling algorithm,
we would simply “sample” the
function, by finding its values at the
*x*-coordinates corresponding to the
centers of the pixels in the resized image.

Instead, we need to calculate the **area** of each section.
The areas represent the
relative intensities of the pixels in the resized image.
If you know some calculus, you’ll
recognize this procedure as *integration*.

This technique (integrating instead of sampling) can be used with functions other than a nearest-neighbor function, but unless the source image has special properties, it will usually make the resized image blurrier than it needs to be.

*This page is by
Jason Summers,
and is one of several documents related to
ImageWorsener.
Created 6/2012.*