在 Python 中使用 OpenCV 将一个图像与另一个包含黑色像素的非矩形图像叠加

Overlaying an image with another non-rectangular image containing black pixels using OpenCV in Python

我想以编程方式叠加图像,例如幸福地熟悉 Windows XP 壁纸:

使用另一个包含黑色像素的非矩形图像,例如一个标准的大光标图标:

复制粘贴来自 this and this 教程的代码,它们都使用 OpenCV 按位掩码魔术我到达了:

import cv2 as cv

# Load two images
img1 = cv.imread('bliss.png') # The image I want the overlay to be diplayed on.
img2 = cv.imread('cursor.png') # The image I want to overlay with, containing black pixels.

# I want to put logo on top-left corner, So I create a ROI.
rows, cols, channels = img2.shape
roi = img1[0:rows, 0:cols ]

# Now create a mask of logo and create its inverse mask also.
img2gray = cv.cvtColor(img2, cv.COLOR_BGR2GRAY)
ret, mask = cv.threshold(img2gray, 20, 255, cv.THRESH_BINARY)
mask_inv = cv.bitwise_not(mask)

# Now black-out the area of logo in ROI.
img1_bg = cv.bitwise_and(roi, roi, mask = mask_inv)

# Take only region of logo from logo image.
img2_fg = cv.bitwise_and(img2, img2, mask = mask)

# Put logo in ROI and modify the main image
dst = cv.add(img1_bg, img2_fg)
img1[0:rows, 0:cols ] = dst
cv.imshow('res',img1)
cv.waitKey(0)
cv.destroyAllWindows()

在尝试为 cv.threshold(包括 thres and maxval arguments as well as thresholding types)寻找正确参数的天真排列过程中,我总是发现原始图像中存在的大量黑色像素从重叠图像中丢失.在下面放大的图片中,左边可以看到重叠的光标,右边是原始复制的:

我认为这种像素损失是由于灰度转换 and/or 反向 (?) 掩码造成的,但无法弄清楚如何或在上面的代码中更改什么。在我上面链接的教程中,不包含黑色像素的图像被用于叠加层,结果看起来不错。有没有办法对包含黑色像素的图像执行相同的操作?

这里的问题是,您在 cv.threshold(img2gray, 20, 255, cv.THRESH_BINARY) 处丢失了 cursor.png 中的黑色像素。其余的只是白色像素,因此您的蒙版太小了。由于 cursor.png 中存储了透明度信息,您可以将其 alpha 通道用于蒙版。

这是您的代码,经过相应修改(我删除了您的所有评论;评论显示了我的更改):

import cv2 as cv

img1 = cv.imread('bliss.png')
img2 = cv.imread('cursor.png', cv.IMREAD_UNCHANGED)         # Added cv.IMREAD_UNCHANGED parameter to maintain alpha channel information

alpha = img2[:, :, 3]                                       # Save alpha channel for later use
_, alpha = cv.threshold(alpha, 5, 255, cv.THRESH_BINARY)    # Threshold alpha channel to prevent gradual transparency
img2 = cv.cvtColor(img2, cv.COLOR_BGRA2BGR)                 # Remove alpha channel information, so that code below still works

rows, cols, channels = img2.shape
roi = img1[0:rows, 0:cols ]

                                                            # img2gray no longer needed
mask = alpha                                                # Mask is just the alpha channel saved above
mask_inv = cv.bitwise_not(mask)

img1_bg = cv.bitwise_and(roi, roi, mask = mask_inv)

img2_fg = cv.bitwise_and(img2, img2, mask = mask)

dst = cv.add(img1_bg, img2_fg)
img1[0:rows, 0:cols ] = dst
cv.imshow('res',img1)
cv.waitKey(0)
cv.destroyAllWindows()

希望输出图像看起来像您预期的那样: