web-dev-qa-db-ja.com

openCVを使用して透明な画像を別の画像にオーバーレイする

PythonでopenCVを使用して透明度を失うことなく、透明なPNGを別の画像にオーバーレイするにはどうすればよいですか?

import cv2

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

# Help please

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

望ましい出力: enter image description here

ソース:

背景画像

オーバーレイ

16
Anthony Budd
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)
11

この質問が出てからしばらく経ちましたが、これは正しい簡単な答えだと思います。

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]部分に表示されます。最初にブレンドを計算してから、計算したブレンドをイメージの一部に配置します。

(オーバーレイは背景画像自体からではなくディスクから読み込まれますが、残念ながらオーバーレイ画像には独自の白い背景があるため、結果でもそれを見ることができます)

6

次のコードは、オーバーレイイメージのアルファチャネルを使用して背景イメージに正しくブレンドします。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
Cristian Garcia

フラグIMREAD_UNCHANGEDを​​使用して透明なpng画像を開く必要があります

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's 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);
1
Derzu

transparencyで作業したいので、必ず THIS ANSWER を1か月前に確認してください。私はそこに言及されている別のブログ投稿からも参考にしたでしょう。

役に立つと思う場合や、他の問題がある場合は、コメントを残してください。

0
Jeru Luke