見出し画像

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を探してみます。
すると、

使った写真
UnsplashNational 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でもなく、すぐに実装可能であることがわかりました。

同じような画像、細胞、菌の顕微鏡画像、蛍光像をお持ちの方、
上のコードを活用して、画像認識させてみてください。

いいなと思ったら応援しよう!

この記事が参加している募集