[PYTHON] I tried to detect the iris from the camera image

Introduction

We have summarized the presentations of 56th Computer Vision Study Group @ Kanto held on Saturday, January 19, 2020. You can see the materials of the day from here.

The source code is available on Github below. https://github.com/33taro/gaze_cv

About the procedure for iris detection

Iris detection is a theme I was researching when I was in college, so I thought it would be easy to do it with the evolved OpenCV. The procedure is as follows.

  1. Detection of human faces and facial landmarks from camera images
  2. Cut out the eye area from the landmark on the face
  3. The eye area is binarized to extract the iris area
  4. Iris detection from the extracted iris area

虹彩検出手順.png

Detection of human faces and facial landmarks from camera images

I tried to detect the iris (black eye part) using the landmark detection of the face introduced in Another article before. Please refer to that for details.

Cut out the eye area from the landmark of the face

As introduced in the above article, the landmark of the face is [here](https://ibug.doc.ic.ac.uk/ We are using the trained model in resources / facial-point-annotations /). Therefore, the right eye is "No.37-42" and the left eye is "No.43-48".

目領域.png

This is described in "eye_region_manager.py" in the "tracking_system" directory in the actual source code.

eye_region_manager.py


    def detect_eye_region(self, face_landmark):
        """
Get the coordinates of the eye area from the landmark
        :param face_landmark:
        """
        #Right eye cutout
        self._right_eye_region = {'top_x': face_landmark[36][0], 'bottom_x': face_landmark[39][0],
                                  'top_y': face_landmark[37][1]
                                  if face_landmark[37][1] < face_landmark[38][1] else face_landmark[38][1],
                                  'bottom_y': face_landmark[41][1]
                                  if face_landmark[41][1] > face_landmark[40][1] else face_landmark[40][1]}

        #Left eye cutout
        self._left_eye_region = {'top_x': face_landmark[42][0], 'bottom_x': face_landmark[45][0],
                                 'top_y': face_landmark[43][1]
                                 if face_landmark[43][1] < face_landmark[45][1] else face_landmark[45][1],
                                 'bottom_y': face_landmark[47][1]
                                 if face_landmark[47][1] > face_landmark[46][1] else face_landmark[46][1]}

Extract the iris area by binarizing the eye area

The P-tile method was used to binarize the eye area. This is a method to specify the percentage of the image area that you want to binarize. As a result, the iris could be acquired regardless of the brightness. (As a rule of thumb, the iris is 40% of the eye area)

目領域の2値化.png

Since the P tile method is not implemented in OpenCV, I made it myself, It is described in "image_utility.py" in the "utility" directory.

image_utility.py


# coding:utf-8

import cv2


def p_tile_threshold(img_gry, per):
    """
Binarization process by P tile method
    :param img_gry:Grayscale image to be binarized
    :param per:Percentage of images that are binarized
    :return img_thr:Binarized image
    """

    #Histogram acquisition
    img_hist = cv2.calcHist([img_gry], [0], None, [256], [0, 256])

    #Calculate the number of pixels from the ratio of the binarized object in the image
    all_pic = img_gry.shape[0] * img_gry.shape[1]
    pic_per = all_pic * per

    #Threshold calculation for binarization by P-tile method
    p_tile_thr = 0
    pic_sum = 0

    #Current brightness and sum of brightness(Add in descending order of value)Calculation
    for hist in img_hist:
        pic_sum += hist

        #Processing ends when the total brightness exceeds the specified ratio
        if pic_sum > pic_per:
            break

        p_tile_thr += 1

    #Binarization process with the threshold value obtained by the P tile method
    ret, img_thr = cv2.threshold(img_gry, p_tile_thr, 255, cv2.THRESH_BINARY)

    return img_thr

Iris detection from the extracted iris area

I was able to obtain the iris area, but I cannot extract only the iris cleanly due to the shadows of the eyebrows and eyelids. Therefore, the black area was acquired by contour point tracking, added to each area to approximate the circumscribed circle, and the circle with the largest radius was used as the iris.

虹彩の外接円近似.png

A series of binarization-iris detection is described in "eye_system_manager.py" in the "tracking_system" directory.

eye_system_manager.py


    @staticmethod
    def _detect_iris(eye_img):
        #After grayscale, smoothing with Gaussian filter
        eye_img_gry = cv2.cvtColor(eye_img, cv2.COLOR_BGR2GRAY)
        eye_img_gau = cv2.GaussianBlur(eye_img_gry, (5, 5), 0)

        #Binarization by P tile method
        eye_img_thr = p_tile_threshold(eye_img_gau, IRIS_PER)

        cv2.rectangle(eye_img_thr, (0, 0), (eye_img_thr.shape[1] - 1, eye_img_thr.shape[0] - 1), (255, 255, 255), 1)

        #Contour extraction
        contours, hierarchy = cv2.findContours(eye_img_thr, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

        #Find the iris from the contour by the smallest circumscribed circle
        iris = {'center': (0, 0), 'radius': 0}
        for i, cnt in enumerate(contours):
            (x, y), radius = cv2.minEnclosingCircle(cnt)
            center = (int(x), int(y))
            radius = int(radius)

            #Exclude from iris candidates if radius is too large
            if eye_img_thr.shape[0] < radius*0.8:
                # #Drawing of iris candidates
                # cv2.circle(eye_img, center, radius, (255, 0, 0))
                continue

            #The circle with the largest radius is recognized as the iris
            if iris['radius'] < radius:
                iris['center'] = center
                iris['radius'] = radius
                iris['num'] = i

        return iris

Iris detection results

demo.gif

As shown in the figure above, the irises of the left and right eyes are firmly acquired. However, there are still issues regarding the top and bottom. However, when a person looks up and down, he often moves his face rather than moving his iris. (Actually looking up and down with just your eyes makes you tired) So I'm wondering if I can somehow detect the orientation of the face from the landmarks on the face.

Reference link

Contour point tracking

Minimum circumscribed circle

P tile method

Recommended Posts

I tried to detect the iris from the camera image
I tried to cut out a still image from the video
I tried to correct the keystone of the image
I tried to compress the image using machine learning
I tried to move the ball
I tried to estimate the interval.
I tried changing the python script from 2.7.11 to 3.6.0 on windows10
I tried to get various information from the codeforces API
I tried to sort out the objects from the image of the steak set meal-④ Clustering
I tried to summarize the umask command
I tried to recognize the wake word
I tried to build the SD boot image of LicheePi Nano
I tried to process the image in "sketch style" with OpenCV
I tried to summarize the graphical modeling.
I tried to estimate the pi stochastically
I tried to touch the COTOHA API
I tried to process the image in "pencil style" with OpenCV
I tried playing with the image with Pillow
I tried to sort out the objects from the image of the steak set meal-① Object detection
I tried to sort out the objects from the image of the steak set meal-② Overlap number sorting
I tried to transform the face image using sparse_image_warp of TensorFlow Addons
I tried to execute SQL from the local environment using Looker SDK
I tried moving the image to the specified folder by right-clicking and left-clicking
I tried to get the batting results of Hachinai using image processing
I tried to learn the angle from sin and cos with chainer
I tried "smoothing" the image with Python + OpenCV
I tried web scraping to analyze the lyrics.
I tried to detect Mario with pytorch + yolov3
I tried hitting the Qiita API from go
I tried "differentiating" the image with Python + OpenCV
I tried to optimize while drying the laundry
I tried image processing like an event camera
I tried to get an image by scraping
I tried to save the data with discord
I tried to detect motion quickly with OpenCV
I tried to touch the API of ebay
I tried "binarizing" the image with Python + OpenCV
I tried to detect an object with M2Det!
Qiita Job I tried to analyze the job offer
I tried using the image filter of OpenCV
LeetCode I tried to summarize the simple ones
I tried to implement the traveling salesman problem
I tried to predict the price of ETF
I tried to vectorize the lyrics of Hinatazaka46!
I tried to sort out the objects from the image of the steak set meal --③ Similar image Heat map detection
I tried to debug.
I tried to paste
I tried to sort out the objects from the image of the steak set meal-⑤ Similar image feature point detection
I tried to summarize the relationship between probability distributions starting from the Bernoulli distribution
[Python] I tried to judge the member image of the idol group using Keras
[IBM Cloud] I tried to access the Db2 on Cloud table from Cloud Funtions (python)
I tried to extract a line art from an image with Deep Learning
I tried to process and transform the image and expand the data for machine learning
[Python] I tried to get the type name as a string from the type function
I tried to pass the G test and E qualification by training from 50
I tried to automate the face hiding work of the coordination image for wear
I tried to learn the sin function with chainer
I tried to graph the packages installed in Python
I want to detect images of cats from Instagram
I tried to summarize the basic form of GPLVM
I tried to touch the CSV file with Python