Thursday, 31 March 2016

Faster and better image shrinking

vips 8.3 is almost here, and one of the new things is a rewritten image shrinker.

Previously, vips combined a block shrink, a variable-sized anti-alias filter, a fixed-size resampler, and a final sharpen. This approach had two main problems: first, you had to have the anti-alias filter tuned very carefully to get nice results and it was hard to find a tuning rule which worked for all images. Secondly, the slowest part of the chain of four operations was the fixed-size resample, and this could not be easily vectorized, since the vector lengths were too small.

The new vips 8.3 shrinker is just two operations: a new block shrinker, and a new variable-sized lanczos3. There's no tuning required, so quality is always great, and the two new operations have been designed to be vectorizable, so performance is up too.

There's a new page on the vips wiki which runs through the new shrinker in some detail, so have a look there if you're curious.

Quality


Here's an interesting test image from Scott Kevill. First, vips 8.1 shrinking the 800x600 original down to 600x450:


It's not too bad, but there is some moiré fringing in the roof tiles and it could be a little sharper. Here's the new code in vips 8.3 doing the same task:


The patterns in the roof tiles have pretty much gone, and it also looks sharper. Put the two images into two tabs and try flipping between them. The original image plus a number of other resizes, including the output of ImageMagick, are on this page.

Performance


The speedup you'll see depends on the image format and the size change. It's most dramatic with TIFF.

Here's vips 8.1 shrinking a 10,000 x 10,000 uncompressed RGB TIFF to a 128x128 pixel JPEG:
$ time vipsthumbnail wtc.tif
real    0m0.559s
user    0m0.468s
sys     0m0.092s
vips 8.3 is more than twice as fast:
$ time vipsthumbnail wtc.tif
real    0m0.238s
user    0m0.172s
sys     0m0.064s
mem     50mb
With JPEG it's less impressive, since almost all the work is done by the JPEG decoder, and that's obviously unchanged.

Here's the same image, but as JPEG with vips 8.1:
$ time vipsthumbnail wtc.jpg
real    0m0.294s
user    0m0.284s
sys     0m0.008s
And with 8.3:
$ time vipsthumbnail wtc.jpg
real    0m0.272s
user    0m0.256s
sys     0m0.016s
mem     24mb
If you ask for a 2,000 x 2,000 pixel output image it looks better, since vips will actually have some work to do. With 8.1 it was
$ time vipsthumbnail wtc.jpg -s 2000
real    0m1.032s
user    0m2.864s
sys     0m0.040s
And 8.3 is now:
$ time vipsthumbnail wtc.jpg -s 2000
real    0m0.491s
user    0m0.924s
sys     0m0.048s
mem     69mb
For comparison, here's ImageMagick doing the same tasks:
$ time convert wtc.tif -resize 128 tn_wtc.jpg
real    0m2.687s
user    0m4.120s
sys     0m0.512s
mem     705mb
$ time convert -define jpeg:size=256x256 wtc.jpg -resize 128 tn_wtc.jpg
real    0m0.259s
user    0m0.284s
sys     0m0.000s
mem     19mb
$ time convert -define jpeg:size=4000x4000 wtc.jpg -resize 2000 tn_wtc.jpg
real    0m1.165s
user    0m2.476s
sys     0m0.352s
mem     285mb
vips is usually faster and occasionally a lot faster. 

2 comments:

  1. Hi John,
    I'm using Vips::Image affine to do fractional rotation and asymmetrical scaling of images from 2K to about a third of that size (frames from movie films). I suppose these new changes to image shrinking do not apply to affine?
    Regards, Paul Howson.

    ReplyDelete
    Replies
    1. Hi Paul, no, no change to affine. You could use shrink to downsize by x2 and then affine from that, but it would probably be slower.

      Delete