Использование openCV для наложения прозрачного изображения на другое изображение

Как я могу наложить прозрачный PNG на другое изображение, не теряя его прозрачность, используя openCV в Python?

import cv2

background = cv2.imread('field.jpg')
overlay = cv2.imread('dice.png')

# Help please

cv2.imwrite('combined.png', background)

Желаемый результат: enter image description here

Источники:

Изображение на заднем плане

оверлей

Ответ 1

import cv2

background = cv2.imread('field.jpg')
overlay = cv2.imread('dice.png')

added_image = cv2.addWeighted(background,0.4,overlay,0.1,0)

cv2.imwrite('combined.png', added_image)

Ответ 2

import numpy as np
import cv2

# ==============================================================================

def blend_transparent(face_img, overlay_t_img):
    # Split out the transparency mask from the colour info
    overlay_img = overlay_t_img[:,:,:3] # Grab the BRG planes
    overlay_mask = overlay_t_img[:,:,3:]  # And the alpha plane

    # Again calculate the inverse mask
    background_mask = 255 - overlay_mask

    # Turn the masks into three channel, so we can use them as weights
    overlay_mask = cv2.cvtColor(overlay_mask, cv2.COLOR_GRAY2BGR)
    background_mask = cv2.cvtColor(background_mask, cv2.COLOR_GRAY2BGR)

    # Create a masked out face image, and masked out overlay
    # We convert the images to floating point in range 0.0 - 1.0
    face_part = (face_img * (1 / 255.0)) * (background_mask * (1 / 255.0))
    overlay_part = (overlay_img * (1 / 255.0)) * (overlay_mask * (1 / 255.0))

    # And finally just add them together, and rescale it back to an 8bit integer image    
    return np.uint8(cv2.addWeighted(face_part, 255.0, overlay_part, 255.0, 0.0))

# ==============================================================================

# We load the images
face_img = cv2.imread("field.jpg")
overlay_t_img = cv2.imread("dice.png", -1) # Load with transparency

result_2 = blend_transparent(face_img, overlay_t_img)
cv2.imwrite("merged_transparent.png", result_2)

Ответ 3

Прошло некоторое время с тех пор, как появился этот вопрос, но я считаю, что это правильный простой ответ, который еще может кому-то помочь.

background = cv2.imread('road.jpg')
overlay = cv2.imread('traffic sign.png')

rows,cols,channels = overlay.shape

overlay=cv2.addWeighted(background[250:250+rows, 0:0+cols],0.5,overlay,0.5,0)

background[250:250+rows, 0:0+cols ] = overlay

Это наложит изображение на фоновое изображение, как показано здесь:

Игнорировать прямоугольники ROI

enter image description here

Обратите внимание, что я использовал фоновое изображение размером 400x300 и оверлейное изображение размером 32x32, которое отображается в части x [0-32] и y [250-282] фонового изображения в соответствии с заданными для него координатами, чтобы сначала вычислите смесь, а затем поместите рассчитанную смесь в ту часть изображения, где я хочу ее разместить.

(оверлей загружается с диска, а не с самого фонового изображения, к сожалению, у оверлейного изображения есть свой собственный белый фон, так что вы можете увидеть это и в результате)

Ответ 4

Следующий код будет использовать альфа-каналы наложенного изображения, чтобы правильно смешать его с фоновым изображением, используйте x и y чтобы установить левый верхний угол наложенного изображения.

import cv2
import numpy as np

def overlay_transparent(background, overlay, x, y):

    background_width = background.shape[1]
    background_height = background.shape[0]

    if x >= background_width or y >= background_height:
        return background

    h, w = overlay.shape[0], overlay.shape[1]

    if x + w > background_width:
        w = background_width - x
        overlay = overlay[:, :w]

    if y + h > background_height:
        h = background_height - y
        overlay = overlay[:h]

    if overlay.shape[2] < 4:
        overlay = np.concatenate(
            [
                overlay,
                np.ones((overlay.shape[0], overlay.shape[1], 1), dtype = overlay.dtype) * 255
            ],
            axis = 2,
        )

    overlay_image = overlay[..., :3]
    mask = overlay[..., 3:] / 255.0

    background[y:y+h, x:x+w] = (1.0 - mask) * background[y:y+h, x:x+w] + mask * overlay_image

    return background

Этот код изменяет фон, поэтому создайте копию, если вы хотите сохранить исходное фоновое изображение.

Ответ 5

Вам нужно открыть прозрачное изображение в формате png, используя флаг IMREAD_UNCHANGED

Mat overlay = cv::imread("dice.png", IMREAD_UNCHANGED);

Затем разделите каналы, сгруппируйте RGB и используйте прозрачный канал в качестве маски, сделайте так:

/**
 * @brief Draws a transparent image over a frame Mat.
 * 
 * @param frame the frame where the transparent image will be drawn
 * @param transp the Mat image with transparency, read from a PNG image, with the IMREAD_UNCHANGED flag
 * @param xPos x position of the frame image where the image will start.
 * @param yPos y position of the frame image where the image will start.
 */
void drawTransparency(Mat frame, Mat transp, int xPos, int yPos) {
    Mat mask;
    vector<Mat> layers;

    split(transp, layers); // seperate channels
    Mat rgb[3] = { layers[0],layers[1],layers[2] };
    mask = layers[3]; // png alpha channel used as mask
    merge(rgb, 3, transp);  // put together the RGB channels, now transp insn't transparent 
    transp.copyTo(frame.rowRange(yPos, yPos + transp.rows).colRange(xPos, xPos + transp.cols), mask);
}

Можно назвать так:

drawTransparency(background, overlay, 10, 10);

Ответ 6

Поскольку вы хотите работать с прозрачностью, обязательно проверьте ЭТО ОТВЕТ, который я предоставил месяц назад. Я бы взял ссылку с другого сообщения в блоге, также упомянутого там.

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