简介
本文主要会对虹软人脸识别SDK在 Qt 平台下的使用过程做简要介绍,其中包含材料准备、环境搭建、代码实现三个主要步骤,帮助我们有过程上的参考。
开发环境 : win10 Qt5.11.2(Mingw 32位)
材料准备
- 人脸识别SDK(ArcSoft_ArcFace)下载
虹软对外有免费的AI开发平台,包括人脸识别SDK、活体检测SDK、人证核验SDK,这里我们使用的是人脸检测SDK,详细可以登陆虹软官网进行具体功能查阅。
登陆 http://ai.arcsoft.com.cn/prod... 进行注册后下载ArcSoft_ArcFace 2.0版本。
需要注意的是,下载SDK的版本要与qt编译器版本一致。这里选择下载 windous(x86)版本。
下载完成后,首先阅读 releasenotes.txt -> ARCSOFT_ARC_FACE_DEVELOPER'S_GUIDE.pdf。
- openCV 下载
这里我们直接下载编译好的 OpenCV(x86 MinGW 版)https://github.com/huihut/Ope...。
下载完成后,首先阅读 README.md。
环境搭建
- 新建Qt工程
在 .pro 文件里面添加OpenCV相关库:
win32 {
INCLUDEPATH += D:\OpenCV-MinGW-Build-OpenCV-3.3.1\include\
INCLUDEPATH += D:\OpenCV-MinGW-Build-OpenCV-3.3.1\include\opencv
INCLUDEPATH += D:\OpenCV-MinGW-Build-OpenCV-3.3.1\include\opencv2
LIBS += D:\OpenCV-MinGW-Build-OpenCV-3.3.1\bin\libopencv_*.dll
}
1. 打开 Qt 工程,添加ArcSoft_ArcFace相关库:
2. 鼠标右键,添加库,外部库;
3. 平台选中 windows,链接选中 动态,其它不做勾选;
4. 库文件指下载好的 ArcSoft_ArcFace 的lib、dll 文件;
5. 包含路径指下载好的 ArcSoft_ArcFace 库相关的头文件。
6. 鼠标右键,添加现有文件,把 ArcSoft_ArcFace 库相关的头文件添加到工程中。
HEADERS += \
ArcSoft_ArcFace/inc/amcomdef.h \
ArcSoft_ArcFace/inc/arcsoft_face_sdk.h \
ArcSoft_ArcFace/inc/asvloffscreen.h \
ArcSoft_ArcFace/inc/merror.h
- 复制运行相关 dll 文件
将ArcSoft_ArcFace 与 OpenCV 相关的 dll 文件复制到工程生成的应用程序文件夹。如果没有添加完整,生成的应用程序运行时,将提示“由于找不到 xxx_.dll,无法继续执行代码。重新安装程序可能会解决此问题”或者“应用程序无法正常启动0xc000007b”等问题。
代码实现
- UI界面实现: 使用 Axure 画界面原型图,组件采用绝对定位方式。
void Wigdet::initUI()
{
m_photoBox.setParent(this);
m_photoBox.move(8, 7);
m_photoBox.resize(422, 278);
m_idCardBox.setParent(this);
m_idCardBox.move(440, 7);
m_idCardBox.resize(276, 154);
m_valLab.setParent(this);
m_valLab.move(482, 171);
m_valLab.resize(33, 16);
m_valLab.setText("阈 值:");
m_valSpinBox.setParent(this);
m_valSpinBox.move(544, 166);
m_valSpinBox.resize(159, 24);
m_valSpinBox.setSingleStep(0.01);
m_valSpinBox.setMinimum(0.01);
m_valSpinBox.setMaximum(1.00);
m_valSpinBox.setValue(0.82);
m_loadPhotoBtn.setParent(this);
m_loadPhotoBtn.move(454, 197);
m_loadPhotoBtn.resize(249, 24);
m_loadPhotoBtn.setText("图像导入");
m_loadIdCardBtn.setParent(this);
m_loadIdCardBtn.move(454, 228);
m_loadIdCardBtn.resize(249, 24);
m_loadIdCardBtn.setText("ID卡导入");
m_compareBtn.setParent(this);
m_compareBtn.move(454, 257);
m_compareBtn.resize(249, 24);
m_compareBtn.setText("面部识别");
setWindowIcon(QIcon(":/pic/pic/icon.png"));
setWindowTitle("AI Changes life [ 1508539502@qq.com -- TianSong ]");
setFixedSize(726, 295);
}
- 关键的槽函数
void Wigdet::initSLot()
{
connect(&m_loadPhotoBtn, SIGNAL(clicked()), this, SLOT(onLoadPhotoBtnClicked()));
connect(&m_loadIdCardBtn, SIGNAL(clicked()), this, SLOT(onLoadIdCardBtnClicked()));
connect(&m_compareBtn, SIGNAL(clicked()), this, SLOT(onCompareBtnClicked()));
}
void Wigdet::onLoadPhotoBtnClicked();
void Wigdet::onLoadIdCardBtnClicked();
void Wigdet::onCompareBtnClicked();
- 重写 painEvent 事件函数
void Wigdet::paintEvent(QPaintEvent*);
- 人脸识别处理 (查阅帮助文档与示例代码)
#define APPID "申请的APPID" //APPID
#define SDKKey "申请的SDKKey" //SDKKey
#define MERR_ASF_BASE_ALREADY_ACTIVATED (0x16002)
bool Wigdet::doCompare(Imag& img_photo, Imag& img_idcard, float val)
{
bool pResult = false;
/** 1. 激活SDK */
MRESULT res = ASFActivation(const_cast<char*>(APPID), const_cast<char*>(SDKKey));
if (MOK == res || MERR_ASF_BASE_ALREADY_ACTIVATED == res)
{
qDebug() << "ALActivation sucess: " << res;
}
else
{
qDebug() << "ALActivation fail: " << res;
}
/** 2. 初始化引擎 */
MHandle handle = NULL;
MInt32 mask = ASF_FACE_DETECT | ASF_FACERECOGNITION | ASF_AGE | ASF_GENDER | ASF_FACE3DANGLE;
res = ASFInitEngine(static_cast<MInt32>(ASF_DETECT_MODE_IMAGE), ASF_OP_0_ONLY, 16, 5, mask, &handle);
if (res == MOK)
{
qDebug() << "ALInitEngine sucess: " << res;
}
else
{
qDebug() << "ALInitEngine fail: " << res;
}
/** 3. 人脸检测 */
img_photo.img.scaled(img_photo.img.width()/4*4, img_photo.img.height()/4*4).save("img1.png");
img_idcard.img.scaled(img_idcard.img.width()/4*4, img_idcard.img.height()/4*4).save("img2.png");
IplImage* img1 = cvLoadImage("img1.png");
IplImage* img2 = cvLoadImage("img2.png");
if (img1 && img2)
{
/** 3.1 第一张人脸特征提取 */
ASF_MultiFaceInfo detectedFaces1 = { 0 };
ASF_SingleFaceInfo SingleDetectedFaces1 = { 0 };
ASF_FaceFeature feature1 = { 0 };
ASF_FaceFeature copyfeature1 = { 0 };
res = ASFDetectFaces(handle, img1->width, img1->height, ASVL_PAF_RGB24_B8G8R8, (MUInt8*)img1->imageData, &detectedFaces1);
if (MOK == res)
{
SingleDetectedFaces1.faceRect.left = detectedFaces1.faceRect[0].left;
SingleDetectedFaces1.faceRect.top = detectedFaces1.faceRect[0].top;
SingleDetectedFaces1.faceRect.right = detectedFaces1.faceRect[0].right;
SingleDetectedFaces1.faceRect.bottom = detectedFaces1.faceRect[0].bottom;
SingleDetectedFaces1.faceOrient = 0x05;
qDebug() << detectedFaces1.faceNum;
res = ASFFaceFeatureExtract(handle, img1->width, img1->height, ASVL_PAF_RGB24_B8G8R8, reinterpret_cast<MUInt8*>(img1->imageData), &SingleDetectedFaces1, &feature1);
if (res == MOK)
{
/** 3.1.1 拷贝feature */
copyfeature1.featureSize = feature1.featureSize;
copyfeature1.feature = reinterpret_cast<MByte*>(malloc(static_cast<size_t>(feature1.featureSize)));
memset(copyfeature1.feature, 0, static_cast<size_t>(feature1.featureSize));
memcpy(copyfeature1.feature, feature1.feature, static_cast<size_t>(feature1.featureSize));
int x = SingleDetectedFaces1.faceRect.left;
int y = SingleDetectedFaces1.faceRect.top;
int w = SingleDetectedFaces1.faceRect.right - SingleDetectedFaces1.faceRect.left;
int h = SingleDetectedFaces1.faceRect.bottom - SingleDetectedFaces1.faceRect.top;
img_photo.rect = QRect(x, y, w, h);
/** 3.1.2 人脸信息检测 */
MInt32 processMask = ASF_AGE | ASF_GENDER;
res = ASFProcess(handle, img1->width, img1->height, ASVL_PAF_RGB24_B8G8R8, reinterpret_cast<MUInt8*>(img1->imageData), &detectedFaces1, processMask);
if (res == MOK)
{
qDebug() << "ASFProcess sucess: " << res;
}
else
{
qDebug() << "ASFProcess fail: " << res;
}
/** 3.1.3 获取年龄 */
ASF_AgeInfo ageInfo = { 0 };
res = ASFGetAge(handle, &ageInfo);
if (res == MOK)
{
img_photo.age = ageInfo.ageArray[0];
qDebug() << ageInfo.ageArray[0];
qDebug() << "ASFGetAge sucess: " << res;
}
else
{
qDebug() << "ASFGetAge fail: " << res;
}
/** 3.1.4 获取性别 */
ASF_GenderInfo genderInfo = { 0 };
res = ASFGetGender(handle, &genderInfo);
if (res == MOK)
{
img_photo.gender = genderInfo.genderArray[0];
qDebug() << genderInfo.genderArray[0];
qDebug() << "ASFGetGender sucess: " << res;
}
else
{
qDebug() << "ASFGetGender fail: " << res;
}
qDebug() << "ASFFaceFeatureExtract 1 Success";
}
else
{
qDebug() << "ASFFaceFeatureExtract 1 fail: " << res;
}
}
else
{
qDebug() << "ASFDetectFaces 1 fail: " << res;
}
/** 3.2 第二张人脸特征提取 */
ASF_MultiFaceInfo detectedFaces2 = { 0 };
ASF_SingleFaceInfo SingleDetectedFaces2 = { 0 };
ASF_FaceFeature feature2 = { 0 };
res = ASFDetectFaces(handle, img2->width, img2->height, ASVL_PAF_RGB24_B8G8R8, reinterpret_cast<MUInt8*>(img2->imageData), &detectedFaces2);
if (MOK == res)
{
SingleDetectedFaces2.faceRect.left = detectedFaces2.faceRect[0].left;
SingleDetectedFaces2.faceRect.top = detectedFaces2.faceRect[0].top;
SingleDetectedFaces2.faceRect.right = detectedFaces2.faceRect[0].right;
SingleDetectedFaces2.faceRect.bottom = detectedFaces2.faceRect[0].bottom;
SingleDetectedFaces2.faceOrient = detectedFaces2.faceOrient[0];
res = ASFFaceFeatureExtract(handle, img2->width, img2->height, ASVL_PAF_RGB24_B8G8R8, reinterpret_cast<MUInt8*>(img2->imageData), &SingleDetectedFaces2, &feature2);
if (res == MOK)
{
int x = SingleDetectedFaces2.faceRect.left;
int y = SingleDetectedFaces2.faceRect.top;
int w = SingleDetectedFaces2.faceRect.right - SingleDetectedFaces2.faceRect.left;
int h = SingleDetectedFaces2.faceRect.bottom - SingleDetectedFaces2.faceRect.top;
img_idcard.rect = QRect(x, y, w, h);
qDebug() << "ASFFaceFeatureExtract 2 Success";
}
else
{
qDebug() << "ASFFaceFeatureExtract 2 fail: " << res;
}
}
else
{
qDebug() << "ASFDetectFaces 2 fail: " << res;
}
/** 3.3 单人脸特征比对 */
MFloat confidenceLevel;
res = ASFFaceFeatureCompare(handle, ©feature1, &feature2, &confidenceLevel);
if (res == MOK)
{
qDebug() << "ASFFaceFeatureCompare sucess: " << confidenceLevel;
if( confidenceLevel >= val ) pResult = true;
}
else
{
qDebug() << "ASFFaceFeatureCompare fail: " << res;
}
}
/** 4. 反初始化 */
res = ASFUninitEngine(handle);
if (res != MOK)
{
qDebug() << "ALUninitEngine fail: " << res;
}
else
{
qDebug() << "ALUninitEngine sucess: " << res;
}
return pResult;
}
以上步骤完成后,就可以正常的编译运行了。
【因篇幅的限制,部分函数实现没有展开,可以根据文章末尾链接到github 中下载查看】
注意事项
ArcSoft_ArcFace_S 版本需要与 Qt 编译器一致 x64 或者 x86
opencv 版本需要与 Qt 编译器一致 x64 或者 x86.
下载链接
OpenCV-MinGW-Build-OpenCV-3.3.1:
https://github.com/cocowts/Op...
ArcSoft_ArcFace_Windows_x86_V2.0:
https://github.com/cocowts/Ar...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。