AlbumentationsExplore
DocumentationExploreAdoptionCommercial LicenseBlog
GitHub

HEStain

Targets:
image
volume
Image Types:uint8, float32

Perturb stain concentrations in histology images to simulate color variation across laboratories, scanners, protocols, and staining panels.

Use this transform to train pathology models against expected staining variation. It converts RGB values to optical density, separates the stain concentrations with the selected basis, perturbs the configured components, and reconstructs the RGB image.

Arguments
method
preset | random_preset | vahadane | macenko | custom
random_preset

Selects the stain basis:

  • "preset": Use the matrix named by preset.
  • "random_preset": Select one of the eight preset matrices for each call.
  • "vahadane": Extract the matrix from the input with the Vahadane method.
  • "macenko": Extract the matrix from the input with the Macenko method.
  • "custom": Use the fixed matrix supplied through stain_matrix. Default: "random_preset".
preset
ruifrok | macenko | standard | high_contrast | h_heavy | e_heavy | dark | light |

Preset stain matrix used when method="preset":

  • "ruifrok": Standard reference from Ruifrok and Johnston.
  • "macenko": Reference from the Macenko method.
  • "standard": Typical bright-field microscopy.
  • "high_contrast": Enhanced contrast.
  • "h_heavy": Hematoxylin-dominant staining.
  • "e_heavy": Eosin-dominant staining.
  • "dark": Darker staining.
  • "light": Lighter staining. When None with method="preset", "standard" is used. Default: None.
intensity_scale_range
tuple[float, float]
[0.7, 1.3]

Non-negative range for the multiplicative concentration factor sampled independently for hematoxylin, eosin, and any augmented third component. For example, (0.7, 1.3) varies each concentration from 70% to 130%. Default: (0.7, 1.3).

intensity_shift_range
tuple[float, float]
[-0.2, 0.2]

Range within [-1.0, 1.0] for the additive concentration shift sampled independently for hematoxylin, eosin, and any augmented third component. Default: (-0.2, 0.2).

augment_background
bool
false

Whether to perturb background pixels along with tissue pixels. Default: False.

residual_mode
project | preserve | augment
project

Controls the third optical-density component:

  • "project": Reconstruct from H&E only, retaining the two-stain model from earlier releases.
  • "preserve": Keep the derived residual or explicit third-stain concentration unchanged.
  • "augment": Independently perturb the derived residual or explicit third stain along with H&E. Default: "project".
p
float
0.5

Probability of applying the transform. Default: 0.5.

stain_matrix
ndarray | None

Fixed stain basis used when method="custom". A (2, 3) matrix contains hematoxylin and eosin RGB optical-density vectors; "preserve" and "augment" derive the third vector as normalize(cross(H, E)). A (3, 3) matrix supplies the third stain directly and requires residual_mode="preserve" or "augment". Every row must contain finite values and be non-zero, and the matrix must have full row rank. The transform copies the matrix as float32 without row normalization. Default: None.

Examples
>>> import numpy as np
>>> import albumentations as A
>>>
>>> # Create a sample H&E stained histopathology image
>>> # For real use cases, load an actual H&E stained image
>>> image = np.zeros((300, 300, 3), dtype=np.uint8)
>>> # Simulate tissue regions with different staining patterns
>>> image[50:150, 50:150] = np.array([120, 140, 180], dtype=np.uint8)  # Hematoxylin-rich region
>>> image[150:250, 150:250] = np.array([140, 160, 120], dtype=np.uint8)  # Eosin-rich region
>>>
>>> # Example 1: Map HEDJitter(theta) to a full H&E+DAB basis
>>> theta = 0.05
>>> hed_basis = np.array(
...     [
...         [0.65, 0.70, 0.29],  # Hematoxylin
...         [0.07, 0.99, 0.11],  # Eosin
...         [0.27, 0.57, 0.78],  # DAB
...     ],
...     dtype=np.float32,
... )
>>> transform = A.HEStain(
...     method="custom",
...     stain_matrix=hed_basis,
...     residual_mode="augment",
...     intensity_scale_range=(1 - theta, 1 + theta),
...     intensity_shift_range=(-theta, theta),
...     augment_background=True,
...     p=1.0,
... )
>>> transformed_image = transform(image=image)["image"]
>>>
>>> # Example 2: Using a specific preset stain matrix
>>> transform = A.HEStain(
...     method="preset",
...     preset="standard",
...     intensity_scale_range=(0.8, 1.2),
...     intensity_shift_range=(-0.1, 0.1),
...     augment_background=False,
...     p=1.0,
... )
>>> transformed_image = transform(image=image)["image"]
>>>
>>> # Example 3: Using random preset selection
>>> transform = A.HEStain(
...     method="random_preset",
...     intensity_scale_range=(0.7, 1.3),
...     intensity_shift_range=(-0.15, 0.15),
...     p=1.0,
... )
>>> transformed_image = transform(image=image)["image"]
>>>
>>> # Example 4: Using Vahadane extraction (requires an H&E stained input)
>>> transform = A.HEStain(
...     method="vahadane",
...     intensity_scale_range=(0.7, 1.3),
...     p=1.0,
... )
>>> transformed_image = transform(image=image)["image"]
>>>
>>> # Example 5: Using Macenko extraction (requires an H&E stained input)
>>> transform = A.HEStain(
...     method="macenko",
...     intensity_scale_range=(0.7, 1.3),
...     intensity_shift_range=(-0.2, 0.2),
...     p=1.0,
... )
>>> transformed_image = transform(image=image)["image"]
>>>
>>> # Example 6: Combining stain and brightness variation in one pipeline
>>> transform = A.Compose([
...     A.HEStain(method="preset", preset="high_contrast", p=1.0),
...     A.RandomBrightnessContrast(p=0.5),
... ])
>>> transformed_image = transform(image=image)["image"]
Notes
  • Let M be the stain matrix and C the per-pixel concentrations. "project" solves OD ~= C @ M, perturbs H&E, and reconstructs RGB = exp(-(C * scale + shift) @ M).
  • For a (2, 3) matrix, "preserve" and "augment" derive R = normalize(cross(H, E)) and solve the full H&E+R basis. A (3, 3) matrix uses its third row directly.
  • A custom matrix is fixed for the lifetime of the transform. Per-image callable extraction is not supported.
References
  • [{'description': 'A. C. Ruifrok and D. A. Johnston, "Quantification of histochemical"', 'source': 'Analytical and quantitative cytology and histology, 2001.'}, {'description': 'M. Macenko et al., "A method for normalizing histology slides for', 'source': '2009 IEEE International Symposium on quantitative analysis," 2009 IEEE International Symposium on Biomedical Imaging, 2009.'}, {'description': 'D. Tellez et al., "H&E stain augmentation improves generalization of convolutional networks for histopathological mitosis detection"', 'source': 'Medical Imaging, 2018.'}]