简体   繁体   English

如何使用 PIL 将透明的 png 图像与另一个图像合并

[英]How to merge a transparent png image with another image using PIL

I have a transparent png image foo.png and I've opened another image with:我有一个透明的 png 图像foo.png并且我打开了另一个图像:

im = Image.open("foo2.png")

Now what I need is to merge foo.png with foo2.png .现在我需要的是将foo.pngfoo2.png合并。

( foo.png contains some text and I want to print that text on foo2.png ) foo.png包含一些文本,我想在foo2.png上打印该文本)

from PIL import Image

background = Image.open("test1.png")
foreground = Image.open("test2.png")

background.paste(foreground, (0, 0), foreground)
background.show()

First parameter to .paste() is the image to paste. .paste()第一个参数是要粘贴的图像。 Second are coordinates, and the secret sauce is the third parameter.第二个是坐标,秘方是第三个参数。 It indicates a mask that will be used to paste the image.它表示将用于粘贴图像的蒙版 If you pass a image with transparency, then the alpha channel is used as mask.如果您传递具有透明度的图像,则 Alpha 通道将用作遮罩。

Check the docs .检查 文档

Image.paste does not work as expected when the background image also contains transparency.当背景图像也包含透明度时, Image.paste无法按预期工作。 You need to use real Alpha Compositing .您需要使用真正的Alpha 合成

Pillow 2.0 contains an alpha_composite function that does this. Pillow 2.0 包含执行此操作的alpha_composite函数。

background = Image.open("test1.png")
foreground = Image.open("test2.png")

Image.alpha_composite(background, foreground).save("test3.png")

EDIT: Both images need to be of the type RGBA.编辑:两个图像都需要是 RGBA 类型。 So you need to call convert('RGBA') if they are paletted, etc.. If the background does not have an alpha channel, then you can use the regular paste method (which should be faster).所以你需要调用convert('RGBA')如果它们是调色板等等。如果背景没有 alpha 通道,那么你可以使用常规的 paste 方法(应该更快)。

As olt already pointed out, Image.paste doesn't work properly, when source and destination both contain alpha.正如olt已经指出的那样,当源目标都包含 alpha 时, Image.paste无法正常工作。

Consider the following scenario:考虑以下场景:

Two test images, both contain alpha:两个测试图像,都包含 alpha:

在此处输入图片说明 在此处输入图片说明

layer1 = Image.open("layer1.png")
layer2 = Image.open("layer2.png")

Compositing image using Image.paste like so:使用Image.paste合成图像, Image.paste所示:

final1 = Image.new("RGBA", layer1.size)
final1.paste(layer1, (0,0), layer1)
final1.paste(layer2, (0,0), layer2)

produces the following image (the alpha part of the overlayed red pixels is completely taken from the 2nd layer. The pixels are not blended correctly):生成以下图像(覆盖的红色像素的 alpha 部分完全取自第二层。像素未正确混合):

在此处输入图片说明

Compositing image using Image.alpha_composite like so:使用Image.alpha_composite合成图像, Image.alpha_composite所示:

final2 = Image.new("RGBA", layer1.size)
final2 = Image.alpha_composite(final2, layer1)
final2 = Image.alpha_composite(final2, layer2)

produces the following (correct) image:产生以下(正确的)图像:

在此处输入图片说明

One can also use blending:还可以使用混合:

im1 = Image.open("im1.png")
im2 = Image.open("im2.png")
blended = Image.blend(im1, im2, alpha=0.5)
blended.save("blended.png")

Had a similar question and had difficulty finding an answer.有一个类似的问题,很难找到答案。 The following function allows you to paste an image with a transparency parameter over another image at a specific offset.以下函数允许您将具有透明度参数的图像粘贴到另一个图像上的特定偏移量。

import Image

def trans_paste(fg_img,bg_img,alpha=1.0,box=(0,0)):
    fg_img_trans = Image.new("RGBA",fg_img.size)
    fg_img_trans = Image.blend(fg_img_trans,fg_img,alpha)
    bg_img.paste(fg_img_trans,box,fg_img_trans)
    return bg_img

bg_img = Image.open("bg.png")
fg_img = Image.open("fg.png")
p = trans_paste(fg_img,bg_img,.7,(250,100))
p.show()
def trans_paste(bg_img,fg_img,box=(0,0)):
    fg_img_trans = Image.new("RGBA",bg_img.size)
    fg_img_trans.paste(fg_img,box,mask=fg_img)
    new_img = Image.alpha_composite(bg_img,fg_img_trans)
    return new_img

I ended up coding myself the suggestion of this comment made by the user @P.Melch and suggested by @Mithril on a project I'm working on.我最终对用户@P.Melch 提出的这条评论的建议进行了编码,并由@Mithril 在我正在从事的一个项目中提出建议。

I coded out of bounds safety as well, here's the code for it .我也对越界安全进行了编码,这是它的代码 (I linked a specific commit because things can change in the future of this repository) (我链接了一个特定的提交,因为这个存储库的未来可能会发生变化)

Note: I expect numpy arrays from the images like so np.array(Image.open(...)) as the inputs A and B from copy_from and this linked function overlay arguments.注意:我希望像np.array(Image.open(...))这样的图像中的 numpy 数组作为copy_from的输入 A 和 B 以及此链接函数overlay参数。

The dependencies are the function right before it, the copy_from method, and numpy arrays as the PIL Image content for slicing.依赖项是它之前的函数、 copy_from方法和 numpy 数组作为用于切片的 PIL Image 内容。

Though the file is very class oriented, if you want to use that function overlay_transparent , be sure to rename the self.frame to your background image numpy array.尽管该文件非常面向类,但如果您想使用该函数overlay_transparent ,请务必将self.frame重命名为您的背景图像 numpy 数组。

Or you can just copy the whole file (probably remove some imports and the Utils class) and interact with this Frame class like so:或者你可以复制整个文件(可能会删除一些导入和Utils类)并与这个 Frame 类交互,如下所示:

# Assuming you named the file frame.py in the same directory
from frame import Frame

background = Frame()
overlay = Frame()

background.load_from_path("your path here")
overlay.load_from_path("your path here")

background.overlay_transparent(overlay.frame, x=300, y=200)

Then you have your background.frame as the overlayed and alpha composited array, you can get a PIL image from it with overlayed = Image.fromarray(background.frame) or something like:然后你有你的background.frame作为覆盖和 alpha 合成数组,你可以从它使用overlayed = Image.fromarray(background.frame)或类似的东西获取 PIL 图像:

overlayed = Frame()
overlayed.load_from_array(background.frame)

Or just background.save("save path") as that takes directly from the alpha composited internal self.frame variable.或者只是background.save("save path")因为它直接从 alpha 合成的内部self.frame变量中获取。

You can read the file and find some other nice functions with this implementation I coded like the methods get_rgb_frame_array , resize_by_ratio , resize_to_resolution , rotate , gaussian_blur , transparency , vignetting :)您可以读取该文件,并找到其它的一些功能,这个实现我喜欢编码方法get_rgb_frame_arrayresize_by_ratioresize_to_resolutionrotategaussian_blurtransparencyvignetting :)

You'd probably want to remove the resolve_pending method as that is specific for that project.您可能希望删除resolve_pending方法,因为它特定于该项目。

Glad if I helped you, be sure to check out the repo of the project I'm talking about, this question and thread helped me a lot on the development :)很高兴如果我帮助了你,一定要查看我正在谈论的项目的 repo,这个问题和线程对我的开发帮助很大:)

the key code is:关键代码是:

_, _, _, alpha = image_element_copy.split()
image_bg_copy.paste(image_element_copy, box=(x0, y0, x1, y1), mask=alpha)

the full function is:完整的功能是:

def paste_image(image_bg, image_element, cx, cy, w, h, rotate=0, h_flip=False):
    image_bg_copy = image_bg.copy()
    image_element_copy = image_element.copy()

    image_element_copy = image_element_copy.resize(size=(w, h))
    if h_flip:
        image_element_copy = image_element_copy.transpose(Image.FLIP_LEFT_RIGHT)
    image_element_copy = image_element_copy.rotate(rotate, expand=True)
    _, _, _, alpha = image_element_copy.split()
    # image_element_copy's width and height will change after rotation
    w = image_element_copy.width
    h = image_element_copy.height
    x0 = cx - w // 2
    y0 = cy - h // 2
    x1 = x0 + w
    y1 = y0 + h
    image_bg_copy.paste(image_element_copy, box=(x0, y0, x1, y1), mask=alpha)
    return image_bg_copy

the above function supports:上述功能支持:

  • position(cx, cy)位置(cx,cy)
  • auto resize image_element to (w, h)自动将 image_element 调整为 (w, h)
  • rotate image_element without cropping it旋转 image_element 而不裁剪它
  • horizontal flip水平翻转

Here is my code to merge 2 images of different sizes, each with transparency and with offset:这是我的代码,用于合并 2 个不同大小的图像,每个图像都具有透明度和偏移量:

from PIL import Image

background = Image.open('image1.png')
foreground = Image.open("image2.png")

x = background.size[0]//2
y = background.size[1]//2

background = Image.alpha_composite(
    Image.new("RGBA", background.size),
    background.convert('RGBA')
)

background.paste(
    foreground,
    (x, y),
    foreground
)

background.show()

This snippet is a mix of the previous answers, blending elements with offset while handling images with different sizes, each with transparency.这个片段是先前答案的混合,在处理具有不同大小的图像时将元素与偏移混合在一起,每个图像都具有透明度。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM