scikit-image における Thresholdingについて

おはこんばんちは!

早速ですが、みなさんはscikit-image使っていますか?
画像処理を行うとなると、どうしてもOpenCV一強になりがちですが、
実はscikit-imageも特徴量や認識に関するライブラリが多数あるので、ぜひ活用してみてください。

その中でも今回は、閾値処理に焦点を当てていきたいと思います。

scikit-imageの閾値処理は10個の手法が用意されています。
(Module: filters — skimage v0.15.dev0 docs)

  • Otsu

  • Yen

  (最大相関値に基づいた二値化)

  • Isodata

  • Local

  (ローカルピクセル近傍に基づいて閾値マスク画像を計算)

  • Li

  (元画像と2値化画像間の交差エントロピーが最小となるように,2値化値を選択する)

  • Minimum

  (入力画像のヒストグラムは、2つの最大値が得られるまで計算され、平滑化される。 そのときの最小値が閾値となる)

  • Mean

  (グレースケール値の平均に基づいて閾値を計算する)

  • Niblack

  • Sauvola

  • Triangle

メジャーなものからマイナーなものまで用意されていますが、何を使ったらいいかわからない人におすすめなのが try_all_threshold です。
これは、先ほどの閾値手法のうち、

  • Isodata
  • Li
  • Mean
  • Minimum
  • Otsu
  • Triangle
  • Yen


の処理をまとめておこない、結果を見ることができるメソッドです。

from skimage.filters import try_all_threshold
from skimage import io
img = io.imread('lena.png',True)#read grayScale
fig, ax = try_all_threshold(img, figsize=(10,8), verbose=False)

f:id:dr_takuya:20180819204355p:plain

個別に行いたい場合は、

from skimage import io
import matplotlib.pyplot as plt
from skimage.filters import threshold_isodata
img = io.imread('lena.png',True)
isodata_thresh =threshold_isodata(img)#Return thresh
binary = img > isodata_thresh
plt.imshow(binary,cmap=plt.cm.gray)

これらの処理は閾値を値として返すので、それらをヒストグラムにプロットしてあげると

from skimage import io
import matplotlib.pyplot as plt
from skimage.filters import threshold_isodata
from skimage.filters import threshold_minimum
from skimage.filters import threshold_yen

img = io.imread('lena.png',True)
isodata_thresh =threshold_isodata(img)#isodata method
minimum_thresh =threshold_minimum(img)#minimum method
yen_thresh =threshold_yen(img)#minimum method

plt.hist(img.ravel()*255,range(0,255))
plt.axvline(x=isodata_thresh*255,c='r',label="isodata")
plt.axvline(x=minimum_thresh*255,c='k',label="minimum")
plt.axvline(x=yen_thresh*255,c='b',label="yen")
plt.legend()

f:id:dr_takuya:20180819211503p:plain

閾値手法の比較が行えますね。