Pynote

Python、機械学習、画像処理について

OpenCV - 画像の2値化について

概要

2値化 (Thresholding) とは、グレースケールの画像をある閾値を基準にして2つの領域に分割する処理 (Segmentation) である。
例えば、画像から文字の領域とそれ以外の背景の領域を分割したい場合などに用いられる。

キーワード

  • 画像2値化 (Image Thresholding, Binarization)
  • 画像分割 (Image Segmentation)

threshold()

OpneCV では、cv2.threshold() で行える。

ret, dst = cv2.threshold(src, dst, threshold, maxValue, thresholdType)
  • 引数
    • src: 入力画像
    • threshold: 閾値
    • maxValue: cv2.THRESH_BINARY, cv2.THRESH_BINARY_INV の場合に使用する
    • thresholdType: Thresholding の方式
  • 返り値
    • retval: 引数の threshold と同じ値
    • dst: Thresholding した結果

thresholdType は次の種類がある。

  • cv2.THRESH_BINARY

{\displaystyle
dst(x, y) =
\left\{ 
\begin{array}{l}
maxValue & src(x, y) > threshold \\
0 & otherwise
\end{array}
\right.
}

  • cv2.THRESH_BINARY_INV

{\displaystyle
dst(x, y) =
\left\{ 
\begin{array}{l}
0 & src(x, y) > threshold \\
maxValue & otherwise
\end{array}
\right.
}

  • cv2.THRESH_TRUNC

{\displaystyle
dst(x, y) =
\left\{ 
\begin{array}{l}
threshold & src(x, y) > threshold \\
src(x, y) & otherwise
\end{array}
\right.
}

  • cv2.THRESH_TOZERO

{\displaystyle
dst(x, y) =
\left\{ 
\begin{array}{l}
src(x, y) & src(x, y) > threshold \\
0 & otherwise
\end{array}
\right.
}

  • cv2.THRESH_TOZERO_INV

{\displaystyle
dst(x, y) =
\left\{ 
\begin{array}{l}
0 & src(x, y) > threshold \\
src(x, y) & otherwise
\end{array}
\right.
}

コード

各 thresholdType の src の値と dst の値の対応

# -*- coding: utf-8 -*-
import cv2
import numpy as np
import matplotlib.pyplot as plt

thresh = 150
maxval = 255
xs = np.arange(256)
ys_list = [np.where(xs > thresh, maxval, 0),   # cv2.THRESH_BINARY
           np.where(xs > thresh, 0, maxval),   # cv2.THRESH_BINARY_INV
           np.where(xs > thresh, thresh, xs),  # cv2.THRESH_TRUNC
           np.where(xs > thresh, xs, 0),       # cv2.THRESH_TOZERO
           np.where(xs > thresh, 0, xs)]       # cv2.THRESH_BINARY

# 結果をグラフに描写する
titles = ['BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']

fig, axes = plt.subplots(2, 3, figsize=(10, 6))
axes = axes.flatten()

fig.subplots_adjust(wspace=0.5, hspace=0.5)
fig.delaxes(axes[5])

for i in range(5):
    axes[i].plot(xs, ys_list[i])
    axes[i].set_title(titles[i])
    axes[i].set_xticks([0, thresh, 255]), axes[i].set_yticks([0, thresh, 255])
    axes[i].set_xlabel('src value'), axes[i].set_ylabel('dst value')

plt.savefig("binarization_02.png", bbox_inches="tight")

f:id:nekobean:20170730195259p:plain

cv2.threshold() の使用例
# -*- coding: utf-8 -*-
import cv2
import numpy as np
import matplotlib.pyplot as plt

# 画像をグレースケールとして読み込む
img = cv2.imread('sign.jpg', 0)

# Thresholding を実行する。
ret, thresh1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
ret, thresh2 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)
ret, thresh3 = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC)
ret, thresh4 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO)
ret, thresh5 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO_INV)

# 結果をグラフに描写する
titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC',
          'TOZERO', 'TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]

fig, axes = plt.subplots(2, 3, figsize=(10, 6))
axes = axes.flatten()
for i in range(6):
    axes[i].imshow(images[i], cmap='gray')
    axes[i].set_title(titles[i])
    axes[i].set_xticks([]), axes[i].set_yticks([])
plt.savefig("binarization_01.png", bbox_inches="tight")

f:id:nekobean:20170730194150p:plain