mcpField
P
pathml

pathml

github.com/jaechang-hitsデータ・データベース38468 回インストール1 週間前に更新
リポジトリ

pathml について

pathmlは、全スライド画像を扱う計算病理学向けのPythonツールキットです。SlideDataとPipelineの抽象化により、病理画像や機械学習の研究者向けに、読み込みからタイル化、前処理、特徴抽出までをまとめて扱えます。

主な機能

  1. 01複数の全スライド画像形式の読み込み
  2. 02スライドのタイル化と組織検出
  3. 03染色正規化と核セグメンテーション
  4. 04多重免疫蛍光画像の処理
  5. 05タイル特徴の抽出とデータ出力

活用シーン

  1. 01病理画像から学習データセットを作成
  2. 02H&E画像間の染色を正規化
  3. 03病理画像内の核をセグメント化
  4. 04複数の全スライド画像を一括処理

インストール

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

$npx skills add https://github.com/jaechang-hits/sciagent-skills --skill pathml

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

詳細

pathml

概要

PathMLは、ホールスライド画像(WSI)を用いた計算病理学のワークフロー向けに設計されたPythonツールキットです。未処理のスライドファイル(SVS、NDPI、MRXS、TIFF)から、タイルの抽出、前処理(染色正規化、核のセグメンテーション、組織検出)、特徴抽出、機械学習までを一貫したパイプラインで提供します。PathMLは、一般的なPythonの機械学習ライブラリや画像処理ライブラリと連携しながら、SlideDataおよびPipelineの抽象化によってWSIの処理の複雑さを軽減します。

使用する場面

  • ホールスライドH&E画像の処理:大きなWSIをタイルに分割し、異なるスキャナーやバッチで取得されたスライド間の染色のばらつきを正規化します。
  • 病理スライド上の核のセグメンテーション:組み込みのセグメンテーションパイプラインを使用して、H&EまたはDAPI染色WSI内の核を検出・セグメンテーションします。
  • WSIからの機械学習トレーニングデータセットの構築:組織分類器、腫瘍検出器、生存予測モデルのトレーニング用に、対応するラベルとともにタイルを抽出します。
  • 多重免疫蛍光(mIF)画像解析:チャンネルごとの前処理と特徴抽出を行い、多チャンネルIFスライドを処理します。
  • コホート間の染色正規化:MacenkoまたはVahadaneの染色正規化を適用し、複数の施設からのH&Eスライドを統一します。
  • 下流の機械学習向け特徴抽出:患者レベルの予測タスク向けに、タイルから手作り特徴量または深層学習特徴量を抽出します。
  • 標準的な2D顕微鏡画像(WSI以外)には、PathMLのオーバーヘッドを避け、scikit-imageまたはcellposeを直接使用してください。

前提条件

  • Pythonパッケージ:pathml、torch、torchvision、numpy、scikit-image、openslide-python
  • システム:OpenSlide Cライブラリ(WSIの読み取りに必要)
  • データ要件:SVS、NDPI、MRXS、またはTIFF形式のWSIファイル。セグメンテーションにはGPUを推奨します。
  • 環境:Python 3.8以降。深層学習の前処理にはCUDA対応GPUが必要です。
# Install system dependency first
conda install -c conda-forge openslide

# Install PathML
pip install pathml

# For GPU support
pip install torch torchvision --extra-index-url https://download.pytorch.org/whl/cu118

クイックスタート

from pathml.core import SlideData
from pathml.preprocessing import Pipeline
from pathml.preprocessing.transforms import BoxBlur, TissueDetectionHE

# Load → build pipeline → tile → preprocess
slide = SlideData("tumor.svs", name="demo")
pipeline = Pipeline([BoxBlur(kernel_size=3), TissueDetectionHE(mask_name="tissue")])
slide.run(pipeline, tile_size=256, tile_stride=256)

# Inspect tiles
from pathml.core import Tile
tiles = [t for t in slide.tiles if t.masks["tissue"].any()]
print(f"Tissue tiles: {len(tiles)} of {len(slide.tiles)}")

ワークフロー

ステップ1:ホールスライド画像を読み込む
from pathml.core import SlideData

# Load an H&E whole-slide image
slide = SlideData("path/to/slide.svs", name="tumor_slide_001")
print(f"Slide name: {slide.name}")
print(f"Slide shape: {slide.slide.shape}")
print(f"Slide properties: {slide.slide.properties}")
ステップ2:前処理パイプラインを定義する
from pathml.preprocessing import Pipeline
from pathml.preprocessing.transforms import (
    BoxBlur,
    TissueDetectionHE,
    HEStainNormalization,
)

# Build a preprocessing pipeline for H&E slides
pipeline = Pipeline([
    BoxBlur(kernel_size=5),                       # smooth image
    TissueDetectionHE(mask_name="tissue"),         # detect tissue regions
    HEStainNormalization(target="normalize"),       # normalize H&E staining
])
print(f"Pipeline steps: {len(pipeline.transforms)}")
ステップ3:TileDatasetを作成する
from pathml.core import TileDataset

# Tile the slide into 256x256 patches at 20x magnification
slide.generate_tiles(
    shape=(256, 256),
    stride=(256, 256),
    pad=False,
    level=0,           # pyramid level 0 = highest resolution
    coords_format="fractional",
)
print(f"Total tiles generated: {len(slide.tiles)}")
ステップ4:前処理パイプラインを実行する
# Apply preprocessing pipeline to all tiles
slide.run(pipeline, distributed=False, tile_pad=False)
print("Pipeline complete — tiles preprocessed")

# Inspect a single tile
tile = slide.tiles[0]
print(f"Tile shape: {tile.image.shape}")      # (256, 256, 3)
print(f"Tile masks: {list(tile.masks.keys())}")
ステップ5:核のセグメンテーション
from pathml.preprocessing.transforms import NuclearSegmentation

# Run Hematoxylin-channel nuclear segmentation
seg_pipeline = Pipeline([
    TissueDetectionHE(mask_name="tissue"),
    NuclearSegmentation(mask_name="nuclei"),
])

slide.run(seg_pipeline, distributed=False)

# Count nuclei per tile
for tile in list(slide.tiles)[:5]:
    n_nuclei = tile.masks["nuclei"].max()
    print(f"Tile {tile.coords}: {n_nuclei} nuclei detected")
ステップ6:特徴抽出
import numpy as np
from pathml.core import SlideDataset

features = []
for tile in slide.tiles:
    if "tissue" in tile.masks and tile.masks["tissue"].any():
        img = tile.image
        feat = {
            "mean_r":    img[:, :, 0].mean(),
            "mean_g":    img[:, :, 1].mean(),
            "mean_b":    img[:, :, 2].mean(),
            "std_r":     img[:, :, 0].std(),
            "n_nuclei":  int(tile.masks["nuclei"].max()) if "nuclei" in tile.masks else 0,
            "tile_x":    tile.coords[0],
            "tile_y":    tile.coords[1],
        }
        features.append(feat)

import pandas as pd
df = pd.DataFrame(features)
df.to_csv("slide_features.csv", index=False)
print(f"Extracted features from {len(df)} tissue tiles -> slide_features.csv")
ステップ7:処理済みスライドを保存・エクスポートする
import h5py

# Save slide data (tiles + masks) to HDF5
slide.write("processed_slide.h5")
print("Slide saved to processed_slide.h5")

# Reload for downstream use
from pathml.core import SlideData
slide_loaded = SlideData.read("processed_slide.h5")
print(f"Reloaded: {len(slide_loaded.tiles)} tiles")

主なパラメーター

パラメーターデフォルト範囲/選択肢効果
shape(256, 256)(64,64) – (1024,1024)タイルのピクセル単位の寸法
strideshapeと同じshape以下の任意のタプルタイル中心間の間隔です。stride < shapeの場合、タイルが重なります。
level00~最大ピラミッドレベルピラミッドの解像度レベル(0=フル解像度)
kernel_size5奇数 3~21BoxBlurの平滑化カーネルサイズ
mask_name必須任意の文字列tile.masksに保存される出力マスクの名前
distributedFalseTrue、False大きなスライドのDask分散処理を有効にします。
padFalseTrue、False端のタイルをshapeと同じサイズになるようパディングします。

よくあるレシピ

レシピ:組織のみを含むタイルのフィルタリング

使用する場面:背景タイルを除外して、下流の処理におけるメモリー使用量と計算量を削減します。

# Filter tiles to only tissue regions after running tissue detection pipeline
tissue_tiles = [t for t in slide.tiles if "tissue" in t.masks and t.masks["tissue"].mean() > 0.5]
print(f"Tissue tiles: {len(tissue_tiles)} / {len(slide.tiles)} total")
レシピ:タイルをPNGファイルとしてエクスポートする

使用する場面:PyTorchでカスタム分類器をトレーニングするための、ラベル付きタイルデータセットを作成します。

from PIL import Image
import numpy as np
from pathlib import Path

output_dir = Path("tiles_png")
output_dir.mkdir(exist_ok=True)

for i, tile in enumerate(slide.tiles):
    if "tissue" in tile.masks and tile.masks["tissue"].mean() > 0.5:
        img = Image.fromarray(tile.image.astype(np.uint8))
        img.save(output_dir / f"tile_{i:05d}_x{tile.coords[0]}_y{tile.coords[1]}.png")

print(f"Saved {i+1} tiles to {output_dir}/")
レシピ:複数のスライドをバッチ処理する

使用する場面:WSIファイルのディレクトリに対して、同じ前処理パイプラインを実行します。

from pathlib import Path
from pathml.core import SlideData
from pathml.preprocessing import Pipeline
from pathml.preprocessing.transforms import TissueDetectionHE, HEStainNormalization

pipeline = Pipeline([
    TissueDetectionHE(mask_name="tissue"),
    HEStainNormalization(target="normalize"),
])

wsi_dir = Path("slides/")
for wsi_path in sorted(wsi_dir.glob("*.svs")):
    slide = SlideData(str(wsi_path), name=wsi_path.stem)
    slide.generate_tiles(shape=(256, 256), stride=(256, 256), level=0)
    slide.run(pipeline, distributed=False)
    slide.write(f"processed/{wsi_path.stem}.h5")
    print(f"Processed {wsi_path.name}: {len(slide.tiles)} tiles")

想定される出力

  • slide.tiles — Tileオブジェクトのイテラブル。それぞれ.image(numpy配列)と.masks(numpy配列の辞書)を含みます。
  • slide_features.csv — タイルごとの表形式の特徴量(色の統計量、核の数、座標)
  • processed_slide.h5 — 下流での使用に向けて、タイル、マスク、メタデータを含むHDF5ファイル
  • PNGタイルファイル(任意)— PyTorchのImageFolderデータセットで読み込み可能な形式です。

トラブルシューティング

問題原因解決方法
openslide.lowlevel.OpenSlideUnsupportedFormatErrorOpenSlide の C ライブラリがインストールされていないか、WSI 形式がサポートされていませんconda install -c conda-forge openslide を実行します。形式の互換性を確認してください
セグメンテーション中の CUDA out of memoryタイルサイズが GPU に対して大きすぎますタイルの shape を (128, 128) に縮小するか、CPU で distributed=False を指定して実行します
generate_tiles の後も slide.tiles が空ですレベルインデックスが範囲外か、すべてのタイルがフィルタリングされていますlevel=0 を指定します。slide.slide.level_count でスライドのピラミッドを確認してください
染色の正規化でタイルが黒くなります元のスライドのコントラストが低すぎるか、組織の検出に失敗しています正規化の前に TissueDetectionHE を適用します。組織マスクのカバー範囲を確認してください
tile.masks で KeyError: 'nuclei' が発生しますセグメンテーションパイプラインがまだ実行されていませんマスクにアクセスする前に、slide.run() で NuclearSegmentation パイプラインを実行します
タイル生成が非常に遅いです大きな SVS で高解像度のレベル 0 を使用していますプロトタイピングを高速化するには、より低いピラミッドレベル(level=1 または level=2)を使用します
AttributeError: SlideData has no attribute 'write'PathML のバージョンが古いですHDF5 の保存/読み込みをサポートするには、pip install --upgrade pathml を実行します

参考資料

コメント