【python-openCV】背景画像に別の画像を合成する方法!

f:id:yshgs_elec:20210316220044p:plain

 

この記事では以下の画像のように、

【左の画像】+【真ん中の画像の黒以外の領域】

という画像を作成する方法をご紹介します。

f:id:yshgs_elec:20210316205701j:plain

「こんなの簡単そうじゃん!」

と思ったそこのあなた。

 

これ作るの意外とめんどくさいんですよ。

その変わり、この画像を作成する過程で画像で様々なことを勉強できるはずです。

python初学者にとっては非常に勉強になる内容になっていると思います。

ぜひ最後までご覧ください。

 

それでは早速やっていきます!

スポンサーリンク

必要なライブラリ

◆openCV:Ver.4.5.1.48

 

使うのはopenCVだけですが、こいつはなかなか曲者でして、バージョンによって、コードの書き方が微妙に違うみたいです。

 

以降で紹介するコードが正常に動作しない場合、バージョン違いの影響である可能性がありますので、もしそのような状況に陥った場合は、バージョンを上記のものに合わせるか、あなたのバージョンに適した形にコードを修正してください。

 

スポンサーリンク

画像を合成する方法:cv2.add

サンプルコードの紹介に移る前に、今回紹介するスキルのキーポイントをご紹介します。

 

今回のように、openCVで画像を合成する場合、cv2.addというスキルを用います。

◆画像合成スキルcv2.addの使い方

完成後配列=cv2.add(画像1の配列, 画像2の配列)

 

使い方はこれだけ。

これで、2枚の画像のそれぞれのピクセルにおける輝度やBGR値、HSV値を合計した配列を作成することができます。

 

今回はこのcv2.addを使って、冒頭に紹介したような2枚の画像を合成したような画像を作成していきたいと思います。

 

キーポイントを理解できたところで、さっそくこのcv2,.addの実際の使い方をご紹介していきます。

 

※このcv2.addは合成する2枚の画像のサイズ(縦、横のピクセル数)が一致していないとうまく動作しません。

今回はあらかじめサイズのそろった画像を準備しているため、なにも特別な処理をしなくても動作しますが、あなたがもし違うサイズの画像を準備しているのであれば、まずはじめに2枚の画像のサイズを揃える作業が必要になります。

ご注意ください。

 

スポンサーリンク

画像を合成するサンプルコード

まずはじめによくある失敗例からご紹介します。

 

◆サンプルコード①

#ライブラリインポート
import cv2
#画像の読み込み⇒合成
pic1=cv2.imread('pic1.jpg',cv2.IMREAD_COLOR)
pic2=cv2.imread('pic2.jpg',cv2.IMREAD_COLOR)
pic3=cv2.add(pic2,pic1)
#画像の出力
cv2.imwrite('pic3.jpg',np.array(pic3))

 

コードを簡単に解説すると、単純に二枚の画像をcv2.imreadで読み込んで、先ほど紹介したcv2.addで合成しただけです。

こいつを実行すると以下の画像のようになります。

※pic1.jpgが左、pic2.jpgが真ん中、pic3.jpgが右です。

f:id:yshgs_elec:20210316211522j:plain

 一方、冒頭で説明した作りたかった画像は以下です。

f:id:yshgs_elec:20210316205701j:plain

なんか違いますよね。

 

先ほども説明しましたが、今回つかったcv2.addは各ピクセルのデータを単純に足し合わせただけのものです。

左の画像が比較的明るい(=輝度値が大きい)ので、真ん中の画像の明るい部分を足した結果、明るくなりすぎてしまったというわけです。

(真ん中の画像の周囲の黒い部分は輝度値がほぼゼロなので足しても何も変化はありません。)

 

つまり、今回のような画像を作ろうと思ったら、次のような手順を踏む必要があります。

※説明の都合上以下のようにそれぞれの画像をA、Bと呼ばせていただきます。

f:id:yshgs_elec:20210318204421j:plain

 

◆画像合成の手順

①Bの画像を二値化する(物体内部にも黒い場所はあるので以下の画像のようになる)

f:id:yshgs_elec:20210316213908j:plain

②①でつくった画像の輪郭を抽出する

③②で抽出した輪郭のうち、最大のものを選択する

(これで中心部の物体の外縁輪郭が取れる)

④③で選択した輪郭の内部を輝度255で塗りつぶす(以下の画像のようになる)

f:id:yshgs_elec:20210316213823j:plain

⑤Aの画像に対して、④の画像で白い場所はゼロ、黒場所は変化なし、という処理を行う。(以下の画像のようになる)

f:id:yshgs_elec:20210316214321j:plain

⑥もともとの画像Bと⑤で作った画像をcv2.addで合成する

f:id:yshgs_elec:20210316214403j:plain

 

これで完成です。

ほら、めちゃくちゃめんどくさいでしょ?

 

つまり冒頭では、以下のようなイメージ図で説明していましたが、

f:id:yshgs_elec:20210316205701j:plain

実際は以下のようなことを行っていたわけです。

f:id:yshgs_elec:20210316214823j:plain

 

処理の流れをイメージできたところで、最後にこの処理を実行してくれるサンプルコードをご紹介します。

 

◆最終的なサンプルコード

#ライブラリインポート
import cv2
#画像の読み込み
pic1=cv2.imread('pic1.jpg',cv2.IMREAD_COLOR)
pic2=cv2.imread('pic2.jpg',cv2.IMREAD_COLOR)
#二値化処理
pic2gray=cv2.imread('pic2.jpg',cv2.IMREAD_GRAYSCALE)
ret, thresh = cv2.threshold(pic2gray, 5, 255, cv2.THRESH_BINARY)
#輪郭抽出
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_LIST,cv2.CHAIN_APPROX_NONE)
max_cnt =max(contours, key=lambda x: cv2.contourArea(x))
#マスク画像の作成
pic2thresh = cv2.drawContours(pic2gray, [max_cnt], -1, 255, -1)
cv2.imwrite('pic2thresh2.jpg',np.array(pic2thresh))
#画像合成前処理
pic2[pic2thresh<255]=[0,0,0]
pic1[pic2thresh==255]=[0,0,0]
cv2.imwrite('pic2thres3.jpg',np.array(pic1))
#画像合成
pic3=cv2.add(pic1,pic2)
cv2.imwrite('add.jpg',np.array(pic3))

 

長いですね。

もしかしたらもっと簡単なやり方があるかもしれません。

知っている方がいればコメント欄から教えてください。 

 

スポンサーリンク

おわりに

というわけで今回はpython-openCVを使って、2枚の画像を重ね合わせたような画像を作成する方法をご紹介しました。

画像処理は様々な場面で役に立ちますので、ぜひひとつひとつ習得していきましょう。

 

このように私のブログでは様々なプログラミングスキルを紹介しています。

・もっと革新的なことをやりたい。

・プログラミングについてもっと詳しくなりたい。

こんな思いを持っている人は、ぜひ他の記事も見てみてくださいね。

 

この記事が役に立ったという方は、ぜひ応援よろしくお願いします。

 ↓ 応援ボタン

にほんブログ村 IT技術ブログへ
にほんブログ村

 

それではまた!

 

コメント

タイトルとURLをコピーしました