Warning: Undefined variable $position in /home/pystyles/pystyle.info/public_html/wp/wp-content/themes/lionblog/functions.php on line 4897

OpenCV – マスク画像を利用した画像処理について

OpenCV – マスク画像を利用した画像処理について

概要

マスク画像とその使い道について解説します。

Advertisement

マスク画像

画像と同じ大きさの2値画像で、処理したい画素は255、そうでない画素は0をマスク画像 (mask image) といいます。マスク画像を使うことで、画像の一部の画素のみ対象に処理を行ったり、背景合成などに利用できます。

マスク画像

マスク画像の作り方

マスク画像は機械的または手動で作成します。

  • 機械的にマスク画像を作成する
    • 2値化などの方法で機械的に抽出する
    • 対象領域が図形の場合、cv2.rectangle()cv2.circle() などで塗りつぶして作成する
  • 手動でマスク画像を作成する
    • GIMP や Photoshop などのレイヤ機能があるペイントソフトで、元画像を背景に設定して作る

関連記事

マスク画像を利用して一部の画素のみ処理を行う

画像の中央部分以外にガウシアンフィルタを適用し、外縁部をぼやけさせる例を紹介します。

sample1.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))


# 画像を読み込む。
img = cv2.imread("sample1.jpg")

# マスク画像を作成する。
mask = np.full(img.shape[:2], 255, dtype=img.dtype)

# 白い画像の中心に黒い円を描画する。
cx = img.shape[1] // 2
cy = img.shape[0] // 2
cv2.circle(mask, (cx, cy), 150, color=0, thickness=-1)
imshow(mask)

# メディアンフィルタを適用する。
dst = cv2.blur(img, (9, 9))

# マスクの値が0の画素は処理を行わないので、元画像の画素値に戻す。
dst[mask == 0] = img[mask == 0]
imshow(dst)
Advertisement

マスク画像を利用して背景合成する

マスク画像を利用して背景を合成することをマスク合成 (mask compositing) といいます。

sample2.jpg

前景画像

sample3.jpg

背景画像

In [2]:
# 前景画像を読み込む。
fg_img = cv2.imread("sample2.jpg")

# 背景画像を読み込む。
bg_img = cv2.imread("sample3.jpg")

# HSV に変換する。
hsv = cv2.cvtColor(fg_img, cv2.COLOR_BGR2HSV)

# 2値化する。
bin_img = cv2.inRange(hsv, (0, 10, 0), (255, 255, 255))
imshow(bin_img)

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

# 面積が最大の輪郭を取得する
contour = max(contours, key=lambda x: cv2.contourArea(x))

抽出した輪郭は以下のようになっています。黒い画像を作成し、輪郭の内部を cv2.drawContours() で255に塗りつぶすことでマスク画像を作成します。

In [3]:
# マスク画像を作成する。
mask = np.zeros_like(bin_img)
cv2.drawContours(mask, [contour], -1, color=255, thickness=-1)
imshow(mask)

前景画像 fg_img を背景画像 bg_img に貼り付けます。 貼り付けた際に前景画像が背景画像にはみ出さないように調整します。

貼り付け処理

In [4]:
x, y = 10, 10  # 貼り付け位置

# 幅、高さは前景画像と背景画像の共通部分をとる
w = min(fg_img.shape[1], bg_img.shape[1] - x)
h = min(fg_img.shape[0], bg_img.shape[0] - y)

# 合成する領域
fg_roi = fg_img[:h, :w]  # 前傾画像のうち、合成する領域
bg_roi = bg_img[y : y + h, x : x + w]  # 背景画像のうち、合成する領域

# 合成する。
bg_roi[:] = np.where(mask[:h, :w, np.newaxis] == 0, bg_roi, fg_roi)
imshow(bg_img)

クロマキー合成

色情報を元にマスク画像を作成して背景を合成するマスク合成をクロマキー合成 (chromekey compositing) といいます。通常は、前景と背景を分離してマスク画像を作成しやすいように、緑を背景にして撮影します (グリーンバック)。 映画やニュース番組の撮影でよく使われる手法です。

sample4.jpg

前景画像

sample5.jpg

背景画像

HSV 色空間に変換し、cv2.inRange() で Hue の値に着目して、緑の領域とそれ以外の領域に分けます。 緑以外の領域を白としたマスク画像を作成したいので、cv2.inRange() の結果をネガポジ反転します。

In [5]:
# 画像を読み込む。
fg_img = cv2.imread("sample4.jpg")

# 背景画像を読み込む。
bg_img = cv2.imread("sample5.jpg")

# HSV に変換する。
hsv = cv2.cvtColor(fg_img, cv2.COLOR_BGR2HSV)

# 2値化する。
bin_img = ~cv2.inRange(hsv, (62, 100, 0), (79, 255, 255))

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

# 面積が最大の輪郭を取得する
contour = max(contours, key=lambda x: cv2.contourArea(x))

# マスク画像を作成する。
mask = np.zeros_like(bin_img)
cv2.drawContours(mask, [contour], -1, color=255, thickness=-1)
imshow(mask)
In [6]:
# 貼り付け位置
x, y = 30, 10

# 幅、高さは前景画像と背景画像の共通部分をとる
w = min(fg_img.shape[1], bg_img.shape[1] - x)
h = min(fg_img.shape[0], bg_img.shape[0] - y)

# 合成する領域
fg_roi = fg_img[:h, :w]
bg_roi = bg_img[y : y + h, x : x + w]

# 合成する。
dst = np.where(mask[:h, :w, np.newaxis] == 0, bg_roi, fg_roi)
imshow(dst)