superpixelの代表的なアルゴリズムと実装について
superpixel(スーパーピクセル)とは,色やテクスチャが類似するピクセルをグルーピングした小領域のことである.
入力画像をsuperpixelに分割することで,色の類似画素の位置関係を反映した小領域に分割することが可能になる.
類似度に基づくピクセルの集合体であるため,それぞれのセグメントは物体認識や画像加工などの前処理に用いるのに適する.
superpixelには以下の四種類がある。
① Felzenszwalb の手法 *1
② Vedaldi の手法 (Quickshift 法) *2
③ Achanta の手法 (SLIC 法) *3
④ Neubert の手法 (Watershed 法) *4
これらを簡単に説明する。
① Felzenszwalb の手法
画像中のある二つの隣り合う分割領域間の相違度を計算し,それぞれの領域内の相違度より大きい場合,二つを異なる領域として扱う.逐次的に計算していくことで,全領域を分割する手法.
② Vedaldi の手法
カーネル密度推定の極値として定義されるクラスタ中心を探索する手法であり,3 つのステップで領域を分割する手法.
③ Achanta の手法
原画像をLab 表色系に変換し,色の類似度とその位置関係に基づいたクラスタリングをおこなう.分水線の距離に基づいたエネルギー最小化法によるセグメンテーションをおこなう手法.
④ Neubert の手法
画像の輝度勾配を山と谷の地形図に見立て、そこに水を流すイメージをした時に、水を貯める分水嶺(壁)を"輪郭"として判定する手法.
Pythonにおいて,scikit-imageにて上記四つのアルゴリズムは実装されている.
これを試してみる.
from skimage import io from skimage.segmentation import felzenszwalb, quickshift, slic, watershed, mark_boundaries from skimage.filters import sobel from skimage.color import rgb2gray import matplotlib.pyplot as plt img=io.imread("kumamon.jpg")#RGBの順番 #セグメント felzen_segments = felzenszwalb(img) quick_segments = quickshift(img) slic_segments = slic(img) water_segments = watershed(sobel(rgb2gray(img)), markers=250) #描画 plt.figure(figsize=(10, 10)) plt.rcParams["font.size"] = 15 plt.subplot(2, 2, 1) plt.title("Felzenszwalb") plt.imshow(mark_boundaries(img,felzen_segments)) plt.subplot(2, 2, 2) plt.title("quickshift") plt.imshow(mark_boundaries(img,quick_segments)) plt.subplot(2, 2, 3) plt.title("slic") plt.imshow(mark_boundaries(img,slic_segments)) plt.subplot(2, 2, 4) plt.title("watershed") plt.imshow(mark_boundaries(img,water_segments))
結果
パラメータのチューニング次第ではあるが,①・②・④の手法は全体的に複雑に状態を捉えすぎる傾向がある.
そのため,情景内画像から物体を絞り込みたいようなシチュエーションにおいてはSLIC法を用いるのが適切である.
この方法では,色やテクスチャ特徴の類似度をもつ領域に画素を分類していき,統合していくためある程度ラフに領域分割をおこなってくれる.
さまざまなパラメータを設定することができる.
SLIC法
slic(image, n_segments=100, compactness=10.0, max_iter=10, sigma=0, spacing=None, multichannel=True, convert2lab=None, enforce_connectivity=True, min_size_factor=0.5, max_size_factor=3, slic_zero=False)
試しにセグメント数を変えてみる.
slic_segments1 = slic(img,n_segments=20) slic_segments2 = slic(img,n_segments=50) slic_segments3 = slic(img,n_segments=80) slic_segments4 = slic(img,n_segments=100)
傾向としてセグメント数を少なくすると,前景領域と背景の大雑把な分離は可能で,
逆にセグメント数が多ければ同一物体におけるシェーディングや模様の違いも違うセグメントとして分離することができるようだ.
SLIC法は非常に便利な手法ではあるが,k平均法におけるパラメータを設定しないといけないので経験値が求められる.
パラメータを自動で推定するような研究もあるようだが*5,決定的な手法はまだないと思われる.
(知ってる方いれば教えてください_| ̄|○)
とにかく,スーパーピクセル使ってみましょう!!
*1:P. F. Felzenszwalb and D. P. Huttenlocher, “Efficient Graph-Based Image Segmentation,” International Journal of Computer Vision, Vol. 59, No. 2,2004.
*2:A. Vedaldi and S. Soatto, “Quick Shift and Kernel Methods for Mode Seeking,” European Conference on Computer Vision (ECCV), pp. 705– 718, 2008.
*3:R. Achanta, A. Shaji, K. Smith, A. Lucchi, P. Fua, and S.Süsstrunk, “SLIC Superpixels Compared to State-of-the-art Superpixel Methods,” IEEE Transactions on Pattern Analysis and Machine Intelligence, Vol. 34, pp. 2274–2282, 2012.
*4:P. Neubert and P. Protzel, “Compact Watershed and Preemptive SLIC : On Improving Trade-offs of Superpixel Segmentation Algorithms,” Inter- national Conference on Pattern Recognition (ICPR), pp. 996–1001, 2014.