mcpField
C
cellpose-cell-segmentation

cellpose-cell-segmentation

github.com/jaechang-hitsデータ・データベース38477 回インストール6 日前に更新
リポジトリ

cellpose-cell-segmentation について

Cellposeの事前学習モデルで細胞や細胞核を分割する、顕微鏡画像解析向けスキルです。多様な細胞や画像群を扱う研究者向けで、ラベルマスクの生成と3D z-stack分割に対応します。

主な機能

  1. 01事前学習モデルによる細胞・核の分割
  2. 02細胞径の自動推定
  3. 033D z-stack分割
  4. 04画像のバッチ処理
  5. 05整数ラベルマスクの出力
  6. 06カスタムモデルのファインチューニング

活用シーン

  1. 01蛍光顕微鏡画像の細胞分割
  2. 02大規模な顕微鏡画像群の一括処理
  3. 03マスクから細胞形態を測定
  4. 04z-stackデータの3D分割

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/jaechang-hits/sciagent-skills --skill cellpose-cell-segmentation

インストール後、Claude Code で/cellpose-cell-segmentationを入力して読み込まれたか確認します。

詳細

Cellpose — ディープラーニングによる細胞セグメンテーション

概要

Cellposeはフローベースのニューラルネットワークを使用し、パラメーターを手動で調整することなく、蛍光顕微鏡画像内の個々の細胞や核をセグメンテーションします。事前学習済みモデル(cyto3、nuclei、tissuenet)は、細胞の種類、倍率、染色条件が異なる場合にも汎用的に機能するため、しきい値の手動選択やウォーターシェッドのパラメーター最適化が不要になります。Cellposeは整数ラベルマスク(各細胞に固有の整数を割り当てたもの)を出力します。このマスクは、形態計測用のscikit-image regionpropsやトラッキング用のTrackPyと互換性があります。内蔵の直径推定機能により細胞サイズの指定は不要ですが、おおよその直径を指定すると精度が向上します。

使用する場面

  • 強度のばらつきや細胞同士の接触によりルールベースのしきい値処理がうまくいかない蛍光顕微鏡画像で、細胞や核をセグメンテーションする場合
  • 画像ごとのパラメーター調整をせずに、大規模な顕微鏡画像データセットをバッチ処理する場合
  • 1つのモデルで、多様な細胞の種類(接着細胞、血球、細菌、オルガノイド)をセグメンテーションする場合
  • scikit-imageを使った後続の領域特性計測(面積、強度、形状)用にラベルマスクを作成する場合
  • do_3D=Trueを指定して、Zスタック顕微鏡データを3Dボリュームセグメンテーションする場合
  • 細胞が十分に分離しており、ルールベースのしきい値処理で十分な場合は、scikit-image watershedを使用してください
  • 星型凸細胞(ニューロン、核)向けに最適化されたディープラーニングセグメンテーション手法として、代替のStarDistを使用してください

前提条件

  • Pythonパッケージ:cellpose、numpy、matplotlib
  • 任意:処理を10~50倍高速化できるCUDA対応GPU(GUIを使用する場合はpip install cellpose[gui])
  • 入力:グレースケールまたはマルチチャンネルのTIFF/PNG画像(2Dまたは3D配列)
# Install Cellpose
pip install cellpose

# Install with GUI support
pip install cellpose[gui]

# Install with GPU (PyTorch CUDA)
pip install cellpose torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118

# Verify
python -c "from cellpose import models; print('Cellpose ready')"

クイックスタート

from cellpose import models
import numpy as np
from skimage import io

# Load image (grayscale or 2D array)
img = io.imread("cells.tif")  # shape: (H, W) or (H, W, C)

# Initialize model and segment
model = models.Cellpose(model_type="cyto3", gpu=False)
masks, flows, styles, diams = model.eval(img, diameter=0, channels=[0, 0])

print(f"Cells segmented: {masks.max()}")  # number of cells
print(f"Estimated diameter: {diams:.1f} px")
print(f"Mask shape: {masks.shape}")

ワークフロー

ステップ1:画像の読み込みと確認

顕微鏡画像を読み込み、セグメンテーションの前にチャンネルの構成を確認します。

import numpy as np
from skimage import io
import matplotlib.pyplot as plt

# Load single-channel fluorescence image
img_gray = io.imread("nucleus_dapi.tif")           # shape: (H, W)
img_rgb = io.imread("cells_multichannel.tif")      # shape: (H, W, C)

print(f"Grayscale shape: {img_gray.shape}, dtype: {img_gray.dtype}")
print(f"Multichannel shape: {img_rgb.shape}")

# Preview
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
axes[0].imshow(img_gray, cmap="gray")
axes[0].set_title("DAPI (nuclei)")
axes[1].imshow(img_rgb[..., 0], cmap="green")
axes[1].set_title("GFP channel")
plt.tight_layout()
plt.savefig("image_preview.png", dpi=100)
print("Saved: image_preview.png")
ステップ2:事前学習済みモデルで細胞をセグメンテーション

適切な事前学習済みモデルを使ってCellposeを実行します。

from cellpose import models
import numpy as np
from skimage import io

# Available models: 'cyto3' (cells), 'nuclei', 'tissuenet', 'cyto2', 'CP'
model = models.Cellpose(model_type="cyto3", gpu=False)

img = io.imread("cells.tif")

# channels=[cytoplasm_channel, nucleus_channel]
# Use [0, 0] for grayscale; [1, 3] for green cytoplasm + blue nucleus (1-indexed)
masks, flows, styles, diams = model.eval(
    img,
    diameter=0,          # 0 = auto-estimate; or provide px estimate
    channels=[0, 0],     # grayscale
    flow_threshold=0.4,  # lower = fewer false positives; range 0.1-1.0
    cellprob_threshold=0.0,  # lower = more cells detected; range -6 to 6
)

print(f"Cells found: {masks.max()}")
print(f"Estimated cell diameter: {diams:.1f} pixels")
np.save("masks.npy", masks)
ステップ3:DAPIチャンネルから核をセグメンテーション

DAPI染色された核にはnucleiモデルを使用します。

from cellpose import models
from skimage import io
import numpy as np

model = models.Cellpose(model_type="nuclei", gpu=False)
dapi = io.imread("dapi.tif")

# Nucleus-only segmentation: channels=[0, 0] (single channel)
masks, flows, styles, diams = model.eval(
    dapi,
    diameter=30,         # approximate nucleus diameter in pixels
    channels=[0, 0],
    flow_threshold=0.4,
    cellprob_threshold=0.0,
)

print(f"Nuclei segmented: {masks.max()}")
# Save label mask as TIFF for ImageJ/FIJI compatibility
from skimage import io as skio
skio.imsave("nuclei_masks.tif", masks.astype(np.uint16))
print("Saved: nuclei_masks.tif")
ステップ4:セグメンテーション結果の可視化

品質管理のため、元の画像にマスクを重ねて表示します。

from cellpose import plot as cpplot
import matplotlib.pyplot as plt
import numpy as np
from skimage import io

img = io.imread("cells.tif")
masks = np.load("masks.npy")
flows_data = None  # load if you saved them: flows = np.load("flows.npy", allow_pickle=True)

# Cellpose built-in visualization
fig, axes = plt.subplots(1, 3, figsize=(15, 5))

# Original image
axes[0].imshow(img, cmap="gray")
axes[0].set_title(f"Original image")

# Label mask (each cell = unique color)
axes[1].imshow(masks, cmap="tab20")
axes[1].set_title(f"Segmentation masks ({masks.max()} cells)")

# Overlay: outline on original
from skimage.segmentation import find_boundaries
boundaries = find_boundaries(masks, mode="inner")
overlay = np.stack([img / img.max()] * 3, axis=-1)
overlay[boundaries] = [1, 0, 0]  # red outlines
axes[2].imshow(overlay)
axes[2].set_title("Outlines overlay")

plt.tight_layout()
plt.savefig("segmentation_result.png", dpi=150)
print("Saved: segmentation_result.png")
ステップ5:マスクから細胞の特性を計測

scikit-imageのregionpropsを使って、形態および強度の計測値を抽出します。

import numpy as np
import pandas as pd
from skimage.measure import regionprops_table
from skimage import io

masks = np.load("masks.npy")
img = io.imread("cells.tif")

# Measure morphology and intensity per cell
props = regionprops_table(
    masks, intensity_image=img,
    properties=["label", "area", "centroid", "eccentricity",
                 "mean_intensity", "max_intensity", "perimeter",
                 "equivalent_diameter_area"]
)
df = pd.DataFrame(props)
df.columns = ["cell_id", "area_px", "centroid_y", "centroid_x",
              "eccentricity", "mean_intensity", "max_intensity",
              "perimeter", "diameter_px"]

print(f"Cells measured: {len(df)}")
print(f"Median area: {df['area_px'].median():.0f} px²")
print(f"Median diameter: {df['diameter_px'].median():.1f} px")
print(df.head())

df.to_csv("cell_measurements.csv", index=False)
ステップ6:複数画像のバッチセグメンテーション

画像ディレクトリを処理し、結果を集約します。

from cellpose import models
from skimage import io
from skimage.measure import regionprops_table
import pandas as pd
import numpy as np
from pathlib import Path

model = models.Cellpose(model_type="cyto3", gpu=False)
image_dir = Path("images/")
output_dir = Path("results/")
output_dir.mkdir(exist_ok=True)

all_stats = []
for img_path in sorted(image_dir.glob("*.tif")):
    img = io.imread(img_path)
    masks, _, _, diams = model.eval(img, diameter=0, channels=[0, 0])
    
    # Save mask
    np.save(output_dir / f"{img_path.stem}_masks.npy", masks)
    
    # Measure
    if masks.max() > 0:
        props = regionprops_table(masks, intensity_image=img,
                                  properties=["label", "area", "mean_intensity"])
        df = pd.DataFrame(props)
        df["image"] = img_path.name
        df["est_diameter"] = diams
        all_stats.append(df)
    
    print(f"{img_path.name}: {masks.max()} cells, diameter={diams:.0f}px")

summary = pd.concat(all_stats, ignore_index=True)
summary.to_csv(output_dir / "all_cells.csv", index=False)
print(f"\nTotal cells: {len(summary)} across {summary['image'].nunique()} images")

主なパラメーター

パラメーターデフォルト範囲/選択肢効果
model_type"cyto3""cyto3"、"cyto2"、"nuclei"、"tissuenet"、"CP"、カスタムパス事前学習済みモデル。cyto3は最も汎用的で、nucleiはDAPIのみの場合に使用します
diameter300~500 pxピクセル単位のおおよその細胞直径。0の場合は画像から自動推定します
channels[0, 0][cyto, nucleus](0=グレー、1=R、2=G、3=B)細胞質および核染色のチャンネルインデックス
flow_threshold0.40.1~1.0フローフィールドに基づく細胞確率のしきい値。値を下げるほど厳しくなります
cellprob_threshold0.0−6~6細胞確率のカットオフ。値を上げると、より多くの細胞を検出します
gpuFalseTrue、FalseGPU推論を有効にします(CUDA対応のPyTorchが必要です)
do_3DFalseTrue、FalseZスタックの3Dボリュームセグメンテーションを有効にします
min_size15整数 px²ピクセル²単位のオブジェクトの最小サイズ。これより小さいオブジェクトは破棄されます
batch_size8整数GPUの1バッチで処理する画像タイルの数
normalizeTrueTrue、Falseセグメンテーションの前に画像の強度を正規化します

よく使うレシピ

レシピ1:マルチチャンネル画像(GFP + DAPI)のセグメンテーション
from cellpose import models
from skimage import io
import numpy as np

model = models.Cellpose(model_type="cyto3", gpu=False)

# Multichannel image: channel 1 = GFP (cytoplasm), channel 3 = DAPI (nucleus)
img_multi = io.imread("cells_gfp_dapi.tif")  # shape: (H, W, 3)

# channels=[cytoplasm_channel, nucleus_channel] (1-indexed for multichannel)
masks, flows, styles, diams = model.eval(
    img_multi,
    diameter=0,
    channels=[2, 3],  # GFP=channel2, DAPI=channel3 (1-indexed)
    flow_threshold=0.4,
)
print(f"Cells segmented: {masks.max()}, diameter: {diams:.0f}px")
np.save("masks_multichannel.npy", masks)
レシピ2:Cellpose CLIでディレクトリをバッチ処理
# CLI batch segmentation of all TIFFs in a directory
cellpose \
    --image_path images/ \
    --pretrained_model cyto3 \
    --diameter 0 \
    --chan 0 \
    --save_tif \
    --no_npy

# With GPU
cellpose \
    --image_path images/ \
    --pretrained_model nuclei \
    --diameter 30 \
    --chan 0 \
    --use_gpu \
    --save_tif

# Results saved as: images/*_cp_masks.tif
echo "Done. Masks saved in images/ directory."
レシピ3:カスタム細胞タイプでCellposeをファインチューニング
from cellpose import models, train
import numpy as np
from skimage import io

# Prepare training data: list of images and corresponding masks
train_images = [io.imread(f"train/img_{i}.tif") for i in range(10)]
train_masks = [np.load(f"train/mask_{i}.npy") for i in range(10)]

# Fine-tune starting from cyto3
model = models.CellposeModel(model_type="cyto3")

# Train: saves model to models/ directory
model_path = train.train_seg(
    model.net,
    train_data=train_images,
    train_labels=train_masks,
    channels=[0, 0],
    save_path="models/",
    n_epochs=100,
    learning_rate=0.2,
    weight_decay=1e-5,
)
print(f"Fine-tuned model saved: {model_path}")

期待される出力

出力形式説明
masks arraynumpy int32ラベルマスク:0=背景、1..N=一意な細胞 ID
flows listnumpy arraysフローフィールドの各成分:[XY フロー、細胞確率、勾配]
styles arraynumpy floatスタイルベクトルの埋め込み(モデルの類似性に使用)
diams floatscalar推定された平均細胞径(ピクセル単位)
*_masks.npyNumPy保存されたマスク配列(np.save による)
*_cp_masks.tifTIFF uint16マスク TIFF(CLI の --save_tif による)。FIJI/ImageJ と互換性があります

トラブルシューティング

問題原因解決策
すべての細胞が 1 つのマスクに統合される直径が大きすぎる、または細胞同士が近すぎるdiameter を小さくし、flow_threshold を 0.6~0.8 に上げます
検出される細胞が非常に少ない直径が小さすぎる、または cellprob_threshold が高すぎるcellprob_threshold を −2 に上げます。自動設定には diameter=0 を使用します
偽陽性が多い(背景がラベル付けされる)flow_threshold が低いflow_threshold を 0.6~0.9 に上げ、min_size を大きくします
GPU のメモリ不足GPU バッチに対して画像が大きすぎるタイルに分割して処理します。batch_size を小さくするか、画像を切り抜きます
新しい細胞タイプへの汎化性能が低い類似した細胞でモデルがトレーニングされていないすべての事前トレーニング済みモデルを試します。アノテーション済み画像を 10~20 枚使ってファインチューニングします
3D セグメンテーションが非常に遅いCPU で z スタックが大きいGPU を有効にします。z スタックの深さを小さくするか、anisotropy パラメーターを使用します
マスク値が uint8 の範囲を超える画像内の細胞数が 255 を超えているdtype=np.uint16 または np.int32 で保存します
インポートエラー:No module named 'cellpose'パッケージがインストールされていないpip install cellpose または conda install -c conda-forge cellpose

参考資料

コメント