scikit-image / scikit-image

Image processing in Python
https://scikit-image.org
Other
6.07k stars 2.22k forks source link

separate_stains output #3858

Closed Mnkach closed 4 years ago

Mnkach commented 5 years ago

Description

The transformed images of ImageJ color deconvolution plugin and skimage.color.separate_stains() are not the same, while transformation matrices are the same. In my case, after separate_stains(img, bex_from_rgb) eosin channel looks like inverted to ImageJ and all the output values are negative. Screenshot from 2019-04-24 11-02-34

The following lines

print(img_bex.min())
print(img_bex.max())

outputs

-0.550177897460211
-0.2117949505092822

So how to correctly convert values after transformation to uint8?

Way to reproduce

import numpy as np
from matplotlib import pyplot as plt
from skimage.color import separate_stains, bex_from_rgb
from matplotlib.colors import LinearSegmentedColormap
from skimage import img_as_float, img_as_ubyte
from skimage import data

import cv2

img = cv2.imread('./40x_col/Snap-450.png')
img = cv2.resize(img, (0, 0), fx=0.4, fy=0.4)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# Create an artificial color close to the original one
cmap_hema = LinearSegmentedColormap.from_list('mycmap', ['white', 'navy'])
# cmap_dab = LinearSegmentedColormap.from_list('mycmap', ['white',
#                                              'saddlebrown'])
cmap_eosin = LinearSegmentedColormap.from_list('mycmap', ['darkviolet',
                                               'white'])

img_bex = separate_stains(img, bex_from_rgb)

print(img_bex.min())
print(img_bex.max())

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

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

ax[1].imshow(img_bex[:, :, 0], cmap=cmap_hema)
ax[1].set_title("Hematoxylin")

ax[2].imshow(img_bex[:, :, 1], cmap=cmap_eosin)
ax[2].set_title("Eosin")

ax[3].imshow(img_bex[:, :, 2], cmap='gray')
ax[3].set_title("...")

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

fig.tight_layout()

plt.show()

Version information

3.6.8 |Anaconda, Inc.| (default, Dec 30 2018, 01:22:34) 
[GCC 7.3.0]
Linux-4.15.0-47-generic-x86_64-with-debian-buster-sid
scikit-image version: 0.15.0
numpy version: 1.14.2

UPD Snap-450.png Snap-450

stefanv commented 5 years ago

Thank you for the detailed bug report, @Mnkach! Are you able to share Snap-450.png as well?

Mnkach commented 5 years ago

I attached it to the header.

stefanv commented 5 years ago

/cc @spotter

stefanv commented 5 years ago

In line 595 of Colour_Deconvolution.java, there seems to be an offset calculation that is not present in our implementation. Could that be the cause?

double output = Math.exp(-((Rscaled + Gscaled + Bscaled) - 255.0) * log255 / 255.0);
                    if(output>255) output=255;
                    newpixels[i][j]=(byte)(0xff&(int)(Math.floor(output+.5)));
                }
            }
             // add new values to output images
            outputstack[0].addSlice(label,newpixels[0]);
            outputstack[1].addSlice(label,newpixels[1]);
            outputstack[2].addSlice(label,newpixels[2]);

I also don't think the visualization method used here is the same as in the code, so the colors will be different.

asmagen commented 4 years ago

Is this function operating correctly? I also get only negative values.

alexdesiqueira commented 4 years ago

Hey @asmagen, thank you for letting us know. Could you give us an example? Some code running would be great to investigate. Thanks again!

asmagen commented 4 years ago

See the following issue where I have placed an example here

alexdesiqueira commented 4 years ago

Thank you @Mnkach!