I am trying to analyze images of cells that are dyed a certain colour. My objectives are to:
- identify individual cells
- measure signal intensity (pixels) within the regions that are identified as the cell (cells have different level of dye staining).
There is a Mathematica blog post that got me started- "how to count cells, annihilate sailboats and warp the mona lisa"
However, this example measures the average pixel size of the cells from the binarized/processed image, not the intensity of the pixels of each cell in the original, non binarized image.
So, what I am trying to do and asking help for is how to process the original image to identify cells and then use that information to map cells back on the original image, and count signal intensity in the defined areas on that original image (that has the pixel intensity information).
One issue is that there is no counter stain, so weakly stained or negative cells are difficult to detect and measure. For that, I have modified the blog code a little, which works well. Here's what I have so far-
i =img;
ibin = Binarize[i]
idil = Dilation[ibin, 5]
idsc = DeleteSmallComponents[idil, 250]
This gets me a binarized image with all cells (including negative and weak signal) as somewhat circular.
Next, I use this code to detect edges and distinguish each cell:
distT = DistanceTransform[idsc, Padding -> 0];
marker = MaxDetect[ImageAdjust[distT], 0.05];
w = WatershedComponents[GradientFilter[idsc, 3], marker,
Method -> "Rainfall"]
Colorize[w]
This gets me a multicolor, binarized map that approximates each cell.
The next step is where I need help. The code from the blog is:
cells = SelectComponents[w, "Count", 100 < # < 450 &];
measures =
ComponentMeasurements[
cells, {"Centroid", "EquivalentDiskRadius", "Label"}];
Show[i,
Graphics[{Blue, Circle @@ # & /@ (measures[[All, 2, 1 ;; 2]]),
MapThread[Text, {measures[[All, 2, 3]],
measures[[All, 2, 1]]}]}]]
Histogram[ComponentMeasurements[cells, "Count"][[All, 2]],
250, AxesLabel -> {"pixels"},
PlotLabel -> "Histogram of cell's pixel counts"]
This displays blue circles around the cells in the original image and displays a histogram of pixel size. So I know that it is identifying cells correctly.
However, I want it use the coordinates of the identified cells from the processed image, but analyze the pixel intensity on the original image with those coordinates, and then display that information as a histogram.
Thanks in advance.
-----------------update Oct 16---------
@ nikie
Thank you very much for your answer. I'm still a little bit stuck on the end. Here is a small test image and the code that I have so far.
i = img;
ibin = Binarize[i];
icn = ColorNegate[ibin];
imax = MaxFilter[icn, 2];
idsc2 = DeleteSmallComponents[imax, 100];
distT = DistanceTransform[idsc2, Padding -> 0];
marker = MaxDetect[ImageAdjust[distT], 0.06];
w = WatershedComponents[GradientFilter[idsc2, 4], marker,
Method -> "Rainfall"]
Colorize[w]
this does a decent job on selecting cells (1 error visible).
cells = SelectComponents[w, "Count", 100 < # < 500 &];
components = ComponentMeasurements[{cells, i}, {"Mean"}]
I am having trouble with
1. mapping the selected cells back on the original image and displaying that image (with circles) to check and verify the selection is what I want it to be.
2. I'm confused as to why the mean values all seem very similar, when the original image suggests that they should vary a bit more
3. understanding the "[[All, 2, 1 ;; 2]])" code, for example in the blog post
thanks so much
-------------- Oct 17 update-----------
@nikie,
thanks for all the explanations, you are very helpful!
I've ran into one issue however. It appears that the intensity values measured do not reflect how the image looks by eye, possibly due to the differences in area? If you take my watershed image (it's now "iw") and do the last steps like this -
cells = SelectComponents[iw, "Count", 200 < # < 700 &];
components = ComponentMeasurements[{cells, i},
{"Centroid", "EquivalentDiskRadius", "Label", "MeanIntensity", "Area"}]
Show[i, Graphics[{Blue,Circle @@ # & /@ (components[[All, 2, 1 ;; 2]]),
MapThread[Text, {components[[All, 2, 3 ;; 5]], components[[All, 2, 1]]}]}]]
You can see that the visible intensity by eye doesn't match up with what it's measuring. Presumably because of the differences in white space around the defined circle? For example, the darkest cells (#6 when I run it) measures a meanintesity of 0.63, while the neighboring cell right above it measures at 0.78. These two cells have a significant difference in area, but if you look at some of the other cells that are more similar in area, they also have measurements that are opposite of what you'd expect when looking at it by eye. Am I missing/overlooking something?
Thanks for the help on manipulating lists. I understand that in the code above now. But when I try to make the histogram I get errors and cannot figure out what I am doing wrong-
Histogram[ComponentMeasurements[cells, "Count"][[All, 2; 4]], 500,
AxesLabel -> {"Mean Intensity"},
PlotLabel -> "Histogram of cell signal"]
thank you for all your help, I am learning a lot!
ComponentMeasurements
overload that takes a label matrix:ComponentMeasurements[{MorphologicalComponents[cells], img}, {"Mean" ...
$\endgroup$[[All, 2, 4]]
in the last block? Semicolon doesn't make sense here $\endgroup$