Last active
April 4, 2018 06:02
-
-
Save jcupitt/c54f874c33bea52ea6c3f270873978a9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from __future__ import print_function | |
import timeit | |
setup = ''' | |
import pyvips | |
# libvips is a demand-driven image processing library -- a line like | |
# | |
# x = y.similarity(angle=20) | |
# | |
# will not perform any computation, it just adds a new node to a pipeline. | |
# Computation only happens when you connect a pipeline to a sink (a thing that | |
# will demand pixels). When this happens, the entire pipeline executes all at | |
# once and in parallel. libvips is able to overlap JPG decode, rotation, and JPG | |
# encode. This can give a nice speed boost and drop in latency, especially on | |
# machines with many cores. It also drops memory use right down, since it never | |
# needs to have all the image present at once. | |
# This benchmark is just timing a single rotate operation from a memory source | |
# to a memory destination. To set this up, we must run two pipelines: one from | |
# the JPG source into a memory buffer (which we don't time), and a second | |
# pipeline (which we do time) running from that first memory buffer into a | |
# second. | |
# A test like this misses two useful libvips features: it does not show off the | |
# ability to overlap operations (which larger programs should benefit | |
# from), and it does not show the memory savings you get with streaming (very | |
# useful for large images). | |
# The speed and memory use benchmark on the libvips wiki has timings for a | |
# slightly larger test program: | |
# | |
# https://github.com/jcupitt/libvips/wiki/Speed-and-memory-use | |
# a 1450 x 2048 RGB jpg | |
test_file = "/home/john/pics/k2.jpg" | |
# this will read the header from the file, but not decode any pixels ... pixels | |
# are only decoded on demand | |
im = pyvips.Image.new_from_file(test_file) | |
# this will connect im to a memory sink and pull pixels from the source into the | |
# memory buffer | |
memory = im.copy_memory() | |
# this will start a new pipeline working from the memory buffer ... but it will | |
# not do any computation! that will only happen when this second pipeline | |
# connects to a sink | |
im2 = memory.similarity(angle=20) | |
# libvips always outs all pixels on rotate, but PIL only outputs the centre area, | |
# the same size as the original -- to make it fair, we crop the libvips one | |
# down | |
# this extra crop operation actually makes libvips quicker, since it will have | |
# fewer pixels to compute | |
im3 = im2.crop((im2.width - memory.width) / 2, | |
(im2.height - memory.height) / 2, | |
memory.width, | |
memory.height) | |
''' | |
stmt = ''' | |
# this will execute the second pipeline working from the memory buffer into | |
# a second memory buffer | |
memory2 = im3.copy_memory() | |
''' | |
print('vips', timeit.timeit(stmt=stmt, setup=setup, number=100) / 100) | |
setup = ''' | |
from PIL import Image | |
test_file = "/home/john/pics/k2.jpg" | |
im = Image.open(test_file) | |
''' | |
stmt=''' | |
im2 = im.rotate(20, resample=Image.BILINEAR) | |
''' | |
print('pillow', timeit.timeit(stmt=stmt, setup=setup, number=100) / 100) |
libvips was outputting a larger image than PIL. I cropped the libvips one down to the same size and I now see:
john@kiwi:~/try$ python bench.py
vips 0.0445712780952
pillow 0.151649999619
so about 3.4x faster
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
On my two-core, four-thread laptop with pillow 4.3 and libvips 8.5:
john@kiwi:~/try$ python bench.py
vips 0.0544475102425
pillow 0.153400540352
With pillow-simd 4.3 I see:
john@kiwi:~/try$ python bench.py
vips 0.0544475102425
pillow 0.116245059967