random($foo)

Posts Tagged ‘graphics’

Performance Comparison of Image Libraries

Friday, July 9th, 2010

For the past couple years, I’ve been using the Python CoreGraphics bindings to do some of my image manipulation. While a bit more complex than I would have liked for setup (dealing w/ context rotations and other scaling math was a bit of the pain), it otherwise worked great (and more importantly, right out of the box) on Leopard. Unfortunately, with Snow Leopard, the CoreGraphics library was unceremoniously (as far as I know, without any sort of announcement or acknowledgement) deprecated. It’d only work in 32-bit mode and more troubling, certain Context calls that used to take floats now required CGFloats. Not so much of a problem… besides the fact that even after much research and poking, I found no way to instantiate a CGFloat (there’s an undocumented CGFloatArray call, but that just gives you uninitialized CGFloats w/o a good way to assign them).

As has been the trend, I’ve been isolating/switching more and more of my code from anything that touches Apple libraries. I’ve come to the conclusion that they just don’t give a shit about breaking your code (much less care about fixing or even responding what they’ve broken). It’s incredibly off-putting. In this case, it’s unfortunate, as the CoreGraphics code performs much better than both PIL and ImageMagick (I would have tested GraphicsMagick as well, but it doesn’t support the chaining features I needed for my particular resizing/layout operations).

CoreGraphics Python w/ kCGInterpolationHigh
real     0m1.885s
user     0m1.456s
sys      0m0.400s

PIL w/ Bilinear Filter Resize
real     0m3.380s
user     0m2.981s
sys      0m0.365s

32-bit Static ImageMagick
real     0m7.125s
user     0m9.730s
sys      0m0.652s

32-bit Static ImageMagick w/ Box Filter Resize
real     0m4.237s
user     0m4.438s
sys      0m0.636s

64-bit Shared ImageMagick
real     0m6.080s
user     0m8.495s
sys      0m0.366s

64-bit Shared ImageMagick w/ Box Filter Resize
real     0m3.268s
user     0m3.599s
sys      0m0.331s

A few things worth noting:

  • I try to use the system Python. After all the problems w/ 10.5->10.6 though, I am reconsidering.
  • PIL seemed to easy_install well (w/ a binary egg no less) on my 10.6 – I’ll have to test on a clean system to make sure I hadn’t made my life easier w/ MacPorts or something, but this is a huge improvement over the problems surrounding installing PIL on 10.5, which was what actually drove me to use the CoreGraphics Python library in the first place. UPDATE: on a clean 10.6 install, it compiles, but doesn’t have JPEG or FreeType support. waah wahhh
  • ImageMagick defaults to Lanczos filtering by default, which is quite slow. Testing out various filters, Box filtering was about twice as fast and for my test images had neglible-to-nonexistent image quality differences even under the loupe. Definitely worth poking around a bit if you’re trying to get better performance.
  • The 64-bit shared lib version of ImageMagick is fair bit faster than the 32-bit static version. Until I’m all on 64-bit hardware, is a bit of a moot point to do further testing though. I’m assuming the extra sys time is due to the staticness and the remainder is due to 64-bitness.
  • Given roughly equivalent performance between PIL and ImageMagick, I’ll be going with ImageMagick for the additional flexibility/features it provides.
  • Although it doesn’t work for this particular set of operations, I wanted to mention that Marc Lyniage’s CoreImageTool is just a wicked, wicked piece of software. It of course has all the CoreImage caveats though, especially if you have to deal with Intel’s crappy GPUs (*fist shaking*)