Python: PIL ( Pillow ) & NumPy add images

Pillow (PIL) and NumPy libraries can do wonders in Python! I had once he requirement to overlap two images – not watermarking.

I found several alternatives, but curious to see which would work best.

  1. (x+y)/2 … Mathematically, x/2+y/2 seems equivalent to above, but it is not. We’d be loosing a ton of info by doing so!
  2. Numpy.minimum((x+y),256)
  3. final = (x+y/2) and then addition = addition[addition>256]=256
  4. Pillow’s Image.blend(x,y,0.5)
  5. Pillow’s Image.composite(x,y,y)

Input images used :

1.png 2.png C.png


Do you speak Parseltongue? I speak Python.

Here are the results :

I am using getImageDifference(x,y) function to compare the outcome with the expected image and get the difference, the lesser the difference, the better, 0 is ideal. Note that if you see few pixel off, that is intentional, as chances are, the human eye would not catch it.

Variant Difference
Variant 1 0.12561853664
Variant 4 0.661266633307
Variant 5 0.0380851773602

As far as my testing, for my particular usage is concerned, 1st variant below has performed better job as compared to others – in terms of getting the job done and being general enough. As you might have noticed, I am converting image to black and white based on some predefined threshold value (=200).

2nd variant gave me a white image, where as 3rd was kind of close by giving me gray color, instead black.

If the arrays of the input images have values 0-255 or 1-256 then adding these two arrays together and dividing by 2 would always be lesser or equal to the maximum value. I do not quite follow why addition = addition[addition>256]=256 is needed as 3rd variant suggests.

4th variant, does what it says – blending (Pillow 3.3.x Docs). 5th variant is to use composite function from Pillow (PIL).Here is what blend (alpha = 0.5) and composite functions return.

Blend Composite
0.661266633307 0.0380851773602


But there’s a catch … the masking parameter in the composite function does matter. See below. It does what it says. In this regard variant 1 is general enough it does the job without overthinking it.

If you want to tell Unix to deliver hammer to your foot, you can. And Unix would make sure to deliver the hammer to your foot in the most efficient way possible!


Composite parameters Result
Image.composite(x, y, x) Image.composite(x, y, y)
1.29032071241 0.0380851773602


May the source be with you!


Published by

Aarsh Talati

Software Developer

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s