OpenCV Iris Detection C++

7.2k views Asked by At

Goal: I am trying to acquire the size of the iris (width/radius) using video as input.

I have tried HoughCircles but it seems that it is not precise as the iris circle seems to not be so accurate. What information I have already is the center point for the eye pupil and its radius.

Grayscale Eye

It has been suggested to me to find the iris edge to try and measure the gradient magnitude starting from the pupil center going outward. Then to use a histogram using the accumulation of the gradient maximum to find the iris width. I am not exactly sure in which way to implement this, starting from a specific point.

I used the Sobel operator on the eye ROI to try and get the gradient with the output shown below.

Sobel Eye

Sobel image code:

void irisFind(Mat gradMat, Point2i pupCenter, int pupRad){

imshow("original", gradMat);


Mat gradX;
Mat gradY;
Mat absGradX;
Mat absGradY;

GaussianBlur(gradMat, gradMat, Size(3, 3), 0, 0, BORDER_DEFAULT);
equalizeHist(gradMat, gradMat);

//Generate Gradient along x
Sobel(gradMat, gradX, CV_16S, 1, 0, 3, 1, 0, BORDER_DEFAULT);
convertScaleAbs(gradX, absGradX);

//Generate Gradient along y
Sobel(gradMat, gradY, CV_16S, 0, 1, 3, 1, 0, BORDER_DEFAULT);
convertScaleAbs(gradY, absGradY);

addWeighted(absGradX, .5, absGradY, .5, 0, gradMat);

imshow("Sobel", gradMat);
}

I am not exactly sure how to proceed next. Any suggestions or comments are appreciated. Also please let me know if I missed any information or if I was vague on something. Much thanks in advance!

EDIT: I should have explained the context of my application better so I apologize for that. I am measuring pupil dilation of the eye over frames from video input. I already know the location of the center point of the pupil and the radius of the pupil. I am trying to find the size of the iris so that variations of the distance from the eye to the camera can be used to compensate for misinterpreted values of the pupil size, since if the eye becomes closer to the camera the pupil will of course appear larger without dilation. I might also try other ways to account for this such as the eye corners but I figured that since I already have several pupil features that I would start with the iris.

Again, sorry for leaving this detail out before. Thanks!

2

There are 2 answers

3
remi On BEST ANSWER

Clarifying the suggestion you talk about in your question:

"It has been suggested to me to find the iris edge to try and measure the gradient magnitude starting from the pupil center going outward. Then to use a histogram using the accumulation of the gradient maximum to find the iris width. I am not exactly sure in which way to implement this, starting from a specific point."

What you can concretely do is to start from your pupil center, and perform a region growing algorithm where your stopping condition, instead of beeing, say, a too different grey level value, is a threshold on the magnitude of your gradient. Some pseudo code:

initalize list of points with center of your pupil
initialize a mask image to zero
while list of point is not empty
   point pt = pop()
   set maskImage at pt to 255
   for  pt2 in pt neighbourhood
       if (gradientMagnitude at pt2 < THRESHOLD and maskImage at pt2 == 0)
          list of points.add (pt2)
2
ArtemStorozhuk On

I think that you should use that fact that there's black circle inside iris.

Here's what I've got after simple black color segmentation on your image:

Segmented image

And it seems that a real iris is in 3 or 4 times bigger than this black circle. So, here's result:

Result image

Looking for a source code? This is it:

int main()
{
    Mat src = imread("input.jpg", CV_LOAD_IMAGE_GRAYSCALE), tmp;

    imshow("Source", src);

    double minVal = 0;
    minMaxLoc(src, &minVal, NULL, NULL, NULL);

    threshold(src, tmp, minVal + 10, 255, THRESH_BINARY_INV);

    //(Optional) remove noise (small areas of white pixels)
/*
    Mat element = getStructuringElement(MORPH_ELLIPSE, Size(3, 3), Point(1, 1));
    erode(tmp, tmp, element);
    dilate(tmp, tmp, element);
*/
    vector<Vec4i> hierarchy;
    vector<vector<Point2i> > contours;
    findContours(tmp, contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);

    //find contour with max area
    int maxArea = 0;
    Rect maxContourRect;
    for (int i=0; i<contours.size(); i++)
    {
        int area = contourArea(contours[i]);
        Rect rect = boundingRect(contours[i]);
        double squareKoef = ((double) rect.width)/rect.height;

        //check if contour is like square (shape)
#define SQUARE_KOEF 1.5
        if (area>maxArea && squareKoef < SQUARE_KOEF && squareKoef > 1.0/SQUARE_KOEF)
        {
            maxArea = area;
            maxContourRect = rect;
        }
    }

    if (maxArea == 0)
    {
        std::cout << "Iris not found!" << std::endl;
    }
    else
    {
        Rect drawRect = Rect(maxContourRect.x-maxContourRect.width, maxContourRect.y-maxContourRect.height, maxContourRect.width*3, maxContourRect.height*3);

        rectangle(src, drawRect, Scalar(0), 1);

        imshow("Dest", src);
        waitKey();
    }
}