scikit-image / scikit-image

Image processing in Python

Home Page:https://scikit-image.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Adding color deconvolution for tissue slides stained with H&E (haematoxylin and eosin)

GParolini opened this issue · comments

Description:

The issue I am opening relates to the discussion in "Enhance gallery example on colour separation of stained tissues" #6333
I am working on tissue slides stained with H&E and I would welcome the opportunity to use the colour deconvolution module in scikit-image to separate the stains.
I looked into the code already available in scikit-image to separate H, E, and DAB and the example in the scikit-image gallery and tried to reproduce the case for just two stains. I used both the colour vectors for H&E given in Landini et al. and the colour vectors I could read in QuPath (H, E, Residual) to have a comparison. I do not have any biological training and I am unable to say which choice of H&E colour vector would lead in principle to better results in object detection, which is my ultimate goal. I would appreciate feedback and suggestions.
output2
output3
output4

One comment perhaps worth making is that currently the colour deconvolution module does not allow users to set their own colour vectors (at least this is my impression). Given the discussions by Landini, it would be useful for advanced users to have this option, at least for the H&E stains, I think.

# IMPLEMENTATION WITH H&E ONLY COLOUR VECTOR AVAILABLE IN FIJI COLOUR DECONVOLUTION JAR
from skimage._shared.utils import identity
from skimage.color.colorconv import separate_stains
from skimage.color.colorconv import combine_stains


rgb_from_he = np.array([[0.644211000, 0.716556000, 0.266844000],
                         [0.09278900, 0.95411100, 0.28311100],
                         [0.00000000, 0.00000000, 0.00000000]])
rgb_from_he = np.round(rgb_from_he, 3)

rgb_from_he[2, :] = np.cross(rgb_from_he[0, :], rgb_from_he[1, :])

he_from_rgb = linalg.inv(rgb_from_he)

rgb=identity(he_image)

def rgb2he(rgb, *, channel_axis=-1):
    return separate_stains(rgb, he_from_rgb)

def he2rgb(he, *, channel_axis=-1):
    return combine_stains(he, rgb_from_he)

# Example IHC image
ihc_rgb = he_image

# Separate the stains from the IHC image

ihc_he = rgb2he(ihc_rgb)


# Create an RGB image for each of the stains
null = np.zeros_like(ihc_he[:, :, 0])
ihc_h = he2rgb(np.stack((ihc_he[:, :, 0], null, null), axis=-1))
ihc_e = he2rgb(np.stack((null, ihc_he[:, :, 1], null), axis=-1))

# Display
fig, axes = plt.subplots(2, 2, figsize=(7, 6), sharex=True, sharey=True)
ax = axes.ravel()

ax[0].imshow(ihc_rgb)
ax[0].set_title("Original image")

ax[1].imshow(ihc_h)
ax[1].set_title("Hematoxylin (Fiji col. vect.)")

ax[2].imshow(ihc_e)
ax[2].set_title("Eosin (Fiji col. vect.)")  


for a in ax.ravel():
    a.axis('off')

fig.tight_layout()

Thanks for raising this issue, @GParolini! Unfortunately, I don't have a substantial background in biology either. Would you mind clarifying what you mean by "set their own colour vectors?" If we consider the separate_stains function, the second parameter is described as "The stain separation matrix as described by G. Landini [1]." Wouldn't this be somewhat related?