StarDistで細胞画像をセグメンテーション
はじめに
AIでの画像処理が最近話題を呼んでいます。その一つにセグメンテーションという画像認識技術があります。
セグメンテーションは何をするのか、というと、画像に映りこんでいる被写体がそれぞれ何か、を識別して可視化してくれる技術です。その応用として期待されているのが、医療画像認識になります。
その一つとして、顕微鏡画像から、各細胞や菌を識別するために開発されたのが、StarDistというライブラリになります。
StarDist、言葉のように、StarDist convex 星突モデル、を使っています。
それは、各細胞の形を認識するのに、星と凸、という2つの形状モデルで判別するという手法です。
では、なぜ医療関係者でもない私がそのモデルに興味を持ったのか?というと、透過電子顕微鏡(TEM)の粒子解析をしたく、粒子のセグメンテーション (segmentation) を探していて出会いました。
さらにこのモデル、Pythonなどで簡単に実装が可能で、ソースコードもGithubで公開されています。
StarDist Github でGoogle検索すると、以下のようなリンクが出てきます。
こんな感じで、菌や細胞ごとに色分けしてくれ、白黒、カラー、2D、3Dと幅広く対応が可能です。
紹介動画
使い方は、こちらの動画がわかりやすいです。
コードもこちらをほぼ使っています。
環境
Tensorflowが入っている環境で動作させるとのことです。
Google colabでしたら、すでにインストールされているので、こちらで試してみます。
確認したい場合は
pip show tensorflow
でインストールされているか確認してください。
StarDist自体は
pip install stardist
でインストールが可能です。
学習済みモデル
今用意されている学習済みモデルは4種類
大きくGray scale用とRGB用に分かれています。
上をGoogle colab上で確認するなら
StarDist2D.from_pretrained()
で確認が可能です。
There are 4 registered models for 'StarDist2D':
Name Alias(es)
──── ─────────
'2D_versatile_fluo' 'Versatile (fluorescent nuclei)'
'2D_versatile_he' 'Versatile (H&E nuclei)'
'2D_paper_dsb2018' 'DSB 2018 (from StarDist 2D paper)'
'2D_demo' None
と表示されるかと思います。
テスト
テストするだけなら
# improt library
from stardist.models import StarDist2D
from stardist.data import test_image_nuclei_2d
from stardist.plot import render_label
from csbdeep.utils import normalize
import matplotlib.pyplot as plt
# Loading Pre-trained model
model = StarDist2D.from_pretrained('2D_versatile_fluo')
# test image loading
img = test_image_nuclei_2d()
# show test image and prediction
labels, _ = model.predict_instances(normalize(img))
plt.figure(figsize=(8, 16))
plt.subplot(1,2,1)
plt.imshow(img, cmap='gray')
plt.axis('off')
plt.title('input image')
plt.subplot(1,2,2)
plt.imshow(render_label(labels, img=img))
plt.axis('off')
plt.title('prediction + input image overlay')
テストで用意されている画像がこちら。
で以下のような解析結果が表示されます。結構よい精度で認識できています。
自分の画像でテスト グレースケール
では自分の画像でテストしてみます。
といっても細胞像はもっていないので、ネットからFreeを探してみます。
すると、
使った写真
UnsplashのNational Cancer Instituteが撮影した写真
が見つかりました。
細胞の蛍光像です。
グレースケールでの解析
画像はRGBなので、Skimageのrgb2grayでグレースケール変換してください。
その後、上のプログラムで実行してみます。
その結果がこちら
パット見は見えているのか、居ないのか判別がつきません。
分散していないのがいけないのでしょうか。
元は変更できないので、細かい粒子(細胞)が見えるように、
任意のエリアを拡大抽出してみます。
# smaller crop
my_img_small = my_img_gray[500:800, 500:800]
plt.figure(figsize=(8, 8))
plt.imshow(my_img_small)
plt.axis('off')
画像の表示もさせています。
こちらの画像を同様に解析してみました。
結果がこちら
やはり小さい粒子を認識している様子です。
Polygon
この画像を今のモデルで認識するには難しいかと思われるので、こちらをPolygon表示してみます。
from scipy.sparse import coo
from stardist import random_label_cmap, _draw_polygons, export_imagej_rois
import numpy as np
np.random.seed(1234)
lbl_cmap = random_label_cmap()
plt.figure(figsize=(13,10))
img_show = my_img_small if my_img_small.ndim==2 else my_img_small[...,0]
coord, points, prob = my_img_small_details['coord'], my_img_small_details['points'], my_img_small_details['prob']
plt.subplot(121)
plt.imshow(img_show, cmap='gray')
plt.axis('off')
a = plt.axis()
_draw_polygons(coord, points, prob, show_dist=True)
plt.axis(a)
plt.subplot(122)
plt.imshow(img_show, cmap='gray')
plt.axis('off')
plt.imshow(my_img_small_labels, cmap=lbl_cmap, alpha=0.5)
plt.tight_layout()
plt.show()
こちらのコードを実行してみてください。
結果は以下のようになります。
RGB画像
RGBは 2D_versatile_he ですので、こちらで
HE_model = StarDist2D.from_pretrained('2D_versatile_he')
he_labels, _ = HE_model.predict_instances(normalize(my_img))
plt.rcParams['figure.figsize'] = (20, 10)
plt.subplot(1,2,1)
plt.imshow(my_img)
plt.axis('off')
plt.title('input image')
plt.subplot(1,2,2)
plt.imshow(he_labels)
plt.axis('off')
plt.title('prediction')
得られた画像がこちら
やはり小さい粒子を認識しています。
2D_paper_dsb2018
こちらでもやってみましょう。
Grayscale用ですので、以前の画像が使えます。
dsb2018 = StarDist2D.from_pretrained('2D_paper_dsb2018')
dsb2018_labels, dsb2018_details = dsb2018.predict_instances(normalize(my_img_gray))
plt.rcParams['figure.figsize'] = (20, 10)
plt.subplot(1,2,1)
plt.imshow(my_img_gray)
plt.axis('off')
plt.title('input image')
plt.subplot(1,2,2)
plt.imshow(dsb2018_labels)
plt.axis('off')
plt.title('prediction')
結果はこちら
先ほどより粒子数は増えましたが、基本的には大きい細胞を認識できていません。
2D_paper_dsb2018 + test image
気になるので最後テスト画像でチャレンジしてみました。
すでにイメージ取得しているので、以下のコードを実行します。
dsb2018_labels_test, dsb2018_details_test = dsb2018.predict_instances(normalize(img))
plt.rcParams['figure.figsize'] = (20, 10)
plt.subplot(1,2,1)
plt.imshow(img)
plt.axis('off')
plt.title('input image')
plt.subplot(1,2,2)
plt.imshow(dsb2018_labels_test)
plt.axis('off')
plt.title('prediction')
得られた結果がこちら
しっかり認識できています。
画像の選択や、処理も重要かもしれません。
最後に
StarDistを試してみました。
学習済みモデルでは、やはりできることに制限があります。
必要なデータでは、特化した学習をする、画像のアノテーションをする必要がありそうです。
次は、そちらについて学んで報告したいと思います。
ただほんの数行で、写真のような細胞(菌)の画像はセグメンテーションできます。
有用なライブラリのようです。
U-NetのようなDNNでもなく、すぐに実装可能であることがわかりました。
同じような画像、細胞、菌の顕微鏡画像、蛍光像をお持ちの方、
上のコードを活用して、画像認識させてみてください。