Spaces:
Running on Zero
Running on Zero
File size: 3,957 Bytes
73e760d 47c4bf8 73e760d 47c4bf8 73e760d 47c4bf8 73e760d 47c4bf8 73e760d 47c4bf8 73e760d 47c4bf8 73e760d 47c4bf8 73e760d 47c4bf8 73e760d 47c4bf8 73e760d 47c4bf8 73e760d 47c4bf8 73e760d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | """
High-level Python API for Rootscope.
from rootscope import predict_tif, predict_folder
df = predict_tif("image.tif", out_dir="results/", gpu=True)
df = predict_folder("my_tifs/", out_dir="results/", gpu=True)
Both return a pandas DataFrame of per-cell predictions and also write
per-image CSVs + labeled overlay PNGs into ``out_dir``.
"""
from pathlib import Path
import pandas as pd
from . import predict as _predict
from .weights import is_v4, resolve_cnn_weights, resolve_model_dir
def _load(model_dir=None, cnn_weights=None):
"""Resolve weights for the selected model version.
v4 returns ``(model_dir, None, None, None, cnn)``: its classifiers are
loaded inside the v4 stage (one bundle per seed, each carrying its own
scaler and feature list), so there is nothing to pre-load here.
"""
mdir = resolve_model_dir(model_dir)
cnn = resolve_cnn_weights(cnn_weights)
if is_v4():
return mdir, None, None, None, cnn
models_dict, scalers, feature_cols, le = _predict.load_models(str(mdir))
if not models_dict:
raise RuntimeError(f"No usable models found in {mdir}.")
return models_dict, scalers, feature_cols, le, cnn
def _gpu_available():
try:
import torch
return bool(torch.cuda.is_available())
except Exception: # noqa: BLE001
return False
def _run_one(tif, loaded, out_dir, gpu, um_per_px, max_rounds, label_cells):
if gpu is None: # library default: use a GPU if there is one
gpu = _gpu_available()
models_dict, scalers, feature_cols, le, cnn = loaded
if is_v4():
return _predict.predict_single_tif_v4(
str(tif), model_dir=str(models_dict), um_per_px=um_per_px, gpu=gpu,
out_dir=str(out_dir), max_rounds=max_rounds,
cnn_weights=str(cnn) if cnn else None, label_cells=label_cells,
)
return _predict.predict_single_tif(
str(tif), models_dict, scalers, feature_cols, le,
um_per_px=um_per_px, gpu=gpu, out_dir=str(out_dir),
max_rounds=max_rounds, cnn_weights=str(cnn) if cnn else None,
label_cells=label_cells,
)
def predict_tif(
tif,
out_dir="results",
gpu=None,
model_dir=None,
cnn_weights=None,
um_per_px=None,
max_rounds=None,
label_cells=False,
):
"""Segment + predict cell types for a single TIFF. Returns a DataFrame.
``um_per_px=None`` reads the pixel size from the TIFF's OME metadata and
fails loudly if it is absent -- a wrong scale distorts every size feature.
``max_rounds=None`` uses the version's own setting (6 for v4, 10 for v2).
"""
loaded = _load(model_dir, cnn_weights)
return _run_one(tif, loaded, out_dir, gpu, um_per_px,
_predict.default_rounds(max_rounds), label_cells)
def predict_folder(
tif_dir,
out_dir="results",
gpu=None,
model_dir=None,
cnn_weights=None,
um_per_px=None,
max_rounds=None,
label_cells=False,
pattern="*.tif",
):
"""Segment + predict for every TIFF in a folder. Returns a combined
DataFrame and writes ``all_predictions.csv`` into ``out_dir``."""
loaded = _load(model_dir, cnn_weights)
rounds = _predict.default_rounds(max_rounds)
tif_paths = sorted(Path(tif_dir).glob(pattern))
if not tif_paths:
raise FileNotFoundError(f"No files matching {pattern} in {tif_dir}")
tables = []
for tp in tif_paths:
try:
df = _run_one(tp, loaded, out_dir, gpu, um_per_px, rounds, label_cells)
if df is not None:
tables.append(df)
except Exception as e: # noqa: BLE001
print(f" FAILED on {tp.name}: {e}")
if not tables:
return None
combined = pd.concat(tables, ignore_index=True)
out = Path(out_dir)
out.mkdir(parents=True, exist_ok=True)
combined.to_csv(out / "all_predictions.csv", index=False)
return combined
|