概要
モルフォロジー演算について解説し、OpenCV でモルフォロジー演算を行う方法を紹介します。モルフォロジー演算は、二値画像からノイズを削除したり、輪郭を抽出するのに役立ちます。
モルフォロジー演算
以下の手順で行うフィルタリング処理をモルフォロジー演算 (morpology operation) といいます。
- 構成要素 (structuring element) またはカーネル (kernel) という入力画像の走査を行うための各要素が0または1で構成された2次元の行列を用意します。通常は 3×3、5×5 など小さい形状のものが使用されます。
- カーネルの原点 (origin) またはアンカー (anchor) と呼ばれる成分 (図の赤マス) を入力画像の画素に合わせて左上から右下にかけてスライドさせ、出力画像の画素を計算していきます。
カーネルの値が1の成分 (青のマス) は、走査対象の画素 (赤のマス) の近傍を表します。例えば、モルフォロジー演算の一種である膨張演算では、近傍の最大値を対応する出力画像の画素にします。
この処理をすべての画素で行うと以下のようになります。 膨張演算により、入力画像の白の線が太くなりました。
カーネルの作成
2次元配列を自分で定義するか、cv2.getStructuringElement()
を使用して作成します。
cv2.getStructuringElement
retval = cv2.getStructuringElement(shape, ksize[, anchor])
名前 | 型 | デフォルト値 |
---|---|---|
shape | MorphShapes | |
近傍とする形状
|
||
ksize | tuple | |
カーネルの大きさ | ||
anchor | tuple | (-1, -1) |
アンカー成分。(-1, -1) の場合はカーネルの中心。 |
名前 | 説明 | ||
---|---|---|---|
dst | カーネル |
import cv2
import numpy as np
from IPython.display import Image, display
from matplotlib import pyplot as plt
def imshow(img):
"""ndarray 配列をインラインで Notebook 上に表示する。
"""
ret, encoded = cv2.imencode(".jpg", img)
display(Image(encoded))
rect_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
cross_kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))
ellipse_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
print("cv2.MORPH_RECT", rect_kernel, sep="\n")
print("cv2.MORPH_CROSS", cross_kernel, sep="\n")
print("cv2.MORPH_ELLIPSE", ellipse_kernel, sep="\n")
cv2.MORPH_RECT [[1 1 1 1 1] [1 1 1 1 1] [1 1 1 1 1] [1 1 1 1 1] [1 1 1 1 1]] cv2.MORPH_CROSS [[0 0 1 0 0] [0 0 1 0 0] [1 1 1 1 1] [0 0 1 0 0] [0 0 1 0 0]] cv2.MORPH_ELLIPSE [[0 0 1 0 0] [1 1 1 1 1] [1 1 1 1 1] [1 1 1 1 1] [0 0 1 0 0]]
モルフォロジー演算の種類
膨張
膨張 (dilation) 演算とは、走査対象の画素を近傍で最も大きい画素値に置き換えるモルフォロジー演算です。
位置 $(x, y)$ の入力画像の画素を $\text{src}(x, y)$、対応する出力画像の画素を $\text{dst}(x, y)$、カーネルの画素を $k(x’, y’)$ とたとき、次の式で表せます。
$$ \text{dst}(x, y) = \max_{k(x’, y’) \ne 0} \text{src}(x + x’, y + y’)] $$cv2.dilate
dst = cv2.dilate(src, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]])
名前 | 型 | デフォルト値 |
---|---|---|
src | ndarray | |
入力画像 | ||
kernel | ndarray | |
カーネル | ||
anchor | tuple | (-1, -1) |
アンカー成分。(-1, -1) の場合はカーネルの中心。 | ||
iterations | int | 1 |
適用回数 | ||
borderType | BorderTypes | cv2.BORDER_CONSTANT |
パディング方法。デフォルトはゼロパディング。 | ||
borderValue | int | 0 |
BorderTypes=cv2.BORDER_CONSTANT の場合の値 |
名前 | 説明 | ||
---|---|---|---|
dst | 出力画像 |
サンプルコード
# 画像をグレースケール形式で読み込む。
img = cv2.imread("sample1.jpg", cv2.IMREAD_GRAYSCALE)
# カーネルを作成する。
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
# 2値画像を収縮する。
dst = cv2.dilate(img, kernel)
imshow(dst)
膨張演算を行うと入力画像の線が太くなります。 2値化やエッジ抽出した結果、輪郭の線が途切れている場合に膨張演算を行うことで線を繋げたい場合に活用できます。
収縮
収縮 (erosion) 演算とは、走査対象の画素を近傍で最も小さい画素値に置き換えるモルフォロジー演算です。
位置 $(x, y)$ の入力画像の画素を $\text{src}(x, y)$、対応する出力画像の画素を $\text{dst}(x, y)$、カーネルの画素を $k(x’, y’)$ とたとき、次の式で表せます。
$$ \text{dst}(x, y) = \min_{k(x’, y’) \ne 0} \text{src}(x + x’, y + y’)] $$cv2.erode
dst = cv2.erode(src, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]])
名前 | 型 | デフォルト値 |
---|---|---|
src | ndarray | |
入力画像 | ||
kernel | ndarray | |
カーネル | ||
anchor | tuple | (-1, -1) |
アンカー成分。(-1, -1) の場合はカーネルの中心。 | ||
iterations | int | 1 |
適用回数 | ||
borderType | BorderTypes | cv2.BORDER_CONSTANT |
パディング方法。デフォルトはゼロパディング。 | ||
borderValue | int | 0 |
BorderTypes=cv2.BORDER_CONSTANT の場合の値 |
名前 | 説明 | ||
---|---|---|---|
dst | 出力画像 |
サンプルコード
# 画像をグレースケール形式で読み込む。
img = cv2.imread("sample2.jpg", cv2.IMREAD_GRAYSCALE)
# カーネルを作成する。
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
# 2値画像を収縮する。
dst = cv2.erode(img, kernel)
imshow(dst)
収縮演算を行うと入力画像の白い領域が小さくなります。2値化後にゴマ粒ノイズを削除したい場合に活用できます。
オープニング
オープニング (Opening) は収縮を $n$ 回行った後に膨張を $n$ 回行います。ノイズ削除に利用されます。
# 画像をグレースケール形式で読み込む。
img = cv2.imread("sample3.jpg", cv2.IMREAD_GRAYSCALE)
# カーネルを作成する。
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
# 2値画像を収縮する。
dst = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel, iterations=2)
imshow(dst)
クロージング
クロージング (Closing) は膨張を $n$ 回行った後に収縮を $n$ 回行います。穴を埋めるのに利用されます。
# 画像をグレースケール形式で読み込む。
img = cv2.imread("sample4.jpg", cv2.IMREAD_GRAYSCALE)
# カーネルを作成する。
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
# 2値画像を収縮する。
dst = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel, iterations=2)
imshow(dst)
モルフォロジー勾配
モルフォロジー勾配 (morphology gradient) は $n$ 回膨張した結果から $n$ 回収縮した結果を減算する演算です。エッジ抽出に利用されます。
# 画像をグレースケール形式で読み込む。
img = cv2.imread("sample5.jpg", cv2.IMREAD_GRAYSCALE)
# カーネルを作成する。
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
# 2値画像を収縮する。
dst = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel, iterations=2)
imshow(dst)
ブラックハット
ブラックハット (black hat) は入力画像とクロージングの結果の差をとる演算です。
# 画像をグレースケール形式で読み込む。
img = cv2.imread("sample6.jpg", cv2.IMREAD_GRAYSCALE)
# カーネルを作成する。
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
# 2値画像を収縮する。
dst = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel, iterations=2)
imshow(dst)
トップハット
トップハット (top hat) は入力画像とオープニングの結果の差をとる演算です。
# 画像をグレースケール形式で読み込む。
img = cv2.imread("sample7.jpg", cv2.IMREAD_GRAYSCALE)
# カーネルを作成する。
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
# 2値画像を収縮する。
dst = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel, iterations=2)
imshow(dst)
コメント
コメント一覧 (0件)
[…] […]