版本:3.0.3902010101.5
参考:ARCSOFT_ARC_FACE_DEVELOPER'S_GUIDE.pdf
更为详尽的示例。
使用同一个引擎句柄不支持多线程调用同一个算法接口,需对同一个接口进行多线程调用需要启动多个引擎。
ASFGetVersion
获取SDK版本信息。无需激活或初始化即可调用。
const ASF_VERSION ASFGetVersion();
示例:
#include <iostream>
#include "arcsoft_face_sdk.h"
#include "merror.h"
#pragma comment(lib, "libarcsoft_face_engine.lib")
using namespace std;
int main() {
ASF_VERSION version = ASFGetVersion();
cout << version.Version << endl;
cout << version.BuildDate << endl;
cout << version.CopyRight << endl;
return 0;
}
ASFGetActiveFileInfo
获取激活文件信息接口
MRESULT ASFGetActiveFileInfo(
LPASF_ActiveFileInfo activeFileInfo // [out] 激活文件信息
);
示例:
#include <iostream>
#include "arcsoft_face_sdk.h"
#include "merror.h"
#pragma comment(lib, "libarcsoft_face_engine.lib")
using namespace std;
int main() {
ASF_ActiveFileInfo info;
MRESULT res = ASFGetActiveFileInfo(&info);
if (res != MOK) {
cout << "ASFGetActiveFileInfo fail: " << res << endl;
}
else {
cout << "ASFGetActiveFileInfo success: " << info.appId << endl;
}
return 0;
}
ASFOnlineActivation
用于在线激活SDK。
初次使用SDK需要联网激活,激活成功后无需重复调用,可离线使用。
MRESULT ASFOnlineActivation(
MPChar AppId, // [in] APPID 官网下载
MPChar SDKKey // [in] SDKKEY 官网下载
);
示例
#include <iostream>
#include "arcsoft_face_sdk.h"
#include "merror.h"
#pragma comment(lib, "libarcsoft_face_engine.lib")
using namespace std;
#define APPID "your_appid"
#define SDKKEY "your_sdkkey"
int main() {
MRESULT res = ASFOnlineActivation(APPID, SDKKEY);
if (res != MOK && res != MERR_ASF_ALREADY_ACTIVATED) {
cout << "ASFOnlineActivation fail: " << res << endl;
}
else {
cout << "ASFOnlineActivation success: " << res << endl;
}
return 0;
}
注意: 实际使用需要更改ASFOnlineActivation
数据结构:
MRESULT ASFOnlineActivation(
MPCChar AppId, // [in] APPID 官网下载
MPCChar SDKKey // [in] SDKKEY 官网下载
);
ASFActivation
用于在线激活SDK。
与ASFOnlineActivation
功能一致。
MRESULT ASFActivation(
MPChar AppId, // [in] APPID 官网下载
MPChar SDKKey // [in] SDKKEY 官网下载
);
示例:
#include <iostream>
#include "arcsoft_face_sdk.h"
#include "merror.h"
#pragma comment(lib, "libarcsoft_face_engine.lib")
using namespace std;
#define APPID "your_appid"
#define SDKKEY "your_sdkkey"
int main() {
MRESULT res = ASFActivation(APPID, SDKKEY);
if (res != MOK && res != MERR_ASF_ALREADY_ACTIVATED) {
cout << "ASFActivation fail: " << res << endl;
}
else {
cout << "ASFActivation success: " << res << endl;
}
return 0;
}
注意: 实际使用需要更改ASFActivation
数据结构:
MRESULT ASFActivation(
MPCChar AppId, // [in] APPID 官网下载
MPCChar SDKKey // [in] SDKKEY 官网下载
);
ASFInitEngine
初始化引擎。
MRESULT ASFInitEngine(
ASF_DetectMode detectMode, // [in]
// AF_DETECT_MODE_VIDEO 视频模式:适用于摄像头预览,视频文件识别
// AF_DETECT_MODE_IMAGE 图片模式:适用于静态图片的识别
ASF_OrientPriority detectFaceOrientPriority, // [in] 检测脸部的角度优先值,参考 ArcFaceCompare_OrientPriority
MInt32 detectFaceScaleVal, // [in] 用于数值化表示的最小人脸尺寸,该尺寸代表人脸尺寸相对于图片长边的占比
// video 模式有效值范围[2, 32], 推荐值为 16
// image 模式有效值范围[2, 32], 推荐值为 32
MInt32 detectFaceMaxNum, // [in] 最大需要检测的人脸个数,取值范围[1, 50]
MInt32 combinedMask, // [in] 用户选择需要检测的功能组合,可单个或多个
MHandle* hEngine // [out] 初始化返回的引擎handle
);
VIDEO模式
- 对视频流中的人脸进行追踪,人脸框平滑过渡,不会出现跳框现象。
- 使用摄像头需要做预览显示,每一帧都需要做人脸检测,人脸检测耗时短不会出现卡顿的现象。
- 视频模式下人脸追踪和带有一个
FaceId
值,标记一张人脸从进入画面直到离开画面。FaceId
值不变,可用于业务中优化程序性能。
IMAGE模式
- 针对单张图片进行人脸检测,精度更高。
- 注册人脸库时,建议使用精度更高的IMAGE模式。
模式选择
- 摄像头中获取数据并需要预览显示,推荐选择VIDEO模式;
- 处理静态图像数据,类似注册人脸库时,推荐使用IMAGE模式;
- 同时进行IMAGE模式人脸检测和VIDEO模式人脸检测,需要创建一个VIDEO模式的引擎和一个IMAGE模式的引擎。
detectFaceOrientPriority
detectFaceScaleVal
识别的最小人脸比例 = 图片长边 / 人脸框长边比值
默认推荐值:VIDEO模式推荐16;IMAGE模式推荐32.
//如下图所示
//图片尺寸 400 x 600
//人脸尺寸 300 x 300
minScale = 600 / 300 //若为小数,向上取整(例如:2.53 取值为 3)
设置推荐:
根据使用场景适当调整。门禁场景推荐使用VIDEO
模式,detectFaceScaleVal
设置为16.
用户使用场景下的成像质量比较高,设置为32,可以在相对较远的位置检测到人脸并比对通过,效果更佳,达到无感通行。
combinedMask
针对算法功能会有常量值与之一一对应,根据业务需求进行自由选择,不需要的属性可以不用初始化,减少内存占用。
#define ASF_FACE_DETECT 0x00000001 //人脸检测
#define ASF_FACERECOGNITION 0x00000004 //人脸特征
#define ASF_AGE 0x00000008 //年龄
#define ASF_GENDER 0x00000010 //性别
#define ASF_FACE3DANGLE 0x00000020 //3D角度
#define ASF_LIVENESS 0x00000080 //RGB活体
#define ASF_IR_LIVENESS 0x00000400 //IR活体
说明:
- 人脸识别一般需要
ASF_FACE_DETECT
和ASF_FACERECOGNITION
属性。 - 需要防止纸张、屏幕等攻击可以传入
ASF_LIVENESS
和ASF_IR_LIVENESS
,RGB
和IR
活体检测根据用户的摄像头类型以及实际的业务需求来决定如何选择。 ASF_AGE
/ASF_GENDER
/ASF_FACE3DANGLE
根据业务需求进行选择即可。
这些属性均是以常量值进行定义,可通过|位运算符进行组合使用。
例如:MInt32 combinedMask = ASF_FACE_DETECT | ASF_FACERECOGNITION |ASF_LIVENESS
。
示例:
#include <iostream>
#include "arcsoft_face_sdk.h"
#include "merror.h"
#pragma comment(lib, "libarcsoft_face_engine.lib")
using namespace std;
#define APPID "your_appid"
#define SDKKEY "your_sdkkey"
int main() {
MHandle handle = nullptr;
MInt32 scale = 32;
MInt32 face_num = 1;
MInt32 mask = ASF_FACE_DETECT
| ASF_FACERECOGNITION
| ASF_AGE
| ASF_GENDER
| ASF_FACE3DANGLE
| ASF_LIVENESS;
MRESULT res = ASFInitEngine(
ASF_DETECT_MODE_IMAGE,
ASF_OP_0_ONLY,
scale,
face_num,
mask,
&handle
);
if (res != MOK) {
cout << "ASFInitEngine fail: " << res << endl;
}
else {
cout << "ASFInitEngine success: " << res << endl;
}
return 0;
}
ASFUninitEngine
销毁SDK引擎。
MRESULT ASFUninitEngine(
MHandle hEngine
);
示例:
#include <opencv2/opencv.hpp>
#include<iostream>
#include "arcsoft_face_sdk.h"
#include "merror.h"
#pragma comment(lib, "libarcsoft_face_engine.lib")
using namespace std;
int main() {
MHandle handle = nullptr;
MInt32 scale = 16;
MInt32 face_num = 1;
MInt32 mask = ASF_FACE_DETECT
| ASF_FACERECOGNITION
| ASF_AGE
| ASF_GENDER
| ASF_FACE3DANGLE
| ASF_LIVENESS
| ASF_IR_LIVENESS;
ASFInitEngine(
ASF_DETECT_MODE_IMAGE,
ASF_OP_0_ONLY,
scale,
face_num,
mask,
&handle
);
MRESULT res = ASFUninitEngine(handle);
if (res != MOK) {
cout << "ASFUninitEngine fail: " << res << endl;
}
else {
cout << "ASFUninitEngine success: " << res << endl;
}
return 0;
}
ASFDetectFaces
VIDEO模式下调用人脸追踪功能。
IMAGE模式下调用人脸检测功能。
初始化中detectFaceOrientPriority
、detectFaceScaleVal
、detectFaceMaxNum
参数的设置,对能否检测到人脸以及检测到几张人脸都有决定性作用。
图像宽度需要四字节对齐(宽度为4的倍数),否则需要裁剪。
MRESULT ASFDetectFaces(
MHandle hEngine, // [in] 引擎handle
MInt32 width, // [in] 图片宽度
MInt32 height, // [in] 图片高度
MInt32 format, // [in] 颜色空间格式
MUInt8* imgData, // [in] 图片数据
LPASF_MultiFaceInfo detectedFaces, // [out]检测到的人脸信息
ASF_DetectModel detectModel = ASF_DETECT_MODEL_RGB // [in] 预留字段,当前版本使用默认参数即可
);
示例:
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv/cv.h>
#include "arcsoft_face_sdk.h"
#include "merror.h"
#pragma comment(lib, "libarcsoft_face_engine.lib")
using namespace std;
int main() {
MHandle handle = nullptr;
MInt32 scale = 16;
MInt32 face_num = 50;
MInt32 mask = ASF_FACE_DETECT;
MRESULT res_init = ASFInitEngine(
ASF_DETECT_MODE_IMAGE,
ASF_OP_0_ONLY,
scale,
face_num,
mask,
&handle
);
if (res_init != MOK) {
cout << "ASFInitEngine fail: " << res_init << endl;
}
else {
cout << "ASFInitEngine success: " << res_init << endl;
}
cv::Mat img = cv::imread("C:\\Users\\milk\\Desktop\\many.jpg");
// 四字节对齐,原始图像裁剪
cv::Rect area(0, 0, img.cols - img.cols % 4, img.rows - img.rows % 4);
cv::Mat img_cut = img(area);
ASF_MultiFaceInfo mult_face_info;
MRESULT res_detect = ASFDetectFaces(
handle,
img_cut.cols,
img_cut.rows,
ASVL_PAF_RGB24_B8G8R8,
img_cut.data,
&mult_face_info
);
if (res_detect != MOK) {
cout << "ASFDetectFaces fail: " << res_detect << endl;
}
else {
cout << "ASFDetectFaces success: " << res_detect << endl;
cv::putText(img, "face num: " + to_string(mult_face_info.faceNum), cv::Point(30, 30), cv::FONT_ITALIC, 1, cv::Scalar(0, 0, 255), 2);
for (int i = 0; i < mult_face_info.faceNum; ++i) {
cv::rectangle(
img,
cv::Point(mult_face_info.faceRect[i].left, mult_face_info.faceRect[i].top),
cv::Point(mult_face_info.faceRect[i].right, mult_face_info.faceRect[i].bottom),
cv::Scalar(0, 0, 255),
2);
}
}
cv::imshow("img", img);
cv::waitKey(0);
return 0;
}
ASFDetectFacesEx
与ASFDetectFaces
功能一致,但采用结构体的形式传入图像数据,对更高精度的图像兼容性更好。
MRESULT ASFDetectFacesEx(
MHandle hEngine, // [in] 引擎handle
LPASF_ImageData imgData, // [in] 图片数据
LPASF_MultiFaceInfo detectedFaces, // [out] 检测到的人脸信息
ASF_DetectModel detectModel = ASF_DETECT_MODEL_RGB // [in] 预留字段,当前版本使用默认参数即可
);
示例:
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv/cv.h>
#include "arcsoft_face_sdk.h"
#include "merror.h"
#pragma comment(lib, "libarcsoft_face_engine.lib")
using namespace std;
int main() {
MHandle handle = nullptr;
MInt32 scale = 16;
MInt32 face_num = 50;
MInt32 mask = ASF_FACE_DETECT;
MRESULT res_init = ASFInitEngine(
ASF_DETECT_MODE_IMAGE,
ASF_OP_0_ONLY,
scale,
face_num,
mask,
&handle
);
if (res_init != MOK) {
cout << "ASFInitEngine fail: " << res_init << endl;
}
else {
cout << "ASFInitEngine success: " << res_init << endl;
}
cv::Mat img = cv::imread("C:\\Users\\milk\\Desktop\\many.jpg");
// 四字节对齐,原始图像裁剪
cv::Rect area(0, 0, img.cols - img.cols % 4, img.rows - img.rows % 4);
cv::Mat img_cut = img(area);
// 使用结构体形式传入,对更高精度的图像兼容性更好
ASVLOFFSCREEN asvl_img;
asvl_img.i32Width = img_cut.cols;
asvl_img.i32Height = img_cut.rows;
asvl_img.pi32Pitch[0] = img.step;
asvl_img.ppu8Plane[0] = img.data;
asvl_img.u32PixelArrayFormat = ASVL_PAF_RGB24_B8G8R8;
ASF_MultiFaceInfo mult_face_info;
MRESULT res_detect = ASFDetectFacesEx(handle, &asvl_img, &mult_face_info);
if (res_detect != MOK) {
cout << "ASFDetectFaces fail: " << res_detect << endl;
}
else {
cout << "ASFDetectFaces success: " << res_detect << endl;
cv::putText(img, "face num: " + to_string(mult_face_info.faceNum), cv::Point(30, 30), cv::FONT_ITALIC, 1, cv::Scalar(0, 0, 255), 2);
for (int i = 0; i < mult_face_info.faceNum; ++i) {
cv::rectangle(
img,
cv::Point(mult_face_info.faceRect[i].left, mult_face_info.faceRect[i].top),
cv::Point(mult_face_info.faceRect[i].right,mult_face_info.faceRect[i].bottom),
cv::Scalar(0, 0, 255),
2);
}
}
cv::imshow("img", img);
cv::waitKey(0);
return 0;
}
ASFFaceFeatureExtract
单人脸特征提取。
在进行第二次特征提取时,覆盖第一次特征提取结果。
例如:1:1的比对分别对两张图片进行特征提取,若使用同一个引擎,第一次特征提取需要拷贝保存,再进行第二次特征提取,否则在比对时输出的结果为1。
MRESULT ASFFaceFeatureExtract(
MHandle hEngine, // [in] 引擎handle
MInt32 width, // [in] 图片宽度
MInt32 height, // [in] 图片高度
MInt32 format, // [in] 颜色空间格式
MUInt8* imgData, // [in] 图片数据
LPASF_SingleFaceInfo faceInfo, // [in] 单张人脸位置和角度信息
LPASF_FaceFeature feature // [out] 人脸特征
);
示例:
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv/cv.h>
#include "arcsoft_face_sdk.h"
#include "merror.h"
#pragma comment(lib, "libarcsoft_face_engine.lib")
using namespace std;
int main() {
MHandle handle = nullptr;
MInt32 scale = 16;
MInt32 face_num = 50;
MInt32 mask = ASF_FACE_DETECT
| ASF_FACERECOGNITION;
MRESULT res_init = ASFInitEngine(
ASF_DETECT_MODE_IMAGE,
ASF_OP_0_ONLY,
scale,
face_num,
mask,
&handle
);
if (res_init != MOK) {
cout << "ASFInitEngine fail: " << res_init << endl;
}
else {
cout << "ASFInitEngine success: " << res_init << endl;
}
cv::Mat img = cv::imread("C:\\Users\\milk\\Desktop\\many.jpg");
// 四字节对齐,原始图像裁剪
cv::Rect area(0, 0, img.cols - img.cols % 4, img.rows - img.rows % 4);
cv::Mat img_cut = img(area);
// 使用结构体形式传入,对更高精度的图像兼容性更好
ASVLOFFSCREEN asvl_img;
asvl_img.i32Width = img_cut.cols;
asvl_img.i32Height = img_cut.rows;
asvl_img.pi32Pitch[0] = img.step;
asvl_img.ppu8Plane[0] = img.data;
asvl_img.u32PixelArrayFormat = ASVL_PAF_RGB24_B8G8R8;
ASF_MultiFaceInfo mult_face_info;
MRESULT res_detect = ASFDetectFacesEx(handle, &asvl_img, &mult_face_info);
if (res_detect != MOK) {
cout << "ASFDetectFaces fail: " << res_detect << endl;
}
else {
cout << "ASFDetectFaces success: " << res_detect << endl;
cv::putText(img, "face num: " + to_string(mult_face_info.faceNum), cv::Point(30, 30), cv::FONT_ITALIC, 1, cv::Scalar(0, 0, 255), 2);
for (int i = 0; i < mult_face_info.faceNum; ++i) {
cv::rectangle(
img,
cv::Point(mult_face_info.faceRect[i].left, mult_face_info.faceRect[i].top),
cv::Point(mult_face_info.faceRect[i].right, mult_face_info.faceRect[i].bottom),
cv::Scalar(0, 0, 255),
2);
ASF_FaceFeature feature;
ASF_SingleFaceInfo single_face_info;
single_face_info.faceRect = mult_face_info.faceRect[i];
single_face_info.faceOrient = mult_face_info.faceOrient[i];
MRESULT res_extract = ASFFaceFeatureExtract(handle, img.cols, img.rows, ASVL_PAF_RGB24_B8G8R8, img.data, &single_face_info, &feature);
cout << "Face: " << i << " --- ";
if (res_extract != MOK) {
cout << "ASFFaceFeatureExtract faile: " << res_extract << endl;
}
else {
cout << "ASFFaceFeatureExtract success: " << res_extract << endl;
}
}
}
cv::imshow("img", img);
cv::waitKey(0);
return 0;
}
ASFFaceFeatureExtractEx
单人脸特征提取。
与ASFFaceFeatureExtract
功能一致,但采用结构体的形式传入图像数据,对更高精度的图像兼容性更好。
在进行第二次特征提取时,会覆盖第一次特征提取的结果。
- 1:1的比对分别对两张图片进行特征提取,若使用同一个引擎,第一次特征提取需要拷贝保存,再进行第二次特征提取,否则在比对时输出的结果为1。
- 1:N搜索可以预先提取N张人脸特征存放在数据库或缓存中,进行比对识别。
MRESULT ASFFaceFeatureExtractEx(
MHandle hEngine, // [in] 引擎handle
LPASF_ImageData imgData, // [in] 图像数据
LPASF_SingleFaceInfo faceInfo, // [in] 单张人脸位置和角度信息
LPASF_FaceFeature feature // [out] 人脸特征
);
示例:
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv/cv.h>
#include "arcsoft_face_sdk.h"
#include "merror.h"
#pragma comment(lib, "libarcsoft_face_engine.lib")
using namespace std;
int main() {
MHandle handle = nullptr;
MInt32 scale = 16;
MInt32 face_num = 50;
MInt32 mask = ASF_FACE_DETECT
| ASF_FACERECOGNITION;
MRESULT res_init = ASFInitEngine(
ASF_DETECT_MODE_IMAGE,
ASF_OP_0_ONLY,
scale,
face_num,
mask,
&handle
);
if (res_init != MOK) {
cout << "ASFInitEngine fail: " << res_init << endl;
}
else {
cout << "ASFInitEngine success: " << res_init << endl;
}
cv::Mat img = cv::imread("C:\\Users\\milk\\Desktop\\many.jpg");
// 四字节对齐,原始图像裁剪
cv::Rect area(0, 0, img.cols - img.cols % 4, img.rows - img.rows % 4);
cv::Mat img_cut = img(area);
// 使用结构体形式传入,对更高精度的图像兼容性更好
ASVLOFFSCREEN asvl_img;
asvl_img.i32Width = img_cut.cols;
asvl_img.i32Height = img_cut.rows;
asvl_img.pi32Pitch[0] = img.step;
asvl_img.ppu8Plane[0] = img.data;
asvl_img.u32PixelArrayFormat = ASVL_PAF_RGB24_B8G8R8;
ASF_MultiFaceInfo mult_face_info;
MRESULT res_detect = ASFDetectFacesEx(handle, &asvl_img, &mult_face_info);
if (res_detect != MOK) {
cout << "ASFDetectFaces fail: " << res_detect << endl;
}
else {
cout << "ASFDetectFaces success: " << res_detect << endl;
cv::putText(img, "face num: " + to_string(mult_face_info.faceNum), cv::Point(30, 30), cv::FONT_ITALIC, 1, cv::Scalar(0, 0, 255), 2);
for (int i = 0; i < mult_face_info.faceNum; ++i) {
cv::rectangle(
img,
cv::Point(mult_face_info.faceRect[i].left, mult_face_info.faceRect[i].top),
cv::Point(mult_face_info.faceRect[i].right, mult_face_info.faceRect[i].bottom),
cv::Scalar(0, 0, 255),
2);
ASF_FaceFeature feature;
ASF_SingleFaceInfo single_face_info;
single_face_info.faceRect = mult_face_info.faceRect[i];
single_face_info.faceOrient = mult_face_info.faceOrient[i];
ASVLOFFSCREEN asvl_img;
asvl_img.i32Width = img_cut.cols;
asvl_img.i32Height = img_cut.rows;
asvl_img.pi32Pitch[0] = img.step;
asvl_img.ppu8Plane[0] = img.data;
asvl_img.u32PixelArrayFormat = ASVL_PAF_RGB24_B8G8R8;
MRESULT res_extract = ASFFaceFeatureExtractEx(handle, &asvl_img, &single_face_info, &feature);
cout << "Face: " << i << " --- ";
if (res_extract != MOK) {
cout << "ASFFaceFeatureExtract faile: " << res_extract << endl;
}
else {
cout << "ASFFaceFeatureExtract success: " << res_extract << endl;
}
}
}
cv::imshow("img", img);
cv::waitKey(0);
return 0;
}
ASFFaceFeatureCompare
人脸特征比对,输出比对相似度。
MRESULT ASFFaceFeatureCompare(
MHandle hEngine, // [in] 引擎handle
LPASF_FaceFeature feature1, // [in] 待比较人脸特征1
LPASF_FaceFeature feature2, // [in] 待比较人脸特征2
MFloat* confidenceLevel, // [out] 比较结果,置信度数值
ASF_CompareModel compareModel = ASF_LIFE_PHOTO // [in]
// ASF_LIFE_PHOTO:用于生活照之间的特征比对,推荐阈值0.80
// ASF_ID_PHOTO:用于证件照或证件照和生活照之间的特征比对,推荐阈值0.82
);
示例:
#include <opencv2/opencv.hpp>
#include<iostream>
#include "arcsoft_face_sdk.h"
#include "merror.h"
#pragma comment(lib, "libarcsoft_face_engine.lib")
#define SafeFree(p) { if ((p)) free(p); (p) = nullptr; }
using namespace std;
int main() {
MHandle handle = nullptr;
MInt32 scale = 16;
MInt32 face_num = 2;
MInt32 mask = ASF_FACE_DETECT
| ASF_FACERECOGNITION;
ASFInitEngine(
ASF_DETECT_MODE_IMAGE,
ASF_OP_0_ONLY,
scale,
face_num,
mask,
&handle
);
ASF_FaceFeature copyfeature_base = { 0 }, copyfeature_todo = { 0 };
{
cv::Mat img_base = cv::imread("C:\\users\\milk\\desktop\\1.jpg");
img_base = img_base(cv::Rect(0, 0, img_base.cols - img_base.cols % 4, img_base.rows - img_base.rows % 4));
ASF_MultiFaceInfo multi_base;
ASF_SingleFaceInfo faceinfo_base = { 0 };
ASF_FaceFeature feature_base;
ASFDetectFaces(handle, img_base.cols, img_base.rows, ASVL_PAF_RGB24_B8G8R8, img_base.data, &multi_base);
cout << "num: " << multi_base.faceNum << endl;
faceinfo_base.faceRect = multi_base.faceRect[0];
faceinfo_base.faceOrient = multi_base.faceOrient[0];
ASFFaceFeatureExtract(handle, img_base.cols, img_base.rows, ASVL_PAF_RGB24_B8G8R8, img_base.data, &faceinfo_base, &feature_base);
copyfeature_base.featureSize = feature_base.featureSize;
copyfeature_base.feature = (MByte*)malloc(feature_base.featureSize);
memset(copyfeature_base.feature, 0, feature_base.featureSize);
memcpy(copyfeature_base.feature, feature_base.feature, feature_base.featureSize);
}
{
cv::Mat img_todo = cv::imread("C:\\users\\milk\\desktop\\6.jpg");
img_todo = img_todo(cv::Rect(0, 0, img_todo.cols - img_todo.cols % 4, img_todo.rows - img_todo.rows % 4));
ASF_MultiFaceInfo multi_todo;
ASF_SingleFaceInfo faceinfo_todo = { 0 };
ASF_FaceFeature feature_todo;
ASFDetectFaces(handle, img_todo.cols, img_todo.rows, ASVL_PAF_RGB24_B8G8R8, img_todo.data, &multi_todo);
cout << "num: " << multi_todo.faceNum << endl;
faceinfo_todo.faceRect = multi_todo.faceRect[0];
faceinfo_todo.faceOrient = multi_todo.faceOrient[0];
ASFFaceFeatureExtract(handle, img_todo.cols, img_todo.rows, ASVL_PAF_RGB24_B8G8R8, img_todo.data, &faceinfo_todo, &feature_todo);
copyfeature_todo.featureSize = feature_todo.featureSize;
copyfeature_todo.feature = (MByte*)malloc(feature_todo.featureSize);
memset(copyfeature_todo.feature, 0, feature_todo.featureSize);
memcpy(copyfeature_todo.feature, feature_todo.feature, feature_todo.featureSize);
}
MFloat result;
ASFFaceFeatureCompare(handle, ©feature_base, ©feature_todo, &result);
cout << result << endl;
SafeFree(copyfeature_base.feature);
SafeFree(copyfeature_todo.feature);
return 0;
}
ASFSetLivenessParam
设置RGB/IR活体阈值,若不设置内部默认RGB:0.5 IR:0.7
MRESULT ASFSetLivenessParam(
MHandle hEngine, // [in] 引擎handle
LPASF_LivenessThreshold threshold // [in] 活体置信度
);
示例:
#include <opencv2/opencv.hpp>
#include<iostream>
#include "arcsoft_face_sdk.h"
#include "merror.h"
#pragma comment(lib, "libarcsoft_face_engine.lib")
using namespace std;
int main() {
MHandle handle = nullptr;
MInt32 scale = 16;
MInt32 face_num = 2;
MInt32 mask = ASF_FACE_DETECT
| ASF_FACERECOGNITION
| ASF_LIVENESS;
ASFInitEngine(
ASF_DETECT_MODE_IMAGE,
ASF_OP_0_ONLY,
scale,
face_num,
mask,
&handle
);
ASF_LivenessThreshold threshold = { 0 };
threshold.thresholdmodel_BGR = 0.5;
threshold.thresholdmodel_IR = 0.7;
MRESULT res = ASFSetLivenessParam(handle, &threshold);
if (res != MOK) {
cout << "ASFSetLivenessParam fail: " << res << endl;
}
else {
cout << "ASFSetLivenessParam success: " << res << endl;
}
return 0;
}
ASFProcess
人脸属性检测(年龄、性别、人脸3D角度),最多支持4张人脸信息检测,超过部分返回未知(活体仅支持单张人脸检测,超出返回未知),接口不支持IR图像检测。
仅支持可见光图像检测。
MRESULT ASFProcess(
MHandle hEngine, // [in] 引擎handle
MInt32 width, // [in] 图片宽度
MInt32 height, // [in] 图片高度
MInt32 format, // [in] 颜色空间格式
MUInt8* imgData, // [in] 图片数据
LPASF_MultiFaceInfo detectedFaces, // [in] 人脸信息,用户根据待检测的功能选择需要使用的人脸。
MInt32 combinedMask // [in] 只支持初始化时候指定需要检测的功能,在process时进一步在这个已经指定的功能集中继续筛选
// 例如初始化的时候指定检测年龄和性别,在process的时候可以只检测年龄,但是不能检测除年龄和性别之外的功能
);
示例:
#include <opencv2/opencv.hpp>
#include<iostream>
#include "arcsoft_face_sdk.h"
#include "merror.h"
#pragma comment(lib, "libarcsoft_face_engine.lib")
using namespace std;
int main() {
MHandle handle = nullptr;
MInt32 scale = 16;
MInt32 face_num = 2;
MInt32 mask = ASF_FACE_DETECT
| ASF_FACERECOGNITION
| ASF_AGE
| ASF_GENDER
| ASF_FACE3DANGLE
| ASF_LIVENESS;
ASFInitEngine(
ASF_DETECT_MODE_IMAGE,
ASF_OP_0_ONLY,
scale,
face_num,
mask,
&handle
);
cv::Mat img = cv::imread("C:\\users\\milk\\desktop\\fuck.jpg");
img = img(cv::Rect(0, 0, img.cols - img.cols % 4, img.rows - img.rows % 4));
ASF_MultiFaceInfo faces = { 0 };
ASFDetectFaces(handle, img.cols, img.rows, ASVL_PAF_RGB24_B8G8R8, img.data, &faces);
cout << "face num: " << faces.faceNum << endl;
MInt32 process_mask = ASF_AGE | ASF_GENDER | ASF_FACE3DANGLE | ASF_LIVENESS;
MRESULT result = ASFProcess(handle, img.cols, img.rows, ASVL_PAF_RGB24_B8G8R8, img.data, &faces, process_mask);
if (result != MOK) {
cout << "ASFProcess fail: " << result << endl;
}
else {
cout << "ASFProcess success: " << result << endl;
}
return 0;
}
combinedMask
process接口中支持检测ASF_AGE
、ASF_GENDER
、ASF_FACE3DANGLE
、ASF_LIVENESS
四种属性,但是想检测这些属性,必须在初始化引擎接口中对想要检测的属性进行初始化。
关于初始化接口中combinedMask
和ASFProcess
接口中combinedMask
参数之间的关系:
ASFProcess
接口中combinedMask
支持传入的属性有ASF_AGE
、ASF_GENDER
、ASF_FACE3DANGLE
、ASF_LIVENESS
。- 初始化中传入了
ASF_FACE_DETECT
、ASF_FACERECOGNITION
、ASF_AGE
、ASF_LIVENESS
属性。 process
可传入属性组合只有ASF_AGE
、ASF_LIVENESS
、ASF_AGE | ASF_LIVENESS
。
ASFProcessEx
与ASFProcess
功能一致,但采用结构体的形式传入图像数据,对更高精度的图像兼容任更好。
MRESULT ASFProcessEx(
MHandle hEngine, // [in] 引擎handle
LPASF_ImageData imgData, // [in] 图片数据
LPASF_MultiFaceInfo detectedFaces, // [in] 人脸信息,用户根据待检测的功能选择需要使用的人脸。
MInt32 combinedMask // [in] 只支持初始化时候指定需要检测的功能,在process时进一步在这个已经指定的功能集中继续筛选
// 例如初始化的时候指定检测年龄和性别,在process的时候可以只检测年龄,但是不能检测除年龄和性别之外的功能
);
示例:
#include <opencv2/opencv.hpp>
#include<iostream>
#include "arcsoft_face_sdk.h"
#include "merror.h"
#pragma comment(lib, "libarcsoft_face_engine.lib")
using namespace std;
int main() {
MHandle handle = nullptr;
MInt32 scale = 16;
MInt32 face_num = 2;
MInt32 mask = ASF_FACE_DETECT
| ASF_FACERECOGNITION
| ASF_AGE
| ASF_GENDER
| ASF_FACE3DANGLE
| ASF_LIVENESS;
ASFInitEngine(
ASF_DETECT_MODE_IMAGE,
ASF_OP_0_ONLY,
scale,
face_num,
mask,
&handle
);
cv::Mat img = cv::imread("C:\\users\\milk\\desktop\\fuck.jpg");
img = img(cv::Rect(0, 0, img.cols - img.cols % 4, img.rows - img.rows % 4));
ASVLOFFSCREEN asvl_img;
asvl_img.u32PixelArrayFormat = ASVL_PAF_RGB24_B8G8R8;
asvl_img.i32Width = img.cols;
asvl_img.i32Height = img.rows;
asvl_img.pi32Pitch[0] = img.step;
asvl_img.ppu8Plane[0] = img.data;
ASF_MultiFaceInfo faces = { 0 };
ASFDetectFacesEx(handle, &asvl_img, &faces);
cout << "face num: " << faces.faceNum << endl;
MInt32 process_mask = ASF_AGE | ASF_GENDER | ASF_FACE3DANGLE | ASF_LIVENESS;
MRESULT result = ASFProcessEx(handle, &asvl_img, &faces, process_mask);
if (result != MOK) {
cout << "ASFProcess fail: " << result << endl;
}
else {
cout << "ASFProcess success: " << result << endl;
}
return 0;
}
ASFProcess_IR
仅支持单人脸IR
活体检测(不支持年龄、性别、3D角度的检测),超出返回未知。
MRESULT ASFProcess_IR(
MHandle hEngine, // [in] 引擎handle
MInt32 width, // [in] 图片宽度
MInt32 height, // [in] 图片高度
MInt32 format, // [in] 颜色空间格式
MUInt8* imgData, // [in] 图片数据
LPASF_MultiFaceInfo detectedFaces, // [in] 人脸信息,用户根据待检测的功能选择需要使用的人脸。
MInt32 combinedMask // [in] 目前只支持传入ASF_IR_LIVENESS属性的传入,且初始化接口需要传入
);
示例:
#include <opencv2/opencv.hpp>
#include<iostream>
#include "arcsoft_face_sdk.h"
#include "merror.h"
#pragma comment(lib, "libarcsoft_face_engine.lib")
using namespace std;
int main() {
MHandle handle = nullptr;
MInt32 scale = 16;
MInt32 face_num = 1;
MInt32 mask = ASF_FACE_DETECT
| ASF_FACERECOGNITION
| ASF_AGE
| ASF_GENDER
| ASF_FACE3DANGLE
| ASF_LIVENESS
| ASF_IR_LIVENESS;
ASFInitEngine(
ASF_DETECT_MODE_IMAGE,
ASF_OP_0_ONLY,
scale,
face_num,
mask,
&handle
);
cv::Mat img = cv::imread("C:\\users\\milk\\desktop\\unreal.jpg");
cv::cvtColor(img, img, CV_BGR2GRAY);
img = img(cv::Rect(0, 0, img.cols - img.cols % 4, img.rows - img.rows % 4));
ASVLOFFSCREEN asvl_img;
asvl_img.u32PixelArrayFormat = ASVL_PAF_GRAY;
asvl_img.i32Width = img.cols;
asvl_img.i32Height = img.rows;
asvl_img.pi32Pitch[0] = img.step;
asvl_img.ppu8Plane[0] = img.data;
ASF_MultiFaceInfo faces = { 0 };
ASFDetectFacesEx(handle, &asvl_img, &faces);
cout << "face num: " << faces.faceNum << endl;
MInt32 process_mask = ASF_IR_LIVENESS;
MRESULT res = ASFProcess_IR(handle, img.cols, img.rows, ASVL_PAF_GRAY, img.data, &faces, process_mask);
if (res != MOK) {
cout << "ASFProcess_IR fail: " << res << endl;
}
else {
cout << "ASFProcess_IR success: " << res << endl;
}
return 0;
}
ASFProcessEx_IR
与ASFProcess_IR
功能一致,但采用结构体的形式传入图像数据,对更高精度的图像兼容性更好。
MRESULT ASFProcessEx_IR(
MHandle hEngine, // [in] 引擎handle
LPASF_ImageData imgData, // [in] 图片数据
LPASF_MultiFaceInfo detectedFaces, // [in] 人脸信息,用户根据待检测的功能选择需要使用的人脸。
MInt32 combinedMask // [in] 目前只支持传入ASF_IR_LIVENESS属性的传入,且初始化接口需要传入
);
示例:
#include <opencv2/opencv.hpp>
#include<iostream>
#include "arcsoft_face_sdk.h"
#include "merror.h"
#pragma comment(lib, "libarcsoft_face_engine.lib")
using namespace std;
int main() {
MHandle handle = nullptr;
MInt32 scale = 16;
MInt32 face_num = 1;
MInt32 mask = ASF_FACE_DETECT
| ASF_FACERECOGNITION
| ASF_AGE
| ASF_GENDER
| ASF_FACE3DANGLE
| ASF_LIVENESS
| ASF_IR_LIVENESS;
ASFInitEngine(
ASF_DETECT_MODE_IMAGE,
ASF_OP_0_ONLY,
scale,
face_num,
mask,
&handle
);
cv::Mat img = cv::imread("C:\\users\\milk\\desktop\\unreal.jpg");
cv::cvtColor(img, img, CV_BGR2GRAY);
img = img(cv::Rect(0, 0, img.cols - img.cols % 4, img.rows - img.rows % 4));
ASVLOFFSCREEN asvl_img;
asvl_img.u32PixelArrayFormat = ASVL_PAF_GRAY;
asvl_img.i32Width = img.cols;
asvl_img.i32Height = img.rows;
asvl_img.pi32Pitch[0] = img.step;
asvl_img.ppu8Plane[0] = img.data;
ASF_MultiFaceInfo faces = { 0 };
ASFDetectFacesEx(handle, &asvl_img, &faces);
cout << "face num: " << faces.faceNum << endl;
MInt32 process_mask = ASF_IR_LIVENESS;
MRESULT res = ASFProcessEx_IR(handle, &asvl_img, &faces, process_mask);
if (res != MOK) {
cout << "ASFProcessEx_IR fail: " << res << endl;
}
else {
cout << "ASFProcessEx_IR success: " << res << endl;
}
return 0;
}
ASFGetAge
获取年龄信息。
MRESULT ASFGetAge(
MHandle hEngine, // [in] 引擎handle
LPASF_AgeInfo ageInfo // [out] 检测到的年龄信息
);
示例:
#include <opencv2/opencv.hpp>
#include<iostream>
#include "arcsoft_face_sdk.h"
#include "merror.h"
#pragma comment(lib, "libarcsoft_face_engine.lib")
using namespace std;
int main() {
MHandle handle = nullptr;
MInt32 scale = 16;
MInt32 face_num = 1;
MInt32 mask = ASF_FACE_DETECT
| ASF_FACERECOGNITION
| ASF_AGE
| ASF_GENDER
| ASF_FACE3DANGLE
| ASF_LIVENESS;
ASFInitEngine(
ASF_DETECT_MODE_IMAGE,
ASF_OP_0_ONLY,
scale,
face_num,
mask,
&handle
);
cv::Mat img = cv::imread("C:\\users\\milk\\desktop\\ding.jpg");
img = img(cv::Rect(0, 0, img.cols - img.cols % 4, img.rows - img.rows % 4));
ASVLOFFSCREEN asvl_img;
asvl_img.u32PixelArrayFormat = ASVL_PAF_RGB24_B8G8R8;
asvl_img.i32Width = img.cols;
asvl_img.i32Height = img.rows;
asvl_img.pi32Pitch[0] = img.step;
asvl_img.ppu8Plane[0] = img.data;
ASF_MultiFaceInfo faces = { 0 };
ASFDetectFacesEx(handle, &asvl_img, &faces);
cout << "face num: " << faces.faceNum << endl;
MInt32 process_mask = ASF_AGE | ASF_GENDER | ASF_FACE3DANGLE | ASF_LIVENESS;
ASFProcessEx(handle, &asvl_img, &faces, process_mask);
ASF_AgeInfo age = { 0 };
MRESULT res = ASFGetAge(handle, &age);
if (res != MOK) {
cout << "ASFGetAge fail: " << res << endl;
}
else {
cout << "age: " << age.ageArray[0] << endl;
}
return 0;
}
ASFGetGender
获取性别信息。
MRESULT ASFGetGender(
MHandle hEngine, // [in] 引擎handle
LPASF_GenderInfo genderInfo // [out] 检测到的性别信息
);
示例:
#include <opencv2/opencv.hpp>
#include<iostream>
#include "arcsoft_face_sdk.h"
#include "merror.h"
#pragma comment(lib, "libarcsoft_face_engine.lib")
using namespace std;
int main() {
MHandle handle = nullptr;
MInt32 scale = 16;
MInt32 face_num = 1;
MInt32 mask = ASF_FACE_DETECT
| ASF_FACERECOGNITION
| ASF_AGE
| ASF_GENDER
| ASF_FACE3DANGLE
| ASF_LIVENESS;
ASFInitEngine(
ASF_DETECT_MODE_IMAGE,
ASF_OP_0_ONLY,
scale,
face_num,
mask,
&handle
);
cv::Mat img = cv::imread("C:\\users\\milk\\desktop\\17\\522627199707165616.jpg");
img = img(cv::Rect(0, 0, img.cols - img.cols % 4, img.rows - img.rows % 4));
ASVLOFFSCREEN asvl_img;
asvl_img.u32PixelArrayFormat = ASVL_PAF_RGB24_B8G8R8;
asvl_img.i32Width = img.cols;
asvl_img.i32Height = img.rows;
asvl_img.pi32Pitch[0] = img.step;
asvl_img.ppu8Plane[0] = img.data;
ASF_MultiFaceInfo faces = { 0 };
ASFDetectFacesEx(handle, &asvl_img, &faces);
cout << "face num: " << faces.faceNum << endl;
MInt32 process_mask = ASF_AGE | ASF_GENDER | ASF_FACE3DANGLE | ASF_LIVENESS;
ASFProcessEx(handle, &asvl_img, &faces, process_mask);
ASF_GenderInfo gender = { 0 };
MRESULT res = ASFGetGender(handle, &gender);
if (res != MOK) {
cout << "ASFGetGender fail: " << res << endl;
}
else {
cout << "gender: ";
if (gender.genderArray[0] == 1) {
cout << "female";
}
else if (gender.genderArray[0] == 0) {
cout << "male";
}
else {
cout << "unknow";
}
cout << endl;
}
return 0;
}
ASFGetFace3DAngle
获取3D角度信息。
MRESULT ASFGetFace3DAngle(
MHandle hEngine, // [in] 引擎handle
LPASF_Face3DAngle p3DAngleInfo // [out] 检测到脸部3D 角度信息
);
示例:
#include <opencv2/opencv.hpp>
#include<iostream>
#include "arcsoft_face_sdk.h"
#include "merror.h"
#pragma comment(lib, "libarcsoft_face_engine.lib")
using namespace std;
int main() {
MHandle handle = nullptr;
MInt32 scale = 16;
MInt32 face_num = 1;
MInt32 mask = ASF_FACE_DETECT
| ASF_FACERECOGNITION
| ASF_AGE
| ASF_GENDER
| ASF_FACE3DANGLE
| ASF_LIVENESS;
ASFInitEngine(
ASF_DETECT_MODE_IMAGE,
ASF_OP_0_ONLY,
scale,
face_num,
mask,
&handle
);
cv::Mat img = cv::imread("C:\\users\\milk\\desktop\\17\\522627199707165616.jpg");
img = img(cv::Rect(0, 0, img.cols - img.cols % 4, img.rows - img.rows % 4));
ASVLOFFSCREEN asvl_img;
asvl_img.u32PixelArrayFormat = ASVL_PAF_RGB24_B8G8R8;
asvl_img.i32Width = img.cols;
asvl_img.i32Height = img.rows;
asvl_img.pi32Pitch[0] = img.step;
asvl_img.ppu8Plane[0] = img.data;
ASF_MultiFaceInfo faces = { 0 };
ASFDetectFacesEx(handle, &asvl_img, &faces);
cout << "face num: " << faces.faceNum << endl;
MInt32 process_mask = ASF_AGE | ASF_GENDER | ASF_FACE3DANGLE | ASF_LIVENESS;
ASFProcessEx(handle, &asvl_img, &faces, process_mask);
ASF_Face3DAngle angle = { 0 };
MRESULT res = ASFGetFace3DAngle(handle, &angle);
if (res != MOK) {
cout << "ASFGetFace3DAngle fail: " << res << endl;
}
else {
cout << "roll: " << angle.roll[0] << "\n"
<< "yaw: " << angle.yaw[0] << "\n"
<< "pitch: " << angle.pitch[0]
<< endl;
}
return 0;
}
ASFGetLivenessScore
获取RGB活体信息。
MRESULT ASFGetLivenessScore(
MHandle hEngine, // [in] 引擎handle
LPASF_LivenessInfo livenessInfo // [out] 检测RGB活体结果
);
示例:
#include <opencv2/opencv.hpp>
#include<iostream>
#include "arcsoft_face_sdk.h"
#include "merror.h"
#pragma comment(lib, "libarcsoft_face_engine.lib")
using namespace std;
int main() {
MHandle handle = nullptr;
MInt32 scale = 16;
MInt32 face_num = 1;
MInt32 mask = ASF_FACE_DETECT
| ASF_FACERECOGNITION
| ASF_AGE
| ASF_GENDER
| ASF_FACE3DANGLE
| ASF_LIVENESS
| ASF_IR_LIVENESS;
ASFInitEngine(
ASF_DETECT_MODE_IMAGE,
ASF_OP_0_ONLY,
scale,
face_num,
mask,
&handle
);
cv::Mat img = cv::imread("C:\\users\\milk\\desktop\\unreal.jpg");
img = img(cv::Rect(0, 0, img.cols - img.cols % 4, img.rows - img.rows % 4));
ASVLOFFSCREEN asvl_img;
asvl_img.u32PixelArrayFormat = ASVL_PAF_RGB24_B8G8R8;
asvl_img.i32Width = img.cols;
asvl_img.i32Height = img.rows;
asvl_img.pi32Pitch[0] = img.step;
asvl_img.ppu8Plane[0] = img.data;
ASF_MultiFaceInfo faces = { 0 };
ASFDetectFacesEx(handle, &asvl_img, &faces);
cout << "face num: " << faces.faceNum << endl;
MInt32 process_mask = ASF_LIVENESS;
ASFProcessEx(handle, &asvl_img, &faces, process_mask);
ASF_LivenessInfo liveness = { 0 };
MRESULT res = ASFGetLivenessScore(handle, &liveness);
if (res != MOK) {
cout << "ASFGetLivenessScore fail: " << res << endl;
}
else {
cout << "ASFGetLivenessScore success: " << res << endl;
cout << "status: " << liveness.isLive[0] << endl;
}
return 0;
}
ASFGetLivenessScore_IR
获取IR活体结果
MRESULT ASFGetLivenessScore_IR(
MHandle hEngine, // [in] 引擎handle
LPASF_LivenessInfo irLivenessInfo // [out] 检测到IR活体结果
);
示例:
#include <opencv2/opencv.hpp>
#include<iostream>
#include "arcsoft_face_sdk.h"
#include "merror.h"
#pragma comment(lib, "libarcsoft_face_engine.lib")
using namespace std;
int main() {
MHandle handle = nullptr;
MInt32 scale = 16;
MInt32 face_num = 1;
MInt32 mask = ASF_FACE_DETECT
| ASF_FACERECOGNITION
| ASF_AGE
| ASF_GENDER
| ASF_FACE3DANGLE
| ASF_LIVENESS
| ASF_IR_LIVENESS;
ASFInitEngine(
ASF_DETECT_MODE_IMAGE,
ASF_OP_0_ONLY,
scale,
face_num,
mask,
&handle
);
cv::Mat img = cv::imread("C:\\users\\milk\\desktop\\unreal.jpg");
cv::cvtColor(img, img, CV_BGR2GRAY);
img = img(cv::Rect(0, 0, img.cols - img.cols % 4, img.rows - img.rows % 4));
ASVLOFFSCREEN asvl_img;
asvl_img.u32PixelArrayFormat = ASVL_PAF_GRAY;
asvl_img.i32Width = img.cols;
asvl_img.i32Height = img.rows;
asvl_img.pi32Pitch[0] = img.step;
asvl_img.ppu8Plane[0] = img.data;
ASF_MultiFaceInfo faces = { 0 };
ASFDetectFacesEx(handle, &asvl_img, &faces);
cout << "face num: " << faces.faceNum << endl;
MInt32 process_mask = ASF_IR_LIVENESS;
ASFProcessEx_IR(handle, &asvl_img, &faces, process_mask);
ASF_LivenessInfo liveness = { 0 };
MRESULT res = ASFGetLivenessScore_IR(handle, &liveness);
if (res != MOK) {
cout << "ASFGetLivenessScore fail: " << res << endl;
}
else {
cout << "ASFGetLivenessScore success: " << res << endl;
cout << "status: " << liveness.isLive[0] << endl;
}
return 0;
}
- Valine
- LiveRe
- ChangYan