PythonでopenCVを使用して透明度を失うことなく、透明なPNGを別の画像にオーバーレイするにはどうすればよいですか?
import cv2
background = cv2.imread('field.jpg')
overlay = cv2.imread('dice.png')
# Help please
cv2.imwrite('combined.png', background)
ソース:
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)
この質問が出てからしばらく経ちましたが、これは正しい簡単な答えだと思います。
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の長方形を無視する
サイズ400x300の背景画像とサイズ32x32のオーバーレイ画像を使用したことに注意してください。設定した座標に従って、背景画像のx [0-32]およびy [250-282]部分に表示されます。最初にブレンドを計算してから、計算したブレンドをイメージの一部に配置します。
(オーバーレイは背景画像自体からではなくディスクから読み込まれますが、残念ながらオーバーレイ画像には独自の白い背景があるため、結果でもそれを見ることができます)
次のコードは、オーバーレイイメージのアルファチャネルを使用して背景イメージに正しくブレンドします。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
このコードは背景を変更するため、元の背景画像を保持する場合はコピーを作成します。
フラグ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);
transparencyで作業したいので、必ず THIS ANSWER を1か月前に確認してください。私はそこに言及されている別のブログ投稿からも参考にしたでしょう。
役に立つと思う場合や、他の問題がある場合は、コメントを残してください。