faceLiveness.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821
  1. #include "faceLiveness.h"
  2. #include "ui_faceLiveness.h"
  3. #include "CAppInfo.h"
  4. #include <QDesktopWidget>
  5. #include <QFile>
  6. #include <QFileInfo>
  7. #include "awMsgBox.h"
  8. #include "logproc.h"
  9. #include "CCommonTools.h"
  10. #include "CFaceRecProc.h"
  11. faceLiveness::faceLiveness(QWidget *parent) :
  12. QWidget(parent),
  13. ui(new Ui::faceLiveness)
  14. {
  15. ui->setupUi(this);
  16. setStyleSheet(g_appInfoPtr->m_sQssStr);
  17. initUI();
  18. qRegisterMetaType<CBaseResponsePackage>("CBaseResponsePackage");
  19. qRegisterMetaType<CProcessUpload>("CProcessUpload");
  20. connect(g_httpBllPtr.get(), &CHttpBll::sgnProcessUpload, this, &faceLiveness::onProcessUpload);
  21. connect(g_httpBllPtr.get(), &CHttpBll::sgnSaveFaceLiveVerifyResult, this, &faceLiveness::onSaveFaceLiveVerifyResult);
  22. m_nMaxSeconds = 60;
  23. QString sFileName = g_appInfoPtr->m_sStudentPhotoPath.right(g_appInfoPtr->m_sStudentPhotoPath.length() - g_appInfoPtr->m_sStudentPhotoPath.lastIndexOf("/") - 1);
  24. sFileName = g_appInfoPtr->m_sCacheFileDir + sFileName;
  25. if(!QFile::exists(sFileName))
  26. {
  27. CHttpRequestPackage hrp;
  28. hrp.sUri = g_appInfoPtr->m_sStudentPhotoPath;
  29. hrp.sCommonStr = sFileName;
  30. hrp.nRequestType = RequestType::rtDownLoadFile;
  31. hrp.nRetryCount = 3;
  32. g_httpBllPtr->downLoad(hrp);
  33. }
  34. // m_cam.set(CV_CAP_PROP_FOURCC, CV_FOURCC('M', 'J', 'P', 'G'));
  35. // int inWidth = ui->widget_fc_camera->width();
  36. // m_cam.set(CV_CAP_PROP_FRAME_WIDTH, inWidth);
  37. // int inHeight = ui->widget_fc_camera->height();
  38. // m_cam.set(CV_CAP_PROP_FRAME_HEIGHT, inHeight);
  39. // m_cam.set(CV_CAP_PROP_FPS, 5);
  40. // m_pinitTimer = std::make_shared<QTimer>();
  41. // m_pinitTimer->setInterval(1000);
  42. // connect(m_pinitTimer.get(), &QTimer::timeout, this, [&](){
  43. // m_pinitTimer->stop();
  44. // if(!m_cam.open(0))
  45. // {
  46. // ShowMsg(QString::fromLocal8Bit("打开摄像头失败"), this, MSG_ICON_TYPE::mit_error);
  47. // return;
  48. // }
  49. // m_pVideoTimer->start();
  50. // });
  51. m_pVideoTimer = std::make_shared<QTimer>();
  52. m_pVideoTimer->setInterval(200);
  53. connect(m_pVideoTimer.get(), &QTimer::timeout, this, [&](){
  54. cv::Mat frame;
  55. {
  56. std::scoped_lock sl(m_imageMutex);
  57. frame = m_nCurImage;
  58. }
  59. QImage img = CCommonTools::Mat2QImage(frame);
  60. ui->widget_fc_camera->setAutoFillBackground(true);
  61. QPalette palette;
  62. palette.setBrush(QPalette::Window, QBrush(img.scaled(ui->widget_fc_camera->width(), ui->widget_fc_camera->height())));
  63. ui->widget_fc_camera->setPalette(palette);
  64. if(m_bStartCompare)
  65. {
  66. std::scoped_lock sl(m_imgMutex);
  67. m_imgList.push_back(frame);
  68. }
  69. });
  70. g_clientVideoProcPtr->startTest(this);
  71. m_pVideoTimer->start();
  72. //生成动作列表
  73. QStringList sActionList = g_appInfoPtr->m_oExamInfo.sActionOptions.split(",");
  74. if(sActionList.count() != g_appInfoPtr->m_oExamInfo.nActionNum)
  75. {
  76. ShowMsg(QString::fromLocal8Bit("初始化活体动作失败"), this, MSG_ICON_TYPE::mit_error);
  77. emit faceLivenessFaild();
  78. return;
  79. }
  80. LivenessVerifyInfo lvif;
  81. lvif.sActionType = ACTION_TYPE::AT_FACE_DETECT;
  82. lvif.nActionLeftSceonds = 60;
  83. m_livenessList.push_back(lvif);
  84. m_currentVerifyInfo = lvif;
  85. if(g_appInfoPtr->m_oExamInfo.sActionOrder == "FIXED")
  86. {
  87. for(QString sAction : sActionList)
  88. {
  89. LivenessVerifyInfo lvi;
  90. lvi.sActionType = sAction;
  91. lvi.nActionLeftSceonds = g_appInfoPtr->m_oExamInfo.nActionDuration;
  92. m_livenessList.push_back(lvi);
  93. }
  94. }
  95. else
  96. {
  97. QList<int> list;
  98. CCommonTools::genRandomNumber(list, g_appInfoPtr->m_oExamInfo.nActionNum);
  99. for(int i = 0; i < g_appInfoPtr->m_oExamInfo.nActionNum; i++)
  100. {
  101. LivenessVerifyInfo lvi;
  102. lvi.sActionType = sActionList[list[i]-1];
  103. lvi.nActionLeftSceonds = g_appInfoPtr->m_oExamInfo.nActionDuration;
  104. m_livenessList.push_back(lvi);
  105. }
  106. }
  107. m_nCurIndex = 0;
  108. m_ActionTimer = std::make_shared<QTimer>();
  109. m_ActionTimer->setInterval(1000);
  110. connect(m_ActionTimer.get(), &QTimer::timeout, this, &faceLiveness::actionTimer);
  111. m_countdownTimer = std::make_shared<QTimer>();
  112. m_countdownTimer->setInterval(1000);
  113. connect(m_countdownTimer.get(), &QTimer::timeout, this, &faceLiveness::countdownTimer);
  114. m_countdownTimer->start();
  115. m_bIsRun = true;
  116. m_thread = std::thread(std::bind(&faceLiveness::threadProc, this));
  117. }
  118. faceLiveness::~faceLiveness()
  119. {
  120. m_pVideoTimer->stop();
  121. m_ActionTimer->stop();
  122. g_clientVideoProcPtr->stopTest();
  123. m_bIsRun = false;
  124. m_thread.join();
  125. awMsgBox::clear(this);
  126. delete ui;
  127. }
  128. void faceLiveness::onRenderVideoFrame(const char* userId, TRTCVideoStreamType streamType, TRTCVideoFrame* frame)
  129. {
  130. if(g_clientVideoProcPtr->isCameraTest())
  131. {
  132. __int64 nServerTime = g_appInfoPtr->serverMTime();
  133. if(nServerTime - m_lastFaceTime >= 100)
  134. {
  135. m_lastFaceTime = nServerTime;
  136. cv::Mat matImg;
  137. cv::cvtColor(cv::Mat(frame->height, frame->width, CV_8UC4, frame->data), matImg, CV_RGBA2RGB);
  138. if(matImg.empty())
  139. {
  140. qDebug()<<"widgetCameraTest frame is empty";
  141. return;
  142. }
  143. std::scoped_lock sl(m_imageMutex);
  144. m_nCurImage = matImg;
  145. }
  146. }
  147. }
  148. void faceLiveness::initUI()
  149. {
  150. QDesktopWidget *dekwiget = QApplication::desktop();
  151. setGeometry(0, 0, dekwiget->width(), dekwiget->height());
  152. ui->widget_mask->setGeometry(0, 0, dekwiget->width(), dekwiget->height());
  153. ui->widget_fc_BG->setGeometry((width() - g_appInfoPtr->m_fRate*800)/2, (height() - g_appInfoPtr->m_fRate*536)/2,
  154. g_appInfoPtr->m_fRate*800, g_appInfoPtr->m_fRate*536);
  155. ui->label_fl_title->adjustSize();
  156. ui->label_fl_title->setGeometry(g_appInfoPtr->m_fRate*20, g_appInfoPtr->m_fRate*20,
  157. ui->label_fl_title->width(), ui->label_fl_title->height());
  158. ui->label_fl_time->setGeometry(ui->label_fl_title->x() + ui->label_fl_title->width(), ui->label_fl_title->y(),
  159. g_appInfoPtr->m_fRate*200, ui->label_fl_title->height());
  160. ui->btn_fc_close->setGeometry(ui->widget_fc_BG->width() - g_appInfoPtr->m_fRate*(20 + 16),
  161. g_appInfoPtr->m_fRate*16, g_appInfoPtr->m_fRate*16, g_appInfoPtr->m_fRate*16);
  162. ui->btn_fc_close->setVisible(false);
  163. ui->widget_fc_camera->setGeometry(g_appInfoPtr->m_fRate*30, g_appInfoPtr->m_fRate*75,
  164. g_appInfoPtr->m_fRate*740, g_appInfoPtr->m_fRate*320);
  165. ui->btn_fl_startVerify->setGeometry((ui->widget_fc_camera->width() - g_appInfoPtr->m_fRate*160)/2,
  166. ui->widget_fc_camera->y() + ui->widget_fc_camera->height() + g_appInfoPtr->m_fRate*30,
  167. g_appInfoPtr->m_fRate*160, g_appInfoPtr->m_fRate*40);
  168. ui->label_fl_tips->adjustSize();
  169. 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,
  170. ui->label_fl_tips->width(), ui->label_fl_tips ->height());
  171. ui->label_fl_actionMoive->setGeometry(0, 0, g_appInfoPtr->m_fRate*64, g_appInfoPtr->m_fRate*64);
  172. ui->label_fl_actionTips->adjustSize();
  173. int nActionWidth = ui->label_fl_actionMoive->width() + g_appInfoPtr->m_fRate*20 + ui->label_fl_actionTips->width() +
  174. g_appInfoPtr->m_fRate*20 + g_appInfoPtr->m_fRate*44;
  175. ui->widget_fl_action->setGeometry((ui->widget_fc_camera->width() - nActionWidth)/2, g_appInfoPtr->m_fRate*10,
  176. nActionWidth, g_appInfoPtr->m_fRate*64) ;
  177. ui->label_fl_actionTips->setGeometry(ui->label_fl_actionMoive->x() + ui->label_fl_actionMoive->width() + g_appInfoPtr->m_fRate*20,
  178. (ui->widget_fl_action->height() - ui->label_fl_actionTips->height())/2,
  179. ui->label_fl_actionTips->width(), ui->label_fl_actionTips->height());
  180. ui->btn_fl_time->setGeometry(ui->label_fl_actionTips->x() + ui->label_fl_actionTips->width() + g_appInfoPtr->m_fRate*20,
  181. (ui->widget_fl_action->height() - g_appInfoPtr->m_fRate*40)/2, g_appInfoPtr->m_fRate*40, g_appInfoPtr->m_fRate*40);
  182. ui->widget_fl_hint->setVisible(false);
  183. ui->widget_fl_hint->setGeometry((width() - g_appInfoPtr->m_fRate*400)/2, (height() - g_appInfoPtr->m_fRate*180)/2,
  184. g_appInfoPtr->m_fRate*400, g_appInfoPtr->m_fRate*180);
  185. 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);
  186. ui->label_fl_hint->adjustSize();
  187. ui->label_fl_hint->setGeometry(ui->label_fl_icon->x() + ui->label_fl_icon->width() + g_appInfoPtr->m_fRate*20,
  188. ui->label_fl_icon->y() + (ui->label_fl_icon->height() - ui->label_fl_hint->height())/2,
  189. ui->label_fl_hint->width(), ui->label_fl_hint->height());
  190. ui->widget_fl_action->setVisible(false);
  191. }
  192. void faceLiveness::threadProc()
  193. {
  194. try
  195. {
  196. while (m_bIsRun)
  197. {
  198. if (m_bStartCompare)
  199. {
  200. if (m_imgList.begin() != m_imgList.end())
  201. {
  202. myDebug() << "m_imgList:" << m_imgList.size();
  203. cv::Mat matImage;
  204. {
  205. std::scoped_lock lock(m_imgMutex);
  206. if (m_imgList.begin() != m_imgList.end())
  207. {
  208. matImage = (*m_imgList.begin()).clone();
  209. m_imgList.erase(m_imgList.begin());
  210. }
  211. else
  212. {
  213. continue;
  214. }
  215. }
  216. if (matImage.empty())
  217. {
  218. myDebug() << "matImage.empty";
  219. continue;
  220. }
  221. if (!m_currentVerifyInfo.bIsVerify)
  222. {
  223. verifyAction(matImage);
  224. }
  225. }
  226. }
  227. else
  228. {
  229. Sleep(100);
  230. }
  231. }
  232. }
  233. catch (const std::exception &e)
  234. {
  235. myDebug()<<QString::fromLocal8Bit("人脸比对失败,%1").arg(e.what());
  236. }
  237. }
  238. void faceLiveness::verifyAction(cv::Mat matImage)
  239. {
  240. try
  241. {
  242. bool bHasStatus = false;
  243. int nFaceCount = 0;
  244. float fScore = 0;
  245. if (m_currentVerifyInfo.bIsVerify)
  246. {
  247. return;
  248. }
  249. m_currentVerifyInfo.matImage = matImage;
  250. if (m_currentVerifyInfo.sActionType == ACTION_TYPE::AT_FACE_DETECT)
  251. {
  252. SeetaRect rt;
  253. if (!g_faceRecProcPtr->compareWithBase(matImage, nFaceCount, fScore, rt))
  254. {
  255. m_currentVerifyInfo.sErrorMsg = g_faceRecProcPtr->errorMsg();
  256. myServerLog() << g_faceRecProcPtr->errorMsg();
  257. return;
  258. }
  259. m_currentVerifyInfo.nFaceCount = nFaceCount;
  260. m_currentVerifyInfo.fSimilarity = fScore;
  261. if (nFaceCount != 1)
  262. {
  263. myServerLog() << QString::fromLocal8Bit("活体检测人脸数量异常,") << nFaceCount;
  264. m_currentVerifyInfo.sErrorMsg = QString::fromLocal8Bit("活体检测人脸数量异常,").arg(nFaceCount);
  265. return;
  266. }
  267. if (fScore * 100 > g_appInfoPtr->m_oExamInfo.nWarnThreshold)
  268. {
  269. bool bRealness = false;
  270. if (!g_faceRecProcPtr->faceRealness(matImage, bRealness))
  271. {
  272. myServerLog() << g_faceRecProcPtr->errorMsg();
  273. m_currentVerifyInfo.sErrorMsg = g_faceRecProcPtr->errorMsg();
  274. return;
  275. }
  276. //验证成功
  277. if (bRealness)
  278. {
  279. m_currentVerifyInfo.nEndTime = g_appInfoPtr->serverMTime();
  280. m_currentVerifyInfo.nRealness = 1;
  281. m_currentVerifyInfo.bPass = true;
  282. m_currentVerifyInfo.bIsVerify = true;
  283. myServerLog() << m_currentVerifyInfo.sActionType << ":" << fScore;
  284. return;
  285. }
  286. else
  287. {
  288. m_currentVerifyInfo.nRealness = 0;
  289. }
  290. }
  291. }
  292. if (m_currentVerifyInfo.sActionType == ACTION_TYPE::AT_BLINK ||
  293. m_currentVerifyInfo.sActionType == ACTION_TYPE::AT_NOD)
  294. {
  295. int nFaceStatus = 0;
  296. if (m_currentVerifyInfo.sActionType == ACTION_TYPE::AT_BLINK)
  297. {
  298. nFaceStatus = SL_EYE_CLOSE;
  299. }
  300. else
  301. {
  302. nFaceStatus = SL_HEAD_DOWN;
  303. }
  304. if (!g_faceRecProcPtr->getFaceAttribute(matImage, nFaceStatus, bHasStatus, nFaceCount))
  305. {
  306. myServerLog() << g_faceRecProcPtr->errorMsg();
  307. m_currentVerifyInfo.sErrorMsg = g_faceRecProcPtr->errorMsg();
  308. return;
  309. }
  310. m_currentVerifyInfo.nFaceCount = nFaceCount;
  311. if (nFaceCount != 1)
  312. {
  313. myServerLog() << QString::fromLocal8Bit("活体检测人脸数量异常,") << nFaceCount;
  314. m_currentVerifyInfo.sErrorMsg = QString::fromLocal8Bit("活体检测人脸数量异常,").arg(nFaceCount);
  315. return;
  316. }
  317. if (bHasStatus)
  318. {
  319. //验证成功
  320. m_currentVerifyInfo.nEndTime = g_appInfoPtr->serverMTime();
  321. m_currentVerifyInfo.nRealness = 1;
  322. m_currentVerifyInfo.bPass = true;
  323. m_currentVerifyInfo.bIsVerify = true;
  324. }
  325. }
  326. else if (m_currentVerifyInfo.sActionType == ACTION_TYPE::AT_SHAKE)
  327. {
  328. float fYaw = 0;
  329. float fPitch = 0;
  330. float fRoll = 0;
  331. int nFaceCount = 0;
  332. if (!g_faceRecProcPtr->getFaceAttribute(matImage, fYaw, fPitch, fRoll, nFaceCount))
  333. {
  334. myServerLog() << g_faceRecProcPtr->errorMsg();
  335. m_currentVerifyInfo.sErrorMsg = g_faceRecProcPtr->errorMsg();
  336. return;
  337. }
  338. m_currentVerifyInfo.nFaceCount = nFaceCount;
  339. if (m_fMinYaw > fYaw)
  340. {
  341. m_fMinYaw = fYaw;
  342. }
  343. if (m_fMaxYaw < fYaw)
  344. {
  345. m_fMaxYaw = fYaw;
  346. }
  347. if (m_fMaxYaw - m_fMinYaw > 30)
  348. {
  349. //验证成功
  350. m_currentVerifyInfo.nEndTime = g_appInfoPtr->serverMTime();
  351. m_currentVerifyInfo.nRealness = 1;
  352. m_currentVerifyInfo.bPass = true;
  353. m_currentVerifyInfo.bIsVerify = true;
  354. }
  355. }
  356. }
  357. catch (const std::exception &e)
  358. {
  359. myDebug() << QString::fromLocal8Bit("人脸比对失败,%1").arg(e.what());
  360. }
  361. }
  362. void faceLiveness::on_btn_fc_close_clicked()
  363. {
  364. }
  365. bool faceLiveness::setBaseImage()
  366. {
  367. QString sFileName = g_appInfoPtr->m_sStudentPhotoPath.right(g_appInfoPtr->m_sStudentPhotoPath.length() - g_appInfoPtr->m_sStudentPhotoPath.lastIndexOf("/") - 1);
  368. sFileName = g_appInfoPtr->m_sCacheFileDir + sFileName;
  369. if(!QFile::exists(sFileName))
  370. {
  371. ShowMsg(QString::fromLocal8Bit("底照下载失败,请检查网络"), this, MSG_ICON_TYPE::mit_error);
  372. return false;
  373. }
  374. QFileInfo filePath(sFileName);
  375. if(!g_faceRecProcPtr->setBaseImage(filePath.absoluteFilePath()))
  376. {
  377. //g_faceRecProcPtr->errorMsg()
  378. ShowMsg(QString::fromLocal8Bit("底照不符合要求,请更换照片"), this, MSG_ICON_TYPE::mit_error);
  379. return false;
  380. }
  381. return true;
  382. }
  383. void faceLiveness::on_btn_fl_startVerify_clicked()
  384. {
  385. if(g_faceRecProcPtr == nullptr)
  386. {
  387. g_faceRecProcPtr = std::make_shared<CFaceRecProc>();
  388. if (!g_appInfoPtr->m_sStudentPhotoPath.isEmpty())
  389. {
  390. if(!g_faceRecProcPtr->hasBaseImage())
  391. {
  392. if(!setBaseImage())
  393. {
  394. return;
  395. }
  396. }
  397. // QString sFileName = g_appInfoPtr->m_sStudentPhotoPath.right(g_appInfoPtr->m_sStudentPhotoPath.length() - g_appInfoPtr->m_sStudentPhotoPath.lastIndexOf("/") - 1);
  398. // sFileName = g_appInfoPtr->m_sCacheFileDir + sFileName;
  399. // if(!QFile::exists(sFileName))
  400. // {
  401. // ShowMsg(QString::fromLocal8Bit("底照下载失败,请检查网络"), this, MSG_ICON_TYPE::mit_error);
  402. // return;
  403. // }
  404. // if(!g_faceRecProcPtr->setBaseImage(sFileName))
  405. // {
  406. // ShowMsg(g_faceRecProcPtr->errorMsg(), this, MSG_ICON_TYPE::mit_error);
  407. // return;
  408. // }
  409. }
  410. else
  411. {
  412. ShowMsg(QString::fromLocal8Bit("当前考试未底照"), this, MSG_ICON_TYPE::mit_error);
  413. return;
  414. }
  415. }
  416. if(!g_faceRecProcPtr->hasBaseImage())
  417. {
  418. if(!setBaseImage())
  419. {
  420. return;
  421. }
  422. }
  423. m_bStartCompare = true;
  424. m_fMaxYaw = 0;
  425. m_fMinYaw = 0;
  426. m_sLivenessStatus = STATUS_TYPE::ST_SUCCESS;
  427. ui->btn_fl_startVerify->setVisible(false);
  428. ui->label_fl_tips->setVisible(false);
  429. ui->widget_fc_camera->setFixedHeight(g_appInfoPtr->m_fRate*431);
  430. ui->widget_fl_action->setVisible(true);
  431. {
  432. std::scoped_lock sl(m_livenessListMutex);
  433. m_currentVerifyInfo = m_livenessList[m_nCurIndex];
  434. }
  435. initAcionIcon();
  436. m_ActionTimer->start();
  437. }
  438. void faceLiveness::initAcionIcon()
  439. {
  440. QMovie *movie;
  441. ui->btn_fl_time->setVisible(true);
  442. ui->btn_fl_time->setText(QString("%1s").arg(m_currentVerifyInfo.nActionLeftSceonds));
  443. if(m_currentVerifyInfo.sActionType == ACTION_TYPE::AT_FACE_DETECT)
  444. {
  445. movie = new QMovie(":/images/img-fl-face.png");
  446. ui->label_fl_actionTips->setText(QString::fromLocal8Bit("请让我看到您的正脸"));
  447. ui->btn_fl_time->setVisible(false);
  448. }
  449. else if(m_currentVerifyInfo.sActionType == ACTION_TYPE::AT_BLINK)
  450. {
  451. movie = new QMovie(":/images/gif-close-eyes.gif");
  452. ui->label_fl_actionTips->setText(QString::fromLocal8Bit("请闭眼"));
  453. }
  454. else if(m_currentVerifyInfo.sActionType == ACTION_TYPE::AT_SHAKE)
  455. {
  456. movie = new QMovie(":/images/gif-turn-head.gif");
  457. ui->label_fl_actionTips->setText(QString::fromLocal8Bit("请摇头"));
  458. }
  459. else if(m_currentVerifyInfo.sActionType == ACTION_TYPE::AT_NOD)
  460. {
  461. movie = new QMovie(":/images/gif-head-down.gif");
  462. ui->label_fl_actionTips->setText(QString::fromLocal8Bit("请点头"));
  463. }
  464. ui->label_fl_actionMoive->setMovie(movie);
  465. movie->start();
  466. }
  467. void faceLiveness::saveLivenessResult()
  468. {
  469. try
  470. {
  471. bool bSubmit = true;
  472. for (int i = 0; i < m_livenessList.count(); ++i)
  473. {
  474. if (!m_livenessList[i].matImage.empty() &&
  475. m_livenessList[i].sUrl.isEmpty())
  476. {
  477. bSubmit = false;
  478. m_nCurIndex = i;
  479. m_currentVerifyInfo = m_livenessList[i];
  480. QString sImageFile = QString("temp/photo/%1.png").arg(CCommonTools::getUuid());
  481. QImage img = CCommonTools::Mat2QImage(m_currentVerifyInfo.matImage);
  482. img.save(sImageFile, "PNG");
  483. //上传图片
  484. CHttpRequestPackage hrp;
  485. hrp.sUri = "/api/ecs_oe_student/client/exam/process/upload";
  486. hrp.nRequestType = RequestType::rtProcessUpload;
  487. hrp.sCommonStr = __FILE__;
  488. hrp.sParamList.push_back(QString("formdataFileType,file,%1").arg(sImageFile));
  489. hrp.sParamList.push_back(QString("md5,%1").arg(CCommonTools::fileMd5(sImageFile)));
  490. hrp.eParamType = HttpParamType::hptFormdata;
  491. g_httpBllPtr->post(hrp);
  492. break;
  493. }
  494. }
  495. if (bSubmit)
  496. {
  497. bool bSucceed = true;
  498. Json::Value jLiveness = Json::Value::null;
  499. jLiveness["status"] = m_sLivenessStatus.toStdString();
  500. jLiveness["faceLiveVerifyId"] = g_appInfoPtr->m_oExamInfo.nFaceLiveVerifyId;
  501. jLiveness["processTime"] = m_nEndTime - m_nStartTime;
  502. for (int i = 0; i < m_livenessList.count(); ++i)
  503. {
  504. if (m_livenessList[i].sActionType == ACTION_TYPE::AT_FACE_DETECT)
  505. {
  506. jLiveness["examRecordDataId"] = g_appInfoPtr->m_oExamInfo.nExamRecordDataId;
  507. jLiveness["faceCount"] = m_livenessList[i].nFaceCount;
  508. jLiveness["realness"] = m_livenessList[i].nRealness;
  509. jLiveness["similarity"] = m_livenessList[i].fSimilarity;
  510. if (m_livenessList[i].nFaceCount == 0)
  511. {
  512. jLiveness["status"] = STATUS_TYPE::ST_NOT_ONESELF.toStdString();
  513. }
  514. }
  515. else
  516. {
  517. Json::Value jAction = Json::Value::null;
  518. if (!m_livenessList[i].bPass)
  519. {
  520. bSucceed = false;
  521. jAction["errorMsg"] = m_livenessList[i].sErrorMsg.toStdString();
  522. }
  523. jAction["fileUrl"] = m_livenessList[i].sUrl.toStdString();
  524. jAction["pass"] = m_livenessList[i].bPass;
  525. jAction["processTime"] = m_livenessList[i].nEndTime - m_livenessList[i].nStartTime;
  526. jAction["retry"] = 0;
  527. jAction["type"] = m_livenessList[i].sActionType.toStdString();
  528. jLiveness["actions"].append(jAction);
  529. }
  530. }
  531. qDebug() << jLiveness.toStyledString().c_str();
  532. CHttpRequestPackage hrp;
  533. hrp.sUri = QString("/api/ecs_oe_student/client/exam/process/saveFaceLiveVerifyResult");
  534. hrp.nRequestType = RequestType::rtSaveFaceLiveVerifyResult;
  535. hrp.eParamType = HttpParamType::hptCustomBody;
  536. hrp.sParamList.push_back(QString("CustomBody,%1").arg(jLiveness.toStyledString().c_str()));
  537. g_httpBllPtr->post(hrp);
  538. }
  539. }
  540. catch (const std::exception &e)
  541. {
  542. myDebug() << QString::fromLocal8Bit("人脸比对失败,%1").arg(e.what());
  543. }
  544. }
  545. void faceLiveness::countdownTimer()
  546. {
  547. try
  548. {
  549. --m_nMaxSeconds;
  550. ui->label_fl_time->setText(QString("(%1)").arg(m_nMaxSeconds));
  551. if (m_nMaxSeconds <= 0)
  552. {
  553. //整体超时
  554. m_bStartCompare = false;
  555. m_ActionTimer->stop();
  556. m_countdownTimer->stop();
  557. {
  558. std::scoped_lock sl(m_livenessListMutex);
  559. m_livenessList[m_nCurIndex] = m_currentVerifyInfo;
  560. }
  561. m_sLivenessStatus = STATUS_TYPE::ST_TIME_OUT;
  562. saveLivenessResult();
  563. }
  564. }
  565. catch (const std::exception &e)
  566. {
  567. myDebug() << QString::fromLocal8Bit("人脸比对失败,%1").arg(e.what());
  568. }
  569. }
  570. void faceLiveness::actionTimer()
  571. {
  572. try
  573. {
  574. if (m_currentVerifyInfo.bIsVerify)
  575. {
  576. //当前比对完成
  577. {
  578. std::scoped_lock sl(m_livenessListMutex);
  579. m_livenessList[m_nCurIndex] = m_currentVerifyInfo;
  580. }
  581. //下一个动作
  582. ++m_nCurIndex;
  583. if (m_nCurIndex < m_livenessList.count())
  584. {
  585. std::scoped_lock sl(m_livenessListMutex);
  586. m_currentVerifyInfo = m_livenessList[m_nCurIndex];
  587. initAcionIcon();
  588. {
  589. std::scoped_lock sl(m_imgMutex);
  590. m_imgList.clear();
  591. }
  592. }
  593. else
  594. {
  595. //整体比对完成
  596. m_sLivenessStatus = STATUS_TYPE::ST_SUCCESS;
  597. m_bStartCompare = false;
  598. m_ActionTimer->stop();
  599. m_countdownTimer->stop();
  600. saveLivenessResult();
  601. return;
  602. }
  603. }
  604. else
  605. {
  606. if (m_currentVerifyInfo.nActionLeftSceonds <= 0)
  607. {
  608. //单个超时
  609. m_bStartCompare = false;
  610. m_currentVerifyInfo.sErrorMsg = QString::fromLocal8Bit("action timeout");
  611. m_ActionTimer->stop();
  612. m_countdownTimer->stop();
  613. {
  614. std::scoped_lock sl(m_livenessListMutex);
  615. m_livenessList[m_nCurIndex] = m_currentVerifyInfo;
  616. }
  617. m_sLivenessStatus = STATUS_TYPE::ST_ACTION_FAILED;
  618. saveLivenessResult();
  619. return;
  620. }
  621. else
  622. {
  623. --m_currentVerifyInfo.nActionLeftSceonds;
  624. ui->btn_fl_time->setText(QString("%1s").arg(m_currentVerifyInfo.nActionLeftSceonds));
  625. }
  626. }
  627. }
  628. catch (const std::exception &e)
  629. {
  630. myDebug() << QString::fromLocal8Bit("人脸比对失败,%1").arg(e.what());
  631. }
  632. }
  633. //文件上传
  634. void faceLiveness::onProcessUpload(CProcessUpload processUpload)
  635. {
  636. try
  637. {
  638. if(processUpload.sCommonStr == __FILE__)
  639. {
  640. if (processUpload.nCode == 200)
  641. {
  642. m_nRetryCount = 0;
  643. m_livenessList[m_nCurIndex].sUrl = processUpload.sFileUrl;
  644. saveLivenessResult();
  645. }
  646. else
  647. {
  648. if (processUpload.sMessage.isEmpty())
  649. {
  650. ShowMsg(QString::fromLocal8Bit("上传照片失败"), this, MSG_ICON_TYPE::mit_error);
  651. }
  652. else
  653. {
  654. ShowMsg(processUpload.sMessage, this, MSG_ICON_TYPE::mit_error);
  655. }
  656. if(m_nRetryCount < 4)
  657. {
  658. saveLivenessResult();
  659. m_nRetryCount++;
  660. }
  661. else
  662. {
  663. emit faceLivenessFaild();
  664. }
  665. }
  666. }
  667. }
  668. catch (const std::exception &e)
  669. {
  670. myDebug() << QString::fromLocal8Bit("人脸比对失败,%1").arg(e.what());
  671. }
  672. }
  673. //保存人脸活体验证结果
  674. void faceLiveness::onSaveFaceLiveVerifyResult(CBaseResponsePackage res)
  675. {
  676. try
  677. {
  678. if (res.nCode == 200)
  679. {
  680. if (m_pCloseTimer == nullptr)
  681. {
  682. m_pCloseTimer = std::make_shared<QTimer>();
  683. m_pCloseTimer->setInterval(2000);
  684. connect(m_pCloseTimer.get(), &QTimer::timeout, this, [&]() {
  685. if (m_sLivenessStatus == STATUS_TYPE::ST_SUCCESS)
  686. {
  687. emit faceLivenessSucceed();
  688. }
  689. else
  690. {
  691. emit faceLivenessFaild();
  692. }
  693. });
  694. }
  695. m_pCloseTimer->start();
  696. if (m_sLivenessStatus == STATUS_TYPE::ST_SUCCESS)
  697. {
  698. ui->label_fl_hint->setText(QString::fromLocal8Bit("恭喜您完成检测!"));
  699. ui->label_fl_icon->setPixmap(QPixmap(":/images/icon-welcom.png"));
  700. }
  701. else
  702. {
  703. ui->label_fl_hint->setText(QString::fromLocal8Bit("检测失败:单个动作超时"));
  704. ui->label_fl_icon->setPixmap(QPixmap(":/images/icon-liveness-faild.png"));
  705. }
  706. ui->label_fl_hint->adjustSize();
  707. ui->widget_fc_BG->setVisible(false);
  708. ui->widget_fl_hint->setVisible(true);
  709. ui->widget_fl_hint->setGeometry((width() - ui->label_fl_hint->width() - g_appInfoPtr->m_fRate * 180) / 2, (height() - g_appInfoPtr->m_fRate * 180) / 2,
  710. ui->label_fl_hint->width() + g_appInfoPtr->m_fRate * 180, g_appInfoPtr->m_fRate * 180);
  711. 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);
  712. ui->label_fl_hint->setGeometry(ui->label_fl_icon->x() + ui->label_fl_icon->width() + g_appInfoPtr->m_fRate * 20,
  713. ui->label_fl_icon->y() + (ui->label_fl_icon->height() - ui->label_fl_hint->height()) / 2,
  714. ui->label_fl_hint->width(), ui->label_fl_hint->height());
  715. }
  716. else
  717. {
  718. if (res.sMessage.isEmpty())
  719. {
  720. ShowMsg(QString::fromLocal8Bit("活体验证结果失败"), this, MSG_ICON_TYPE::mit_error);
  721. }
  722. else
  723. {
  724. ShowMsg(res.sMessage, this, MSG_ICON_TYPE::mit_error);
  725. }
  726. if(m_nRetryCount < 4)
  727. {
  728. saveLivenessResult();
  729. m_nRetryCount++;
  730. }
  731. else
  732. {
  733. emit faceLivenessFaild();
  734. }
  735. }
  736. }
  737. catch (const std::exception &e)
  738. {
  739. myDebug() << QString::fromLocal8Bit("人脸比对失败,%1").arg(e.what());
  740. }
  741. }