1
3

More than 1 year has passed since last update.

openCVで画像を合成する

Posted at

はじめに

openCVを使って、正式にはアルファブレンドと呼ばれる画像の合成のやり方を学んだのでメモ。

画像の合成は実用面で言うと、例えば超解像タスクでTTA(Test Time Augmentation)の一種で、何枚かの画像を合成してスコアを上げるGeometric Self-ensembleとして論文でも紹介されていたりします。

詳しくはコチラの論文を。

サンプル画像

以下の4枚の画像を使います。
建物、森、氷河、海の画像です。

download.png

cv2.addWeightedを使う

画像の合成自体はopenCVを使えば実装自体は非常に簡単でcv2.addWeightedを使用すれば良いです。

必要なものをインポートして

インポート
import cv2
import matplotlib.pyplot as plt

いちいち画像パス書いて、読み込みしてみたいなのを書くのはめんどくさいので
画像をカラー画像として読み込むとこまで一連の関数にします

RGB画像としてopencvで読み込み
def read_img_to_rgb(image_path):
    img = cv2.imread(image_path)
    img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

    return img_rgb

PILの方がRGBの順番など気にしなくて良いですけどね、、、

同じくplt.imshowでいちいち表示したりするのは面倒なので、画像を表示する関数も設定します。

画像を表示する関数
def show_img(img):
    plt.imshow(img)
    plt.axis('off')

4つの画像を読み込みます。

building_img = read_img_to_rgb('building.jpg')
forest_img = read_img_to_rgb('forest.jpg')
sea_img = read_img_to_rgb('sea.jpg')
glacier_img = read_img_to_rgb('glacier.jpg')

下準備はできたので、画像の合成を行っていきます。
例えば海と森の画像を合成するコードは以下になります。

sea_forest_img = cv2.addWeighted(src1=sea_img, alpha=0.5, src2=forest_img, beta=0.5, gamma=0)

引数の説明をします。
src1, src2はそれぞれ合成したい画像
alpha, betaは2枚の画像をどれだけの割合で合成するか(alpha : betaの割合で合成する)
gammaは全ての画素値に加えられる数。

以下の式に従ってそれぞれの画素値を計算している。

$$ dst = src1 × alpha + src2 × beta + gamma $$

上記コードを実行してできた画像が以下。

download.png
今回画素値は0~255までの離散値を取るため、上記計算式での計算結果の小数点以下は丸められてます。
より正確に合成するならfloat32型にして、0~1の範囲で正規化して合成すると良いと思う。

ここでなんとなくalphaとbetaの合計は1じゃないといけない気もするがそれは間違い。
alpha=1/4, beta=1/4でやってみると以下。

download.png

ちょっと暗くなりましたね。要は上記計算式の計算結果が0以下の数値は0に設定され、255以上の数値は255になるだけです。

なのでalpha=10, beta=10とかってすると
download.png
ほぼ全ての画素値が255を超えるため255に設定され真っ白に近くなります。

alpha=-1, beta=-1なら
download.png

全ての画素値がマイナスになるので全て0に設定されるため、真っ黒になりますね。

ただ画素値の範囲が0〜255なのか0~1なのかとかによって変わるのでそこだけ注意。

4枚の画像を均等に合成する

2枚の画像を均等に合成するならalphaとbetaを0.5に設定すれば良いですが、4枚の画像を均等に合成するにはどうすれば良いでしょうか。

正直自分もやり方が正しいか不安なところですが2枚ずつ1/4の割合で合成して、再度出来上がった2枚を1:1で合成するやり方でいけます。

sea_forest_img = cv2.addWeighted(sea_img, 1/4, forest_img, 1/4, 0)

glacier_and_building = cv2.addWeighted(glacier_img, 1/4, building_img, 1/4, 0)

all_combined_img = cv2.addWeighted(sea_forest_img, 1, glacier_and_building, 1, 0)
海と森の合成画像

download.png

氷河と建物の合成画像

download.png

4枚全て混ぜた画像

download.png

これを応用すれば8枚を均等に合成したりとかもできたりすると思います。

まとめ

cv2.addWeightedを使ったアルファブレンドの使い方について紹介しました。超解像の分野ではよく使う処理だと思うので、覚えておきたいです。

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3