views:

173

answers:

2

I have two images, both with alpha channels. I want to put one image over the other, resulting in a new image with an alpha channel, just as would occur if they were rendered in layers. I would like to do this with the Python Imaging Library, but recommendations in other systems would be fantastic, even the raw math would be a boon; I could use NumPy.

OVER:

a + b = blend

As opposed to BLEND 0.5:

a + b = blend

+2  A: 

I couldn't find an alpha composite function in PIL, so here is my attempt at implementing it with numpy:

import numpy as np
import Image

def alpha_composite(front,back):
    # The formula comes from http://en.wikipedia.org/wiki/Alpha_compositing
    # front, back are assumed to be RGBA Images
    front=np.asarray(front)
    back=np.asarray(back)    
    result=np.empty(front.shape,dtype='float')
    alpha=np.index_exp[:,:,3:]
    rgb=np.index_exp[:,:,:3]
    falpha=front[alpha]/255.0
    balpha=back[alpha]/255.0
    result[alpha]=falpha+balpha*(1-falpha)
    result[rgb]=(front[rgb]*falpha + back[rgb]*balpha*(1-falpha))/result[alpha]
    result[alpha]*=255
    front_transparent=(falpha<=0.001)&(balpha>0.001)
    result[front_transparent]=back[front_transparent]
    back_transparent=(balpha<=0.001)&(falpha>0.001)
    result[back_transparent]=front[back_transparent]
    result[result>255]=255
    # astype('uint8') maps np.nan and np.inf to 0
    result=result.astype('uint8')
    result=Image.fromarray(result,'RGBA')
    return result

img1=Image.open('a.png').convert('RGBA')
img2=Image.open('b.png').convert('RGBA')
img3=alpha_composite(img2,img1)
img3.show()
img3.save('img3.png')

PS. I suspect the numpy computation could be tightened up considerably...

unutbu
Works like a charm. Thanks.
Kris Kowal
+2  A: 

This appears to do the trick:

from PIL import Image
bottom = g = Image.open("a.png")
top = l = Image.open("b.png")

r, g, b, a = top.split()
top = Image.merge("RGB", (r, g, b))
mask = Image.merge("L", (a,))
bottom.paste(top, (0, 0), mask)
bottom.save("over.png")
Kris Kowal
I stand corrected :) Thanks for sharing.
unutbu
@~unutbu No, yours works better. I've incorporated your solution in my project.
Kris Kowal