Skip to main content

Basic cell counting and segmentation in Matlab

Counting cells manually is a tedious error prone process for humans. Given a large data set of microscopy images this task can be achieved much faster by means of basic computer vision techniques. In this tutorial we will segment cells from an image following a method similar to the one presented by Yongming Chen in 1999. The method uses basic morphological operations and the watershed algorithm to segment the cells. Nowadays better methods for cell segmentation exist. This method was chosen for its simplicity and ease of implementation.

We start with an image of cell-like structures by Anna-Katerina Hadjantonakis and Virginia E Papaioannou.

A = imread('cells.jpg');

We convert the image to grayscale:

I = rgb2gray(A);

To be able to extract the dimmer cells, it is necessary to perform some local contrast adjustments

I = adapthisteq(I);

Objects on the borders can be caused by noise and other artifacts. We can eliminate objects on the borders of the image like this:

I = imclearborder(I);

Additionally, we can remove noise by adaptive filtering, using a small window (in this case 5x5 pixels). The changes are barely noticeable to the human eye, but they greatly reduce the number of incorrect cells found:

I = wiener2(I, [5 5]);

Next we will perform some steps to extract the perimeters of cell or cell groups following a binarization technique. We will use some basic morphological operations to further remove objects that are too small to be cells. We find a global threshold using Otsu's method, and we use it to convert the greyscale image to binary:

bw = im2bw(I, graythresh(I));

We then fill image regions and holes. This is necessary when the cell have varying contrast within themselves. In our example image we could skip this step without loss of accuracy.

bw2 = imfill(bw,'holes');

We then perform morphological opening using a disc kernel:

bw3 = imopen(bw2, strel('disk',2));

Next we remove from the binary image all connected components (cells) that have fewer than 10 pixels.

bw4 = bwareaopen(bw3, 100);

We can see that many cells are grouped. We can visualize the groups by finding their perimeter and overlaying it over the grayscale image. To overlay the perimeters the imoverlay function written by Steven L. Eddins was used.

bw4_perim = bwperim(bw4);
overlay1 = imoverlay(I, bw4_perim, [1 .3 .3]);

Counting the number of groups will not yield accurate counts of cells, because several cells overlap. For this reason, we are going to apply the watershed algorithm on the image, which is able to partially divide the groups into distinct cells. The watershed algorithm interprets the gray level of pixels as the altitude of a relief. For this reason we need to modify our image so that the cell borders have the highest intensity and the background is clearly marked (we mark is as negative infinity). We achieve this by first finding the maxima which should approximately correspond to the cell nuclei and then we transform the image such that the background pixels and these maxima are the only local minima in the image:

% Discover putative cell centroids
maxs = imextendedmax(I,  5);
maxs = imclose(maxs, strel('disk',3));
maxs = imfill(maxs, 'holes');
maxs = bwareaopen(maxs, 2);
overlay2 = imoverlay(I, bw4_perim | maxs, [1 .3 .3]);

% modify the image so that the background pixels and the extended maxima pixels are forced to be the only local minima in the image.
Jc = imcomplement(I);
I_mod = imimposemin(Jc, ~bw4 | maxs);

Finally, we can apply the watershed algorithm:

L = watershed(I_mod);
labeledImage = label2rgb(L);

We can then easily count the number of discovered cells. We have detected 185 cells in this image.

[L, num] = bwlabel(L);

Let's overlay the detected cells over the original grayscale image to visually evaluate the performance of the algorithm:

mask = im2bw(L, 1);
overlay3 = imoverlay(I, mask, [1 .3 .3]);

While many cells have been correctly detected, there are several that our algorithm does not detect. Additionally we have detected several cells in the center of the image, but even a human eye could hardly count their number as they appear as a dust cloud. Some cells are fragmented into two distinct cells. Finally, the detected cells appear smaller than the real ones, which means that we were not sufficiently careful when applying the morphological operations.

The algorithm completes in 0.3s on a 3.4GHz i7-3770 CPU for an input image of dimensions 540x512 pixels.

Below I present additional results, using different images featuring cells under different imaging conditions and bubbles. The point of these results is to show that this algorithm was optimized to segment and count cells in a single type of images, and will perform poorly in the rest. Several parameters had to be changed to improve the performance in the different scenarios. Images with dark cells and bright background had to be color inverted before processing.

The algorithm performs best on this image, because it was used to guide the design of the algorithm.

The algorithm has difficulties correctly segmenting the shapes of the cells because of the high contrast difference within them.

The low contrast cell boundaries and large overlapping cause the algorithm to perform poorly on this image.

The detection of bubbles could be improved by tweaking the morphological operations performed on the image.

The varying intensities within the cells cause the algorithm to perform poorly.

The use of an automatic global threshold for binarization (Otsu's method) caused the algorithm to perform poorly on this image. Manually adjusting the threshold results in much better detection of the bright spots.

In this tutorial we have presented a relatively simple method to segment and count cells in an image. Some tweaking could improve the results of the segmentation, and improve the detection accuracy. Also, we could add a merging method to merge cells that are over-fragmented.


Popular posts from this blog

The Increased Addictiveness of Today's Video Games

This is a guest post by Miles Walker, a freelance writer and blogger who usually  compares car insurance  deals over at CarinsuranceComparison.Org. His most recent review looked at the best  car insurance quotes . Video games have always held some addiction, but now more than ever that addiction is growing. People are spending more time than ever playing the games, and game designers are constantly finding new ways keep it that way. Their efforts have a been a complete success, and some games have true addicts, addicts who play 24 hours a week or more. Visual enhancements Video games have come a long way since a certain duo of Italian plumbers started showing up in people's houses in the late 1980s. By leaps and bounds, video game graphics have become alarmingly sophisticated. Each graphical improvement increased a game's possibilities and added more depth to video games. Designers began thriving on this depth, making games with more achievements, unlocks, levels an

Project planning in a text file

Whenever you work on a project it is important to be able to plan it ahead of time. This holds true for small and big project, from planning a trip to the spa to building a spaceship. The small project plans can be maintained in you thoughts while bigger ones require tools to help you see the big-picture of the project and manage task at a lower level. There are projects which start with a fully prepared plan and projects which pivot overnight, thus invalidating any original plan. For the latter flexibility is very important, and tools like Trello offer a great solution because they can be adjusted to fit your project. However, it may happen sometimes that the project starts adjusting to the tool or that you still want to maintain a bigger picture of the main points of the project. You may also need to produce a rough development schedule to serve as a long term road-map. I have prototyped a tool (and defined a workflow) which allows you to plan such projects. To better understa