Pynote

Python、機械学習、画像処理について

OpenCV - マスクを使用した画像の合成方法について

概要

マスクを使用した画像の合成方法について紹介する。

import cv2
import matplotlib.pyplot as plt
import numpy as np


def imshow(img):
    if img.ndim == 2:
        plt.imshow(img, cmap="gray")
    else:
        plt.imshow(img[..., ::-1])
    plt.axis("off")
    plt.show()

手順

背景画像及び前景画像を読み込む。

# 背景画像及び前景画像を読み込む。
background = cv2.imread("background.jpg")
foreground = cv2.imread("forground.png")

マスク画像を作成する。

前景画像のうち、合成する画素を白 (255, 255, 255)、そうでない画素を黒 (0, 0, 0) としたマスク画像を作成する。

# グレースケールに変換する。
gray = cv2.cvtColor(foreground, cv2.COLOR_BGR2GRAY)

# 2値化する。
_, binary = cv2.threshold(gray, 250, 255, cv2.THRESH_BINARY_INV)
imshow(binary)

2値化した画像を見てみると、コピーしたい画素が黒くなってしまっている箇所があるため、このあと輪郭抽出して輪郭の内部を白で塗りつぶす。

# 輪郭抽出する。
contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)


# 検出された輪郭内部を255で塗りつぶす。
mask = np.zeros_like(binary)
cv2.drawContours(mask, contours, -1, color=255, thickness=-1)

# 以上の手順で前景画像のうち、合成する画素を255としたマスク画像が作成できた。
imshow(mask)


背景画像と前景画像を合成する。

numpy.where() を使用する。
numpy.where() はマスクの値が255の要素は前景画像 foreground の値、マスクの値が0の要素は背景画像 background の値を返す。

h, w = foreground.shape[:2]  # 前景画像の大きさ
x, y = 100, 200  # 背景画像の座標上で前景画像を貼り付ける位置
roi = background[y : y + h, x : x + w, :]
result = np.where(np.expand_dims(mask == 255, -1), foreground, roi)

imshow(result)