Skill Tracer
Skills › Scientific Agent Skills › histolab › typical_workflows.md

typical_workflows.md

107 lines · skills/histolab/references/typical_workflows.md at 5f2bc03

Open on GitHub
1# Typical workflows (Histolab 0.7.0)
2
3These recipes use local inputs and distinct output directories. They are tested
4with a small bundled SVS and synthetic images; parameter choices still need
5validation for the user's tissue, scanner and study. Paths below are illustrative.
6Do not derive train/validation/test splits from tiles after extraction: assign
7patients first and preserve the mapping throughout preparation.
8

Typical workflows (Histolab 0.7.0)

These recipes use local inputs and distinct output directories. They are tested with a small bundled SVS and synthetic images; parameter choices still need validation for the user's tissue, scanner and study. Paths below are illustrative. Do not derive train/validation/test splits from tiles after extraction: assign patients first and preserve the mapping throughout preparation.

Raw lines 1 to 8
9## Random, grid and scored extraction
11This shared function previews the exact extraction mask and configuration,
12separates previews from tiles, and verifies output rather than trusting logs.
14<!-- recipe: extract-run -->
15```python
16from pathlib import Path
17from histolab.slide import Slide
18from histolab.masks import TissueMask
19from histolab.tiler import ScoreTiler
21def extract_run(slide_path, output_dir, tiler, mask=None):
22 if tiler.mpp is not None:
23 raise ValueError("This helper supports level-based extraction only")
24 output_dir = Path(output_dir)
25 output_dir.mkdir(parents=True, exist_ok=False)
26 tiles_dir = output_dir / "tiles"
27 tiles_dir.mkdir()
28 slide = Slide(slide_path, processed_path=tiles_dir)
29 if tiler.level not in slide.levels:
30 raise ValueError("Choose an available slide level")
31 mask = TissueMask() if mask is None else mask
32 slide.thumbnail.save(output_dir / "thumbnail.png")
33 slide.locate_mask(mask).save(output_dir / "mask.png")
34 tiler.locate_tiles(slide, extraction_mask=mask).save(output_dir / "locations.png")
35 options = {"extraction_mask": mask}
36 if isinstance(tiler, ScoreTiler):
37 options["report_path"] = str(output_dir / "scores.csv")
38 tiler.extract(slide, **options)
39 paths = sorted(tiles_dir.glob(f"*{tiler.suffix}"))
40 if not paths:
41 raise RuntimeError("No tiles saved; inspect mask, size, level and tissue threshold")
42 return paths
43```
45The fresh-directory requirement preserves earlier runs. Failed extraction may
46leave a partial new directory; inspect it before retrying into another directory.
47This helper targets **level-based extraction**; configure and validate optional
48MPP backends separately.
50```python
51from histolab.tiler import RandomTiler, GridTiler, ScoreTiler
52from histolab.scorer import NucleiScorer
54# Choose one recipe; each processes its input slide independently.
55random_tiles = extract_run("slide.svs", "output/random", RandomTiler(
56 tile_size=(256, 256), n_tiles=20, level=0, seed=42,
57 check_tissue=True, tissue_percent=80.0,
58))
59grid_tiles = extract_run("slide.svs", "output/grid", GridTiler(
60 tile_size=(256, 256), level=0, pixel_overlap=0,
61 check_tissue=True, tissue_percent=80.0,
62))
63scored_tiles = extract_run("slide.svs", "output/scored", ScoreTiler(
64 tile_size=(256, 256), level=0, n_tiles=10, scorer=NucleiScorer(),
65 check_tissue=True,
66))
67```
69Use the score-report plot in the visualization reference on `scores.csv`.
70NucleiScorer selects nuclear-stain-rich regions, not validated high-quality or
71malignant tissue. ScoreTiler evaluates the whole eligible grid even for ten
72output tiles and can fail for degenerate constant scores.

Random, grid and scored extraction

This shared function previews the exact extraction mask and configuration, separates previews from tiles, and verifies output rather than trusting logs.

<!-- recipe: extract-run -->

from pathlib import Path
from histolab.slide import Slide
from histolab.masks import TissueMask
from histolab.tiler import ScoreTiler

def extract_run(slide_path, output_dir, tiler, mask=None):
    if tiler.mpp is not None:
        raise ValueError("This helper supports level-based extraction only")
    output_dir = Path(output_dir)
    output_dir.mkdir(parents=True, exist_ok=False)
    tiles_dir = output_dir / "tiles"
    tiles_dir.mkdir()
    slide = Slide(slide_path, processed_path=tiles_dir)
    if tiler.level not in slide.levels:
        raise ValueError("Choose an available slide level")
    mask = TissueMask() if mask is None else mask
    slide.thumbnail.save(output_dir / "thumbnail.png")
    slide.locate_mask(mask).save(output_dir / "mask.png")
    tiler.locate_tiles(slide, extraction_mask=mask).save(output_dir / "locations.png")
    options = {"extraction_mask": mask}
    if isinstance(tiler, ScoreTiler):
        options["report_path"] = str(output_dir / "scores.csv")
    tiler.extract(slide, **options)
    paths = sorted(tiles_dir.glob(f"*{tiler.suffix}"))
    if not paths:
        raise RuntimeError("No tiles saved; inspect mask, size, level and tissue threshold")
    return paths

The fresh-directory requirement preserves earlier runs. Failed extraction may leave a partial new directory; inspect it before retrying into another directory. This helper targets level-based extraction; configure and validate optional MPP backends separately.

from histolab.tiler import RandomTiler, GridTiler, ScoreTiler
from histolab.scorer import NucleiScorer

# Choose one recipe; each processes its input slide independently.
random_tiles = extract_run("slide.svs", "output/random", RandomTiler(
    tile_size=(256, 256), n_tiles=20, level=0, seed=42,
    check_tissue=True, tissue_percent=80.0,
))
grid_tiles = extract_run("slide.svs", "output/grid", GridTiler(
    tile_size=(256, 256), level=0, pixel_overlap=0,
    check_tissue=True, tissue_percent=80.0,
))
scored_tiles = extract_run("slide.svs", "output/scored", ScoreTiler(
    tile_size=(256, 256), level=0, n_tiles=10, scorer=NucleiScorer(),
    check_tissue=True,
))

Use the score-report plot in the visualization reference on scores.csv. NucleiScorer selects nuclear-stain-rich regions, not validated high-quality or malignant tissue. ScoreTiler evaluates the whole eligible grid even for ten output tiles and can fail for degenerate constant scores.

Raw lines 9 to 73
74## Cohort processing
76```python
77from pathlib import Path
78from histolab.tiler import RandomTiler
80for slide_path in sorted(Path("slides").glob("*.svs")):
81 tiler = RandomTiler(tile_size=(256, 256), n_tiles=20, level=0, seed=42)
82 paths = extract_run(slide_path, Path("output/cohort") / slide_path.stem, tiler)
83 print("[OK]", slide_path.name, len(paths))
84```
86Resolve duplicate slide stems in the input manifest before using them as keys.
87For every run, store the source slide ID/hash, patient and split, software
88versions, level/MPP metadata, output pixel size, mask/filter parameters,
89tiler/scorer parameters, seed, expected/actual tile count and any QC rejection.
90Across scanners, equal level numbers do not imply equal physical resolution.
91This sequential example does not validate parallel access or cohort-scale memory.

Cohort processing

from pathlib import Path
from histolab.tiler import RandomTiler

for slide_path in sorted(Path("slides").glob("*.svs")):
    tiler = RandomTiler(tile_size=(256, 256), n_tiles=20, level=0, seed=42)
    paths = extract_run(slide_path, Path("output/cohort") / slide_path.stem, tiler)
    print("[OK]", slide_path.name, len(paths))

Resolve duplicate slide stems in the input manifest before using them as keys. For every run, store the source slide ID/hash, patient and split, software versions, level/MPP metadata, output pixel size, mask/filter parameters, tiler/scorer parameters, seed, expected/actual tile count and any QC rejection. Across scanners, equal level numbers do not imply equal physical resolution. This sequential example does not validate parallel access or cohort-scale memory.

Raw lines 74 to 92
93## Custom detection
95Construct `TissueMask(*mask_filters)` using the filters reference and pass that
96same object as `mask=custom_mask` to `extract_run`. Larger morphology thresholds
97may discard small real tissue; compare results before and after the change.
98`BiggestTissueBoxMask()` can instead restrict extraction to a largest-region
99rectangle, at the cost of excluding other sections.

Custom detection

Construct TissueMask(*mask_filters) using the filters reference and pass that same object as mask=custom_mask to extract_run. Larger morphology thresholds may discard small real tissue; compare results before and after the change. BiggestTissueBoxMask() can instead restrict extraction to a largest-region rectangle, at the cost of excluding other sections.

Raw lines 93 to 100
101## Optional normalization
103After extracting and inspecting RGB tiles, fit a Macenko or Reinhard normalizer
104on a representative training-only target. Transform each tile, save to a distinct
105normalized directory with the same source tile identifier, and preserve original
106tiles and target provenance. Do not fit on held-out patient tissue or normalize
107quantitative IHC measurements without a validated assay-specific protocol.

Optional normalization

After extracting and inspecting RGB tiles, fit a Macenko or Reinhard normalizer on a representative training-only target. Transform each tile, save to a distinct normalized directory with the same source tile identifier, and preserve original tiles and target provenance. Do not fit on held-out patient tissue or normalize quantitative IHC measurements without a validated assay-specific protocol.

Raw lines 101 to 107