Torch-first stain normalization for histopathology images with batch processing, training transforms, and optional CUDA kernels.
0.1.x migration (from 0.0.x): CuPy backends were removed in 0.1.0. Pin
stainx<0.1to stay on the CuPy stack, or switch to Torch tensors withbackend="torch"/"torch_cuda". Current release: seestainx.__version__/ PyPI.
Features
- Multiple algorithms: Histogram Matching, Reinhard, and Macenko normalization
- Torch backends:
torch(CPU / CUDA / MPS) and optionaltorch_cudacompiled kernels - Training-ready:
StainNormalizerTransformfor DataLoader / torchvision pipelines
Installation
Requirements
- Python >= 3.11
- PyTorch >= 2.0.0
- Optional CUDA extension: CUDA GPU visible to PyTorch at build time and
nvcc
Supported platforms
| Platform | Support |
|---|---|
| Linux + CUDA | Primary (Torch + optional CUDA extension) |
| Linux CPU | Primary (Torch backend) |
| Windows | Torch path in CI (CUDA extension not guaranteed) |
| macOS (MPS / CPU) | Best-effort Torch path (no CUDA extension; not in CI) |
Install from PyPI
pip install stainx
PyPI publishes an sdist. Torch backends work out of the box; torch_cuda
compiles locally only when the CUDA build gates are met (no prebuilt CUDA wheels).
Install from source (recommended: Makefile)
git clone https://github.com/rendeirolab/stainx.git
cd stainx
make install # editable + best-effort CUDA build
# or
make install-dev # + test/docs tooling
Plain pip also works:
pip install .
# Extension builds when torch.cuda.is_available() and nvcc are present; otherwise Torch-only.
# Prefer make install if you want compile failures to be skipped gracefully.
Quick Start
Use float tensors in [0, 1] (or uint8). Prefer torch.rand — Macenko does not
accept negative pixels from torch.randn.
import torch
from stainx import Reinhard, Macenko, HistogramMatching, StainNormalizerTransform
reference_image = torch.rand(1, 3, 512, 512)
source_images = torch.rand(10, 3, 512, 512)
normalizer = Reinhard(device="cuda") # or "cpu" / "mps"
normalizer.fit(reference_image)
normalized = normalizer.transform(source_images)
# Training transform (fit once on a reference — preferred for supervised training)
transform = StainNormalizerTransform(
method="macenko",
mode="reference",
reference=reference_image,
device="cuda",
# normalize_to_0_1 defaults to True for Macenko (float [0,1] pipelines)
)
batch_out = transform(source_images)
Modes
| Mode | Behavior | When to use |
|---|---|---|
reference |
Fit once on a fixed reference, then transform | Default for training |
batch |
Fit on the current batch every forward | Exploratory / domain-shift checks; usually unsafe for reproducible supervised training |
API
fit(images)/transform(images)/fit_transform(images)StainNormalizerTransform—nn.Modulefor pipelines- Backends:
"torch"(default) or"torch_cuda"when the extension is built
Documentation
See the documentation site for installation details, training usage, and examples.
Citation
If you use StainX, please cite the preprint:
https://www.biorxiv.org/content/10.64898/2026.08.06.743198v1
DOI: 10.64898/2026.08.06.743198
License
GPL-3.0-or-later
Release files for stainx 0.1.6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| stainx-0.1.6.tar.gz | 41.5 kB | Details |
Release files / stainx-0.1.6.tar.gz
| Download URL | stainx-0.1.6.tar.gz |
|---|---|
| Size | 41.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2de8fa05d08da33ddb3ca9df21ed91cb20277a1392c865f1ff609d56f8021812
|
|
BLAKE2b-256 checksum How to use checksums |
94a28d4a8be76427dda745c948b00278f6007aa96734de7800afc526399054bb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 9, 2026.
Transparency log