【问题标题】:Changing the color for the overlay of a PIL image makes no difference更改 PIL 图像覆盖的颜色没有区别
【发布时间】:2021-01-05 15:37:49
【问题描述】:

我正在尝试使用此功能在透明徽标上应用叠加层:

def overlay(path):

    logo_img = cv2.imread(path, cv2.IMREAD_UNCHANGED)

    '''Saving the alpha channel of the logo to the "alpha" variable.'''
    alpha = logo_img[:, :, 3]

    '''Creating the overlay of the logo by first creating an array of zeros in the shape of the logo.
    The color on this will change later to become the overlay that will mask the logo.'''
    mask = np.zeros(logo_img.shape, dtype=np.uint8)

    '''Adding the alpha (transparency) of the original logo so that the overlay has the same transparecy
    that the original logo has.'''
    # mask[:, :, 2] = alpha

    '''This code chooses random values for Red, Green and Blue channels of the image so that the final
    overlay always has a different background'''
    # r, g, b = (random.randint(0, 255),
    #            random.randint(0, 255),
    #            random.randint(0, 255))

    r, g, b = (0, 255, 0)

    '''There is a risk of losing the transparency when randomizing the overlay color so here I'm saving the
    alpha value'''
    a = 255

    '''Creating the overlay'''
    mask[:, :] = r, g, b, a
    mask[:, :, 3] = alpha

    '''Alp, short for alpha, is separate from above. This determines the opacity level of the logo. The 
    beta parameter determines the opacity level of the overlay.'''
    alp = 1
    beta = 1 - alp

    '''addWeighted() is what masks the overlay on top of the logo'''
    dst = cv2.addWeighted(logo_img, alp, mask, beta, 0, dtype=cv2.CV_32F).astype(np.uint8)

    '''Converting the output dst to a PIL image with the RGBA channels.'''
    pil_image = Image.fromarray(dst).convert('RGBA')

    return pil_image

如您所见,我有这两个元组用于设置 RGB。无论是随机化还是选择特定颜色,叠加层的颜色都没有区别。

# r, g, b = (random.randint(0, 255),
    #            random.randint(0, 255),
    #            random.randint(0, 255))

    r, g, b = (0, 255, 0)

【问题讨论】:

    标签: python numpy opencv python-imaging-library rgb


    【解决方案1】:

    编辑

    您希望使用 alpha 遮罩“更改徽标的颜色”。除非您实际操作实际的图像像素,否则您无法执行此操作。使用 alpha matting 方法不是正确的答案。我建议您实际上掩盖要更改的徽标区域,然后用所需的颜色替换颜色。 Alpha 遮罩主要用于将对象混合 在一起,而不是更改对象的颜色分布。我为后代留下了下面的答案,因为原始问题中提供的原始 alpha matting 方法的核心是不正确的。


    这种方法的核心误解来自于cv2.addWeighted的执行方式。引用the documentation(强调我的):

    如果是多通道数组,每个通道都是独立处理的。该函数可以替换为矩阵表达式:

    dst = src1*alpha + src2*beta + gamma;

    cv2.addWeighted 不会以您期望的方式正确处理 Alpha 通道。具体来说,它会将 alpha 通道视为另一个信息通道,并单独对该通道进行加权求和以用于最终输出。它实际上并没有实现 alpha matting。因此,如果您想做 alpha matting,您需要自己实际计算操作。

    类似:

    import numpy as np
    import cv2
    from PIL import Image
    
    def overlay(path):
        ### Some code from your function - comments removed for brevity
        logo_img = cv2.imread(path, cv2.IMREAD_UNCHANGED)
        alpha = logo_img[:, :, 3]
    
        mask = np.zeros(logo_img.shape, dtype=np.uint8)
    
        # r, g, b = (random.randint(0, 255),
        #            random.randint(0, 255),
        #            random.randint(0, 255))
    
        r, g, b = (0, 255, 0)
        a = 255
        mask[:, :] = r, g, b, a
        mask[:, :, 3] = alpha
    
        ### Alpha matte code here
        alp = alpha.astype(np.float32) / 255.0  # To make between [0, 1]
        alp = alp[..., None]  # For broadcasting
        dst_tmp = logo_img[..., :3].astype(np.float32) * alp + mask[..., :3].astype(np.float32) * (1.0 - alp)
        dst = np.zeros_like(logo_img)
        dst[..., :3] = dst_tmp.astype(np.uint8)
        dst[..., 3] = 255
    
        pil_image = Image.fromarray(dst).convert('RGBA')
    
        return pil_image
    

    这个新功能的第一个部分来自您最初拥有的功能。但是,具有 alpha matting 的部分在上面的相应注释之后标记。该部分的第一行将 alpha 映射转换为[0, 1] 范围。这是必需的,因此当您执行 alpha 抠图操作(这是两个图像的加权和)时,您可以确保没有输出像素超出其本机数据类型的范围。另外,我引入了一个单例三维,以便我们可以在每个 RGB 通道上分别广播 alpha 通道以正确地进行加权。之后,我们将计算 alpha 遮罩作为徽标图像和遮罩的加权和。请注意,我对每个通道进行了子集化并仅提取了 RGB 通道。你不需要这里的 alpha 通道,因为我直接在加权和中使用它。完成此操作后,创建一个新的输出图像,前三个通道是生成的 alpha 遮罩,但 alpha 通道全部设置为 255,因为此时我们已经实现了混合,并且您希望所有像素值现在显示不透明。

    【讨论】:

    • 为什么要转换成[0,1]范围?
    • 您的代码存在一些问题。一,logo_img[.., :3] 必须是logo_img[..., :3]。否则会引发错误。其次,您的解决方案不会更改徽标的颜色。它的作用是将r, g, b 值添加到透明背景中,从而消除背景的透明度,但覆盖颜色在徽标上保持不变...
    • 感谢您的错字。当您不测试代码时会发生这种情况。现在谈谈您的其他问题:(1)因为它是加权和,因此您可以确保没有像素超出 [0,255] 范围。 (2) 啊,你想改变标志的颜色。我不认为这可以通过 alpha 遮罩操作来完成。事实上,这都是 错误 操作。 Alpha 抠图主要用于将两个图像/对象混合在一起。如果你想改变颜色,你需要遮住你想要的区域并用选择的颜色填充它然后混合之后。
    • 是的,但这就是我的代码已经在做的事情。它会创建一个作为徽标切口的蒙版,并将其应用到徽标顶部,降低不透明度..
    • 降低不透明度不起作用。您需要修改徽标内的实际元素。 Alpha matting 是错误的解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-02
    • 1970-01-01
    • 2012-10-22
    • 1970-01-01
    • 2016-07-27
    • 2020-10-19
    • 1970-01-01
    相关资源
    最近更新 更多