图片合成方法 - paste/seamlessclone/或运算/传统方法

1 总叙

  本文主要介绍将两张图片合成为一张图片的方法,包括:将一张图片粘贴至另一张图片的paste()函数、将指定目标与背景融合的seamlessClone()函数和通过位运算合成两张 mask 图的bitewise系列函数。

2. paste() 函数

  PIL库中的paste()函数的作用是将一张前景图片覆盖到另一张背景图片的指定位置上。函数的声明为

def paste (self, img, box=None, mask=None)

其中:参数 img 表示背景图片,参数 box 是坐标,参数 mask 表示前景图片的蒙版。如是具有透明度的前景图像,则 alpha 通道将用作遮罩。前景图片要求是带有 mask 的 png 图片,背景图片则不做要求。如是 jpg 图片,转为 png 格式即可。废话不多说,下面上代码

# _*_coding:utf-8_*_
from PIL import Image


def myPaste(fgr_path, bgd_path, save_path):
    # 前景 (png)
    fgr = Image.open(fgr_path)
    # 前景
    bgd = Image.open(bgd_path)
    bgd = bgd.convert('RGBA')  # 转为 png
    # bgd = Image.new("RGBA", (3840, 2160), (155, 255, 120))  # 绿幕背景
    # bgd = Image.new("RGBA", (3840, 2160))  # 透明背景
    # 粘贴
    (a1, a2) = fgr.size
    (b1, b2) = bgd.size
    dot = ((b1 - a1) // 2, (b2 - a2) // 2)  # 左上角坐标
    bgd.paste(fgr, dot, fgr)
    bgd.save(save_path)

    return bgd


if __name__ == "__main__":
    fgr_path = r"vehicle.png"
    bgd_path = r"bgd.jpg"
    save_path = r"out.png"
    out = myPaste(fgr_path, bgd_path, save_path)
    out.show()

效果如下

背景图前景图
合成图片背景合成绿幕背景

3. seamlessClone() 函数

  泊松融合是图像处理领域著名的图像融合算法,seamlessClone()函数是OpenCV中泊松融合的实现方法。函数的声明为

def seamlessClone (src, dst, mask, p, blend, flags )

其中:src 是源图像,dst 是目标图像,mask 是遮罩,p 是融合位置中心点坐标,blend 是融合结果,flags 是融合类别(有 NORMAL_CLONE、MIXED_CLONE 和 MONOCHROME_TRANSFER三类)。废话说完了,开始上代码

# _*_coding:utf-8_*_
import cv2
import numpy as np


def mySeamlessClone(fgr_path, bgd_path):
    obj = cv2.imread(fgr_path)
    im = cv2.imread(bgd_path)
    # 创建全白的 mask
    mask = 255 * np.ones(obj.shape, obj.dtype)
    # 背景图片的中心点
    width, height, channels = im.shape
    center = (height // 2, width // 2)
    # 三种不同的融合方式
    normal_clone = cv2.seamlessClone(obj, im, mask, center, cv2.NORMAL_CLONE)
    mixed_clone = cv2.seamlessClone(obj, im, mask, center, cv2.MIXED_CLONE)
    monochrome_clone = cv2.seamlessClone(obj, im, mask, center, cv2.MONOCHROME_TRANSFER)
    # 结果保存
    cv2.imwrite("normal-clone.jpg", normal_clone)
    cv2.imwrite("mixed-clone.jpg", mixed_clone)
    cv2.imwrite("monochrome-clone.jpg", monochrome_clone)


if __name__ == "__main__":
    fgr_path = r"love.jpg"
    bgd_path = r"wood.jpg"
    mySeamlessClone(fgr_path, bgd_path)

效果如下

背景图前景图
NormalMixedMonochrome
  仔细观察可知,mixed 模式下字体的背景细节被较好地保存,而 normal 和 monochrome 两种模式下字体的背景一片模糊。

4. bitwise_or() 或运算

  图像的位运算是指对图像的数值按照二进制值逐位进行取反、与、或、异或操作。比如按位取反就是将数值根据每个 bit 位 1 变0,0 变 1,比如 0xf0 按位取反就变成了 0x0f。如果是 uint8 类型的数据,取反前后的数据相加结果为 0xff(255)。图像的或运算主要用于获取两张图像加起来的部分。相关代码如下

# _*_coding:utf-8_*_
import cv2
import numpy as np
from PIL import Image


# 闭运算:先膨胀后腐蚀
def closed(img):
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
    img = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
    return img


# 图片调整
def img_convert(img, dot):
    tran_bgd = Image.new("RGBA", (1920, 1080))
    tran_bgd.paste(img, dot, img)
    return tran_bgd


def myPaste(fgr_path, bgd_path, com_save, pha_paste_path):
    # 电动车
    vehicle = Image.open(bgd_path)
    vehicle = vehicle.resize((554, 536), Image.ANTIALIAS)
    dot1 = (640, 180)
    bgd = img_convert(vehicle, dot1)
    pha_bgd = bgd.split()[-1]
    # 女孩
    girl = Image.open(fgr_path)
    girl = girl.resize((280, 800), Image.ANTIALIAS)
    dot2 = (950, 5)
    fgr = img_convert(girl, dot2)
    pha_fgr = fgr.split()[-1]
    # paste方法合成
    bgd.paste(fgr, (0, 0), fgr)
    bgd.save(com_save)
    bgd_green = Image.new("RGBA", (1920, 1080), (155, 255, 120))
    bgd_green.paste(bgd, (0, 0), bgd)
    bgd_green.save(com_save.replace('com', 'green'))
    pha_paste = bgd.split()[-1]
    pha_paste.save(pha_paste_path)
    # or方法合成
    e = np.array(pha_bgd)
    f = np.array(pha_fgr)
    pha_or = cv2.bitwise_or(e, f)
    cv2.imwrite(pha_paste_path.replace('paste', 'or'), pha_or)
    return


if __name__ == "__main__":
    fgr_path = r"girl.png"
    bgd_path = r"vehicle.png"
    com_save = r"com.png"
    pha_paste = r"pha_paste.jpg"
    out = myPaste(fgr_path, bgd_path, com_save, pha_paste)
    image = cv2.imread(com_save, -1)
    pha_com = cv2.split(image)[-1]
    pha_com = closed(pha_com)
    cv2.imwrite(pha_paste.replace('paste', 'close'), pha_com)

  以上代码主要比较了paste()bitwise_or()两种方法的不同。效果如下

电动车女舞者合成效果
Paste方法闭运算或运算
  单纯观察两种方法的合成效果并没有什么区别,但查看二种方法得到的 mask 就可以发现很明显的区别。Paste 方法就是将女舞者的 mask 贴到电动车的 mask 上,女舞者的黑色边缘依旧存在。此处的闭运算是对 paste 方法得到的结果进行后处理,可以看到女舞者的黑色被消除了,但合成的 mask 图边缘的细节明显丢失了。至于或运算得到的结果,完美到无需解释。

5. 传统方法

  至于传统方法,就是更改背景图片的像素值,涉及大量矩阵的处理。思路就是用前景的像素值覆盖背景中选定区域的像素值,方法太过繁琐低效。故而此处只记录这一解决思路,并不基于这一思路进行实现。

【参考】

  1. 关于python:如何使用PIL将透明png图像与另一个图像合并
  2. OpenCV源码解读:泊松融合seamlessClone(normalClone)
  3. opencv实现无缝融合–seamless clone
  4. opencv学习笔记(三):图像运算
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值