1+ #ifndef INSPIRSE_FACE_FACE_ACTION_H
2+ #define INSPIRSE_FACE_FACE_ACTION_H
3+
4+ #include < iostream>
5+ #include " opencv2/opencv.hpp"
6+ #include " middleware/utils.h"
7+ #include " data_type.h"
8+ #include " track_module/landmark/face_landmark.h"
9+
10+ namespace inspire {
11+
12+ enum FACE_ACTION {
13+ NORMAL = 0 ,
14+ SHAKE = 0 ,
15+ BROW_UP = 1 ,
16+ BLINK = 2 ,
17+ JAW_OPEN = 3 ,
18+ HEAD_RISE = 4
19+ };
20+
21+ class INSPIRE_API FaceActionAnalyse {
22+ public:
23+ FaceActionAnalyse (int record_list_length) {
24+ record_list.resize (record_list_length);
25+ record_list_euler.resize (record_list_length);
26+ record_list_eyes.resize (record_list_length);
27+ record_size = record_list_length;
28+ index = 0 ;
29+ }
30+
31+ void RecordActionFrame (const std::vector<cv::Point2f> &landmark,
32+ const cv::Vec3f &euler_angle,
33+ const cv::Vec2f &eyes_status) {
34+ MoveRecordList ();
35+ record_list[0 ] = landmark;
36+ record_list_euler[0 ] = euler_angle;
37+ record_list_eyes[0 ] = eyes_status;
38+ index += 1 ;
39+ }
40+
41+ void Reset () {
42+ record_list.clear ();
43+ record_list.resize (record_size);
44+ record_list_euler.clear ();
45+ record_list_euler.resize (record_size);
46+ record_list_eyes.clear ();
47+ record_list_eyes.resize (record_size);
48+ index = 0 ;
49+ }
50+
51+ void AnalysisFaceAction () {
52+ actions.clear ();
53+ eye_state_list.clear ();
54+ if (index < record_list.size ()) {
55+ actions.push_back (NORMAL);
56+ } else {
57+ for (int i = 0 ; i < record_list_eyes.size (); i++) {
58+ const auto &eye = record_list_eyes[i];
59+ std::pair<float , float > eye_state (eye[0 ], eye[1 ]);
60+ eye_state_list.push_back (eye_state);
61+ }
62+
63+ // count mouth aspect ratio
64+ float mouth_widthwise_d =
65+ PointDistance (record_list[0 ][FaceLandmark::MOUTH_LEFT_CORNER],
66+ record_list[0 ][FaceLandmark::MOUTH_RIGHT_CORNER]);
67+ float mouth_heightwise_d =
68+ PointDistance (record_list[0 ][FaceLandmark::MOUTH_UPPER],
69+ record_list[0 ][FaceLandmark::MOUTH_LOWER]);
70+ float mouth_aspect_ratio = mouth_heightwise_d / mouth_widthwise_d;
71+ if (mouth_aspect_ratio > 0.3 ) {
72+ actions.push_back (JAW_OPEN);
73+ }
74+
75+ int counter_eye_open = 0 ;
76+ int counter_eye_close = 0 ;
77+ for (auto &e : eye_state_list) {
78+ if (e.first < 0.5 || e.second < 0.5 ) {
79+ counter_eye_close += 1 ;
80+ }
81+ if (e.first > 0.5 || e.second > 0.5 ) {
82+ counter_eye_open += 1 ;
83+ }
84+ }
85+ if (counter_eye_close > 0 && counter_eye_open > 2 &&
86+ record_list_euler[0 ][1 ] > -6 && record_list_euler[0 ][0 ] < 6 ) {
87+ actions.push_back (BLINK);
88+ Reset ();
89+ }
90+
91+ bool counter_head_shake_left = false ;
92+ bool counter_head_shake_right = false ;
93+ for (auto &e : record_list_euler) {
94+ if (e[1 ] < -6 ) {
95+ counter_head_shake_left = true ;
96+ }
97+ if (e[1 ] > 6 ) {
98+ counter_head_shake_right = true ;
99+ }
100+ }
101+ if (counter_head_shake_left && counter_head_shake_right) {
102+ actions.push_back (SHAKE);
103+ }
104+
105+ if (record_list_euler[0 ][0 ] < -10 ) {
106+ actions.push_back (HEAD_RISE);
107+ }
108+
109+ }
110+ }
111+
112+ private:
113+ void MoveRecordList () {
114+ // for(int i = 0 ; i < record_list.size() - 1 ; i++){
115+ // record_list[i+1] = record_list[i];
116+ // record_list_euler[i+1] = record_list_euler[i];
117+ // }
118+ for (int i = record_list.size () - 1 ; i > 0 ; i--) {
119+ record_list[i] = record_list[i - 1 ];
120+ record_list_euler[i] = record_list_euler[i - 1 ];
121+ record_list_eyes[i] = record_list_eyes[i - 1 ];
122+ }
123+ }
124+
125+
126+ std::vector<std::vector<cv::Point2f>> record_list;
127+ std::vector<cv::Vec3f> record_list_euler;
128+ std::vector<cv::Vec2f> record_list_eyes;
129+ std::vector<std::pair<float , float >> eye_state_list; // pair left right
130+ std::vector<float > mouth_state_list;
131+ std::vector<FACE_ACTION> actions;
132+ int record_size;
133+ int index;
134+ };
135+
136+ } // namespace inspire
137+
138+ #endif
0 commit comments