@nahisaho/satori 0.13.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +134 -43
- package/package.json +1 -1
- package/src/.github/skills/scientific-advanced-imaging/SKILL.md +382 -0
- package/src/.github/skills/scientific-biomedical-pubtator/SKILL.md +331 -0
- package/src/.github/skills/scientific-cell-line-resources/SKILL.md +258 -0
- package/src/.github/skills/scientific-chembl-assay-mining/SKILL.md +509 -0
- package/src/.github/skills/scientific-deep-chemistry/SKILL.md +350 -0
- package/src/.github/skills/scientific-ebi-databases/SKILL.md +280 -0
- package/src/.github/skills/scientific-ensembl-genomics/SKILL.md +378 -0
- package/src/.github/skills/scientific-expression-comparison/SKILL.md +303 -0
- package/src/.github/skills/scientific-md-simulation/SKILL.md +315 -0
- package/src/.github/skills/scientific-model-organism-db/SKILL.md +329 -0
- package/src/.github/skills/scientific-ontology-enrichment/SKILL.md +340 -0
- package/src/.github/skills/scientific-perturbation-analysis/SKILL.md +297 -0
- package/src/.github/skills/scientific-phylogenetics/SKILL.md +297 -0
- package/src/.github/skills/scientific-preprint-archive/SKILL.md +476 -0
- package/src/.github/skills/scientific-public-health-data/SKILL.md +322 -0
- package/src/.github/skills/scientific-regulatory-genomics/SKILL.md +274 -0
- package/src/.github/skills/scientific-reinforcement-learning/SKILL.md +280 -0
- package/src/.github/skills/scientific-scvi-integration/SKILL.md +344 -0
- package/src/.github/skills/scientific-string-network-api/SKILL.md +376 -0
- package/src/.github/skills/scientific-symbolic-mathematics/SKILL.md +277 -0
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scientific-advanced-imaging
|
|
3
|
+
description: |
|
|
4
|
+
高度バイオイメージング解析スキル。CellProfiler によるモフォロジカル
|
|
5
|
+
プロファイリング・Cell Painting 解析、Cellpose による深層学習
|
|
6
|
+
セルセグメンテーション、napari によるインタラクティブ 3D 可視化。
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Scientific Advanced Imaging
|
|
10
|
+
|
|
11
|
+
CellProfiler / Cellpose / napari を活用した高度バイオイメージング
|
|
12
|
+
解析パイプラインを提供する。セルセグメンテーション、形態学的
|
|
13
|
+
特徴抽出、Cell Painting アッセイ解析、3D 画像可視化。
|
|
14
|
+
|
|
15
|
+
## When to Use
|
|
16
|
+
|
|
17
|
+
- Cell Painting アッセイ画像を解析するとき
|
|
18
|
+
- 深層学習によるセルセグメンテーションが必要なとき (Cellpose)
|
|
19
|
+
- 形態学的特徴量 (面積、真円度、テクスチャ等) を定量するとき
|
|
20
|
+
- 蛍光顕微鏡スタック画像を 3D 可視化するとき
|
|
21
|
+
- カスタム Cellpose モデルを微調整するとき
|
|
22
|
+
- 高コンテンツスクリーニング (HCS) データを処理するとき
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
## 1. Cellpose セルセグメンテーション
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from cellpose import models, io
|
|
32
|
+
import numpy as np
|
|
33
|
+
from pathlib import Path
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def cellpose_segmentation(image_path, model_type="cyto2", diameter=None,
|
|
37
|
+
channels=None, gpu=True):
|
|
38
|
+
"""
|
|
39
|
+
Cellpose で細胞セグメンテーション。
|
|
40
|
+
|
|
41
|
+
Parameters:
|
|
42
|
+
image_path: str — 画像ファイルパス
|
|
43
|
+
model_type: str — モデル ("cyto", "cyto2", "nuclei")
|
|
44
|
+
diameter: float — 細胞直径 (None で自動)
|
|
45
|
+
channels: list — チャネル [cytoplasm, nuclei]
|
|
46
|
+
gpu: bool — GPU 使用
|
|
47
|
+
|
|
48
|
+
K-Dense: cellpose
|
|
49
|
+
"""
|
|
50
|
+
model = models.Cellpose(model_type=model_type, gpu=gpu)
|
|
51
|
+
|
|
52
|
+
if channels is None:
|
|
53
|
+
channels = [0, 0] # grayscale
|
|
54
|
+
|
|
55
|
+
img = io.imread(str(image_path))
|
|
56
|
+
masks, flows, styles, diams = model.eval(
|
|
57
|
+
img, diameter=diameter, channels=channels
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
n_cells = len(np.unique(masks)) - 1 # background除外
|
|
61
|
+
print(f"Cellpose: {n_cells} cells detected (model={model_type})")
|
|
62
|
+
print(f" Auto diameter: {diams:.1f}")
|
|
63
|
+
return masks, flows, styles
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## 2. バッチセグメンテーション
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
def batch_segmentation(image_dir, output_dir, model_type="cyto2",
|
|
70
|
+
image_pattern="*.tif", diameter=None):
|
|
71
|
+
"""
|
|
72
|
+
ディレクトリ内画像のバッチセグメンテーション。
|
|
73
|
+
|
|
74
|
+
Parameters:
|
|
75
|
+
image_dir: str — 入力画像ディレクトリ
|
|
76
|
+
output_dir: str — 出力ディレクトリ
|
|
77
|
+
model_type: str — Cellpose モデル
|
|
78
|
+
"""
|
|
79
|
+
model = models.Cellpose(model_type=model_type, gpu=True)
|
|
80
|
+
image_dir = Path(image_dir)
|
|
81
|
+
output_dir = Path(output_dir)
|
|
82
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
83
|
+
|
|
84
|
+
image_files = sorted(image_dir.glob(image_pattern))
|
|
85
|
+
results = []
|
|
86
|
+
|
|
87
|
+
for img_path in image_files:
|
|
88
|
+
img = io.imread(str(img_path))
|
|
89
|
+
masks, flows, styles, diams = model.eval(
|
|
90
|
+
img, diameter=diameter, channels=[0, 0]
|
|
91
|
+
)
|
|
92
|
+
n_cells = len(np.unique(masks)) - 1
|
|
93
|
+
|
|
94
|
+
# マスク保存
|
|
95
|
+
out_path = output_dir / f"{img_path.stem}_masks.npy"
|
|
96
|
+
np.save(str(out_path), masks)
|
|
97
|
+
|
|
98
|
+
results.append({
|
|
99
|
+
"image": img_path.name,
|
|
100
|
+
"n_cells": n_cells,
|
|
101
|
+
"diameter": float(diams),
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
print(f"Batch: {len(results)} images, "
|
|
105
|
+
f"{sum(r['n_cells'] for r in results)} total cells")
|
|
106
|
+
return results
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## 3. CellProfiler 形態学的プロファイリング
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
import skimage.measure as measure
|
|
113
|
+
import pandas as pd
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def morphological_profiling(image, masks, channel_names=None):
|
|
117
|
+
"""
|
|
118
|
+
CellProfiler スタイルの形態学的特徴量抽出。
|
|
119
|
+
|
|
120
|
+
Parameters:
|
|
121
|
+
image: np.ndarray — 画像 (H, W) or (H, W, C)
|
|
122
|
+
masks: np.ndarray — セグメンテーションマスク
|
|
123
|
+
channel_names: list — チャネル名
|
|
124
|
+
|
|
125
|
+
K-Dense: cellprofiler
|
|
126
|
+
"""
|
|
127
|
+
if image.ndim == 2:
|
|
128
|
+
image = image[..., np.newaxis]
|
|
129
|
+
if channel_names is None:
|
|
130
|
+
channel_names = [f"ch{i}" for i in range(image.shape[-1])]
|
|
131
|
+
|
|
132
|
+
props = measure.regionprops(masks, intensity_image=image[..., 0])
|
|
133
|
+
|
|
134
|
+
features = []
|
|
135
|
+
for prop in props:
|
|
136
|
+
feat = {
|
|
137
|
+
"cell_id": prop.label,
|
|
138
|
+
"area": prop.area,
|
|
139
|
+
"perimeter": prop.perimeter,
|
|
140
|
+
"eccentricity": prop.eccentricity,
|
|
141
|
+
"solidity": prop.solidity,
|
|
142
|
+
"major_axis": prop.major_axis_length,
|
|
143
|
+
"minor_axis": prop.minor_axis_length,
|
|
144
|
+
}
|
|
145
|
+
# 真円度
|
|
146
|
+
if prop.perimeter > 0:
|
|
147
|
+
feat["circularity"] = (4 * np.pi * prop.area) / (prop.perimeter ** 2)
|
|
148
|
+
else:
|
|
149
|
+
feat["circularity"] = 0.0
|
|
150
|
+
|
|
151
|
+
# チャネルごと蛍光強度
|
|
152
|
+
for ch_idx, ch_name in enumerate(channel_names):
|
|
153
|
+
ch_props = measure.regionprops(
|
|
154
|
+
masks, intensity_image=image[..., ch_idx]
|
|
155
|
+
)
|
|
156
|
+
for cp in ch_props:
|
|
157
|
+
if cp.label == prop.label:
|
|
158
|
+
feat[f"{ch_name}_mean"] = cp.mean_intensity
|
|
159
|
+
feat[f"{ch_name}_max"] = cp.max_intensity
|
|
160
|
+
feat[f"{ch_name}_min"] = cp.min_intensity
|
|
161
|
+
break
|
|
162
|
+
|
|
163
|
+
features.append(feat)
|
|
164
|
+
|
|
165
|
+
df = pd.DataFrame(features)
|
|
166
|
+
print(f"Morphological profiling: {len(df)} cells, {len(df.columns)} features")
|
|
167
|
+
return df
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## 4. Cell Painting 解析
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
def cell_painting_analysis(image_5ch, masks, normalize=True):
|
|
174
|
+
"""
|
|
175
|
+
Cell Painting 5 チャネル解析。
|
|
176
|
+
|
|
177
|
+
Channels:
|
|
178
|
+
ch0: DNA (Hoechst), ch1: ER (ConA), ch2: RNA (SYTO14),
|
|
179
|
+
ch3: AGP (Phalloidin), ch4: Mito (MitoTracker)
|
|
180
|
+
|
|
181
|
+
Parameters:
|
|
182
|
+
image_5ch: np.ndarray — (H, W, 5) 画像
|
|
183
|
+
masks: np.ndarray — セグメンテーションマスク
|
|
184
|
+
normalize: bool — Z-score 正規化
|
|
185
|
+
"""
|
|
186
|
+
channel_names = ["DNA", "ER", "RNA", "AGP", "Mito"]
|
|
187
|
+
|
|
188
|
+
# 形態 + 蛍光特徴量抽出
|
|
189
|
+
features_df = morphological_profiling(image_5ch, masks, channel_names)
|
|
190
|
+
|
|
191
|
+
# テクスチャ特徴量 (Haralick-like)
|
|
192
|
+
from skimage.feature import graycomatrix, graycoprops
|
|
193
|
+
|
|
194
|
+
texture_features = []
|
|
195
|
+
for prop in measure.regionprops(masks):
|
|
196
|
+
cell_mask = masks == prop.label
|
|
197
|
+
bbox = prop.bbox
|
|
198
|
+
cell_region = image_5ch[bbox[0]:bbox[2], bbox[1]:bbox[3], 0]
|
|
199
|
+
cell_mask_crop = cell_mask[bbox[0]:bbox[2], bbox[1]:bbox[3]]
|
|
200
|
+
cell_region = (cell_region * cell_mask_crop).astype(np.uint8)
|
|
201
|
+
|
|
202
|
+
if cell_region.max() > 0:
|
|
203
|
+
glcm = graycomatrix(cell_region, [1], [0], levels=256, symmetric=True)
|
|
204
|
+
texture_features.append({
|
|
205
|
+
"cell_id": prop.label,
|
|
206
|
+
"contrast": graycoprops(glcm, "contrast")[0, 0],
|
|
207
|
+
"homogeneity": graycoprops(glcm, "homogeneity")[0, 0],
|
|
208
|
+
"energy": graycoprops(glcm, "energy")[0, 0],
|
|
209
|
+
"correlation": graycoprops(glcm, "correlation")[0, 0],
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
texture_df = pd.DataFrame(texture_features)
|
|
213
|
+
combined = features_df.merge(texture_df, on="cell_id", how="left")
|
|
214
|
+
|
|
215
|
+
if normalize:
|
|
216
|
+
numeric_cols = combined.select_dtypes(include=[np.number]).columns
|
|
217
|
+
numeric_cols = [c for c in numeric_cols if c != "cell_id"]
|
|
218
|
+
combined[numeric_cols] = (
|
|
219
|
+
(combined[numeric_cols] - combined[numeric_cols].mean())
|
|
220
|
+
/ combined[numeric_cols].std()
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
print(f"Cell Painting: {len(combined)} cells, {len(combined.columns)} features")
|
|
224
|
+
return combined
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## 5. napari 3D 可視化
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
def napari_visualization(image, masks=None, points=None, labels=None):
|
|
231
|
+
"""
|
|
232
|
+
napari でインタラクティブ 3D 可視化。
|
|
233
|
+
|
|
234
|
+
Parameters:
|
|
235
|
+
image: np.ndarray — 画像 (Z, Y, X) or (Z, Y, X, C)
|
|
236
|
+
masks: np.ndarray — セグメンテーションマスク
|
|
237
|
+
points: np.ndarray — 座標点 (N, 3)
|
|
238
|
+
labels: list — ポイントラベル
|
|
239
|
+
|
|
240
|
+
K-Dense: napari
|
|
241
|
+
"""
|
|
242
|
+
import napari
|
|
243
|
+
|
|
244
|
+
viewer = napari.Viewer()
|
|
245
|
+
|
|
246
|
+
# 画像レイヤー
|
|
247
|
+
if image.ndim == 4:
|
|
248
|
+
for ch in range(image.shape[-1]):
|
|
249
|
+
viewer.add_image(
|
|
250
|
+
image[..., ch],
|
|
251
|
+
name=f"Channel-{ch}",
|
|
252
|
+
blending="additive",
|
|
253
|
+
)
|
|
254
|
+
else:
|
|
255
|
+
viewer.add_image(image, name="Image")
|
|
256
|
+
|
|
257
|
+
# マスクレイヤー
|
|
258
|
+
if masks is not None:
|
|
259
|
+
viewer.add_labels(masks, name="Segmentation")
|
|
260
|
+
|
|
261
|
+
# ポイントレイヤー
|
|
262
|
+
if points is not None:
|
|
263
|
+
properties = {"label": labels} if labels else None
|
|
264
|
+
viewer.add_points(
|
|
265
|
+
points,
|
|
266
|
+
properties=properties,
|
|
267
|
+
name="Points",
|
|
268
|
+
size=5,
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
print(f"napari viewer: {image.shape}, "
|
|
272
|
+
f"masks={'Yes' if masks is not None else 'No'}")
|
|
273
|
+
return viewer
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## 6. Cellpose カスタムモデル微調整
|
|
277
|
+
|
|
278
|
+
```python
|
|
279
|
+
def finetune_cellpose(train_dir, model_type="cyto2", n_epochs=100,
|
|
280
|
+
learning_rate=0.1):
|
|
281
|
+
"""
|
|
282
|
+
Cellpose モデルの微調整。
|
|
283
|
+
|
|
284
|
+
Parameters:
|
|
285
|
+
train_dir: str — 訓練データ (画像 + _masks)
|
|
286
|
+
model_type: str — ベースモデル
|
|
287
|
+
n_epochs: int — エポック数
|
|
288
|
+
learning_rate: float — 学習率
|
|
289
|
+
"""
|
|
290
|
+
from cellpose import train
|
|
291
|
+
|
|
292
|
+
train_dir = Path(train_dir)
|
|
293
|
+
image_files = sorted(train_dir.glob("*.tif"))
|
|
294
|
+
mask_files = sorted(train_dir.glob("*_masks.tif"))
|
|
295
|
+
|
|
296
|
+
images = [io.imread(str(f)) for f in image_files]
|
|
297
|
+
labels = [io.imread(str(f)) for f in mask_files]
|
|
298
|
+
|
|
299
|
+
model = models.CellposeModel(model_type=model_type, gpu=True)
|
|
300
|
+
model_path = model.train(
|
|
301
|
+
images, labels,
|
|
302
|
+
channels=[0, 0],
|
|
303
|
+
n_epochs=n_epochs,
|
|
304
|
+
learning_rate=learning_rate,
|
|
305
|
+
save_path=str(train_dir / "models"),
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
print(f"Fine-tuned model saved: {model_path}")
|
|
309
|
+
print(f" Base: {model_type}, Epochs: {n_epochs}")
|
|
310
|
+
return model_path
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## 7. 統合イメージングパイプライン
|
|
314
|
+
|
|
315
|
+
```python
|
|
316
|
+
def imaging_pipeline(image_dir, output_dir, model_type="cyto2",
|
|
317
|
+
channels_5=True):
|
|
318
|
+
"""
|
|
319
|
+
セグメンテーション + 特徴量抽出 統合パイプライン。
|
|
320
|
+
|
|
321
|
+
Parameters:
|
|
322
|
+
image_dir: str — 入力画像ディレクトリ
|
|
323
|
+
output_dir: str — 出力ディレクトリ
|
|
324
|
+
model_type: str — Cellpose モデル
|
|
325
|
+
channels_5: bool — 5ch Cell Painting
|
|
326
|
+
"""
|
|
327
|
+
output_dir = Path(output_dir)
|
|
328
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
329
|
+
|
|
330
|
+
# 1) バッチセグメンテーション
|
|
331
|
+
seg_results = batch_segmentation(
|
|
332
|
+
image_dir, output_dir / "masks", model_type=model_type
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
# 2) 特徴量抽出
|
|
336
|
+
all_features = []
|
|
337
|
+
for res in seg_results:
|
|
338
|
+
img_path = Path(image_dir) / res["image"]
|
|
339
|
+
mask_path = output_dir / "masks" / f"{img_path.stem}_masks.npy"
|
|
340
|
+
|
|
341
|
+
img = io.imread(str(img_path))
|
|
342
|
+
masks = np.load(str(mask_path))
|
|
343
|
+
|
|
344
|
+
if channels_5 and img.ndim == 3 and img.shape[-1] == 5:
|
|
345
|
+
feats = cell_painting_analysis(img, masks)
|
|
346
|
+
else:
|
|
347
|
+
feats = morphological_profiling(img, masks)
|
|
348
|
+
|
|
349
|
+
feats["image"] = res["image"]
|
|
350
|
+
all_features.append(feats)
|
|
351
|
+
|
|
352
|
+
combined = pd.concat(all_features, ignore_index=True)
|
|
353
|
+
combined.to_csv(output_dir / "features.csv", index=False)
|
|
354
|
+
|
|
355
|
+
print(f"Pipeline complete: {len(seg_results)} images, "
|
|
356
|
+
f"{len(combined)} cells profiled")
|
|
357
|
+
return combined
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
## パイプライン統合
|
|
363
|
+
|
|
364
|
+
```
|
|
365
|
+
image-analysis → advanced-imaging → medical-imaging
|
|
366
|
+
(OpenCV/基本) (Cellpose/CellProfiler) (DICOM/MONAI)
|
|
367
|
+
│ │ ↓
|
|
368
|
+
fluorescence-microscopy ──┘ drug-target-profiling
|
|
369
|
+
(蛍光画像取得) │ (Cell Painting hit)
|
|
370
|
+
↓
|
|
371
|
+
cheminformatics
|
|
372
|
+
(Cell Painting → 化合物活性)
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
## パイプライン出力
|
|
376
|
+
|
|
377
|
+
| ファイル | 説明 | 次スキル |
|
|
378
|
+
|---------|------|---------|
|
|
379
|
+
| `results/masks/` | セグメンテーションマスク群 | → medical-imaging |
|
|
380
|
+
| `results/features.csv` | 形態学的特徴量マトリクス | → cheminformatics |
|
|
381
|
+
| `results/cell_painting.csv` | Cell Painting プロファイル | → drug-target-profiling |
|
|
382
|
+
| `results/model/` | 微調整 Cellpose モデル | — |
|