Alpha使用OpenCV和/或Numpy混合两个图像

2024-05-15 11:57:35 发布

您现在位置:Python中文网/ 问答频道 /正文

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

enter image description here

该图像加载了一个标准的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))

下面是我得到的结果:

enter image description here

乍一看,它看起来是可以接受的。我们有一个半透明矩形在中间的输入图像。然而,仔细观察后,我们可以观察到混合alpha通道(用箭头标记)时的奇怪行为:

enter image description here

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

也许我将透明PNG与半透明形状混合的方法远非理想。顺便说一下,我确实尝试了cv2.addWeighted方法,但结果更糟

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


Tags: 方法图像imagealpha示例pngnpmask
2条回答

正如unlut指出的,这确实是一个重复。为了防止有人无意中发现,马克·塞切尔的回答非常有效:

# 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)

alpha混合的简单操作: https://learnopencv.com/alpha-blending-using-opencv-cpp-python/

import cv2

# Read the images
foreground = cv2.imread("puppets.png")
background = cv2.imread("ocean.png")
alpha = cv2.imread("puppets_alpha.png")

# Convert uint8 to float
foreground = foreground.astype(float)
background = background.astype(float)

# Normalize the alpha mask to keep intensity between 0 and 1
alpha = alpha.astype(float)/255

# Multiply the foreground with the alpha matte
foreground = cv2.multiply(alpha, foreground)

# Multiply the background with ( 1 - alpha )
background = cv2.multiply(1.0 - alpha, background)

# Add the masked foreground and background.
outImage = cv2.add(foreground, background)

# Display image
cv2.imshow("outImg", outImage/255)
cv2.waitKey(0)

相关问题 更多 >