A command-line tool to harmonise the colour, tone and saturation of haematoxylin and eosin (H&E)-stained histology images acquired on different microscopes or on different days, making them visually comparable without any loss of spatial resolution.
Colour transfer is performed using the Reinhard et al. (2001) algorithm in the CIE Lab colour space. For each image, the mean and standard deviation of each Lab channel (L, a, b) are matched to a common target computed as the batch average. A tissue mask (based on luminance) excludes background pixels — white areas such as vessels, sinusoids or empty space — from the statistics, so they do not bias the colour reference. No spatial resampling is applied; output images are pixel-for-pixel identical in resolution to their inputs.
Reinhard E. et al. (2001). Color transfer between images. IEEE Computer Graphics and Applications, 21(5), 34–41. https://doi.org/10.1109/38.946629
- Python ≥ 3.10
- scikit-image
- tifffile
It is recommended to install dependencies in an isolated conda environment:
conda create -n he-norm python=3.12 -y
conda activate he-norm
pip install scikit-image tifffilepython3 normalize_he.py INPUT_FOLDER [OUTPUT_FOLDER]INPUT_FOLDER— folder containing the.tif/.tiffimages to normalise. All files with those extensions found directly inside the folder are processed as a batch.OUTPUT_FOLDER— optional. If omitted, anormalized/subfolder is created insideINPUT_FOLDER.
conda activate he-norm
python3 normalize_he.py ~/histology/june_batch ~/histology/june_batch_normalisedOutput files are saved as uncompressed RGB TIFF and named <original_stem>_normalized.tif.
- The colour target is computed as the mean across the current batch, so results are internally consistent within a run. If you need to match a specific reference image (e.g. a gold-standard slide), the target statistics can be hard-coded in the script by replacing
target_meanandtarget_std. - The script handles greyscale images (converted to RGB) and RGBA images (alpha channel discarded).
- A
UserWarningabout a small number of clipped negative Z values during Lab→sRGB conversion is expected and harmless; those pixels are clipped to the valid sRGB range.
Copyright (C) 2026 Alfonso Mora Corral. GNU General Public License v3.0 — see LICENSE for details.