10

I have a bunch of Petri dishes full of dots which I'd like to count in Matlab. Can this be done reliably and in batches?

E.g. This plate has 352 colonies

enter image description here

I've tried ImageJ but need to do quite a bit of cropping out of the border and get variable results.

Do you have any suggestions?

Peter O.
  • 32,158
  • 14
  • 82
  • 96
HCAI
  • 2,213
  • 8
  • 33
  • 65
  • It's ages since I had to do anything like this or use Matlab - but don't you have to use [edge detection](http://initora.wordpress.com/article/learn-matlab-image-processing-edge-232y3pcqwxodx-29/])? There must be plenty of pre-written scripts out there. – benedict_w Mar 31 '12 at 10:04
  • There is this tool: [NICE](http://www.nist.gov/pml/div682/grp01/nice.cfm) for the job but I can't get it to open. It complains about not having a certain dll file. – HCAI Mar 31 '12 at 10:10
  • try and download / install the .dll? Check you have the correct version of Matlab for it, etc. – benedict_w Mar 31 '12 at 10:16
  • @benedict_w do I have to have a specific Matlab compiler runtime to that application. Will it overwrite my current installation? – HCAI Mar 31 '12 at 11:47
  • Please count the number of colonies in the example image as a "ground truth." – reve_etrange Mar 31 '12 at 12:16
  • @reve_etrange 352 colonies counted by hand. – HCAI Mar 31 '12 at 12:29

3 Answers3

14

My approach to this problem is as follows:

  1. Use Hough transform to identify circles corresponding to the Petri dish.
  2. Global thresholding with Otsu's method, restricted to the dish.
  3. Count colonies as the regional maxima of the original image, which are represented in the segmented image.

This file exchange toolbox provides us with a working circular Hough transform. Things are pretty straightforward from there:

function [count,colonies,bw] = colony_count(I)

I = rgb2gray(im2double(I)); %# Color-to-gray conversion.
[m,n] = size(I);

%# Uncomment this if you have might have some images with light background
%# and dark colonies. It will invert any that seem that way.
%#if graythresh(I) < 0.5
%#    I = imcomplement(I);
%#end

bw = I > graythresh(I); %# Otsu's method.
radii = 115:1:130; %# Approx. size of plate, narrower range = faster.
h = circle_hough(bw,radii,'same','normalise'); %# Circular HT.
peaks = circle_houghpeaks(h, radii, 'npeaks', 10); %# Pick top 10 circles.

roi = true(m,n);
for peak = peaks
    [x, y] = circlepoints(peak(3)); %# Points on the circle of this radius.
    x = x + peak(1); %# Translate the circle appropriately.
    y = y + peak(2);
    roi = roi & poly2mask(x,y,m,n); %# Cumulative union of all circles.
end

%# Restrict segmentation to dish. The erosion is to make sure no dish pixels
%# are included in the segmentation.
bw = bw & bwmorph(roi,'erode');

%# Colonies are merged in the segmented image. Observing that colonies are 
%# quite bright, we can find a single point per colony by as the regional
%# maxima (the brightest points in the image) which occur in the segmentation.
colonies = imregionalmax(I) & bw;

%# Component labeling with 4-connectivity to avoid merging adjacent colonies.
bwcc = bwconncomp(colonies,4);
count = bwcc.NumObjects;

We use this code like this:

I = imread('https://i.stack.imgur.com/TiLS3.jpg');
[count,colonies,mask] = colony_count(I);

I have also uploaded the colony_count function on the file exchange. If you have an image which doesn't work but you think should, leave a comment there.

The count is 359, which I'd say is pretty close. You can inspect the segmentation (mask) and colony markers (colonies) to see where mistakes are made:

%# Leave out the changes to mask to just see the colony markers.
%# Then you can see why we are getting some false colonies.
R = I; R(mask) = 255; R(colonies) = 0;
G = I; G(mask) = 0; G(colonies) = 255;
B = I; B(mask) = 0; B(colonies) = 0;
RGB = cat(3,R,G,B);
imshow(RGB);
reve_etrange
  • 2,561
  • 1
  • 22
  • 36
  • @Li-aungYip Thanks, but hopefully no one puts their plate on a white background... – reve_etrange Mar 31 '12 at 14:14
  • [What kind of sucker would do that?](http://farm4.static.flickr.com/3008/2367953025_b5760be025_o.jpg) – Li-aung Yip Mar 31 '12 at 14:16
  • @Li-aungYip Indeed...but of course that example would be trivial in HSV space. – reve_etrange Mar 31 '12 at 14:19
  • This is also a good reason to inspect a random sample of any data you process automatically. As a generalisation, a method will work flawlessly on the sample data you developed it with, but parts of the data may violate your assumptions. – Li-aung Yip Mar 31 '12 at 14:24
  • @reve_etrange This works beautifully! Thank you! In fact it is better than a hand counting method because colonies which grow closely together are hard for the human eye to identify separately. 48,000 colonies counted by hand... millions counted by Matlab! What a beautiful world! Will you be putting this on file exchange? – HCAI Mar 31 '12 at 14:54
  • I've tried a few stock images: eg [1](http://www.ccp-berlin.org/img/7_2_bacteria_on_an_Agar_plate.jpg) and find the code to be very sensitive the the radii variable. How do you judge what this ought to be? Is it the radius of the growth area in pixels? – HCAI Mar 31 '12 at 15:38
  • The internal radius of the Petri dish, in pixels. You probably have to set the range based on the stability of your imaging apparatus. I found that the radius was about ~125 so I used a range that would work as long as the zoom was pretty similar. – reve_etrange Mar 31 '12 at 15:44
  • Oh yeah, also I used the code from the Hough circles demo to display the circles I was getting. – reve_etrange Mar 31 '12 at 15:48
  • Is it OK if I use your image as example on the file exchange? – reve_etrange Mar 31 '12 at 16:10
  • @reve_etrange In fact this is an image I found on the net. Do you think there is some way of automating the radius detection and reflection reduction from the sides of the dishes? This will be a very popular file! – HCAI Mar 31 '12 at 16:36
  • 2
    Very nice answer. Just a comment that the latest release of Image Processing Toolbox (12a) has a new function for circular Hough transforms built in. – Sam Roberts Mar 31 '12 at 21:43
2

You could use a technique called connected component labeling which can be used do distinguish between different objects in an image.

First of all you need to make the image binary by some mean of thresholding. The labeling is the done by scanning each pixel row twice, once left-to-right and once right-to-left. We are looking for object pixels, i.e. pixels that have value 1.

In the left-to-right scan: for each pixel p: If p is an object pixel, copy the label from above or left. If p is a background pixel or p has a label, do nothing.

For the right-to-left scan: for each pixel p: If p is an object pixel, copy the label from the right if there is one, otherwise set a new label. If p is a background pixel or p has a label, do nothing. If a label exists and the pixel to the right of p has a different label, make a note of this.

For example (from lecture slides at http://webstaff.itn.liu.se/~bjogu/TNM087-2012/Fo7-2012-AH.pdf):

labeling example

When you have scanned the whole image, merge all labels that you have noted (they are connected to the same object) and then count the number of distinct labels and you will have your count.

erik
  • 1,238
  • 3
  • 12
  • 23
  • I understand the procedure you have described. My images have the added difficulty of a Petri dish border which is a nuisance, particularly because it is of similar colour to the dots... Can this be eliminated without physical removal? – HCAI Mar 31 '12 at 12:06
  • well explained mate!! – Jeru Luke Mar 08 '17 at 12:46
1

What I would do is:

  1. Transform the image to binary image which can be done using some threshold on the Intensity. notice the dots are lighter so you might do 1-binaryImage after taking the threshold. I don't know why you said they are black, but it the same idea no matter what color they are in.

  2. after that you can use Hough transform and plot the histogram of rho and theta

  3. and on that histogram you might take a second threshold on the rho == radius.

Added:

Detect circles with various radii in grayscale image via Hough Transform

0x90
  • 39,472
  • 36
  • 165
  • 245
  • Why would you use the Hough transform? There are no lines to detect here. – Niki Mar 31 '12 at 11:53
  • @nikie from wikipedia (link is in message) "In automated analysis of digital images, a subproblem often arises of detecting simple shapes, such as straight lines, circles or ellipses" – 0x90 Mar 31 '12 at 14:50
  • Did you use the wrong link? If I follow the Hough Transform link in your answer, it clearly says "Use the hough function to detect lines in an image" – Niki Mar 31 '12 at 19:45
  • @nikie I added a moudule to detect circles using hough transform as well. – 0x90 Mar 31 '12 at 20:38