问题描述
Python调用PIL实现图片合成,一张背景图,一张抠好的前景图
解决方案
安装
python install Pillow
函数原型:Image.paste(im, box=None, mask=None)
im
:源图像或像素值(整数或元组)。
box
:合成位置。取值 None,同(0, 0)。2元组,左上角坐标。4元组,左、上、右、下像素坐标,大小需匹配。
mask
:遮罩、掩膜图像,即透明区域的不合成。
尺寸一样
background.png
foreground.png
直接合成
from PIL import Image
background = Image.open('background.png') # 背景图
foreground = Image.open('foreground.png') # 前景图
background.paste(foreground, mask=foreground) # 以自身透明区域作为掩膜
background.show()
background.save('result.png') # 保存
效果
尺寸不一样
background1.png
background2.png
自动对比两图大小,等比调整尺寸
from PIL import Image
def match_size(background, foreground):
'''根据背景图调整前景图,根据面积等比调整'''
(width1, height1), (width2, height2) = background.size, foreground.size
if width1 >= width2 and height1 >= height2: # 背景图宽高均大于前景图
pass
else:
scale_width, scale_height = width2 / width1, height2 / height1 # 宽比和高比
width2, height2 = (width1, width1 / width2 * height2) if scale_width > scale_height else (
height1 / height2 * width2, height1)
size = (round(width2), round(height2))
foreground = foreground.resize(size) # 调整尺寸
return foreground
if __name__ == '__main__':
background1 = Image.open('background1.png') # 背景图1
foreground = Image.open('foreground.png') # 前景图
foreground = match_size(background1, foreground)
print(background1.size, foreground.size)
background1.paste(foreground, mask=foreground) # 以自身透明区域作为掩膜
background1.show()
background1.save('result1.png') # 保存
background2 = Image.open('background2.png') # 背景图2
foreground = Image.open('foreground.png') # 前景图
foreground = match_size(background2, foreground)
print(background2.size, foreground.size)
background2.paste(foreground, mask=foreground) # 以自身透明区域作为掩膜
background2.show()
background2.save('result2.png') # 保存
效果
result1.png
result2.png
指定区域
box
:合成位置。
- 取值 None,同(0, 0)
- 2元组,左上角坐标
- 4元组,左、上、右、下像素坐标,大小需匹配
background3.png
当 背景图大小 > 前景图:
合成位置 | box | 效果 |
---|---|---|
任意 | (x, y) | ![]() |
左上角 | (0, 0) | ![]() |
右上角 | (背景图宽 - 前景图宽, 0) | ![]() |
左下角 | (0, 背景高度 - 前景高度) | ![]() |
右下角 | (背景图宽 - 前景图宽, 背景高度 - 前景高度) | ![]() |
居中 | ( 背景图宽 − 前景图宽 2 , 背景图高 − 前景图高 2 ) \left( \frac{\text{背景图宽}-\text{前景图宽}}{2},\ \frac{\text{背景图高}-\text{前景图高}}{2} \right) (2背景图宽−前景图宽, 2背景图高−前景图高) | ![]() |
from PIL import Image
from PIL import ImageDraw
background = Image.open('background3.png') # 背景图
foreground = Image.open('foreground.png') # 前景图,宽高均小于背景图
w_b, h_b = background.size # 背景图的宽高
w_f, h_f = foreground.size # 前景图的宽高
# 随意
random = background.copy()
draw = ImageDraw.ImageDraw(random)
draw.ellipse((100, 100, 110, 110), 'red') # 画点,半径10
random.paste(foreground, box=(100, 100), mask=foreground) # 合成的左上角坐标为(100, 100)
random.show()
random.save('random.png')
# 左上角
topleft = background.copy()
draw = ImageDraw.ImageDraw(topleft)
draw.ellipse((0, 0, 10, 10), 'red')
topleft.paste(foreground, mask=foreground) # box默认为None或传(0, 0)为左上角
topleft.show()
topleft.save('topleft.png')
# 右上角
topright = background.copy()
draw = ImageDraw.ImageDraw(topright)
draw.ellipse((w_b - w_f, 0, w_b - w_f + 10, 10), 'red')
topright.paste(foreground, box=(w_b - w_f, 0), mask=foreground)
topright.show()
topright.save('topright.png')
# 左下角
bottomleft = background.copy()
draw = ImageDraw.ImageDraw(bottomleft)
draw.ellipse((0, h_b - h_f, 10, h_b - h_f + 10), 'red')
bottomleft.paste(foreground, box=(0, h_b - h_f), mask=foreground)
bottomleft.show()
bottomleft.save('bottomleft.png')
# 右下角
bottomright = background.copy()
draw = ImageDraw.ImageDraw(bottomright)
draw.ellipse((w_b - w_f, h_b - h_f, w_b - w_f + 10, h_b - h_f + 10), 'red')
bottomright.paste(foreground, box=(w_b - w_f, h_b - h_f), mask=foreground)
bottomright.show()
bottomright.save('bottomright.png')
# 居中
center = background.copy()
draw = ImageDraw.ImageDraw(center)
draw.ellipse((round((w_b - w_f) / 2), round((h_b - h_f) / 2), round((w_b - w_f) / 2) + 10, round((h_b - h_f) / 2) + 10),
'red')
center.paste(foreground, box=(round((w_b - w_f) / 2), round((h_b - h_f) / 2)), mask=foreground)
center.show()
center.save('center.png')
纯色背景
用于证件照合成
颜色 | RGB | 示例 |
---|---|---|
蓝色 | 67, 142, 219 | ![]() |
白色 | 255, 255, 255 | ![]() |
红色 | 255, 0, 0 | ![]() |
from PIL import Image
color = {
'red': (255, 0, 0, 255),
'blue': (67, 142, 219, 255),
'white': (255, 255, 255, 255)
}
foreground = Image.open('foreground.png') # 前景图
background = Image.new('RGBA', foreground.size, color['white']) # 背景图,大小同前景图
background.paste(foreground, mask=foreground)
background.show()
background.save('result.png')
效果
证件照合成
抠图使用 remove.bg
pip install removebg
在官网注册后申请 API 密钥,每个月可以调用50次
photo.png
from PIL import Image
from removebg import RemoveBg
BACKGROUND_COLOR = {
'RED': (255, 0, 0, 255),
'BLUE': (67, 142, 219, 255),
'WHITE': (255, 255, 255, 255)
}
rmbg = RemoveBg('YOUR-API-KEY', 'error.log')
rmbg.remove_background_from_img_file('photo.png') # 抠图
foreground = Image.open('photo.png_no_bg.png') # 前景图
background = Image.new('RGBA', foreground.size, BACKGROUND_COLOR['BLUE']) # 背景图,大小同前景图
background.paste(foreground, mask=foreground)
background.show()
background.save('photo_result.png')
效果