OpenCV – distanceTransform で距離変換を行う方法

目次

概要

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
距離関数の種類
  • cv2.DIST_C: $L^\infty$ ノルム
  • cv2.DIST_L1: $L1$ ノルム (マンハッタン距離)
  • cv2.DIST_L2: $L2$ ノルム (ユークリッド距離)
maskSize int
距離変換に使用するマスクの大きさ
dstType DistanceTransformLabelTypes cv2.DIST_LABEL_CCOMP
値0の画素のラベル割当て方法
  • cv2.DIST_LABEL_CCOMP: 0はすべて同じ値を割り当てる
  • cv2.DIST_LABEL_PIXEL: 0はすべて異なるラベルを割り当てる
返り値
名前 説明
dst 距離画像

sample1.jpg

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 値画像で接触している物体同士を分離したい場合などに、距離変換が活用できます。

sample2.jpg

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

コメント

コメントする

目次