#include "faceLiveness.h" #include "ui_faceLiveness.h" #include "CAppInfo.h" #include #include #include "awMsgBox.h" #include "logproc.h" #include "CCommonTools.h" #include "CFaceRecProc.h" faceLiveness::faceLiveness(QWidget *parent) : QWidget(parent), ui(new Ui::faceLiveness) { ui->setupUi(this); setStyleSheet(g_appInfoPtr->m_sQssStr); initUI(); qRegisterMetaType("CBaseResponsePackage"); qRegisterMetaType("CProcessUpload"); connect(g_httpBllPtr.get(), &CHttpBll::sgnProcessUpload, this, &faceLiveness::onProcessUpload); connect(g_httpBllPtr.get(), &CHttpBll::sgnSaveFaceLiveVerifyResult, this, &faceLiveness::onSaveFaceLiveVerifyResult); m_nMaxSeconds = 60; QString sFileName = g_appInfoPtr->m_sStudentPhotoPath.right(g_appInfoPtr->m_sStudentPhotoPath.length() - g_appInfoPtr->m_sStudentPhotoPath.lastIndexOf("/") - 1); sFileName = g_appInfoPtr->m_sCacheFileDir + sFileName; if(!QFile::exists(sFileName)) { CHttpRequestPackage hrp; hrp.sUri = g_appInfoPtr->m_sStudentPhotoPath; hrp.sCommonStr = sFileName; hrp.nRequestType = RequestType::rtDownLoadFile; hrp.nRetryCount = 3; g_httpBllPtr->downLoad(hrp); } // m_cam.set(CV_CAP_PROP_FOURCC, CV_FOURCC('M', 'J', 'P', 'G')); // int inWidth = ui->widget_fc_camera->width(); // m_cam.set(CV_CAP_PROP_FRAME_WIDTH, inWidth); // int inHeight = ui->widget_fc_camera->height(); // m_cam.set(CV_CAP_PROP_FRAME_HEIGHT, inHeight); // m_cam.set(CV_CAP_PROP_FPS, 5); // m_pinitTimer = std::make_shared(); // m_pinitTimer->setInterval(1000); // connect(m_pinitTimer.get(), &QTimer::timeout, this, [&](){ // m_pinitTimer->stop(); // if(!m_cam.open(0)) // { // ShowMsg(QString::fromLocal8Bit("打开摄像头失败"), this, MSG_ICON_TYPE::mit_error); // return; // } // m_pVideoTimer->start(); // }); m_pVideoTimer = std::make_shared(); m_pVideoTimer->setInterval(200); connect(m_pVideoTimer.get(), &QTimer::timeout, this, [&](){ cv::Mat frame; { std::scoped_lock sl(m_imageMutex); frame = m_nCurImage; } QImage img = CCommonTools::Mat2QImage(frame); ui->widget_fc_camera->setAutoFillBackground(true); QPalette palette; palette.setBrush(QPalette::Window, QBrush(img.scaled(ui->widget_fc_camera->width(), ui->widget_fc_camera->height()))); ui->widget_fc_camera->setPalette(palette); if(m_bStartCompare) { std::scoped_lock sl(m_imgMutex); m_imgList.push_back(frame); } }); g_clientVideoProcPtr->startTest(this); m_pVideoTimer->start(); //生成动作列表 QStringList sActionList = g_appInfoPtr->m_oExamInfo.sActionOptions.split(","); if(sActionList.count() != g_appInfoPtr->m_oExamInfo.nActionNum) { ShowMsg(QString::fromLocal8Bit("初始化活体动作失败"), this, MSG_ICON_TYPE::mit_error); emit faceLivenessFaild(); return; } LivenessVerifyInfo lvif; lvif.sActionType = ACTION_TYPE::AT_FACE_DETECT; lvif.nActionLeftSceonds = 60; m_livenessList.push_back(lvif); m_currentVerifyInfo = lvif; if(g_appInfoPtr->m_oExamInfo.sActionOrder == "FIXED") { for(QString sAction : sActionList) { LivenessVerifyInfo lvi; lvi.sActionType = sAction; lvi.nActionLeftSceonds = g_appInfoPtr->m_oExamInfo.nActionDuration; m_livenessList.push_back(lvi); } } else { QList list; CCommonTools::genRandomNumber(list, g_appInfoPtr->m_oExamInfo.nActionNum); for(int i = 0; i < g_appInfoPtr->m_oExamInfo.nActionNum; i++) { LivenessVerifyInfo lvi; lvi.sActionType = sActionList[list[i]-1]; lvi.nActionLeftSceonds = g_appInfoPtr->m_oExamInfo.nActionDuration; m_livenessList.push_back(lvi); } } m_nCurIndex = 0; m_ActionTimer = std::make_shared(); m_ActionTimer->setInterval(1000); connect(m_ActionTimer.get(), &QTimer::timeout, this, &faceLiveness::actionTimer); m_countdownTimer = std::make_shared(); m_countdownTimer->setInterval(1000); connect(m_countdownTimer.get(), &QTimer::timeout, this, &faceLiveness::countdownTimer); m_countdownTimer->start(); m_bIsRun = true; m_thread = std::thread(std::bind(&faceLiveness::threadProc, this)); } faceLiveness::~faceLiveness() { m_pVideoTimer->stop(); m_ActionTimer->stop(); g_clientVideoProcPtr->stopTest(); m_bIsRun = false; m_thread.join(); awMsgBox::clear(this); delete ui; } void faceLiveness::onRenderVideoFrame(const char* userId, TRTCVideoStreamType streamType, TRTCVideoFrame* frame) { if(g_clientVideoProcPtr->isCameraTest()) { __int64 nServerTime = g_appInfoPtr->serverMTime(); if(nServerTime - m_lastFaceTime >= 100) { m_lastFaceTime = nServerTime; cv::Mat matImg; cv::cvtColor(cv::Mat(frame->height, frame->width, CV_8UC4, frame->data), matImg, CV_RGBA2RGB); if(matImg.empty()) { qDebug()<<"widgetCameraTest frame is empty"; return; } std::scoped_lock sl(m_imageMutex); m_nCurImage = matImg; } } } void faceLiveness::initUI() { QDesktopWidget *dekwiget = QApplication::desktop(); setGeometry(0, 0, dekwiget->width(), dekwiget->height()); ui->widget_mask->setGeometry(0, 0, dekwiget->width(), dekwiget->height()); ui->widget_fc_BG->setGeometry((width() - g_appInfoPtr->m_fRate*800)/2, (height() - g_appInfoPtr->m_fRate*536)/2, g_appInfoPtr->m_fRate*800, g_appInfoPtr->m_fRate*536); ui->label_fl_title->adjustSize(); ui->label_fl_title->setGeometry(g_appInfoPtr->m_fRate*20, g_appInfoPtr->m_fRate*20, ui->label_fl_title->width(), ui->label_fl_title->height()); ui->label_fl_time->setGeometry(ui->label_fl_title->x() + ui->label_fl_title->width(), ui->label_fl_title->y(), g_appInfoPtr->m_fRate*200, ui->label_fl_title->height()); ui->btn_fc_close->setGeometry(ui->widget_fc_BG->width() - g_appInfoPtr->m_fRate*(20 + 16), g_appInfoPtr->m_fRate*16, g_appInfoPtr->m_fRate*16, g_appInfoPtr->m_fRate*16); ui->btn_fc_close->setVisible(false); ui->widget_fc_camera->setGeometry(g_appInfoPtr->m_fRate*30, g_appInfoPtr->m_fRate*75, g_appInfoPtr->m_fRate*740, g_appInfoPtr->m_fRate*320); ui->btn_fl_startVerify->setGeometry((ui->widget_fc_camera->width() - g_appInfoPtr->m_fRate*160)/2, ui->widget_fc_camera->y() + ui->widget_fc_camera->height() + g_appInfoPtr->m_fRate*30, g_appInfoPtr->m_fRate*160, g_appInfoPtr->m_fRate*40); ui->label_fl_tips->adjustSize(); ui->label_fl_tips->setGeometry((ui->widget_fc_BG->width() - ui->label_fl_tips->width())/2, ui->btn_fl_startVerify->y() + ui->btn_fl_startVerify->height() + g_appInfoPtr->m_fRate*20, ui->label_fl_tips->width(), ui->label_fl_tips ->height()); ui->label_fl_actionMoive->setGeometry(0, 0, g_appInfoPtr->m_fRate*64, g_appInfoPtr->m_fRate*64); ui->label_fl_actionTips->adjustSize(); int nActionWidth = ui->label_fl_actionMoive->width() + g_appInfoPtr->m_fRate*20 + ui->label_fl_actionTips->width() + g_appInfoPtr->m_fRate*20 + g_appInfoPtr->m_fRate*44; ui->widget_fl_action->setGeometry((ui->widget_fc_camera->width() - nActionWidth)/2, g_appInfoPtr->m_fRate*10, nActionWidth, g_appInfoPtr->m_fRate*64) ; ui->label_fl_actionTips->setGeometry(ui->label_fl_actionMoive->x() + ui->label_fl_actionMoive->width() + g_appInfoPtr->m_fRate*20, (ui->widget_fl_action->height() - ui->label_fl_actionTips->height())/2, ui->label_fl_actionTips->width(), ui->label_fl_actionTips->height()); ui->btn_fl_time->setGeometry(ui->label_fl_actionTips->x() + ui->label_fl_actionTips->width() + g_appInfoPtr->m_fRate*20, (ui->widget_fl_action->height() - g_appInfoPtr->m_fRate*40)/2, g_appInfoPtr->m_fRate*40, g_appInfoPtr->m_fRate*40); ui->widget_fl_hint->setVisible(false); ui->widget_fl_hint->setGeometry((width() - g_appInfoPtr->m_fRate*400)/2, (height() - g_appInfoPtr->m_fRate*180)/2, g_appInfoPtr->m_fRate*400, g_appInfoPtr->m_fRate*180); ui->label_fl_icon->setGeometry(g_appInfoPtr->m_fRate*75, g_appInfoPtr->m_fRate*70, g_appInfoPtr->m_fRate*40, g_appInfoPtr->m_fRate*40); ui->label_fl_hint->adjustSize(); ui->label_fl_hint->setGeometry(ui->label_fl_icon->x() + ui->label_fl_icon->width() + g_appInfoPtr->m_fRate*20, ui->label_fl_icon->y() + (ui->label_fl_icon->height() - ui->label_fl_hint->height())/2, ui->label_fl_hint->width(), ui->label_fl_hint->height()); ui->widget_fl_action->setVisible(false); } void faceLiveness::threadProc() { try { while (m_bIsRun) { if (m_bStartCompare) { if (m_imgList.begin() != m_imgList.end()) { myDebug() << "m_imgList:" << m_imgList.size(); cv::Mat matImage; { std::scoped_lock lock(m_imgMutex); if (m_imgList.begin() != m_imgList.end()) { matImage = (*m_imgList.begin()).clone(); m_imgList.erase(m_imgList.begin()); } else { continue; } } if (matImage.empty()) { myDebug() << "matImage.empty"; continue; } if (!m_currentVerifyInfo.bIsVerify) { verifyAction(matImage); } } } else { Sleep(100); } } } catch (const std::exception &e) { myDebug()<compareWithBase(matImage, nFaceCount, fScore, rt)) { m_currentVerifyInfo.sErrorMsg = g_faceRecProcPtr->errorMsg(); myServerLog() << g_faceRecProcPtr->errorMsg(); return; } m_currentVerifyInfo.nFaceCount = nFaceCount; m_currentVerifyInfo.fSimilarity = fScore; if (nFaceCount != 1) { myServerLog() << QString::fromLocal8Bit("活体检测人脸数量异常,") << nFaceCount; m_currentVerifyInfo.sErrorMsg = QString::fromLocal8Bit("活体检测人脸数量异常,").arg(nFaceCount); return; } if (fScore * 100 > g_appInfoPtr->m_oExamInfo.nWarnThreshold) { bool bRealness = false; if (!g_faceRecProcPtr->faceRealness(matImage, bRealness)) { myServerLog() << g_faceRecProcPtr->errorMsg(); m_currentVerifyInfo.sErrorMsg = g_faceRecProcPtr->errorMsg(); return; } //验证成功 if (bRealness) { m_currentVerifyInfo.nEndTime = g_appInfoPtr->serverMTime(); m_currentVerifyInfo.nRealness = 1; m_currentVerifyInfo.bPass = true; m_currentVerifyInfo.bIsVerify = true; myServerLog() << m_currentVerifyInfo.sActionType << ":" << fScore; return; } else { m_currentVerifyInfo.nRealness = 0; } } } if (m_currentVerifyInfo.sActionType == ACTION_TYPE::AT_BLINK || m_currentVerifyInfo.sActionType == ACTION_TYPE::AT_NOD) { int nFaceStatus = 0; if (m_currentVerifyInfo.sActionType == ACTION_TYPE::AT_BLINK) { nFaceStatus = SL_EYE_CLOSE; } else { nFaceStatus = SL_HEAD_DOWN; } if (!g_faceRecProcPtr->getFaceAttribute(matImage, nFaceStatus, bHasStatus, nFaceCount)) { myServerLog() << g_faceRecProcPtr->errorMsg(); m_currentVerifyInfo.sErrorMsg = g_faceRecProcPtr->errorMsg(); return; } m_currentVerifyInfo.nFaceCount = nFaceCount; if (nFaceCount != 1) { myServerLog() << QString::fromLocal8Bit("活体检测人脸数量异常,") << nFaceCount; m_currentVerifyInfo.sErrorMsg = QString::fromLocal8Bit("活体检测人脸数量异常,").arg(nFaceCount); return; } if (bHasStatus) { //验证成功 m_currentVerifyInfo.nEndTime = g_appInfoPtr->serverMTime(); m_currentVerifyInfo.nRealness = 1; m_currentVerifyInfo.bPass = true; m_currentVerifyInfo.bIsVerify = true; } } else if (m_currentVerifyInfo.sActionType == ACTION_TYPE::AT_SHAKE) { float fYaw = 0; float fPitch = 0; float fRoll = 0; int nFaceCount = 0; if (!g_faceRecProcPtr->getFaceAttribute(matImage, fYaw, fPitch, fRoll, nFaceCount)) { myServerLog() << g_faceRecProcPtr->errorMsg(); m_currentVerifyInfo.sErrorMsg = g_faceRecProcPtr->errorMsg(); return; } m_currentVerifyInfo.nFaceCount = nFaceCount; if (m_fMinYaw > fYaw) { m_fMinYaw = fYaw; } if (m_fMaxYaw < fYaw) { m_fMaxYaw = fYaw; } if (m_fMaxYaw - m_fMinYaw > 30) { //验证成功 m_currentVerifyInfo.nEndTime = g_appInfoPtr->serverMTime(); m_currentVerifyInfo.nRealness = 1; m_currentVerifyInfo.bPass = true; m_currentVerifyInfo.bIsVerify = true; } } } catch (const std::exception &e) { myDebug() << QString::fromLocal8Bit("人脸比对失败,%1").arg(e.what()); } } void faceLiveness::on_btn_fc_close_clicked() { } void faceLiveness::on_btn_fl_startVerify_clicked() { if(g_faceRecProcPtr == nullptr) { g_faceRecProcPtr = std::make_shared(); if (!g_appInfoPtr->m_sStudentPhotoPath.isEmpty()) { QString sFileName = g_appInfoPtr->m_sStudentPhotoPath.right(g_appInfoPtr->m_sStudentPhotoPath.length() - g_appInfoPtr->m_sStudentPhotoPath.lastIndexOf("/") - 1); sFileName = g_appInfoPtr->m_sCacheFileDir + sFileName; if(!QFile::exists(sFileName)) { ShowMsg(QString::fromLocal8Bit("底照下载失败,请检查网络"), this, MSG_ICON_TYPE::mit_error); return; } if(!g_faceRecProcPtr->setBaseImage(sFileName)) { ShowMsg(g_faceRecProcPtr->errorMsg(), this, MSG_ICON_TYPE::mit_error); return; } } else { ShowMsg(QString::fromLocal8Bit("当前考试未底照"), this, MSG_ICON_TYPE::mit_error); return; } } m_bStartCompare = true; m_fMaxYaw = 0; m_fMinYaw = 0; m_sLivenessStatus = STATUS_TYPE::ST_SUCCESS; ui->btn_fl_startVerify->setVisible(false); ui->label_fl_tips->setVisible(false); ui->widget_fc_camera->setFixedHeight(g_appInfoPtr->m_fRate*431); ui->widget_fl_action->setVisible(true); { std::scoped_lock sl(m_livenessListMutex); m_currentVerifyInfo = m_livenessList[m_nCurIndex]; } initAcionIcon(); m_ActionTimer->start(); } void faceLiveness::initAcionIcon() { QMovie *movie; ui->btn_fl_time->setVisible(true); ui->btn_fl_time->setText(QString("%1s").arg(m_currentVerifyInfo.nActionLeftSceonds)); if(m_currentVerifyInfo.sActionType == ACTION_TYPE::AT_FACE_DETECT) { movie = new QMovie(":/images/img-fl-face.png"); ui->label_fl_actionTips->setText(QString::fromLocal8Bit("请让我看到您的正脸")); ui->btn_fl_time->setVisible(false); } else if(m_currentVerifyInfo.sActionType == ACTION_TYPE::AT_BLINK) { movie = new QMovie(":/images/gif-close-eyes.gif"); ui->label_fl_actionTips->setText(QString::fromLocal8Bit("请闭眼")); } else if(m_currentVerifyInfo.sActionType == ACTION_TYPE::AT_SHAKE) { movie = new QMovie(":/images/gif-turn-head.gif"); ui->label_fl_actionTips->setText(QString::fromLocal8Bit("请摇头")); } else if(m_currentVerifyInfo.sActionType == ACTION_TYPE::AT_NOD) { movie = new QMovie(":/images/gif-head-down.gif"); ui->label_fl_actionTips->setText(QString::fromLocal8Bit("请点头")); } ui->label_fl_actionMoive->setMovie(movie); movie->start(); } void faceLiveness::saveLivenessResult() { try { bool bSubmit = true; for (int i = 0; i < m_livenessList.count(); ++i) { if (!m_livenessList[i].matImage.empty() && m_livenessList[i].sUrl.isEmpty()) { bSubmit = false; m_nCurIndex = i; m_currentVerifyInfo = m_livenessList[i]; QString sImageFile = QString("temp/photo/%1.png").arg(CCommonTools::getUuid()); QImage img = CCommonTools::Mat2QImage(m_currentVerifyInfo.matImage); img.save(sImageFile, "PNG"); //上传图片 CHttpRequestPackage hrp; hrp.sUri = "/api/ecs_oe_student/client/exam/process/upload"; hrp.nRequestType = RequestType::rtProcessUpload; hrp.sCommonStr = __FILE__; hrp.sParamList.push_back(QString("formdataFileType,file,%1").arg(sImageFile)); hrp.sParamList.push_back(QString("md5,%1").arg(CCommonTools::fileMd5(sImageFile))); hrp.eParamType = HttpParamType::hptFormdata; g_httpBllPtr->post(hrp); break; } } if (bSubmit) { bool bSucceed = true; Json::Value jLiveness = Json::Value::null; jLiveness["status"] = m_sLivenessStatus.toStdString(); jLiveness["faceLiveVerifyId"] = g_appInfoPtr->m_oExamInfo.nFaceLiveVerifyId; jLiveness["processTime"] = m_nEndTime - m_nStartTime; for (int i = 0; i < m_livenessList.count(); ++i) { if (m_livenessList[i].sActionType == ACTION_TYPE::AT_FACE_DETECT) { jLiveness["examRecordDataId"] = g_appInfoPtr->m_oExamInfo.nExamRecordDataId; jLiveness["faceCount"] = m_livenessList[i].nFaceCount; jLiveness["realness"] = m_livenessList[i].nRealness; jLiveness["similarity"] = m_livenessList[i].fSimilarity; if (m_livenessList[i].nFaceCount == 0) { jLiveness["status"] = STATUS_TYPE::ST_NOT_ONESELF.toStdString(); } } else { Json::Value jAction = Json::Value::null; if (!m_livenessList[i].bPass) { bSucceed = false; jAction["errorMsg"] = m_livenessList[i].sErrorMsg.toStdString(); } jAction["fileUrl"] = m_livenessList[i].sUrl.toStdString(); jAction["pass"] = m_livenessList[i].bPass; jAction["processTime"] = m_livenessList[i].nEndTime - m_livenessList[i].nStartTime; jAction["retry"] = 0; jAction["type"] = m_livenessList[i].sActionType.toStdString(); jLiveness["actions"].append(jAction); } } qDebug() << jLiveness.toStyledString().c_str(); CHttpRequestPackage hrp; hrp.sUri = QString("/api/ecs_oe_student/client/exam/process/saveFaceLiveVerifyResult"); hrp.nRequestType = RequestType::rtSaveFaceLiveVerifyResult; hrp.eParamType = HttpParamType::hptCustomBody; hrp.sParamList.push_back(QString("CustomBody,%1").arg(jLiveness.toStyledString().c_str())); g_httpBllPtr->post(hrp); } } catch (const std::exception &e) { myDebug() << QString::fromLocal8Bit("人脸比对失败,%1").arg(e.what()); } } void faceLiveness::countdownTimer() { try { --m_nMaxSeconds; ui->label_fl_time->setText(QString("(%1)").arg(m_nMaxSeconds)); if (m_nMaxSeconds <= 0) { //整体超时 m_bStartCompare = false; m_ActionTimer->stop(); m_countdownTimer->stop(); { std::scoped_lock sl(m_livenessListMutex); m_livenessList[m_nCurIndex] = m_currentVerifyInfo; } m_sLivenessStatus = STATUS_TYPE::ST_TIME_OUT; saveLivenessResult(); } } catch (const std::exception &e) { myDebug() << QString::fromLocal8Bit("人脸比对失败,%1").arg(e.what()); } } void faceLiveness::actionTimer() { try { if (m_currentVerifyInfo.bIsVerify) { //当前比对完成 { std::scoped_lock sl(m_livenessListMutex); m_livenessList[m_nCurIndex] = m_currentVerifyInfo; } //下一个动作 ++m_nCurIndex; if (m_nCurIndex < m_livenessList.count()) { std::scoped_lock sl(m_livenessListMutex); m_currentVerifyInfo = m_livenessList[m_nCurIndex]; initAcionIcon(); { std::scoped_lock sl(m_imgMutex); m_imgList.clear(); } } else { //整体比对完成 m_sLivenessStatus = STATUS_TYPE::ST_SUCCESS; m_bStartCompare = false; m_ActionTimer->stop(); m_countdownTimer->stop(); saveLivenessResult(); return; } } else { if (m_currentVerifyInfo.nActionLeftSceonds <= 0) { //单个超时 m_bStartCompare = false; m_currentVerifyInfo.sErrorMsg = QString::fromLocal8Bit("action timeout"); m_ActionTimer->stop(); m_countdownTimer->stop(); { std::scoped_lock sl(m_livenessListMutex); m_livenessList[m_nCurIndex] = m_currentVerifyInfo; } m_sLivenessStatus = STATUS_TYPE::ST_ACTION_FAILED; saveLivenessResult(); return; } else { --m_currentVerifyInfo.nActionLeftSceonds; ui->btn_fl_time->setText(QString("%1s").arg(m_currentVerifyInfo.nActionLeftSceonds)); } } } catch (const std::exception &e) { myDebug() << QString::fromLocal8Bit("人脸比对失败,%1").arg(e.what()); } } //文件上传 void faceLiveness::onProcessUpload(CProcessUpload processUpload) { try { if(processUpload.sCommonStr == __FILE__) { if (processUpload.nCode == 200) { m_nRetryCount = 0; m_livenessList[m_nCurIndex].sUrl = processUpload.sFileUrl; saveLivenessResult(); } else { if (processUpload.sMessage.isEmpty()) { ShowMsg(QString::fromLocal8Bit("上传照片失败"), this, MSG_ICON_TYPE::mit_error); } else { ShowMsg(processUpload.sMessage, this, MSG_ICON_TYPE::mit_error); } if(m_nRetryCount < 4) { saveLivenessResult(); m_nRetryCount++; } else { emit faceLivenessFaild(); } } } } catch (const std::exception &e) { myDebug() << QString::fromLocal8Bit("人脸比对失败,%1").arg(e.what()); } } //保存人脸活体验证结果 void faceLiveness::onSaveFaceLiveVerifyResult(CBaseResponsePackage res) { try { if (res.nCode == 200) { if (m_pCloseTimer == nullptr) { m_pCloseTimer = std::make_shared(); m_pCloseTimer->setInterval(2000); connect(m_pCloseTimer.get(), &QTimer::timeout, this, [&]() { if (m_sLivenessStatus == STATUS_TYPE::ST_SUCCESS) { emit faceLivenessSucceed(); } else { emit faceLivenessFaild(); } }); } m_pCloseTimer->start(); if (m_sLivenessStatus == STATUS_TYPE::ST_SUCCESS) { ui->label_fl_hint->setText(QString::fromLocal8Bit("恭喜您完成检测!")); ui->label_fl_icon->setPixmap(QPixmap(":/images/icon-welcom.png")); } else { ui->label_fl_hint->setText(QString::fromLocal8Bit("检测失败:单个动作超时")); ui->label_fl_icon->setPixmap(QPixmap(":/images/icon-liveness-faild.png")); } ui->label_fl_hint->adjustSize(); ui->widget_fc_BG->setVisible(false); ui->widget_fl_hint->setVisible(true); ui->widget_fl_hint->setGeometry((width() - ui->label_fl_hint->width() - g_appInfoPtr->m_fRate * 180) / 2, (height() - g_appInfoPtr->m_fRate * 180) / 2, ui->label_fl_hint->width() + g_appInfoPtr->m_fRate * 180, g_appInfoPtr->m_fRate * 180); ui->label_fl_icon->setGeometry(g_appInfoPtr->m_fRate * 75, g_appInfoPtr->m_fRate * 70, g_appInfoPtr->m_fRate * 40, g_appInfoPtr->m_fRate * 40); ui->label_fl_hint->setGeometry(ui->label_fl_icon->x() + ui->label_fl_icon->width() + g_appInfoPtr->m_fRate * 20, ui->label_fl_icon->y() + (ui->label_fl_icon->height() - ui->label_fl_hint->height()) / 2, ui->label_fl_hint->width(), ui->label_fl_hint->height()); } else { if (res.sMessage.isEmpty()) { ShowMsg(QString::fromLocal8Bit("活体验证结果失败"), this, MSG_ICON_TYPE::mit_error); } else { ShowMsg(res.sMessage, this, MSG_ICON_TYPE::mit_error); } if(m_nRetryCount < 4) { saveLivenessResult(); m_nRetryCount++; } else { emit faceLivenessFaild(); } } } catch (const std::exception &e) { myDebug() << QString::fromLocal8Bit("人脸比对失败,%1").arg(e.what()); } }