Skip to main content

HE-to-IHC whole-slide image alignment pipeline

Project description

HISAlign banner

Whole-slide image alignment for H&E and multiplex IHC markers

English · 简体中文

Python 3.11+ Version 0.2.0 MIT License


"Align once. Map everywhere."
"一次配准,处处映射"


HISAlign registration before/after

✨ Why HISAlign

Problem Solution
H&E and multiple IHC slides of the same tissue are spatially misaligned Rigid + optical-flow non-rigid registration, per-marker alignment to H&E
Registration results depend on open slide handles and are hard to reuse Only numpy arrays and transform parameters are saved; fully serializable
Downstream analysis needs to map ROIs from H&E to IHC Offline warp_xy interface: provide level-0 coordinates and get mapped coordinates
Need a quick way to assess registration quality Optional unified viz_report.html with slide summary and patch gallery

🎨 Workflow

flowchart LR
    HE["H&E Reference"]
    IHC["IHC Markers\nCD3 / Ki67 / ..."]
    PRE["Optical Density\nPreprocessing"]
    RIGID["Rigid Registration"]
    NR["Optical-Flow\nNon-Rigid"]
    MODEL["model.pkl\nSerializable Model"]
    WARP["warp_xy\nOffline Mapping"]
    VIZ["viz_report.html"]

    HE --> PRE
    IHC --> PRE
    PRE --> RIGID
    RIGID --> NR
    NR --> MODEL
    MODEL --> WARP
    NR --> VIZ

🚀 Installation

Install from PyPI using uv:

uv tool install hisalign

Or install it as a library in your current environment:

uv pip install hisalign

Verify the CLI entry point:

hisalign --help

🧪 Quickstart

Python API

from hisalign import HisAlign, HisAlignModel

# 1. Fit and save the model
aligner = HisAlign(
    he_path="HE.kfb",
    ihc_paths={"CD3": "CD3.svs", "Ki67": "Ki67.svs"},
    registration_level=3,
    max_image_dim_px=1024,
    preprocessing="od",
    feature_detector="kaze",
    mpp=0.25,  # explicit when slide metadata lacks MPP
)
model = aligner.fit()
model.save("model.pkl")

# 2. Offline coordinate mapping (no slides needed)
loaded = HisAlignModel.load("model.pkl")
mapped = loaded.warp_xy(
    coords=[[1000, 2000]],  # H&E level-0 pixel coordinates
    marker="CD3",
    direction="he_to_ihc",
)
print(mapped)  # -> [[ihc_x, ihc_y]]

CLI

1. Register and save the model

hisalign register \
  --he HE.kfb \
  --ihc CD3=CD3.svs \
  --ihc Ki67=Ki67.svs \
  --output model.pkl \
  --config configs/default.yaml \
  --mpp 0.25

If you omit marker=, the marker name is derived from the last token of the filename stem. hisalign register only produces model.pkl by default; set generate_report: true in the config to also emit viz_report.html.

2. Warp coordinates with the model

hisalign warp \
  --model model.pkl \
  --marker CD3 \
  --direction he_to_ihc \
  --coords coords.csv \
  --output mapped.csv

The input CSV must contain x and y columns; the output adds marker and direction columns.

3. Generate visualizations from an existing model

hisalign visualize \
  --model model.pkl \
  --output-dir ./out \
  --config configs/default.yaml

Default behavior: hisalign register only writes model.pkl by default. Set generate_report: true in your config (or in configs/default.yaml) to also produce the unified viz_report.html.

register also writes viz_report.html automatically when visualization is enabled.


🖼️ Works with Plain Images Too

The repo includes whole-slide thumbnail exports of an H&E slide and a CD3 IHC slide (examples/images/he.jpg and examples/images/ihc.jpg) for a quick demo:

python examples/register_jpg.py --output-dir ./out

For synthetic data:

python examples/register_jpg.py --synthetic --output-dir ./out

Or provide your own images:

python examples/register_jpg.py --he he.jpg --ihc ihc.jpg --output-dir ./out

📐 Coordinate Convention

⚠️ All coordinates are level-0 (highest resolution) pixel coordinates.

  • Order is (x, y) = (column, row).
  • Origin is the top-left corner.
  • For coordinates from another pyramid level, scale them to level-0 first.

📦 Supported Formats

Type Formats
KFBio native .kfb
OpenSlide .svs, .tif/.tiff, .ndpi, .vms/.vmu, .mrxs, .scn
Plain images .jpg, .jpeg, .png, .bmp

📤 Outputs

After running hisalign register:

  • model.pkl — serializable alignment model containing all spatial transforms; no original slides required afterwards.

If visualization is enabled, the same directory also contains:

  • viz_report.htmlunified visualization report: a single self-contained web page with two tabs. The "Slide Summary" tab shows overlay comparisons, rTRE statistics, per-marker thumbnails, and deformation fields. The "Patch Gallery" tab shows the sampled patches with global context and local HE/IHC patch comparisons. Images are JPEG-compressed and web-sized so the file stays small enough to open and share.

Tip: The default configs/default.yaml has generate_report: false. Set it to true to get viz_report.html directly from hisalign register without running hisalign visualize.


⚙️ Configuration

Key items in configs/default.yaml:

registration_level: 3          # pyramid level used for registration
max_image_dim_px: 1024         # longest side of the processed registration image
preprocessing: "od"            # "od" optical density | "gray" simple grayscale
feature_detector: "kaze"       # kaze / akaze / sift / orb / brisk
feature_n_levels: 3
match_max_ratio: 1.0           # Lowe ratio test; 1.0 disables
mpp: null                      # level-0 pixel size (µm/px); set when metadata is missing

# Visualization
viz_sample_n: 8              # number of patches in gallery, 0 to disable
viz_global_thumb_max_dim_px: 512  # longest side of global location thumbnails
viz_image_format: "jpeg"      # png | jpeg — base format for most figures
viz_image_quality: 85         # JPEG quality (0-100), ignored for PNG
viz_overlay_dpi: 80           # DPI for overlay figures
viz_thumb_dpi: 80             # DPI for per-marker thumbnails
viz_deformation_dpi: 60       # DPI for deformation field plots
viz_patch_dpi: 80             # DPI for patch gallery figures
viz_patch_image_format: "jpeg"  # format specifically for patch gallery
viz_patch_image_quality: 85     # JPEG quality for patch gallery
viz_patch_max_px: 512         # local patches are resized to this longest side before plotting
viz_patch_col_inches: 2.5     # width per marker column in patch gallery figures
generate_report: false        # whether to generate viz_report.html
report_rtre_threshold: 5.0    # rTRE threshold for "good" highlighting

🗂️ Project Structure

hisalign/
├── README.md
├── README.zh.md
├── pyproject.toml
├── configs/default.yaml
├── examples/
│   ├── register_jpg.py
│   └── images/
│       ├── he.jpg
│       └── ihc.jpg
├── src/hisalign/
│   ├── api.py
│   ├── cli.py
│   ├── preprocessing.py
│   ├── registration/
│   ├── slide_io/
│   └── viz.py
└── tests/

🧪 Try It

The fastest way to verify the installation and see HISAlign in action is to run the bundled example:

python examples/register_jpg.py --output-dir ./out

This registers the real whole-slide thumbnails in examples/images/ and produces:

  • out/model.pkl
  • out/00_unregistered.png
  • out/01_rigid.png
  • out/02_nonrigid.png

Example Results

After running the command above, open the generated overlays:

  • out/00_unregistered.png — green/magenta overlay before registration (structures are shifted).
  • out/01_rigid.png — overlay after rigid registration.
  • out/02_nonrigid.png — overlay after non-rigid registration; overlapping structures turn white/gray.

Green = H&E, magenta = CD3 IHC.


🙋 Author

Created with 💙 by Yifan Feng
📧 evanfeng97@gmail.com


📚 References

  • VALIS: Virtual Alignment of pathology Image Series
  • DISK: Learning local features with policy gradient (Tyszkiewicz et al., NeurIPS 2020)
  • LightGlue: Local Feature Matching at Light Speed (Lindenberger et al., CVPR 2023)

Making whole-slide alignment as intuitive as solving a jigsaw puzzle.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hisalign-0.2.0.tar.gz (2.1 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hisalign-0.2.0-py3-none-any.whl (52.1 kB view details)

Uploaded Python 3

File details

Details for the file hisalign-0.2.0.tar.gz.

File metadata

  • Download URL: hisalign-0.2.0.tar.gz
  • Upload date:
  • Size: 2.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for hisalign-0.2.0.tar.gz
Algorithm Hash digest
SHA256 301675f5dca69082f149d7c7d28b6f7d2fc4389b4970d8a4aa24fd0a0804b081
MD5 c79611185a7eb061f9361faa69dbabc2
BLAKE2b-256 a8e83083cb1f0b1f2d915887d82cef87e350e49246b86c799ff7a4f732a96e5e

See more details on using hashes here.

Provenance

The following attestation bundles were made for hisalign-0.2.0.tar.gz:

Publisher: publish.yml on yifanfeng97/hisalign

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file hisalign-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: hisalign-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 52.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for hisalign-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e81b1fb4eccdaf7ec2b2ce2987e94ac22f877eaffb007180e8f0b55b2900ba09
MD5 8be1b0393354cbcae8c367adf1398fee
BLAKE2b-256 3db7293f2e80077d58b55bcc8072d1174d8fc139001106eee80f7df54b352289

See more details on using hashes here.

Provenance

The following attestation bundles were made for hisalign-0.2.0-py3-none-any.whl:

Publisher: publish.yml on yifanfeng97/hisalign

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page