OpenCV – アルファブレンドで画像を合成する方法

目次

概要

OpenCV で2枚の画像をアルファブレンド (alpha blend) して、合成する方法について紹介します。

アルファブレンド

アルファブレンド (alpha blend) とは、2枚の画像を係数 $\alpha \in [0, 1]$ を用いて、以下の式で合成する処理をいう。

$$ \text{dst}(x, y) = \text{src1}(x, y) \times \alpha + \text{src2}(x, y) \times (1 – \alpha) $$

この式は、2枚の入力画像 $\text{src1}, \text{src2}$ の画素値を $\alpha:1 – \alpha$ の割合で配合し、出力画像の画素値を生成することを意味します。 加算を行うため、2枚の入力画像の大きさは同じでなければなりません。

cv2.addWeighted

この関数は以下の計算を行います。

$$ \text{dst} = \text{src1} \times \alpha + \text{src2} \times \beta + \gamma $$

この関数で、$\beta = 1 – \alpha, \gamma = 0$ とすれば、アルファブレンドの式になります。

dst = cv2.addWeighted(src1, alpha, src2, beta, gamma[, dst[, dtype]])
引数
名前 デフォルト値
src1 ndarray
入力画像1
alpha ndarray
$\alpha$
src2 ndarray
入力画像2
beta ndarray
$\beta$
gamma ndarray
$\gamma$
返り値
名前 説明
dst 出力画像
In [1]:
import cv2
import numpy as np
from IPython.display import Image, display


def imshow(img):
    """ndarray 配列をインラインで Notebook 上に表示する。
    """
    ret, encoded = cv2.imencode(".jpg", img)
    display(Image(encoded))

すべての画素を同じアルファ値でブレンドする

sample1.jpg

sample2.jpg

In [2]:
# 入力画像を読み込む。
img1 = cv2.imread("sample1.jpg")
img2 = cv2.imread("sample2.jpg")
assert img1.shape == img2.shape, "画像の大きさは同じでなければならない"

alpha = 0.3
blended = cv2.addWeighted(img1, alpha, img2, 1 - alpha, 0)

imshow(blended)

画素によって異なるアルファ値でブレンドする

画素ごとにブレンドするアルファ値を変えることでグラデーションして合成ができます。

sample3.jpg

sample4.jpg

横方向にグラデーションする

形状が (1, Width, 1) で値が $[0, 1]$ に連続的に変化する配列を作っておくと、アルファブレンドした際に (Height, Width, Channels) にブロードキャストされて計算されます。

In [3]:
# 入力画像を読み込む。
img1 = cv2.imread("sample3.jpg")
img2 = cv2.imread("sample4.jpg")
assert img1.shape == img2.shape, "画像の大きさは同じでなければならない"

# アルファ値を作成する。
w = img1.shape[1]
alpha = np.linspace(0, 1, w).reshape(1, -1, 1)  # (1, W, 1)

dst = img1 * alpha + img2 * (1 - alpha)
imshow(dst)

縦方向にグラデーションする

形状が (Height, 1, 1) で値が $[0, 1]$ に連続的に変化する配列を作っておくと、アルファブレンドした際に (Height, Width, Channels) にブロードキャストされて計算されます。

In [4]:
# 入力画像を読み込む。
img1 = cv2.imread("sample3.jpg")
img2 = cv2.imread("sample4.jpg")
assert img1.shape == img2.shape, "画像の大きさは同じでなければならない"

# アルファ値を作成する。
w = img1.shape[0]
alpha = np.linspace(0, 1, h).reshape(-1, 1, 1)  # (H, 1, 1)

dst = img1 * alpha + img2 * (1 - alpha)
imshow(dst)

矩形外をグレーアウトする

アルファブレンドの応用例として、画像の注目領域以外をグレーアウトする例を示します。

入力画像の残す画素を 1、グレーアウトする画素を 0.5 で表したアルファ値を作成します。このアルファ値で入力画像と同じ大きさの黒の画像をアルファブレンドします。

In [5]:
# 入力画像を読み込む。
img1 = cv2.imread("sample2.jpg")
img2 = np.zeros_like(img1)

# 入力画像の残す画素を (1, 1, 1)、グレーアウトする画素を (0, 0, 0) で表したマスクを作成する。
h, w = img1.shape[:2]
alpha = np.full(img1.shape, 0.5, dtype=float)
cv2.rectangle(alpha, (100, 100), (250, 250), color=(1, 1, 1), thickness=-1)

dst = img1 * alpha + img2 * (1 - alpha)
imshow(dst)

コメント

コメントする

目次