faceCompare.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. #include "faceCompare.h"
  2. #include "ui_faceCompare.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. faceCompare::faceCompare(QWidget *parent) :
  12. QWidget(parent),
  13. ui(new Ui::faceCompare)
  14. {
  15. ui->setupUi(this);
  16. setStyleSheet(g_appInfoPtr->m_sQssStr);
  17. initUI();
  18. m_bStartCompare = false;
  19. qRegisterMetaType<CBaseResponsePackage>("CBaseResponsePackage");
  20. qRegisterMetaType<CClientExamProcessUploadSign>("CClientExamProcessUploadSign");
  21. qRegisterMetaType<CUploadFileToAliyun>("CUploadFileToAliyun");
  22. connect(g_httpBllPtr.get(), &CHttpBll::sgnClientExamProcessUploadSign, this, &faceCompare::onClientExamProcessUploadSign);
  23. connect(g_httpBllPtr.get(), &CHttpBll::sgnSaveFaceCompareResult, this, &faceCompare::onSaveFaceCompareResult);
  24. connect(g_httpBllPtr.get(), &CHttpBll::sgnUploadFileToAliyun, this, &faceCompare::onUploadFileToAliyun);
  25. QString sFileName = g_appInfoPtr->m_sStudentPhotoPath.right(g_appInfoPtr->m_sStudentPhotoPath.length() - g_appInfoPtr->m_sStudentPhotoPath.lastIndexOf("/") - 1);
  26. sFileName = g_appInfoPtr->m_sCacheFileDir + sFileName;
  27. if(!QFile::exists(sFileName))
  28. {
  29. CHttpRequestPackage hrp;
  30. hrp.sUri = g_appInfoPtr->m_sStudentPhotoPath;
  31. hrp.sCommonStr = sFileName;
  32. hrp.sCommonStr1 = __FILE__;
  33. hrp.nRequestType = RequestType::rtDownLoadFile;
  34. hrp.nRetryCount = 3;
  35. g_httpBllPtr->downLoad(hrp);
  36. }
  37. m_pVideoTimer = std::make_shared<QTimer>();
  38. m_pVideoTimer->setInterval(200);
  39. connect(m_pVideoTimer.get(), &QTimer::timeout, this, [&](){
  40. std::scoped_lock lock(m_imageMutex);
  41. QImage img = CCommonTools::Mat2QImage(m_nCurImage);
  42. ui->widget_fc_camera->setAutoFillBackground(true);
  43. QPalette palette;
  44. palette.setBrush(QPalette::Window, QBrush(img.scaled(ui->widget_fc_camera->width(), ui->widget_fc_camera->height())));
  45. ui->widget_fc_camera->setPalette(palette);
  46. });
  47. g_clientVideoProcPtr->startTest(this);
  48. m_pVideoTimer->start();
  49. connect(this, &faceCompare::compareFailed, this, [&](QString sErrorMsg) {
  50. ShowMsg(sErrorMsg, this, MSG_ICON_TYPE::mit_error);
  51. ui->btn_fc_compare->setEnabled(true);
  52. if(!g_appInfoPtr->m_oExamInfo.bIsFaceCheck)
  53. {
  54. if(m_pSkipFaceCompare == nullptr)
  55. {
  56. m_pSkipFaceCompare = std::make_shared<skipFaceCompare>(this);
  57. connect(m_pSkipFaceCompare.get(), &skipFaceCompare::cancel, this, [&](){
  58. m_pSkipFaceCompare.reset();
  59. });
  60. connect(m_pSkipFaceCompare.get(), &skipFaceCompare::confirm, this, [&](){
  61. //比对成功
  62. QString sFileName = QString("temp/photo/%1.png").arg(CCommonTools::getUuid());
  63. QImage imgCompare = CCommonTools::Mat2QImage(m_nCurImage);
  64. imgCompare.save(sFileName, "PNG");
  65. CHttpRequestPackage hrp;
  66. hrp.sUri = "/api/ecs_oe_student/client/exam/process/upload/sign";
  67. hrp.nRequestType = RequestType::rtClientExamProcessUploadSign;
  68. hrp.sCommonStr = __FILE__;
  69. hrp.sCommonStr1 = sFileName;
  70. hrp.sParamList.push_back(QString("fileSuffix,%1").arg(".png"));
  71. hrp.sParamList.push_back(QString("fileMd5,%1").arg(CCommonTools::fileMd5(sFileName)));
  72. hrp.eParamType = HttpParamType::hptBody;
  73. g_httpBllPtr->post(hrp);
  74. });
  75. }
  76. m_pSkipFaceCompare->show();
  77. }
  78. });
  79. m_bIsRun = true;
  80. m_thread = std::thread(std::bind(&faceCompare::threadProc, this));
  81. }
  82. faceCompare::~faceCompare()
  83. {
  84. m_pVideoTimer->stop();
  85. g_clientVideoProcPtr->stopTest();
  86. m_bIsRun = false;
  87. m_thread.join();
  88. awMsgBox::clear(this);
  89. delete ui;
  90. }
  91. void faceCompare::onRenderVideoFrame(const char* userId, TRTCVideoStreamType streamType, TRTCVideoFrame* frame)
  92. {
  93. if(g_clientVideoProcPtr->isCameraTest())
  94. {
  95. __int64 nServerTime = g_appInfoPtr->serverMTime();
  96. if(nServerTime - m_lastFaceTime >= 100)
  97. {
  98. m_lastFaceTime = nServerTime;
  99. cv::Mat matImg;
  100. cv::cvtColor(cv::Mat(frame->height, frame->width, CV_8UC4, frame->data), matImg, CV_RGBA2RGB);
  101. std::scoped_lock lock(m_imageMutex);
  102. m_nCurImage = matImg.clone();
  103. }
  104. }
  105. }
  106. void faceCompare::onDownLoadFile(CDownLoadFileInfo downLoadFileInfo)
  107. {
  108. if(downLoadFileInfo.sModuleName == __FILE__)
  109. {
  110. if (downLoadFileInfo.nCode == 200)
  111. {
  112. QString sFileName = g_appInfoPtr->m_sStudentPhotoPath.right(g_appInfoPtr->m_sStudentPhotoPath.length() - g_appInfoPtr->m_sStudentPhotoPath.lastIndexOf("/") - 1);
  113. sFileName = g_appInfoPtr->m_sCacheFileDir + sFileName;
  114. ui->label_fc_basePhoto->setPixmap(QPixmap(sFileName).scaled(ui->label_fc_basePhoto->width(), ui->label_fc_basePhoto->height(),
  115. Qt::IgnoreAspectRatio));
  116. }
  117. else
  118. {
  119. if(downLoadFileInfo.sMessage.isEmpty())
  120. {
  121. ShowMsg(QString::fromLocal8Bit("下载失败"), this, MSG_ICON_TYPE::mit_error);
  122. }
  123. else
  124. {
  125. ShowMsg(downLoadFileInfo.sMessage, this, MSG_ICON_TYPE::mit_error);
  126. }
  127. }
  128. }
  129. }
  130. void faceCompare::initUI()
  131. {
  132. QDesktopWidget *dekwiget = QApplication::desktop();
  133. setGeometry(0, 0, dekwiget->width(), dekwiget->height());
  134. ui->widget_mask->setGeometry(0, 0, dekwiget->width(), dekwiget->height());
  135. ui->widget_fc_BG->setGeometry((width() - g_appInfoPtr->m_fRate*800)/2, (height() - g_appInfoPtr->m_fRate*536)/2,
  136. g_appInfoPtr->m_fRate*800, g_appInfoPtr->m_fRate*536);
  137. ui->label_fc_title->adjustSize();
  138. ui->label_fc_title->setGeometry(g_appInfoPtr->m_fRate*20, g_appInfoPtr->m_fRate*16,
  139. ui->label_fc_title->width(), ui->label_fc_title->height());
  140. ui->btn_fc_close->setGeometry(ui->widget_fc_BG->width() - g_appInfoPtr->m_fRate*(20 + 16),
  141. g_appInfoPtr->m_fRate*16, g_appInfoPtr->m_fRate*16, g_appInfoPtr->m_fRate*16);
  142. ui->label_HLine->setGeometry(0, ui->label_fc_title->y() + ui->label_fc_title->height() + g_appInfoPtr->m_fRate*16,
  143. ui->widget_fc_BG->width(), g_appInfoPtr->m_fRate*1 < 1 ? 1 : g_appInfoPtr->m_fRate*1);
  144. ui->label_fc_basePhoto->setGeometry(g_appInfoPtr->m_fRate*30, ui->label_HLine->y() + ui->label_HLine->height() + g_appInfoPtr->m_fRate*20,
  145. g_appInfoPtr->m_fRate*140, g_appInfoPtr->m_fRate*180);
  146. QString sFileName = g_appInfoPtr->m_sStudentPhotoPath.right(g_appInfoPtr->m_sStudentPhotoPath.length() - g_appInfoPtr->m_sStudentPhotoPath.lastIndexOf("/") - 1);
  147. sFileName = g_appInfoPtr->m_sCacheFileDir + sFileName;
  148. ui->label_fc_basePhoto->setPixmap(QPixmap(sFileName).scaled(ui->label_fc_basePhoto->width(), ui->label_fc_basePhoto->height(),
  149. Qt::IgnoreAspectRatio));
  150. ui->label_fc_basePhotoTips->setGeometry(ui->label_fc_basePhoto->x() + g_appInfoPtr->m_fRate*10,
  151. ui->label_fc_basePhoto->y() + ui->label_fc_basePhoto->height() - g_appInfoPtr->m_fRate*(10+20),
  152. ui->label_fc_basePhoto->width() - g_appInfoPtr->m_fRate*10*2, g_appInfoPtr->m_fRate*20);
  153. ui->widget_fc_camera->setGeometry(ui->label_fc_basePhoto->x() + ui->label_fc_basePhoto->width() + g_appInfoPtr->m_fRate*20,
  154. ui->label_fc_basePhoto->y(), g_appInfoPtr->m_fRate*580, g_appInfoPtr->m_fRate*300);
  155. ui->label_faceRect->setGeometry((ui->widget_fc_camera->width() - g_appInfoPtr->m_fRate*140)/2,
  156. (ui->widget_fc_camera->height() - g_appInfoPtr->m_fRate*140 - g_appInfoPtr->m_fRate*(20 + 40))/2,
  157. g_appInfoPtr->m_fRate*140, g_appInfoPtr->m_fRate*140);
  158. ui->btn_fc_compare->setGeometry((ui->widget_fc_camera->width() - g_appInfoPtr->m_fRate*120)/2,
  159. ui->widget_fc_camera->height() - g_appInfoPtr->m_fRate*(20 + 40),
  160. g_appInfoPtr->m_fRate*120, g_appInfoPtr->m_fRate*40);
  161. ui->label_fc_tips->adjustSize();
  162. ui->label_fc_tips->setGeometry(ui->widget_fc_camera->x(), ui->widget_fc_camera->y() + ui->widget_fc_camera->height() + g_appInfoPtr->m_fRate*20,
  163. ui->label_fc_tips->width(), ui->label_fc_tips->height());
  164. ui->label_fc_note->setGeometry(ui->widget_fc_camera->x(), ui->label_fc_tips->y() + ui->label_fc_tips->height() + g_appInfoPtr->m_fRate*5,
  165. g_appInfoPtr->m_fRate*580, g_appInfoPtr->m_fRate*100);
  166. }
  167. void faceCompare::on_btn_fc_compare_clicked()
  168. {
  169. if(g_faceRecProcPtr == nullptr)
  170. {
  171. g_faceRecProcPtr = std::make_shared<CFaceRecProc>();
  172. }
  173. if (!g_appInfoPtr->m_sStudentPhotoPath.isEmpty())
  174. {
  175. if(!setBaseImage())
  176. {
  177. return;
  178. }
  179. }
  180. else
  181. {
  182. ShowMsg(QString::fromLocal8Bit("本场考试需要进行人脸检测,但是您没有上传底照,请联系老师"), this, MSG_ICON_TYPE::mit_error);
  183. QTimer::singleShot(3000, this, [&]() { emit exitFaceCompare(); });
  184. return;
  185. }
  186. // if(!g_faceRecProcPtr->hasBaseImage())
  187. // {
  188. // if(!setBaseImage())
  189. // {
  190. // return;
  191. // }
  192. // }
  193. m_bStartCompare = true;
  194. ui->btn_fc_compare->setEnabled(false);
  195. }
  196. bool faceCompare::setBaseImage()
  197. {
  198. QString sFileName = g_appInfoPtr->m_sStudentPhotoPath.right(g_appInfoPtr->m_sStudentPhotoPath.length() - g_appInfoPtr->m_sStudentPhotoPath.lastIndexOf("/") - 1);
  199. sFileName = g_appInfoPtr->m_sCacheFileDir + sFileName;
  200. if(!QFile::exists(sFileName))
  201. {
  202. ShowMsg(QString::fromLocal8Bit("底照下载失败,请检查网络"), this, MSG_ICON_TYPE::mit_error);
  203. return false;
  204. }
  205. QFileInfo filePath(sFileName);
  206. if(!g_faceRecProcPtr->setBaseImage(filePath.absoluteFilePath()))
  207. {
  208. //g_faceRecProcPtr->errorMsg()
  209. ShowMsg(QString::fromLocal8Bit("底照不符合要求,请更换照片"), this, MSG_ICON_TYPE::mit_error);
  210. return false;
  211. }
  212. return true;
  213. }
  214. void faceCompare::on_btn_fc_close_clicked()
  215. {
  216. m_bIsRun = false;
  217. emit exitFaceCompare();
  218. }
  219. void faceCompare::threadProc()
  220. {
  221. while(m_bIsRun)
  222. {
  223. if(m_bStartCompare)
  224. {
  225. cv::Mat img = m_nCurImage;
  226. if(!img.empty())
  227. {
  228. //人脸比对
  229. int nFaceCount = 0;
  230. float fScore = 0;
  231. bool bRealness = false;
  232. int nTime = 0;
  233. if(!g_faceRecProcPtr->getMaxFaceScoreWithBase(img, nFaceCount, fScore, bRealness, nTime))
  234. {
  235. //比对失败
  236. QString sErrorMsg = g_faceRecProcPtr->errorMsg();
  237. emit compareFailed(sErrorMsg);
  238. }
  239. else
  240. {
  241. if(nFaceCount == 0)
  242. {
  243. //无人脸
  244. emit compareFailed(QString::fromLocal8Bit("请让我看到您的正脸"));
  245. }
  246. else if(nFaceCount > 1 && g_appInfoPtr->m_oExamInfo.bIsStrangerEnable)
  247. {
  248. //陌生人
  249. emit compareFailed(QString::fromLocal8Bit("检测到陌生人"));
  250. }
  251. else
  252. {
  253. #ifdef _DEBUG
  254. g_appInfoPtr->m_oExamInfo.nFaceThreshold = 1;
  255. #endif // _DEBUG
  256. if(fScore*100 > g_appInfoPtr->m_oExamInfo.nFaceThreshold || g_appInfoPtr->m_bSkipFaceCheck)
  257. {
  258. m_fScore = fScore;
  259. m_nFaceCount = nFaceCount;
  260. m_nTime = nTime;
  261. //比对成功
  262. QString sFileName = QString("temp/photo/%1.png").arg(CCommonTools::getUuid());
  263. QImage imgCompare = CCommonTools::Mat2QImage(img);
  264. imgCompare.save(sFileName, "PNG");
  265. CHttpRequestPackage hrp;
  266. hrp.sUri = "/api/ecs_oe_student/client/exam/process/upload/sign";
  267. hrp.nRequestType = RequestType::rtClientExamProcessUploadSign;
  268. hrp.sCommonStr = __FILE__;
  269. hrp.sCommonStr1 = sFileName;
  270. hrp.sParamList.push_back(QString("fileSuffix,%1").arg(".png"));
  271. hrp.sParamList.push_back(QString("fileMd5,%1").arg(CCommonTools::fileMd5(sFileName)));
  272. hrp.eParamType = HttpParamType::hptBody;
  273. g_httpBllPtr->post(hrp);
  274. }
  275. else
  276. {
  277. //低于阈值
  278. emit compareFailed(QString::fromLocal8Bit("检测失败"));
  279. }
  280. }
  281. }
  282. m_bStartCompare = false;
  283. }
  284. }
  285. else
  286. {
  287. Sleep(100);
  288. }
  289. }
  290. }
  291. //文件上传
  292. void faceCompare::onClientExamProcessUploadSign(CClientExamProcessUploadSign processUpload)
  293. {
  294. try
  295. {
  296. if(processUpload.sCommonStr == __FILE__)
  297. {
  298. if(processUpload.nCode == 200)
  299. {
  300. CHttpRequestPackage hrp;
  301. hrp.sUri = processUpload.sFormUrl;
  302. hrp.nRequestType = RequestType::rtUploadFileToAliyun;
  303. hrp.sCommonStr = __FILE__;
  304. hrp.sCommonStr1 = processUpload.sAccessUrl;
  305. hrp.sParamList.push_back(QString("OSSAccessKeyId,%1").arg(processUpload.sOssAcessKeyId));
  306. hrp.sParamList.push_back(QString("Signature,%1").arg(processUpload.sSignature));
  307. hrp.sParamList.push_back(QString("key,%1").arg(processUpload.sKey));
  308. hrp.sParamList.push_back(QString("policy,%1").arg(processUpload.sPolicy));
  309. hrp.sParamList.push_back(QString("success_action_status,%1").arg(200));
  310. hrp.sParamList.push_back(QString("formdataFileType,file,%1").arg(processUpload.sFilePath));
  311. hrp.bNoHostPrefix = true;
  312. hrp.eParamType = HttpParamType::hptFormdata;
  313. g_httpBllPtr->post(hrp);
  314. }
  315. else
  316. {
  317. if(processUpload.sMessage.isEmpty())
  318. {
  319. ShowMsg(QString::fromLocal8Bit("上传照片失败"), this, MSG_ICON_TYPE::mit_error);
  320. }
  321. else
  322. {
  323. ShowMsg(processUpload.sMessage, this, MSG_ICON_TYPE::mit_error);
  324. }
  325. }
  326. }
  327. }
  328. catch (const std::exception &e)
  329. {
  330. ShowMsg(QString::fromLocal8Bit("上传照片失败"), this, MSG_ICON_TYPE::mit_error);
  331. myServerLog()<<"onClientExamProcessUploadSign error"<<e.what();
  332. }
  333. }
  334. void faceCompare::onUploadFileToAliyun(CUploadFileToAliyun uploadFileToAliyun)
  335. {
  336. try
  337. {
  338. if(uploadFileToAliyun.sCommonStr == __FILE__)
  339. {
  340. if(uploadFileToAliyun.nCode == 200)
  341. {
  342. CHttpRequestPackage hrp;
  343. hrp.sUri = "/api/ecs_oe_student/client/exam/process/saveFaceCompareResult";
  344. hrp.nRequestType = RequestType::rtSaveFaceCompareResult;
  345. Json::Value jBody = Json::Value::null;
  346. jBody["faceCompareResult"] = QString::number(m_fScore).toStdString();
  347. jBody["fileUrl"] = uploadFileToAliyun.sFileUrl.toStdString();
  348. jBody["pass"] = true;
  349. jBody["processTime"] = m_nTime;
  350. jBody["stranger"] = m_nFaceCount > 1;
  351. hrp.sParamList.push_back(QString("CustomBody,%1").arg(jBody.toStyledString().c_str()));
  352. hrp.eParamType = HttpParamType::hptCustomBody;
  353. g_httpBllPtr->post(hrp);
  354. }
  355. else
  356. {
  357. if(uploadFileToAliyun.sMessage.isEmpty())
  358. {
  359. ShowMsg(QString::fromLocal8Bit("上传照片失败"), this, MSG_ICON_TYPE::mit_error);
  360. }
  361. else
  362. {
  363. ShowMsg(uploadFileToAliyun.sMessage, this, MSG_ICON_TYPE::mit_error);
  364. }
  365. }
  366. }
  367. }
  368. catch (const std::exception &e)
  369. {
  370. ShowMsg(QString::fromLocal8Bit("上传照片失败"), this, MSG_ICON_TYPE::mit_error);
  371. myServerLog()<<"onUploadFileToAliyun error"<<e.what();
  372. }
  373. }
  374. //保存人脸识别比对验证结果
  375. void faceCompare::onSaveFaceCompareResult(CBaseResponsePackage res)
  376. {
  377. try
  378. {
  379. if(res.nCode == 200)
  380. {
  381. if(g_appInfoPtr->m_bSkipFaceCheck)
  382. {
  383. emit faceComparePass();
  384. }
  385. else
  386. {
  387. if(m_pSkipFaceCompare && m_pSkipFaceCompare->isVisible())
  388. {
  389. m_pSkipFaceCompare.reset();
  390. emit faceComparePass();
  391. }
  392. else
  393. {
  394. ShowMsg(QString::fromLocal8Bit("人脸比对成功"), this, MSG_ICON_TYPE::mit_succeed);
  395. QTimer::singleShot(3000, this, [&](){
  396. emit faceComparePass();
  397. });
  398. }
  399. }
  400. }
  401. else
  402. {
  403. if(res.sMessage.isEmpty())
  404. {
  405. ShowMsg(QString::fromLocal8Bit("保存人脸识别信息失败"), this, MSG_ICON_TYPE::mit_error);
  406. }
  407. else
  408. {
  409. ShowMsg(res.sMessage, this, MSG_ICON_TYPE::mit_error);
  410. }
  411. }
  412. }
  413. catch (const std::exception &e)
  414. {
  415. ShowMsg(QString::fromLocal8Bit("保存人脸识别信息失败"), this, MSG_ICON_TYPE::mit_error);
  416. myServerLog()<<"onSaveFaceCompareResult error"<<e.what();
  417. }
  418. }