Staining calculation

Hi everyone

I’m reaching to you with a rather “strange” question, concerning the calculation of the staining-intensity values for brightfield images.

I’m trying to calculate additional staining values based on RGB values and staining vectors. Thus I was testing my script on the H / DAB / Residual staining vectors (set as default), resolving the 3x3 matrix.

Unfortunately I did only get somehow similar but not the same results for the staining intensities. So my question would be how the staining calculation based on RGB values and staining vectors works in qupath and whether it is more complicated than just resolving the 3x3 equation system?
Even a link to the actual source code making the calculations of the staining values of objects based on their RGB values would already be helpful.

Thank you very much.

Did you also subtract for your background value?
Or perhaps, if you set the background to 255, 255,255, do the values work as you would expect.

I have actually set the background to 255, 255, 255 already…

1 Like

Ah, well, best I can do is point you here, which indicates that a lookup table was used, which might result in slight differences in the measurements?
@petebankhead will likely have a better answer.

1 Like

QuPath is using the color deconvolution method of Ruifrok and Johnston – this is really widely used, and there are lots of descriptions and implementations available, although they may differ in some details.

The code in QuPath is a little bit scattered because color deconvolution is used in different ways in different places (i.e. for transform pixels for analysis, or also to transform them purely for display in the viewer) and needs to be quite optimized for performance. Typically, the input is a packed (A)RGB int value for a pixel, which needs to be unpacked and converted to an optical density (using a lookup table for performance) before using the stain matrix.

To decipher the code, I’d suggest starting here:

1 Like

thanks for the literature @petebankhead !

The key to get the correct calculations actually was to not directly use the RGB values but to logarithmize first.