目次
概要
OpenCV の cv2.distanceTransform()
で距離変換を行う方法について解説します。
画像における距離の定義
2 つの画素を $(x_1, y_1), (x_2, y_2)$ としたとき、距離関数には次の種類があります。
- $L^\infty$ ノルム: $\max(|x_1 – x_2|, |y_1 – y_2|)$
- $L1$ ノルム (マンハッタン距離): $|x_1 – x_2| + |y_1 – y_2|$
- $L2$ ノルム (ユークリッド距離): $\sqrt{(x_1 – x_2)^2 + (y_1 – y_2)^2}$
距離変換
距離変換 (distance transform) とは、2 値画像を入力として、各画素から最も近い画素値 0 までの距離を計算し、距離マップ (distance map) を作成する処理です。
cv2.distanceTransform
dst = cv2.distanceTransform(src, distanceType, maskSize[, dst[, dstType]])
公式リファレンス: cv2.distanceTransform
引数
名前 | 型 | デフォルト値 |
---|---|---|
src | ndarray | |
入力画像 (1チャンネル) | ||
distanceType | DistanceTypes | |
距離関数の種類
|
||
maskSize | int | |
距離変換に使用するマスクの大きさ | ||
dstType | DistanceTransformLabelTypes | cv2.DIST_LABEL_CCOMP |
値0の画素のラベル割当て方法
|
返り値
名前 | 説明 | ||
---|---|---|---|
dst | 距離画像 |
In [1]:
import cv2
import matplotlib.pyplot as plt
from IPython.display import Image, display
def imshow(img):
"""ndarray 配列をインラインで Notebook 上に表示する。"""
ret, encoded = cv2.imencode(".jpg", img)
display(Image(encoded))
In [2]:
# 画像を読み込む。
img = cv2.imread("sample1.jpg", cv2.IMREAD_GRAYSCALE)
# 2値化する
ret, img_bin = cv2.threshold(img, 20, 255, cv2.THRESH_BINARY)
# 距離変換する。
img_dist = cv2.distanceTransform(img_bin, cv2.DIST_L2, 5)
fig, ax = plt.subplots()
ax.imshow(img_dist)
plt.show()
セグメンテーションに利用する
2 値画像で接触している物体同士を分離したい場合などに、距離変換が活用できます。
In [3]:
# 画像を読み込む。
img = cv2.imread("sample2.jpg")
# グレースケールに変換する。
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 2値化する
ret, img_bin = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
imshow(img_bin)
この段階では、コインの端が接触しているため、輪郭抽出を行っても 1 枚ずつを別々の輪郭として認識できません。ここで、距離変換を用いて距離マップを作成し、その距離に応じて 2 値化することで、コインを 1 枚ずつ分離します。
In [4]:
# 距離変換する。
dist = cv2.distanceTransform(img_bin, cv2.DIST_L2, 5)
fig, ax = plt.subplots(figsize=(6, 6))
ax.imshow(dist)
plt.show()
# 距離を利用して2値化する。
ret, img_bin2 = cv2.threshold(dist, 0.5 * dist.max(), 255, cv2.THRESH_BINARY)
imshow(img_bin2)
参考文献
- デジタル画像処理 P191 9-2-8
コメント