Alpha 将两个图像与 OpenCV 和/或 Numpy 混合

Pon*_*ono 8 python opencv numpy

我想向已经加载的半透明 PNG 添加一个填充纯色的半透明矩形。这是我正在使用的示例输入图像:

在此处输入图片说明

该图像加载了一个标准cv2.IMREAD_UNCHANGED标志,以便完美地保留 alpha 通道。该输入图像存储在image变量中。

这是我到目前为止的代码:

# get image dimensions
imgHeight, imgWidth = image.shape[:2]

# create empty overlay layer with 4 channels
overlay = np.zeros((imgHeight, imgWidth, 4), dtype = "uint8")

# draw semi-transparent red rectangle
overlay[200:300, 0:imgWidth] = (0, 0, 255, 200)

# extract alpha channel from overlay
alpha = cv2.split(overlay)[3]

# compute mask
mask = (np.multiply(alpha, 1.0 / 255))[:, :, np.newaxis]

# blend input image and overlay
output = cv2.convertScaleAbs(overlay * mask + image * (1 - mask))
Run Code Online (Sandbox Code Playgroud)

这是我得到的结果:

在此处输入图片说明

乍一看还可以接受。我们的输入图像中间有一个半透明的矩形。但是,经过仔细检查,我们可以观察到混合 alpha 通道(用箭头标记)时的奇怪行为:

在此处输入图片说明

似乎 alpha 根本没有混合,这导致原始图像像素仅完全不透明或完全透明。

也许我将透明 PNG 与半透明形状混合的方法远非理想。作为旁注,我确实尝试了该cv2.addWeighted方法,但结果更糟。

我希望解决方案仅限于 OpenCV 和/或 Numpy。任何帮助将不胜感激。

Kni*_*ked 9

正如 unlut 指出的那样,这确实是重复的。以防万一有人偶然发现,Mark Setchell 的回答非常有效:

# get image dimensions
imgHeight, imgWidth = image.shape[:2]

# create empty overlay layer with 4 channels
overlay = np.zeros((imgHeight, imgWidth, 4), dtype = "uint8")

# draw semi-transparent red rectangle
overlay[200:300, 0:imgWidth] = (0, 0, 255, 200)

# Extract the RGB channels
srcRGB = image[...,:3]
dstRGB = overlay[...,:3]

# Extract the alpha channels and normalise to range 0..1
srcA = image[...,3]/255.0
dstA = overlay[...,3]/255.0

# Work out resultant alpha channel
outA = srcA + dstA*(1-srcA)

# Work out resultant RGB
outRGB = (srcRGB*srcA[...,np.newaxis] + dstRGB*dstA[...,np.newaxis]*(1-srcA[...,np.newaxis])) / outA[...,np.newaxis]

# Merge RGB and alpha (scaled back up to 0..255) back into single image
outRGBA = np.dstack((outRGB,outA*255)).astype(np.uint8)

plt.imshow(outRGBA)
Run Code Online (Sandbox Code Playgroud)