faceCompare.cpp 14 KB

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