A few years ago, I wrote up a brief comparison of various image libraries running a series of operations (image compositing and resizing) that we use for Lensley on an OS X + Python setup.
Just recently, I started doing work with Ruby + RMagick, however I ran into some issues doing basic operations (PNG resizing on a set of images) that was just incredibly slow.
ruby 1.9.3p385 (rvm) + RMagick 2.13.2 (ImageMagick 6.8.0-7 2013-02-19 Q16) real 9m37.735s user 4m11.995s sys 3m16.644s
What’s going on here? Looking more closely, Ruby started out maxing out the CPU but this actually declined as the script ran, and memory steadily climbed, reaching 6GB by the end (which took about 30s after processing just to release). Obviously a GC issue, and sure enough, there was a thread about it. Adding a couple destroy!
calls at the end seemed to fix things nicely:
real 3m49.132s user 3m44.673s sys 0m3.150s
Now, how did that compare with running convert via Python, I wondered?
Python 2.7.3 + envoy + convert (ImageMagick 6.8.0-7 2013-02-19 Q16) real 4m58.882s user 4m40.536s sys 0m15.840s
Seems about right (one interesting thing to note is that the processing was actually shorter than Activity Monitor’s refresh so it never showed maxed CPU usage). Now how about running ImageMagick directly?
time mogrify -path test-seq3 -scale 800x450 test-in/*.png real 3m17.050s user 3m14.937s sys 0m1.879s
OK, and since we’re just doing simple manipulation, lets see how it does against sips.
real 0m56.272s user 0m51.000s sys 0m5.150s
Well now, that’s a bit embarrassing isn’t it? Still, one thing with all of these so far was that only a single processor was being maxed out.
I decided to try multiprocessing (this was easier for me in Python) to see how fast I could really process these images. I used multiprocessing + Queue w/ 8 processes for my cores (similar to this example).
Python MP + envoy + convert (ImageMagick 6.8.0-7 2013-02-19 Q16) real 0m51.472s user 4m44.998s sys 0m19.737s Python MP + PIL 1.1.7 real 0m18.123s user 2m5.540s sys 0m2.721s Python MP + Wand (ImageMagick 6.8.0-7 2013-02-19 Q16) real 0m39.012s user 4m39.162s sys 0m4.145s Python MP + pgmagick (GraphicsMagick 1.3.17 2012-10-13 Q8) real 0m17.148s user 1m47.560s sys 0m1.593s Python MP + envoy + sips real 0m52.984s user 0m58.504s sys 0m13.715s
The biggest surprise was that sips had virtually no gain and no effect on the actual processing. I wonder if there’s some pipelining going on or what the loss in subprocesses was… PIL and GraphicsMagick beat the pants of ImageMagick, both being over twice as fast in processor and wall time.
I would have liked to have tried comparing to freeimage, but alas couldn’t get wrappers to work. smc.freeimage and FreeImagePy had problems talking to the dylib, and I was able to get mhotas‘ freeimage wrapper mostly working but it was giving me fits on resizing. Maybe next time.