
Pillow-SIMD: improving the performance of image processing - igordebatur
https://github.com/uploadcare/pillow-simd#readme
======
wolf550e
re: [https://github.com/uploadcare/pillow-simd#why-do-not-
contrib...](https://github.com/uploadcare/pillow-simd#why-do-not-contribute-
simd-to-the-original-pillow)

They can create three versions of each affected function (fallback, SSE4 and
AVX2), place them in separate files (one file for each set of compiler flags),
compile each version with its own compiler flags, then link them all together,
and in the main module (which is compiled for generic cpu) run cpuid and set
global function pointers to the right function implementation.

Then always use the global function pointer to call the right implementation
of the function, and only expose calling the global function pointer if the
function is exported from a shared library.

They do need to make sure that function pre and post conditions are preserved
in all versions and that memory alignment/layout required by optimized
functions is created by the generic code.

I think x264 does this.

~~~
asb
You can even use the GCC ifunc attribute and get the dynamic linker to handle
selecting the right function.

~~~
btown
Certainly seems like this is the right way to go:
[http://clang.llvm.org/docs/AttributeReference.html#ifunc-
gnu...](http://clang.llvm.org/docs/AttributeReference.html#ifunc-gnu-ifunc)

~~~
dman
Any pointers for similar functionality for Visual Studio?

~~~
tacos
Code in separate libs then this inside #ifdefs.

#pragma comment(linker, ...)

~~~
dman
Thanks!

------
Veratyr
It'd be interesting to see this compared to Halide [0], which conveniently
already has a resize example [1]. Parallelization and data locality for
example can make big differences.

[0]: [http://halide-lang.org/](http://halide-lang.org/)

[1]:
[https://github.com/halide/Halide/blob/e9ece5ee8ee9cb62295d5e...](https://github.com/halide/Halide/blob/e9ece5ee8ee9cb62295d5e7e5409e54390bb01b4/apps/resize/resize.cpp)

~~~
andrewbadams
I just discovered today that our resize example is actually absurdly slow.
Working on a better one. So far it's about 8x faster. The other apps are much
better tuned.

(I'm one of the main Halide devs)

~~~
Veratyr
Cool! On another note, are you aware of any other places with a lot of Halide
code? A repository for common but not-obvious processes like brightness
changing, denoising, contrast adjustment and such would be really cool.

------
woodruffw
I don't really want to defend ImageMagick, but does Pillow come anywhere close
to it in terms of format support? A magnitude better performance is great, but
sometimes you just need to operate on and convert strange files (X bitmaps,
ASCII braille come to mind).

~~~
St-Clock
ImageMagick has also better default handling. For example, in a previous
project, we were automatically resizing jpeg images. Surprisingly, some
resulting images were blurry. After some investigation, we found that these
images had been photoshopped and Photoshop was using a different sampling
factor (one of the variables used in jpeg compression). ImageMagick
automatically detected this sampling factor and reused the same, but Pillow
was using a default sampling factor and was blurring the image.

~~~
wiredfool
Did you submit a bug? We're using libjpeg, so the support for that
functionality should be there.

------
jbaiter
This is a bit OT, but if you only care about downscaling, cropping and/or
rotating JPEG images by multiples of 90 degrees, you might also want to take a
look at jpegtran-cffi ([https://github.com/jbaiter/jpegtran-
cffi](https://github.com/jbaiter/jpegtran-cffi)).

It does all of the above operations without decoding the image, giving a
significant speed boost.

I just benchmarked it against pillow-smd on my laptop (SSE4 only) and it's
1.3-1.8x faster, depending on the operation.

------
brokentone
I wonder why this isn't benched against graphics magick (which I have found to
be ~2x faster than imagemagick)

~~~
liuliu
Both of the implementations you mentioned are not best known for its speed,
rather, its their versatility (or bloatedness, some may argue).

------
spiderfarmer
With Python, is there an alternative for pexif.py to parse the orientation
data for reorientating images? I used Thumbor in production for a while (which
relies on Pexif) and found so many bugs in it that I had to make a hurried
switch back to PHP.

------
tacos
Just slipped this into an image resize-bound Python script I'm using.
Immediate 3x speedup. Glorious!

(But yeah, would love to see this merged upstream. Lots of Python libraries
have sorted out harder CPU/GPU dependencies.)

------
wolf550e
Does Pillow have good security tests like fuzzing? Is it safe to pass
arbitrary user input (file upload) to Pillow and Pillow-SIMD?

~~~
wiredfool
Fuzzing is slow. I've tried afl against a small subset of images and I was
getting about 10 tries per sec per core.

There have been some bugs that look like people have been successfully
fuzzing, but there's nothing organized.

The goal is certainly to be safe against user input, I would say we're there,
but we're better off than we were 6months ago.

~~~
tacos
At the next major rev, Image.DecompressionBombWarning probably should default
to error instead of warning.

------
wyldfire
Why did Pillow fork from PIL in the first place?

> If you have ever worried or wondered about the future of PIL, please stop.
> We're here to save the day

What's the backstory here?

~~~
masklinn
> What's the backstory here?

No backstory, the development of PIL gradually slowed down and ultimately
stopped in 2011 (the last official release having been cut in 2009), I've
never seen any info as to why that happened, it just did. Possibly the
difficulty of implementing P3 compatibility while remaining pre-2.7
compatible.

PIL was always an idiosyncratic package with a completely custom setup script,
a difficult install (including setuptools-incompatibility) and weird-ass
modules (probably owing in part to 1.5~2.7 compatibility), as well as a fairly
slow release schedule (bi-yearly at the best of times).

And so in 2013 it was forked (not entirely unlike LibreSSL from OpenSSL) and a
dedicated group started on maintaining and cleaning the stuff, progressively
phasing out pre-2.6 compatibility and adding Python 3 support, etc...

~~~
cjmarks
Very easy install:

    
    
      wget http://effbot.org/downloads/Imaging-1.1.7.tar.gz
      tar xvf Imaging-1.1.7.tar.gz
      cd Imaging-1.1.7/
      python2.7 setup.py build
      sudo python2.7 setup.py install
    
    

Alas, those simple days are over.

EDIT: Preemptively, I know how to verify checksums.

~~~
wiredfool
Thankfully, you can still do that if you don't like pip.

------
vinayan3
What about compared to opencv's image handling functions? I've seen Opencv run
about 4x faster than pillow for certain operations.

~~~
homm
Opencv doesn't provide convolution-based resampling. Only supersampling with
INTER_AREA flag, which is comparable to BICUBIC for high-ratio downscaling.
So, such statements don't make sense without exact code :-)

------
odc
Is there any chance the ImageMagick developers would consider adding such
optimizations?

------
kolapuriya
Which operations you do the most? I'll try speed up them too.

------
Keyframe
How about versus imagemagick with openCL?

------
masterleep
What if you don't care about speed, but you do care about not embedding
strange scripting languages from the mid-1990s that can write files and make
network requests?

~~~
projct
[https://github.com/imazen/imageflow](https://github.com/imazen/imageflow)
works for that and still gives you speed. :P

