🦔

【画像解析】Cellposeで顕微鏡写真から細胞をセグメンテーション1

2023/08/01に公開

Cellposeは機械学習を用いて細胞のような小単位を1つずつ分離(セグメンテーション)するツールである。
https://www.cellpose.org/

この記事ではCellposeのインストールから学習済みモデルでのセグメンテーション、自身のデータに合わせた再学習方法を紹介する。

なおWindows 11での検証となる。

Anacondaを事前にインストールしておき、Anaconda Promptを使える環境を用意しておく必要がある。

https://www.anaconda.com/download

【インストール】

以下の公式ページを参考にCellpose version 2.0のインストールを進める。

https://github.com/mouseland/cellpose
https://pypi.org/project/cellpose/

Cellpose用の仮想環境作成

Anaconda promptを立ち上げて、次のコマンドでcellposeという名前の仮想環境を作成する。※ GitHubにpython versionの3.8が推奨とあるのでv3.8を指定しているが、v3.8以降でもうまくいくみたい。

conda create --name cellpose python=3.8
インストール中の画面

途中でダウンロードを実行するか聞かれるので、yを打ち込む。

インストール画面

インストール画面 終了時

Cellposeパッケージのインストール

まずはcellpose仮想環境に入る。

conda activate cellpose

そして、cellpose仮想環境にcellposeをインストールする。

python -m pip install cellpose
インストール中の画面


開始画面:必要な関連パッケージのダウンロードが始まる。


終了画面

Cellpose GUIのインストール

マウス操作でCellposeを使用可能なGUI版を使うには次の追加インストールが必要。

python -m pip install cellpose[gui]

追加で必要な関連パッケージがインストールされる。

インストール中の画面


終了画面

Cellposeのupdate

最新版に更新する。23年7月現在の最新版はv2.2.2のようだ。

python -m pip install cellpose --upgrade

【Cellpose GUIの立ち上げ】

Cellpose GUIを立ち上げるには以下のコマンドを実行する。

python -m cellpose


立ち上がったCellpose

Anaconda PromptにCellpose GUI操作でのログが表示されるので、確認しながら進めるとよい。


【事前学習済みモデルで予測】

Cellposeは蛍光の細胞写真等ではよくデモされているが、ここでは位相差顕微鏡で撮影した培養細胞の写真を使って、Cellposeの有用性を検証してみる。

検証データ

cell diameter

Cellposeでは分離対象のおおよその直径をピクセル単位で指定する必要がある。間違った値だと予測精度が大きく落ちるので、要検討項目である。

calibrateボタンをクリックすると、cytoという学習済みモデルを使って直径を決めてくれる。このデモ画像の場合は、48.2 pxが良いらしい。

Channel

chan to segment:で分離に用いるチャンネルを指定する。「0: gray」「1: red」「2: green」「3: blue」から選べる。chan2 (optional):からは「0: none」「1: red」「2: green」「3: blue」から選べる。channel2を使わない場合は「0: none」で良い。

どのチャンネルを指定すべきかは機械学習モデルに依存する。各モデルがどのchannelを使って学習したのかを知ったうえで、同様のchannelを予測時に使用するのが良い。
※ ただし、学習時と全く同じにしなくてもうまくいくこともある。

予測の実行

左側メニューのmodel zooから学習済みモデルを選択する。(初めて選択したモデルはモデルのダウンロードから行われるので余計時間がかかる。)



presetのモデルで予測してみると以下のような結果となった。丸い細胞はきれいに検出できているが、細長い細胞はうまく検出できていない。

「cyto」 「cyto2」


【再学習】

正解となるセグメンテーションマスクを手作業で作成し、再学習を行う。

マスクの操作も含めてHelp > Help with GUIから操作が確認できる。

以下に幾つかピックアップしておく。

項目 操作方法
マスクの選択 マスクの上でクリック
マスクの削除 マスクの上でCtr+クリック
マスクの全削除 Ctr+0
マスクの結合 既に1つのマスクを選んだ状態で、新たなマスクの上でAlt+クリック
マスクの描画 右クリックを1度 -> マウスカーソルを動かしてマスクの輪郭描画 -> 始点に戻るか再度右クリック
マスクデータの保存 Ctr+S。画像名_seg.npyのファイルが書き出される。
RGBチャンネル表示 キーボードのR,G,Bを押す。左側メニューのViewsからも変更可能
マスクの表示/非表示 キーボードのX。左側メニューのDrawingからも変更可能
マスクの輪郭表示 キーボードのZ。左側メニューのDrawingからも変更可能
flowsや予測確率の表示 キーボードのPageUp/PageDownボタン。左側メニューのViewsからも変更可能
ブラシサイズの変更 キーボードの,でサイズダウン、キーボードの.でサイズアップ。左側メニューのDrawingからも変更可能

ラベル付け

1から全て手作業で付け直すのは大変なので、まずは適当なモデルで予測を行い、精度が悪い箇所を修正していく。

対象に予測マスクが無い場合は新規作成。右クリックで始点を作り、カーソルを動かしてマスク輪郭を描く。

マスクの作成

予測マスクの形状が不足している場合は、不足箇所にマスクを作り、Alt+クリックで2つを結合する。

マスクの結合

もしろんCtr+クリックでマスクを消して初めから付け直してもよい。

このように画像全体を修正した。

マスクの保存

上部メニュー FileSave masks and image (as *_seg.npy) か Ctr+Sでマスクのデータを保存しておく。

画像が保存されているフォルダと同じ個所に「画像名_seg.npy」が作られる。

学習はフォルダ内の画像に対して行われるようなので、学習用画像を何個か作成してもよい。


学習の実行

上部メニュー ModelsTrain new model with image+masks in folderをクリック。Train settingウィンドウが立ち上がる。

rain setting


パラメーターは幾つかあるが、今回はデフォルト設定で進めた。


学習開始画面

学習終了画面

学習が終了すると、開いていた画像にも新規モデルが適応される。予測が不十分な箇所には再度ラベルの調整 -> 再学習を行う。

再学習モデルを使った予測

学習済みモデルは左側メニューのcustom modelsから選択できる。run modelをクリックして予測を実行する。

別の画像でこの予測モデルを適応してみたが、良いモデルができたようだ。

予測前 予測後

本記事のデモデータはこちらから取得可能。
ダウンロードしたモデルを自身のCellpose GUIで使うには、Cellpose GUIメニューのModels > Add custom torch model to GUIからモデルファイルを選択しておく。



【GPUの利用】

CPUを使って1画像を100 epochで再学習すると30分以上を要した。より高速に作動させるためCellposeでGPUを使えるようにする方法を紹介する。(Cellposeは内部でPyTorchを使っており、pytorchでGPUを認識できればよい。)

GitHubで紹介されているインストールコマンド

GitHubのページのインストールコマンド

私の場合、この方法はうまくいかなかったが、一応紹介しておく。

https://github.com/mouseland/cellpose


  1. GPU版のtorchを入れるために、まずはCPU版のtorchをアンインストール。
    ※ torchを入れなおすまでCellposeは使えなくなる。
pip uninstall torch
  1. Pytorchの入れ直し
conda install pytorch pytorch-cuda=11.6 -c pytorch -c nvidia
エラーが出たのでその対策

私の環境では以下のエラーがでた。

CondaSSLError: OpenSSL appears to be unavailable on this machine. OpenSSL is required to
download and install packages.

こちらの投稿を参考にC:\ProgramData\Anaconda3\DLLsに"C:\ProgramData\Anaconda3\Library\bin\libcrypto-1_1-x64.dll"と"C:\ProgramData\Anaconda3\Library\bin\libssl-1_1-x64.dll"をコピペすると解決した。

https://github.com/conda/conda/issues/11795


  1. GitHubからcellposeをインストール
pip install git+https://www.github.com/mouseland/cellpose.git

途中で文字コードのエラー。

UnicodeDecodeError: 'cp932' codec can't decode byte 0xef in position 16542: illegal multibyte sequence


Pytorchのインストール

Pytorchの公式サイトのインストールコマンドを使ってPytorchをインストールし直す。

https://pytorch.org/get-started/locally/

自身のOSやCUDA versionなどを選んで、インストールコマンドを取得しておく。

  1. Anaconda promptを立ち上げて仮想環境に入る。
conda activate cellpose
  1. --updateオプションを付けてPytorchをアップデートする。
pip3 install --upgrade torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
  1. Anacoda promptでpip listの出力を見てみて、torchのversionに+cu118などのCUDA versionがついていることを確認する。

  2. さらに次のようにしてGPUを認識しているか確認してTrueであれば問題ない。

python開始
python
GPUを認識しているか確認
import torch
torch.cuda.is_available()


GPUモードの利用

Cellpose GUIを立ち上げ直して、左側パネルの「Segmentation:」の欄で 「use GPU」にチェックが入っていればGPUの利用ができる準備ができている。

python -m cellpose

後は予測、モデルの訓練などの操作は変わらない。上記で30分以上かかったモデルの訓練も、GPUを使うと3分以内で終わってしまった。



【ImageJでの計測へ】

CellposeにはセグメンテーションしたROIの計測をする機能は無いので、画像解析ソフトにROI情報を渡す必要がある。CellposeからImageJ用のデータが2種類得られる。どちらのファイルを使ってもよいがそれぞれImageJへのimport方法が異なる。

方法1

FileSave Outlines as text for imageJから輪郭情報をテキストファイルとして保存し、
Cellposeが配布しているImageJプラグイン (imagej_roi_converter.py)を使ってImageJにROIを再現する。

輪郭情報は、1行に1つのオブジェクトのX座標、Y座標が交互に記録されている。

outlines.txt

参考
https://qiita.com/Naka24-sun/items/f7d47171657629431a45#良好な-segmentation-結果を得るために
https://satoshithermophilus.hatenablog.com/entry/2017/06/12/195827

ImageJのテキストエディタからPythonを実行

1. ImageJで画像を開く

まずは輪郭を載せたい画像を開く。

2. Text Windowを開く

FileNewText Window

3. LanuageをPython (Jython)に設定

4. 「imagej_roi_converter.py」の内容をコピペ

pyファイルをローカルに保存済みなら、FileOpenから開いても良い。

from ij import IJ
from ij.plugin.frame import RoiManager
from ij.gui import PolygonRoi
from ij.gui import Roi
from java.awt import FileDialog

fd = FileDialog(IJ.getInstance(), "Open", FileDialog.LOAD)
fd.show()
file_name = fd.getDirectory() + fd.getFile()
print(file_name)

RM = RoiManager()
rm = RM.getRoiManager()

imp = IJ.getImage()

textfile = open(file_name, "r")
for line in textfile:
    lineText = line.rstrip()
    if not lineText:
        continue
    xy = map(int, line.rstrip().split(","))
    X = xy[::2]
    Y = xy[1::2]
    imp.setRoi(PolygonRoi(X, Y, Roi.POLYGON))
    # IJ.run(imp, "Convex Hull", "")
    roi = imp.getRoi()
    print(roi)
    rm.addRoi(roi)
textfile.close()
rm.runCommand("Associate", "true")
rm.runCommand("Show All with labels")

5. Run

Runボタンをクリックするとエクスプローラーが開くので、輪郭座標のテキストファイルを選択する。

一瞬でImageJに反映される。

プラグインから使う方法

1. ImageJ Pluginとして登録

PluginsInstall

エクスプローラーが開かれるので「imagej_roi_converter.py」ファイルを選択。次のpluginsフォルダへの保存画面で保存を選択。

2. ImageJを再起動

Pluginsタブから「imagej_roi_converter」があれば成功。

3. ImageJで画像を開く

輪郭を載せたい画像を開く。

4. imagej_roi_converterプラグインを実行

エクスプローラーが開かれるので、輪郭座標のテキストファイルを選択する。一瞬でImageJに反映される。

方法2

FileSave outlines as .zip archive of ROI files for ImageJから取得できるzipファイルはImageJのROI Managerから開くことができる。こちらの場合はPluginが不要。
具体的には以下の手順。

  1. ImageJで元画像を開く
  2. AnalyzeToolsROI Manager
  3. ROI ManagerのMoreOpenからRoiのzipファイルを開く。


方法3 _seg.npyファイルからインスタンスマスク画像を作成

CellposeのFileメニューからImageJ用のデータが取得できなかった場合は、こちらの方法でも対応可能。

「画像名_seg.npy」のファイルにはすでにマスクの情報を保持している。このファイルをPythonで処理してインスタンスマスク画像を作成する。

次のスクリプトはカレントディレクトリにある「_seg.npy」ファイルから「_label.png」画像を作成するスクリプトである。

npy2mask.py
import numpy as np
import imageio
from glob import glob

npfiles = glob("*_seg.npy")

for npfile in npfiles:
    
    # ファイル名取得
    filename = npfile[:-8]
    
    # npyファイルの読み込み
    mask = np.load(npfile, allow_pickle=True)
    
    # dist型が得られる
    mask = mask.tolist()
    
    # 8bit以上のグレースケール画像に対応するためにimageioを使って書き出し
    imageio.imwrite(f"{filename}_label.png", mask["masks"])

Anaconda Promptから行うには、以下の手順で進める。

  1. 「_seg.npy」ファイルがあるフォルダに上記スクリプト(npy2mask.py)を保存
  2. cdコマンドで「_seg.npy」ファイルがあるディレクトリに移動
  3. pythonファイルの実行
python npy2mask.py

書き出されたインスタンスマスク画像をImageJで開くと、ROIごとに異なる輝度値を持つ画像が確認できる。

ImageJ LabelsToROisプラグインを使用して画像にインスタンスマスクをつける

次に書き出したマスク画像を使って、ImageJのROIを作成する。LabelsToRoisプラグインを使用すれば、元画像にインスタンスマスク画像から計算したROIを付与することができる。

https://labelstorois.github.io/

プラグインのダウンロード

上記リンクのトップページにあるDownload.zipのリンクをクリック。

ダウンロードしたzipファイルを解凍し、その中にある「Labels_To_Rois.py」ファイルをImageJのpluginsフォルダにコピペしておく。

ImageJを立ち上げて、PluginsからLabels_To_Roisがあれば成功。

1画像版

  1. Labels_To_Roisを起動し、Single imageをクリック。

  2. 元画像/インスタンスマスク画像のパスを記入してNext

  1. ROI付き画像とROI Managerが立ち上がる。

  2. ROIの計測、保存
    LabelToRoi - ROI erotionウィンドウからはROIのErosionが追加で行える。
    作成したROIを保存する場合はSave ROIsをクリック。ローカルに自動で書き出される。ROI ManagerのOPENから「画像名_Erosion_〇px_RoiSet.zip」を開くとROIが呼び出せる。
    Set measuremtnsから計測項目を選択し、Save CSV TableでROIの計測結果がローカルに保存される。

複数画像の一括処理版

フォルダを指定すると、「画像名_labels」と入った画像ファイルを探して、その元画像を含めて一括で処理する。

  1. Labels_To_Roisを起動し、Multiple imagesをクリック。
  2. フォルダのパスを指定。
    Erodeや計測項目等の指定があればここでやっておく。
  3. Runを押すと結果の書き出しまで一括で行われる。

Discussion