【问题标题】:How to merge one RGBA and one RGB images in opencv如何在opencv中合并一张RGBA和一张RGB图像
【发布时间】:2022-01-04 12:11:52
【问题描述】:

我有两张图片。在一个图像中,通过以RGBA 图像格式编辑通道A,将白色像素设置为透明(或无色)。假设这个图像名称是image_rgba.png,另一个图像是image.jpg。现在,我想使用以下 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

当我写这个图像时,image_rgba.png 的无色边缘在输出图像中被设置为白色(下图中绿色框的白色边缘)。

我希望绿色框标签的白色边缘不显示,而是显示在该像素中的背景图像。我找到了similar 问题,但它并不能帮助我解决我的问题。如果有人可以帮助我,我将不胜感激。

【问题讨论】:

  • 好问题。像这样简单的任务真的可以让 OpenCV 陷入困境。花了 1 小时搜索重复项,但没有一个该死的答案解释了如何合并具有不同大小的 alpha 通道的 JPG 和 PNG。
  • @DanMašek:几乎恕我直言。但它不考虑不同大小的图像
  • 顺便说一句,这些问题每隔一周出现一次,并且有足够高质量的答案,绝对应该作为其中任何一个的副本关闭。只需寻找“叠加”、“透明度”……并注意那些仅使用 Alpha 通道作为蒙版而不是正确相乘的解决方案。 addWeighted 总是错误的,因为它的权重是标量,而不是图片。

标签: python opencv


【解决方案1】:

您可以这样做。我不是 OpenCV 专家,所以可能有更简单的方法。代码中的注释解释了它的作用。总体思路是:

  1. 从 PNG 中提取 Alpha 通道
  2. 提取一块相同大小的背景
  3. Alpha 混合这些
  4. 将结果放回后台
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()

我在以下背景下进行了测试:

还有这个前景:

结果如 Python 代码所示:

【讨论】:

  • 非常感谢,我的朋友。你的回答对我很有帮助。
猜你喜欢
  • 1970-01-01
  • 2022-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-18
  • 1970-01-01
  • 1970-01-01
  • 2012-03-04
相关资源
最近更新 更多