I'm trying to add two images together using NumPy and PIL. The way I would do this in MATLAB would be something like:
>> M1 = imread('_1.jpg'); >> M2 = imread('_2.jpg'); >> resM = M1 + M2; >> imwrite(resM, 'res.jpg');
I get something like this:
Using a compositing program and adding the images the MATLAB result seems to be right.
In Python I'm trying to do the same thing like this:
from PIL import Image from numpy import * im1 = Image.open('/Users/rem7/Desktop/_1.jpg') im2 = Image.open('/Users/rem7/Desktop/_2.jpg') im1arr = asarray(im1) im2arr = asarray(im2) addition = im1arr + im2arr resultImage = Image.fromarray(addition) resultImage.save('/Users/rem7/Desktop/a.jpg')
and I get something like this:
Why am I getting all those funky colors? I also tried using
ImageMath.eval("a+b", a=im1, b=im2), but I get an error about RGB unsupported.
I also saw that there is an
Image.blend() but that requires an alpha.
What's the best way to achieve what I'm looking for?
Source Images (images have been removed):
Humm, OK, well I added the source images using the add image icon and they show up when I'm editing the post, but for some reason the images don't show up in the post.
(images have been removed) 2013 05 09
As everyone suggested already, the weird colors you're observing are overflow. And as you point out in the comment of schnaader's answer you still get overflow if you add your images like this:
The reason for this overflow is that your NumPy arrays (im1arr im2arr) are of the uint8 type (i.e. 8-bit). This means each element of the array can only hold values up to 255, so when your sum exceeds 255, it loops back around 0:
>>>array([255,10,100],dtype='uint8') + array([1,10,160],dtype='uint8') array([ 0, 20, 4], dtype=uint8)
To avoid overflow, your arrays should be able to contain values beyond 255. You need to convert them to floats for instance, perform the blending operation and convert the result back to uint8:
im1arrF = im1arr.astype('float') im2arrF = im2arr.astype('float') additionF = (im1arrF+im2arrF)/2 addition = additionF.astype('uint8')
You should not do this:
addition = im1arr/2 + im2arr/2
as you lose information, by squashing the dynamic of the image (you effectively make the images 7-bit) before you perform the blending information.
MATLAB note: the reason you don't see this problem in MATLAB, is probably because MATLAB takes care of the overflow implicitly in one of its functions.
Using PIL's blend() with an alpha value of 0.5 would be equivalent to (im1arr + im2arr)/2. Blend does not require that the images have alpha layers.
from PIL import Image im1 = Image.open('/Users/rem7/Desktop/_1.jpg') im2 = Image.open('/Users/rem7/Desktop/_2.jpg') Image.blend(im1,im2,0.5).save('/Users/rem7/Desktop/a.jpg')
It seems the code you posted just sums up the values and values bigger than 256 are overflowing. You want something like "(a + b) / 2" or "min(a + b, 256)". The latter seems to be the way that your Matlab example does it.
I do (im1arr+im2arr)/2 I get funky colors, only dimmer, max value 127 so I did: addition=(im1arr/2)+(im2arr/2) and that seems to work - rem7 2009-02-08 03:02
min(a + b, 256)because if you get a value over 256 you want to clamp the value at 256 (you don't want to take a value over 256). In any case, to fix the error @rem7 pointed out, you can do
additionF = np.minimum(im1arrF + im2arrF, 256)Vincent 2016-06-29 05:12
To clamp numpy array values:
>>> c = a + b >>> c[c > 256] = 256
Your sample images are not showing up form me so I am going to do a bit of guessing.
I can't remember exactly how the numpy to pil conversion works but there are two likely cases. I am 95% sure it is 1 but am giving 2 just in case I am wrong. 1) 1 im1Arr is a MxN array of integers (ARGB) and when you add im1arr and im2arr together you are overflowing from one channel into the next if the components b1+b2>255. I am guessing matlab represents their images as MxNx3 arrays so each color channel is separate. You can solve this by splitting the PIL image channels and then making numpy arrays
2) 1 im1Arr is a MxNx3 array of bytes and when you add im1arr and im2arr together you are wrapping the component around.
You are also going to have to rescale the range back to between 0-255 before displaying. Your choices are divide by 2, scale by 255/array.max() or do a clip. I don't know what matlab does