This is an analysis of Adobe Photoshop CS5.1’s image resizing algorithms, done with the help of my ResampleScope utility.
Anything on this page could be wrong. It’s easy to make mistakes in this kind of analysis.
I used ResampleScope’s standard test images. For upscaling, I resized a 15×15 image to 555×15. For downscaling, I resized a 555×275 image to several different widths. All processing was done in Photoshop’s RGB mode.
I did a lot of other things too. This document only contains the final results.
Photoshop offers five algorithms, to which it gives the following names:
This is what I’ve figured out about them so far. Some of the parameters may not be exactly right, but they’re pretty close.
Let SRCN = the width or height of the source image, in pixels.
Let DSTN = the width or height of the target image, in pixels.
Let SF = DSTN/SRCN. SF is the scale factor.
Nearest neighbor | |
---|---|
If SF = (any?) | Nearest neighbor, with image features shifted left (or up) by approximately 1/36th of a source pixel. |
Bilinear | |
---|---|
If SF > 1 | Linear interpolation; i.e. a triangle filter. |
If 0.5 ≤ SF < 1 | Simple linear interpolation; i.e. a triangle filter with blur=SF. |
If ? ≤ SF < 0.5 | Box filter, with image features shifted right (or down) by 1/2 of a source pixel. |
Bicubic | |
---|---|
If SF ≥ 0.25 | Cubic with B=0, C=0.75. |
If ? ≤ SF < 0.25 | Step 1: Use box filter (as defined above in Bilinear) to scale to 4×DSTN. Step 2: Cubic with B=0, C=0.75. |
Bicubic Smoother | |
---|---|
If SF > 1 | Cubic with B=0, C=0.625, blur=1.15. |
If 0.25 ≤ SF < 1 | Cubic with B=0, C=1.125−0.5×SF, blur=1.15. |
If ? ≤ SF < 0.25 | Step 1: Use box filter (as defined above in Bilinear) to scale to 4×DSTN. Step 2: Cubic with B=0, C=1, blur=1.15. |
Bicubic Sharper | |
---|---|
If SF > 1 | Cubic with B=0, C=1, blur=1.05. |
If 0.25 ≤ SF < 1 | Cubic with B=0, C=2.6−1.6×SF, blur=1.05. |
If ? ≤ SF < 0.25 | Step 1: Use box filter (as defined above in Bilinear) to scale to 4×DSTN. Step 2: Cubic with B=0, C=2.2, blur=1.05. |
Note: Large downscales are harder to analyze, and I haven’t looked much at scale factors below about 0.2. It seems likely that the formulas I’ve given for the Bicubic algorithms don’t account for sufficiently small scale factors.
Note: Photoshop resizes the X dimension, then the Y dimension. If there are multiple steps, it does all the X steps, then all the Y steps (X1 X2 Y1 Y2, not X1 Y1 X2 Y2). The order makes a difference because of clamping (see next note).
Note: Photoshop does what I call “intermediate clamping”. It does not appear to support intermediate pixel values that are outside the displayable range (usually that means 0 to 255). The cubic filters often produce such values, so if you’re trying to emulate what Photoshop does, make sure to clamp the pixels to the displayable range after each application of a cubic filter. Storing the temporary image in a PNG file is one way to do that.
Note: If a dimension of the image is not being changed at all (SF=1), Photoshop does not apply the algorithm to that dimension. It simply leaves the pixels the same. This makes a difference with the Smoother and Sharper algorithms.
Note: Box filters are very sensitive to slight implementation differences, which adds to the difficulty of emulating Photoshop’s algorithms.
This web site looks at how Photoshop resizes a pathological “rings” image. The Bicubic Sharper filter produces the following result:
How closely can we reproduce that using other software?
With ImageMagick, I don’t know how to make it apply the cubic filter to just one dimension. So, this will be less than perfect.
The source image is 1000×1000 pixels, and the target image is 200×200 pixels. SF = 200/1000 = 0.2, which is less than 0.25, so we need to use a box filter, then a cubic filter. 200 times 4 is 800, so we first resize it to 800 pixels, then to 200.
This might not be the best way to do the box filter, but it’s the best I could figure out.
convert Rings1.gif \ -filter box -define filter:blur=0.707 \ +distort SRT "0,0 0.8,1.0 0 0.3999,0.0" -crop 800x1000+0+0 \ +distort SRT "0,0 1.0,0.8 0 0.0,0.3999" -crop 800x800+0+0 \ -transpose \ -filter cubic -define filter:b=0 -define filter:c=2.2 -define filter:blur=1.05 \ -resize 200x200 \ -transpose \ im-bicubicsharp.png
The result:
Photoshop | ImageMagick | Differences |
---|
Note that whether ImageMagick was compiled with HDRI support may have an effect on the results.
ImageWorsener is an image scaling utility I wrote, in part to help see how other applications scale images. (It’s not really noteworthy that it does well on this test. Since it’s my program, I can cheat, and make sure it does well.)
It can only scale each dimension once per invocation, so I have to use temporary files, and run it multiple times, to emulate what Photoshop does.
ImageWorsener’s box filter may do rounding differently than Photoshop’s, so to be safe, I fudged it a bit, and translated the image by 0.3999 instead of 0.4.
# x, box imagew Rings1.gif temp1.png -nogamma -depth 16 -w 800 -h 1000 \ -filterx box -filtery nearest -translate 0.3999,0 # x, cubic imagew temp1.png temp2.png -nogamma -depth 16 -w 200 -h 1000 \ -filterx cubic0,2.2 -blurx 1.05 -filtery nearest # y, box imagew temp2.png temp3.png -nogamma -depth 16 -w 200 -h 800 \ -filterx nearest -filtery box -translate 0,0.3999 # y, cubic imagew temp3.png iw-bicubicsharp.png -nogamma -w 200 -h 200 \ -filterx nearest -filtery cubic0,2.2 -blury 1.05
(The second and third steps cannot be combined, because ImageWorsener resizes the Y dimension first, and the order of operations must not be changed.)
The result:
Photoshop | ImageWorsener | Differences |
---|
The “Differences” image was made with ImageMagick’s compare utility. Any pixels that differ at all are marked in red. There’s some room for improvement, but I think most of the differences are just rounding errors. More investigation is needed to figure out how Photoshop handles pixels near the edges of the image.