Skip to content

Latest commit

 

History

History
278 lines (220 loc) · 12.9 KB

File metadata and controls

278 lines (220 loc) · 12.9 KB

fturader CLI reference

The unified fturader command handles both H&E brightfield and multiplex fluorescence (CODEX / OME-TIFF) inputs through a single entry point.

Migration note: the older commands fturader-infer (H&E only) and fturader-multiplex (multiplex only) are backward-compatibility aliases. They share the same core logic as fturader and are deprecated; they will be removed in a future release.


Full parameter list

usage: fturader [-h] --input PATH [--he {auto,true,false}] [--channel-names TXT]
                [--pixel-size UM] [--region REGION] [--recipe RECIPE]
                [--organ {kidney,largeintestine,lung,prostate,spleen}]
                [--score-threshold T] [--min-mask-area PX2]
                [--weights-root DIR] [--sam2-config SAM2_CONFIG]
                [--finder-device DEV] [--sam-device DEV]
                [--overlap-filter {NON_MAX_MERGE,NON_MAX_SUPPRESSION}]
                [--overlap-metric {IOU,IOS}] [--iou-threshold T]
                [--output-dir DIR] [--save-overlay] [--print-classification]
Argument Default Description
--input PATH required Image file (TIFF / OME-TIFF / PNG / JPG) or a processed CODEX directory
--he {auto,true,false} auto H&E handling. auto auto-detects (passthrough for ≤3-ch brightfield, synthesize for multichannel); true forces H&E / brightfield passthrough (no synthesis); false forces fluorescence synthesis even for a 3-channel image
--channel-names TXT Path to channelnames.txt; required for non-OME multiplex TIFFs
--pixel-size UM auto Physical pixel size µm/px (read from OME-XML when available)
--region REGION 1 Region index for CODEX datasets
--recipe RECIPE auto Pseudo-H&E recipe: auto | auto:mean | auto:max | ck | comma-separated list of eosin markers (e.g. Cytokeratin,Vimentin). v1 / v2 still work but are deprecated aliases.
--organ largeintestine Target organ; selects the RF-DETR checkpoint and default thresholds. One of kidney / largeintestine / lung / prostate / spleen
--score-threshold T 0 (organ default) RF-DETR confidence threshold; 0 = use the organs.py organ default
--min-mask-area PX2 0 (organ default) Minimum mask area px²; 0 = use the organs.py organ default
--weights-root DIR ~/.deepcell/models/ftusam_v0.1 Model-weights root directory
--sam2-config configs/sam2.1/sam2.1_hiera_b+.yaml SAM2 config file
--finder-device DEV cuda PyTorch device for RF-DETR (use CUDA_VISIBLE_DEVICES to pick the GPU)
--sam-device DEV cuda PyTorch device for SAM2
--overlap-filter NON_MAX_MERGE Cross-tile merge strategy: NON_MAX_MERGE or NON_MAX_SUPPRESSION
--overlap-metric IOS Overlap metric for cross-tile de-duplication: IOU or IOS
--iou-threshold T 0.5 IoU/IoS threshold for cross-tile merging
--output-dir DIR required* Output directory (*may be omitted with --print-classification)
--save-overlay flag Also write the exp4-style turbo filled-mask overlay (full image + short-side-2000px JPEG)
--print-classification flag Dry run: print channel classification and exit (no inference)

Organ default thresholds (single source: src/fturader/organs.py):

Organ min_mask_area (px²) score_threshold
prostate 40 0.33
largeintestine 200 0.36
lung 1 000 0.25
kidney 5 000 0.25
spleen 10 000 0.38

Lung default raised in R3 (score_threshold 0.13 → 0.25, min_mask_area1 000) for cleaner, faster output. To get fewer, cleaner detections on any organ, raise --score-threshold and/or --min-mask-area above the organ default (0 keeps the default).


Example commands

1. Kidney H&E (brightfield passthrough, no synthesis)

fturader \
    --input  "/data/user-data/qli2/FTU/datasets/hubmap_dataset/\
Kidney-HandE-Stained-Microscopy(HBM269.FMTJ.275)-3a7480e53dc874ce2199cb73b31b4bdd/\
lab_processed/images/V12D05-071_XY02_K21-00202-1.ome.tiff" \
    --he true \
    --organ  kidney \
    --weights-root /home/qli2/fturader/model_weights \
    --output-dir ./out_kidney/ \
    --save-overlay

2. Large-intestine CODEX as an OME-TIFF (HBM685; names + pixel size from OME-XML)

The HBM685 pipeline output is a single multichannel OME-TIFF whose OME-XML carries the 54 channel names and the pixel size, so no --channel-names / --pixel-size is needed.

fturader \
    --input  "/data/user-data/qli2/FTU/datasets/hubmap_dataset/\
LargeIntestine-ANNO_CODEX(HBM685.PCCJ.427)-c8fa615fb884c7b51d08c0cf35debfee/\
ometiff-pyramids/pipeline_output/expr/reg001_expr.ome.tif" \
    --recipe auto \
    --organ  largeintestine \
    --weights-root /home/qli2/fturader/model_weights \
    --output-dir ./out_hbm685/ \
    --save-overlay

3. Processed CODEX directory (HBM573; verified HuBMAP reg001 layout)

Pointing --input at a processed CODEX directory triggers CodexDataset, which reads Experiment.json / tileMap.txt / channelnames.txt itself. This path is supported only for the verified HuBMAP reg{NNN}_X##_Y##.tif layout (see "Loading boundary" below).

fturader \
    --input  "/data/user-data/qli2/FTU/datasets/hubmap_dataset/\
LargeIntestine-CODEX(HBM573.TTLG.748)-8eeca1a98041348bb14fd652b766661e/processed" \
    --recipe ck \
    --organ  largeintestine \
    --weights-root /home/qli2/fturader/model_weights \
    --output-dir ./out_hbm573/ \
    --save-overlay

HBM288 caveat (not directly loadable via the CLI). HBM288 names its tiles reg004_* while its tileMap.txt records RegionNumber=1, so the default CODEX directory loader looks for reg001_* and fails. The CLI does not expose a --tile-pattern override. Handle HBM288 in Python with TiledDataset.from_tiles(..., region=1, tile_pattern="reg004_X{x:02d}_Y{y:02d}.tif"), or pre-stitch it into one image and use SingleImageDataset.from_image.

Dry run: print channel classification only

fturader --input /path/to/stitched.ome.tif --print-classification

Loading boundary

The maintained Python loading contracts are two first-class entries by input shape: SingleImageDataset.from_image (one assembled image + manual metadata; tile_grid= for a big multi-z image processed block-wise) and TiledDataset.from_tiles (a grid of separate tiles + geometry, modality-agnostic). CodexDataset is deprecated and delegates to the from_tiles engine for the verified HuBMAP reg{NNN}_X##_Y##.tif layout.

The CLI exposes only the single---input path (one image, or a processed CODEX dir) and intentionally has no --tile-pattern flag. Anything needing custom geometry — HBM288's reg004 quirk, explicit tile positions, a custom reader_factory, or tile_grid block-wise focus — is Python API only: use TiledDataset.from_tiles / SingleImageDataset.from_image directly, or pre-stitch into one image first. See docs/multiplex_pseudo_he.md.


Output bundle

Files written under --output-dir:

output_dir/
  labels.tif          (H, W) uint16/uint32 instance label map
  detections.npz      compact-RLE per-instance masks + scores
  summary.json        run metadata
  overlay_full.jpg    [--save-overlay] exp4-style full-resolution overlay
  overlay_2000.jpg    [--save-overlay] short-side-2000px version

labels.tif

  • Shape (H, W), dtype uint16 (N < 65535) or uint32.
  • Pixel value 0 = background, 1..N = instance index.
  • Overlapping instances: higher confidence painted last (overlap_strategy = "higher-confidence-on-top").

detections.npz keys

Always present:

Key Shape / dtype Meaning
xyxy (N, 4) float32 Bounding boxes (x1, y1, x2, y2) in original-image pixels
confidence (N,) float32 Combined score √(rf_score × sam_score) (all-NaN when unset)
label_id (N,) uint16/uint32 Pixel value in labels.tif (1-indexed); matches the labels.tif dtype

Per-instance mask, compact-RLE encoding (written when compact_masks=True, the default):

Key Shape / dtype Meaning
mask_rle_flat (sum Lᵢ,) int32 All per-instance RLE runs concatenated
mask_rle_lengths (N,) int32 Run-count Lᵢ per instance (splits mask_rle_flat)
mask_crop_shapes (N, 2) int32 Per-instance crop size (h, w)
mask_offsets (N, 2) int32 Per-instance crop top-left offset (x, y)
mask_image_hw (2,) int32 Original image size (H, W)

Optional (present only when the detections carry them — they do for normal inference):

Key Shape / dtype Meaning
rf_score (N,) float32 Raw RF-DETR confidence
sam_score (N,) float32 SAM2 mask-quality score

When the bundle was saved with compact_masks=False, the mask keys above are replaced by a single mask_dense (N, H, W) uint8 array instead.

Format rationale (compact-RLE vs dense): see multiplex_exp/2026-06-19/U2_detections_format_FINDINGS_CN.md.

summary.json fields

Field Meaning
organ Organ name
pixel_size_um µm/px used for inference
score_threshold Score threshold actually used
min_mask_area Minimum mask area actually used
weights Nested object {"rf_detr": <path>, "sam2": <path>}
n_detections Number of detected FTUs
label_dtype numpy dtype string of labels.tif
overlap_strategy Mask-overlap strategy — exactly "higher-confidence-on-top"
output_files List of files actually written
input Absolute path of the input passed to the CLI
region Region index used
pseudo_he_report Effective pseudo-H&E report — the config actually used, mirroring the _refine_auto SNR selection (multiplex inputs only). The legacy fturader-multiplex CLI instead writes pseudo_he_config.
profile Per-stage wall-clock timings (the CLI always runs infer_wsi(profile=True))

The profile block mirrors FTURader.last_profile (equivalently segment_ftu(..., profile=True, return_report=True)["infer"]["profile"]). Keys: scale_s, n_tiles, tile_forward_s (RF-DETR + SAM2 tile inference), assemble_s (cross-tile concat), merge_s (the NMM/NMS dedup — timed directly by wrapping sv.Detections.with_nmm), slicer_overhead_s, rescale_s, total_s, n_detections.

NMM is the bottleneck at high detection counts. Across R3 runs tile_forward_s (inference) stays bounded at ~2–19 s, while merge_s scales with detection count and dominates: HBM573 6 det → 0.02 s; CODEX ~26 det → ~1.0 s; lung 6000²-px @ 0.25 ~219 det → ~27 s; HBM288 full 247 det → 99 s (≈80 % of a 124 s run). 8× more detections (26 → 209) → ~46× the merge time, inference roughly unchanged. Raising --score-threshold / --min-mask-area makes runs both cleaner and faster.


Reloading in Python (fturader.io.load_detections)

from fturader.io import load_detections

# One call reloads an sv.Detections plus the summary.json metadata dict.
dets, meta = load_detections("./out_kidney/")

# dets: sv.Detections
#   .xyxy          (N, 4) float32   bounding boxes in original-image pixels
#   .confidence    (N,)   float32   combined score (None when it was unset)
#   .mask          CompactMask (RLE crops) by default; dense (N, H, W) bool only
#                  when the bundle was saved with compact_masks=False
#   .data          {"label_id", "rf_score", "sam_score"} when present in the npz
#
# meta: dict = the summary.json contents (organ, pixel_size_um, n_detections, weights, …)

print(f"{len(dets)} FTUs, organ={meta['organ']}")
# The original image size is in the npz as mask_image_hw — summary.json has no image_shape.

Backward-compatibility aliases

Old command Status Equivalent
fturader-infer deprecated (kept for compatibility) fturader --he true --organ <organ>
fturader-multiplex deprecated (kept for compatibility) fturader --recipe <recipe> --organ <organ>

fturader-infer additionally accepts the legacy WSI flags --tiled, --overlap-ratio, --iou-threshold, --overlap-filter, and --overlap-metric so that old invocations keep working (inference is always tiled, so --tiled is a no-op). The aliases share their core logic with fturader (implemented in src/fturader/cli/_common.py).


Related documentation