簡體   English   中英

更改 PIL 圖像覆蓋的顏色沒有區別

[英]Changing the color for the overlay of a PIL image makes no difference

我正在嘗試使用此 function 在透明徽標上應用疊加層:

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。 無論我是隨機化它還是我 select 一個特定的顏色,疊加的顏色都沒有區別。

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

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

編輯

您希望使用 alpha 遮罩“更改徽標的顏色”。 除非您實際操作實際的圖像像素,否則您無法執行此操作。 使用 alpha matting 方法不是正確的答案。 我建議您實際上掩蓋要更改的徽標區域,然后用所需的顏色替換顏色。 Alpha 遮罩主要用於將對象混合在一起,而不是更改 object 的顏色分布。 我為后代留下了下面的答案,因為在其核心的原始問題中提供的原始 alpha matting 方法是不正確的。


這種方法的核心誤解來自於cv2.addWeighted的執行方式。 引用文檔(強調我的):

在多通道 arrays 的情況下,每個通道都是獨立處理的 function 可以替換為矩陣表達式:

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

cv2.addWeighted不會以您期望的方式正確處理 alpha 通道。 具體來說,它會將 alpha 通道視為另一個信息通道,並單獨對最終 output 的該通道進行加權求和。 它實際上並沒有實現 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

這個新的 function 的第一個位來自您最初擁有的。 但是,具有 alpha matting 的部分在上面的相應注釋之后標記。 該部分的第一行將 alpha map 轉換為[0, 1]范圍。 這是必需的,因此當您執行 alpha 摳圖操作(這是兩個圖像的加權和)時,您可以確保沒有 output 像素超出其本機數據類型的范圍。 另外,我介紹了一個 singleton 三維,以便我們可以在每個 RGB 通道上分別廣播 alpha 通道以正確地進行加權。 之后,我們將計算 alpha 遮罩作為徽標圖像和遮罩的加權和。 請注意,我對每個通道進行了子集化並僅提取了 RGB 通道。 你不需要這里的 alpha 通道,因為我直接在加權和中使用它。 完成此操作后,創建一個新的 output 圖像,前三個通道是生成的 alpha 遮罩,但 alpha 通道全部設置為 255,因為此時我們已經實現了混合,並且您希望所有像素值現在顯示沒有透明度。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM