Colour Deconvolution

The colour deconvolution plugin (java and class files) implements stain separation using Ruifrok and Johnston's method described in [1]. The code is based on a NIH Image macro kindly provided by A.C. Ruifrok.
The plugin assumes images generated by color subtraction (i.e. light-absorbing dyes such as those used in bright field histology or ink on printed paper). However, the dyes should not be neutral grey (most histological stains are not so).
If you intend to work with this plugin, it is important to read the original paper to understand how to determine new vectors and how the whole procedure works.
The plugin works correctly when the background is neutral (white to grey), so background subtraction with colour correction must be applied to the images before processing.
The plugin provides a number of "built in" stain vectors some of which were determined experimentally in our lab (marked in the source with GL), but you may have to determine your own vectors to provide a more accurate stain separation, depending on the stains and methods you use. See note below.
The built-in vectors are :

Note: A very frequently asked question posted to the ImageJ list relates to quantification of immunostain intensity (for example DAB intensity) to evaluate antigen expression. However, please consider 2 main issues that prevent doing this in a quantitative manner:
  1. Antigen-antibody reactions are not stoichiometric, so "darkness of stain" does not mean "amount of reaction products". In fact most histological stains are not stoichiometric (an exception is Feulgen stain which is commonly used for DNA cytometry).

  2. In particular DAB does not follow Beer-Lambert law. See for example CM van der Loos paper:
    "The brown DAB reaction product is not a true absorber of light, 
    but a scatterer of light, and has a very broad, featureless spectrum.
    This means that DAB does not follow the Beer-Lambert law, which describes
    the linear relationship between the concentration of a compound and 
    its absorbance, or optical density. As a consequence,darkly stained 
    DAB has a different spectral shape than lightly stained DAB."
  3. Further details are mentioned in this informative message posted by Al Floyd to the ImageJ mailing list.
In consequence, while colour deconvolution might be useful in segmentation of immunostained structures or image enahancement for colour blind observers, attempting to quantify DAB intensity using the above plugin is not a good idea.

Ideally, new vector determination should be done on slides stained with only one colour at a time (using the "From ROI" interactive option).
The plugin takes an RGB image and returns three 8-bit images. If the specimen is stained with a 2 colour scheme (such as H&E) the 3rd image represents the complementary of the first two colours (i.e. green). Ideally the 3rd image should be completely white. If not, then either the colour vectors or the background colour correction have not been correctly determined.
Read the paper!



New in version 1.2: Dennis Chao has kindly provided the following modifications to the code, 1) the plugin works with stacks, 2) the user-defined vectors can now also be recorded by the macro recorder, 3) the result images keep the original image name plus " (Colour[n])" in the name (note the leading space). Example: "test.tif" will produce images named "test.tif (Colour[1])", "test.tif (Colour[2])" and "test.tif (Colour[3])".

New in version 1.3: disable popup menu when using ROIs.

Examples

Haematoxylin and Eosin separation (using the built-in vectors).
H and E stained Haematoxylin Eosin 3rd pigment
From left to right: original, Haematoxylin, Eosin, virtually empty 3rd (complementary) component (showing that the vectors match the image quite well).


Haematoxylin and DAB separation (using the built-in vectors).
Haematoxylin and DAB stained Haematoxylin DAB 3rd pigment
From left to right: original, Haematoxylin, DAB, 3rd component (the vectors did not perfectly matched the stains in this image, so they should be determined again from single-stained samples).


Ink/pigment separation (using ROI defined vectors).
This example shows stain separation in an old manuscript using regions of interest defined by the user (where stains were applied uniquely). The top part of the image was pasted from the same manuscript page to allow sampling the ink alone within the same image. (Image of MS408, folio 2 recto courtesy of the Beinecke Rare Book and Manuscript Library, Yale University).
Original image green
ink 3rd component
Top row: original, green pigment.
Bottom row: brown ink, 3rd component.

Vector values for this example:
 Colour[1] (green pigment):
   R1: 0.592132
   G1: 0.4580393
   B1: 0.6630081
 
 Colour[2] (brown ink):
   R2: 0.39982012
   G2: 0.55231196
   B2: 0.7315021
 
 Colour[3] (3rd component):
   R3: 0.69965965
   G3: 0.6965282
   B3: 0.15913807



Ink/pigment separation (using ROI defined vectors and image ratios).
Sometimes, the pigments are not easily separated. In such case the pigment that is best separated can be filtered out using image ratio (a division of the original rgb planes by the pigment rgb planes followed by a multiplication of each plane by 255) The example below uses ratio of the original image to the blue pigment image. (Image of MS408, folio 9 verso courtesy of the Beinecke Rare Book and Manuscript Library, Yale University).
original image blue pigment
Left: original, right: ratio of the original and the blue pigment image.
Here is an ImageJ macro to perform this task (requires Colour_decovolution plugin and assumes that the 1st. colour in the deconvolved images is the one to filter out ).



Determining new vectors

  • Grab images with single stains (e.g. if one wants to determine the vectors of H and DAB, grab one image with only DAB and one stained only with Haematoxylin) and correct the background so it appears white or bright neutral grey. See this document for step by step instructions on background correction. If no background correction is applied, the colours in the image will depend on the colour/temperature of the light source.

  • Stitch or paste these 2 or 3 images together into a test image (so singly-stained areas exist in the same image)

  • Run the Colour Deconvolution plugin and select the From ROI option to let you define the stained areas and check the Show matrices box to display the vectors in the log window so they can be copied and pasted to the plugin source code later. Press OK.

  • Now the plugin will ask you to make selections. Select small ROIs areas which are all intensely stained with only one of the dyes. Select fully stained areas (i.e. without empty background). Repeat this for each dye.

  • If you are using 2 colours instead of 3, for the 3rd selection just right-click and the vector will be defined automatically as the complementary of the other 2 colours.
    After this, the deconvolution of the test image will take place so you can evaluate the stain separation and a log window will show you something like this (the values will be different, of course):
    ------------------------------------------------------------
     From ROI Vector Matrix ---
    Colour[1]:
       R1: 59.86929
       G1: 65.04342
       B1: 27.730581
    
    Colour[2]:
       R2: 23.209948
       G2: 47.378456
       B2: 51.81141
    
    Colour[3]:
       R3: 0.0
       G3: 0.0
       B3: 0.0
    
     From ROI Translation Matrix ---
    Colour[1]:
       R1: 0.6461899
       G1: 0.7020361
       B1: 0.29930574
    
    Colour[2]:
       R2: 0.3138818
       G2: 0.64072686
       B2: 0.70067626
    
    Colour[3]:
       R3: 0.6956413
       G3: 0.31082857
       B3: 0.6476641
    
    --------------------------------------------------------------------
    
    These are the vectors for the dyes selected but bear in mind that one may have to repeat the procedure a few times to make sure the separation is optimal.

  • Now look for the 3 sets of vectors under the title:
    "From ROI Translation Matrix ---"
    
    and copy the values to the plugin java source code, where it says (for example if this is H DAB):
    if (myStain.equals("H DAB")){
        // 3,3-diamino-benzidine tetrahydrochloride
        // Haem matrix
        MODx[0]= 0.650;
        MODy[0]= 0.704;
        MODz[0]= 0.286;
        // DAB matrix
        MODx[1]= 0.268;
        MODy[1]= 0.570;
        MODz[1]= 0.776;
        // Zero matrix
        MODx[2]= 0.0;
        MODy[2]= 0.0;
        MODz[2]= 0.0;
    }

    That means that the 3 values in the log window:
     R1: 0.6461899
     G1: 0.7020361
     B1: 0.29930574
    need to replace the values already in the plugin, so:
     MODx[0]= 0.650;
     MODy[0]= 0.704;
     MODz[0]= 0.286;
    
    becomes:
     MODx[0]= 0.6461899;
     MODy[0]= 0.7020361;
     MODz[0]= 0.29930574;
    
    and so on for the other two colours.
    If the 3rd colour was not defined (i.e. staining method consists of only 2 dyes), just insert the values as 0.0 and they will be recalculated by the plugin at run time.

  • Recompile the plugin from the menu entry Plugins>Compile and Run...

  • Restart IJ so the new class becomes active.



  • References

    [1] Ruifrok AC, Johnston DA. Quantification of histochemical staining by color deconvolution. Anal Quant Cytol Histol 23: 291-299, 2001.
    [2] A free plugin for Photoshop-compatible hosts to do colour separation is available from www.4n6site.com
    [3] Tom Macura has ported the code of this plugin to MATLAB MEX c code, and it is available at the Open Microscopy Environment Repository.
    Copyright G. Landini, 2004-2009 (except where indicated).
    Last updated on 19/July/2009.

    Back