画像のセグメンテーション - Level set 法の実装 (Chan-Vese) -

画像処理のセグメンテーションの分野で用いられるLevel set 法を用いて画像のセグメンテーションを行います.

目次

セグメンテーションとは

画像のセグメンテーションとは,画像から注目している領域を切り取る ということです.例えば,細胞の画像が与えられたとき,その画像から細胞部分と背景部分とを区別することは,非常に重要です.

一見,二値化すれば終わりのように思いますが,画像処理の分野では,画像にノイズが含まれる場合を考慮する必要があり,簡単にはいきません. ここで力を発揮するのが,画像のセグメンテーションです.

画像のセグメンテーションには,いくつか手法があります.

ここではその中でも,Level set 法と呼ばれる方法を紹介したいと思います.

Level set 法

Level set 法とは,Osher やSethean によって開発された,セグメンテーションの枠組みです.この枠組みでは,領域の内部,外部をLevel set 関数と呼ばれる陰関数$\phi$の符号によって表現します. 具体的には

\begin{equation} \phi(r,t) < 0 \ \ r \in \Omega \end{equation}

\begin{equation} \phi(r,t) =0 \ \ r \in \partial \Omega
\end{equation} \begin{equation} \phi(r,t) >0 \ \ r \notin \Omega \end{equation}

とします.Level set 関数には,領域の個数などの事前情報が必要ないといったメリットがあります.

Level set 法の更新則

ここで更新の仕方をざっと説明したいと思います.

\begin{align} \phi(r+dr,t+dt) - \phi(r,t) = 0 \end{align} \begin{align} \therefore \ \frac{\partial \phi}{\partial t} + v\cdot \nabla \phi =0 \end{align}

この式はHamilton-Jacobi 方程式と呼ばれ,様々なところで目にすると思います.

ここで,上の$v$は更新速度であり,評価関数の微分によって計算されます.

実装

大まかな理論に関して説明したところで,具体的に画像のセグメンテーションを行いましょう. 今回は,Github で公開されていた,Python のプログラムを用いてみます.

Chan-Vese level sets in Python

Chan-Vese Level set では以下のコスト関数を最小化します.

\begin{align} E(C) = \mu_1 \int_{\rm inside} |I(x,y)-c_1|dxdy + \mu_2 \int_{\rm outside} |I(x,y)-c_2|dxdy + \alpha \kappa \end{align}

この式の意味は

です.つまり,内部と外部の輝度値を決めておくことで,外部の輪郭の抽出ができるということですね.

それでは,上のコードを用いて,画像のセグメンテーションをしてみましょう.

基本的にはchanvase.py を実行すれば可能なのですが,convergenceの関数のところで,以下のように修正しました.
# Convergence Test
def convergence(p_mask, n_mask, thresh, c):
    diff = np.array(p_mask.astype(np.int)) - np.array(n_mask.astype(np.int)) ## modified
    n_diff = np.sum(np.abs(diff))
    if n_diff < thresh:
        c = c + 1
    else:
        c = 0
    return c
コードサンプル (上のサイトから少し修正).py
もし,パッケージなどでエラーがあれば,以下のようにパッケージをインストールしてみてください.私は,scipy の方で
ImportError: dlopen(/usr/local/lib/python2.7/site-packages/scipy/special/_ufuncs.so, 2): Library not loaded: /usr/local/opt/gcc/lib/gcc/5/libquadmath.0.dylib
  Referenced from: /usr/local/lib/python2.7/site-packages/scipy/special/_ufuncs.so
  Reason: image not found
Error1
のようなエラーがあったので,以下の方法で対処しました.
sudo pip install --upgrade --force-reinstall scipy
solve

実行結果

python chanvese.py
iteration: 0
iteration: 50
iteration: 100
iteration: 150
iteration: 200
iteration: 250
iteration: 300
iteration: 350
iteration: 400
iteration: 450
iteration: 500
iteration: 550
iteration: 600
iteration: 650
iteration: 700
iteration: 750
iteration: 800
iteration: 850
iteration: 900
iteration: 950
update

上のコードをそのまま実行しました.

うまく動いているようですね!

Rice 画像のセグメンテーション

Rice 画像

それでは,別の画像でSegmentation を行ってみましょう.
今回使うのはImageJのサンプルの,Rice 画像です.
コードを以下のように変更して,セグメンテーションを行います.
if __name__ == "__main__":
    img = nd.imread('./../rice.png', flatten=True)
    mask = np.zeros(img.shape)
    shp = img.shape
    mask[30:shp[0]-30, 30:shp[1]-30] = 1 ##modified

    chanvese(img, mask, max_its=1000, display=True, alpha=1.0)
コードサンプル.py

初期値

150回の更新

300回の更新

最終的な値

参考文献