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, hierarchy = cv2.findContours(
    binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)


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

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


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

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

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

imshow(result)