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

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

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

概要

OpenCV の cv2.distanceTransform() で距離変換を行う方法について解説します。

Advertisement

画像における距離の定義

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]])
引数
名前 デフォルト値
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はすべて異なるラベルを割り当てる
返り値
名前 説明
edges 出力画像

sample1.jpg

In [1]:
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))


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

# グレースケールに変換する。
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 2値化する
ret, bin_img = cv2.threshold(gray, 20, 255, cv2.THRESH_BINARY)

# 距離変換する。
dist = cv2.distanceTransform(bin_img, cv2.DIST_L2, 5)


fig, ax = plt.subplots(figsize=(6, 6))
ax.imshow(dist, cmap="magma")

plt.show()
Advertisement

応用例

2値画像でくっつている物体同士を分離したい場合などに活用できます。

sample2.jpg

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

# グレースケールに変換する。
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 2値化する
ret, bin_img = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
imshow(bin_img)

この段階では、コインの端がくっついているため、このあと輪郭抽出を行っても1枚1枚を別々の輪郭として認識できません。 ここで、距離変換で距離マップを作成し、距離に応じて2値化することで1枚ごとに分離します。

In [3]:
# 距離変換する。
dist = cv2.distanceTransform(bin_img, cv2.DIST_L2, 5)

fig, ax = plt.subplots(figsize=(6, 6))
ax.imshow(dist, cmap="magma")
plt.show()

# 距離を利用して2値化する。
ret, bin_img2 = cv2.threshold(dist, 0.5 * dist.max(), 255, cv2.THRESH_BINARY)
imshow(bin_img2)

参考文献

  • デジタル画像処理 P191 9-2-8