Background
I got a chance to test this Raspberry Pi 5” TFT capacitive screen a while ago but I was busy all the time. Finally, I have some free time lately. This day I was on the MediaPipe site and just found the “MediaPipe Iris” function. Although the Python version of MediaPipe does not support Iris tracking, it doesn’t bother me. I decided to give it a try!
Design
The MediaPipe Face Mesh model estimates 468 3D facial landmarks in real time covering the overall surface geometry of a human face.
We can easily find out the landmarks where the eyes are located, and cut out that area.
Then the functions of iris recognition and tracking can be realized by cv2.findContours in Opencv.
Programming
Part 1. Load MediaPipe and Opencv Libraries
import cv2 as cv2
import mediapipe as mp
import numpy as np
Part 2. Coding face Landmark detection
1.
# Import visual functions and styles
2.
3. mp_drawing=mp.solutions.drawing_utils
4.
5. #mp_drawing_styles=mp.solutions.drawing_styles
6.
7. # Import 3D face landmarks detection model
8.
9. mp_face_mesh=mp.solutions.face_mesh
10.
11. drawing_spec = mp_drawing.DrawingSpec(thickness=1, circle_radius=1)
12.
13. cap = cv2.VideoCapture(0)
14.
15. with mp_face_mesh.FaceMesh(
16.
17. max_num_faces=4,
18.
19. min_detection_confidence=0.5,
20.
21. min_tracking_confidence=0.5) as face_mesh:
22.
23. while cap.isOpened():
24.
25. success, frame = cap.read()
26.
27. if not success:
28.
29. print("Ignoring empty camera frame.")
30.
31. # If loading a video, use 'break' instead of 'continue'.
32.
33. break
34.
35.
36.
37. h, w, c = frame.shape
38.
39. # image = cv2.resize(frame, (w //2, h//2))
40.
41. # frame = cv2.flip(frame, 1)
42.
43. image = np.copy(frame)
44.
45. h2, w2, c2 = image.shape
46.
47. # To improve performance, optionally mark the image as not writeable to
48.
49. # pass by reference.
50.
51. image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
52.
53. results = face_mesh.process(image)
54.
55.
56.
57. # Draw the face mesh annotations on the image.
58.
59. image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
60.
61. left_eyes = []
62.
63. right_eyes = []
64.
65. if results.multi_face_landmarks:
66.
67. for face_landmarks in results.multi_face_landmarks:
68.
69. for idx, landmark in enumerate(face_landmarks.landmark):
70.
71.
72.
73. if idx == 246 or idx == 159 or idx == 158 or idx == 145 or idx == 153 or idx == 190: # left
74.
75. #if idx == 53 or idx == 111: # left
76.
77. x1 = np.int(landmark.x * w2)
78.
79. y1 = np.int(landmark.y * h2)
80.
81. left_eyes.append((x1, y1))
82.
83. #cv2.circle(image, (x1, y1), 4, (255, 0, 255), 4, cv2.LINE_AA)
84.
85. if idx ==374 or idx == 380 or idx == 385 or idx == 386 or idx == 390 or idx == 414: # right
86.
87. #if idx == 276 or idx == 340: # right
88.
89. x1 = np.int(landmark.x * w2)
90.
91. y1 = np.int(landmark.y * h2)
92.
93. right_eyes.append((x1, y1))
94.
95. #cv2.circle(image, (x1, y1), 4, (0, 255, 255), 4, cv2.LINE_AA)
96.
97. if len(right_eyes)+len(left_eyes)==12:
98.
99. # Bounding Rectangle, wrap the found shape with a smallest rectangle.
100.
101. right_box = cv2.boundingRect(np.asarray(right_eyes))
102.
103.
104.
105. left_box = cv2.boundingRect(np.asarray(left_eyes))
106.
107.
108.
109. detect_iris(image, right_box, left_box)
110.
111. cv2.imshow('MediaPipe Face Mesh', image)
112.
113. if cv2.waitKey(5) & 0xFF == 27:
114.
115. cv2.imwrite("D:/iris_detect_result.png", image)
116.
117. break
118.
119. cap.release()
120.
121. cv2.waitKey(0)
122.
123. cv2.destroyAllWindows()
124.
Part 3. Coding iris detection
def detect_iris(image, right_box, left_box):
2.
3.
4.
5. left_roi = image[left_box[1]:left_box[1] + left_box[3], left_box[0]:left_box[0] + left_box[2]]
6.
7. cv2.imshow('left_eye', left_roi)
8.
9. lh, lw, lc = left_roi.shape
10.
11. right_roi = image[right_box[1]:right_box[1]+right_box[3],right_box[0]:right_box[0]+right_box[2]]
12.
13. cv2.imshow('right_eye', right_roi)
14.
15. rh, rw, rc = right_roi.shape
16.
17. if rh>0 and lh>0:
18.
19. rows, cols, _ =right_roi.shape # Save video size for backup
20.
21. gray_roi = cv2.cvtColor(right_roi, cv2.COLOR_BGR2GRAY) # convert greyscale
22.
23. gray_roi = cv2.GaussianBlur(gray_roi, (7, 7), 0) # Gaussian filter once
24.
25. _, threshold = cv2.threshold(gray_roi, 30, 255, cv2.THRESH_BINARY_INV) #Binarization, adjust threshold as per need
26.
27. contours, _ = cv2.findContours(threshold, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # Draw detection area
28.
29. contours = sorted(contours, key=lambda x: cv2.contourArea(x), reverse=True)
30.
31.
32.
33. for cnt in contours:
34.
35. (x, y, w, h) = cv2.boundingRect(cnt)
36.
37. cv2.circle(right_roi, (x + int(w/2), y + int(h/2)), int(h/2), (0, 0, 255), 3)
38.
39. break
40.
41.
42.
43. rows, cols, _ =left_roi.shape # Save video size for backup
44.
45. gray_roi = cv2.cvtColor(left_roi, cv2.COLOR_BGR2GRAY) # convert greyscale
46.
47. gray_roi = cv2.GaussianBlur(gray_roi, (7, 7), 0) # Gaussian filter once
48.
49. _, threshold = cv2.threshold(gray_roi, 30, 255, cv2.THRESH_BINARY_INV) # Binarization, adjust threshold as per need
50.
51.
52. contours, _ = cv2.findContours(threshold, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # Draw detection area
53.
54. contours = sorted(contours, key=lambda x: cv2.contourArea(x), reverse=True)
55.
56.
57.
58. for cnt in contours:
59.
60. (x, y, w, h) = cv2.boundingRect(cnt)
61.
62. cv2.circle(left_roi, (x + int(w/2), y + int(h/2)), int(h/2), (0, 0, 255), 3)
63.
64. break
65.
Connect all parts together and test the program.
The article was first published in dfrobot.com.cn, 2022/05/02
URL: https://mc.dfrobot.com.cn/thread-313093-1-1.html
Author:云天