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
Python调用PIL实现图片合成(含证件照换背景)_第1张图片
foreground.png
Python调用PIL实现图片合成(含证件照换背景)_第2张图片

直接合成

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')  # 保存

效果
Python调用PIL实现图片合成(含证件照换背景)_第3张图片




尺寸不一样

background1.png
Python调用PIL实现图片合成(含证件照换背景)_第4张图片
background2.png
Python调用PIL实现图片合成(含证件照换背景)_第5张图片

自动对比两图大小,等比调整尺寸

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
Python调用PIL实现图片合成(含证件照换背景)_第6张图片
result2.png
Python调用PIL实现图片合成(含证件照换背景)_第7张图片




指定区域

box:合成位置。

  • 取值 None,同(0, 0)
  • 2元组,左上角坐标
  • 4元组,左、上、右、下像素坐标,大小需匹配

background3.png
Python调用PIL实现图片合成(含证件照换背景)_第8张图片

当 背景图大小 > 前景图:

合成位置 box 效果
任意 (x, y) Python调用PIL实现图片合成(含证件照换背景)_第9张图片
左上角 (0, 0) Python调用PIL实现图片合成(含证件照换背景)_第10张图片
右上角 (背景图宽 - 前景图宽, 0) Python调用PIL实现图片合成(含证件照换背景)_第11张图片
左下角 (0, 背景高度 - 前景高度) Python调用PIL实现图片合成(含证件照换背景)_第12张图片
右下角 (背景图宽 - 前景图宽, 背景高度 - 前景高度) Python调用PIL实现图片合成(含证件照换背景)_第13张图片
居中 ( 背景图宽 − 前景图宽 2 ,   背景图高 − 前景图高 2 ) \left( \frac{\text{背景图宽}-\text{前景图宽}}{2},\ \frac{\text{背景图高}-\text{前景图高}}{2} \right) (2背景图宽前景图宽, 2背景图高前景图高) Python调用PIL实现图片合成(含证件照换背景)_第14张图片
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 Python调用PIL实现图片合成(含证件照换背景)_第15张图片
白色 255, 255, 255 Python调用PIL实现图片合成(含证件照换背景)_第16张图片
红色 255, 0, 0 Python调用PIL实现图片合成(含证件照换背景)_第17张图片
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')

效果
Python调用PIL实现图片合成(含证件照换背景)_第18张图片




证件照合成

抠图使用 remove.bg

pip install removebg

在官网注册后申请 API 密钥,每个月可以调用50次

Python调用PIL实现图片合成(含证件照换背景)_第19张图片
photo.png
Python调用PIL实现图片合成(含证件照换背景)_第20张图片

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')

效果
Python调用PIL实现图片合成(含证件照换背景)_第21张图片




参考文献

  1. Pillow (PIL) 文档
  2. remove.bg – 消除图片中的背景
  3. 图鱼
  4. 摄图网

你可能感兴趣的:(Python,PIL,python,计算机视觉,pil)