ouyangandy 2019-06-29
本文主要会对虹软人脸识别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 [ [email protected] -- 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...