Counting the pixels within a circle detected in an image

Hi everyone.
Based on this image,
Using Hough Transformation, I managed to detect many circles. But I require only the middle circle detected around the pupil. There are several methods that I was thinking, that could remove the other circles.
For example,
1) counting the number of black pixels within the circle and the one with the most is the pupil. 2) taking the white pixels along the circumference of the pupil. the one with the most white pixels is the pupil.
I was thinking number 2 would be a more accurate solution. Hence, how do I count the number of white pixels?
Thank you!

 Accepted Answer

How standard are your images? Could you choose the circle whose radius and centre coordinates are within expected ranges?
If you can't do this, I'd suggest making measurements on the original image, rather than on the edge map. There have been answers here recently showing how to make measurements on the pixels in a circular disk - add a comment if you need help finding one, but do a search first.
By the way, there's a highlight which badly affects the parameters of the circle round the pupil. If you can find some way of removing it (by preprocessing prior to the edge detection perhaps) that will improve your accuracy enormously.
EDIT
Rather than counting black pixels (which means defining what is "black"), why not compare the mean of the grey-levels inside the circles? Here's a function you can use to compute these means:
function m = meanDisk(img, xc, yc, r)
%meanDisk computes mean of values inside a circle
% M = meanDisk(IMG, XC, YC, R) returns the mean of IMG(Y,X) for all X and
% Y such that the Euclidean distance of (X,Y) from (XC,YC) is less than
% R. IMG must be 2-D, R must be positive, and some elements of IMG must
% lie within the circle.
% This section is for efficiency only - avoids wasting computation time on
% pixels outside the bounding square
[sy sx] = size(img);
xmin = max(1, floor(xc-r));
xmax = min(sx, ceil(xc+r));
ymin = max(1, floor(yc-r));
ymax = min(sy, ceil(yc+r));
img = img(ymin:ymax, xmin:xmax); % trim boundaries
xc = xc - xmin + 1;
yc = yc - ymin + 1;
% Make a circle mask
[x y] = meshgrid(1:size(img,2), 1:size(img,1));
mask = (x-xc).^2 + (y-yc).^2 < r.^2;
% Compute mean
m = sum(sum(double(img) .* mask)) / sum(mask(:));
end
EDIT Adding code to deal with the four example images linked to from Ivan's comment of 12 Jan 2012.
This assumes the use of this Hough transform from the file exchange.
The code below works for all 4 of the example images posted (though note that cropping may affect the results as the original image isn't in quite the same place in all of them). I used the fact that the pupil is dark to detect the case where the eye is closed - this works better than playing with the Hough transform parameters.
% Read in the image as downloaded, crop out the starting image, convert to
% grayscale in range 0-1
img = imread('help1.jpg'); % or whatever
img = double(rgb2gray(img(28:169, 167:391, :)))/256;
% Find edges. Note that Canny method incorporates Gaussian smoothing and
% gradient calculation, so no need to do these separately
edgeim = edge(img, 'canny');
% Detect most prominent circle. Radius range may be overgenerous.
radii = 7:2:21;
[h, margin] = circle_hough(edgeim, radii);
peak = circle_houghpeaks(h, radii, margin, 'npeaks', 1);
cx = peak(1);
cy = peak(2);
r = peak(3);
% Test whether the brightness inside the circle is greater than the average
% image brightness divided by the following constant. If it is, the pupil
% is probably not visible.
pupil_darkness_ratio = 2;
if pupil_darkness_ratio*meanDisk(img, cx, cy, r) > mean(img(:))
disp('No pupil found');
else
imshow(img);
hold on;
[x, y] = circlepoints(r);
plot(x+cx, y+cy, 'g-');
hold off
end

21 Comments

the images are generally standardised except for 10% of the time where the pupil may move left to right.
So I think counting the pixels would be a better solution.
As you mentioned, i have drawn the circles on the original image.
http://i241.photobucket.com/albums/ff200/whu_esle/pupil.jpg
i think counting the number of black pixels would be the most ideal way.
OK, I'll edit the question to make a suggestion.
ok thank you David, will try it now and see how I adapt. thank you so much!
Hi David, I was wondering if your brilliant HT code provides the coordinates of the centre of the circles drawn?
Yes, each row of the result of a call to circle_houghpeaks relates to a circle, and contains the x and y coordinates of the centre and the radius. So if you have a call like
peaks = circle_houghpeaks(h, ...)
then peaks(k,1) is the x-coord of the centre of the k'th circle, peaks(k,2) is the y-coord, and peaks(k,3) is the radius.
hi David, hope you had a great new year,
i realised that
peaks = circle_houghpeaks(h, radii, 'nhoodxy', 15, 'nhoodr', 21, 'npeaks', 1);
means that only 1 peak will be detected. and i realised that if it is not able to detect the circle, it will just plot a circle at bottom right hand corner of my image.
Is there a way to tweek it such that if it is only either 1 or no peaks?
Thank you!
Yes, thanks
You'll need to use the 'threshold' parameter, along with npeaks. If you set the threshold to the right value, then you'll get the most prominent circle if there is enough evidence for it, and if not you'll get an empty matrix returned. You can test whether the result is empty using isempty().
You'll need to find a good value for 'threshold' by trial and error, because it depends on your data.
Hi David, managed to use Threshold, but still stuck.
somehow it is detecting something else and not the circle.
feeling so hopeless haha
Please could you give a link to the image that causes the problem, without the superimposed circles, and I'll have a look.
Thank you David.
This are the images that worked perfectly fine!
http://i241.photobucket.com/albums/ff200/whu_esle/help.jpg
http://i241.photobucket.com/albums/ff200/whu_esle/help2.jpg
However this are the one I was referring to.
It detects even though there are no circles.
http://i241.photobucket.com/albums/ff200/whu_esle/help4.jpg
and the last image belows spoils the whole accuracy of my program.
http://i241.photobucket.com/albums/ff200/whu_esle/help3.jpg
I used the "After threshold and thinning" as the reference for detecting the circles.
For the first 2 images, the partial circle can be seen quite clearly.
for the 3rd image, it should not detect anything when the eyelid is closed however there a circle at the corner. and I guess failure for the last image is due to the poor thinning? but maybe its because the image is too dark, but i still need to be able to detect the circle nonetheless.
This is draining my brain juice with so many different trial and errors. haha and I really appreciate you still reaching out a helping hand to a student like me.
Thank you!
Please see my edited answer, with some additional code.
You can check whether the radius range is right by making manual measurements of the pupil diameter in the images. If you display a frame using imshow, you can click on the measurement cursor in the figure's toolbar and hence find the coordinate of points in the image. This is what I did (but quickly and roughly) for the 4 frames I worked on - I measured the diameter and divided by 2.
Looking at the video, it's very noticeable that there are huge illumination changes as the light moves. These may not be helping. Even so, the tools you now have should still handle the problem, though the parameters may well need attention.
It might help to revisit my initial suggestion of testing whether the centre coordinates are in the correct range, or Image Analyst's closely related suggestion of choosing the centre closest to the middle of the image.
Hi David,
I have solved the problem finally! I am really thankful of your guidance and help in this problem!
You are amazing! Thank you so much, I truly appreciate all the effort contributed to find a solution.
Thank you!
Oh man, feel so guilty opening this thread again..
Is there a way to manipulate such that the circle is a slight oval?
(changing parameters in circlepoints.m?)
Thank you
See the line:
mask = (x-xc).^2 + (y-yc).^2 < r.^2;
Well, what do you think it would be for an ellipse?
oh that's good! i would like to ask if the units for my area and diameter would be in pixels right? can I convert it to mm?
Sure, if you know how many mm correspond to a pixel. What is that conversion factor - do you have a number for it? In other words, have you imaged a ruler yet and measured how many pixels correspond to a mm or cm on that ruler?
yeah I was thinking I could use the axis to make an error comparison, comparing with what the system has calculated and what i can see from the axis manually. but just to confirm that the default units would be in pixels ?
Units of measurements are in pixels. To convert to mm you need to multiply by a conversion factor that has units of mm/pixel. You can do that by measuring a ruler and measuring a known distance in mm to see how many pixels it is. Maybe you can use improfile() for doing that.
Replying to your question about using an ellipse rather than a circle. As Image Analyst says, you can readily modify the function for measuring mean graylevel to work with an ellipse, by changing the equation that generates the mask. It's also not too hard to draw an ellipse on the image.
Making the Hough Transform detect ellipses in the first place is much more work. You might find some general ellipse detection code that you could use instead of the HT for circles, but it will have the problem that it's trying to find 5 parameters. You can fit an ellipse to the pupil with only two free parameters by exploiting some constraints: there's more information in this paper: http://www.sussex.ac.uk/Users/davidy/eyetrack_csrp.pdf

Sign in to comment.

More Answers (1)

I think you should look at what you said: "require only the middle circle." Now since you placed those circles, you know where the centers are. So you simply take the center that is closest to (numberOfRows/2, numberOfColumns/2). It's as simple as that, assuming the circle you want is the one closest to the middle of the image.

6 Comments

hmm sorry i complicate things, the images may not be standardised as the pupil may move left or right. so I cant take the centre that is closest to the pupil.
So Image Analyst, can i ask how to count the no of black pixels using this new image?
http://i241.photobucket.com/albums/ff200/whu_esle/pupil.jpg
Thank you so much!
Well why are you getting so many false positives in the first place? Maybe you can adjust the Hough parameters to get fewer. The ones it's getting don't all look right. Maybe you should just threshold on intensity and look for circular regions? Once you have your regions, do some size filtering (see my BlobsDemo File Exchange for a tutorial), and some circularity filtering and then measure the intensity of what's left.
measurements = regionprops(labeledImage, grayImage, 'MeanIntensity');
(You need > R2008a - if you don't see BlobsDemo for code to work with earlier/all versions)
The darkest one will be the pupil.
hi Image Analyst, i appreciate your suggestion so much. Will try it out first. Thank you so much!
hi Image Analyst, i have tried your demo. unfortunately it doesnt work well on my image. as it is not against a black background unlike your image.
I didn't give a demo. Upload your image to tinypic.com and your code for finding the circle locations.
I have solved it by only accepting the circle that is near the original circle. thank you so much Image Analyst!

Sign in to comment.

Asked:

on 23 Dec 2011

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!