Skip to content
Advertisement

How to calculate nucleus amount of cell?

I am using Python 3.5 and OpenCV 3 to analyze pictures of cells in biology. My pictures look like this:

Tissue slide

I want to be able to calculate a ratio of the area of the cell’s nucleus to the area of the cell as a whole.

In my slides, the nucleus is dark purple and other regions of the cell are light blue. There are also tan coloured red blood cells which I want to ignore entirely. For clarity, here’s a labeled image:

Labeled cell

How can I use image segmentation to identify and measure my regions of interest?

I have tried follow this guide, but it returns a completely black image.

Advertisement

Answer

First, some preliminary code that we’ll use below:

JavaScript

For reference, here’s your original image:

JavaScript

Original Image

The article you’ve linked to suggests using Otsu’s method for colour segmentation. The method assumes that the intensity of the pixels of the image can be plotted into a bimodal histogram, and finds an optimal separator for that histogram. I apply the method below.

JavaScript

Grayscale cells Tresholded grayscale cells

The binary form of the image isn’t that good! Looking at the grayscale image, you can see why: the Otsu transformation produces three classes of pixels: the dark background pixels, the donut cells and cell interiors, and the nuclei. The histogram below demonstrates this:

JavaScript

Histogram with three peaks: Otsu's method doesn't work here

Thus, you’ve broken the assumptions of the algorithm you are using, so it’s not unexpected that you get bad results. By throwing away colour information, we’ve lost the ability to differentiate donuts from cell interiors.

One way of dealing with this is to perform segmentation based on colour thresholding. To do this, you choose a color space to work in. This guide has an excellent pictorial description of the different spaces.

Let’s choose HSV. This has the advantage that a single channel, H, describes the image’s colour. Once we’ve converted our image into this space, we can find the bounds of our colours of interest. For instance, to find the cell’s nuclei we could do as follows:

JavaScript

Color Thresholding image mask Color Thresholding image with mask applied

This looks much better! Though, notice that some portions of the cell’s interiors are being labeled as nucleii, even though they should not. One could also argue that it’s not very automatic: you still have to carefully handpick your colours. Operating in HSV space eliminates a lot of the guesswork, but maybe we could use the fact that there are four distinct colours to obviate the need for ranges! To do so, we pass our HSV pixels through a k-means clustering algorithm.

JavaScript

K-means labeled image with colours K-means labeled image with labels

Notice that this has done an excellent job of separting the colours without the need for manual specification! (Other than specifying the number of clusters.)

Now, we need to figure out which labels correspond to which parts of the cell.

To do so, we find the colour of two pixels: one which is clearly a nucleus pixel and one which is clearly a cell pixel. We then figure out which cluster center is closest to each of these pixels.

JavaScript

Now, let’s build the binary classifier we need to identify the entirety of the cells for the watershed algorithm:

JavaScript

Binary classifier

We can now eliminate single-pixel noise:

JavaScript

With noise eliminated

We now need to identify the peaks of the watershed and give them separate labels. The goal of this is to generate a set of pixels such that each of the nuclei+cells has a pixel within it and no two nuclei have their identifier pixels touching.

To achieve this, we could perform a distance transformation and then filter out distances that are two far from the center of the nuclei+cells.

However, we have to be careful since long, narrow cells with high thresholds might disappear entirely. In the image below, we’ve separated the two cells that were touching in the bottom right, but entirely eliminated the long, narrow cell that was in the upper right.

JavaScript

Distance transformation Distance transformation eliminates a cell

Decreasing the threshold brings the long, narrow cell back, but leaves the cells in the bottom right connected.

We can fix this by using an adaptive method which identifies the peaks in each local area. This eliminates the need to set a single, global constant for our threshold. To do so, we use the h_axima function, which returns all local maxima that are greater than a specified cut-off value. This contrasts with the distance function, which returned all pixels greater than a given value.

JavaScript

Distance transform Local maxima

Now we identify unknown regions, the regions which will be labeled by the watershed algorithm, by subtracting off the maxima:

JavaScript

Unknown regions

Next, we give each of the maxima unique labels and then mark the unknown regions before finally performing the watershed transform:

JavaScript

Connected components Markers Labeled watershed components Watershed outlines

This gives us a set of labeled regions representing the cells. Next, we iterate through these regions, use them as masks on our labeled data, and calculate the fractions:

JavaScript

This gives:

JavaScript

Note that if you’re using this for academic purposes, please cite this Zenodo repo.

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement