Python+OpenCV怎么实现多张png透明图像叠加在jpg图像上??

Python+OpenCV怎么实现多张png透明图像叠加在jpg图像上?? 就和这张图片一样 多张png叠加在jpg图片上

img

import cv2
import numpy as np
def gen_png_to_jpg(png_path,jpg_path,png_size=(),jpg_size=(),png_in_jpg_p=(0,0),out_path="",show=True):
    png_image = cv2.imread(png_path, cv2.IMREAD_UNCHANGED)
    jpg_image = cv2.imread(jpg_path, cv2.IMREAD_UNCHANGED)
    if jpg_size:
        jpg_image=cv2.resize(jpg_image,jpg_size)
    a_mask = png_image[:, :, -1]
    x, y = np.where(a_mask == 255)
    x_min = min(x)
    x_max = max(x)
    y_min = min(y)
    y_max = max(y)
    # 裁剪到最小
    new_png = png_image[x_min:x_max, y_min:y_max, :3].copy()
    new_mask = png_image[x_min:x_max, y_min:y_max, -1:].copy()
    if png_size:
        new_png=cv2.resize(new_png, png_size)
        new_mask=cv2.resize(new_mask,png_size)
        new_mask=new_mask.reshape(new_mask.shape[0],new_mask.shape[1],1)
    re_mask = (~new_mask == 255)
    if png_in_jpg_p[0]+re_mask.shape[1]<jpg_image.shape[1] or png_in_jpg_p[1]+re_mask.shape[0]<jpg_image.shape[0]:


        jpg_image[png_in_jpg_p[1]:re_mask.shape[0]+png_in_jpg_p[1], png_in_jpg_p[0]:re_mask.shape[1]+png_in_jpg_p[0], :] *= re_mask
        jpg_image[png_in_jpg_p[1]:re_mask.shape[0]+png_in_jpg_p[1], png_in_jpg_p[0]:re_mask.shape[1]+png_in_jpg_p[0], :] += new_png
        if out_path:
            cv2.imwrite(out_path,jpg_image)
        if show:
            cv2.imshow("",jpg_image )
            cv2.waitKey()

def gen_png_to_jpg_p(png_path,jpg_path,png_size=(),jpg_size=(),png_in_jpg_p=(0,0),out_path="",show=True):
    png_image = cv2.imread(png_path, cv2.IMREAD_UNCHANGED)
    if type(jpg_path)==type(""):
        jpg_image = cv2.imread(jpg_path, cv2.IMREAD_UNCHANGED)
    else:
        jpg_image=jpg_path
    if jpg_size:
        jpg_image=cv2.resize(jpg_image,jpg_size)
    a_mask = png_image[:, :, -1]
    x, y = np.where(a_mask == 255)
    x_min = min(x)
    x_max = max(x)
    y_min = min(y)
    y_max = max(y)
    # 裁剪到最小
    new_png = png_image[x_min:x_max, y_min:y_max, :3].copy()
    new_mask = png_image[x_min:x_max, y_min:y_max, -1:].copy()
    if png_size:
        new_png=cv2.resize(new_png, png_size)
        new_mask=cv2.resize(new_mask,png_size)
        new_mask=new_mask.reshape(new_mask.shape[0],new_mask.shape[1],1)
    re_mask = (~new_mask == 255)
    if png_in_jpg_p[0]+re_mask.shape[1]<jpg_image.shape[1] or png_in_jpg_p[1]+re_mask.shape[0]<jpg_image.shape[0]:


        jpg_image[png_in_jpg_p[1]:re_mask.shape[0]+png_in_jpg_p[1], png_in_jpg_p[0]:re_mask.shape[1]+png_in_jpg_p[0], :] *= re_mask
        jpg_image[png_in_jpg_p[1]:re_mask.shape[0]+png_in_jpg_p[1], png_in_jpg_p[0]:re_mask.shape[1]+png_in_jpg_p[0], :] += new_png
        if out_path:
            cv2.imwrite(out_path,jpg_image)
        if show:
            cv2.imshow("",jpg_image )
            cv2.waitKey()
    return jpg_image
def gen_pngs_to_jpg(jpg_path,png_path_list,png_size_list=None,jpg_size=(),png_in_jpg_p_list=None,out_path="",show=True):

    for i,png_path in enumerate(png_path_list):
        jpg_path=gen_png_to_jpg_p(png_path=png_path,jpg_path=jpg_path,jpg_size=jpg_size,png_size=png_size_list[i], png_in_jpg_p=png_in_jpg_p_list[i],out_path="",show=False)
        if show:
            cv2.imshow("",jpg_path)
            cv2.waitKeyEx()
    if out_path:
        cv2.imwrite(out_path,jpg_path)




if __name__ == '__main__':
    # gen_png_to_jpg("457788647446175.png","837709647446145.jpg",png_in_jpg_p=(1,50))
    gen_pngs_to_jpg("837709647446145.jpg",png_path_list=["457788647446175.png","457788647446175.png"],jpg_size=(),png_size_list=[(100,50),(100,50)],png_in_jpg_p_list=[(1,50),(103,50)])

img


废话不多说,直接上代码


import cv2


def cv_show(neme, img):
    cv2.imshow(neme, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


def Set_up_the(path, x, y):
    """
    图像路径,
    想放置的背景图的位置,左上角坐标
    :return:
    """
    image1 = cv2.imread(path)
    im1 = image1 == 0
    # 设置"图像1"放置在"背景图"中的位置:
    # 设置x y偏移多少
    _x, _y = x, y
    # 设置的参数:左上角、右下角坐标 x1 y1 x2 y2
    x1, y1, x2, y2 = 0 + _x, 0 + _y, image1.shape[1] + _x, image1.shape[0] + _y
    return x1, y1, x2, y2, im1, image1


def add(image1, image3, im, x1, y1, x2, y2):
    # 掩膜
    image1_ = image3[int(y1):int(y2), int(x1):int(x2)] * im
    # 图像相加
    image1_1 = cv2.add(image1_, image1)
    # 赋给原图
    image3[int(y1):int(y2), int(x1):int(x2)] = image1_1
    return image3


# 图像1
x1, y1, x2, y2, im1, image1 = Set_up_the("1.png", 100, 100)
# 图像2
x10, y10, x20, y20, im10, image2 = Set_up_the("2.png", 500, 100)

# 背景图
image3 = cv2.imread("3.jpg")

img = add(image1, image3, im1, x1, y1, x2, y2)
cv_show('neme', img)
img = add(image2, img, im10, x10, y10, x20, y20)
cv_show('neme', img)


img

img

img

你试一下这一版:

import cv2
import numpy as np
 
def add_alpha_channel(img):
    """ 为jpg图像添加alpha通道 """
 
    b_channel, g_channel, r_channel = cv2.split(img) # 剥离jpg图像通道
    alpha_channel = np.ones(b_channel.shape, dtype=b_channel.dtype) * 255 # 创建Alpha通道
 
    img_new = cv2.merge((b_channel, g_channel, r_channel, alpha_channel)) # 融合通道
    return img_new
 
def merge_img(jpg_img, png_img, png2_img,y1, y2, x1, x2, y3, y4, x3, x4):
    """ 将png透明图像与jpg图像叠加 
        y1,y2,x1,x2为叠加位置坐标值
    """
    
    # 判断jpg图像是否已经为4通道
    if jpg_img.shape[2] == 3:
        jpg_img = add_alpha_channel(jpg_img)
    
    '''
    当叠加图像时,可能因为叠加位置设置不当,导致png图像的边界超过背景jpg图像,而程序报错
    这里设定一系列叠加位置的限制,可以满足png图像超出jpg图像范围时,依然可以正常叠加
    '''
    yy1 = 0
    yy2 = png_img.shape[0]
    xx1 = 0
    xx2 = png_img.shape[1]
 
    if x1 < 0:
        xx1 = -x1
        x1 = 0
    if y1 < 0:
        yy1 = - y1
        y1 = 0
    if x2 > jpg_img.shape[1]:
        xx2 = png_img.shape[1] - (x2 - jpg_img.shape[1])
        x2 = jpg_img.shape[1]
    if y2 > jpg_img.shape[0]:
        yy2 = png_img.shape[0] - (y2 - jpg_img.shape[0])
        y2 = jpg_img.shape[0]
 
    # 获取要覆盖图像的alpha值,将像素值除以255,使值保持在0-1之间
    alpha_png = png_img[yy1:yy2,xx1:xx2,3] / 255.0
    alpha_jpg = 1 - alpha_png
    
    png2_yy1 = 0
    png2_yy2 = png_img.shape[0]
    png2_xx1 = 0
    png2_xx2 = png_img.shape[1]
 
    if x3 < 0:
        png2_xx1 = -x3
        x3 = 0
    if y3 < 0:
        png2_yy1 = - y3
        y3 = 0
    if x4 > jpg_img.shape[1]:
        png2_xx2 = png_img.shape[1] - (x4 - jpg_img.shape[1])
        x4 = jpg_img.shape[1]
    if y4 > jpg_img.shape[0]:
        png2_yy2 = png_img.shape[0] - (y4 - jpg_img.shape[0])
        y4 = jpg_img.shape[0]
 
    # 获取要覆盖图像的alpha值,将像素值除以255,使值保持在0-1之间
    png2_alpha_png = png2_img[png2_yy1:png2_yy2,png2_xx1:png2_xx2,3] / 255.0
    png2_alpha_jpg = 1 - png2_alpha_png
    
    # 开始叠加
    for c in range(0,3):
        jpg1_img[y1:y2, x1:x2, c] = ((alpha_jpg*jpg_img[y1:y2,x1:x2,c]) + (alpha_png*png_img[yy1:yy2,xx1:xx2,c]))
        jpg_img[y3:y4, x3:x4, c] = ((png2_alpha_jpg*jpg1_img[y1:y2,x1:x2,c]) + (png2_alpha_png*png2_img[yy1:yy2,xx1:xx2,c]))
    return jpg_img
    
if __name__ == '__main__':
    # 定义图像路径
    img_jpg_path = '3.jpg' # 读者可自行修改文件路径
    img_png_path = '1.png' # 读者可自行修改文件路径
    img2_png_path = '2.png'
    # 读取图像
    img_jpg = cv2.imread(img_jpg_path, cv2.IMREAD_UNCHANGED)
    img_png = cv2.imread(img_png_path, cv2.IMREAD_UNCHANGED)
    img2_png = cv2.imread(img2_png_path, cv2.IMREAD_UNCHANGED)
    # 设置叠加位置坐标
    #图一
    x1 = 560
    y1 = 180
    x2 = x1 + img_png.shape[1]
    y2 = y1 + img_png.shape[0]
    #图二
    x3 = 100
    y3 = 100
    x4 = x3 + img2_png.shape[1]
    y4 = y3 + img2_png.shape[0]
    # 开始叠加
    res_img = merge_img(jpg_img, png_img, png2_img,y1, y2, x1, x2,y3, y4, x3, x4)
    
    # 显示结果图像
    cv2.imshow('result', res_img)
 
    # 保存结果图像,读者可自行修改文件路径
    cv2.imwrite('imgs/res.jpg', res_img)
 
    # 定义程序退出方式:鼠标点击显示图像的窗口后,按ESC键即可退出程序
    if cv2.waitKey(0) & 0xFF == 27:
        cv2.destroyAllWindows()

若是没什么问题请点击采纳

可以结合之前用PS修图时的多层图叠加,就是多图层叠加顺序,然后去实现叠加功能。

图片合并,这里面涉及到图层的设计排版

上面的代码好像没有一个可以跑通的。。。

import cv2
import numpy as np
 
def add_alpha_channel(img):
    """ 为jpg图像添加alpha通道 """
 
    b_channel, g_channel, r_channel = cv2.split(img) # 剥离jpg图像通道
    alpha_channel = np.ones(b_channel.shape, dtype=b_channel.dtype) * 255 # 创建Alpha通道
 
    img_new = cv2.merge((b_channel, g_channel, r_channel, alpha_channel)) # 融合通道
    return img_new
 
def merge_img(jpg_img, png_img, y1, y2, x1, x2):
    """ 将png透明图像与jpg图像叠加 
        y1,y2,x1,x2为叠加位置坐标值
    """
    
    # 判断jpg图像是否已经为4通道
    if jpg_img.shape[2] == 3:
        jpg_img = add_alpha_channel(jpg_img)
    
    '''
    当叠加图像时,可能因为叠加位置设置不当,导致png图像的边界超过背景jpg图像,而程序报错
    这里设定一系列叠加位置的限制,可以满足png图像超出jpg图像范围时,依然可以正常叠加
    '''
    yy1 = 0
    yy2 = png_img.shape[0]
    xx1 = 0
    xx2 = png_img.shape[1]
 
    if x1 < 0:
        xx1 = -x1
        x1 = 0
    if y1 < 0:
        yy1 = - y1
        y1 = 0
    if x2 > jpg_img.shape[1]:
        xx2 = png_img.shape[1] - (x2 - jpg_img.shape[1])
        x2 = jpg_img.shape[1]
    if y2 > jpg_img.shape[0]:
        yy2 = png_img.shape[0] - (y2 - jpg_img.shape[0])
        y2 = jpg_img.shape[0]
 
    # 获取要覆盖图像的alpha值,将像素值除以255,使值保持在0-1之间
    alpha_png = png_img[yy1:yy2,xx1:xx2,3] / 255.0
    alpha_jpg = 1 - alpha_png
    
    # 开始叠加
    for c in range(0,3):
        jpg_img[y1:y2, x1:x2, c] = ((alpha_jpg*jpg_img[y1:y2,x1:x2,c]) + (alpha_png*png_img[yy1:yy2,xx1:xx2,c]))
 
    return jpg_img
 
if __name__ == '__main__':
    # 定义图像路径
    img_jpg_path = 'imgs/0.jpg' # 读者可自行修改文件路径
    img_png_path = 'imgs/0.png' # 读者可自行修改文件路径
 
    # 读取图像
    img_jpg = cv2.imread(img_jpg_path, cv2.IMREAD_UNCHANGED)
    img_png = cv2.imread(img_png_path, cv2.IMREAD_UNCHANGED)
 
    # 设置叠加位置坐标
    x1 = 560
    y1 = 180
    x2 = x1 + img_png.shape[1]
    y2 = y1 + img_png.shape[0]
 
    # 开始叠加
    res_img = merge_img(img_jpg, img_png, y1, y2, x1, x2)
 
    # 显示结果图像
    cv2.imshow('result', res_img)
 
    # 保存结果图像,读者可自行修改文件路径
    cv2.imwrite('imgs/res.jpg', res_img)
 
    # 定义程序退出方式:鼠标点击显示图像的窗口后,按ESC键即可退出程序
    if cv2.waitKey(0) & 0xFF == 27:
        cv2.destroyAllWindows()

加一个for就行了


import cv2
import numpy as np
 
def add_alpha_channel(img):
    """ 为jpg图像添加alpha通道 """
 
    b_channel, g_channel, r_channel = cv2.split(img) # 剥离jpg图像通道
    alpha_channel = np.ones(b_channel.shape, dtype=b_channel.dtype) * 255 # 创建Alpha通道
 
    img_new = cv2.merge((b_channel, g_channel, r_channel, alpha_channel)) # 融合通道
    return img_new
 
def merge_img(jpg_img, png_img, y1, y2, x1, x2):
    """ 将png透明图像与jpg图像叠加 
        y1,y2,x1,x2为叠加位置坐标值
    """
    
    # 判断jpg图像是否已经为4通道
    if jpg_img.shape[2] == 3:
        jpg_img = add_alpha_channel(jpg_img)
    
    '''
    当叠加图像时,可能因为叠加位置设置不当,导致png图像的边界超过背景jpg图像,而程序报错
    这里设定一系列叠加位置的限制,可以满足png图像超出jpg图像范围时,依然可以正常叠加
    '''
    yy1 = 0
    yy2 = png_img.shape[0]
    xx1 = 0
    xx2 = png_img.shape[1]
 
    if x1 < 0:
        xx1 = -x1
        x1 = 0
    if y1 < 0:
        yy1 = - y1
        y1 = 0
    if x2 > jpg_img.shape[1]:
        xx2 = png_img.shape[1] - (x2 - jpg_img.shape[1])
        x2 = jpg_img.shape[1]
    if y2 > jpg_img.shape[0]:
        yy2 = png_img.shape[0] - (y2 - jpg_img.shape[0])
        y2 = jpg_img.shape[0]
 
    # 获取要覆盖图像的alpha值,将像素值除以255,使值保持在0-1之间
    alpha_png = png_img[yy1:yy2,xx1:xx2,3] / 255.0
    alpha_jpg = 1 - alpha_png
    
    # 开始叠加
    for c in range(0,3):
        jpg_img[y1:y2, x1:x2, c] = ((alpha_jpg*jpg_img[y1:y2,x1:x2,c]) + (alpha_png*png_img[yy1:yy2,xx1:xx2,c]))
 
    return jpg_img
 
if __name__ == '__main__':
    # 定义图像路径
    pnglist = ["xxx.png","xxx"]#这里填所有的png路径
    for i in pnglist:
        img_jpg_path = 'imgs/0.jpg' # 读者可自行修改文件路径
        img_png_path = i 
 
        # 读取图像
        img_jpg = cv2.imread(img_jpg_path, cv2.IMREAD_UNCHANGED)
        img_png = cv2.imread(img_png_path, cv2.IMREAD_UNCHANGED)
 
        # 设置叠加位置坐标
        x1 = 560
        y1 = 180
        x2 = x1 + img_png.shape[1]
        y2 = y1 + img_png.shape[0]
 
        # 开始叠加
        res_img = merge_img(img_jpg, img_png, y1, y2, x1, x2)
 
    # 显示结果图像
    cv2.imshow('result', res_img)
 
    # 保存结果图像,读者可自行修改文件路径
    cv2.imwrite('imgs/res.jpg', res_img)
 
    # 定义程序退出方式:鼠标点击显示图像的窗口后,按ESC键即可退出程序
    if cv2.waitKey(0) & 0xFF == 27:
        cv2.destroyAllWindows()
 

你是不是顺序错了?先粉的,后蓝的,最后是鞋

按顺序一张一张叠加就好,先是背景,再是最下层的,再一张一张往上叠加就可以实现多张png的透明叠加。

https://blog.csdn.net/weixin_40065609/article/details/114886234?spm=1005.2026.3001.5635&utm_medium=distribute.pc_relevant_ask_down.none-task-blog-2~default~OPENSEARCH~Rate-4.pc_feed_download_top3ask&depth_1-utm_source=distribute.pc_relevant_ask_down.none-task-blog-2~default~OPENSEARCH~Rate-4.pc_feed_download_top3ask


 
import cv2
 
 
def cv_show(neme, img):
    cv2.imshow(neme, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
 
 
def Set_up_the(path, x, y):
    """
    图像路径,
    想放置的背景图的位置,左上角坐标
    :return:
    """
    image1 = cv2.imread(path)
    im1 = image1 == 0
    # 设置"图像1"放置在"背景图"中的位置:
    # 设置x y偏移多少
    _x, _y = x, y
    # 设置的参数:左上角、右下角坐标 x1 y1 x2 y2
    x1, y1, x2, y2 = 0 + _x, 0 + _y, image1.shape[1] + _x, image1.shape[0] + _y
    return x1, y1, x2, y2, im1, image1
 
 
def add(image1, image3, im, x1, y1, x2, y2):
    # 掩膜
    image1_ = image3[int(y1):int(y2), int(x1):int(x2)] * im
    # 图像相加
    image1_1 = cv2.add(image1_, image1)
    # 赋给原图
    image3[int(y1):int(y2), int(x1):int(x2)] = image1_1
    return image3
 
 
# 图像1
x1, y1, x2, y2, im1, image1 = Set_up_the("1.png", 100, 100)
# 图像2
x10, y10, x20, y20, im10, image2 = Set_up_the("2.png", 500, 100)
 
# 背景图
image3 = cv2.imread("3.jpg")
 
img = add(image1, image3, im1, x1, y1, x2, y2)
cv_show('neme', img)
img = add(image2, img, im10, x10, y10, x20, y20)
cv_show('neme', img)
 
 

排一下图层顺序