Skip to content

Commit 4818ecd

Browse files
committed
Add face actions
Former-commit-id: de2ea53
1 parent fe31584 commit 4818ecd

File tree

16 files changed

+284
-97
lines changed

16 files changed

+284
-97
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
99
# Current version
1010
set(INSPIRE_FACE_VERSION_MAJOR 1)
1111
set(INSPIRE_FACE_VERSION_MINOR 1)
12-
set(INSPIRE_FACE_VERSION_PATCH 4)
12+
set(INSPIRE_FACE_VERSION_PATCH 5)
1313

1414
# Converts the version number to a string
1515
string(CONCAT INSPIRE_FACE_VERSION_MAJOR_STR ${INSPIRE_FACE_VERSION_MAJOR})

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ Please contact [contact@insightface.ai](mailto:contact@insightface.ai?subject=In
1313

1414
## Change Logs
1515

16+
**`2024-07-07`** Add some face action detection to the face interaction module.
17+
1618
**`2024-07-05`** Fixed some bugs in the python ctypes interface.
1719

1820
**`2024-07-03`** Add the blink detection algorithm of face interaction module.

cpp/inspireface/c_api/inspireface.cc

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -500,9 +500,14 @@ HResult HFMultipleFacePipelineProcess(HFSession session, HFImageStream streamHan
500500
if (stream == nullptr) {
501501
return HERR_INVALID_IMAGE_STREAM_HANDLE;
502502
}
503-
if (faces->detectedNum <= 0 || faces->tokens->data == nullptr) {
503+
if (faces->tokens->data == nullptr) {
504504
return HERR_INVALID_FACE_LIST;
505505
}
506+
507+
if (faces->detectedNum == 0) {
508+
return HSUCCEED;
509+
}
510+
506511
inspire::ContextCustomParameter param;
507512
param.enable_mask_detect = parameter.enable_mask_detect;
508513
param.enable_face_attribute = parameter.enable_face_quality;
@@ -545,9 +550,12 @@ HResult HFMultipleFacePipelineProcessOptional(HFSession session, HFImageStream s
545550
if (stream == nullptr) {
546551
return HERR_INVALID_IMAGE_STREAM_HANDLE;
547552
}
548-
if (faces->detectedNum <= 0 || faces->tokens->data == nullptr) {
553+
if (faces->tokens->data == nullptr) {
549554
return HERR_INVALID_FACE_LIST;
550555
}
556+
if (faces->detectedNum == 0) {
557+
return HSUCCEED;
558+
}
551559

552560
inspire::ContextCustomParameter param;
553561
if (customOption & HF_ENABLE_FACE_RECOGNITION) {
@@ -572,7 +580,6 @@ HResult HFMultipleFacePipelineProcessOptional(HFSession session, HFImageStream s
572580
param.enable_interaction_liveness = true;
573581
}
574582

575-
576583
HResult ret;
577584
std::vector<inspire::HyperFaceData> data;
578585
data.resize(faces->detectedNum);
@@ -654,8 +661,8 @@ HResult HFFaceQualityDetect(HFSession session, HFFaceBasicToken singleFace, HFlo
654661

655662
}
656663

657-
HResult HFGetFaceIntereactionResult(HFSession session, PHFFaceIntereactionResult result) {
658-
if (session == nullptr) {
664+
HResult HFGetFaceIntereactionStateResult(HFSession session, PHFFaceIntereactionState result) {
665+
if (session == nullptr) {
659666
return HERR_INVALID_CONTEXT_HANDLE;
660667
}
661668
HF_FaceAlgorithmSession *ctx = (HF_FaceAlgorithmSession* ) session;
@@ -669,6 +676,24 @@ HResult HFGetFaceIntereactionResult(HFSession session, PHFFaceIntereactionResult
669676
return HSUCCEED;
670677
}
671678

679+
HResult HFGetFaceIntereactionActionsResult(HFSession session, PHFFaceIntereactionsActions actions) {
680+
if (session == nullptr) {
681+
return HERR_INVALID_CONTEXT_HANDLE;
682+
}
683+
HF_FaceAlgorithmSession *ctx = (HF_FaceAlgorithmSession* ) session;
684+
if (ctx == nullptr) {
685+
return HERR_INVALID_CONTEXT_HANDLE;
686+
}
687+
actions->num = ctx->impl.GetFaceNormalAactionsResultCache().size();
688+
actions->normal = (HInt32* )ctx->impl.GetFaceNormalAactionsResultCache().data();
689+
actions->blink = (HInt32* )ctx->impl.GetFaceBlinkAactionsResultCache().data();
690+
actions->shake = (HInt32* )ctx->impl.GetFaceShakeAactionsResultCache().data();
691+
actions->headRiase = (HInt32* )ctx->impl.GetFaceRaiseHeadAactionsResultCache().data();
692+
actions->jawOpen = (HInt32* )ctx->impl.GetFaceJawOpenAactionsResultCache().data();
693+
694+
return HSUCCEED;
695+
}
696+
672697
HResult HFGetFaceAttributeResult(HFSession session, PHFFaceAttributeResult results) {
673698
if (session == nullptr) {
674699
return HERR_INVALID_CONTEXT_HANDLE;

cpp/inspireface/c_api/inspireface.h

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -638,19 +638,38 @@ HYPER_CAPI_EXPORT extern HResult HFFaceQualityDetect(HFSession session, HFFaceBa
638638
/**
639639
* @brief Facial states in the face interaction module.
640640
*/
641-
typedef struct HFFaceIntereactionResult {
641+
typedef struct HFFaceIntereactionState {
642642
HInt32 num; ///< Number of faces detected.
643643
HPFloat leftEyeStatusConfidence; ///< Left eye state: confidence close to 1 means open, close to 0 means closed.
644644
HPFloat rightEyeStatusConfidence; ///< Right eye state: confidence close to 1 means open, close to 0 means closed.
645-
} HFFaceIntereactionResult, *PHFFaceIntereactionResult;
645+
} HFFaceIntereactionState, *PHFFaceIntereactionState;
646646

647647
/**
648648
* @brief Get the prediction results of face interaction.
649649
* @param session Handle to the session.
650650
* @param result Facial state prediction results in the face interaction module.
651651
*/
652-
HYPER_CAPI_EXPORT extern HResult HFGetFaceIntereactionResult(HFSession session, PHFFaceIntereactionResult result);
652+
HYPER_CAPI_EXPORT extern HResult HFGetFaceIntereactionStateResult(HFSession session, PHFFaceIntereactionState result);
653653

654+
/**
655+
* @brief Actions detected in the face interaction module.
656+
*/
657+
typedef struct HFFaceIntereactionsActions {
658+
HInt32 num; ///< Number of actions detected.
659+
HPInt32 normal; ///< Normal actions.
660+
HPInt32 shake; ///< Shake actions.
661+
HPInt32 jawOpen; ///< Jaw open actions.
662+
HPInt32 headRiase; ///< Head raise actions.
663+
HPInt32 blink; ///< Blink actions.
664+
} HFFaceIntereactionsActions, *PHFFaceIntereactionsActions;
665+
666+
/**
667+
* @brief Get the prediction results of face interaction actions.
668+
* @param session Handle to the session.
669+
* @param actions Facial action prediction results in the face interaction module.
670+
* @return HResult indicating success or failure of the function call.
671+
*/
672+
HYPER_CAPI_EXPORT extern HResult HFGetFaceIntereactionActionsResult(HFSession session, PHFFaceIntereactionsActions actions);
654673
/**
655674
* @brief Struct representing face attribute results.
656675
*

cpp/inspireface/common/face_info/face_action.h

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,19 @@ namespace inspire {
1212
enum FACE_ACTION {
1313
NORMAL = 0,
1414
SHAKE = 0,
15-
BROW_UP = 1,
16-
BLINK = 2,
17-
JAW_OPEN = 3,
18-
HEAD_RISE = 4
15+
BLINK = 1,
16+
JAW_OPEN = 2,
17+
RAISE_HEAD = 3
1918
};
2019

20+
typedef struct FaceActions{
21+
int normal = 0;
22+
int shake = 0;
23+
int blink = 0;
24+
int jawOpen = 0;
25+
int raiseHead = 0;
26+
} FaceActions;
27+
2128
class INSPIRE_API FaceActionAnalyse {
2229
public:
2330
FaceActionAnalyse(int record_list_length) {
@@ -48,11 +55,13 @@ class INSPIRE_API FaceActionAnalyse {
4855
index = 0;
4956
}
5057

51-
void AnalysisFaceAction() {
58+
FaceActions AnalysisFaceAction() {
59+
FaceActions actionRecord;
5260
actions.clear();
5361
eye_state_list.clear();
5462
if (index < record_list.size()) {
5563
actions.push_back(NORMAL);
64+
actionRecord.normal = 1;
5665
} else {
5766
for (int i = 0; i < record_list_eyes.size(); i++) {
5867
const auto &eye = record_list_eyes[i];
@@ -70,6 +79,7 @@ class INSPIRE_API FaceActionAnalyse {
7079
float mouth_aspect_ratio = mouth_heightwise_d / mouth_widthwise_d;
7180
if (mouth_aspect_ratio > 0.3) {
7281
actions.push_back(JAW_OPEN);
82+
actionRecord.jawOpen = 1;
7383
}
7484

7585
int counter_eye_open = 0;
@@ -85,6 +95,7 @@ class INSPIRE_API FaceActionAnalyse {
8595
if (counter_eye_close > 0 && counter_eye_open > 2 &&
8696
record_list_euler[0][1] > -6 && record_list_euler[0][0] < 6) {
8797
actions.push_back(BLINK);
98+
actionRecord.blink = 1;
8899
Reset();
89100
}
90101

@@ -100,13 +111,20 @@ class INSPIRE_API FaceActionAnalyse {
100111
}
101112
if (counter_head_shake_left && counter_head_shake_right) {
102113
actions.push_back(SHAKE);
114+
actionRecord.shake = 1;
103115
}
104116

105-
if (record_list_euler[0][0] < -10) {
106-
actions.push_back(HEAD_RISE);
117+
if (record_list_euler[0][0] > 10) {
118+
actions.push_back(RAISE_HEAD);
119+
actionRecord.raiseHead = 1;
107120
}
108121

109122
}
123+
return actionRecord;
124+
}
125+
126+
std::vector<FACE_ACTION> GetActions() const {
127+
return actions;
110128
}
111129

112130
private:

cpp/inspireface/common/face_info/face_object.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,11 @@ class INSPIRE_API FaceObject {
138138
return box_square;
139139
}
140140

141-
void UpdateFaceAction() {
141+
FaceActions UpdateFaceAction() {
142142
cv::Vec3f euler(high_result.pitch, high_result.yaw, high_result.roll);
143143
cv::Vec2f eyes(left_eye_status_.back(), right_eye_status_.back());
144144
face_action_->RecordActionFrame(landmark_, euler, eyes);
145-
face_action_->AnalysisFaceAction();
145+
return face_action_->AnalysisFaceAction();
146146
}
147147

148148
void DisableTracking() { tracking_state_ = UNTRACKING; }

cpp/inspireface/face_context.cpp

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,13 @@ int32_t FaceContext::FaceDetectAndTrack(CameraStream &image) {
6363
m_quality_score_results_cache_.clear();
6464
m_react_left_eye_results_cache_.clear();
6565
m_react_right_eye_results_cache_.clear();
66+
67+
m_action_normal_results_cache_.clear();
68+
m_action_shake_results_cache_.clear();
69+
m_action_blink_results_cache_.clear();
70+
m_action_jaw_open_results_cache_.clear();
71+
m_action_raise_head_results_cache_.clear();
72+
6673
m_quality_score_results_cache_.clear();
6774
m_attribute_race_results_cache_.clear();
6875
m_attribute_gender_results_cache_.clear();
@@ -138,6 +145,11 @@ int32_t FaceContext::FacesProcess(CameraStream &image, const std::vector<HyperFa
138145
m_attribute_race_results_cache_.resize(faces.size(), -1);
139146
m_attribute_gender_results_cache_.resize(faces.size(), -1);
140147
m_attribute_age_results_cache_.resize(faces.size(), -1);
148+
m_action_normal_results_cache_.resize(faces.size(), -1);
149+
m_action_jaw_open_results_cache_.resize(faces.size(), -1);
150+
m_action_blink_results_cache_.resize(faces.size(), -1);
151+
m_action_raise_head_results_cache_.resize(faces.size(), -1);
152+
m_action_shake_results_cache_.resize(faces.size(), -1);
141153
for (int i = 0; i < faces.size(); ++i) {
142154
const auto &face = faces[i];
143155
// RGB Liveness Detect
@@ -190,8 +202,12 @@ int32_t FaceContext::FacesProcess(CameraStream &image, const std::vector<HyperFa
190202
m_react_left_eye_results_cache_[i] = new_eye_left;
191203
m_react_right_eye_results_cache_[i] = new_eye_right;
192204
}
193-
target.UpdateFaceAction();
194-
205+
const auto actions = target.UpdateFaceAction();
206+
m_action_normal_results_cache_[i] = actions.normal;
207+
m_action_jaw_open_results_cache_[i] = actions.jawOpen;
208+
m_action_blink_results_cache_[i] = actions.blink;
209+
m_action_raise_head_results_cache_[i] = actions.raiseHead;
210+
m_action_shake_results_cache_[i] = actions.shake;
195211
} else {
196212
INSPIRE_LOGD("Serialized objects cannot connect to trace objects in memory, and there may be some problems");
197213
}
@@ -275,6 +291,26 @@ const std::vector<int>& FaceContext::GetFaceAgeBracketResultsCache() const {
275291
return m_attribute_age_results_cache_;
276292
}
277293

294+
const std::vector<int>& FaceContext::GetFaceNormalAactionsResultCache() const {
295+
return m_action_normal_results_cache_;
296+
}
297+
298+
const std::vector<int>& FaceContext::GetFaceJawOpenAactionsResultCache() const {
299+
return m_action_jaw_open_results_cache_;
300+
}
301+
302+
const std::vector<int>& FaceContext::GetFaceBlinkAactionsResultCache() const {
303+
return m_action_blink_results_cache_;
304+
}
305+
306+
const std::vector<int>& FaceContext::GetFaceShakeAactionsResultCache() const {
307+
return m_action_shake_results_cache_;
308+
}
309+
310+
const std::vector<int>& FaceContext::GetFaceRaiseHeadAactionsResultCache() const {
311+
return m_action_raise_head_results_cache_;
312+
}
313+
278314
int32_t FaceContext::FaceFeatureExtract(CameraStream &image, FaceBasicData& data) {
279315
std::lock_guard<std::mutex> lock(m_mtx_);
280316
int32_t ret;

cpp/inspireface/face_context.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Created by Tunm-Air13 on 2023/9/7.
33
//
44
#pragma once
5+
#include <vector>
56
#ifndef HYPERFACEREPO_FACE_CONTEXT_H
67
#define HYPERFACEREPO_FACE_CONTEXT_H
78

@@ -261,6 +262,36 @@ class INSPIRE_API FaceContext {
261262
*/
262263
const std::vector<int>& GetFaceAgeBracketResultsCache() const;
263264

265+
/**
266+
* @brief Gets the cache of face action normal results.
267+
* @return A const reference to a vector containing face action normal results.
268+
*/
269+
const std::vector<int>& GetFaceNormalAactionsResultCache() const;
270+
271+
/**
272+
* @brief Gets the cache of face action jaw open results.
273+
* @return A const reference to a vector containing face action jaw open results.
274+
*/
275+
const std::vector<int>& GetFaceJawOpenAactionsResultCache() const;
276+
277+
/**
278+
* @brief Gets the cache of face action blink results.
279+
* @return A const reference to a vector containing face action blink results.
280+
*/
281+
const std::vector<int>& GetFaceBlinkAactionsResultCache() const;
282+
283+
/**
284+
* @brief Gets the cache of face action shake results.
285+
* @return A const reference to a vector containing face action shake results.
286+
*/
287+
const std::vector<int>& GetFaceShakeAactionsResultCache() const;
288+
289+
/**
290+
* @brief Gets the cache of face action raise head results.
291+
* @return A const reference to a vector containing face action raise head results.
292+
*/
293+
const std::vector<int>& GetFaceRaiseHeadAactionsResultCache() const;
294+
264295
/**
265296
* @brief Gets the cache of the current face features.
266297
* @return A const reference to the Embedded object containing current face feature data.
@@ -294,6 +325,13 @@ class INSPIRE_API FaceContext {
294325
std::vector<float> m_quality_score_results_cache_; ///< Cache for RGB face quality score results
295326
std::vector<float> m_react_left_eye_results_cache_; ///< Cache for Left eye state in face interaction
296327
std::vector<float> m_react_right_eye_results_cache_; ///< Cache for Right eye state in face interaction
328+
329+
std::vector<int> m_action_normal_results_cache_; ///< Cache for normal action in face interaction
330+
std::vector<int> m_action_shake_results_cache_; ///< Cache for shake action in face interaction
331+
std::vector<int> m_action_blink_results_cache_; ///< Cache for blink action in face interaction
332+
std::vector<int> m_action_jaw_open_results_cache_; ///< Cache for jaw open action in face interaction
333+
std::vector<int> m_action_raise_head_results_cache_; ///< Cache for raise head action in face interaction
334+
297335
std::vector<int> m_attribute_race_results_cache_;
298336
std::vector<int> m_attribute_gender_results_cache_;
299337
std::vector<int> m_attribute_age_results_cache_;

cpp/inspireface/information.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77

88
#define INSPIRE_FACE_VERSION_MAJOR_STR "1"
99
#define INSPIRE_FACE_VERSION_MINOR_STR "1"
10-
#define INSPIRE_FACE_VERSION_PATCH_STR "4"
10+
#define INSPIRE_FACE_VERSION_PATCH_STR "5"
1111

1212
#endif //HYPERFACEREPO_INFORMATION_H

cpp/inspireface/track_module/face_track.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,15 +307,25 @@ void FaceTrack::nms(float th) {
307307
float inter = w * h;
308308
float ovr = inter / (area[i] + area[j] - inter);
309309
if (ovr >= th) {
310-
trackingFace.erase(trackingFace.begin() + j);
311-
area.erase(area.begin() + j);
310+
// Compare tracking IDs to decide which to keep
311+
if (trackingFace[i].GetTrackingId() < trackingFace[j].GetTrackingId()) {
312+
trackingFace.erase(trackingFace.begin() + j);
313+
area.erase(area.begin() + j);
314+
} else {
315+
trackingFace.erase(trackingFace.begin() + i);
316+
area.erase(area.begin() + i);
317+
// If we erase i, we need to break the inner loop
318+
// and start over with a new i, because the indexes shifted.
319+
break;
320+
}
312321
} else {
313322
j++;
314323
}
315324
}
316325
}
317326
}
318327

328+
319329
void FaceTrack::BlackingTrackingRegion(cv::Mat &image, cv::Rect &rect_mask) {
320330
int height = image.rows;
321331
int width = image.cols;

0 commit comments

Comments
 (0)