【问题标题】:Overlaying an image with another non-rectangular image containing black pixels using OpenCV in Python在 Python 中使用 OpenCV 将图像与另一个包含黑色像素的非矩形图像叠加
【发布时间】:2019-05-15 08:36:04
【问题描述】:

我想以编程方式覆盖图像,例如幸福熟悉的 Windows XP 壁纸:

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

复制粘贴来自thisthis 教程的代码,它们都使用了我到达的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 argumentsthresholding types)寻找正确参数的天真的排列过程中,我总是发现原始图像中存在大量黑色像素从覆盖的图像中丢失.在左下方的放大图片中,您可以看到重叠的光标,右侧是原始复制的:

我认为这种像素损失是由于灰度转换和/或反向 (?) 掩码造成的,但无法弄清楚如何或在上面的代码中进行更改。在教程中,我将上面链接的不包含黑色像素的图像用于叠加,结果看起来很好。有没有办法对包含黑色像素的图像做同样的事情?

【问题讨论】:

    标签: python opencv image-processing overlay


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 当我使用最初链接的大光标时,这很有魅力。但是,对于较小的光标图像(例如i.imgur.com/0YC5qVV.png),黑色像素的损失会逐渐减少:i.imgur.com/TWnalik.png
    • @bugfoot 我编辑了我的答案。原始 Alpha 通道包含某种“渐变”透明度,由值 0 < x < 255 表示。我添加了_, alpha = cv.threshold(alpha, 5, 255, cv.THRESH_BINARY) 来二值化 Alpha 通道。它现在也适用于您提供的小光标图像。
    猜你喜欢
    • 1970-01-01
    • 2020-02-03
    • 1970-01-01
    • 1970-01-01
    • 2019-07-25
    • 2020-01-09
    • 1970-01-01
    • 2021-06-25
    • 2021-07-29
    相关资源
    最近更新 更多