faceLiveness.cpp 24 KB

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