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 出力画像

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

sample1.jpg

sample2.jpg

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))
In [2]:
def alpha_blend(img1, img2, alpha):
    dst = cv2.addWeighted(img1, alpha, img2, 1 - alpha, 0)

    return dst


img1 = cv2.imread("sample1.jpg")
img2 = cv2.imread("sample2.jpg")
assert img1.shape == img2.shape, "2つの画像のサイズが異なります。"

dst = alpha_blend(img1, img2, 0.5)
imshow(dst)

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

画素ごとに異なるアルファ値を用いることで、グラデーションを利用した合成が可能になります。

sample3.jpg

sample4.jpg

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

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

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

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

    return dst


img1 = cv2.imread("sample3.jpg")
img2 = cv2.imread("sample4.jpg")
assert img1.shape == img2.shape, "画像の大きさは同じでなければならない"

dst = alpha_blend_horizontal(img1, img2)
imshow(dst)

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

形状が (height, 1, 1) で、値が $[0, 1]$ の範囲で連続的に変化する配列を作成すると、アルファブレンドを行う際にこの配列が (height, width, channels) にブロードキャストされ、計算が行われます。

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

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

    return dst


img1 = cv2.imread("sample3.jpg")
img2 = cv2.imread("sample4.jpg")
assert img1.shape == img2.shape, "画像の大きさは同じでなければならない"

dst = alpha_blend_vertical(img1, img2)
imshow(dst)

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

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

まず、入力画像の残す画素に対してはアルファ値を 1、グレーアウトする画素に対してはアルファ値を 0.5 とします。このアルファ値を用いて、入力画像と同じ大きさの黒い画像をアルファブレンドします。

In [5]:
def alpha_blend_rect(img, p1, p2):
    # 入力画像の残す画素を (1, 1, 1)、グレーアウトする画素を (0, 0, 0) で表したマスクを作成する。
    img2 = np.zeros_like(img)
    alpha = np.full(img.shape, 0.5, dtype=float)
    cv2.rectangle(alpha, p1, p2, color=(1, 1, 1), thickness=-1)

    dst = img * alpha + img2 * (1 - alpha)

    return dst


img = cv2.imread("sample2.jpg")
dst = alpha_blend_rect(img, (100, 100), (250, 250))
imshow(dst)

コメント

コメントする

目次