简体   繁体   English

如何在 opencv 中合并一张 RGBA 和一张 RGB 图像

[英]How to merge one RGBA and one RGB images in opencv

I have two images.我有两张图片。 In one image, the white pixels are set to be transparent (or colorless) by editing the channel A in RGBA image format.在一幅图像中,通过以RGBA图像格式编辑通道A ,将白色像素设置为透明(或无色)。 Suppose this image name is image_rgba.png and the other image is image.jpg .假设这个图像名称是image_rgba.png而另一个图像是image.jpg Now, I want to put the image_rgba.png image in a specific location of the image.jpg using the following python code现在,我想使用以下 python 代码将image_rgba.png图像放在image.jpg的特定位置

import cv2
import numpy as np
import matplotlib.pyplot as plt

image = cv2.imread('image.jpg')
label = cv2.imread('image_rgba.png')
label = cv2.cvtColor(label, cv2.COLOR_BGR2RGBA)

new_image = image.copy()
new_image = cv2.cvtColor(new_image, cv2.COLOR_BGR2RGBA)

new_image[200:290, 300:384, :] = label

When I write this image, the edges of the image_rgba.png which is colorless, are set to be white in the output image (the white edges of the green box in the following image).当我写这个图像时,无色的image_rgba.png的边缘在 output 图像中设置为白色(下图中绿色框的白色边缘)。

在此处输入图像描述

I want the white edges of the green box label does not to show and instead the background image shown in that pixels.我希望绿色框 label 的白色边缘不显示,而是显示在该像素中的背景图像。 I found the similar question but it does not help me to solve my problem.我发现了类似的问题,但它并不能帮助我解决我的问题。 I would be appreciated it if anybody can help me.如果有人可以帮助我,我将不胜感激。

Here's how you can do it.这是你如何做到的。 I'm not an OpenCV expert, so there might be simpler approaches.我不是 OpenCV 专家,所以可能有更简单的方法。 Comments in the code explain what it does.代码中的注释解释了它的作用。 The overall idea is:总体思路是:

  1. Extract the alpha channel from the PNG从 PNG 中提取 alpha 通道
  2. Extract a piece of the background with the same size提取一块相同大小的背景
  3. Alpha blend these阿尔法混合这些
  4. Put the result back into the background将结果放回后台
import cv2

def alphaMerge(small_foreground, background, top, left):
    """
    Puts a small BGRA picture in front of a larger BGR background.
    :param small_foreground: The overlay image. Must have 4 channels.
    :param background: The background. Must have 3 channels.
    :param top: Y position where to put the overlay.
    :param left: X position where to put the overlay.
    :return: a copy of the background with the overlay added.
    """
    result = background.copy()
    # From everything I read so far, it seems we need the alpha channel separately
    # so let's split the overlay image into its individual channels
    fg_b, fg_g, fg_r, fg_a = cv2.split(small_foreground)
    # Make the range 0...1 instead of 0...255
    fg_a = fg_a / 255.0
    # Multiply the RGB channels with the alpha channel
    label_rgb = cv2.merge([fg_b * fg_a, fg_g * fg_a, fg_r * fg_a])

    # Work on a part of the background only
    height, width = small_foreground.shape[0], small_foreground.shape[1]
    part_of_bg = result[top:top + height, left:left + width, :]
    # Same procedure as before: split the individual channels
    bg_b, bg_g, bg_r = cv2.split(part_of_bg)
    # Merge them back with opposite of the alpha channel
    part_of_bg = cv2.merge([bg_b * (1 - fg_a), bg_g * (1 - fg_a), bg_r * (1 - fg_a)])

    # Add the label and the part of the background
    cv2.add(label_rgb, part_of_bg, part_of_bg)
    # Replace a part of the background
    result[top:top + height, left:left + width, :] = part_of_bg
    return result

background = cv2.imread('image.jpg')
# Read the image "unchanged" to get the alpha channel as well
label = cv2.imread('image_rgba.png', cv2.IMREAD_UNCHANGED)
result = alphaMerge(label, background, 100, 200)
cv2.imshow("result", result)
cv2.waitKey()

I tested with the following background:我在以下背景下进行了测试:

背景

And this foreground:而这个前景:

前景

Result as shown by the Python code:结果如 Python 代码所示:

结果

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM