15

I've been reading about the subject but cannot get the idea in "plain English" about the usage and parameters for HoughCircles (specially the ones after CV_HOUGH_GRADIENT).

What's an accumulator threshold? Are 100 "votes" a right value?

I could find and "mask" the pupil, and worked my way through the Canny function, but I'm struggling beyond that and my problem is the HoughCircles function. There seems to be failing at finding the Iris' circle and I don't know why.

This is what I have so far. LEFT: masked pupil RIGHT: canny result

And this is the function I'm working on:

def getRadius(area):
    r = 1.0
    r = math.sqrt(area/3.14)
    return (r)

def getIris(frame):
    grayImg = cv.CreateImage(cv.GetSize(frame), 8, 1)
    cv.CvtColor(frame,grayImg,cv.CV_BGR2GRAY)
    cv.Smooth(grayImg,grayImg,cv.CV_GAUSSIAN,9,9)
    cv.Canny(grayImg, grayImg, 32, 2)
    storage = cv.CreateMat(grayImg.width, 1, cv.CV_32FC3)
    minRad = int(getRadius(pupilArea))
    circles = cv.HoughCircles(grayImg, storage, cv.CV_HOUGH_GRADIENT, 2, 10,32,200,minRad, minRad*2)
    cv.ShowImage("output", grayImg)
    while circles:
        cv.DrawContours(frame, circles, (0,0,0), (0,0,0), 2)
        # this message is never shown, therefore I'm not detecting circles
        print "circle!"
        circles = circles.h_next()
    return (frame)
jorge_codes
  • 3,026
  • 4
  • 26
  • 25

2 Answers2

27

HoughCircles can be kind of tricky, I suggest looking through this thread. Where a bunch of people, including me ;), discuss how to use it. The key parameter is param2, the so-called accumulator threshold. Basically, the higher it is the less circles you get. And these circles have a higher probability of being correct. The best value is different for every image. I think the best approach is to use a parameter search on param2. Ie. keep on trying values until your criteria is met (such as: there are 2 circles, or max. number of circles that are non-overlapping, etc.). I have some code that does a binary search on 'param2', so it meet the criteria quickly.

The other crucial factor is pre-processing, try to reduce noise, and simplify the image. Some combination of blurring/thresholding/canny is good for this.

Anyhow, I get this:

enter image description here

From your uploded image, using this code:

import cv
import numpy as np

def draw_circles(storage, output):
    circles = np.asarray(storage)
    for circle in circles:
        Radius, x, y = int(circle[0][3]), int(circle[0][0]), int(circle[0][4])
        cv.Circle(output, (x, y), 1, cv.CV_RGB(0, 255, 0), -1, 8, 0)
        cv.Circle(output, (x, y), Radius, cv.CV_RGB(255, 0, 0), 3, 8, 0)    

orig = cv.LoadImage('eyez.png')
processed = cv.LoadImage('eyez.png',cv.CV_LOAD_IMAGE_GRAYSCALE)
storage = cv.CreateMat(orig.width, 1, cv.CV_32FC3)
#use canny, as HoughCircles seems to prefer ring like circles to filled ones.
cv.Canny(processed, processed, 5, 70, 3)
#smooth to reduce noise a bit more
cv.Smooth(processed, processed, cv.CV_GAUSSIAN, 7, 7)

cv.HoughCircles(processed, storage, cv.CV_HOUGH_GRADIENT, 2, 32.0, 30, 550)
draw_circles(storage, orig)

cv.ShowImage("original with circles", orig)
cv.WaitKey(0)

Update

I realise I somewhat miss-read your question! You actually want to find the iris edges. They are not so clearly defined, as the pupils. So we need to help HoughCircles as much as possible. We can do this, by:

  1. Specifying a size range for the iris (we can work out a plausible range from the pupil size).
  2. Increasing the minimum distance between circle centres (we know two irises can never overlap, so we can safely set this to our minimum iris size)

And then we need to do a param search on param2 again. Replacing the 'HoughCircles' line in the above code with this:

cv.HoughCircles(processed, storage, cv.CV_HOUGH_GRADIENT, 2, 100.0, 30, 150,100,140)

Gets us this:

enter image description here

Which isn't too bad.

Community
  • 1
  • 1
fraxel
  • 34,470
  • 11
  • 98
  • 102
  • Thanks fraxel. Is it the same procedure for finding the Iris' outer bound? As you can see my problem is not the pupil, but the outer eye ring. I got the centroid using regular color isolation as can be seen here http://bit.ly/Lqaz4J I'll give your code a try after coming back from work =) Thanks again. – jorge_codes May 23 '12 at 11:42
  • @pctroll - sorry, I miss understood your question! I've corrected my answer to do what you're after :). You can probably use your centroid info to position the circles better. – fraxel May 23 '12 at 12:03
  • @flaxel - thank you!. And yes, I can worked out the center better. However, It's very interesting how the function finds the circle despite the noise (I've read about Hough Transform, but I'm very visual and I had Canny and Smooth in inverse order). – jorge_codes May 24 '12 at 06:54
1

My alternative suggestion is to use Threshold and Blob analysis. It more simple to detect iris than using canny edge and hough transform.

My way is... First you threshold it. Pick up any threshold value until the black and white image produce only (black color) iris and eyelashes.

Then separate the the iris and eyelashes by putting in blob analysis value min length at XX and min width at YY. The XX and YY value are the value of iris length and width.

Zulhilmi
  • 11
  • 1
  • 1
    +1 for using Blob analysis instead of Hough circle detection. I tend to get very imprecise results with OpenCV's implementation of the Circle Hough Transform, as if the step size of the parameter space search was too big. I could have clearly defined full circles, where just adapting the centre point one or two pixels to one side would make the detected circle fit a lot more precisely to the contrast changes in the image (as visible in the images of the accepted answer, too). Blobs tend to give me a much more precise centre point and radius. – Daniel Saner Aug 16 '17 at 13:00