Skip to content
6 changes: 4 additions & 2 deletions tests/test_stainnorm.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,9 @@ def test_macenko_normalize(source_image: Path, norm_macenko: Path) -> None:
assert np.mean(np.absolute(macenko_img / 255.0 - transform / 255.0)) < 1e-2


def test_vahadane_normalize(source_image: Path, norm_vahadane: Path) -> None:
def test_vahadane_normalize(
source_image: Path, norm_vahadane: Path, caplog: pytest.LogCaptureFixture
) -> None:
"""Test for stain normalization with stain matrix from Vahadane et al."""
source_img = imread(Path(source_image))
target_img = stain_norm_target()
Expand All @@ -158,7 +160,7 @@ def test_vahadane_normalize(source_image: Path, norm_vahadane: Path) -> None:
norm = get_normalizer("vahadane")
norm.fit(target_img) # get stain information of target image
transform = norm.transform(source_img) # transform source image

assert "Vahadane stain extraction/normalization algorithms" in caplog.text
assert np.shape(transform) == np.shape(source_img)
assert np.mean(np.absolute(vahadane_img / 255.0 - transform / 255.0)) < 1e-1

Expand Down
18 changes: 17 additions & 1 deletion tiatoolbox/tools/stainextract.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import numpy as np
from sklearn.decomposition import DictionaryLearning

from tiatoolbox import logger
from tiatoolbox.utils.misc import get_luminosity_tissue_mask
from tiatoolbox.utils.transforms import rgb2od

Expand Down Expand Up @@ -238,6 +239,13 @@ class VahadaneExtractor:
This class contains code inspired by StainTools
[https://github.com/Peter554/StainTools] written by Peter Byfield.

.. warning::
Vahadane stain extraction/normalization algorithms are unstable
after the update to `dictionary learning` algorithm in
scikit-learn > v0.23.0 (see issue #382). Please be advised and
consider using other stain extraction (normalization) algorithms
or toolboxes, such as https://github.com/CielAl/torch-staintools

Args:
luminosity_threshold (float):
Threshold used for tissue area selection.
Expand All @@ -259,6 +267,14 @@ def __init__(
regularizer: float = 0.1,
) -> None:
"""Initialize :class:`VahadaneExtractor`."""
# Issue a warning about the algorithm's stability
logger.warning(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mostafajahanifar Please can you add links to alternatives as discussed during the meeting?

"Vahadane stain extraction/normalization algorithms are unstable "
"after the update to `dictionary learning` algorithm in "
"scikit-learn > v0.23.0 (see issue #382). Please be advised and "
"consider using other stain extraction (normalization) algorithms.",
stacklevel=2,
)
self.__luminosity_threshold = luminosity_threshold
self.__regularizer = regularizer

Expand All @@ -267,7 +283,7 @@ def get_stain_matrix(self: VahadaneExtractor, img: np.ndarray) -> np.ndarray:

Args:
img (:class:`numpy.ndarray`):
Input image used for stain matrix estimation
Input image used for stain matrix estimation.

Returns:
:class:`numpy.ndarray`:
Expand Down