Наложение изображения на другое непрямоугольное изображение, содержащее черные пиксели, с использованием OpenCV в Python - PullRequest
1 голос
/ 15 мая 2019

Я хочу программно наложить изображение, например блаженно знакомые обои для Windows XP:

Windows XP wallpaper

с другим непрямоугольным изображением, содержащим черные пикселиНапример, стандартный большой значок курсора:

enter image description here

Копирование и вставка кодов из этого и этого учебник, в котором оба используют магию битового маскирования 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 и maxval-аргументы , а также типы порогов ), я всегда нахожу, что значительное количество черных пикселей, присутствующих в исходном изображении, отсутствует в наложенном.На увеличенном изображении ниже слева вы можете видеть наложенный курсор, а справа - оригинально скопированный:

enter image description here

Я считаю эту потерюпикселей происходит из-за преобразования в градациях серого и / или обратной (?) маскировки, но не может понять, как или что изменить в приведенном выше коде.В уроках, которые я привел выше, изображения, не содержащие черные пиксели, использовались для наложения, и результаты выглядят хорошо.Есть ли способ сделать то же самое с изображениями, содержащими черные пиксели?

1 Ответ

2 голосов
/ 15 мая 2019

Проблема в том, что вы теряете черные пиксели в cursor.png при cv.threshold(img2gray, 20, 255, cv.THRESH_BINARY).Остальные - только белые пиксели, поэтому ваша маска слишком мала.Поскольку в cursor.png хранится информация о прозрачности, вы можете использовать ее альфа-канал для своей маски.

Вот ваш код, соответствующим образом измененный (я удалил все ваши комментарии; комментарии показывают мои изменения):

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

Будем надеяться, что выходное изображение будет выглядеть так, как вы ожидали:

Output

...