使用OpenCV将一个PNG图片叠加到另一个PNG图片上

我在网上找到过不少将一个png叠加到一个jpg图片上的教程(如相关代码所示),但是没找到如何将一个PNG图片叠加到另一个(没有任何颜色、完全透明,但是尺寸更大的)PNG图片上。我用将png叠加到jpg上的代码应用在png叠加到png上时,背景的png变成了黑色(如图所示),而我希望的结果是背景依旧是透明

请问如何实现将一个PNG叠加到另一个PNG上?

import cv2
import numpy as np
from PIL import Image

def overlay_image_alpha(img, img_overlay, x, y, alpha_mask):
    """Overlay `img_overlay` onto `img` at (x, y) and blend using `alpha_mask`.

    `alpha_mask` must have same HxW as `img_overlay` and values in range [0, 1].
    """
    # Image ranges
    y1, y2 = max(0, y), min(img.shape[0], y + img_overlay.shape[0])
    x1, x2 = max(0, x), min(img.shape[1], x + img_overlay.shape[1])

    # Overlay ranges
    y1o, y2o = max(0, -y), min(img_overlay.shape[0], img.shape[0] - y)
    x1o, x2o = max(0, -x), min(img_overlay.shape[1], img.shape[1] - x)

    # Exit if nothing to do
    if y1 >= y2 or x1 >= x2 or y1o >= y2o or x1o >= x2o:
        return

    # Blend overlay within the determined ranges
    img_crop = img[y1:y2, x1:x2]
    img_overlay_crop = img_overlay[y1o:y2o, x1o:x2o]
    alpha = alpha_mask[y1o:y2o, x1o:x2o, np.newaxis]
    alpha_inv = 1.0 - alpha

    img_crop[:] = alpha * img_overlay_crop + alpha_inv * img_crop


# Prepare inputs
x, y = 0, 0
img = np.array(Image.open("template.png"))
img_overlay_rgba = np.array(Image.open("../outimages/input.png"))

# Perform blending
alpha_mask = img_overlay_rgba[:, :, 3] / 255.0
img_result = img[:, :, :3].copy()
img_overlay = img_overlay_rgba[:, :, :3]
overlay_image_alpha(img_result, img_overlay, x, y, alpha_mask)

# Save result
Image.fromarray(img_result).save("img_result.png")

输入图片1:

img

输入图片2(纯透明):

img

结果:

img

参考;import cv2
import os
import random

def put_the_png_to_webcam(frame, num, img, step, right):
"""
Arguments:
frame: the webcam's one frame
num: the number to record the frequency of the frame
img: the png image to put.
step: distance to move each frame
right: the location for the image to put
Returns:
frame: the frames after processed
"""
h, w= img.shape[:2]
# method 1 使用位操作:
# 创建掩膜
imggray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(imggray, 10, 255, cv2.THRESH_BINARY)
mask_inv = cv2.bitwise_not(mask)

# 保留除png图像外的背景
roi = frame[num*step:h+num*step,right:right+w]
frame_bg = cv2.bitwise_and(roi, roi, mask=mask_inv)
img_fg = cv2.bitwise_and(img, img, mask=mask)

dst = cv2.add(frame_bg, img_fg)  # 进行融合
frame[num*step:h+num*step,right:right+w] = dst  # 融合后放在原图上
 
# method 2 使用带权重的图像融合:
# alpha = 0.5
# added_image = cv2.addWeighted(frame[num*step:h+num*step,right:right+w,:], alpha, img[0:h,0:w,:], 1-alpha, 0)
# frame[num*step:h+num*step,right:right+w,:] = added_image

return frame

if name == "main":
video = cv2.VideoCapture(0)
if not video.isOpened():
print("can't open the camera!")

png_dir = 'textures'  # png图像存放目录
num = 0 # 记录帧数,当达到一定帧数后消失
step = 8  # 每帧移动 8px
img_path = os.path.join(png_dir, "1.png")  # png图片的存储地址
img = cv2.imread(img_path)
right = 480
while True:
    _, frame = video.read()
    
    if num < 28:  # 28帧后图片消失
        # 调用函数,将png放在视频流中
        frame = put_the_png_to_webcam(frame, num, img, step, right)
    
    cv2.imshow("vedio", frame)
    if cv2.waitKey(1) == 27 :  # 按ESC键退出程序
        break
    num += 1

video.release()
cv2.destroyAllWindows() 

直接使用add

png背景为黑色,是因为你读入图片的时候,没有读入透明通道。
错误例子(黑色背景):
Image<Bgr, byte> src = new Image<Bgr, byte>(@“D://123.png”);
正确例子(透明背景):
Image<Bgra, byte> src = new Image<Bgra, byte>(@“D://123.png”);