-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy patheye.py
81 lines (62 loc) · 2.65 KB
/
eye.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import math
import numpy as np
import cv2
from pupil import Pupil
class Eye(object):
LEFT_EYE_POINTS = [36, 37, 38, 39, 40, 41]
RIGHT_EYE_POINTS = [42, 43, 44, 45, 46, 47]
def __init__(self, original_frame, landmarks, side, calibration):
self.frame = None
self.origin = None
self.center = None
self.pupil = None
self._analyze(original_frame, landmarks, side, calibration)
@staticmethod
def _middle_point(p1, p2):
x = int((p1.x + p2.x) / 2)
y = int((p1.y + p2.y) / 2)
return (x, y)
def _isolate(self, frame, landmarks, points):
region = np.array([(landmarks.part(point).x, landmarks.part(point).y) for point in points])
region = region.astype(np.int32)
# Applying a mask to get only the eye
height, width = frame.shape[:2]
black_frame = np.zeros((height, width), np.uint8)
mask = np.full((height, width), 255, np.uint8)
cv2.fillPoly(mask, [region], (0, 0, 0))
eye = cv2.bitwise_not(black_frame, frame.copy(), mask=mask)
# Cropping on the eye
margin = 5
min_x = np.min(region[:, 0]) - margin
max_x = np.max(region[:, 0]) + margin
min_y = np.min(region[:, 1]) - margin
max_y = np.max(region[:, 1]) + margin
self.frame = eye[min_y:max_y, min_x:max_x]
self.origin = (min_x, min_y)
height, width = self.frame.shape[:2]
self.center = (width / 2, height / 2)
def _blinking_ratio(self, landmarks, points):
left = (landmarks.part(points[0]).x, landmarks.part(points[0]).y)
right = (landmarks.part(points[3]).x, landmarks.part(points[3]).y)
top = self._middle_point(landmarks.part(points[1]), landmarks.part(points[2]))
bottom = self._middle_point(landmarks.part(points[5]), landmarks.part(points[4]))
eye_width = math.hypot((left[0] - right[0]), (left[1] - right[1]))
eye_height = math.hypot((top[0] - bottom[0]), (top[1] - bottom[1]))
try:
ratio = eye_width / eye_height
except ZeroDivisionError:
ratio = None
return ratio
def _analyze(self, original_frame, landmarks, side, calibration):
if side == 0:
points = self.LEFT_EYE_POINTS
elif side == 1:
points = self.RIGHT_EYE_POINTS
else:
return
self.blinking = self._blinking_ratio(landmarks, points)
self._isolate(original_frame, landmarks, points)
if not calibration.is_complete():
calibration.evaluate(self.frame, side)
threshold = calibration.threshold(side)
self.pupil = Pupil(self.frame, threshold)