File size: 3,585 Bytes
ac7cda5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import numpy as np
from dataclasses import dataclass


@dataclass
class EyeIdxMP:
    LO = [33]
    LI = [133]
    LD = [7, 163, 144, 145, 153, 154, 155]  # O -> I
    LU = [246, 161, 160, 159, 158, 157, 173]  # O -> I
    RO = [263]
    RI = [362]
    RD = [249, 390, 373, 374, 380, 381, 382]  # O -> I
    RU = [466, 388, 387, 386, 385, 384, 398]  # O -> I

    LW = [33, 133]    # oi
    LH0 = [145, 159]
    LH1 = [144, 160]
    LH2 = [153, 158]

    RW = [263, 362]   # oi
    RH0 = [374, 386]
    RH1 = [373, 387]
    RH2 = [380, 385]

    LB = [468]  # eye ball
    RB = [473]


class EyeAttrUtilsByMP:
    def __init__(self, lmks_mp):
        self.IDX = EyeIdxMP()
        self.lmks = lmks_mp    # [n, 478, 3]

        self.L_width = self._dist_idx(*self.IDX.LW)   # [n]
        self.R_width = self._dist_idx(*self.IDX.RW)

        self.L_h0 = self._dist_idx(*self.IDX.LH0)
        self.L_h1 = self._dist_idx(*self.IDX.LH1)
        self.L_h2 = self._dist_idx(*self.IDX.LH2)

        self.R_h0 = self._dist_idx(*self.IDX.RH0)
        self.R_h1 = self._dist_idx(*self.IDX.RH1)
        self.R_h2 = self._dist_idx(*self.IDX.RH2)

        self.L_open =  (self.L_h0 + self.L_h1 + self.L_h2) / (self.L_width + 1e-8)   # [n]
        self.R_open =  (self.R_h0 + self.R_h1 + self.R_h2) / (self.R_width + 1e-8)

        self.L_center = self._center_idx(*self.IDX.LW)    # [n, 3/2]
        self.R_center = self._center_idx(*self.IDX.RW)

        self.L_ball = self.lmks[:, self.IDX.LB[0]]   # [n, 3/2]
        self.R_ball = self.lmks[:, self.IDX.RB[0]]

        self.L_ball_direc = (self.L_ball - self.L_center) / (self.L_width[:, None] + 1e-8)   # [n, 3/2]
        self.R_ball_direc = (self.R_ball - self.R_center) / (self.R_width[:, None] + 1e-8)

        self.L_eye_direc = self._direc_idx(*self.IDX.LW)  # I->O
        self.R_eye_direc = self._direc_idx(*self.IDX.RW)

        self.L_ball_move_dist = self._dist(self.L_ball, self.L_center)
        self.R_ball_move_dist = self._dist(self.R_ball, self.R_center)

        self.L_ball_move_direc = self._direc(self.L_ball, self.L_center) - self.L_eye_direc
        self.R_ball_move_direc = self._direc(self.R_ball, self.R_center) - self.R_eye_direc

        self.L_ball_move = self.L_ball_move_direc * self.L_ball_move_dist[:, None]
        self.R_ball_move = self.R_ball_move_direc * self.R_ball_move_dist[:, None]

    def LR_open(self):
        LR_open = np.stack([self.L_open, self.R_open], -1)    # [n, 2]
        return LR_open
    
    def LR_ball_direc(self):
        LR_ball_direc = np.stack([self.L_ball_direc, self.R_ball_direc], -1)    # [n, 3, 2]
        return LR_ball_direc
    
    def LR_ball_move(self):
        LR_ball_move = np.stack([self.L_ball_move, self.R_ball_move], -1)
        return LR_ball_move

    @staticmethod
    def _dist(p1, p2):
        # p1/p2: [n, 3/2]
        return (((p1 - p2) ** 2).sum(-1)) ** 0.5    # [n]
    
    @staticmethod
    def _center(p1, p2):
        return (p1 + p2) * 0.5   # [n, 3/2]
    
    def _direc(self, p1, p2):
        # p1 - p2, (2->1)
        return (p1 - p2) / (self._dist(p1, p2)[:, None] + 1e-8)
    
    def _dist_idx(self, idx1, idx2):
        p1 = self.lmks[:, idx1]
        p2 = self.lmks[:, idx2]
        d = self._dist(p1, p2)
        return d
    
    def _center_idx(self, idx1, idx2):
        p1 = self.lmks[:, idx1]
        p2 = self.lmks[:, idx2]
        c = self._center(p1, p2)
        return c
    
    def _direc_idx(self, idx1, idx2):
        p1 = self.lmks[:, idx1]
        p2 = self.lmks[:, idx2]
        dir = self._direc(p1, p2)
        return dir