Python调用PIL实现图片合成(含证件照换背景)

问题描述

Python调用PIL实现图片合成,一张背景图,一张抠好的前景图

本文代码及示例图下载




解决方案

安装

python install Pillow

调用 PIL.Image.paste

函数原型: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')

效果
在这里插入图片描述




参考文献

  1. Pillow (PIL) 文档
  2. remove.bg – 消除图片中的背景
  3. 图鱼
  4. 摄图网
  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XerCis

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值