Tissue detection (simple thresholder)
Pixel classification (tissue regions)
Why stain? And why DAB is not quantitative
Brightfield images, or at least the ones I will be discussing here, are originally fairly colorless pieces of tissue that have been stained with one or more dyes (I am not covering DIC/phase contrast or other unstained live cell analyses). The stains themselves vary greatly in terms of their functionality. Most brightfield images are three images in one, Red, Green and Blue all dropped on top of each other and presented to you on your screen via tiny Red Green and Blue lights. But these colors are usually not what we are interested in, unlike in fluorescence. There are no pure color channels in brightfield, unless you manage to have a perfectly blue, red, or green dye. As far as I know of, that does not exist, and the color of the lighting can impact the color of the stains we see on the screen, as can the color shading of the monitor.
Trying to analyze an image, though, we are interested in stains, not the original RGB values. Color deconvoution gives us a way to ESTIMATE the amount of stain in a given pixel. It will never be perfect. The tissue itself will have some small absorbance, as will the mounting media. The color of the incoming light is unlikely to be perfectly uniform, even from an LED. Bulbs will age, darken, and their color warmth will shift. We do the best we can, but generally brightfield analyses are much less quantitative than other types of imaging. That does not mean Fluorescence is perfectly quantitative - it is not for a variety of reasons - but brightfield is usually less so. As such, the standard method of analyzing brightfield images is to attempt to isolate regions where your stain is present in sufficient quantities to meet some threshold, and then calculate the area of that stain. You may be counting nuclei or cells via a stain like hematoxylin, or DAB nearby the nucleus via an expansion away from that nucleus, but the presence or absence of a stain, and in how many places is what most analyses will come down to.
DAB - ignore this section if you are lucky enough to not work with DAB
One of the most difficult stains, and yet most common, is DAB (DAB Wiki entry) ( DAB IHC description from abcam), which, in addition to being brown and thus crossing all three of the Red, Green and Blue channels for an RGB image, is a precipitate, which means it will not follow Lambert-Beer law and stoichiometrically absorb light that passes through it. DAB is commonly used both for historical reason (compare your staining vs other staining done with DAB), accessibility, and because it is usually dark and easy to see. None of these reasons are particularly helpful from a quantitative analysis standpoint. The take home message here is "be careful with what you think your analysis means." Twice the DAB "intensity" does not mean twice the protein.
Additionally, because DAB shows up in the red green and blue channels, it is much harder to untangle from stains like hematoxylin, which are primarily blue. If you have access to red and green stains, those work much better with the hematoxylin as a counterstain since they will primarily - though not perfectly - affect information in different channels.
DAB: TLDR
Quote from the van der Loos paper below, from a summary of such information on the Image.sc forum.
“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.”
Color deconvolution resources
Back to stains in general
It is always best to generate your stain vectors from SINGLE stain samples. In this case I would need an Eosin only, and a Hematoxylin only stained sample - which I do not have. So I will have to make an estimate. For stains like H&E, it is very important to keep the staining conditions constant. That means equal timing on the dips and washes per slide, and changing out the hematoxylin (and everything else) frequently enough. Even in a perfect world, with thin tissue slices, perfect staining procedures, and well separated stains (red, green, and hematoxylin), information is lost as the stains get darker. A black pixel allows no light, and therefor you have no idea what dyes were present. It could be 100% DAB, 100% hematoxylin, or something else. Titrating your antibodies/dyes so that the stains are not extremely dark can be very helpful if you need to deal with overlapping stains.
Another option is exporting a subsection of the image into Fiji to use ColorDeconvolution2 or other plugins to more carefully refine the vector values.
Estimating stain vectors in QuPath
For the moment, we will use the Analyze->Preprocessing->Estimate stain vectors method, as it gives the most control over the stain vectors. Creating small ROIs for specific stains can be very problematic as you are sampling a small number of pixels, and any blemish or small stain variation can have a major impact on your results. In addition, if you notice that your microscope or slide scanner has tiling artifacts (each image tile position is very apparent due to shading), you may want to take an elongated sample box to try and cover as much of the variation as possible. The best option is always to improve the image at the scanner, though, and fix whatever is wrong with the scanner so that you are working with nice, even images!
The first question QuPath asks is whether to set the background values, with a dialog that looks like the following.
As long as enough blank space was included in the selected area, QuPath should do a fairly good job of estimating the background color intensity. As stated in the question, it takes the mode, or most common pixel value. Another way to think about this, is QuPath is determining the amount of light that is blocked by the slide and mounting media itself. Here I usually select “Yes”, provided I am convinced the background values are correct (mouse over empty areas of the image and look at the R G and B values in the lower right corner of the Viewer).
Note
Next, you are presented with the Visual Stain Editor, which is a set of 2D representations of the 3D color space volume. I have placed an image of it side by side with the Color Inspector 3D plugin from Fiji, showing the 3D color space. QuPath’s three charts are each a view from one side of the cube.
The “after adjustments” image below shows what I obtained after first clicking Auto, which usually does a fairly good job, and then adjusting things slightly more to catch more of the “outside” pixels. In well mixed stains like Hematoxylin and Eosin (dyes where most pixels will have at least a little bit of both stains), I have often found that moving my color vectors a bit farther away from each other improves my separation. How would you check? Well, qualitatively, you can use the 2 and 3 keys to look at the Hematoxylin and Eosin channels (or the Brightness & Contrast dialog).
Once I am happy with the results, I can create a short script using the Workflow tab, isolate the line that has the new color deconvolution stain, and verify in several other images that the color deconvolution settings work there as well. Do not simply assume that your first try will work well across the bulk of your project. Also, some areas with other kinds of staining will definitely show up strongly in the residual channel, do not be surprised by this. In the case of the test project, there are areas of teal staining and brown staining that will show up very strongly in the residual channel as they are neither hematoxylin or eosin.
Final Step: save to script
At this point, we have the first lines of our script - the Workflow tab can be used to extract the color deconvolution vectors for later use.
Up in the menus, Automate->Project scripts->New script…
Name the script
Go to the Workflow tab, and at the bottom, Create script
From the created script (should be called Untitled*), copy the setImageType and the last (not the original!) setColorDeconvolutionVectors lines, and paste them into your new script.
Use either File->Save or CTRL+S to save the script, you should see the * at the end of the file name on the left disappear once the file is saved.