事件
アルファ付きpng画像を重ねて表示したいときに事件は起きた。imreadで背景画像を読み込んだ時には大丈夫なのに、真っ白なキャンバスを生成するためにnp.zerosを使ったときに問題発生。cv2.cvshowで表示したときに色がおかしくなる。cv2.imwriteで書き出すと思っていた通りの色が出る
この記事を参考に(ほぼコピペ)、背景画像を読み込むところを、真っ白い画像を生成することによって代替した。
真っ白い画像を生成する(4,5行目)のは適当にググった ←伏線
import cv2
import numpy as np
frame = np.zeros((720, 1280, 3)) #真っ黒画像(ゼロ埋め)
frame += 255 #真っ白画像を生成
#frame = cv2.imread("bg.jpg") #特定の画像を読み込むわけではない
png_image = cv2.imread("alpha.png", cv2.IMREAD_UNCHANGED) # アルファチャンネル込みで読み込む
# 貼り付け先座標の設定。とりあえず左上に
x1, y1, x2, y2 = 0, 0, png_image.shape[1], png_image.shape[0]
# 合成!
frame[y1:y2, x1:x2] = frame[y1:y2, x1:x2] * (1 - png_image[:, :, 3:] / 255) + \
png_image[:, :, :3] * (png_image[:, :, 3:] / 255)
cv2.imwrite("out.png",frame)
cv2.imshow("window",frame)
cv2.waitKey(0)
結果
imshowで出したウィンドウは、明らかにおかしい。なんというか、アルファチャンネルが読み込めていないようにも見える(アルファ値255のみが見えているように感じる)。しかし、よく見るとカラフルな線が黒い枠線に重なったところが白抜きされてるなど様子が変だ。(黒い枠線はどう考えてもアルファ値255である)
対策
4行目でframe=np.zeros()
としてnp配列を作成して画像としている。どうやらnp.zerosのdtype引数はデフォルトでfloatとなっているらしい。しかしopenCVで使用するのはnp.uint8らしく、どうやらこれが原因だったらしい。
と、後になって調べてみると、np.zerosで生成するときにほとんどの記事でdtype=np.uint8を指定しているではないか。適当にググったのが仇となってしまった。 ←伏線回収
ちなみにunit(ユニット)と見間違えやすいがこれはunsigned intのことである。
import cv2
import numpy as np
frame = np.zeros((720, 1280, 3),dtype=np.uint8) #真っ黒画像(ゼロ埋め)
frame += 255 #真っ白画像を生成
#frame = cv2.imread("bg.jpg") #特定の画像を読み込むわけではない
png_image = cv2.imread("alpha.png", -1) # アルファチャンネル込みで読み込む
# 貼り付け先座標の設定。とりあえず左上に
x1, y1, x2, y2 = 0, 0, png_image.shape[1], png_image.shape[0]
# 合成!
frame[y1:y2, x1:x2] = frame[y1:y2, x1:x2] * (1 - png_image[:, :, 3:] / 255) + \
png_image[:, :, :3] * (png_image[:, :, 3:] / 255)
cv2.imwrite("out.png",frame)
cv2.imshow("window",frame)
cv2.waitKey(0)
余談だがimreadでアルファチャンネルを読み込むならfilenameの次に-1で良い。こっそり直してみた