2010-07-30 19 views
12

Tengo dos imágenes, ambas con canales alfa. Quiero poner una imagen sobre la otra, lo que da como resultado una nueva imagen con un canal alfa, tal como ocurriría si se representaran en capas. Me gustaría hacer esto con la Biblioteca de imágenes de Python, pero las recomendaciones en otros sistemas serían fantásticas, incluso las matemáticas en bruto serían una bendición; Podría usar NumPy.Con Python Imaging Library (PIL), ¿cómo se puede componer una imagen con un canal alfa sobre otra imagen?

SOBRE:

a http://dl.dropbox.com/u/1688099/ennorath/tmp/a.png + b http://dl.dropbox.com/u/1688099/ennorath/tmp/b.png = blend http://dl.dropbox.com/u/1688099/ennorath/tmp/over.png

A diferencia de 0,5 MEZCLA:

a http://dl.dropbox.com/u/1688099/ennorath/tmp/a.png + b http://dl.dropbox.com/u/1688099/ennorath/tmp/b.png = blend http://dl.dropbox.com/u/1688099/ennorath/tmp/blend.png

+0

Esto funcionó para mí: im.paste (imagen, cuadro, máscara) http://stackoverflow.com/questions/5324647/how-to-merge-a-transparant-png-image -with-another-image-using-pil – Gonzo

Respuesta

15

no pude encontrar una func alpha composite ción en el PIL, así que aquí está mi intento de implementar con numpy:

import numpy as np 
from PIL import Image 

def alpha_composite(src, dst): 
    ''' 
    Return the alpha composite of src and dst. 

    Parameters: 
    src -- PIL RGBA Image object 
    dst -- PIL RGBA Image object 

    The algorithm comes from http://en.wikipedia.org/wiki/Alpha_compositing 
    ''' 
    # http://stackoverflow.com/a/3375291/190597 
    # http://stackoverflow.com/a/9166671/190597 
    src = np.asarray(src) 
    dst = np.asarray(dst) 
    out = np.empty(src.shape, dtype = 'float') 
    alpha = np.index_exp[:, :, 3:] 
    rgb = np.index_exp[:, :, :3] 
    src_a = src[alpha]/255.0 
    dst_a = dst[alpha]/255.0 
    out[alpha] = src_a+dst_a*(1-src_a) 
    old_setting = np.seterr(invalid = 'ignore') 
    out[rgb] = (src[rgb]*src_a + dst[rgb]*dst_a*(1-src_a))/out[alpha] 
    np.seterr(**old_setting)  
    out[alpha] *= 255 
    np.clip(out,0,255) 
    # astype('uint8') maps np.nan (and np.inf) to 0 
    out = out.astype('uint8') 
    out = Image.fromarray(out, 'RGBA') 
    return out 

Por ejemplo dado estas dos imágenes,

img1 = Image.new('RGBA', size = (100, 100), color = (255, 0, 0, 255)) 
draw = ImageDraw.Draw(img1) 
draw.rectangle((33, 0, 66, 100), fill = (255, 0, 0, 128)) 
draw.rectangle((67, 0, 100, 100), fill = (255, 0, 0, 0)) 
img1.save('/tmp/img1.png') 

enter image description here

img2 = Image.new('RGBA', size = (100, 100), color = (0, 255, 0, 255)) 
draw = ImageDraw.Draw(img2) 
draw.rectangle((0, 33, 100, 66), fill = (0, 255, 0, 128)) 
draw.rectangle((0, 67, 100, 100), fill = (0, 255, 0, 0)) 
img2.save('/tmp/img2.png') 

enter image description here

alpha_composite produce:

img3 = alpha_composite(img1, img2) 
img3.save('/tmp/img3.png') 

enter image description here

+0

Funciona como un encanto. Gracias. –

28

Esto parece hacer el truco:

from PIL import Image 
bottom = Image.open("a.png") 
top = 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") 
+0

Me corresponde corregir :) Gracias por compartir. – unutbu

+1

@ ~ unutbu No, el tuyo funciona mejor. He incorporado tu solución en mi proyecto. –

+1

Acabo de probar este y (a) funciona muy bien, al menos para la tarea rápida y sucia que estoy haciendo y (b) no requiere Numpy para ser instalado. Tenga en cuenta el comentario anterior sin embargo. – dpjanes

19

Almohada 2.0 ahora contiene una función alpha_composite que hace esto.

img3 = Image.alpha_composite(img1, img2) 
Cuestiones relacionadas