Skip to content

modify_and_reconstruct

modify_and_reconstruct(tile, modify, stain0, stain1, stain2=None)

Modifies RGB tile in stain space and converts back to RGB.

Parameters:

Name Type Description Default
tile RGBArray

Input RGB representation of the region.

required
modify ModifyFunction

Function that takes three channels in stain space and returns their modified versions.

required
stain0 StainTuple

First default color vector.

required
stain1 StainTuple

Second default color vector.

required
stain2 StainTuple | None

Third default color vector. If not provided, a residual vector is computed from the first two.

None

Returns:

Type Description
RGBArray

Modified region in RGB space.

Note
  • To ensure as precise reconstruction as possible, clipping of negative values is ommited from stain separation.
References

Stain separation is adapted from skimage.color.separate_stains.

Example:

import numpy as np
from skimage.data import immunohistochemistry

from rationai.staining import modify_and_reconstruct
from rationai.staining.constants import QUPATH_DAB, QUPATH_H


def modify(c0, c1, c2):
    # Remove second channel from the image
    c1 = np.zeros_like(c1)

    return c0, c1, c2


original = immunohistochemistry()
modified = modify_and_reconstruct(original, modify, QUPATH_H, QUPATH_DAB)

Source code in rationai/staining/modify_and_reconstruct.py
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
def modify_and_reconstruct(
    tile: RGBArray,
    modify: ModifyFunction,
    stain0: StainTuple,
    stain1: StainTuple,
    stain2: StainTuple | None = None,
) -> RGBArray:
    """Modifies RGB tile in stain space and converts back to RGB.

    Args:
        tile: Input RGB representation of the region.
        modify: Function that takes three channels in stain space
            and returns their modified versions.
        stain0: First default color vector.
        stain1: Second default color vector.
        stain2: Third default color vector. If not provided,
            a residual vector is computed from the first two.

    Returns:
        Modified region in RGB space.

    Note:
        - To ensure as precise reconstruction as possible,
        **clipping of negative values is ommited** from stain separation.

    References:
        Stain separation is adapted from <a href="https://scikit-image.org/docs/stable/api/skimage.color.html#skimage.color.separate_stains">skimage.color.separate_stains</a>.

    Example:
    ```python
    import numpy as np
    from skimage.data import immunohistochemistry

    from rationai.staining import modify_and_reconstruct
    from rationai.staining.constants import QUPATH_DAB, QUPATH_H


    def modify(c0, c1, c2):
        # Remove second channel from the image
        c1 = np.zeros_like(c1)

        return c0, c1, c2


    original = immunohistochemistry()
    modified = modify_and_reconstruct(original, modify, QUPATH_H, QUPATH_DAB)
    ```
    """
    if stain2 is None:
        stain2 = residual(stain0, stain1)

    mat = (stain0, stain1, stain2)

    stain2rgb = np.stack(mat)
    rgb2stain = np.stack(inv_mat(mat))

    values = np.maximum(tile.astype(np.float64) / 255, 1e-6)
    log_adjust = np.log(1e-6)

    stains = (np.log(values) / log_adjust) @ rgb2stain
    c0, c1, c2 = tuple(np.moveaxis(stains, -1, 0))

    modified_stains = np.stack(modify(c0, c1, c2), axis=-1)

    return (255 * combine_stains(modified_stains, stain2rgb)).astype(np.uint8)