|
@@ -11,9 +11,9 @@
|
|
|
#include "CCommonTools.h"
|
|
|
#include "CFaceRecProc.h"
|
|
|
|
|
|
-faceLiveness::faceLiveness(QWidget *parent) :
|
|
|
+faceLiveness::faceLiveness(FACE_LIVENESS_TYPE livenessType, QWidget *parent) :
|
|
|
QWidget(parent),
|
|
|
- ui(new Ui::faceLiveness)
|
|
|
+ ui(new Ui::faceLiveness), m_livenessType(livenessType)
|
|
|
{
|
|
|
ui->setupUi(this);
|
|
|
|
|
@@ -25,8 +25,18 @@ faceLiveness::faceLiveness(QWidget *parent) :
|
|
|
qRegisterMetaType<CProcessUpload>("CProcessUpload");
|
|
|
connect(g_httpBllPtr.get(), &CHttpBll::sgnProcessUpload, this, &faceLiveness::onProcessUpload);
|
|
|
connect(g_httpBllPtr.get(), &CHttpBll::sgnSaveFaceLiveVerifyResult, this, &faceLiveness::onSaveFaceLiveVerifyResult);
|
|
|
+ connect(g_httpBllPtr.get(), &CHttpBll::sgnSaveFaceCompareResult, this, &faceLiveness::onSaveFaceCompareResult);
|
|
|
|
|
|
- m_nMaxSeconds = 60;
|
|
|
+ if(m_livenessType == FACE_LIVENESS_TYPE::flt_inprogress)
|
|
|
+ {
|
|
|
+ ui->label_fl_time->setVisible(true);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ ui->label_fl_time->setVisible(false);
|
|
|
+ }
|
|
|
+
|
|
|
+ m_nMaxSeconds = g_appInfoPtr->m_oExamInfo.nAllActionDuration;
|
|
|
|
|
|
QString sFileName = g_appInfoPtr->m_sStudentPhotoPath.right(g_appInfoPtr->m_sStudentPhotoPath.length() - g_appInfoPtr->m_sStudentPhotoPath.lastIndexOf("/") - 1);
|
|
|
sFileName = g_appInfoPtr->m_sCacheFileDir + sFileName;
|
|
@@ -40,26 +50,6 @@ faceLiveness::faceLiveness(QWidget *parent) :
|
|
|
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<QTimer>();
|
|
|
-// 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<QTimer>();
|
|
|
m_pVideoTimer->setInterval(200);
|
|
|
connect(m_pVideoTimer.get(), &QTimer::timeout, this, [&](){
|
|
@@ -97,7 +87,7 @@ faceLiveness::faceLiveness(QWidget *parent) :
|
|
|
|
|
|
LivenessVerifyInfo lvif;
|
|
|
lvif.sActionType = ACTION_TYPE::AT_FACE_DETECT;
|
|
|
- lvif.nActionLeftSceonds = 60;
|
|
|
+ lvif.nActionLeftSceonds = m_nFaceDetectDuration;
|
|
|
m_livenessList.push_back(lvif);
|
|
|
m_currentVerifyInfo = lvif;
|
|
|
if(g_appInfoPtr->m_oExamInfo.sActionOrder == "FIXED")
|
|
@@ -136,6 +126,53 @@ faceLiveness::faceLiveness(QWidget *parent) :
|
|
|
|
|
|
m_bIsRun = true;
|
|
|
m_thread = std::thread(std::bind(&faceLiveness::threadProc, this));
|
|
|
+
|
|
|
+ m_initTimer = std::make_shared<QTimer>();
|
|
|
+ m_initTimer->setInterval(100);
|
|
|
+ connect(m_initTimer.get(), &QTimer::timeout, this, [&](){
|
|
|
+ m_initTimer->stop();
|
|
|
+ if(g_faceRecProcPtr == nullptr)
|
|
|
+ {
|
|
|
+ g_faceRecProcPtr = std::make_shared<CFaceRecProc>();
|
|
|
+
|
|
|
+ if (!g_appInfoPtr->m_sStudentPhotoPath.isEmpty())
|
|
|
+ {
|
|
|
+ if(!g_faceRecProcPtr->hasBaseImage())
|
|
|
+ {
|
|
|
+ if(!setBaseImage())
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ ShowMsg(QString::fromLocal8Bit("当前考试未底照"), this, MSG_ICON_TYPE::mit_error);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!g_faceRecProcPtr->hasBaseImage())
|
|
|
+ {
|
|
|
+ if(!setBaseImage())
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ m_bStartCompare = true;
|
|
|
+ m_fMaxYaw = 0;
|
|
|
+ m_fMinYaw = 0;
|
|
|
+ m_sLivenessStatus = STATUS_TYPE::ST_SUCCESS;
|
|
|
+
|
|
|
+ {
|
|
|
+ std::scoped_lock sl(m_livenessListMutex);
|
|
|
+ m_currentVerifyInfo = m_livenessList[m_nCurIndex];
|
|
|
+ }
|
|
|
+ initAcionIcon();
|
|
|
+ m_ActionTimer->start();
|
|
|
+ });
|
|
|
+ m_initTimer->start();
|
|
|
}
|
|
|
|
|
|
faceLiveness::~faceLiveness()
|
|
@@ -219,6 +256,11 @@ void faceLiveness::initUI()
|
|
|
ui->label_fl_hint->width(), ui->label_fl_hint->height());
|
|
|
|
|
|
ui->widget_fl_action->setVisible(false);
|
|
|
+
|
|
|
+ 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);
|
|
|
}
|
|
|
|
|
|
void faceLiveness::threadProc()
|
|
@@ -506,7 +548,7 @@ void faceLiveness::initAcionIcon()
|
|
|
{
|
|
|
movie = new QMovie(":/images/img-fl-face.png");
|
|
|
ui->label_fl_actionTips->setText(QString::fromLocal8Bit("请让我看到您的正脸"));
|
|
|
- ui->btn_fl_time->setVisible(false);
|
|
|
+ //ui->btn_fl_time->setVisible(false);
|
|
|
}
|
|
|
else if(m_currentVerifyInfo.sActionType == ACTION_TYPE::AT_BLINK)
|
|
|
{
|
|
@@ -618,18 +660,19 @@ void faceLiveness::countdownTimer()
|
|
|
{
|
|
|
--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();
|
|
|
+ if(m_livenessType == FACE_LIVENESS_TYPE::flt_inprogress && 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)
|
|
@@ -656,6 +699,7 @@ void faceLiveness::actionTimer()
|
|
|
{
|
|
|
std::scoped_lock sl(m_livenessListMutex);
|
|
|
m_currentVerifyInfo = m_livenessList[m_nCurIndex];
|
|
|
+ m_currentVerifyInfo.reset(m_livenessList[m_nCurIndex].sActionType == ACTION_TYPE ::AT_FACE_DETECT ? m_nFaceDetectDuration : g_appInfoPtr->m_oExamInfo.nActionDuration);
|
|
|
initAcionIcon();
|
|
|
{
|
|
|
std::scoped_lock sl(m_imgMutex);
|
|
@@ -678,23 +722,83 @@ void faceLiveness::actionTimer()
|
|
|
{
|
|
|
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;
|
|
|
+ ++m_nFaceRetryCount;
|
|
|
+ {
|
|
|
+ std::scoped_lock sl(m_imgMutex);
|
|
|
+ m_imgList.clear();
|
|
|
+ }
|
|
|
+
|
|
|
+ if(m_nFaceRetryCount >= m_nMaxFaceRetryCount)
|
|
|
+ {
|
|
|
+ if(m_nFaceWholeRetryCount >= m_nMaxFaceWholeRetryCount)
|
|
|
+ {
|
|
|
+ //整体失败
|
|
|
+ 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_TIME_OUT;
|
|
|
+ if(m_livenessType == FACE_LIVENESS_TYPE::flt_inprogress)
|
|
|
+ {
|
|
|
+ saveLivenessResult();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ showVerifyResultUI();
|
|
|
+ QTimer::singleShot(2000, this, [&]() {
|
|
|
+ emit faceLivenessFaild();
|
|
|
+ });
|
|
|
+
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ ++m_nFaceWholeRetryCount;
|
|
|
+ {
|
|
|
+ std::scoped_lock sl(m_imgMutex);
|
|
|
+ m_imgList.clear();
|
|
|
+ }
|
|
|
+
|
|
|
+ m_nFaceRetryCount = 0;
|
|
|
+ m_nCurIndex = 0;
|
|
|
+ if (m_nCurIndex < m_livenessList.count())
|
|
|
+ {
|
|
|
+ std::scoped_lock sl(m_livenessListMutex);
|
|
|
+ m_currentVerifyInfo = m_livenessList[m_nCurIndex];
|
|
|
+ m_currentVerifyInfo.reset(m_livenessList[m_nCurIndex].sActionType == ACTION_TYPE::AT_FACE_DETECT ? m_nFaceDetectDuration : g_appInfoPtr->m_oExamInfo.nActionDuration);
|
|
|
+ initAcionIcon();
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ ++m_nFaceRetryCount;
|
|
|
+ m_currentVerifyInfo.reset(m_currentVerifyInfo.sActionType == ACTION_TYPE::AT_FACE_DETECT ? m_nFaceDetectDuration : g_appInfoPtr->m_oExamInfo.nActionDuration);
|
|
|
+ initAcionIcon();
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
--m_currentVerifyInfo.nActionLeftSceonds;
|
|
|
ui->btn_fl_time->setText(QString("%1s").arg(m_currentVerifyInfo.nActionLeftSceonds));
|
|
|
+
|
|
|
+ if(m_currentVerifyInfo.sActionType == ACTION_TYPE::AT_FACE_DETECT)
|
|
|
+ {
|
|
|
+ if(m_currentVerifyInfo.nActionLeftSceonds == 50)
|
|
|
+ {
|
|
|
+ ShowMsg(QString::fromLocal8Bit("人脸检测不通过(请调整角度和光线进行尝试,不要戴眼镜)"), (QWidget*)this->parent());
|
|
|
+ }
|
|
|
+ else if(m_currentVerifyInfo.nActionLeftSceonds == 30)
|
|
|
+ {
|
|
|
+ ShowMsg(QString::fromLocal8Bit("人脸检测不通过(请调整角度和光线进行尝试,不要戴眼镜)"), (QWidget*)this->parent());
|
|
|
+ }
|
|
|
+ else if(m_currentVerifyInfo.nActionLeftSceonds == 1)
|
|
|
+ {
|
|
|
+ ShowMsg(QString::fromLocal8Bit("若多次尝试不通过,请联系老师更换照片后重试"), (QWidget*)this->parent());
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -715,7 +819,16 @@ void faceLiveness::onProcessUpload(CProcessUpload processUpload)
|
|
|
{
|
|
|
m_nRetryCount = 0;
|
|
|
m_livenessList[m_nCurIndex].sUrl = processUpload.sFileUrl;
|
|
|
- saveLivenessResult();
|
|
|
+ if(m_livenessType == FACE_LIVENESS_TYPE::flt_entry_exam &&
|
|
|
+ m_livenessList[m_nCurIndex].sActionType == ACTION_TYPE::AT_FACE_DETECT)
|
|
|
+ {
|
|
|
+ saveFaceCampareResult();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ saveLivenessResult();
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
else
|
|
|
{
|
|
@@ -746,6 +859,82 @@ void faceLiveness::onProcessUpload(CProcessUpload processUpload)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void faceLiveness::saveFaceCampareResult()
|
|
|
+{
|
|
|
+ CHttpRequestPackage hrp;
|
|
|
+ hrp.sUri = "/api/ecs_oe_student/client/exam/process/saveFaceCompareResult";
|
|
|
+ hrp.nRequestType = RequestType::rtSaveFaceCompareResult;
|
|
|
+ Json::Value jBody = Json::Value::null;
|
|
|
+ jBody["faceCompareResult"] = QString::number(m_livenessList[m_nCurIndex].fSimilarity).toStdString();
|
|
|
+ jBody["fileUrl"] = m_livenessList[m_nCurIndex].sUrl.toStdString();
|
|
|
+ jBody["pass"] = true;
|
|
|
+ jBody["processTime"] = m_livenessList[m_nCurIndex].nEndTime - m_livenessList[m_nCurIndex].nStartTime;
|
|
|
+ jBody["stranger"] = m_livenessList[m_nCurIndex].nFaceCount > 1;
|
|
|
+ hrp.sParamList.push_back(QString("CustomBody,%1").arg(jBody.toStyledString().c_str()));
|
|
|
+ hrp.eParamType = HttpParamType::hptCustomBody;
|
|
|
+
|
|
|
+ g_httpBllPtr->post(hrp);
|
|
|
+}
|
|
|
+
|
|
|
+void faceLiveness::onSaveFaceCompareResult(CBaseResponsePackage res)
|
|
|
+{
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if(res.nCode == 200)
|
|
|
+ {
|
|
|
+ m_nRetryCount = 0;
|
|
|
+ saveLivenessResult();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if(m_nRetryCount < 4)
|
|
|
+ {
|
|
|
+ saveFaceCampareResult();
|
|
|
+ m_nRetryCount++;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ emit faceLivenessFaild();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (const std::exception &e)
|
|
|
+ {
|
|
|
+ ShowMsg(QString::fromLocal8Bit("保存人脸识别信息失败"), this, MSG_ICON_TYPE::mit_error);
|
|
|
+ myServerLog()<<"exception error"<<e.what();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void faceLiveness::showVerifyResultUI()
|
|
|
+{
|
|
|
+ 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 if(m_sLivenessStatus == STATUS_TYPE::ST_TIME_OUT)
|
|
|
+ {
|
|
|
+ ui->label_fl_hint->setText(QString::fromLocal8Bit("检测失败:活体检测超时"));
|
|
|
+ ui->label_fl_icon->setPixmap(QPixmap(":/images/icon-liveness-faild.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());
|
|
|
+}
|
|
|
+
|
|
|
//保存人脸活体验证结果
|
|
|
void faceLiveness::onSaveFaceLiveVerifyResult(CBaseResponsePackage res)
|
|
|
{
|
|
@@ -769,27 +958,10 @@ void faceLiveness::onSaveFaceLiveVerifyResult(CBaseResponsePackage res)
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+ showVerifyResultUI();
|
|
|
+
|
|
|
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
|