[英]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.png
与foo2.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 通道将用作遮罩。
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_array
, resize_by_ratio
, resize_to_resolution
, rotate
, gaussian_blur
, transparency
, vignetting
:)
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:上述功能支持:
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.