つれづれなる備忘録

日々の発見をあるがままに綴る

OpenCVの使い方3 ~ 画像の重ね合わせ

 OpenCVを使用方法について、今回は2つの画像を重ね合わせる方法について紹介したい。

1. 画像読み込みまで

 今回は以前撮影した源平桃の画像とOpen CVのロゴ画像を使用する。コードは前回記事を参照で源平桃の画像をorig, Open CVのロゴ画像をorig2とする。 orig, orig2はcv2.imreadで読み込んだデータで、BGRとして読み込まれていることに注意する必要があり、画像を表示させるにはcv2.cvtColor(orig, cv2.COLOR_BGR2RGB)としてBGR→RGBの変換が必要。

atatat.hatenablog.com

2枚のテスト画像は以下の通りだが、サイズがorig:480x640, orig2:296x240と異なっている。

"テスト画像2枚"
テスト画像2枚

2. 画像の重みつき重ね合わせ

まずorigに対してorig2の画像を重みをつけて重ね合わせる。桃の画像にOpen CVのロゴが透かしのように入るようなイメージを作成する。これはaddWeighted(画像1,重み,画像2,重み,γ値)を用いるが、使用上の注意としては画像1と画像2のサイズが一致している必要がある。重みはそれぞれの和が1になるように設定する。今回は画像サイズが小さいOpenCVのロゴ:296x240に合わせるが、大きい方に合わせるにはダミーの値などをいれるなどして画像サイズを拡張する必要がある。

blend=cv2.addWeighted(orig[0:296,0:240],0.7,orig2,0.3,0)
blendsrc = cv2.cvtColor(blend, cv2.COLOR_BGR2RGB)
plt.imshow(blendsrc)

実行結果は以下のようになり、確かに桃の画像にOpen CVのロゴが透かしのように入っている。

"2つの画像の重み付き重ね合わせ"
2つの画像の重み付き重ね合わせ

3. 画像の重ね合わせ

 ロゴの部分だけを完全に重ね合わせるには、しきい値を使ったマスクを用いる。処理の流れとしては桃の画像から重ね合わせるOpen CVのロゴの部分の画素のRGB値をマスクを用いてすべて0にして、2枚の画像の足し合わせる(正確には画素のRGB値をそれぞれ加算)ことで、桃の画像の上にOpen CVのロゴの画像を重ねる。

まずOpenCVのロゴ画像は296x240だが、以下のように領域サイズを取得することもできる。 roiは桃の画像左上から296x240の領域を切り出したデータとなる。

rows,cols,channels = orig2.shape
roi = orig[0:rows, 0:cols ]

ここでroiは桃の画像480x640から左上を起点としてロゴ画像の領域296x240だけ切り出した画像となる。

次に画像の2値化処理(白か黒)をする。2値化処理をする画像はグレースケール画像にする必要があるためcv2.cvtColor(orig2,cv2.COLOR_BGR2GRAY)としてカラーからグレースケール画像に変換する。 次にグレースケール画像img2grayに対してしきい値(1)以上の部分は白(255)を入れて2値化画像を生成するためには cv2.threshold(img2gray, 1, 255, cv2.THRESH_BINARY)とする。 また反転マスクmask_invを作成するにはビット値を反転するcv2.bitwise_not(mask)を使用する。

img2gray = cv2.cvtColor(orig2,cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 1, 255, cv2.THRESH_BINARY)
mask_inv = cv2.bitwise_not(mask)

img2gray_src = cv2.cvtColor(mask_inv, cv2.COLOR_BGR2RGB)
plt.imshow(img2gray_src)

反転マスクを表示すると以下のようになる。

"反転マスク"
反転マスク

次に桃の画像origから切り出した領域roiに対して上記のマスクを適用して、OpenCVのロゴの画素情報を流し込む領域を作成する。 2つの画像のANDを出力するbitwise_andでは二つの画像のANDをとることができるが、オプションとして2値のマスクデータを指定できる。今回は2つの画像は同じものするが、マスクを上記のmask_invを指定するとOpenCVのロゴ形状を領域として確保することができる。なおマスクデータを指定せずに2値のマスクデータをBGRに変換して画像とANDをとっても同様になる。

img1_bg = cv2.bitwise_and(roi,roi,mask = mask_inv)
img1_bg_src = cv2.cvtColor(img1_bg, cv2.COLOR_BGR2RGB)
plt.imshow(img1_bg_src)

"桃の画像にマスクデータを適用"
桃の画像にマスクデータを適用

同様にOpenCVのロゴ側に反転していないマスクを適用する。(もともと背景が黒なのであまり変化はないが)

img2_fg = cv2.bitwise_and(orig2,orig2,mask = mask)
img2_fg_src = cv2.cvtColor(img2_fg, cv2.COLOR_BGR2RGB)
plt.imshow(img2_fg_src)

"ロゴ画像にマスク適用"
ロゴ画像にマスク適用

反転マスクを適用した桃の画像とマスクを適用したロゴの画像を足し合わせるにはadd()を用い、さらにroiの領域に足し合わせた画像の画素データをもとの桃の画像(480x640)に流すことで2つの画像を重ね合わせる。

dst = cv2.add(img1_bg,img2_fg)
orig[0:rows, 0:cols ] = dst
src3 = cv2.cvtColor(orig, cv2.COLOR_BGR2RGB)
plt.imshow(src3)

"桃の画像とロゴの画像の重ね合わせ"
桃の画像とロゴの画像の重ね合わせ

4. まとめ

 今回2つの画像を重ね合わせる方法としてaddWeightedを用いる方法とマスクデータを作成・bitwise_andを用いて適用して最後にaddで画像データを重ね合わせる方法について紹介した。