Floris Floris - 2 months ago 11
Python Question

A split image can't be merged after performing a .dot on any of the split bands using pillow/numpy

I am trying to correct the color in images using pillow and numpy. Using im.split() in combination with np.array.

I would like to multiply all colours in the red band, but can't find a way of doing it.

I've tried all kinds of things and after a lot of googling had hoped that this would be the solution:

from PIL import Image
import numpy as np

im=Image.open('test.jpg')
r,g,b=im.split()

datar = np.array(r)
datag = np.array(g)
datab = np.array(b)

rm=0.4 # the value I would like to multiply all red pixels by

datar=datar.dot(rm) # this works, but turns the values in the array into floats
datar=datar.astype(int) # I was hoping this would solve it

im=Image.merge("RGB", (Image.fromarray(datar), Image.fromarray(datag), Image.fromarray(datab)))


I can do a lot of things with the arrays and the merge succeeds, but trying this gives me the following error:

im=Image.merge("RGB", (Image.fromarray(datar), Image.fromarray(datag), Image.fromarray(datab)))
File "/usr/local/lib/python2.7/dist-packages/PIL/Image.py", line 2408, in merge
im.putband(bands[i].im, i)
ValueError: images do not match


The array looks the same before and after the .dot and the .astype(int) are applied, and the values are multiplied correctly.

Answer

Image.merge fails because rgb images are not of the same mode (see PIL Image modes). You can check the mode this way:

>>> Image.fromarray(datar).mode
'I'
>>> Image.fromarray(datag).mode
'L'

The reason for this is the type of the numpy array:

>>> datar.dtype
dtype('int32')
>>> datag.dtype
dtype('uint8')

To fix that, replace this:

datar=datar.astype(int)

with this:

datar = datar.astype('uint8')