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:
→ | → |
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:
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.