diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index fe3819d..934dfad 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -1,7 +1,5 @@ #include "CasicBioRecWin.h" #include "ui_CasicBioRecWin.h" -#include -#include CasicBioRecWin::CasicBioRecWin(QWidget *parent) : QMainWindow(parent) @@ -26,11 +24,15 @@ // 初始化识别和注册的各个线程 initFaceRegistThread(); // 人脸注册线程 + initFaceRecogThread(); // 人脸识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); + ProMemory::getInstance().faceCam->openFaceCamera(1000); connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDraw, addPersonForm, &AddPersonForm::drawImageOnForm); + connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDrawForRecognize, + recogResultForm, &RecognizeResultForm::drawImageOnHomeForm); // 打印日志 LOG(INFO) << QString("应用程序启动成功[Application Startup Success]").toStdString(); @@ -43,8 +45,13 @@ ProMemory::getInstance().faceRegistPro->deleteLater(); ProMemory::getInstance().faceRegistPro->wait(); + ProMemory::getInstance().faceRecogPro->exitThread(); + ProMemory::getInstance().faceRecogPro->deleteLater(); + ProMemory::getInstance().faceRecogPro->wait(); + delete ui; delete ProMemory::getInstance().faceRegistPro; + delete ProMemory::getInstance().faceRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -94,6 +101,13 @@ ui->stacked->setCurrentWidget(addPersonForm); ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::ADD_PERSON_FORM; } +void CasicBioRecWin::switchToRecognizeForm() +{ + ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM; + ui->stacked->setCurrentWidget(recogResultForm); + + recogResultForm->startWorkingRecognize(); +} void CasicBioRecWin::initFormsPtr() { @@ -101,18 +115,21 @@ personListForm = new PersonListForm(this); settingForm = new SettingForm(this); addPersonForm = new AddPersonForm(this); + recogResultForm = new RecognizeResultForm(this); ui->stacked->addWidget(startForm); ui->stacked->addWidget(personListForm); ui->stacked->addWidget(settingForm); ui->stacked->addWidget(addPersonForm); - + ui->stacked->addWidget(recogResultForm); // 绑定按钮函数 connect(startForm, &StartupForm::switchToUserListForm, this, &CasicBioRecWin::switchToUserListForm); connect(startForm, &StartupForm::switchToSettingForm, this, &CasicBioRecWin::switchToSettingForm); + connect(startForm, &StartupForm::startRecognize, + this, &CasicBioRecWin::switchToRecognizeForm); connect(personListForm, &PersonListForm::switchToRegistForm, this, &CasicBioRecWin::switchToRegistForm); @@ -146,3 +163,20 @@ ProMemory::getInstance().faceRegistPro->start(); } + +void CasicBioRecWin::initFaceRecogThread() +{ + // 人脸识别处理过程 + ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().faceRecogPro->start(); +} diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index fe3819d..934dfad 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -1,7 +1,5 @@ #include "CasicBioRecWin.h" #include "ui_CasicBioRecWin.h" -#include -#include CasicBioRecWin::CasicBioRecWin(QWidget *parent) : QMainWindow(parent) @@ -26,11 +24,15 @@ // 初始化识别和注册的各个线程 initFaceRegistThread(); // 人脸注册线程 + initFaceRecogThread(); // 人脸识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); + ProMemory::getInstance().faceCam->openFaceCamera(1000); connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDraw, addPersonForm, &AddPersonForm::drawImageOnForm); + connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDrawForRecognize, + recogResultForm, &RecognizeResultForm::drawImageOnHomeForm); // 打印日志 LOG(INFO) << QString("应用程序启动成功[Application Startup Success]").toStdString(); @@ -43,8 +45,13 @@ ProMemory::getInstance().faceRegistPro->deleteLater(); ProMemory::getInstance().faceRegistPro->wait(); + ProMemory::getInstance().faceRecogPro->exitThread(); + ProMemory::getInstance().faceRecogPro->deleteLater(); + ProMemory::getInstance().faceRecogPro->wait(); + delete ui; delete ProMemory::getInstance().faceRegistPro; + delete ProMemory::getInstance().faceRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -94,6 +101,13 @@ ui->stacked->setCurrentWidget(addPersonForm); ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::ADD_PERSON_FORM; } +void CasicBioRecWin::switchToRecognizeForm() +{ + ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM; + ui->stacked->setCurrentWidget(recogResultForm); + + recogResultForm->startWorkingRecognize(); +} void CasicBioRecWin::initFormsPtr() { @@ -101,18 +115,21 @@ personListForm = new PersonListForm(this); settingForm = new SettingForm(this); addPersonForm = new AddPersonForm(this); + recogResultForm = new RecognizeResultForm(this); ui->stacked->addWidget(startForm); ui->stacked->addWidget(personListForm); ui->stacked->addWidget(settingForm); ui->stacked->addWidget(addPersonForm); - + ui->stacked->addWidget(recogResultForm); // 绑定按钮函数 connect(startForm, &StartupForm::switchToUserListForm, this, &CasicBioRecWin::switchToUserListForm); connect(startForm, &StartupForm::switchToSettingForm, this, &CasicBioRecWin::switchToSettingForm); + connect(startForm, &StartupForm::startRecognize, + this, &CasicBioRecWin::switchToRecognizeForm); connect(personListForm, &PersonListForm::switchToRegistForm, this, &CasicBioRecWin::switchToRegistForm); @@ -146,3 +163,20 @@ ProMemory::getInstance().faceRegistPro->start(); } + +void CasicBioRecWin::initFaceRecogThread() +{ + // 人脸识别处理过程 + ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().faceRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index 3e706fe..f0b47bf 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -2,19 +2,20 @@ #define CASICBIORECWIN_H #include +#include +#include #include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SettingConfig.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" #include "StartupForm.h" #include "PersonListForm.h" #include "SettingForm.h" #include "AddPersonForm.h" +#include "RecognizeResultForm.h" #include "device/FaceCameraController.h" -#include "device/face/FaceDetectRegistProcess.h" QT_BEGIN_NAMESPACE namespace Ui { class CasicBioRecWin; } @@ -33,6 +34,7 @@ void switchToUserListForm(); void switchToSettingForm(); void switchToRegistForm(QString personId); + void switchToRecognizeForm(); private: Ui::CasicBioRecWin *ui; @@ -41,11 +43,13 @@ PersonListForm * personListForm; SettingForm * settingForm; AddPersonForm * addPersonForm; + RecognizeResultForm * recogResultForm; void keyPressEvent(QKeyEvent *event); void initFormsPtr(); void initCacheData(); void initFaceRegistThread(); + void initFaceRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index fe3819d..934dfad 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -1,7 +1,5 @@ #include "CasicBioRecWin.h" #include "ui_CasicBioRecWin.h" -#include -#include CasicBioRecWin::CasicBioRecWin(QWidget *parent) : QMainWindow(parent) @@ -26,11 +24,15 @@ // 初始化识别和注册的各个线程 initFaceRegistThread(); // 人脸注册线程 + initFaceRecogThread(); // 人脸识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); + ProMemory::getInstance().faceCam->openFaceCamera(1000); connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDraw, addPersonForm, &AddPersonForm::drawImageOnForm); + connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDrawForRecognize, + recogResultForm, &RecognizeResultForm::drawImageOnHomeForm); // 打印日志 LOG(INFO) << QString("应用程序启动成功[Application Startup Success]").toStdString(); @@ -43,8 +45,13 @@ ProMemory::getInstance().faceRegistPro->deleteLater(); ProMemory::getInstance().faceRegistPro->wait(); + ProMemory::getInstance().faceRecogPro->exitThread(); + ProMemory::getInstance().faceRecogPro->deleteLater(); + ProMemory::getInstance().faceRecogPro->wait(); + delete ui; delete ProMemory::getInstance().faceRegistPro; + delete ProMemory::getInstance().faceRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -94,6 +101,13 @@ ui->stacked->setCurrentWidget(addPersonForm); ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::ADD_PERSON_FORM; } +void CasicBioRecWin::switchToRecognizeForm() +{ + ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM; + ui->stacked->setCurrentWidget(recogResultForm); + + recogResultForm->startWorkingRecognize(); +} void CasicBioRecWin::initFormsPtr() { @@ -101,18 +115,21 @@ personListForm = new PersonListForm(this); settingForm = new SettingForm(this); addPersonForm = new AddPersonForm(this); + recogResultForm = new RecognizeResultForm(this); ui->stacked->addWidget(startForm); ui->stacked->addWidget(personListForm); ui->stacked->addWidget(settingForm); ui->stacked->addWidget(addPersonForm); - + ui->stacked->addWidget(recogResultForm); // 绑定按钮函数 connect(startForm, &StartupForm::switchToUserListForm, this, &CasicBioRecWin::switchToUserListForm); connect(startForm, &StartupForm::switchToSettingForm, this, &CasicBioRecWin::switchToSettingForm); + connect(startForm, &StartupForm::startRecognize, + this, &CasicBioRecWin::switchToRecognizeForm); connect(personListForm, &PersonListForm::switchToRegistForm, this, &CasicBioRecWin::switchToRegistForm); @@ -146,3 +163,20 @@ ProMemory::getInstance().faceRegistPro->start(); } + +void CasicBioRecWin::initFaceRecogThread() +{ + // 人脸识别处理过程 + ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().faceRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index 3e706fe..f0b47bf 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -2,19 +2,20 @@ #define CASICBIORECWIN_H #include +#include +#include #include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SettingConfig.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" #include "StartupForm.h" #include "PersonListForm.h" #include "SettingForm.h" #include "AddPersonForm.h" +#include "RecognizeResultForm.h" #include "device/FaceCameraController.h" -#include "device/face/FaceDetectRegistProcess.h" QT_BEGIN_NAMESPACE namespace Ui { class CasicBioRecWin; } @@ -33,6 +34,7 @@ void switchToUserListForm(); void switchToSettingForm(); void switchToRegistForm(QString personId); + void switchToRecognizeForm(); private: Ui::CasicBioRecWin *ui; @@ -41,11 +43,13 @@ PersonListForm * personListForm; SettingForm * settingForm; AddPersonForm * addPersonForm; + RecognizeResultForm * recogResultForm; void keyPressEvent(QKeyEvent *event); void initFormsPtr(); void initCacheData(); void initFaceRegistThread(); + void initFaceRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/PersonListForm.h b/PersonListForm.h index db352c6..65bd3f5 100644 --- a/PersonListForm.h +++ b/PersonListForm.h @@ -7,7 +7,7 @@ #include "ConfirmTipsDialog.h" #include "OperationTipsDialog.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" +#include "utils/UtilInclude.h" namespace Ui { class PersonListForm; diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index fe3819d..934dfad 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -1,7 +1,5 @@ #include "CasicBioRecWin.h" #include "ui_CasicBioRecWin.h" -#include -#include CasicBioRecWin::CasicBioRecWin(QWidget *parent) : QMainWindow(parent) @@ -26,11 +24,15 @@ // 初始化识别和注册的各个线程 initFaceRegistThread(); // 人脸注册线程 + initFaceRecogThread(); // 人脸识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); + ProMemory::getInstance().faceCam->openFaceCamera(1000); connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDraw, addPersonForm, &AddPersonForm::drawImageOnForm); + connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDrawForRecognize, + recogResultForm, &RecognizeResultForm::drawImageOnHomeForm); // 打印日志 LOG(INFO) << QString("应用程序启动成功[Application Startup Success]").toStdString(); @@ -43,8 +45,13 @@ ProMemory::getInstance().faceRegistPro->deleteLater(); ProMemory::getInstance().faceRegistPro->wait(); + ProMemory::getInstance().faceRecogPro->exitThread(); + ProMemory::getInstance().faceRecogPro->deleteLater(); + ProMemory::getInstance().faceRecogPro->wait(); + delete ui; delete ProMemory::getInstance().faceRegistPro; + delete ProMemory::getInstance().faceRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -94,6 +101,13 @@ ui->stacked->setCurrentWidget(addPersonForm); ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::ADD_PERSON_FORM; } +void CasicBioRecWin::switchToRecognizeForm() +{ + ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM; + ui->stacked->setCurrentWidget(recogResultForm); + + recogResultForm->startWorkingRecognize(); +} void CasicBioRecWin::initFormsPtr() { @@ -101,18 +115,21 @@ personListForm = new PersonListForm(this); settingForm = new SettingForm(this); addPersonForm = new AddPersonForm(this); + recogResultForm = new RecognizeResultForm(this); ui->stacked->addWidget(startForm); ui->stacked->addWidget(personListForm); ui->stacked->addWidget(settingForm); ui->stacked->addWidget(addPersonForm); - + ui->stacked->addWidget(recogResultForm); // 绑定按钮函数 connect(startForm, &StartupForm::switchToUserListForm, this, &CasicBioRecWin::switchToUserListForm); connect(startForm, &StartupForm::switchToSettingForm, this, &CasicBioRecWin::switchToSettingForm); + connect(startForm, &StartupForm::startRecognize, + this, &CasicBioRecWin::switchToRecognizeForm); connect(personListForm, &PersonListForm::switchToRegistForm, this, &CasicBioRecWin::switchToRegistForm); @@ -146,3 +163,20 @@ ProMemory::getInstance().faceRegistPro->start(); } + +void CasicBioRecWin::initFaceRecogThread() +{ + // 人脸识别处理过程 + ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().faceRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index 3e706fe..f0b47bf 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -2,19 +2,20 @@ #define CASICBIORECWIN_H #include +#include +#include #include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SettingConfig.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" #include "StartupForm.h" #include "PersonListForm.h" #include "SettingForm.h" #include "AddPersonForm.h" +#include "RecognizeResultForm.h" #include "device/FaceCameraController.h" -#include "device/face/FaceDetectRegistProcess.h" QT_BEGIN_NAMESPACE namespace Ui { class CasicBioRecWin; } @@ -33,6 +34,7 @@ void switchToUserListForm(); void switchToSettingForm(); void switchToRegistForm(QString personId); + void switchToRecognizeForm(); private: Ui::CasicBioRecWin *ui; @@ -41,11 +43,13 @@ PersonListForm * personListForm; SettingForm * settingForm; AddPersonForm * addPersonForm; + RecognizeResultForm * recogResultForm; void keyPressEvent(QKeyEvent *event); void initFormsPtr(); void initCacheData(); void initFaceRegistThread(); + void initFaceRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/PersonListForm.h b/PersonListForm.h index db352c6..65bd3f5 100644 --- a/PersonListForm.h +++ b/PersonListForm.h @@ -7,7 +7,7 @@ #include "ConfirmTipsDialog.h" #include "OperationTipsDialog.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" +#include "utils/UtilInclude.h" namespace Ui { class PersonListForm; diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp new file mode 100644 index 0000000..b6790a9 --- /dev/null +++ b/RecognizeResultForm.cpp @@ -0,0 +1,60 @@ +#include "RecognizeResultForm.h" +#include "ui_RecognizeResultForm.h" + +RecognizeResultForm::RecognizeResultForm(QWidget *parent) : + QWidget(parent), + ui(new Ui::RecognizeResultForm) +{ + ui->setupUi(this); + ui->labVideo->hide(); + + // 加载css文件设置控件样式 + QFile file(QApplication::applicationDirPath() + "/qss/recognize.css"); + if (file.open(QFile::ReadOnly)) + { + QString qssStr = QLatin1String(file.readAll()); + this->setStyleSheet(qssStr); + file.close(); + } +} + +RecognizeResultForm::~RecognizeResultForm() +{ + delete ui; +} + +void RecognizeResultForm::startWorkingRecognize() +{ + // 开始人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + + // 将界面切换到识别界面 RecognizeResultForm + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + + // 1人脸图像显示的容器 + ui->labVideo->resize(1060, 607); + ui->labVideo->move(110, 100); + ui->labVideo->raise(); + ui->labVideo->show(); +} + + +void RecognizeResultForm::drawImageOnHomeForm(QImage imageDisp) +{ + if (ui->labVideo->isVisible() == true) + { + LOG(TRACE) << "DRAW IMAGE ON FORM " << imageDisp.width() << "*" << imageDisp.height(); + imageDisp = imageDisp.scaled(1040, 585); + ui->labVideo->setPixmap(QPixmap::fromImage(imageDisp)); + } +} + +void RecognizeResultForm::showRecogFailure() +{ + +} +void RecognizeResultForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功"); +// ui->labVideo->hide(); +} diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index fe3819d..934dfad 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -1,7 +1,5 @@ #include "CasicBioRecWin.h" #include "ui_CasicBioRecWin.h" -#include -#include CasicBioRecWin::CasicBioRecWin(QWidget *parent) : QMainWindow(parent) @@ -26,11 +24,15 @@ // 初始化识别和注册的各个线程 initFaceRegistThread(); // 人脸注册线程 + initFaceRecogThread(); // 人脸识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); + ProMemory::getInstance().faceCam->openFaceCamera(1000); connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDraw, addPersonForm, &AddPersonForm::drawImageOnForm); + connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDrawForRecognize, + recogResultForm, &RecognizeResultForm::drawImageOnHomeForm); // 打印日志 LOG(INFO) << QString("应用程序启动成功[Application Startup Success]").toStdString(); @@ -43,8 +45,13 @@ ProMemory::getInstance().faceRegistPro->deleteLater(); ProMemory::getInstance().faceRegistPro->wait(); + ProMemory::getInstance().faceRecogPro->exitThread(); + ProMemory::getInstance().faceRecogPro->deleteLater(); + ProMemory::getInstance().faceRecogPro->wait(); + delete ui; delete ProMemory::getInstance().faceRegistPro; + delete ProMemory::getInstance().faceRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -94,6 +101,13 @@ ui->stacked->setCurrentWidget(addPersonForm); ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::ADD_PERSON_FORM; } +void CasicBioRecWin::switchToRecognizeForm() +{ + ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM; + ui->stacked->setCurrentWidget(recogResultForm); + + recogResultForm->startWorkingRecognize(); +} void CasicBioRecWin::initFormsPtr() { @@ -101,18 +115,21 @@ personListForm = new PersonListForm(this); settingForm = new SettingForm(this); addPersonForm = new AddPersonForm(this); + recogResultForm = new RecognizeResultForm(this); ui->stacked->addWidget(startForm); ui->stacked->addWidget(personListForm); ui->stacked->addWidget(settingForm); ui->stacked->addWidget(addPersonForm); - + ui->stacked->addWidget(recogResultForm); // 绑定按钮函数 connect(startForm, &StartupForm::switchToUserListForm, this, &CasicBioRecWin::switchToUserListForm); connect(startForm, &StartupForm::switchToSettingForm, this, &CasicBioRecWin::switchToSettingForm); + connect(startForm, &StartupForm::startRecognize, + this, &CasicBioRecWin::switchToRecognizeForm); connect(personListForm, &PersonListForm::switchToRegistForm, this, &CasicBioRecWin::switchToRegistForm); @@ -146,3 +163,20 @@ ProMemory::getInstance().faceRegistPro->start(); } + +void CasicBioRecWin::initFaceRecogThread() +{ + // 人脸识别处理过程 + ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().faceRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index 3e706fe..f0b47bf 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -2,19 +2,20 @@ #define CASICBIORECWIN_H #include +#include +#include #include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SettingConfig.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" #include "StartupForm.h" #include "PersonListForm.h" #include "SettingForm.h" #include "AddPersonForm.h" +#include "RecognizeResultForm.h" #include "device/FaceCameraController.h" -#include "device/face/FaceDetectRegistProcess.h" QT_BEGIN_NAMESPACE namespace Ui { class CasicBioRecWin; } @@ -33,6 +34,7 @@ void switchToUserListForm(); void switchToSettingForm(); void switchToRegistForm(QString personId); + void switchToRecognizeForm(); private: Ui::CasicBioRecWin *ui; @@ -41,11 +43,13 @@ PersonListForm * personListForm; SettingForm * settingForm; AddPersonForm * addPersonForm; + RecognizeResultForm * recogResultForm; void keyPressEvent(QKeyEvent *event); void initFormsPtr(); void initCacheData(); void initFaceRegistThread(); + void initFaceRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/PersonListForm.h b/PersonListForm.h index db352c6..65bd3f5 100644 --- a/PersonListForm.h +++ b/PersonListForm.h @@ -7,7 +7,7 @@ #include "ConfirmTipsDialog.h" #include "OperationTipsDialog.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" +#include "utils/UtilInclude.h" namespace Ui { class PersonListForm; diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp new file mode 100644 index 0000000..b6790a9 --- /dev/null +++ b/RecognizeResultForm.cpp @@ -0,0 +1,60 @@ +#include "RecognizeResultForm.h" +#include "ui_RecognizeResultForm.h" + +RecognizeResultForm::RecognizeResultForm(QWidget *parent) : + QWidget(parent), + ui(new Ui::RecognizeResultForm) +{ + ui->setupUi(this); + ui->labVideo->hide(); + + // 加载css文件设置控件样式 + QFile file(QApplication::applicationDirPath() + "/qss/recognize.css"); + if (file.open(QFile::ReadOnly)) + { + QString qssStr = QLatin1String(file.readAll()); + this->setStyleSheet(qssStr); + file.close(); + } +} + +RecognizeResultForm::~RecognizeResultForm() +{ + delete ui; +} + +void RecognizeResultForm::startWorkingRecognize() +{ + // 开始人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + + // 将界面切换到识别界面 RecognizeResultForm + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + + // 1人脸图像显示的容器 + ui->labVideo->resize(1060, 607); + ui->labVideo->move(110, 100); + ui->labVideo->raise(); + ui->labVideo->show(); +} + + +void RecognizeResultForm::drawImageOnHomeForm(QImage imageDisp) +{ + if (ui->labVideo->isVisible() == true) + { + LOG(TRACE) << "DRAW IMAGE ON FORM " << imageDisp.width() << "*" << imageDisp.height(); + imageDisp = imageDisp.scaled(1040, 585); + ui->labVideo->setPixmap(QPixmap::fromImage(imageDisp)); + } +} + +void RecognizeResultForm::showRecogFailure() +{ + +} +void RecognizeResultForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功"); +// ui->labVideo->hide(); +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h new file mode 100644 index 0000000..3be5410 --- /dev/null +++ b/RecognizeResultForm.h @@ -0,0 +1,34 @@ +#ifndef RECOGNIZERESULTFORM_H +#define RECOGNIZERESULTFORM_H + +#include + +#include "utils/UtilInclude.h" + +#include "casic/ProMemory.h" + +namespace Ui { +class RecognizeResultForm; +} + +class RecognizeResultForm : public QWidget +{ + Q_OBJECT + +public: + explicit RecognizeResultForm(QWidget *parent = nullptr); + ~RecognizeResultForm(); + +public slots: + void showRecogFailure(); + void showRecognizeResult(QString personId); + + void startWorkingRecognize(); // 开始工作 + void drawImageOnHomeForm(QImage imageDisp); + +private: + Ui::RecognizeResultForm *ui; + +}; + +#endif // RECOGNIZERESULTFORM_H diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index fe3819d..934dfad 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -1,7 +1,5 @@ #include "CasicBioRecWin.h" #include "ui_CasicBioRecWin.h" -#include -#include CasicBioRecWin::CasicBioRecWin(QWidget *parent) : QMainWindow(parent) @@ -26,11 +24,15 @@ // 初始化识别和注册的各个线程 initFaceRegistThread(); // 人脸注册线程 + initFaceRecogThread(); // 人脸识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); + ProMemory::getInstance().faceCam->openFaceCamera(1000); connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDraw, addPersonForm, &AddPersonForm::drawImageOnForm); + connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDrawForRecognize, + recogResultForm, &RecognizeResultForm::drawImageOnHomeForm); // 打印日志 LOG(INFO) << QString("应用程序启动成功[Application Startup Success]").toStdString(); @@ -43,8 +45,13 @@ ProMemory::getInstance().faceRegistPro->deleteLater(); ProMemory::getInstance().faceRegistPro->wait(); + ProMemory::getInstance().faceRecogPro->exitThread(); + ProMemory::getInstance().faceRecogPro->deleteLater(); + ProMemory::getInstance().faceRecogPro->wait(); + delete ui; delete ProMemory::getInstance().faceRegistPro; + delete ProMemory::getInstance().faceRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -94,6 +101,13 @@ ui->stacked->setCurrentWidget(addPersonForm); ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::ADD_PERSON_FORM; } +void CasicBioRecWin::switchToRecognizeForm() +{ + ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM; + ui->stacked->setCurrentWidget(recogResultForm); + + recogResultForm->startWorkingRecognize(); +} void CasicBioRecWin::initFormsPtr() { @@ -101,18 +115,21 @@ personListForm = new PersonListForm(this); settingForm = new SettingForm(this); addPersonForm = new AddPersonForm(this); + recogResultForm = new RecognizeResultForm(this); ui->stacked->addWidget(startForm); ui->stacked->addWidget(personListForm); ui->stacked->addWidget(settingForm); ui->stacked->addWidget(addPersonForm); - + ui->stacked->addWidget(recogResultForm); // 绑定按钮函数 connect(startForm, &StartupForm::switchToUserListForm, this, &CasicBioRecWin::switchToUserListForm); connect(startForm, &StartupForm::switchToSettingForm, this, &CasicBioRecWin::switchToSettingForm); + connect(startForm, &StartupForm::startRecognize, + this, &CasicBioRecWin::switchToRecognizeForm); connect(personListForm, &PersonListForm::switchToRegistForm, this, &CasicBioRecWin::switchToRegistForm); @@ -146,3 +163,20 @@ ProMemory::getInstance().faceRegistPro->start(); } + +void CasicBioRecWin::initFaceRecogThread() +{ + // 人脸识别处理过程 + ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().faceRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index 3e706fe..f0b47bf 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -2,19 +2,20 @@ #define CASICBIORECWIN_H #include +#include +#include #include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SettingConfig.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" #include "StartupForm.h" #include "PersonListForm.h" #include "SettingForm.h" #include "AddPersonForm.h" +#include "RecognizeResultForm.h" #include "device/FaceCameraController.h" -#include "device/face/FaceDetectRegistProcess.h" QT_BEGIN_NAMESPACE namespace Ui { class CasicBioRecWin; } @@ -33,6 +34,7 @@ void switchToUserListForm(); void switchToSettingForm(); void switchToRegistForm(QString personId); + void switchToRecognizeForm(); private: Ui::CasicBioRecWin *ui; @@ -41,11 +43,13 @@ PersonListForm * personListForm; SettingForm * settingForm; AddPersonForm * addPersonForm; + RecognizeResultForm * recogResultForm; void keyPressEvent(QKeyEvent *event); void initFormsPtr(); void initCacheData(); void initFaceRegistThread(); + void initFaceRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/PersonListForm.h b/PersonListForm.h index db352c6..65bd3f5 100644 --- a/PersonListForm.h +++ b/PersonListForm.h @@ -7,7 +7,7 @@ #include "ConfirmTipsDialog.h" #include "OperationTipsDialog.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" +#include "utils/UtilInclude.h" namespace Ui { class PersonListForm; diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp new file mode 100644 index 0000000..b6790a9 --- /dev/null +++ b/RecognizeResultForm.cpp @@ -0,0 +1,60 @@ +#include "RecognizeResultForm.h" +#include "ui_RecognizeResultForm.h" + +RecognizeResultForm::RecognizeResultForm(QWidget *parent) : + QWidget(parent), + ui(new Ui::RecognizeResultForm) +{ + ui->setupUi(this); + ui->labVideo->hide(); + + // 加载css文件设置控件样式 + QFile file(QApplication::applicationDirPath() + "/qss/recognize.css"); + if (file.open(QFile::ReadOnly)) + { + QString qssStr = QLatin1String(file.readAll()); + this->setStyleSheet(qssStr); + file.close(); + } +} + +RecognizeResultForm::~RecognizeResultForm() +{ + delete ui; +} + +void RecognizeResultForm::startWorkingRecognize() +{ + // 开始人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + + // 将界面切换到识别界面 RecognizeResultForm + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + + // 1人脸图像显示的容器 + ui->labVideo->resize(1060, 607); + ui->labVideo->move(110, 100); + ui->labVideo->raise(); + ui->labVideo->show(); +} + + +void RecognizeResultForm::drawImageOnHomeForm(QImage imageDisp) +{ + if (ui->labVideo->isVisible() == true) + { + LOG(TRACE) << "DRAW IMAGE ON FORM " << imageDisp.width() << "*" << imageDisp.height(); + imageDisp = imageDisp.scaled(1040, 585); + ui->labVideo->setPixmap(QPixmap::fromImage(imageDisp)); + } +} + +void RecognizeResultForm::showRecogFailure() +{ + +} +void RecognizeResultForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功"); +// ui->labVideo->hide(); +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h new file mode 100644 index 0000000..3be5410 --- /dev/null +++ b/RecognizeResultForm.h @@ -0,0 +1,34 @@ +#ifndef RECOGNIZERESULTFORM_H +#define RECOGNIZERESULTFORM_H + +#include + +#include "utils/UtilInclude.h" + +#include "casic/ProMemory.h" + +namespace Ui { +class RecognizeResultForm; +} + +class RecognizeResultForm : public QWidget +{ + Q_OBJECT + +public: + explicit RecognizeResultForm(QWidget *parent = nullptr); + ~RecognizeResultForm(); + +public slots: + void showRecogFailure(); + void showRecognizeResult(QString personId); + + void startWorkingRecognize(); // 开始工作 + void drawImageOnHomeForm(QImage imageDisp); + +private: + Ui::RecognizeResultForm *ui; + +}; + +#endif // RECOGNIZERESULTFORM_H diff --git a/RecognizeResultForm.ui b/RecognizeResultForm.ui new file mode 100644 index 0000000..9d08547 --- /dev/null +++ b/RecognizeResultForm.ui @@ -0,0 +1,212 @@ + + + RecognizeResultForm + + + + 0 + 0 + 1280 + 800 + + + + Form + + + + + 0 + 0 + 1280 + 800 + + + + + + + :/images/bg_recognize_result.png + + + + + + 0 + 0 + 0 + 0 + + + + + + + Qt::AlignCenter + + + + + + 0 + 0 + 1280 + 90 + + + + + + + 人员识别 + + + Qt::AlignCenter + + + + + + 109 + 119 + 551 + 431 + + + + + + -110 + -70 + 280 + 380 + + + + :/images/photoFace.png + + + Qt::AlignCenter + + + + + + 240 + 220 + 54 + 12 + + + + TextLabel + + + + + + 240 + 10 + 54 + 12 + + + + TextLabel + + + + + + 240 + 160 + 54 + 12 + + + + TextLabel + + + + + + 240 + 90 + 54 + 12 + + + + TextLabel + + + + + + 440 + 260 + 54 + 12 + + + + TextLabel + + + + + + 430 + 130 + 54 + 12 + + + + TextLabel + + + + + + 440 + 200 + 54 + 12 + + + + TextLabel + + + + + + 430 + 50 + 54 + 12 + + + + TextLabel + + + + + + + 550 + 470 + 120 + 80 + + + + + + + + + diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index fe3819d..934dfad 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -1,7 +1,5 @@ #include "CasicBioRecWin.h" #include "ui_CasicBioRecWin.h" -#include -#include CasicBioRecWin::CasicBioRecWin(QWidget *parent) : QMainWindow(parent) @@ -26,11 +24,15 @@ // 初始化识别和注册的各个线程 initFaceRegistThread(); // 人脸注册线程 + initFaceRecogThread(); // 人脸识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); + ProMemory::getInstance().faceCam->openFaceCamera(1000); connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDraw, addPersonForm, &AddPersonForm::drawImageOnForm); + connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDrawForRecognize, + recogResultForm, &RecognizeResultForm::drawImageOnHomeForm); // 打印日志 LOG(INFO) << QString("应用程序启动成功[Application Startup Success]").toStdString(); @@ -43,8 +45,13 @@ ProMemory::getInstance().faceRegistPro->deleteLater(); ProMemory::getInstance().faceRegistPro->wait(); + ProMemory::getInstance().faceRecogPro->exitThread(); + ProMemory::getInstance().faceRecogPro->deleteLater(); + ProMemory::getInstance().faceRecogPro->wait(); + delete ui; delete ProMemory::getInstance().faceRegistPro; + delete ProMemory::getInstance().faceRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -94,6 +101,13 @@ ui->stacked->setCurrentWidget(addPersonForm); ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::ADD_PERSON_FORM; } +void CasicBioRecWin::switchToRecognizeForm() +{ + ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM; + ui->stacked->setCurrentWidget(recogResultForm); + + recogResultForm->startWorkingRecognize(); +} void CasicBioRecWin::initFormsPtr() { @@ -101,18 +115,21 @@ personListForm = new PersonListForm(this); settingForm = new SettingForm(this); addPersonForm = new AddPersonForm(this); + recogResultForm = new RecognizeResultForm(this); ui->stacked->addWidget(startForm); ui->stacked->addWidget(personListForm); ui->stacked->addWidget(settingForm); ui->stacked->addWidget(addPersonForm); - + ui->stacked->addWidget(recogResultForm); // 绑定按钮函数 connect(startForm, &StartupForm::switchToUserListForm, this, &CasicBioRecWin::switchToUserListForm); connect(startForm, &StartupForm::switchToSettingForm, this, &CasicBioRecWin::switchToSettingForm); + connect(startForm, &StartupForm::startRecognize, + this, &CasicBioRecWin::switchToRecognizeForm); connect(personListForm, &PersonListForm::switchToRegistForm, this, &CasicBioRecWin::switchToRegistForm); @@ -146,3 +163,20 @@ ProMemory::getInstance().faceRegistPro->start(); } + +void CasicBioRecWin::initFaceRecogThread() +{ + // 人脸识别处理过程 + ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().faceRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index 3e706fe..f0b47bf 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -2,19 +2,20 @@ #define CASICBIORECWIN_H #include +#include +#include #include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SettingConfig.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" #include "StartupForm.h" #include "PersonListForm.h" #include "SettingForm.h" #include "AddPersonForm.h" +#include "RecognizeResultForm.h" #include "device/FaceCameraController.h" -#include "device/face/FaceDetectRegistProcess.h" QT_BEGIN_NAMESPACE namespace Ui { class CasicBioRecWin; } @@ -33,6 +34,7 @@ void switchToUserListForm(); void switchToSettingForm(); void switchToRegistForm(QString personId); + void switchToRecognizeForm(); private: Ui::CasicBioRecWin *ui; @@ -41,11 +43,13 @@ PersonListForm * personListForm; SettingForm * settingForm; AddPersonForm * addPersonForm; + RecognizeResultForm * recogResultForm; void keyPressEvent(QKeyEvent *event); void initFormsPtr(); void initCacheData(); void initFaceRegistThread(); + void initFaceRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/PersonListForm.h b/PersonListForm.h index db352c6..65bd3f5 100644 --- a/PersonListForm.h +++ b/PersonListForm.h @@ -7,7 +7,7 @@ #include "ConfirmTipsDialog.h" #include "OperationTipsDialog.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" +#include "utils/UtilInclude.h" namespace Ui { class PersonListForm; diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp new file mode 100644 index 0000000..b6790a9 --- /dev/null +++ b/RecognizeResultForm.cpp @@ -0,0 +1,60 @@ +#include "RecognizeResultForm.h" +#include "ui_RecognizeResultForm.h" + +RecognizeResultForm::RecognizeResultForm(QWidget *parent) : + QWidget(parent), + ui(new Ui::RecognizeResultForm) +{ + ui->setupUi(this); + ui->labVideo->hide(); + + // 加载css文件设置控件样式 + QFile file(QApplication::applicationDirPath() + "/qss/recognize.css"); + if (file.open(QFile::ReadOnly)) + { + QString qssStr = QLatin1String(file.readAll()); + this->setStyleSheet(qssStr); + file.close(); + } +} + +RecognizeResultForm::~RecognizeResultForm() +{ + delete ui; +} + +void RecognizeResultForm::startWorkingRecognize() +{ + // 开始人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + + // 将界面切换到识别界面 RecognizeResultForm + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + + // 1人脸图像显示的容器 + ui->labVideo->resize(1060, 607); + ui->labVideo->move(110, 100); + ui->labVideo->raise(); + ui->labVideo->show(); +} + + +void RecognizeResultForm::drawImageOnHomeForm(QImage imageDisp) +{ + if (ui->labVideo->isVisible() == true) + { + LOG(TRACE) << "DRAW IMAGE ON FORM " << imageDisp.width() << "*" << imageDisp.height(); + imageDisp = imageDisp.scaled(1040, 585); + ui->labVideo->setPixmap(QPixmap::fromImage(imageDisp)); + } +} + +void RecognizeResultForm::showRecogFailure() +{ + +} +void RecognizeResultForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功"); +// ui->labVideo->hide(); +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h new file mode 100644 index 0000000..3be5410 --- /dev/null +++ b/RecognizeResultForm.h @@ -0,0 +1,34 @@ +#ifndef RECOGNIZERESULTFORM_H +#define RECOGNIZERESULTFORM_H + +#include + +#include "utils/UtilInclude.h" + +#include "casic/ProMemory.h" + +namespace Ui { +class RecognizeResultForm; +} + +class RecognizeResultForm : public QWidget +{ + Q_OBJECT + +public: + explicit RecognizeResultForm(QWidget *parent = nullptr); + ~RecognizeResultForm(); + +public slots: + void showRecogFailure(); + void showRecognizeResult(QString personId); + + void startWorkingRecognize(); // 开始工作 + void drawImageOnHomeForm(QImage imageDisp); + +private: + Ui::RecognizeResultForm *ui; + +}; + +#endif // RECOGNIZERESULTFORM_H diff --git a/RecognizeResultForm.ui b/RecognizeResultForm.ui new file mode 100644 index 0000000..9d08547 --- /dev/null +++ b/RecognizeResultForm.ui @@ -0,0 +1,212 @@ + + + RecognizeResultForm + + + + 0 + 0 + 1280 + 800 + + + + Form + + + + + 0 + 0 + 1280 + 800 + + + + + + + :/images/bg_recognize_result.png + + + + + + 0 + 0 + 0 + 0 + + + + + + + Qt::AlignCenter + + + + + + 0 + 0 + 1280 + 90 + + + + + + + 人员识别 + + + Qt::AlignCenter + + + + + + 109 + 119 + 551 + 431 + + + + + + -110 + -70 + 280 + 380 + + + + :/images/photoFace.png + + + Qt::AlignCenter + + + + + + 240 + 220 + 54 + 12 + + + + TextLabel + + + + + + 240 + 10 + 54 + 12 + + + + TextLabel + + + + + + 240 + 160 + 54 + 12 + + + + TextLabel + + + + + + 240 + 90 + 54 + 12 + + + + TextLabel + + + + + + 440 + 260 + 54 + 12 + + + + TextLabel + + + + + + 430 + 130 + 54 + 12 + + + + TextLabel + + + + + + 440 + 200 + 54 + 12 + + + + TextLabel + + + + + + 430 + 50 + 54 + 12 + + + + TextLabel + + + + + + + 550 + 470 + 120 + 80 + + + + + + + + + diff --git a/StartupForm.cpp b/StartupForm.cpp index af51bcc..c8b9c64 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -26,12 +26,13 @@ ui->hsMidd->changeSize(150, 0); // 初始化更新界面的定时器 - // 每分钟执行一次 + // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); - TimeCounterUtil::getInstance().clockCounter->setInterval(1000); - TimeCounterUtil::getInstance().clockCounter->start(); + TimeCounterUtil::getInstance().clockCounter->start(1000); } StartupForm::~StartupForm() @@ -45,6 +46,30 @@ ui->labDate->setText(QDate::currentDate().toString("yyyy-MM-dd")); } +void StartupForm::takeOneFrameForCheckStatus() +{ + if (ProMemory::getInstance().appState != CasicBioRecConst::ApplicationState::STATE_WAIT) + { + // 非待机状态直接返回 + return; + } + + cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); + bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + if (hasFace == true) + { + LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; + + // 启动识别线程 + // 槽函数 CasicBioRecWin::switchToRecognizeForm + emit startRecognize(); + + // 退出 + return ; + } +} + void StartupForm::on_btnUser_clicked() { emit switchToUserListForm(); diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index fe3819d..934dfad 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -1,7 +1,5 @@ #include "CasicBioRecWin.h" #include "ui_CasicBioRecWin.h" -#include -#include CasicBioRecWin::CasicBioRecWin(QWidget *parent) : QMainWindow(parent) @@ -26,11 +24,15 @@ // 初始化识别和注册的各个线程 initFaceRegistThread(); // 人脸注册线程 + initFaceRecogThread(); // 人脸识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); + ProMemory::getInstance().faceCam->openFaceCamera(1000); connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDraw, addPersonForm, &AddPersonForm::drawImageOnForm); + connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDrawForRecognize, + recogResultForm, &RecognizeResultForm::drawImageOnHomeForm); // 打印日志 LOG(INFO) << QString("应用程序启动成功[Application Startup Success]").toStdString(); @@ -43,8 +45,13 @@ ProMemory::getInstance().faceRegistPro->deleteLater(); ProMemory::getInstance().faceRegistPro->wait(); + ProMemory::getInstance().faceRecogPro->exitThread(); + ProMemory::getInstance().faceRecogPro->deleteLater(); + ProMemory::getInstance().faceRecogPro->wait(); + delete ui; delete ProMemory::getInstance().faceRegistPro; + delete ProMemory::getInstance().faceRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -94,6 +101,13 @@ ui->stacked->setCurrentWidget(addPersonForm); ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::ADD_PERSON_FORM; } +void CasicBioRecWin::switchToRecognizeForm() +{ + ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM; + ui->stacked->setCurrentWidget(recogResultForm); + + recogResultForm->startWorkingRecognize(); +} void CasicBioRecWin::initFormsPtr() { @@ -101,18 +115,21 @@ personListForm = new PersonListForm(this); settingForm = new SettingForm(this); addPersonForm = new AddPersonForm(this); + recogResultForm = new RecognizeResultForm(this); ui->stacked->addWidget(startForm); ui->stacked->addWidget(personListForm); ui->stacked->addWidget(settingForm); ui->stacked->addWidget(addPersonForm); - + ui->stacked->addWidget(recogResultForm); // 绑定按钮函数 connect(startForm, &StartupForm::switchToUserListForm, this, &CasicBioRecWin::switchToUserListForm); connect(startForm, &StartupForm::switchToSettingForm, this, &CasicBioRecWin::switchToSettingForm); + connect(startForm, &StartupForm::startRecognize, + this, &CasicBioRecWin::switchToRecognizeForm); connect(personListForm, &PersonListForm::switchToRegistForm, this, &CasicBioRecWin::switchToRegistForm); @@ -146,3 +163,20 @@ ProMemory::getInstance().faceRegistPro->start(); } + +void CasicBioRecWin::initFaceRecogThread() +{ + // 人脸识别处理过程 + ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().faceRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index 3e706fe..f0b47bf 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -2,19 +2,20 @@ #define CASICBIORECWIN_H #include +#include +#include #include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SettingConfig.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" #include "StartupForm.h" #include "PersonListForm.h" #include "SettingForm.h" #include "AddPersonForm.h" +#include "RecognizeResultForm.h" #include "device/FaceCameraController.h" -#include "device/face/FaceDetectRegistProcess.h" QT_BEGIN_NAMESPACE namespace Ui { class CasicBioRecWin; } @@ -33,6 +34,7 @@ void switchToUserListForm(); void switchToSettingForm(); void switchToRegistForm(QString personId); + void switchToRecognizeForm(); private: Ui::CasicBioRecWin *ui; @@ -41,11 +43,13 @@ PersonListForm * personListForm; SettingForm * settingForm; AddPersonForm * addPersonForm; + RecognizeResultForm * recogResultForm; void keyPressEvent(QKeyEvent *event); void initFormsPtr(); void initCacheData(); void initFaceRegistThread(); + void initFaceRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/PersonListForm.h b/PersonListForm.h index db352c6..65bd3f5 100644 --- a/PersonListForm.h +++ b/PersonListForm.h @@ -7,7 +7,7 @@ #include "ConfirmTipsDialog.h" #include "OperationTipsDialog.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" +#include "utils/UtilInclude.h" namespace Ui { class PersonListForm; diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp new file mode 100644 index 0000000..b6790a9 --- /dev/null +++ b/RecognizeResultForm.cpp @@ -0,0 +1,60 @@ +#include "RecognizeResultForm.h" +#include "ui_RecognizeResultForm.h" + +RecognizeResultForm::RecognizeResultForm(QWidget *parent) : + QWidget(parent), + ui(new Ui::RecognizeResultForm) +{ + ui->setupUi(this); + ui->labVideo->hide(); + + // 加载css文件设置控件样式 + QFile file(QApplication::applicationDirPath() + "/qss/recognize.css"); + if (file.open(QFile::ReadOnly)) + { + QString qssStr = QLatin1String(file.readAll()); + this->setStyleSheet(qssStr); + file.close(); + } +} + +RecognizeResultForm::~RecognizeResultForm() +{ + delete ui; +} + +void RecognizeResultForm::startWorkingRecognize() +{ + // 开始人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + + // 将界面切换到识别界面 RecognizeResultForm + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + + // 1人脸图像显示的容器 + ui->labVideo->resize(1060, 607); + ui->labVideo->move(110, 100); + ui->labVideo->raise(); + ui->labVideo->show(); +} + + +void RecognizeResultForm::drawImageOnHomeForm(QImage imageDisp) +{ + if (ui->labVideo->isVisible() == true) + { + LOG(TRACE) << "DRAW IMAGE ON FORM " << imageDisp.width() << "*" << imageDisp.height(); + imageDisp = imageDisp.scaled(1040, 585); + ui->labVideo->setPixmap(QPixmap::fromImage(imageDisp)); + } +} + +void RecognizeResultForm::showRecogFailure() +{ + +} +void RecognizeResultForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功"); +// ui->labVideo->hide(); +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h new file mode 100644 index 0000000..3be5410 --- /dev/null +++ b/RecognizeResultForm.h @@ -0,0 +1,34 @@ +#ifndef RECOGNIZERESULTFORM_H +#define RECOGNIZERESULTFORM_H + +#include + +#include "utils/UtilInclude.h" + +#include "casic/ProMemory.h" + +namespace Ui { +class RecognizeResultForm; +} + +class RecognizeResultForm : public QWidget +{ + Q_OBJECT + +public: + explicit RecognizeResultForm(QWidget *parent = nullptr); + ~RecognizeResultForm(); + +public slots: + void showRecogFailure(); + void showRecognizeResult(QString personId); + + void startWorkingRecognize(); // 开始工作 + void drawImageOnHomeForm(QImage imageDisp); + +private: + Ui::RecognizeResultForm *ui; + +}; + +#endif // RECOGNIZERESULTFORM_H diff --git a/RecognizeResultForm.ui b/RecognizeResultForm.ui new file mode 100644 index 0000000..9d08547 --- /dev/null +++ b/RecognizeResultForm.ui @@ -0,0 +1,212 @@ + + + RecognizeResultForm + + + + 0 + 0 + 1280 + 800 + + + + Form + + + + + 0 + 0 + 1280 + 800 + + + + + + + :/images/bg_recognize_result.png + + + + + + 0 + 0 + 0 + 0 + + + + + + + Qt::AlignCenter + + + + + + 0 + 0 + 1280 + 90 + + + + + + + 人员识别 + + + Qt::AlignCenter + + + + + + 109 + 119 + 551 + 431 + + + + + + -110 + -70 + 280 + 380 + + + + :/images/photoFace.png + + + Qt::AlignCenter + + + + + + 240 + 220 + 54 + 12 + + + + TextLabel + + + + + + 240 + 10 + 54 + 12 + + + + TextLabel + + + + + + 240 + 160 + 54 + 12 + + + + TextLabel + + + + + + 240 + 90 + 54 + 12 + + + + TextLabel + + + + + + 440 + 260 + 54 + 12 + + + + TextLabel + + + + + + 430 + 130 + 54 + 12 + + + + TextLabel + + + + + + 440 + 200 + 54 + 12 + + + + TextLabel + + + + + + 430 + 50 + 54 + 12 + + + + TextLabel + + + + + + + 550 + 470 + 120 + 80 + + + + + + + + + diff --git a/StartupForm.cpp b/StartupForm.cpp index af51bcc..c8b9c64 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -26,12 +26,13 @@ ui->hsMidd->changeSize(150, 0); // 初始化更新界面的定时器 - // 每分钟执行一次 + // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); - TimeCounterUtil::getInstance().clockCounter->setInterval(1000); - TimeCounterUtil::getInstance().clockCounter->start(); + TimeCounterUtil::getInstance().clockCounter->start(1000); } StartupForm::~StartupForm() @@ -45,6 +46,30 @@ ui->labDate->setText(QDate::currentDate().toString("yyyy-MM-dd")); } +void StartupForm::takeOneFrameForCheckStatus() +{ + if (ProMemory::getInstance().appState != CasicBioRecConst::ApplicationState::STATE_WAIT) + { + // 非待机状态直接返回 + return; + } + + cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); + bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + if (hasFace == true) + { + LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; + + // 启动识别线程 + // 槽函数 CasicBioRecWin::switchToRecognizeForm + emit startRecognize(); + + // 退出 + return ; + } +} + void StartupForm::on_btnUser_clicked() { emit switchToUserListForm(); diff --git a/StartupForm.h b/StartupForm.h index 6aed14d..f2850e9 100644 --- a/StartupForm.h +++ b/StartupForm.h @@ -4,9 +4,10 @@ #include #include #include +#include -#include "utils/SettingConfig.h" -#include "utils/TimeCounterUtil.h" +#include "casic/ProMemory.h" +#include "utils/UtilInclude.h" namespace Ui { class StartupForm; @@ -25,12 +26,15 @@ private slots: void updateDateAndTime(); + void takeOneFrameForCheckStatus(); void on_btnUser_clicked(); void on_btnSetting_clicked(); signals: void switchToUserListForm(); void switchToSettingForm(); + + void startRecognize(); }; #endif // STARTUPFORM_H diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index fe3819d..934dfad 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -1,7 +1,5 @@ #include "CasicBioRecWin.h" #include "ui_CasicBioRecWin.h" -#include -#include CasicBioRecWin::CasicBioRecWin(QWidget *parent) : QMainWindow(parent) @@ -26,11 +24,15 @@ // 初始化识别和注册的各个线程 initFaceRegistThread(); // 人脸注册线程 + initFaceRecogThread(); // 人脸识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); + ProMemory::getInstance().faceCam->openFaceCamera(1000); connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDraw, addPersonForm, &AddPersonForm::drawImageOnForm); + connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDrawForRecognize, + recogResultForm, &RecognizeResultForm::drawImageOnHomeForm); // 打印日志 LOG(INFO) << QString("应用程序启动成功[Application Startup Success]").toStdString(); @@ -43,8 +45,13 @@ ProMemory::getInstance().faceRegistPro->deleteLater(); ProMemory::getInstance().faceRegistPro->wait(); + ProMemory::getInstance().faceRecogPro->exitThread(); + ProMemory::getInstance().faceRecogPro->deleteLater(); + ProMemory::getInstance().faceRecogPro->wait(); + delete ui; delete ProMemory::getInstance().faceRegistPro; + delete ProMemory::getInstance().faceRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -94,6 +101,13 @@ ui->stacked->setCurrentWidget(addPersonForm); ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::ADD_PERSON_FORM; } +void CasicBioRecWin::switchToRecognizeForm() +{ + ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM; + ui->stacked->setCurrentWidget(recogResultForm); + + recogResultForm->startWorkingRecognize(); +} void CasicBioRecWin::initFormsPtr() { @@ -101,18 +115,21 @@ personListForm = new PersonListForm(this); settingForm = new SettingForm(this); addPersonForm = new AddPersonForm(this); + recogResultForm = new RecognizeResultForm(this); ui->stacked->addWidget(startForm); ui->stacked->addWidget(personListForm); ui->stacked->addWidget(settingForm); ui->stacked->addWidget(addPersonForm); - + ui->stacked->addWidget(recogResultForm); // 绑定按钮函数 connect(startForm, &StartupForm::switchToUserListForm, this, &CasicBioRecWin::switchToUserListForm); connect(startForm, &StartupForm::switchToSettingForm, this, &CasicBioRecWin::switchToSettingForm); + connect(startForm, &StartupForm::startRecognize, + this, &CasicBioRecWin::switchToRecognizeForm); connect(personListForm, &PersonListForm::switchToRegistForm, this, &CasicBioRecWin::switchToRegistForm); @@ -146,3 +163,20 @@ ProMemory::getInstance().faceRegistPro->start(); } + +void CasicBioRecWin::initFaceRecogThread() +{ + // 人脸识别处理过程 + ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().faceRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index 3e706fe..f0b47bf 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -2,19 +2,20 @@ #define CASICBIORECWIN_H #include +#include +#include #include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SettingConfig.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" #include "StartupForm.h" #include "PersonListForm.h" #include "SettingForm.h" #include "AddPersonForm.h" +#include "RecognizeResultForm.h" #include "device/FaceCameraController.h" -#include "device/face/FaceDetectRegistProcess.h" QT_BEGIN_NAMESPACE namespace Ui { class CasicBioRecWin; } @@ -33,6 +34,7 @@ void switchToUserListForm(); void switchToSettingForm(); void switchToRegistForm(QString personId); + void switchToRecognizeForm(); private: Ui::CasicBioRecWin *ui; @@ -41,11 +43,13 @@ PersonListForm * personListForm; SettingForm * settingForm; AddPersonForm * addPersonForm; + RecognizeResultForm * recogResultForm; void keyPressEvent(QKeyEvent *event); void initFormsPtr(); void initCacheData(); void initFaceRegistThread(); + void initFaceRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/PersonListForm.h b/PersonListForm.h index db352c6..65bd3f5 100644 --- a/PersonListForm.h +++ b/PersonListForm.h @@ -7,7 +7,7 @@ #include "ConfirmTipsDialog.h" #include "OperationTipsDialog.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" +#include "utils/UtilInclude.h" namespace Ui { class PersonListForm; diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp new file mode 100644 index 0000000..b6790a9 --- /dev/null +++ b/RecognizeResultForm.cpp @@ -0,0 +1,60 @@ +#include "RecognizeResultForm.h" +#include "ui_RecognizeResultForm.h" + +RecognizeResultForm::RecognizeResultForm(QWidget *parent) : + QWidget(parent), + ui(new Ui::RecognizeResultForm) +{ + ui->setupUi(this); + ui->labVideo->hide(); + + // 加载css文件设置控件样式 + QFile file(QApplication::applicationDirPath() + "/qss/recognize.css"); + if (file.open(QFile::ReadOnly)) + { + QString qssStr = QLatin1String(file.readAll()); + this->setStyleSheet(qssStr); + file.close(); + } +} + +RecognizeResultForm::~RecognizeResultForm() +{ + delete ui; +} + +void RecognizeResultForm::startWorkingRecognize() +{ + // 开始人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + + // 将界面切换到识别界面 RecognizeResultForm + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + + // 1人脸图像显示的容器 + ui->labVideo->resize(1060, 607); + ui->labVideo->move(110, 100); + ui->labVideo->raise(); + ui->labVideo->show(); +} + + +void RecognizeResultForm::drawImageOnHomeForm(QImage imageDisp) +{ + if (ui->labVideo->isVisible() == true) + { + LOG(TRACE) << "DRAW IMAGE ON FORM " << imageDisp.width() << "*" << imageDisp.height(); + imageDisp = imageDisp.scaled(1040, 585); + ui->labVideo->setPixmap(QPixmap::fromImage(imageDisp)); + } +} + +void RecognizeResultForm::showRecogFailure() +{ + +} +void RecognizeResultForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功"); +// ui->labVideo->hide(); +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h new file mode 100644 index 0000000..3be5410 --- /dev/null +++ b/RecognizeResultForm.h @@ -0,0 +1,34 @@ +#ifndef RECOGNIZERESULTFORM_H +#define RECOGNIZERESULTFORM_H + +#include + +#include "utils/UtilInclude.h" + +#include "casic/ProMemory.h" + +namespace Ui { +class RecognizeResultForm; +} + +class RecognizeResultForm : public QWidget +{ + Q_OBJECT + +public: + explicit RecognizeResultForm(QWidget *parent = nullptr); + ~RecognizeResultForm(); + +public slots: + void showRecogFailure(); + void showRecognizeResult(QString personId); + + void startWorkingRecognize(); // 开始工作 + void drawImageOnHomeForm(QImage imageDisp); + +private: + Ui::RecognizeResultForm *ui; + +}; + +#endif // RECOGNIZERESULTFORM_H diff --git a/RecognizeResultForm.ui b/RecognizeResultForm.ui new file mode 100644 index 0000000..9d08547 --- /dev/null +++ b/RecognizeResultForm.ui @@ -0,0 +1,212 @@ + + + RecognizeResultForm + + + + 0 + 0 + 1280 + 800 + + + + Form + + + + + 0 + 0 + 1280 + 800 + + + + + + + :/images/bg_recognize_result.png + + + + + + 0 + 0 + 0 + 0 + + + + + + + Qt::AlignCenter + + + + + + 0 + 0 + 1280 + 90 + + + + + + + 人员识别 + + + Qt::AlignCenter + + + + + + 109 + 119 + 551 + 431 + + + + + + -110 + -70 + 280 + 380 + + + + :/images/photoFace.png + + + Qt::AlignCenter + + + + + + 240 + 220 + 54 + 12 + + + + TextLabel + + + + + + 240 + 10 + 54 + 12 + + + + TextLabel + + + + + + 240 + 160 + 54 + 12 + + + + TextLabel + + + + + + 240 + 90 + 54 + 12 + + + + TextLabel + + + + + + 440 + 260 + 54 + 12 + + + + TextLabel + + + + + + 430 + 130 + 54 + 12 + + + + TextLabel + + + + + + 440 + 200 + 54 + 12 + + + + TextLabel + + + + + + 430 + 50 + 54 + 12 + + + + TextLabel + + + + + + + 550 + 470 + 120 + 80 + + + + + + + + + diff --git a/StartupForm.cpp b/StartupForm.cpp index af51bcc..c8b9c64 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -26,12 +26,13 @@ ui->hsMidd->changeSize(150, 0); // 初始化更新界面的定时器 - // 每分钟执行一次 + // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); - TimeCounterUtil::getInstance().clockCounter->setInterval(1000); - TimeCounterUtil::getInstance().clockCounter->start(); + TimeCounterUtil::getInstance().clockCounter->start(1000); } StartupForm::~StartupForm() @@ -45,6 +46,30 @@ ui->labDate->setText(QDate::currentDate().toString("yyyy-MM-dd")); } +void StartupForm::takeOneFrameForCheckStatus() +{ + if (ProMemory::getInstance().appState != CasicBioRecConst::ApplicationState::STATE_WAIT) + { + // 非待机状态直接返回 + return; + } + + cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); + bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + if (hasFace == true) + { + LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; + + // 启动识别线程 + // 槽函数 CasicBioRecWin::switchToRecognizeForm + emit startRecognize(); + + // 退出 + return ; + } +} + void StartupForm::on_btnUser_clicked() { emit switchToUserListForm(); diff --git a/StartupForm.h b/StartupForm.h index 6aed14d..f2850e9 100644 --- a/StartupForm.h +++ b/StartupForm.h @@ -4,9 +4,10 @@ #include #include #include +#include -#include "utils/SettingConfig.h" -#include "utils/TimeCounterUtil.h" +#include "casic/ProMemory.h" +#include "utils/UtilInclude.h" namespace Ui { class StartupForm; @@ -25,12 +26,15 @@ private slots: void updateDateAndTime(); + void takeOneFrameForCheckStatus(); void on_btnUser_clicked(); void on_btnSetting_clicked(); signals: void switchToUserListForm(); void switchToSettingForm(); + + void startRecognize(); }; #endif // STARTUPFORM_H diff --git a/casic/CasicBioRecConst.h b/casic/CasicBioRecConst.h index f55c84f..78d150b 100644 --- a/casic/CasicBioRecConst.h +++ b/casic/CasicBioRecConst.h @@ -12,7 +12,13 @@ ADD_PERSON_CAPTURE_FACE = 21, // 添加/编辑人员时进行人脸拍图 ADD_PERSON_CAPTURE_IRIS = 22, // 添加/编辑人员时进行虹膜拍图 SETTING_FORM = 3, // 设置页面 - RECOGNIZE_SUCCESS_FORM = 4 // 识别成功界面 + RECOGNIZE_RESULT_FORM = 4 // 识别结果界面 + }; + + enum ApplicationState + { + STATE_WAIT = 0, // 待机 + STATE_WORKING = 1, // 工作状态 }; }; diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index fe3819d..934dfad 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -1,7 +1,5 @@ #include "CasicBioRecWin.h" #include "ui_CasicBioRecWin.h" -#include -#include CasicBioRecWin::CasicBioRecWin(QWidget *parent) : QMainWindow(parent) @@ -26,11 +24,15 @@ // 初始化识别和注册的各个线程 initFaceRegistThread(); // 人脸注册线程 + initFaceRecogThread(); // 人脸识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); + ProMemory::getInstance().faceCam->openFaceCamera(1000); connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDraw, addPersonForm, &AddPersonForm::drawImageOnForm); + connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDrawForRecognize, + recogResultForm, &RecognizeResultForm::drawImageOnHomeForm); // 打印日志 LOG(INFO) << QString("应用程序启动成功[Application Startup Success]").toStdString(); @@ -43,8 +45,13 @@ ProMemory::getInstance().faceRegistPro->deleteLater(); ProMemory::getInstance().faceRegistPro->wait(); + ProMemory::getInstance().faceRecogPro->exitThread(); + ProMemory::getInstance().faceRecogPro->deleteLater(); + ProMemory::getInstance().faceRecogPro->wait(); + delete ui; delete ProMemory::getInstance().faceRegistPro; + delete ProMemory::getInstance().faceRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -94,6 +101,13 @@ ui->stacked->setCurrentWidget(addPersonForm); ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::ADD_PERSON_FORM; } +void CasicBioRecWin::switchToRecognizeForm() +{ + ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM; + ui->stacked->setCurrentWidget(recogResultForm); + + recogResultForm->startWorkingRecognize(); +} void CasicBioRecWin::initFormsPtr() { @@ -101,18 +115,21 @@ personListForm = new PersonListForm(this); settingForm = new SettingForm(this); addPersonForm = new AddPersonForm(this); + recogResultForm = new RecognizeResultForm(this); ui->stacked->addWidget(startForm); ui->stacked->addWidget(personListForm); ui->stacked->addWidget(settingForm); ui->stacked->addWidget(addPersonForm); - + ui->stacked->addWidget(recogResultForm); // 绑定按钮函数 connect(startForm, &StartupForm::switchToUserListForm, this, &CasicBioRecWin::switchToUserListForm); connect(startForm, &StartupForm::switchToSettingForm, this, &CasicBioRecWin::switchToSettingForm); + connect(startForm, &StartupForm::startRecognize, + this, &CasicBioRecWin::switchToRecognizeForm); connect(personListForm, &PersonListForm::switchToRegistForm, this, &CasicBioRecWin::switchToRegistForm); @@ -146,3 +163,20 @@ ProMemory::getInstance().faceRegistPro->start(); } + +void CasicBioRecWin::initFaceRecogThread() +{ + // 人脸识别处理过程 + ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().faceRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index 3e706fe..f0b47bf 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -2,19 +2,20 @@ #define CASICBIORECWIN_H #include +#include +#include #include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SettingConfig.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" #include "StartupForm.h" #include "PersonListForm.h" #include "SettingForm.h" #include "AddPersonForm.h" +#include "RecognizeResultForm.h" #include "device/FaceCameraController.h" -#include "device/face/FaceDetectRegistProcess.h" QT_BEGIN_NAMESPACE namespace Ui { class CasicBioRecWin; } @@ -33,6 +34,7 @@ void switchToUserListForm(); void switchToSettingForm(); void switchToRegistForm(QString personId); + void switchToRecognizeForm(); private: Ui::CasicBioRecWin *ui; @@ -41,11 +43,13 @@ PersonListForm * personListForm; SettingForm * settingForm; AddPersonForm * addPersonForm; + RecognizeResultForm * recogResultForm; void keyPressEvent(QKeyEvent *event); void initFormsPtr(); void initCacheData(); void initFaceRegistThread(); + void initFaceRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/PersonListForm.h b/PersonListForm.h index db352c6..65bd3f5 100644 --- a/PersonListForm.h +++ b/PersonListForm.h @@ -7,7 +7,7 @@ #include "ConfirmTipsDialog.h" #include "OperationTipsDialog.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" +#include "utils/UtilInclude.h" namespace Ui { class PersonListForm; diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp new file mode 100644 index 0000000..b6790a9 --- /dev/null +++ b/RecognizeResultForm.cpp @@ -0,0 +1,60 @@ +#include "RecognizeResultForm.h" +#include "ui_RecognizeResultForm.h" + +RecognizeResultForm::RecognizeResultForm(QWidget *parent) : + QWidget(parent), + ui(new Ui::RecognizeResultForm) +{ + ui->setupUi(this); + ui->labVideo->hide(); + + // 加载css文件设置控件样式 + QFile file(QApplication::applicationDirPath() + "/qss/recognize.css"); + if (file.open(QFile::ReadOnly)) + { + QString qssStr = QLatin1String(file.readAll()); + this->setStyleSheet(qssStr); + file.close(); + } +} + +RecognizeResultForm::~RecognizeResultForm() +{ + delete ui; +} + +void RecognizeResultForm::startWorkingRecognize() +{ + // 开始人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + + // 将界面切换到识别界面 RecognizeResultForm + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + + // 1人脸图像显示的容器 + ui->labVideo->resize(1060, 607); + ui->labVideo->move(110, 100); + ui->labVideo->raise(); + ui->labVideo->show(); +} + + +void RecognizeResultForm::drawImageOnHomeForm(QImage imageDisp) +{ + if (ui->labVideo->isVisible() == true) + { + LOG(TRACE) << "DRAW IMAGE ON FORM " << imageDisp.width() << "*" << imageDisp.height(); + imageDisp = imageDisp.scaled(1040, 585); + ui->labVideo->setPixmap(QPixmap::fromImage(imageDisp)); + } +} + +void RecognizeResultForm::showRecogFailure() +{ + +} +void RecognizeResultForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功"); +// ui->labVideo->hide(); +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h new file mode 100644 index 0000000..3be5410 --- /dev/null +++ b/RecognizeResultForm.h @@ -0,0 +1,34 @@ +#ifndef RECOGNIZERESULTFORM_H +#define RECOGNIZERESULTFORM_H + +#include + +#include "utils/UtilInclude.h" + +#include "casic/ProMemory.h" + +namespace Ui { +class RecognizeResultForm; +} + +class RecognizeResultForm : public QWidget +{ + Q_OBJECT + +public: + explicit RecognizeResultForm(QWidget *parent = nullptr); + ~RecognizeResultForm(); + +public slots: + void showRecogFailure(); + void showRecognizeResult(QString personId); + + void startWorkingRecognize(); // 开始工作 + void drawImageOnHomeForm(QImage imageDisp); + +private: + Ui::RecognizeResultForm *ui; + +}; + +#endif // RECOGNIZERESULTFORM_H diff --git a/RecognizeResultForm.ui b/RecognizeResultForm.ui new file mode 100644 index 0000000..9d08547 --- /dev/null +++ b/RecognizeResultForm.ui @@ -0,0 +1,212 @@ + + + RecognizeResultForm + + + + 0 + 0 + 1280 + 800 + + + + Form + + + + + 0 + 0 + 1280 + 800 + + + + + + + :/images/bg_recognize_result.png + + + + + + 0 + 0 + 0 + 0 + + + + + + + Qt::AlignCenter + + + + + + 0 + 0 + 1280 + 90 + + + + + + + 人员识别 + + + Qt::AlignCenter + + + + + + 109 + 119 + 551 + 431 + + + + + + -110 + -70 + 280 + 380 + + + + :/images/photoFace.png + + + Qt::AlignCenter + + + + + + 240 + 220 + 54 + 12 + + + + TextLabel + + + + + + 240 + 10 + 54 + 12 + + + + TextLabel + + + + + + 240 + 160 + 54 + 12 + + + + TextLabel + + + + + + 240 + 90 + 54 + 12 + + + + TextLabel + + + + + + 440 + 260 + 54 + 12 + + + + TextLabel + + + + + + 430 + 130 + 54 + 12 + + + + TextLabel + + + + + + 440 + 200 + 54 + 12 + + + + TextLabel + + + + + + 430 + 50 + 54 + 12 + + + + TextLabel + + + + + + + 550 + 470 + 120 + 80 + + + + + + + + + diff --git a/StartupForm.cpp b/StartupForm.cpp index af51bcc..c8b9c64 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -26,12 +26,13 @@ ui->hsMidd->changeSize(150, 0); // 初始化更新界面的定时器 - // 每分钟执行一次 + // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); - TimeCounterUtil::getInstance().clockCounter->setInterval(1000); - TimeCounterUtil::getInstance().clockCounter->start(); + TimeCounterUtil::getInstance().clockCounter->start(1000); } StartupForm::~StartupForm() @@ -45,6 +46,30 @@ ui->labDate->setText(QDate::currentDate().toString("yyyy-MM-dd")); } +void StartupForm::takeOneFrameForCheckStatus() +{ + if (ProMemory::getInstance().appState != CasicBioRecConst::ApplicationState::STATE_WAIT) + { + // 非待机状态直接返回 + return; + } + + cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); + bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + if (hasFace == true) + { + LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; + + // 启动识别线程 + // 槽函数 CasicBioRecWin::switchToRecognizeForm + emit startRecognize(); + + // 退出 + return ; + } +} + void StartupForm::on_btnUser_clicked() { emit switchToUserListForm(); diff --git a/StartupForm.h b/StartupForm.h index 6aed14d..f2850e9 100644 --- a/StartupForm.h +++ b/StartupForm.h @@ -4,9 +4,10 @@ #include #include #include +#include -#include "utils/SettingConfig.h" -#include "utils/TimeCounterUtil.h" +#include "casic/ProMemory.h" +#include "utils/UtilInclude.h" namespace Ui { class StartupForm; @@ -25,12 +26,15 @@ private slots: void updateDateAndTime(); + void takeOneFrameForCheckStatus(); void on_btnUser_clicked(); void on_btnSetting_clicked(); signals: void switchToUserListForm(); void switchToSettingForm(); + + void startRecognize(); }; #endif // STARTUPFORM_H diff --git a/casic/CasicBioRecConst.h b/casic/CasicBioRecConst.h index f55c84f..78d150b 100644 --- a/casic/CasicBioRecConst.h +++ b/casic/CasicBioRecConst.h @@ -12,7 +12,13 @@ ADD_PERSON_CAPTURE_FACE = 21, // 添加/编辑人员时进行人脸拍图 ADD_PERSON_CAPTURE_IRIS = 22, // 添加/编辑人员时进行虹膜拍图 SETTING_FORM = 3, // 设置页面 - RECOGNIZE_SUCCESS_FORM = 4 // 识别成功界面 + RECOGNIZE_RESULT_FORM = 4 // 识别结果界面 + }; + + enum ApplicationState + { + STATE_WAIT = 0, // 待机 + STATE_WORKING = 1, // 工作状态 }; }; diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 33010d2..6454343 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -12,9 +12,11 @@ #include "device/FaceCameraController.h" #include "device/face/FaceDetectRegistProcess.h" +#include "device/face/FaceDetectRecogProcess.h" class FaceCameraController; class FaceDetectRegistProcess; +class FaceDetectRecogProcess; class ProMemory { @@ -41,7 +43,8 @@ bool isIrisQueueEmpty(); void clearIrisQueue(); - volatile int widgeFrame; + volatile int widgeFrame = 0; // 当前显示的界面 + volatile int appState = 0; // 当前程序所处的状态 QString capFaceOrIris; // 注册虹膜或者人脸 void initFaceFeatures(); // 初始化人脸特征值集合 @@ -51,6 +54,8 @@ FaceCameraController * faceCam; FaceDetectRegistProcess * faceRegistPro; + FaceDetectRecogProcess * faceRecogPro; + private: ProMemory(); diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index fe3819d..934dfad 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -1,7 +1,5 @@ #include "CasicBioRecWin.h" #include "ui_CasicBioRecWin.h" -#include -#include CasicBioRecWin::CasicBioRecWin(QWidget *parent) : QMainWindow(parent) @@ -26,11 +24,15 @@ // 初始化识别和注册的各个线程 initFaceRegistThread(); // 人脸注册线程 + initFaceRecogThread(); // 人脸识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); + ProMemory::getInstance().faceCam->openFaceCamera(1000); connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDraw, addPersonForm, &AddPersonForm::drawImageOnForm); + connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDrawForRecognize, + recogResultForm, &RecognizeResultForm::drawImageOnHomeForm); // 打印日志 LOG(INFO) << QString("应用程序启动成功[Application Startup Success]").toStdString(); @@ -43,8 +45,13 @@ ProMemory::getInstance().faceRegistPro->deleteLater(); ProMemory::getInstance().faceRegistPro->wait(); + ProMemory::getInstance().faceRecogPro->exitThread(); + ProMemory::getInstance().faceRecogPro->deleteLater(); + ProMemory::getInstance().faceRecogPro->wait(); + delete ui; delete ProMemory::getInstance().faceRegistPro; + delete ProMemory::getInstance().faceRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -94,6 +101,13 @@ ui->stacked->setCurrentWidget(addPersonForm); ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::ADD_PERSON_FORM; } +void CasicBioRecWin::switchToRecognizeForm() +{ + ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM; + ui->stacked->setCurrentWidget(recogResultForm); + + recogResultForm->startWorkingRecognize(); +} void CasicBioRecWin::initFormsPtr() { @@ -101,18 +115,21 @@ personListForm = new PersonListForm(this); settingForm = new SettingForm(this); addPersonForm = new AddPersonForm(this); + recogResultForm = new RecognizeResultForm(this); ui->stacked->addWidget(startForm); ui->stacked->addWidget(personListForm); ui->stacked->addWidget(settingForm); ui->stacked->addWidget(addPersonForm); - + ui->stacked->addWidget(recogResultForm); // 绑定按钮函数 connect(startForm, &StartupForm::switchToUserListForm, this, &CasicBioRecWin::switchToUserListForm); connect(startForm, &StartupForm::switchToSettingForm, this, &CasicBioRecWin::switchToSettingForm); + connect(startForm, &StartupForm::startRecognize, + this, &CasicBioRecWin::switchToRecognizeForm); connect(personListForm, &PersonListForm::switchToRegistForm, this, &CasicBioRecWin::switchToRegistForm); @@ -146,3 +163,20 @@ ProMemory::getInstance().faceRegistPro->start(); } + +void CasicBioRecWin::initFaceRecogThread() +{ + // 人脸识别处理过程 + ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().faceRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index 3e706fe..f0b47bf 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -2,19 +2,20 @@ #define CASICBIORECWIN_H #include +#include +#include #include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SettingConfig.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" #include "StartupForm.h" #include "PersonListForm.h" #include "SettingForm.h" #include "AddPersonForm.h" +#include "RecognizeResultForm.h" #include "device/FaceCameraController.h" -#include "device/face/FaceDetectRegistProcess.h" QT_BEGIN_NAMESPACE namespace Ui { class CasicBioRecWin; } @@ -33,6 +34,7 @@ void switchToUserListForm(); void switchToSettingForm(); void switchToRegistForm(QString personId); + void switchToRecognizeForm(); private: Ui::CasicBioRecWin *ui; @@ -41,11 +43,13 @@ PersonListForm * personListForm; SettingForm * settingForm; AddPersonForm * addPersonForm; + RecognizeResultForm * recogResultForm; void keyPressEvent(QKeyEvent *event); void initFormsPtr(); void initCacheData(); void initFaceRegistThread(); + void initFaceRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/PersonListForm.h b/PersonListForm.h index db352c6..65bd3f5 100644 --- a/PersonListForm.h +++ b/PersonListForm.h @@ -7,7 +7,7 @@ #include "ConfirmTipsDialog.h" #include "OperationTipsDialog.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" +#include "utils/UtilInclude.h" namespace Ui { class PersonListForm; diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp new file mode 100644 index 0000000..b6790a9 --- /dev/null +++ b/RecognizeResultForm.cpp @@ -0,0 +1,60 @@ +#include "RecognizeResultForm.h" +#include "ui_RecognizeResultForm.h" + +RecognizeResultForm::RecognizeResultForm(QWidget *parent) : + QWidget(parent), + ui(new Ui::RecognizeResultForm) +{ + ui->setupUi(this); + ui->labVideo->hide(); + + // 加载css文件设置控件样式 + QFile file(QApplication::applicationDirPath() + "/qss/recognize.css"); + if (file.open(QFile::ReadOnly)) + { + QString qssStr = QLatin1String(file.readAll()); + this->setStyleSheet(qssStr); + file.close(); + } +} + +RecognizeResultForm::~RecognizeResultForm() +{ + delete ui; +} + +void RecognizeResultForm::startWorkingRecognize() +{ + // 开始人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + + // 将界面切换到识别界面 RecognizeResultForm + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + + // 1人脸图像显示的容器 + ui->labVideo->resize(1060, 607); + ui->labVideo->move(110, 100); + ui->labVideo->raise(); + ui->labVideo->show(); +} + + +void RecognizeResultForm::drawImageOnHomeForm(QImage imageDisp) +{ + if (ui->labVideo->isVisible() == true) + { + LOG(TRACE) << "DRAW IMAGE ON FORM " << imageDisp.width() << "*" << imageDisp.height(); + imageDisp = imageDisp.scaled(1040, 585); + ui->labVideo->setPixmap(QPixmap::fromImage(imageDisp)); + } +} + +void RecognizeResultForm::showRecogFailure() +{ + +} +void RecognizeResultForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功"); +// ui->labVideo->hide(); +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h new file mode 100644 index 0000000..3be5410 --- /dev/null +++ b/RecognizeResultForm.h @@ -0,0 +1,34 @@ +#ifndef RECOGNIZERESULTFORM_H +#define RECOGNIZERESULTFORM_H + +#include + +#include "utils/UtilInclude.h" + +#include "casic/ProMemory.h" + +namespace Ui { +class RecognizeResultForm; +} + +class RecognizeResultForm : public QWidget +{ + Q_OBJECT + +public: + explicit RecognizeResultForm(QWidget *parent = nullptr); + ~RecognizeResultForm(); + +public slots: + void showRecogFailure(); + void showRecognizeResult(QString personId); + + void startWorkingRecognize(); // 开始工作 + void drawImageOnHomeForm(QImage imageDisp); + +private: + Ui::RecognizeResultForm *ui; + +}; + +#endif // RECOGNIZERESULTFORM_H diff --git a/RecognizeResultForm.ui b/RecognizeResultForm.ui new file mode 100644 index 0000000..9d08547 --- /dev/null +++ b/RecognizeResultForm.ui @@ -0,0 +1,212 @@ + + + RecognizeResultForm + + + + 0 + 0 + 1280 + 800 + + + + Form + + + + + 0 + 0 + 1280 + 800 + + + + + + + :/images/bg_recognize_result.png + + + + + + 0 + 0 + 0 + 0 + + + + + + + Qt::AlignCenter + + + + + + 0 + 0 + 1280 + 90 + + + + + + + 人员识别 + + + Qt::AlignCenter + + + + + + 109 + 119 + 551 + 431 + + + + + + -110 + -70 + 280 + 380 + + + + :/images/photoFace.png + + + Qt::AlignCenter + + + + + + 240 + 220 + 54 + 12 + + + + TextLabel + + + + + + 240 + 10 + 54 + 12 + + + + TextLabel + + + + + + 240 + 160 + 54 + 12 + + + + TextLabel + + + + + + 240 + 90 + 54 + 12 + + + + TextLabel + + + + + + 440 + 260 + 54 + 12 + + + + TextLabel + + + + + + 430 + 130 + 54 + 12 + + + + TextLabel + + + + + + 440 + 200 + 54 + 12 + + + + TextLabel + + + + + + 430 + 50 + 54 + 12 + + + + TextLabel + + + + + + + 550 + 470 + 120 + 80 + + + + + + + + + diff --git a/StartupForm.cpp b/StartupForm.cpp index af51bcc..c8b9c64 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -26,12 +26,13 @@ ui->hsMidd->changeSize(150, 0); // 初始化更新界面的定时器 - // 每分钟执行一次 + // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); - TimeCounterUtil::getInstance().clockCounter->setInterval(1000); - TimeCounterUtil::getInstance().clockCounter->start(); + TimeCounterUtil::getInstance().clockCounter->start(1000); } StartupForm::~StartupForm() @@ -45,6 +46,30 @@ ui->labDate->setText(QDate::currentDate().toString("yyyy-MM-dd")); } +void StartupForm::takeOneFrameForCheckStatus() +{ + if (ProMemory::getInstance().appState != CasicBioRecConst::ApplicationState::STATE_WAIT) + { + // 非待机状态直接返回 + return; + } + + cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); + bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + if (hasFace == true) + { + LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; + + // 启动识别线程 + // 槽函数 CasicBioRecWin::switchToRecognizeForm + emit startRecognize(); + + // 退出 + return ; + } +} + void StartupForm::on_btnUser_clicked() { emit switchToUserListForm(); diff --git a/StartupForm.h b/StartupForm.h index 6aed14d..f2850e9 100644 --- a/StartupForm.h +++ b/StartupForm.h @@ -4,9 +4,10 @@ #include #include #include +#include -#include "utils/SettingConfig.h" -#include "utils/TimeCounterUtil.h" +#include "casic/ProMemory.h" +#include "utils/UtilInclude.h" namespace Ui { class StartupForm; @@ -25,12 +26,15 @@ private slots: void updateDateAndTime(); + void takeOneFrameForCheckStatus(); void on_btnUser_clicked(); void on_btnSetting_clicked(); signals: void switchToUserListForm(); void switchToSettingForm(); + + void startRecognize(); }; #endif // STARTUPFORM_H diff --git a/casic/CasicBioRecConst.h b/casic/CasicBioRecConst.h index f55c84f..78d150b 100644 --- a/casic/CasicBioRecConst.h +++ b/casic/CasicBioRecConst.h @@ -12,7 +12,13 @@ ADD_PERSON_CAPTURE_FACE = 21, // 添加/编辑人员时进行人脸拍图 ADD_PERSON_CAPTURE_IRIS = 22, // 添加/编辑人员时进行虹膜拍图 SETTING_FORM = 3, // 设置页面 - RECOGNIZE_SUCCESS_FORM = 4 // 识别成功界面 + RECOGNIZE_RESULT_FORM = 4 // 识别结果界面 + }; + + enum ApplicationState + { + STATE_WAIT = 0, // 待机 + STATE_WORKING = 1, // 工作状态 }; }; diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 33010d2..6454343 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -12,9 +12,11 @@ #include "device/FaceCameraController.h" #include "device/face/FaceDetectRegistProcess.h" +#include "device/face/FaceDetectRecogProcess.h" class FaceCameraController; class FaceDetectRegistProcess; +class FaceDetectRecogProcess; class ProMemory { @@ -41,7 +43,8 @@ bool isIrisQueueEmpty(); void clearIrisQueue(); - volatile int widgeFrame; + volatile int widgeFrame = 0; // 当前显示的界面 + volatile int appState = 0; // 当前程序所处的状态 QString capFaceOrIris; // 注册虹膜或者人脸 void initFaceFeatures(); // 初始化人脸特征值集合 @@ -51,6 +54,8 @@ FaceCameraController * faceCam; FaceDetectRegistProcess * faceRegistPro; + FaceDetectRecogProcess * faceRecogPro; + private: ProMemory(); diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index 5e09b86..cb4d3bd 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -402,6 +402,42 @@ return rect.at(0); } +bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} +bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) +{ + // 构建openCV自带的眼睛分类器 + if (this->eyeCascade == nullptr) + { + this->eyeCascade = new cv::CascadeClassifier(); + this->eyeCascade->load(cvEyeCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minEyeSize, minEyeSize); + cv::Size maxRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + eyeCascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} + void casic::face::CasicFaceInterface::setMinFaceSize(int minFaceSize) { this->minFaceSize = minFaceSize; diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index fe3819d..934dfad 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -1,7 +1,5 @@ #include "CasicBioRecWin.h" #include "ui_CasicBioRecWin.h" -#include -#include CasicBioRecWin::CasicBioRecWin(QWidget *parent) : QMainWindow(parent) @@ -26,11 +24,15 @@ // 初始化识别和注册的各个线程 initFaceRegistThread(); // 人脸注册线程 + initFaceRecogThread(); // 人脸识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); + ProMemory::getInstance().faceCam->openFaceCamera(1000); connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDraw, addPersonForm, &AddPersonForm::drawImageOnForm); + connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDrawForRecognize, + recogResultForm, &RecognizeResultForm::drawImageOnHomeForm); // 打印日志 LOG(INFO) << QString("应用程序启动成功[Application Startup Success]").toStdString(); @@ -43,8 +45,13 @@ ProMemory::getInstance().faceRegistPro->deleteLater(); ProMemory::getInstance().faceRegistPro->wait(); + ProMemory::getInstance().faceRecogPro->exitThread(); + ProMemory::getInstance().faceRecogPro->deleteLater(); + ProMemory::getInstance().faceRecogPro->wait(); + delete ui; delete ProMemory::getInstance().faceRegistPro; + delete ProMemory::getInstance().faceRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -94,6 +101,13 @@ ui->stacked->setCurrentWidget(addPersonForm); ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::ADD_PERSON_FORM; } +void CasicBioRecWin::switchToRecognizeForm() +{ + ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM; + ui->stacked->setCurrentWidget(recogResultForm); + + recogResultForm->startWorkingRecognize(); +} void CasicBioRecWin::initFormsPtr() { @@ -101,18 +115,21 @@ personListForm = new PersonListForm(this); settingForm = new SettingForm(this); addPersonForm = new AddPersonForm(this); + recogResultForm = new RecognizeResultForm(this); ui->stacked->addWidget(startForm); ui->stacked->addWidget(personListForm); ui->stacked->addWidget(settingForm); ui->stacked->addWidget(addPersonForm); - + ui->stacked->addWidget(recogResultForm); // 绑定按钮函数 connect(startForm, &StartupForm::switchToUserListForm, this, &CasicBioRecWin::switchToUserListForm); connect(startForm, &StartupForm::switchToSettingForm, this, &CasicBioRecWin::switchToSettingForm); + connect(startForm, &StartupForm::startRecognize, + this, &CasicBioRecWin::switchToRecognizeForm); connect(personListForm, &PersonListForm::switchToRegistForm, this, &CasicBioRecWin::switchToRegistForm); @@ -146,3 +163,20 @@ ProMemory::getInstance().faceRegistPro->start(); } + +void CasicBioRecWin::initFaceRecogThread() +{ + // 人脸识别处理过程 + ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().faceRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index 3e706fe..f0b47bf 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -2,19 +2,20 @@ #define CASICBIORECWIN_H #include +#include +#include #include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SettingConfig.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" #include "StartupForm.h" #include "PersonListForm.h" #include "SettingForm.h" #include "AddPersonForm.h" +#include "RecognizeResultForm.h" #include "device/FaceCameraController.h" -#include "device/face/FaceDetectRegistProcess.h" QT_BEGIN_NAMESPACE namespace Ui { class CasicBioRecWin; } @@ -33,6 +34,7 @@ void switchToUserListForm(); void switchToSettingForm(); void switchToRegistForm(QString personId); + void switchToRecognizeForm(); private: Ui::CasicBioRecWin *ui; @@ -41,11 +43,13 @@ PersonListForm * personListForm; SettingForm * settingForm; AddPersonForm * addPersonForm; + RecognizeResultForm * recogResultForm; void keyPressEvent(QKeyEvent *event); void initFormsPtr(); void initCacheData(); void initFaceRegistThread(); + void initFaceRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/PersonListForm.h b/PersonListForm.h index db352c6..65bd3f5 100644 --- a/PersonListForm.h +++ b/PersonListForm.h @@ -7,7 +7,7 @@ #include "ConfirmTipsDialog.h" #include "OperationTipsDialog.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" +#include "utils/UtilInclude.h" namespace Ui { class PersonListForm; diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp new file mode 100644 index 0000000..b6790a9 --- /dev/null +++ b/RecognizeResultForm.cpp @@ -0,0 +1,60 @@ +#include "RecognizeResultForm.h" +#include "ui_RecognizeResultForm.h" + +RecognizeResultForm::RecognizeResultForm(QWidget *parent) : + QWidget(parent), + ui(new Ui::RecognizeResultForm) +{ + ui->setupUi(this); + ui->labVideo->hide(); + + // 加载css文件设置控件样式 + QFile file(QApplication::applicationDirPath() + "/qss/recognize.css"); + if (file.open(QFile::ReadOnly)) + { + QString qssStr = QLatin1String(file.readAll()); + this->setStyleSheet(qssStr); + file.close(); + } +} + +RecognizeResultForm::~RecognizeResultForm() +{ + delete ui; +} + +void RecognizeResultForm::startWorkingRecognize() +{ + // 开始人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + + // 将界面切换到识别界面 RecognizeResultForm + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + + // 1人脸图像显示的容器 + ui->labVideo->resize(1060, 607); + ui->labVideo->move(110, 100); + ui->labVideo->raise(); + ui->labVideo->show(); +} + + +void RecognizeResultForm::drawImageOnHomeForm(QImage imageDisp) +{ + if (ui->labVideo->isVisible() == true) + { + LOG(TRACE) << "DRAW IMAGE ON FORM " << imageDisp.width() << "*" << imageDisp.height(); + imageDisp = imageDisp.scaled(1040, 585); + ui->labVideo->setPixmap(QPixmap::fromImage(imageDisp)); + } +} + +void RecognizeResultForm::showRecogFailure() +{ + +} +void RecognizeResultForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功"); +// ui->labVideo->hide(); +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h new file mode 100644 index 0000000..3be5410 --- /dev/null +++ b/RecognizeResultForm.h @@ -0,0 +1,34 @@ +#ifndef RECOGNIZERESULTFORM_H +#define RECOGNIZERESULTFORM_H + +#include + +#include "utils/UtilInclude.h" + +#include "casic/ProMemory.h" + +namespace Ui { +class RecognizeResultForm; +} + +class RecognizeResultForm : public QWidget +{ + Q_OBJECT + +public: + explicit RecognizeResultForm(QWidget *parent = nullptr); + ~RecognizeResultForm(); + +public slots: + void showRecogFailure(); + void showRecognizeResult(QString personId); + + void startWorkingRecognize(); // 开始工作 + void drawImageOnHomeForm(QImage imageDisp); + +private: + Ui::RecognizeResultForm *ui; + +}; + +#endif // RECOGNIZERESULTFORM_H diff --git a/RecognizeResultForm.ui b/RecognizeResultForm.ui new file mode 100644 index 0000000..9d08547 --- /dev/null +++ b/RecognizeResultForm.ui @@ -0,0 +1,212 @@ + + + RecognizeResultForm + + + + 0 + 0 + 1280 + 800 + + + + Form + + + + + 0 + 0 + 1280 + 800 + + + + + + + :/images/bg_recognize_result.png + + + + + + 0 + 0 + 0 + 0 + + + + + + + Qt::AlignCenter + + + + + + 0 + 0 + 1280 + 90 + + + + + + + 人员识别 + + + Qt::AlignCenter + + + + + + 109 + 119 + 551 + 431 + + + + + + -110 + -70 + 280 + 380 + + + + :/images/photoFace.png + + + Qt::AlignCenter + + + + + + 240 + 220 + 54 + 12 + + + + TextLabel + + + + + + 240 + 10 + 54 + 12 + + + + TextLabel + + + + + + 240 + 160 + 54 + 12 + + + + TextLabel + + + + + + 240 + 90 + 54 + 12 + + + + TextLabel + + + + + + 440 + 260 + 54 + 12 + + + + TextLabel + + + + + + 430 + 130 + 54 + 12 + + + + TextLabel + + + + + + 440 + 200 + 54 + 12 + + + + TextLabel + + + + + + 430 + 50 + 54 + 12 + + + + TextLabel + + + + + + + 550 + 470 + 120 + 80 + + + + + + + + + diff --git a/StartupForm.cpp b/StartupForm.cpp index af51bcc..c8b9c64 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -26,12 +26,13 @@ ui->hsMidd->changeSize(150, 0); // 初始化更新界面的定时器 - // 每分钟执行一次 + // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); - TimeCounterUtil::getInstance().clockCounter->setInterval(1000); - TimeCounterUtil::getInstance().clockCounter->start(); + TimeCounterUtil::getInstance().clockCounter->start(1000); } StartupForm::~StartupForm() @@ -45,6 +46,30 @@ ui->labDate->setText(QDate::currentDate().toString("yyyy-MM-dd")); } +void StartupForm::takeOneFrameForCheckStatus() +{ + if (ProMemory::getInstance().appState != CasicBioRecConst::ApplicationState::STATE_WAIT) + { + // 非待机状态直接返回 + return; + } + + cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); + bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + if (hasFace == true) + { + LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; + + // 启动识别线程 + // 槽函数 CasicBioRecWin::switchToRecognizeForm + emit startRecognize(); + + // 退出 + return ; + } +} + void StartupForm::on_btnUser_clicked() { emit switchToUserListForm(); diff --git a/StartupForm.h b/StartupForm.h index 6aed14d..f2850e9 100644 --- a/StartupForm.h +++ b/StartupForm.h @@ -4,9 +4,10 @@ #include #include #include +#include -#include "utils/SettingConfig.h" -#include "utils/TimeCounterUtil.h" +#include "casic/ProMemory.h" +#include "utils/UtilInclude.h" namespace Ui { class StartupForm; @@ -25,12 +26,15 @@ private slots: void updateDateAndTime(); + void takeOneFrameForCheckStatus(); void on_btnUser_clicked(); void on_btnSetting_clicked(); signals: void switchToUserListForm(); void switchToSettingForm(); + + void startRecognize(); }; #endif // STARTUPFORM_H diff --git a/casic/CasicBioRecConst.h b/casic/CasicBioRecConst.h index f55c84f..78d150b 100644 --- a/casic/CasicBioRecConst.h +++ b/casic/CasicBioRecConst.h @@ -12,7 +12,13 @@ ADD_PERSON_CAPTURE_FACE = 21, // 添加/编辑人员时进行人脸拍图 ADD_PERSON_CAPTURE_IRIS = 22, // 添加/编辑人员时进行虹膜拍图 SETTING_FORM = 3, // 设置页面 - RECOGNIZE_SUCCESS_FORM = 4 // 识别成功界面 + RECOGNIZE_RESULT_FORM = 4 // 识别结果界面 + }; + + enum ApplicationState + { + STATE_WAIT = 0, // 待机 + STATE_WORKING = 1, // 工作状态 }; }; diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 33010d2..6454343 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -12,9 +12,11 @@ #include "device/FaceCameraController.h" #include "device/face/FaceDetectRegistProcess.h" +#include "device/face/FaceDetectRecogProcess.h" class FaceCameraController; class FaceDetectRegistProcess; +class FaceDetectRecogProcess; class ProMemory { @@ -41,7 +43,8 @@ bool isIrisQueueEmpty(); void clearIrisQueue(); - volatile int widgeFrame; + volatile int widgeFrame = 0; // 当前显示的界面 + volatile int appState = 0; // 当前程序所处的状态 QString capFaceOrIris; // 注册虹膜或者人脸 void initFaceFeatures(); // 初始化人脸特征值集合 @@ -51,6 +54,8 @@ FaceCameraController * faceCam; FaceDetectRegistProcess * faceRegistPro; + FaceDetectRecogProcess * faceRecogPro; + private: ProMemory(); diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index 5e09b86..cb4d3bd 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -402,6 +402,42 @@ return rect.at(0); } +bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} +bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) +{ + // 构建openCV自带的眼睛分类器 + if (this->eyeCascade == nullptr) + { + this->eyeCascade = new cv::CascadeClassifier(); + this->eyeCascade->load(cvEyeCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minEyeSize, minEyeSize); + cv::Size maxRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + eyeCascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} + void casic::face::CasicFaceInterface::setMinFaceSize(int minFaceSize) { this->minFaceSize = minFaceSize; diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index d6d4494..8a1c564 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -50,6 +50,8 @@ cv::Rect faceDetectByCVCascade(cv::Mat frame); cv::Rect eyeDetectByCVCascade(cv::Mat frame); + bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); + bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); private: diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index fe3819d..934dfad 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -1,7 +1,5 @@ #include "CasicBioRecWin.h" #include "ui_CasicBioRecWin.h" -#include -#include CasicBioRecWin::CasicBioRecWin(QWidget *parent) : QMainWindow(parent) @@ -26,11 +24,15 @@ // 初始化识别和注册的各个线程 initFaceRegistThread(); // 人脸注册线程 + initFaceRecogThread(); // 人脸识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); + ProMemory::getInstance().faceCam->openFaceCamera(1000); connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDraw, addPersonForm, &AddPersonForm::drawImageOnForm); + connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDrawForRecognize, + recogResultForm, &RecognizeResultForm::drawImageOnHomeForm); // 打印日志 LOG(INFO) << QString("应用程序启动成功[Application Startup Success]").toStdString(); @@ -43,8 +45,13 @@ ProMemory::getInstance().faceRegistPro->deleteLater(); ProMemory::getInstance().faceRegistPro->wait(); + ProMemory::getInstance().faceRecogPro->exitThread(); + ProMemory::getInstance().faceRecogPro->deleteLater(); + ProMemory::getInstance().faceRecogPro->wait(); + delete ui; delete ProMemory::getInstance().faceRegistPro; + delete ProMemory::getInstance().faceRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -94,6 +101,13 @@ ui->stacked->setCurrentWidget(addPersonForm); ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::ADD_PERSON_FORM; } +void CasicBioRecWin::switchToRecognizeForm() +{ + ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM; + ui->stacked->setCurrentWidget(recogResultForm); + + recogResultForm->startWorkingRecognize(); +} void CasicBioRecWin::initFormsPtr() { @@ -101,18 +115,21 @@ personListForm = new PersonListForm(this); settingForm = new SettingForm(this); addPersonForm = new AddPersonForm(this); + recogResultForm = new RecognizeResultForm(this); ui->stacked->addWidget(startForm); ui->stacked->addWidget(personListForm); ui->stacked->addWidget(settingForm); ui->stacked->addWidget(addPersonForm); - + ui->stacked->addWidget(recogResultForm); // 绑定按钮函数 connect(startForm, &StartupForm::switchToUserListForm, this, &CasicBioRecWin::switchToUserListForm); connect(startForm, &StartupForm::switchToSettingForm, this, &CasicBioRecWin::switchToSettingForm); + connect(startForm, &StartupForm::startRecognize, + this, &CasicBioRecWin::switchToRecognizeForm); connect(personListForm, &PersonListForm::switchToRegistForm, this, &CasicBioRecWin::switchToRegistForm); @@ -146,3 +163,20 @@ ProMemory::getInstance().faceRegistPro->start(); } + +void CasicBioRecWin::initFaceRecogThread() +{ + // 人脸识别处理过程 + ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().faceRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index 3e706fe..f0b47bf 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -2,19 +2,20 @@ #define CASICBIORECWIN_H #include +#include +#include #include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SettingConfig.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" #include "StartupForm.h" #include "PersonListForm.h" #include "SettingForm.h" #include "AddPersonForm.h" +#include "RecognizeResultForm.h" #include "device/FaceCameraController.h" -#include "device/face/FaceDetectRegistProcess.h" QT_BEGIN_NAMESPACE namespace Ui { class CasicBioRecWin; } @@ -33,6 +34,7 @@ void switchToUserListForm(); void switchToSettingForm(); void switchToRegistForm(QString personId); + void switchToRecognizeForm(); private: Ui::CasicBioRecWin *ui; @@ -41,11 +43,13 @@ PersonListForm * personListForm; SettingForm * settingForm; AddPersonForm * addPersonForm; + RecognizeResultForm * recogResultForm; void keyPressEvent(QKeyEvent *event); void initFormsPtr(); void initCacheData(); void initFaceRegistThread(); + void initFaceRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/PersonListForm.h b/PersonListForm.h index db352c6..65bd3f5 100644 --- a/PersonListForm.h +++ b/PersonListForm.h @@ -7,7 +7,7 @@ #include "ConfirmTipsDialog.h" #include "OperationTipsDialog.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" +#include "utils/UtilInclude.h" namespace Ui { class PersonListForm; diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp new file mode 100644 index 0000000..b6790a9 --- /dev/null +++ b/RecognizeResultForm.cpp @@ -0,0 +1,60 @@ +#include "RecognizeResultForm.h" +#include "ui_RecognizeResultForm.h" + +RecognizeResultForm::RecognizeResultForm(QWidget *parent) : + QWidget(parent), + ui(new Ui::RecognizeResultForm) +{ + ui->setupUi(this); + ui->labVideo->hide(); + + // 加载css文件设置控件样式 + QFile file(QApplication::applicationDirPath() + "/qss/recognize.css"); + if (file.open(QFile::ReadOnly)) + { + QString qssStr = QLatin1String(file.readAll()); + this->setStyleSheet(qssStr); + file.close(); + } +} + +RecognizeResultForm::~RecognizeResultForm() +{ + delete ui; +} + +void RecognizeResultForm::startWorkingRecognize() +{ + // 开始人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + + // 将界面切换到识别界面 RecognizeResultForm + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + + // 1人脸图像显示的容器 + ui->labVideo->resize(1060, 607); + ui->labVideo->move(110, 100); + ui->labVideo->raise(); + ui->labVideo->show(); +} + + +void RecognizeResultForm::drawImageOnHomeForm(QImage imageDisp) +{ + if (ui->labVideo->isVisible() == true) + { + LOG(TRACE) << "DRAW IMAGE ON FORM " << imageDisp.width() << "*" << imageDisp.height(); + imageDisp = imageDisp.scaled(1040, 585); + ui->labVideo->setPixmap(QPixmap::fromImage(imageDisp)); + } +} + +void RecognizeResultForm::showRecogFailure() +{ + +} +void RecognizeResultForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功"); +// ui->labVideo->hide(); +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h new file mode 100644 index 0000000..3be5410 --- /dev/null +++ b/RecognizeResultForm.h @@ -0,0 +1,34 @@ +#ifndef RECOGNIZERESULTFORM_H +#define RECOGNIZERESULTFORM_H + +#include + +#include "utils/UtilInclude.h" + +#include "casic/ProMemory.h" + +namespace Ui { +class RecognizeResultForm; +} + +class RecognizeResultForm : public QWidget +{ + Q_OBJECT + +public: + explicit RecognizeResultForm(QWidget *parent = nullptr); + ~RecognizeResultForm(); + +public slots: + void showRecogFailure(); + void showRecognizeResult(QString personId); + + void startWorkingRecognize(); // 开始工作 + void drawImageOnHomeForm(QImage imageDisp); + +private: + Ui::RecognizeResultForm *ui; + +}; + +#endif // RECOGNIZERESULTFORM_H diff --git a/RecognizeResultForm.ui b/RecognizeResultForm.ui new file mode 100644 index 0000000..9d08547 --- /dev/null +++ b/RecognizeResultForm.ui @@ -0,0 +1,212 @@ + + + RecognizeResultForm + + + + 0 + 0 + 1280 + 800 + + + + Form + + + + + 0 + 0 + 1280 + 800 + + + + + + + :/images/bg_recognize_result.png + + + + + + 0 + 0 + 0 + 0 + + + + + + + Qt::AlignCenter + + + + + + 0 + 0 + 1280 + 90 + + + + + + + 人员识别 + + + Qt::AlignCenter + + + + + + 109 + 119 + 551 + 431 + + + + + + -110 + -70 + 280 + 380 + + + + :/images/photoFace.png + + + Qt::AlignCenter + + + + + + 240 + 220 + 54 + 12 + + + + TextLabel + + + + + + 240 + 10 + 54 + 12 + + + + TextLabel + + + + + + 240 + 160 + 54 + 12 + + + + TextLabel + + + + + + 240 + 90 + 54 + 12 + + + + TextLabel + + + + + + 440 + 260 + 54 + 12 + + + + TextLabel + + + + + + 430 + 130 + 54 + 12 + + + + TextLabel + + + + + + 440 + 200 + 54 + 12 + + + + TextLabel + + + + + + 430 + 50 + 54 + 12 + + + + TextLabel + + + + + + + 550 + 470 + 120 + 80 + + + + + + + + + diff --git a/StartupForm.cpp b/StartupForm.cpp index af51bcc..c8b9c64 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -26,12 +26,13 @@ ui->hsMidd->changeSize(150, 0); // 初始化更新界面的定时器 - // 每分钟执行一次 + // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); - TimeCounterUtil::getInstance().clockCounter->setInterval(1000); - TimeCounterUtil::getInstance().clockCounter->start(); + TimeCounterUtil::getInstance().clockCounter->start(1000); } StartupForm::~StartupForm() @@ -45,6 +46,30 @@ ui->labDate->setText(QDate::currentDate().toString("yyyy-MM-dd")); } +void StartupForm::takeOneFrameForCheckStatus() +{ + if (ProMemory::getInstance().appState != CasicBioRecConst::ApplicationState::STATE_WAIT) + { + // 非待机状态直接返回 + return; + } + + cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); + bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + if (hasFace == true) + { + LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; + + // 启动识别线程 + // 槽函数 CasicBioRecWin::switchToRecognizeForm + emit startRecognize(); + + // 退出 + return ; + } +} + void StartupForm::on_btnUser_clicked() { emit switchToUserListForm(); diff --git a/StartupForm.h b/StartupForm.h index 6aed14d..f2850e9 100644 --- a/StartupForm.h +++ b/StartupForm.h @@ -4,9 +4,10 @@ #include #include #include +#include -#include "utils/SettingConfig.h" -#include "utils/TimeCounterUtil.h" +#include "casic/ProMemory.h" +#include "utils/UtilInclude.h" namespace Ui { class StartupForm; @@ -25,12 +26,15 @@ private slots: void updateDateAndTime(); + void takeOneFrameForCheckStatus(); void on_btnUser_clicked(); void on_btnSetting_clicked(); signals: void switchToUserListForm(); void switchToSettingForm(); + + void startRecognize(); }; #endif // STARTUPFORM_H diff --git a/casic/CasicBioRecConst.h b/casic/CasicBioRecConst.h index f55c84f..78d150b 100644 --- a/casic/CasicBioRecConst.h +++ b/casic/CasicBioRecConst.h @@ -12,7 +12,13 @@ ADD_PERSON_CAPTURE_FACE = 21, // 添加/编辑人员时进行人脸拍图 ADD_PERSON_CAPTURE_IRIS = 22, // 添加/编辑人员时进行虹膜拍图 SETTING_FORM = 3, // 设置页面 - RECOGNIZE_SUCCESS_FORM = 4 // 识别成功界面 + RECOGNIZE_RESULT_FORM = 4 // 识别结果界面 + }; + + enum ApplicationState + { + STATE_WAIT = 0, // 待机 + STATE_WORKING = 1, // 工作状态 }; }; diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 33010d2..6454343 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -12,9 +12,11 @@ #include "device/FaceCameraController.h" #include "device/face/FaceDetectRegistProcess.h" +#include "device/face/FaceDetectRecogProcess.h" class FaceCameraController; class FaceDetectRegistProcess; +class FaceDetectRecogProcess; class ProMemory { @@ -41,7 +43,8 @@ bool isIrisQueueEmpty(); void clearIrisQueue(); - volatile int widgeFrame; + volatile int widgeFrame = 0; // 当前显示的界面 + volatile int appState = 0; // 当前程序所处的状态 QString capFaceOrIris; // 注册虹膜或者人脸 void initFaceFeatures(); // 初始化人脸特征值集合 @@ -51,6 +54,8 @@ FaceCameraController * faceCam; FaceDetectRegistProcess * faceRegistPro; + FaceDetectRecogProcess * faceRecogPro; + private: ProMemory(); diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index 5e09b86..cb4d3bd 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -402,6 +402,42 @@ return rect.at(0); } +bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} +bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) +{ + // 构建openCV自带的眼睛分类器 + if (this->eyeCascade == nullptr) + { + this->eyeCascade = new cv::CascadeClassifier(); + this->eyeCascade->load(cvEyeCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minEyeSize, minEyeSize); + cv::Size maxRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + eyeCascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} + void casic::face::CasicFaceInterface::setMinFaceSize(int minFaceSize) { this->minFaceSize = minFaceSize; diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index d6d4494..8a1c564 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -50,6 +50,8 @@ cv::Rect faceDetectByCVCascade(cv::Mat frame); cv::Rect eyeDetectByCVCascade(cv::Mat frame); + bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); + bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); private: diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 5f0e2ae..493fdb7 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -6,7 +6,18 @@ FaceCameraController::FaceCameraController(QObject *parent) : QObject(parent) { + this->faceCap = new cv::VideoCapture(SettingConfig::getInstance().FACE_CAMERA_INDEX, cv::CAP_DSHOW); + faceCap->set(cv::CAP_PROP_FRAME_WIDTH, SettingConfig::getInstance().FACE_FRAME_WIDTH); + faceCap->set(cv::CAP_PROP_FRAME_HEIGHT, SettingConfig::getInstance().FACE_FRAME_HEIGHT); + LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]初始化相机[%1][%2 * %3]") + .arg(SettingConfig::getInstance().FACE_CAMERA_INDEX) + .arg(SettingConfig::getInstance().FACE_FRAME_WIDTH) + .arg(SettingConfig::getInstance().FACE_FRAME_HEIGHT).toStdString(); + + // 获取定时器, 绑定定时函数 + connect(TimeCounterUtil::getInstance().faceCapCounter, &QTimer::timeout, + this, &FaceCameraController::getOneFaceFrm); } FaceCameraController::~FaceCameraController() @@ -15,25 +26,11 @@ } -void FaceCameraController::openFaceCamera() +void FaceCameraController::openFaceCamera(int mInterval) { - // 获取定时器, 绑定定时函数 - connect(TimeCounterUtil::getInstance().faceCapCounter, &QTimer::timeout, - this, &FaceCameraController::getOneFaceFrm); - - this->faceCap = new cv::VideoCapture(SettingConfig::getInstance().FACE_CAMERA_INDEX, cv::CAP_DSHOW); - faceCap->set(cv::CAP_PROP_FRAME_WIDTH, SettingConfig::getInstance().FACE_FRAME_WIDTH); - faceCap->set(cv::CAP_PROP_FRAME_HEIGHT, SettingConfig::getInstance().FACE_FRAME_HEIGHT); - - LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]打开相机[%1][%2 * %3]") - .arg(SettingConfig::getInstance().FACE_CAMERA_INDEX) - .arg(SettingConfig::getInstance().FACE_FRAME_WIDTH) - .arg(SettingConfig::getInstance().FACE_FRAME_HEIGHT).toStdString(); - // 启动定时器 - TimeCounterUtil::getInstance().faceCapCounter->start(SettingConfig::getInstance().FACE_FRAME_INTERVAL); - LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]相机开始拍图[%1ms]") - .arg(SettingConfig::getInstance().FACE_FRAME_INTERVAL).toStdString(); + TimeCounterUtil::getInstance().faceCapCounter->start(mInterval); + LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]相机开始拍图[%1ms]").arg(mInterval).toStdString(); } void FaceCameraController::stopTakingPhoto() @@ -87,5 +84,39 @@ // 发送信号用于界面显示 emit sendImageToDraw(imgDisplay); + } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM) + { + // 拍图 + faceCap->read(faceMat); + + LOG(TRACE) << "TAKE ONE FACE FRAME " << faceMat.cols << " * " << faceMat.rows; + + // 左右翻转 + cv::Mat imageMatMiir; + flip(faceMat, imageMatMiir, 1); + + // clone一个mat, 用于界面显示 + cv::Mat faceMatDisp = imageMatMiir.clone(); + + CasicFaceInfo faceInfo; + faceInfo.hasFace = false; + faceInfo.matData = imageMatMiir; + + // 将图片数据压入堆栈 + ProMemory::getInstance().pushCasicFace(faceInfo); + + // 将mat转成QImage + QImage imgDisplay = ImageUtil::MatImageToQImage(faceMatDisp); + + // 发送信号用于界面显示 + emit sendImageToDrawForRecognize(imgDisplay); } } + +cv::Mat FaceCameraController::takeOneRawFrame() +{ + // 拍图 + cv::Mat camMat; + faceCap->read(camMat); + return camMat; +} diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index fe3819d..934dfad 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -1,7 +1,5 @@ #include "CasicBioRecWin.h" #include "ui_CasicBioRecWin.h" -#include -#include CasicBioRecWin::CasicBioRecWin(QWidget *parent) : QMainWindow(parent) @@ -26,11 +24,15 @@ // 初始化识别和注册的各个线程 initFaceRegistThread(); // 人脸注册线程 + initFaceRecogThread(); // 人脸识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); + ProMemory::getInstance().faceCam->openFaceCamera(1000); connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDraw, addPersonForm, &AddPersonForm::drawImageOnForm); + connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDrawForRecognize, + recogResultForm, &RecognizeResultForm::drawImageOnHomeForm); // 打印日志 LOG(INFO) << QString("应用程序启动成功[Application Startup Success]").toStdString(); @@ -43,8 +45,13 @@ ProMemory::getInstance().faceRegistPro->deleteLater(); ProMemory::getInstance().faceRegistPro->wait(); + ProMemory::getInstance().faceRecogPro->exitThread(); + ProMemory::getInstance().faceRecogPro->deleteLater(); + ProMemory::getInstance().faceRecogPro->wait(); + delete ui; delete ProMemory::getInstance().faceRegistPro; + delete ProMemory::getInstance().faceRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -94,6 +101,13 @@ ui->stacked->setCurrentWidget(addPersonForm); ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::ADD_PERSON_FORM; } +void CasicBioRecWin::switchToRecognizeForm() +{ + ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM; + ui->stacked->setCurrentWidget(recogResultForm); + + recogResultForm->startWorkingRecognize(); +} void CasicBioRecWin::initFormsPtr() { @@ -101,18 +115,21 @@ personListForm = new PersonListForm(this); settingForm = new SettingForm(this); addPersonForm = new AddPersonForm(this); + recogResultForm = new RecognizeResultForm(this); ui->stacked->addWidget(startForm); ui->stacked->addWidget(personListForm); ui->stacked->addWidget(settingForm); ui->stacked->addWidget(addPersonForm); - + ui->stacked->addWidget(recogResultForm); // 绑定按钮函数 connect(startForm, &StartupForm::switchToUserListForm, this, &CasicBioRecWin::switchToUserListForm); connect(startForm, &StartupForm::switchToSettingForm, this, &CasicBioRecWin::switchToSettingForm); + connect(startForm, &StartupForm::startRecognize, + this, &CasicBioRecWin::switchToRecognizeForm); connect(personListForm, &PersonListForm::switchToRegistForm, this, &CasicBioRecWin::switchToRegistForm); @@ -146,3 +163,20 @@ ProMemory::getInstance().faceRegistPro->start(); } + +void CasicBioRecWin::initFaceRecogThread() +{ + // 人脸识别处理过程 + ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().faceRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index 3e706fe..f0b47bf 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -2,19 +2,20 @@ #define CASICBIORECWIN_H #include +#include +#include #include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SettingConfig.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" #include "StartupForm.h" #include "PersonListForm.h" #include "SettingForm.h" #include "AddPersonForm.h" +#include "RecognizeResultForm.h" #include "device/FaceCameraController.h" -#include "device/face/FaceDetectRegistProcess.h" QT_BEGIN_NAMESPACE namespace Ui { class CasicBioRecWin; } @@ -33,6 +34,7 @@ void switchToUserListForm(); void switchToSettingForm(); void switchToRegistForm(QString personId); + void switchToRecognizeForm(); private: Ui::CasicBioRecWin *ui; @@ -41,11 +43,13 @@ PersonListForm * personListForm; SettingForm * settingForm; AddPersonForm * addPersonForm; + RecognizeResultForm * recogResultForm; void keyPressEvent(QKeyEvent *event); void initFormsPtr(); void initCacheData(); void initFaceRegistThread(); + void initFaceRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/PersonListForm.h b/PersonListForm.h index db352c6..65bd3f5 100644 --- a/PersonListForm.h +++ b/PersonListForm.h @@ -7,7 +7,7 @@ #include "ConfirmTipsDialog.h" #include "OperationTipsDialog.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" +#include "utils/UtilInclude.h" namespace Ui { class PersonListForm; diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp new file mode 100644 index 0000000..b6790a9 --- /dev/null +++ b/RecognizeResultForm.cpp @@ -0,0 +1,60 @@ +#include "RecognizeResultForm.h" +#include "ui_RecognizeResultForm.h" + +RecognizeResultForm::RecognizeResultForm(QWidget *parent) : + QWidget(parent), + ui(new Ui::RecognizeResultForm) +{ + ui->setupUi(this); + ui->labVideo->hide(); + + // 加载css文件设置控件样式 + QFile file(QApplication::applicationDirPath() + "/qss/recognize.css"); + if (file.open(QFile::ReadOnly)) + { + QString qssStr = QLatin1String(file.readAll()); + this->setStyleSheet(qssStr); + file.close(); + } +} + +RecognizeResultForm::~RecognizeResultForm() +{ + delete ui; +} + +void RecognizeResultForm::startWorkingRecognize() +{ + // 开始人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + + // 将界面切换到识别界面 RecognizeResultForm + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + + // 1人脸图像显示的容器 + ui->labVideo->resize(1060, 607); + ui->labVideo->move(110, 100); + ui->labVideo->raise(); + ui->labVideo->show(); +} + + +void RecognizeResultForm::drawImageOnHomeForm(QImage imageDisp) +{ + if (ui->labVideo->isVisible() == true) + { + LOG(TRACE) << "DRAW IMAGE ON FORM " << imageDisp.width() << "*" << imageDisp.height(); + imageDisp = imageDisp.scaled(1040, 585); + ui->labVideo->setPixmap(QPixmap::fromImage(imageDisp)); + } +} + +void RecognizeResultForm::showRecogFailure() +{ + +} +void RecognizeResultForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功"); +// ui->labVideo->hide(); +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h new file mode 100644 index 0000000..3be5410 --- /dev/null +++ b/RecognizeResultForm.h @@ -0,0 +1,34 @@ +#ifndef RECOGNIZERESULTFORM_H +#define RECOGNIZERESULTFORM_H + +#include + +#include "utils/UtilInclude.h" + +#include "casic/ProMemory.h" + +namespace Ui { +class RecognizeResultForm; +} + +class RecognizeResultForm : public QWidget +{ + Q_OBJECT + +public: + explicit RecognizeResultForm(QWidget *parent = nullptr); + ~RecognizeResultForm(); + +public slots: + void showRecogFailure(); + void showRecognizeResult(QString personId); + + void startWorkingRecognize(); // 开始工作 + void drawImageOnHomeForm(QImage imageDisp); + +private: + Ui::RecognizeResultForm *ui; + +}; + +#endif // RECOGNIZERESULTFORM_H diff --git a/RecognizeResultForm.ui b/RecognizeResultForm.ui new file mode 100644 index 0000000..9d08547 --- /dev/null +++ b/RecognizeResultForm.ui @@ -0,0 +1,212 @@ + + + RecognizeResultForm + + + + 0 + 0 + 1280 + 800 + + + + Form + + + + + 0 + 0 + 1280 + 800 + + + + + + + :/images/bg_recognize_result.png + + + + + + 0 + 0 + 0 + 0 + + + + + + + Qt::AlignCenter + + + + + + 0 + 0 + 1280 + 90 + + + + + + + 人员识别 + + + Qt::AlignCenter + + + + + + 109 + 119 + 551 + 431 + + + + + + -110 + -70 + 280 + 380 + + + + :/images/photoFace.png + + + Qt::AlignCenter + + + + + + 240 + 220 + 54 + 12 + + + + TextLabel + + + + + + 240 + 10 + 54 + 12 + + + + TextLabel + + + + + + 240 + 160 + 54 + 12 + + + + TextLabel + + + + + + 240 + 90 + 54 + 12 + + + + TextLabel + + + + + + 440 + 260 + 54 + 12 + + + + TextLabel + + + + + + 430 + 130 + 54 + 12 + + + + TextLabel + + + + + + 440 + 200 + 54 + 12 + + + + TextLabel + + + + + + 430 + 50 + 54 + 12 + + + + TextLabel + + + + + + + 550 + 470 + 120 + 80 + + + + + + + + + diff --git a/StartupForm.cpp b/StartupForm.cpp index af51bcc..c8b9c64 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -26,12 +26,13 @@ ui->hsMidd->changeSize(150, 0); // 初始化更新界面的定时器 - // 每分钟执行一次 + // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); - TimeCounterUtil::getInstance().clockCounter->setInterval(1000); - TimeCounterUtil::getInstance().clockCounter->start(); + TimeCounterUtil::getInstance().clockCounter->start(1000); } StartupForm::~StartupForm() @@ -45,6 +46,30 @@ ui->labDate->setText(QDate::currentDate().toString("yyyy-MM-dd")); } +void StartupForm::takeOneFrameForCheckStatus() +{ + if (ProMemory::getInstance().appState != CasicBioRecConst::ApplicationState::STATE_WAIT) + { + // 非待机状态直接返回 + return; + } + + cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); + bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + if (hasFace == true) + { + LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; + + // 启动识别线程 + // 槽函数 CasicBioRecWin::switchToRecognizeForm + emit startRecognize(); + + // 退出 + return ; + } +} + void StartupForm::on_btnUser_clicked() { emit switchToUserListForm(); diff --git a/StartupForm.h b/StartupForm.h index 6aed14d..f2850e9 100644 --- a/StartupForm.h +++ b/StartupForm.h @@ -4,9 +4,10 @@ #include #include #include +#include -#include "utils/SettingConfig.h" -#include "utils/TimeCounterUtil.h" +#include "casic/ProMemory.h" +#include "utils/UtilInclude.h" namespace Ui { class StartupForm; @@ -25,12 +26,15 @@ private slots: void updateDateAndTime(); + void takeOneFrameForCheckStatus(); void on_btnUser_clicked(); void on_btnSetting_clicked(); signals: void switchToUserListForm(); void switchToSettingForm(); + + void startRecognize(); }; #endif // STARTUPFORM_H diff --git a/casic/CasicBioRecConst.h b/casic/CasicBioRecConst.h index f55c84f..78d150b 100644 --- a/casic/CasicBioRecConst.h +++ b/casic/CasicBioRecConst.h @@ -12,7 +12,13 @@ ADD_PERSON_CAPTURE_FACE = 21, // 添加/编辑人员时进行人脸拍图 ADD_PERSON_CAPTURE_IRIS = 22, // 添加/编辑人员时进行虹膜拍图 SETTING_FORM = 3, // 设置页面 - RECOGNIZE_SUCCESS_FORM = 4 // 识别成功界面 + RECOGNIZE_RESULT_FORM = 4 // 识别结果界面 + }; + + enum ApplicationState + { + STATE_WAIT = 0, // 待机 + STATE_WORKING = 1, // 工作状态 }; }; diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 33010d2..6454343 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -12,9 +12,11 @@ #include "device/FaceCameraController.h" #include "device/face/FaceDetectRegistProcess.h" +#include "device/face/FaceDetectRecogProcess.h" class FaceCameraController; class FaceDetectRegistProcess; +class FaceDetectRecogProcess; class ProMemory { @@ -41,7 +43,8 @@ bool isIrisQueueEmpty(); void clearIrisQueue(); - volatile int widgeFrame; + volatile int widgeFrame = 0; // 当前显示的界面 + volatile int appState = 0; // 当前程序所处的状态 QString capFaceOrIris; // 注册虹膜或者人脸 void initFaceFeatures(); // 初始化人脸特征值集合 @@ -51,6 +54,8 @@ FaceCameraController * faceCam; FaceDetectRegistProcess * faceRegistPro; + FaceDetectRecogProcess * faceRecogPro; + private: ProMemory(); diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index 5e09b86..cb4d3bd 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -402,6 +402,42 @@ return rect.at(0); } +bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} +bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) +{ + // 构建openCV自带的眼睛分类器 + if (this->eyeCascade == nullptr) + { + this->eyeCascade = new cv::CascadeClassifier(); + this->eyeCascade->load(cvEyeCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minEyeSize, minEyeSize); + cv::Size maxRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + eyeCascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} + void casic::face::CasicFaceInterface::setMinFaceSize(int minFaceSize) { this->minFaceSize = minFaceSize; diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index d6d4494..8a1c564 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -50,6 +50,8 @@ cv::Rect faceDetectByCVCascade(cv::Mat frame); cv::Rect eyeDetectByCVCascade(cv::Mat frame); + bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); + bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); private: diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 5f0e2ae..493fdb7 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -6,7 +6,18 @@ FaceCameraController::FaceCameraController(QObject *parent) : QObject(parent) { + this->faceCap = new cv::VideoCapture(SettingConfig::getInstance().FACE_CAMERA_INDEX, cv::CAP_DSHOW); + faceCap->set(cv::CAP_PROP_FRAME_WIDTH, SettingConfig::getInstance().FACE_FRAME_WIDTH); + faceCap->set(cv::CAP_PROP_FRAME_HEIGHT, SettingConfig::getInstance().FACE_FRAME_HEIGHT); + LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]初始化相机[%1][%2 * %3]") + .arg(SettingConfig::getInstance().FACE_CAMERA_INDEX) + .arg(SettingConfig::getInstance().FACE_FRAME_WIDTH) + .arg(SettingConfig::getInstance().FACE_FRAME_HEIGHT).toStdString(); + + // 获取定时器, 绑定定时函数 + connect(TimeCounterUtil::getInstance().faceCapCounter, &QTimer::timeout, + this, &FaceCameraController::getOneFaceFrm); } FaceCameraController::~FaceCameraController() @@ -15,25 +26,11 @@ } -void FaceCameraController::openFaceCamera() +void FaceCameraController::openFaceCamera(int mInterval) { - // 获取定时器, 绑定定时函数 - connect(TimeCounterUtil::getInstance().faceCapCounter, &QTimer::timeout, - this, &FaceCameraController::getOneFaceFrm); - - this->faceCap = new cv::VideoCapture(SettingConfig::getInstance().FACE_CAMERA_INDEX, cv::CAP_DSHOW); - faceCap->set(cv::CAP_PROP_FRAME_WIDTH, SettingConfig::getInstance().FACE_FRAME_WIDTH); - faceCap->set(cv::CAP_PROP_FRAME_HEIGHT, SettingConfig::getInstance().FACE_FRAME_HEIGHT); - - LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]打开相机[%1][%2 * %3]") - .arg(SettingConfig::getInstance().FACE_CAMERA_INDEX) - .arg(SettingConfig::getInstance().FACE_FRAME_WIDTH) - .arg(SettingConfig::getInstance().FACE_FRAME_HEIGHT).toStdString(); - // 启动定时器 - TimeCounterUtil::getInstance().faceCapCounter->start(SettingConfig::getInstance().FACE_FRAME_INTERVAL); - LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]相机开始拍图[%1ms]") - .arg(SettingConfig::getInstance().FACE_FRAME_INTERVAL).toStdString(); + TimeCounterUtil::getInstance().faceCapCounter->start(mInterval); + LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]相机开始拍图[%1ms]").arg(mInterval).toStdString(); } void FaceCameraController::stopTakingPhoto() @@ -87,5 +84,39 @@ // 发送信号用于界面显示 emit sendImageToDraw(imgDisplay); + } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM) + { + // 拍图 + faceCap->read(faceMat); + + LOG(TRACE) << "TAKE ONE FACE FRAME " << faceMat.cols << " * " << faceMat.rows; + + // 左右翻转 + cv::Mat imageMatMiir; + flip(faceMat, imageMatMiir, 1); + + // clone一个mat, 用于界面显示 + cv::Mat faceMatDisp = imageMatMiir.clone(); + + CasicFaceInfo faceInfo; + faceInfo.hasFace = false; + faceInfo.matData = imageMatMiir; + + // 将图片数据压入堆栈 + ProMemory::getInstance().pushCasicFace(faceInfo); + + // 将mat转成QImage + QImage imgDisplay = ImageUtil::MatImageToQImage(faceMatDisp); + + // 发送信号用于界面显示 + emit sendImageToDrawForRecognize(imgDisplay); } } + +cv::Mat FaceCameraController::takeOneRawFrame() +{ + // 拍图 + cv::Mat camMat; + faceCap->read(camMat); + return camMat; +} diff --git a/device/FaceCameraController.h b/device/FaceCameraController.h index 6570cfb..b6dfd61 100644 --- a/device/FaceCameraController.h +++ b/device/FaceCameraController.h @@ -6,9 +6,6 @@ #include "opencv2/opencv.hpp" #include "casic/ProMemory.h" -//#include "casic/face/CasicFaceInterface.h" -//#include "process/memory/ProMemory.h" -//#include "process/face/CasicFaceRecState.h" #include "utils/ImageUtil.h" #include "utils/SettingConfig.h" #include "utils/TimeCounterUtil.h" @@ -22,7 +19,8 @@ ~FaceCameraController(); // 初始化并打开人脸相机 - void openFaceCamera(); + void openFaceCamera(int mInterval); + cv::Mat takeOneRawFrame(); void stopTakingPhoto(); void closeFaceCamera(); @@ -36,6 +34,7 @@ signals: void sendImageToDraw(QImage imageDisp); + void sendImageToDrawForRecognize(QImage imageDisp); void sendImageToDetect(cv::Mat imgMat); }; diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index fe3819d..934dfad 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -1,7 +1,5 @@ #include "CasicBioRecWin.h" #include "ui_CasicBioRecWin.h" -#include -#include CasicBioRecWin::CasicBioRecWin(QWidget *parent) : QMainWindow(parent) @@ -26,11 +24,15 @@ // 初始化识别和注册的各个线程 initFaceRegistThread(); // 人脸注册线程 + initFaceRecogThread(); // 人脸识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); + ProMemory::getInstance().faceCam->openFaceCamera(1000); connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDraw, addPersonForm, &AddPersonForm::drawImageOnForm); + connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDrawForRecognize, + recogResultForm, &RecognizeResultForm::drawImageOnHomeForm); // 打印日志 LOG(INFO) << QString("应用程序启动成功[Application Startup Success]").toStdString(); @@ -43,8 +45,13 @@ ProMemory::getInstance().faceRegistPro->deleteLater(); ProMemory::getInstance().faceRegistPro->wait(); + ProMemory::getInstance().faceRecogPro->exitThread(); + ProMemory::getInstance().faceRecogPro->deleteLater(); + ProMemory::getInstance().faceRecogPro->wait(); + delete ui; delete ProMemory::getInstance().faceRegistPro; + delete ProMemory::getInstance().faceRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -94,6 +101,13 @@ ui->stacked->setCurrentWidget(addPersonForm); ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::ADD_PERSON_FORM; } +void CasicBioRecWin::switchToRecognizeForm() +{ + ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM; + ui->stacked->setCurrentWidget(recogResultForm); + + recogResultForm->startWorkingRecognize(); +} void CasicBioRecWin::initFormsPtr() { @@ -101,18 +115,21 @@ personListForm = new PersonListForm(this); settingForm = new SettingForm(this); addPersonForm = new AddPersonForm(this); + recogResultForm = new RecognizeResultForm(this); ui->stacked->addWidget(startForm); ui->stacked->addWidget(personListForm); ui->stacked->addWidget(settingForm); ui->stacked->addWidget(addPersonForm); - + ui->stacked->addWidget(recogResultForm); // 绑定按钮函数 connect(startForm, &StartupForm::switchToUserListForm, this, &CasicBioRecWin::switchToUserListForm); connect(startForm, &StartupForm::switchToSettingForm, this, &CasicBioRecWin::switchToSettingForm); + connect(startForm, &StartupForm::startRecognize, + this, &CasicBioRecWin::switchToRecognizeForm); connect(personListForm, &PersonListForm::switchToRegistForm, this, &CasicBioRecWin::switchToRegistForm); @@ -146,3 +163,20 @@ ProMemory::getInstance().faceRegistPro->start(); } + +void CasicBioRecWin::initFaceRecogThread() +{ + // 人脸识别处理过程 + ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().faceRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index 3e706fe..f0b47bf 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -2,19 +2,20 @@ #define CASICBIORECWIN_H #include +#include +#include #include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SettingConfig.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" #include "StartupForm.h" #include "PersonListForm.h" #include "SettingForm.h" #include "AddPersonForm.h" +#include "RecognizeResultForm.h" #include "device/FaceCameraController.h" -#include "device/face/FaceDetectRegistProcess.h" QT_BEGIN_NAMESPACE namespace Ui { class CasicBioRecWin; } @@ -33,6 +34,7 @@ void switchToUserListForm(); void switchToSettingForm(); void switchToRegistForm(QString personId); + void switchToRecognizeForm(); private: Ui::CasicBioRecWin *ui; @@ -41,11 +43,13 @@ PersonListForm * personListForm; SettingForm * settingForm; AddPersonForm * addPersonForm; + RecognizeResultForm * recogResultForm; void keyPressEvent(QKeyEvent *event); void initFormsPtr(); void initCacheData(); void initFaceRegistThread(); + void initFaceRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/PersonListForm.h b/PersonListForm.h index db352c6..65bd3f5 100644 --- a/PersonListForm.h +++ b/PersonListForm.h @@ -7,7 +7,7 @@ #include "ConfirmTipsDialog.h" #include "OperationTipsDialog.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" +#include "utils/UtilInclude.h" namespace Ui { class PersonListForm; diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp new file mode 100644 index 0000000..b6790a9 --- /dev/null +++ b/RecognizeResultForm.cpp @@ -0,0 +1,60 @@ +#include "RecognizeResultForm.h" +#include "ui_RecognizeResultForm.h" + +RecognizeResultForm::RecognizeResultForm(QWidget *parent) : + QWidget(parent), + ui(new Ui::RecognizeResultForm) +{ + ui->setupUi(this); + ui->labVideo->hide(); + + // 加载css文件设置控件样式 + QFile file(QApplication::applicationDirPath() + "/qss/recognize.css"); + if (file.open(QFile::ReadOnly)) + { + QString qssStr = QLatin1String(file.readAll()); + this->setStyleSheet(qssStr); + file.close(); + } +} + +RecognizeResultForm::~RecognizeResultForm() +{ + delete ui; +} + +void RecognizeResultForm::startWorkingRecognize() +{ + // 开始人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + + // 将界面切换到识别界面 RecognizeResultForm + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + + // 1人脸图像显示的容器 + ui->labVideo->resize(1060, 607); + ui->labVideo->move(110, 100); + ui->labVideo->raise(); + ui->labVideo->show(); +} + + +void RecognizeResultForm::drawImageOnHomeForm(QImage imageDisp) +{ + if (ui->labVideo->isVisible() == true) + { + LOG(TRACE) << "DRAW IMAGE ON FORM " << imageDisp.width() << "*" << imageDisp.height(); + imageDisp = imageDisp.scaled(1040, 585); + ui->labVideo->setPixmap(QPixmap::fromImage(imageDisp)); + } +} + +void RecognizeResultForm::showRecogFailure() +{ + +} +void RecognizeResultForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功"); +// ui->labVideo->hide(); +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h new file mode 100644 index 0000000..3be5410 --- /dev/null +++ b/RecognizeResultForm.h @@ -0,0 +1,34 @@ +#ifndef RECOGNIZERESULTFORM_H +#define RECOGNIZERESULTFORM_H + +#include + +#include "utils/UtilInclude.h" + +#include "casic/ProMemory.h" + +namespace Ui { +class RecognizeResultForm; +} + +class RecognizeResultForm : public QWidget +{ + Q_OBJECT + +public: + explicit RecognizeResultForm(QWidget *parent = nullptr); + ~RecognizeResultForm(); + +public slots: + void showRecogFailure(); + void showRecognizeResult(QString personId); + + void startWorkingRecognize(); // 开始工作 + void drawImageOnHomeForm(QImage imageDisp); + +private: + Ui::RecognizeResultForm *ui; + +}; + +#endif // RECOGNIZERESULTFORM_H diff --git a/RecognizeResultForm.ui b/RecognizeResultForm.ui new file mode 100644 index 0000000..9d08547 --- /dev/null +++ b/RecognizeResultForm.ui @@ -0,0 +1,212 @@ + + + RecognizeResultForm + + + + 0 + 0 + 1280 + 800 + + + + Form + + + + + 0 + 0 + 1280 + 800 + + + + + + + :/images/bg_recognize_result.png + + + + + + 0 + 0 + 0 + 0 + + + + + + + Qt::AlignCenter + + + + + + 0 + 0 + 1280 + 90 + + + + + + + 人员识别 + + + Qt::AlignCenter + + + + + + 109 + 119 + 551 + 431 + + + + + + -110 + -70 + 280 + 380 + + + + :/images/photoFace.png + + + Qt::AlignCenter + + + + + + 240 + 220 + 54 + 12 + + + + TextLabel + + + + + + 240 + 10 + 54 + 12 + + + + TextLabel + + + + + + 240 + 160 + 54 + 12 + + + + TextLabel + + + + + + 240 + 90 + 54 + 12 + + + + TextLabel + + + + + + 440 + 260 + 54 + 12 + + + + TextLabel + + + + + + 430 + 130 + 54 + 12 + + + + TextLabel + + + + + + 440 + 200 + 54 + 12 + + + + TextLabel + + + + + + 430 + 50 + 54 + 12 + + + + TextLabel + + + + + + + 550 + 470 + 120 + 80 + + + + + + + + + diff --git a/StartupForm.cpp b/StartupForm.cpp index af51bcc..c8b9c64 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -26,12 +26,13 @@ ui->hsMidd->changeSize(150, 0); // 初始化更新界面的定时器 - // 每分钟执行一次 + // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); - TimeCounterUtil::getInstance().clockCounter->setInterval(1000); - TimeCounterUtil::getInstance().clockCounter->start(); + TimeCounterUtil::getInstance().clockCounter->start(1000); } StartupForm::~StartupForm() @@ -45,6 +46,30 @@ ui->labDate->setText(QDate::currentDate().toString("yyyy-MM-dd")); } +void StartupForm::takeOneFrameForCheckStatus() +{ + if (ProMemory::getInstance().appState != CasicBioRecConst::ApplicationState::STATE_WAIT) + { + // 非待机状态直接返回 + return; + } + + cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); + bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + if (hasFace == true) + { + LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; + + // 启动识别线程 + // 槽函数 CasicBioRecWin::switchToRecognizeForm + emit startRecognize(); + + // 退出 + return ; + } +} + void StartupForm::on_btnUser_clicked() { emit switchToUserListForm(); diff --git a/StartupForm.h b/StartupForm.h index 6aed14d..f2850e9 100644 --- a/StartupForm.h +++ b/StartupForm.h @@ -4,9 +4,10 @@ #include #include #include +#include -#include "utils/SettingConfig.h" -#include "utils/TimeCounterUtil.h" +#include "casic/ProMemory.h" +#include "utils/UtilInclude.h" namespace Ui { class StartupForm; @@ -25,12 +26,15 @@ private slots: void updateDateAndTime(); + void takeOneFrameForCheckStatus(); void on_btnUser_clicked(); void on_btnSetting_clicked(); signals: void switchToUserListForm(); void switchToSettingForm(); + + void startRecognize(); }; #endif // STARTUPFORM_H diff --git a/casic/CasicBioRecConst.h b/casic/CasicBioRecConst.h index f55c84f..78d150b 100644 --- a/casic/CasicBioRecConst.h +++ b/casic/CasicBioRecConst.h @@ -12,7 +12,13 @@ ADD_PERSON_CAPTURE_FACE = 21, // 添加/编辑人员时进行人脸拍图 ADD_PERSON_CAPTURE_IRIS = 22, // 添加/编辑人员时进行虹膜拍图 SETTING_FORM = 3, // 设置页面 - RECOGNIZE_SUCCESS_FORM = 4 // 识别成功界面 + RECOGNIZE_RESULT_FORM = 4 // 识别结果界面 + }; + + enum ApplicationState + { + STATE_WAIT = 0, // 待机 + STATE_WORKING = 1, // 工作状态 }; }; diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 33010d2..6454343 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -12,9 +12,11 @@ #include "device/FaceCameraController.h" #include "device/face/FaceDetectRegistProcess.h" +#include "device/face/FaceDetectRecogProcess.h" class FaceCameraController; class FaceDetectRegistProcess; +class FaceDetectRecogProcess; class ProMemory { @@ -41,7 +43,8 @@ bool isIrisQueueEmpty(); void clearIrisQueue(); - volatile int widgeFrame; + volatile int widgeFrame = 0; // 当前显示的界面 + volatile int appState = 0; // 当前程序所处的状态 QString capFaceOrIris; // 注册虹膜或者人脸 void initFaceFeatures(); // 初始化人脸特征值集合 @@ -51,6 +54,8 @@ FaceCameraController * faceCam; FaceDetectRegistProcess * faceRegistPro; + FaceDetectRecogProcess * faceRecogPro; + private: ProMemory(); diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index 5e09b86..cb4d3bd 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -402,6 +402,42 @@ return rect.at(0); } +bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} +bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) +{ + // 构建openCV自带的眼睛分类器 + if (this->eyeCascade == nullptr) + { + this->eyeCascade = new cv::CascadeClassifier(); + this->eyeCascade->load(cvEyeCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minEyeSize, minEyeSize); + cv::Size maxRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + eyeCascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} + void casic::face::CasicFaceInterface::setMinFaceSize(int minFaceSize) { this->minFaceSize = minFaceSize; diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index d6d4494..8a1c564 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -50,6 +50,8 @@ cv::Rect faceDetectByCVCascade(cv::Mat frame); cv::Rect eyeDetectByCVCascade(cv::Mat frame); + bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); + bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); private: diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 5f0e2ae..493fdb7 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -6,7 +6,18 @@ FaceCameraController::FaceCameraController(QObject *parent) : QObject(parent) { + this->faceCap = new cv::VideoCapture(SettingConfig::getInstance().FACE_CAMERA_INDEX, cv::CAP_DSHOW); + faceCap->set(cv::CAP_PROP_FRAME_WIDTH, SettingConfig::getInstance().FACE_FRAME_WIDTH); + faceCap->set(cv::CAP_PROP_FRAME_HEIGHT, SettingConfig::getInstance().FACE_FRAME_HEIGHT); + LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]初始化相机[%1][%2 * %3]") + .arg(SettingConfig::getInstance().FACE_CAMERA_INDEX) + .arg(SettingConfig::getInstance().FACE_FRAME_WIDTH) + .arg(SettingConfig::getInstance().FACE_FRAME_HEIGHT).toStdString(); + + // 获取定时器, 绑定定时函数 + connect(TimeCounterUtil::getInstance().faceCapCounter, &QTimer::timeout, + this, &FaceCameraController::getOneFaceFrm); } FaceCameraController::~FaceCameraController() @@ -15,25 +26,11 @@ } -void FaceCameraController::openFaceCamera() +void FaceCameraController::openFaceCamera(int mInterval) { - // 获取定时器, 绑定定时函数 - connect(TimeCounterUtil::getInstance().faceCapCounter, &QTimer::timeout, - this, &FaceCameraController::getOneFaceFrm); - - this->faceCap = new cv::VideoCapture(SettingConfig::getInstance().FACE_CAMERA_INDEX, cv::CAP_DSHOW); - faceCap->set(cv::CAP_PROP_FRAME_WIDTH, SettingConfig::getInstance().FACE_FRAME_WIDTH); - faceCap->set(cv::CAP_PROP_FRAME_HEIGHT, SettingConfig::getInstance().FACE_FRAME_HEIGHT); - - LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]打开相机[%1][%2 * %3]") - .arg(SettingConfig::getInstance().FACE_CAMERA_INDEX) - .arg(SettingConfig::getInstance().FACE_FRAME_WIDTH) - .arg(SettingConfig::getInstance().FACE_FRAME_HEIGHT).toStdString(); - // 启动定时器 - TimeCounterUtil::getInstance().faceCapCounter->start(SettingConfig::getInstance().FACE_FRAME_INTERVAL); - LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]相机开始拍图[%1ms]") - .arg(SettingConfig::getInstance().FACE_FRAME_INTERVAL).toStdString(); + TimeCounterUtil::getInstance().faceCapCounter->start(mInterval); + LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]相机开始拍图[%1ms]").arg(mInterval).toStdString(); } void FaceCameraController::stopTakingPhoto() @@ -87,5 +84,39 @@ // 发送信号用于界面显示 emit sendImageToDraw(imgDisplay); + } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM) + { + // 拍图 + faceCap->read(faceMat); + + LOG(TRACE) << "TAKE ONE FACE FRAME " << faceMat.cols << " * " << faceMat.rows; + + // 左右翻转 + cv::Mat imageMatMiir; + flip(faceMat, imageMatMiir, 1); + + // clone一个mat, 用于界面显示 + cv::Mat faceMatDisp = imageMatMiir.clone(); + + CasicFaceInfo faceInfo; + faceInfo.hasFace = false; + faceInfo.matData = imageMatMiir; + + // 将图片数据压入堆栈 + ProMemory::getInstance().pushCasicFace(faceInfo); + + // 将mat转成QImage + QImage imgDisplay = ImageUtil::MatImageToQImage(faceMatDisp); + + // 发送信号用于界面显示 + emit sendImageToDrawForRecognize(imgDisplay); } } + +cv::Mat FaceCameraController::takeOneRawFrame() +{ + // 拍图 + cv::Mat camMat; + faceCap->read(camMat); + return camMat; +} diff --git a/device/FaceCameraController.h b/device/FaceCameraController.h index 6570cfb..b6dfd61 100644 --- a/device/FaceCameraController.h +++ b/device/FaceCameraController.h @@ -6,9 +6,6 @@ #include "opencv2/opencv.hpp" #include "casic/ProMemory.h" -//#include "casic/face/CasicFaceInterface.h" -//#include "process/memory/ProMemory.h" -//#include "process/face/CasicFaceRecState.h" #include "utils/ImageUtil.h" #include "utils/SettingConfig.h" #include "utils/TimeCounterUtil.h" @@ -22,7 +19,8 @@ ~FaceCameraController(); // 初始化并打开人脸相机 - void openFaceCamera(); + void openFaceCamera(int mInterval); + cv::Mat takeOneRawFrame(); void stopTakingPhoto(); void closeFaceCamera(); @@ -36,6 +34,7 @@ signals: void sendImageToDraw(QImage imageDisp); + void sendImageToDrawForRecognize(QImage imageDisp); void sendImageToDetect(cv::Mat imgMat); }; diff --git a/device/device.pri b/device/device.pri index 71d9dfa..274ba60 100644 --- a/device/device.pri +++ b/device/device.pri @@ -1,10 +1,12 @@ HEADERS += $$PWD/FaceCameraController.h HEADERS += $$PWD/face/FaceDetectRegistProcess.h +HEADERS += $$PWD/face/FaceDetectRecogProcess.h HEADERS += $$PWD/face/CasicFaceRecState.h SOURCES += $$PWD/FaceCameraController.cpp SOURCES += $$PWD/face/FaceDetectRegistProcess.cpp +SOURCES += $$PWD/face/FaceDetectRecogProcess.cpp SOURCES += $$PWD/face/CasicFaceRecState.cpp #HEADERS += $$PWD/IrisCameraController.h diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index fe3819d..934dfad 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -1,7 +1,5 @@ #include "CasicBioRecWin.h" #include "ui_CasicBioRecWin.h" -#include -#include CasicBioRecWin::CasicBioRecWin(QWidget *parent) : QMainWindow(parent) @@ -26,11 +24,15 @@ // 初始化识别和注册的各个线程 initFaceRegistThread(); // 人脸注册线程 + initFaceRecogThread(); // 人脸识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); + ProMemory::getInstance().faceCam->openFaceCamera(1000); connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDraw, addPersonForm, &AddPersonForm::drawImageOnForm); + connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDrawForRecognize, + recogResultForm, &RecognizeResultForm::drawImageOnHomeForm); // 打印日志 LOG(INFO) << QString("应用程序启动成功[Application Startup Success]").toStdString(); @@ -43,8 +45,13 @@ ProMemory::getInstance().faceRegistPro->deleteLater(); ProMemory::getInstance().faceRegistPro->wait(); + ProMemory::getInstance().faceRecogPro->exitThread(); + ProMemory::getInstance().faceRecogPro->deleteLater(); + ProMemory::getInstance().faceRecogPro->wait(); + delete ui; delete ProMemory::getInstance().faceRegistPro; + delete ProMemory::getInstance().faceRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -94,6 +101,13 @@ ui->stacked->setCurrentWidget(addPersonForm); ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::ADD_PERSON_FORM; } +void CasicBioRecWin::switchToRecognizeForm() +{ + ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM; + ui->stacked->setCurrentWidget(recogResultForm); + + recogResultForm->startWorkingRecognize(); +} void CasicBioRecWin::initFormsPtr() { @@ -101,18 +115,21 @@ personListForm = new PersonListForm(this); settingForm = new SettingForm(this); addPersonForm = new AddPersonForm(this); + recogResultForm = new RecognizeResultForm(this); ui->stacked->addWidget(startForm); ui->stacked->addWidget(personListForm); ui->stacked->addWidget(settingForm); ui->stacked->addWidget(addPersonForm); - + ui->stacked->addWidget(recogResultForm); // 绑定按钮函数 connect(startForm, &StartupForm::switchToUserListForm, this, &CasicBioRecWin::switchToUserListForm); connect(startForm, &StartupForm::switchToSettingForm, this, &CasicBioRecWin::switchToSettingForm); + connect(startForm, &StartupForm::startRecognize, + this, &CasicBioRecWin::switchToRecognizeForm); connect(personListForm, &PersonListForm::switchToRegistForm, this, &CasicBioRecWin::switchToRegistForm); @@ -146,3 +163,20 @@ ProMemory::getInstance().faceRegistPro->start(); } + +void CasicBioRecWin::initFaceRecogThread() +{ + // 人脸识别处理过程 + ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().faceRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index 3e706fe..f0b47bf 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -2,19 +2,20 @@ #define CASICBIORECWIN_H #include +#include +#include #include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SettingConfig.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" #include "StartupForm.h" #include "PersonListForm.h" #include "SettingForm.h" #include "AddPersonForm.h" +#include "RecognizeResultForm.h" #include "device/FaceCameraController.h" -#include "device/face/FaceDetectRegistProcess.h" QT_BEGIN_NAMESPACE namespace Ui { class CasicBioRecWin; } @@ -33,6 +34,7 @@ void switchToUserListForm(); void switchToSettingForm(); void switchToRegistForm(QString personId); + void switchToRecognizeForm(); private: Ui::CasicBioRecWin *ui; @@ -41,11 +43,13 @@ PersonListForm * personListForm; SettingForm * settingForm; AddPersonForm * addPersonForm; + RecognizeResultForm * recogResultForm; void keyPressEvent(QKeyEvent *event); void initFormsPtr(); void initCacheData(); void initFaceRegistThread(); + void initFaceRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/PersonListForm.h b/PersonListForm.h index db352c6..65bd3f5 100644 --- a/PersonListForm.h +++ b/PersonListForm.h @@ -7,7 +7,7 @@ #include "ConfirmTipsDialog.h" #include "OperationTipsDialog.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" +#include "utils/UtilInclude.h" namespace Ui { class PersonListForm; diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp new file mode 100644 index 0000000..b6790a9 --- /dev/null +++ b/RecognizeResultForm.cpp @@ -0,0 +1,60 @@ +#include "RecognizeResultForm.h" +#include "ui_RecognizeResultForm.h" + +RecognizeResultForm::RecognizeResultForm(QWidget *parent) : + QWidget(parent), + ui(new Ui::RecognizeResultForm) +{ + ui->setupUi(this); + ui->labVideo->hide(); + + // 加载css文件设置控件样式 + QFile file(QApplication::applicationDirPath() + "/qss/recognize.css"); + if (file.open(QFile::ReadOnly)) + { + QString qssStr = QLatin1String(file.readAll()); + this->setStyleSheet(qssStr); + file.close(); + } +} + +RecognizeResultForm::~RecognizeResultForm() +{ + delete ui; +} + +void RecognizeResultForm::startWorkingRecognize() +{ + // 开始人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + + // 将界面切换到识别界面 RecognizeResultForm + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + + // 1人脸图像显示的容器 + ui->labVideo->resize(1060, 607); + ui->labVideo->move(110, 100); + ui->labVideo->raise(); + ui->labVideo->show(); +} + + +void RecognizeResultForm::drawImageOnHomeForm(QImage imageDisp) +{ + if (ui->labVideo->isVisible() == true) + { + LOG(TRACE) << "DRAW IMAGE ON FORM " << imageDisp.width() << "*" << imageDisp.height(); + imageDisp = imageDisp.scaled(1040, 585); + ui->labVideo->setPixmap(QPixmap::fromImage(imageDisp)); + } +} + +void RecognizeResultForm::showRecogFailure() +{ + +} +void RecognizeResultForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功"); +// ui->labVideo->hide(); +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h new file mode 100644 index 0000000..3be5410 --- /dev/null +++ b/RecognizeResultForm.h @@ -0,0 +1,34 @@ +#ifndef RECOGNIZERESULTFORM_H +#define RECOGNIZERESULTFORM_H + +#include + +#include "utils/UtilInclude.h" + +#include "casic/ProMemory.h" + +namespace Ui { +class RecognizeResultForm; +} + +class RecognizeResultForm : public QWidget +{ + Q_OBJECT + +public: + explicit RecognizeResultForm(QWidget *parent = nullptr); + ~RecognizeResultForm(); + +public slots: + void showRecogFailure(); + void showRecognizeResult(QString personId); + + void startWorkingRecognize(); // 开始工作 + void drawImageOnHomeForm(QImage imageDisp); + +private: + Ui::RecognizeResultForm *ui; + +}; + +#endif // RECOGNIZERESULTFORM_H diff --git a/RecognizeResultForm.ui b/RecognizeResultForm.ui new file mode 100644 index 0000000..9d08547 --- /dev/null +++ b/RecognizeResultForm.ui @@ -0,0 +1,212 @@ + + + RecognizeResultForm + + + + 0 + 0 + 1280 + 800 + + + + Form + + + + + 0 + 0 + 1280 + 800 + + + + + + + :/images/bg_recognize_result.png + + + + + + 0 + 0 + 0 + 0 + + + + + + + Qt::AlignCenter + + + + + + 0 + 0 + 1280 + 90 + + + + + + + 人员识别 + + + Qt::AlignCenter + + + + + + 109 + 119 + 551 + 431 + + + + + + -110 + -70 + 280 + 380 + + + + :/images/photoFace.png + + + Qt::AlignCenter + + + + + + 240 + 220 + 54 + 12 + + + + TextLabel + + + + + + 240 + 10 + 54 + 12 + + + + TextLabel + + + + + + 240 + 160 + 54 + 12 + + + + TextLabel + + + + + + 240 + 90 + 54 + 12 + + + + TextLabel + + + + + + 440 + 260 + 54 + 12 + + + + TextLabel + + + + + + 430 + 130 + 54 + 12 + + + + TextLabel + + + + + + 440 + 200 + 54 + 12 + + + + TextLabel + + + + + + 430 + 50 + 54 + 12 + + + + TextLabel + + + + + + + 550 + 470 + 120 + 80 + + + + + + + + + diff --git a/StartupForm.cpp b/StartupForm.cpp index af51bcc..c8b9c64 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -26,12 +26,13 @@ ui->hsMidd->changeSize(150, 0); // 初始化更新界面的定时器 - // 每分钟执行一次 + // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); - TimeCounterUtil::getInstance().clockCounter->setInterval(1000); - TimeCounterUtil::getInstance().clockCounter->start(); + TimeCounterUtil::getInstance().clockCounter->start(1000); } StartupForm::~StartupForm() @@ -45,6 +46,30 @@ ui->labDate->setText(QDate::currentDate().toString("yyyy-MM-dd")); } +void StartupForm::takeOneFrameForCheckStatus() +{ + if (ProMemory::getInstance().appState != CasicBioRecConst::ApplicationState::STATE_WAIT) + { + // 非待机状态直接返回 + return; + } + + cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); + bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + if (hasFace == true) + { + LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; + + // 启动识别线程 + // 槽函数 CasicBioRecWin::switchToRecognizeForm + emit startRecognize(); + + // 退出 + return ; + } +} + void StartupForm::on_btnUser_clicked() { emit switchToUserListForm(); diff --git a/StartupForm.h b/StartupForm.h index 6aed14d..f2850e9 100644 --- a/StartupForm.h +++ b/StartupForm.h @@ -4,9 +4,10 @@ #include #include #include +#include -#include "utils/SettingConfig.h" -#include "utils/TimeCounterUtil.h" +#include "casic/ProMemory.h" +#include "utils/UtilInclude.h" namespace Ui { class StartupForm; @@ -25,12 +26,15 @@ private slots: void updateDateAndTime(); + void takeOneFrameForCheckStatus(); void on_btnUser_clicked(); void on_btnSetting_clicked(); signals: void switchToUserListForm(); void switchToSettingForm(); + + void startRecognize(); }; #endif // STARTUPFORM_H diff --git a/casic/CasicBioRecConst.h b/casic/CasicBioRecConst.h index f55c84f..78d150b 100644 --- a/casic/CasicBioRecConst.h +++ b/casic/CasicBioRecConst.h @@ -12,7 +12,13 @@ ADD_PERSON_CAPTURE_FACE = 21, // 添加/编辑人员时进行人脸拍图 ADD_PERSON_CAPTURE_IRIS = 22, // 添加/编辑人员时进行虹膜拍图 SETTING_FORM = 3, // 设置页面 - RECOGNIZE_SUCCESS_FORM = 4 // 识别成功界面 + RECOGNIZE_RESULT_FORM = 4 // 识别结果界面 + }; + + enum ApplicationState + { + STATE_WAIT = 0, // 待机 + STATE_WORKING = 1, // 工作状态 }; }; diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 33010d2..6454343 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -12,9 +12,11 @@ #include "device/FaceCameraController.h" #include "device/face/FaceDetectRegistProcess.h" +#include "device/face/FaceDetectRecogProcess.h" class FaceCameraController; class FaceDetectRegistProcess; +class FaceDetectRecogProcess; class ProMemory { @@ -41,7 +43,8 @@ bool isIrisQueueEmpty(); void clearIrisQueue(); - volatile int widgeFrame; + volatile int widgeFrame = 0; // 当前显示的界面 + volatile int appState = 0; // 当前程序所处的状态 QString capFaceOrIris; // 注册虹膜或者人脸 void initFaceFeatures(); // 初始化人脸特征值集合 @@ -51,6 +54,8 @@ FaceCameraController * faceCam; FaceDetectRegistProcess * faceRegistPro; + FaceDetectRecogProcess * faceRecogPro; + private: ProMemory(); diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index 5e09b86..cb4d3bd 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -402,6 +402,42 @@ return rect.at(0); } +bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} +bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) +{ + // 构建openCV自带的眼睛分类器 + if (this->eyeCascade == nullptr) + { + this->eyeCascade = new cv::CascadeClassifier(); + this->eyeCascade->load(cvEyeCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minEyeSize, minEyeSize); + cv::Size maxRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + eyeCascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} + void casic::face::CasicFaceInterface::setMinFaceSize(int minFaceSize) { this->minFaceSize = minFaceSize; diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index d6d4494..8a1c564 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -50,6 +50,8 @@ cv::Rect faceDetectByCVCascade(cv::Mat frame); cv::Rect eyeDetectByCVCascade(cv::Mat frame); + bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); + bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); private: diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 5f0e2ae..493fdb7 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -6,7 +6,18 @@ FaceCameraController::FaceCameraController(QObject *parent) : QObject(parent) { + this->faceCap = new cv::VideoCapture(SettingConfig::getInstance().FACE_CAMERA_INDEX, cv::CAP_DSHOW); + faceCap->set(cv::CAP_PROP_FRAME_WIDTH, SettingConfig::getInstance().FACE_FRAME_WIDTH); + faceCap->set(cv::CAP_PROP_FRAME_HEIGHT, SettingConfig::getInstance().FACE_FRAME_HEIGHT); + LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]初始化相机[%1][%2 * %3]") + .arg(SettingConfig::getInstance().FACE_CAMERA_INDEX) + .arg(SettingConfig::getInstance().FACE_FRAME_WIDTH) + .arg(SettingConfig::getInstance().FACE_FRAME_HEIGHT).toStdString(); + + // 获取定时器, 绑定定时函数 + connect(TimeCounterUtil::getInstance().faceCapCounter, &QTimer::timeout, + this, &FaceCameraController::getOneFaceFrm); } FaceCameraController::~FaceCameraController() @@ -15,25 +26,11 @@ } -void FaceCameraController::openFaceCamera() +void FaceCameraController::openFaceCamera(int mInterval) { - // 获取定时器, 绑定定时函数 - connect(TimeCounterUtil::getInstance().faceCapCounter, &QTimer::timeout, - this, &FaceCameraController::getOneFaceFrm); - - this->faceCap = new cv::VideoCapture(SettingConfig::getInstance().FACE_CAMERA_INDEX, cv::CAP_DSHOW); - faceCap->set(cv::CAP_PROP_FRAME_WIDTH, SettingConfig::getInstance().FACE_FRAME_WIDTH); - faceCap->set(cv::CAP_PROP_FRAME_HEIGHT, SettingConfig::getInstance().FACE_FRAME_HEIGHT); - - LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]打开相机[%1][%2 * %3]") - .arg(SettingConfig::getInstance().FACE_CAMERA_INDEX) - .arg(SettingConfig::getInstance().FACE_FRAME_WIDTH) - .arg(SettingConfig::getInstance().FACE_FRAME_HEIGHT).toStdString(); - // 启动定时器 - TimeCounterUtil::getInstance().faceCapCounter->start(SettingConfig::getInstance().FACE_FRAME_INTERVAL); - LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]相机开始拍图[%1ms]") - .arg(SettingConfig::getInstance().FACE_FRAME_INTERVAL).toStdString(); + TimeCounterUtil::getInstance().faceCapCounter->start(mInterval); + LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]相机开始拍图[%1ms]").arg(mInterval).toStdString(); } void FaceCameraController::stopTakingPhoto() @@ -87,5 +84,39 @@ // 发送信号用于界面显示 emit sendImageToDraw(imgDisplay); + } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM) + { + // 拍图 + faceCap->read(faceMat); + + LOG(TRACE) << "TAKE ONE FACE FRAME " << faceMat.cols << " * " << faceMat.rows; + + // 左右翻转 + cv::Mat imageMatMiir; + flip(faceMat, imageMatMiir, 1); + + // clone一个mat, 用于界面显示 + cv::Mat faceMatDisp = imageMatMiir.clone(); + + CasicFaceInfo faceInfo; + faceInfo.hasFace = false; + faceInfo.matData = imageMatMiir; + + // 将图片数据压入堆栈 + ProMemory::getInstance().pushCasicFace(faceInfo); + + // 将mat转成QImage + QImage imgDisplay = ImageUtil::MatImageToQImage(faceMatDisp); + + // 发送信号用于界面显示 + emit sendImageToDrawForRecognize(imgDisplay); } } + +cv::Mat FaceCameraController::takeOneRawFrame() +{ + // 拍图 + cv::Mat camMat; + faceCap->read(camMat); + return camMat; +} diff --git a/device/FaceCameraController.h b/device/FaceCameraController.h index 6570cfb..b6dfd61 100644 --- a/device/FaceCameraController.h +++ b/device/FaceCameraController.h @@ -6,9 +6,6 @@ #include "opencv2/opencv.hpp" #include "casic/ProMemory.h" -//#include "casic/face/CasicFaceInterface.h" -//#include "process/memory/ProMemory.h" -//#include "process/face/CasicFaceRecState.h" #include "utils/ImageUtil.h" #include "utils/SettingConfig.h" #include "utils/TimeCounterUtil.h" @@ -22,7 +19,8 @@ ~FaceCameraController(); // 初始化并打开人脸相机 - void openFaceCamera(); + void openFaceCamera(int mInterval); + cv::Mat takeOneRawFrame(); void stopTakingPhoto(); void closeFaceCamera(); @@ -36,6 +34,7 @@ signals: void sendImageToDraw(QImage imageDisp); + void sendImageToDrawForRecognize(QImage imageDisp); void sendImageToDetect(cv::Mat imgMat); }; diff --git a/device/device.pri b/device/device.pri index 71d9dfa..274ba60 100644 --- a/device/device.pri +++ b/device/device.pri @@ -1,10 +1,12 @@ HEADERS += $$PWD/FaceCameraController.h HEADERS += $$PWD/face/FaceDetectRegistProcess.h +HEADERS += $$PWD/face/FaceDetectRecogProcess.h HEADERS += $$PWD/face/CasicFaceRecState.h SOURCES += $$PWD/FaceCameraController.cpp SOURCES += $$PWD/face/FaceDetectRegistProcess.cpp +SOURCES += $$PWD/face/FaceDetectRecogProcess.cpp SOURCES += $$PWD/face/CasicFaceRecState.cpp #HEADERS += $$PWD/IrisCameraController.h diff --git a/device/face/FaceDetectRecogProcess.cpp b/device/face/FaceDetectRecogProcess.cpp new file mode 100644 index 0000000..00e45ff --- /dev/null +++ b/device/face/FaceDetectRecogProcess.cpp @@ -0,0 +1,198 @@ +#include "FaceDetectRecogProcess.h" + +FaceDetectRecogProcess::FaceDetectRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; +} + +FaceDetectRecogProcess::~FaceDetectRecogProcess() +{ + this->setWorking(false); +} + +void FaceDetectRecogProcess::setWorking(bool working) +{ + this->working = working; +} +void FaceDetectRecogProcess::exitThread() +{ + this->exit = true; +} +void FaceDetectRecogProcess::startThread() +{ + this->exit = false; + this->start(); +} + +void FaceDetectRecogProcess::addOneTryCount() +{ + LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); + if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) + { + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + } else + { + CasicFaceRecState::getInstance().tryCount = 0; + CasicFaceRecState::getInstance().noFaceCount = 0; + emit matchFailure(); + + this->setWorking(false); // 返回后则线程暂停工作 + } +} + +void FaceDetectRecogProcess::addOneNoFaceCount() +{ + CasicFaceRecState::getInstance().noFaceCount++; + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) + { + CasicFaceRecState::getInstance().noFaceCount = 0; + emit matchFailure(); + + this->setWorking(false); // 返回后则暂停工作 + } +} + +void FaceDetectRecogProcess::run() +{ + while (exit == false) + { + if (this->working == false) + { + this->msleep(100); // 100ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isFaceQueueEmpty() == true) + { + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) + { + LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 取出人脸图像栈中的一条数据 + CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); + + // 调用人脸检测算法 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); + + // 没有找到人脸则返回 + if (faceInfo.hasFace == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 找到人脸则开始一次识别 + if (CasicFaceRecState::getInstance().recoginzeId == "0") + { + CasicFaceRecState::getInstance().initRecognize(); + } + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 + CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 + + // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 + casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); + faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); + + // 活体检测判断为假脸 + if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) + { + // 表示本次识别结束, 可以开始下一次识别过程 + LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); + + addOneTryCount(); // 判断是否超过次数, 重置识别状态 + this->msleep(200); // 200ms后再判断 + continue; + } + + // 设置识别状态值=通过活体检测 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; + + // 调用算法提取特征值, 1024个字节的float数组 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); + + // 设置识别状态值=特征值提取 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + + LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + this->setWorking(false); + // 特征值提取成功的人脸 与人脸库中的人脸进行比较 + compareFaceInCollection(); + } +} + +void FaceDetectRecogProcess::compareFaceInCollection() +{ + ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 + QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); + for (int i = 0; i < faceFeatures.size(); i++) + { + QVariantMap ffMap = faceFeatures.at(i); + + QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); + float ffArr[1024]; + for (int i = 0; i < 1024; i++) + { + QByteArray tempBa; + tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); + ffArr[i] = ByteUtil::binToFloat(tempBa); + } + + float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); + + LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); + if (sim > 0.62) + { + CasicFaceRecState::getInstance().faceInfo->sim = sim; + CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); + CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; + + // 找到匹配的人脸图像 + this->afterRecogAction(ffMap.value("person_id").toString()); + return ; + } + } + + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + this->addOneTryCount(); +} + +void FaceDetectRecogProcess::afterRecogAction(QString personId) +{ + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + + LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + // 发送信号, 在主界面上显示 + emit matchSuccess(personId); +} + diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index fe3819d..934dfad 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -1,7 +1,5 @@ #include "CasicBioRecWin.h" #include "ui_CasicBioRecWin.h" -#include -#include CasicBioRecWin::CasicBioRecWin(QWidget *parent) : QMainWindow(parent) @@ -26,11 +24,15 @@ // 初始化识别和注册的各个线程 initFaceRegistThread(); // 人脸注册线程 + initFaceRecogThread(); // 人脸识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); + ProMemory::getInstance().faceCam->openFaceCamera(1000); connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDraw, addPersonForm, &AddPersonForm::drawImageOnForm); + connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDrawForRecognize, + recogResultForm, &RecognizeResultForm::drawImageOnHomeForm); // 打印日志 LOG(INFO) << QString("应用程序启动成功[Application Startup Success]").toStdString(); @@ -43,8 +45,13 @@ ProMemory::getInstance().faceRegistPro->deleteLater(); ProMemory::getInstance().faceRegistPro->wait(); + ProMemory::getInstance().faceRecogPro->exitThread(); + ProMemory::getInstance().faceRecogPro->deleteLater(); + ProMemory::getInstance().faceRecogPro->wait(); + delete ui; delete ProMemory::getInstance().faceRegistPro; + delete ProMemory::getInstance().faceRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -94,6 +101,13 @@ ui->stacked->setCurrentWidget(addPersonForm); ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::ADD_PERSON_FORM; } +void CasicBioRecWin::switchToRecognizeForm() +{ + ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM; + ui->stacked->setCurrentWidget(recogResultForm); + + recogResultForm->startWorkingRecognize(); +} void CasicBioRecWin::initFormsPtr() { @@ -101,18 +115,21 @@ personListForm = new PersonListForm(this); settingForm = new SettingForm(this); addPersonForm = new AddPersonForm(this); + recogResultForm = new RecognizeResultForm(this); ui->stacked->addWidget(startForm); ui->stacked->addWidget(personListForm); ui->stacked->addWidget(settingForm); ui->stacked->addWidget(addPersonForm); - + ui->stacked->addWidget(recogResultForm); // 绑定按钮函数 connect(startForm, &StartupForm::switchToUserListForm, this, &CasicBioRecWin::switchToUserListForm); connect(startForm, &StartupForm::switchToSettingForm, this, &CasicBioRecWin::switchToSettingForm); + connect(startForm, &StartupForm::startRecognize, + this, &CasicBioRecWin::switchToRecognizeForm); connect(personListForm, &PersonListForm::switchToRegistForm, this, &CasicBioRecWin::switchToRegistForm); @@ -146,3 +163,20 @@ ProMemory::getInstance().faceRegistPro->start(); } + +void CasicBioRecWin::initFaceRecogThread() +{ + // 人脸识别处理过程 + ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().faceRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index 3e706fe..f0b47bf 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -2,19 +2,20 @@ #define CASICBIORECWIN_H #include +#include +#include #include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SettingConfig.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" #include "StartupForm.h" #include "PersonListForm.h" #include "SettingForm.h" #include "AddPersonForm.h" +#include "RecognizeResultForm.h" #include "device/FaceCameraController.h" -#include "device/face/FaceDetectRegistProcess.h" QT_BEGIN_NAMESPACE namespace Ui { class CasicBioRecWin; } @@ -33,6 +34,7 @@ void switchToUserListForm(); void switchToSettingForm(); void switchToRegistForm(QString personId); + void switchToRecognizeForm(); private: Ui::CasicBioRecWin *ui; @@ -41,11 +43,13 @@ PersonListForm * personListForm; SettingForm * settingForm; AddPersonForm * addPersonForm; + RecognizeResultForm * recogResultForm; void keyPressEvent(QKeyEvent *event); void initFormsPtr(); void initCacheData(); void initFaceRegistThread(); + void initFaceRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/PersonListForm.h b/PersonListForm.h index db352c6..65bd3f5 100644 --- a/PersonListForm.h +++ b/PersonListForm.h @@ -7,7 +7,7 @@ #include "ConfirmTipsDialog.h" #include "OperationTipsDialog.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" +#include "utils/UtilInclude.h" namespace Ui { class PersonListForm; diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp new file mode 100644 index 0000000..b6790a9 --- /dev/null +++ b/RecognizeResultForm.cpp @@ -0,0 +1,60 @@ +#include "RecognizeResultForm.h" +#include "ui_RecognizeResultForm.h" + +RecognizeResultForm::RecognizeResultForm(QWidget *parent) : + QWidget(parent), + ui(new Ui::RecognizeResultForm) +{ + ui->setupUi(this); + ui->labVideo->hide(); + + // 加载css文件设置控件样式 + QFile file(QApplication::applicationDirPath() + "/qss/recognize.css"); + if (file.open(QFile::ReadOnly)) + { + QString qssStr = QLatin1String(file.readAll()); + this->setStyleSheet(qssStr); + file.close(); + } +} + +RecognizeResultForm::~RecognizeResultForm() +{ + delete ui; +} + +void RecognizeResultForm::startWorkingRecognize() +{ + // 开始人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + + // 将界面切换到识别界面 RecognizeResultForm + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + + // 1人脸图像显示的容器 + ui->labVideo->resize(1060, 607); + ui->labVideo->move(110, 100); + ui->labVideo->raise(); + ui->labVideo->show(); +} + + +void RecognizeResultForm::drawImageOnHomeForm(QImage imageDisp) +{ + if (ui->labVideo->isVisible() == true) + { + LOG(TRACE) << "DRAW IMAGE ON FORM " << imageDisp.width() << "*" << imageDisp.height(); + imageDisp = imageDisp.scaled(1040, 585); + ui->labVideo->setPixmap(QPixmap::fromImage(imageDisp)); + } +} + +void RecognizeResultForm::showRecogFailure() +{ + +} +void RecognizeResultForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功"); +// ui->labVideo->hide(); +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h new file mode 100644 index 0000000..3be5410 --- /dev/null +++ b/RecognizeResultForm.h @@ -0,0 +1,34 @@ +#ifndef RECOGNIZERESULTFORM_H +#define RECOGNIZERESULTFORM_H + +#include + +#include "utils/UtilInclude.h" + +#include "casic/ProMemory.h" + +namespace Ui { +class RecognizeResultForm; +} + +class RecognizeResultForm : public QWidget +{ + Q_OBJECT + +public: + explicit RecognizeResultForm(QWidget *parent = nullptr); + ~RecognizeResultForm(); + +public slots: + void showRecogFailure(); + void showRecognizeResult(QString personId); + + void startWorkingRecognize(); // 开始工作 + void drawImageOnHomeForm(QImage imageDisp); + +private: + Ui::RecognizeResultForm *ui; + +}; + +#endif // RECOGNIZERESULTFORM_H diff --git a/RecognizeResultForm.ui b/RecognizeResultForm.ui new file mode 100644 index 0000000..9d08547 --- /dev/null +++ b/RecognizeResultForm.ui @@ -0,0 +1,212 @@ + + + RecognizeResultForm + + + + 0 + 0 + 1280 + 800 + + + + Form + + + + + 0 + 0 + 1280 + 800 + + + + + + + :/images/bg_recognize_result.png + + + + + + 0 + 0 + 0 + 0 + + + + + + + Qt::AlignCenter + + + + + + 0 + 0 + 1280 + 90 + + + + + + + 人员识别 + + + Qt::AlignCenter + + + + + + 109 + 119 + 551 + 431 + + + + + + -110 + -70 + 280 + 380 + + + + :/images/photoFace.png + + + Qt::AlignCenter + + + + + + 240 + 220 + 54 + 12 + + + + TextLabel + + + + + + 240 + 10 + 54 + 12 + + + + TextLabel + + + + + + 240 + 160 + 54 + 12 + + + + TextLabel + + + + + + 240 + 90 + 54 + 12 + + + + TextLabel + + + + + + 440 + 260 + 54 + 12 + + + + TextLabel + + + + + + 430 + 130 + 54 + 12 + + + + TextLabel + + + + + + 440 + 200 + 54 + 12 + + + + TextLabel + + + + + + 430 + 50 + 54 + 12 + + + + TextLabel + + + + + + + 550 + 470 + 120 + 80 + + + + + + + + + diff --git a/StartupForm.cpp b/StartupForm.cpp index af51bcc..c8b9c64 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -26,12 +26,13 @@ ui->hsMidd->changeSize(150, 0); // 初始化更新界面的定时器 - // 每分钟执行一次 + // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); - TimeCounterUtil::getInstance().clockCounter->setInterval(1000); - TimeCounterUtil::getInstance().clockCounter->start(); + TimeCounterUtil::getInstance().clockCounter->start(1000); } StartupForm::~StartupForm() @@ -45,6 +46,30 @@ ui->labDate->setText(QDate::currentDate().toString("yyyy-MM-dd")); } +void StartupForm::takeOneFrameForCheckStatus() +{ + if (ProMemory::getInstance().appState != CasicBioRecConst::ApplicationState::STATE_WAIT) + { + // 非待机状态直接返回 + return; + } + + cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); + bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + if (hasFace == true) + { + LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; + + // 启动识别线程 + // 槽函数 CasicBioRecWin::switchToRecognizeForm + emit startRecognize(); + + // 退出 + return ; + } +} + void StartupForm::on_btnUser_clicked() { emit switchToUserListForm(); diff --git a/StartupForm.h b/StartupForm.h index 6aed14d..f2850e9 100644 --- a/StartupForm.h +++ b/StartupForm.h @@ -4,9 +4,10 @@ #include #include #include +#include -#include "utils/SettingConfig.h" -#include "utils/TimeCounterUtil.h" +#include "casic/ProMemory.h" +#include "utils/UtilInclude.h" namespace Ui { class StartupForm; @@ -25,12 +26,15 @@ private slots: void updateDateAndTime(); + void takeOneFrameForCheckStatus(); void on_btnUser_clicked(); void on_btnSetting_clicked(); signals: void switchToUserListForm(); void switchToSettingForm(); + + void startRecognize(); }; #endif // STARTUPFORM_H diff --git a/casic/CasicBioRecConst.h b/casic/CasicBioRecConst.h index f55c84f..78d150b 100644 --- a/casic/CasicBioRecConst.h +++ b/casic/CasicBioRecConst.h @@ -12,7 +12,13 @@ ADD_PERSON_CAPTURE_FACE = 21, // 添加/编辑人员时进行人脸拍图 ADD_PERSON_CAPTURE_IRIS = 22, // 添加/编辑人员时进行虹膜拍图 SETTING_FORM = 3, // 设置页面 - RECOGNIZE_SUCCESS_FORM = 4 // 识别成功界面 + RECOGNIZE_RESULT_FORM = 4 // 识别结果界面 + }; + + enum ApplicationState + { + STATE_WAIT = 0, // 待机 + STATE_WORKING = 1, // 工作状态 }; }; diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 33010d2..6454343 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -12,9 +12,11 @@ #include "device/FaceCameraController.h" #include "device/face/FaceDetectRegistProcess.h" +#include "device/face/FaceDetectRecogProcess.h" class FaceCameraController; class FaceDetectRegistProcess; +class FaceDetectRecogProcess; class ProMemory { @@ -41,7 +43,8 @@ bool isIrisQueueEmpty(); void clearIrisQueue(); - volatile int widgeFrame; + volatile int widgeFrame = 0; // 当前显示的界面 + volatile int appState = 0; // 当前程序所处的状态 QString capFaceOrIris; // 注册虹膜或者人脸 void initFaceFeatures(); // 初始化人脸特征值集合 @@ -51,6 +54,8 @@ FaceCameraController * faceCam; FaceDetectRegistProcess * faceRegistPro; + FaceDetectRecogProcess * faceRecogPro; + private: ProMemory(); diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index 5e09b86..cb4d3bd 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -402,6 +402,42 @@ return rect.at(0); } +bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} +bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) +{ + // 构建openCV自带的眼睛分类器 + if (this->eyeCascade == nullptr) + { + this->eyeCascade = new cv::CascadeClassifier(); + this->eyeCascade->load(cvEyeCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minEyeSize, minEyeSize); + cv::Size maxRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + eyeCascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} + void casic::face::CasicFaceInterface::setMinFaceSize(int minFaceSize) { this->minFaceSize = minFaceSize; diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index d6d4494..8a1c564 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -50,6 +50,8 @@ cv::Rect faceDetectByCVCascade(cv::Mat frame); cv::Rect eyeDetectByCVCascade(cv::Mat frame); + bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); + bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); private: diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 5f0e2ae..493fdb7 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -6,7 +6,18 @@ FaceCameraController::FaceCameraController(QObject *parent) : QObject(parent) { + this->faceCap = new cv::VideoCapture(SettingConfig::getInstance().FACE_CAMERA_INDEX, cv::CAP_DSHOW); + faceCap->set(cv::CAP_PROP_FRAME_WIDTH, SettingConfig::getInstance().FACE_FRAME_WIDTH); + faceCap->set(cv::CAP_PROP_FRAME_HEIGHT, SettingConfig::getInstance().FACE_FRAME_HEIGHT); + LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]初始化相机[%1][%2 * %3]") + .arg(SettingConfig::getInstance().FACE_CAMERA_INDEX) + .arg(SettingConfig::getInstance().FACE_FRAME_WIDTH) + .arg(SettingConfig::getInstance().FACE_FRAME_HEIGHT).toStdString(); + + // 获取定时器, 绑定定时函数 + connect(TimeCounterUtil::getInstance().faceCapCounter, &QTimer::timeout, + this, &FaceCameraController::getOneFaceFrm); } FaceCameraController::~FaceCameraController() @@ -15,25 +26,11 @@ } -void FaceCameraController::openFaceCamera() +void FaceCameraController::openFaceCamera(int mInterval) { - // 获取定时器, 绑定定时函数 - connect(TimeCounterUtil::getInstance().faceCapCounter, &QTimer::timeout, - this, &FaceCameraController::getOneFaceFrm); - - this->faceCap = new cv::VideoCapture(SettingConfig::getInstance().FACE_CAMERA_INDEX, cv::CAP_DSHOW); - faceCap->set(cv::CAP_PROP_FRAME_WIDTH, SettingConfig::getInstance().FACE_FRAME_WIDTH); - faceCap->set(cv::CAP_PROP_FRAME_HEIGHT, SettingConfig::getInstance().FACE_FRAME_HEIGHT); - - LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]打开相机[%1][%2 * %3]") - .arg(SettingConfig::getInstance().FACE_CAMERA_INDEX) - .arg(SettingConfig::getInstance().FACE_FRAME_WIDTH) - .arg(SettingConfig::getInstance().FACE_FRAME_HEIGHT).toStdString(); - // 启动定时器 - TimeCounterUtil::getInstance().faceCapCounter->start(SettingConfig::getInstance().FACE_FRAME_INTERVAL); - LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]相机开始拍图[%1ms]") - .arg(SettingConfig::getInstance().FACE_FRAME_INTERVAL).toStdString(); + TimeCounterUtil::getInstance().faceCapCounter->start(mInterval); + LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]相机开始拍图[%1ms]").arg(mInterval).toStdString(); } void FaceCameraController::stopTakingPhoto() @@ -87,5 +84,39 @@ // 发送信号用于界面显示 emit sendImageToDraw(imgDisplay); + } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM) + { + // 拍图 + faceCap->read(faceMat); + + LOG(TRACE) << "TAKE ONE FACE FRAME " << faceMat.cols << " * " << faceMat.rows; + + // 左右翻转 + cv::Mat imageMatMiir; + flip(faceMat, imageMatMiir, 1); + + // clone一个mat, 用于界面显示 + cv::Mat faceMatDisp = imageMatMiir.clone(); + + CasicFaceInfo faceInfo; + faceInfo.hasFace = false; + faceInfo.matData = imageMatMiir; + + // 将图片数据压入堆栈 + ProMemory::getInstance().pushCasicFace(faceInfo); + + // 将mat转成QImage + QImage imgDisplay = ImageUtil::MatImageToQImage(faceMatDisp); + + // 发送信号用于界面显示 + emit sendImageToDrawForRecognize(imgDisplay); } } + +cv::Mat FaceCameraController::takeOneRawFrame() +{ + // 拍图 + cv::Mat camMat; + faceCap->read(camMat); + return camMat; +} diff --git a/device/FaceCameraController.h b/device/FaceCameraController.h index 6570cfb..b6dfd61 100644 --- a/device/FaceCameraController.h +++ b/device/FaceCameraController.h @@ -6,9 +6,6 @@ #include "opencv2/opencv.hpp" #include "casic/ProMemory.h" -//#include "casic/face/CasicFaceInterface.h" -//#include "process/memory/ProMemory.h" -//#include "process/face/CasicFaceRecState.h" #include "utils/ImageUtil.h" #include "utils/SettingConfig.h" #include "utils/TimeCounterUtil.h" @@ -22,7 +19,8 @@ ~FaceCameraController(); // 初始化并打开人脸相机 - void openFaceCamera(); + void openFaceCamera(int mInterval); + cv::Mat takeOneRawFrame(); void stopTakingPhoto(); void closeFaceCamera(); @@ -36,6 +34,7 @@ signals: void sendImageToDraw(QImage imageDisp); + void sendImageToDrawForRecognize(QImage imageDisp); void sendImageToDetect(cv::Mat imgMat); }; diff --git a/device/device.pri b/device/device.pri index 71d9dfa..274ba60 100644 --- a/device/device.pri +++ b/device/device.pri @@ -1,10 +1,12 @@ HEADERS += $$PWD/FaceCameraController.h HEADERS += $$PWD/face/FaceDetectRegistProcess.h +HEADERS += $$PWD/face/FaceDetectRecogProcess.h HEADERS += $$PWD/face/CasicFaceRecState.h SOURCES += $$PWD/FaceCameraController.cpp SOURCES += $$PWD/face/FaceDetectRegistProcess.cpp +SOURCES += $$PWD/face/FaceDetectRecogProcess.cpp SOURCES += $$PWD/face/CasicFaceRecState.cpp #HEADERS += $$PWD/IrisCameraController.h diff --git a/device/face/FaceDetectRecogProcess.cpp b/device/face/FaceDetectRecogProcess.cpp new file mode 100644 index 0000000..00e45ff --- /dev/null +++ b/device/face/FaceDetectRecogProcess.cpp @@ -0,0 +1,198 @@ +#include "FaceDetectRecogProcess.h" + +FaceDetectRecogProcess::FaceDetectRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; +} + +FaceDetectRecogProcess::~FaceDetectRecogProcess() +{ + this->setWorking(false); +} + +void FaceDetectRecogProcess::setWorking(bool working) +{ + this->working = working; +} +void FaceDetectRecogProcess::exitThread() +{ + this->exit = true; +} +void FaceDetectRecogProcess::startThread() +{ + this->exit = false; + this->start(); +} + +void FaceDetectRecogProcess::addOneTryCount() +{ + LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); + if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) + { + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + } else + { + CasicFaceRecState::getInstance().tryCount = 0; + CasicFaceRecState::getInstance().noFaceCount = 0; + emit matchFailure(); + + this->setWorking(false); // 返回后则线程暂停工作 + } +} + +void FaceDetectRecogProcess::addOneNoFaceCount() +{ + CasicFaceRecState::getInstance().noFaceCount++; + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) + { + CasicFaceRecState::getInstance().noFaceCount = 0; + emit matchFailure(); + + this->setWorking(false); // 返回后则暂停工作 + } +} + +void FaceDetectRecogProcess::run() +{ + while (exit == false) + { + if (this->working == false) + { + this->msleep(100); // 100ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isFaceQueueEmpty() == true) + { + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) + { + LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 取出人脸图像栈中的一条数据 + CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); + + // 调用人脸检测算法 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); + + // 没有找到人脸则返回 + if (faceInfo.hasFace == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 找到人脸则开始一次识别 + if (CasicFaceRecState::getInstance().recoginzeId == "0") + { + CasicFaceRecState::getInstance().initRecognize(); + } + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 + CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 + + // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 + casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); + faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); + + // 活体检测判断为假脸 + if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) + { + // 表示本次识别结束, 可以开始下一次识别过程 + LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); + + addOneTryCount(); // 判断是否超过次数, 重置识别状态 + this->msleep(200); // 200ms后再判断 + continue; + } + + // 设置识别状态值=通过活体检测 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; + + // 调用算法提取特征值, 1024个字节的float数组 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); + + // 设置识别状态值=特征值提取 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + + LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + this->setWorking(false); + // 特征值提取成功的人脸 与人脸库中的人脸进行比较 + compareFaceInCollection(); + } +} + +void FaceDetectRecogProcess::compareFaceInCollection() +{ + ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 + QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); + for (int i = 0; i < faceFeatures.size(); i++) + { + QVariantMap ffMap = faceFeatures.at(i); + + QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); + float ffArr[1024]; + for (int i = 0; i < 1024; i++) + { + QByteArray tempBa; + tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); + ffArr[i] = ByteUtil::binToFloat(tempBa); + } + + float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); + + LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); + if (sim > 0.62) + { + CasicFaceRecState::getInstance().faceInfo->sim = sim; + CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); + CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; + + // 找到匹配的人脸图像 + this->afterRecogAction(ffMap.value("person_id").toString()); + return ; + } + } + + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + this->addOneTryCount(); +} + +void FaceDetectRecogProcess::afterRecogAction(QString personId) +{ + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + + LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + // 发送信号, 在主界面上显示 + emit matchSuccess(personId); +} + diff --git a/device/face/FaceDetectRecogProcess.h b/device/face/FaceDetectRecogProcess.h new file mode 100644 index 0000000..b1051b7 --- /dev/null +++ b/device/face/FaceDetectRecogProcess.h @@ -0,0 +1,50 @@ +#ifndef FACEDETECTRECOGPROCESS_H +#define FACEDETECTRECOGPROCESS_H + +#include +#include +#include "opencv2/opencv.hpp" + +#include "dao/RecognitionRecordDao.h" + +#include "utils/easyloggingpp/easylogging++.h" +#include "utils/ImageUtil.h" +#include "utils/SettingConfig.h" +#include "utils/ByteUtil.h" + +#include "CasicFaceRecState.h" +#include "casic/ProMemory.h" +#include "casic/face/CasicFaceInterface.h" + +class FaceDetectRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit FaceDetectRecogProcess(QObject *parent = nullptr); + ~FaceDetectRecogProcess(); + + void setWorking(bool working); + void exitThread(); + void startThread(); + + void addOneTryCount(); + void addOneNoFaceCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + void compareFaceInCollection(); + void afterRecogAction(QString personId); + + volatile bool working; + volatile bool exit; + +signals: + void matchSuccess(QString personId); // 匹配成功 + void matchFailure(); // 匹配失败 + +}; + +#endif // FACEDETECTRECOGPROCESS_H diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index fe3819d..934dfad 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -1,7 +1,5 @@ #include "CasicBioRecWin.h" #include "ui_CasicBioRecWin.h" -#include -#include CasicBioRecWin::CasicBioRecWin(QWidget *parent) : QMainWindow(parent) @@ -26,11 +24,15 @@ // 初始化识别和注册的各个线程 initFaceRegistThread(); // 人脸注册线程 + initFaceRecogThread(); // 人脸识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); + ProMemory::getInstance().faceCam->openFaceCamera(1000); connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDraw, addPersonForm, &AddPersonForm::drawImageOnForm); + connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDrawForRecognize, + recogResultForm, &RecognizeResultForm::drawImageOnHomeForm); // 打印日志 LOG(INFO) << QString("应用程序启动成功[Application Startup Success]").toStdString(); @@ -43,8 +45,13 @@ ProMemory::getInstance().faceRegistPro->deleteLater(); ProMemory::getInstance().faceRegistPro->wait(); + ProMemory::getInstance().faceRecogPro->exitThread(); + ProMemory::getInstance().faceRecogPro->deleteLater(); + ProMemory::getInstance().faceRecogPro->wait(); + delete ui; delete ProMemory::getInstance().faceRegistPro; + delete ProMemory::getInstance().faceRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -94,6 +101,13 @@ ui->stacked->setCurrentWidget(addPersonForm); ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::ADD_PERSON_FORM; } +void CasicBioRecWin::switchToRecognizeForm() +{ + ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM; + ui->stacked->setCurrentWidget(recogResultForm); + + recogResultForm->startWorkingRecognize(); +} void CasicBioRecWin::initFormsPtr() { @@ -101,18 +115,21 @@ personListForm = new PersonListForm(this); settingForm = new SettingForm(this); addPersonForm = new AddPersonForm(this); + recogResultForm = new RecognizeResultForm(this); ui->stacked->addWidget(startForm); ui->stacked->addWidget(personListForm); ui->stacked->addWidget(settingForm); ui->stacked->addWidget(addPersonForm); - + ui->stacked->addWidget(recogResultForm); // 绑定按钮函数 connect(startForm, &StartupForm::switchToUserListForm, this, &CasicBioRecWin::switchToUserListForm); connect(startForm, &StartupForm::switchToSettingForm, this, &CasicBioRecWin::switchToSettingForm); + connect(startForm, &StartupForm::startRecognize, + this, &CasicBioRecWin::switchToRecognizeForm); connect(personListForm, &PersonListForm::switchToRegistForm, this, &CasicBioRecWin::switchToRegistForm); @@ -146,3 +163,20 @@ ProMemory::getInstance().faceRegistPro->start(); } + +void CasicBioRecWin::initFaceRecogThread() +{ + // 人脸识别处理过程 + ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().faceRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index 3e706fe..f0b47bf 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -2,19 +2,20 @@ #define CASICBIORECWIN_H #include +#include +#include #include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SettingConfig.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" #include "StartupForm.h" #include "PersonListForm.h" #include "SettingForm.h" #include "AddPersonForm.h" +#include "RecognizeResultForm.h" #include "device/FaceCameraController.h" -#include "device/face/FaceDetectRegistProcess.h" QT_BEGIN_NAMESPACE namespace Ui { class CasicBioRecWin; } @@ -33,6 +34,7 @@ void switchToUserListForm(); void switchToSettingForm(); void switchToRegistForm(QString personId); + void switchToRecognizeForm(); private: Ui::CasicBioRecWin *ui; @@ -41,11 +43,13 @@ PersonListForm * personListForm; SettingForm * settingForm; AddPersonForm * addPersonForm; + RecognizeResultForm * recogResultForm; void keyPressEvent(QKeyEvent *event); void initFormsPtr(); void initCacheData(); void initFaceRegistThread(); + void initFaceRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/PersonListForm.h b/PersonListForm.h index db352c6..65bd3f5 100644 --- a/PersonListForm.h +++ b/PersonListForm.h @@ -7,7 +7,7 @@ #include "ConfirmTipsDialog.h" #include "OperationTipsDialog.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" +#include "utils/UtilInclude.h" namespace Ui { class PersonListForm; diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp new file mode 100644 index 0000000..b6790a9 --- /dev/null +++ b/RecognizeResultForm.cpp @@ -0,0 +1,60 @@ +#include "RecognizeResultForm.h" +#include "ui_RecognizeResultForm.h" + +RecognizeResultForm::RecognizeResultForm(QWidget *parent) : + QWidget(parent), + ui(new Ui::RecognizeResultForm) +{ + ui->setupUi(this); + ui->labVideo->hide(); + + // 加载css文件设置控件样式 + QFile file(QApplication::applicationDirPath() + "/qss/recognize.css"); + if (file.open(QFile::ReadOnly)) + { + QString qssStr = QLatin1String(file.readAll()); + this->setStyleSheet(qssStr); + file.close(); + } +} + +RecognizeResultForm::~RecognizeResultForm() +{ + delete ui; +} + +void RecognizeResultForm::startWorkingRecognize() +{ + // 开始人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + + // 将界面切换到识别界面 RecognizeResultForm + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + + // 1人脸图像显示的容器 + ui->labVideo->resize(1060, 607); + ui->labVideo->move(110, 100); + ui->labVideo->raise(); + ui->labVideo->show(); +} + + +void RecognizeResultForm::drawImageOnHomeForm(QImage imageDisp) +{ + if (ui->labVideo->isVisible() == true) + { + LOG(TRACE) << "DRAW IMAGE ON FORM " << imageDisp.width() << "*" << imageDisp.height(); + imageDisp = imageDisp.scaled(1040, 585); + ui->labVideo->setPixmap(QPixmap::fromImage(imageDisp)); + } +} + +void RecognizeResultForm::showRecogFailure() +{ + +} +void RecognizeResultForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功"); +// ui->labVideo->hide(); +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h new file mode 100644 index 0000000..3be5410 --- /dev/null +++ b/RecognizeResultForm.h @@ -0,0 +1,34 @@ +#ifndef RECOGNIZERESULTFORM_H +#define RECOGNIZERESULTFORM_H + +#include + +#include "utils/UtilInclude.h" + +#include "casic/ProMemory.h" + +namespace Ui { +class RecognizeResultForm; +} + +class RecognizeResultForm : public QWidget +{ + Q_OBJECT + +public: + explicit RecognizeResultForm(QWidget *parent = nullptr); + ~RecognizeResultForm(); + +public slots: + void showRecogFailure(); + void showRecognizeResult(QString personId); + + void startWorkingRecognize(); // 开始工作 + void drawImageOnHomeForm(QImage imageDisp); + +private: + Ui::RecognizeResultForm *ui; + +}; + +#endif // RECOGNIZERESULTFORM_H diff --git a/RecognizeResultForm.ui b/RecognizeResultForm.ui new file mode 100644 index 0000000..9d08547 --- /dev/null +++ b/RecognizeResultForm.ui @@ -0,0 +1,212 @@ + + + RecognizeResultForm + + + + 0 + 0 + 1280 + 800 + + + + Form + + + + + 0 + 0 + 1280 + 800 + + + + + + + :/images/bg_recognize_result.png + + + + + + 0 + 0 + 0 + 0 + + + + + + + Qt::AlignCenter + + + + + + 0 + 0 + 1280 + 90 + + + + + + + 人员识别 + + + Qt::AlignCenter + + + + + + 109 + 119 + 551 + 431 + + + + + + -110 + -70 + 280 + 380 + + + + :/images/photoFace.png + + + Qt::AlignCenter + + + + + + 240 + 220 + 54 + 12 + + + + TextLabel + + + + + + 240 + 10 + 54 + 12 + + + + TextLabel + + + + + + 240 + 160 + 54 + 12 + + + + TextLabel + + + + + + 240 + 90 + 54 + 12 + + + + TextLabel + + + + + + 440 + 260 + 54 + 12 + + + + TextLabel + + + + + + 430 + 130 + 54 + 12 + + + + TextLabel + + + + + + 440 + 200 + 54 + 12 + + + + TextLabel + + + + + + 430 + 50 + 54 + 12 + + + + TextLabel + + + + + + + 550 + 470 + 120 + 80 + + + + + + + + + diff --git a/StartupForm.cpp b/StartupForm.cpp index af51bcc..c8b9c64 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -26,12 +26,13 @@ ui->hsMidd->changeSize(150, 0); // 初始化更新界面的定时器 - // 每分钟执行一次 + // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); - TimeCounterUtil::getInstance().clockCounter->setInterval(1000); - TimeCounterUtil::getInstance().clockCounter->start(); + TimeCounterUtil::getInstance().clockCounter->start(1000); } StartupForm::~StartupForm() @@ -45,6 +46,30 @@ ui->labDate->setText(QDate::currentDate().toString("yyyy-MM-dd")); } +void StartupForm::takeOneFrameForCheckStatus() +{ + if (ProMemory::getInstance().appState != CasicBioRecConst::ApplicationState::STATE_WAIT) + { + // 非待机状态直接返回 + return; + } + + cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); + bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + if (hasFace == true) + { + LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; + + // 启动识别线程 + // 槽函数 CasicBioRecWin::switchToRecognizeForm + emit startRecognize(); + + // 退出 + return ; + } +} + void StartupForm::on_btnUser_clicked() { emit switchToUserListForm(); diff --git a/StartupForm.h b/StartupForm.h index 6aed14d..f2850e9 100644 --- a/StartupForm.h +++ b/StartupForm.h @@ -4,9 +4,10 @@ #include #include #include +#include -#include "utils/SettingConfig.h" -#include "utils/TimeCounterUtil.h" +#include "casic/ProMemory.h" +#include "utils/UtilInclude.h" namespace Ui { class StartupForm; @@ -25,12 +26,15 @@ private slots: void updateDateAndTime(); + void takeOneFrameForCheckStatus(); void on_btnUser_clicked(); void on_btnSetting_clicked(); signals: void switchToUserListForm(); void switchToSettingForm(); + + void startRecognize(); }; #endif // STARTUPFORM_H diff --git a/casic/CasicBioRecConst.h b/casic/CasicBioRecConst.h index f55c84f..78d150b 100644 --- a/casic/CasicBioRecConst.h +++ b/casic/CasicBioRecConst.h @@ -12,7 +12,13 @@ ADD_PERSON_CAPTURE_FACE = 21, // 添加/编辑人员时进行人脸拍图 ADD_PERSON_CAPTURE_IRIS = 22, // 添加/编辑人员时进行虹膜拍图 SETTING_FORM = 3, // 设置页面 - RECOGNIZE_SUCCESS_FORM = 4 // 识别成功界面 + RECOGNIZE_RESULT_FORM = 4 // 识别结果界面 + }; + + enum ApplicationState + { + STATE_WAIT = 0, // 待机 + STATE_WORKING = 1, // 工作状态 }; }; diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 33010d2..6454343 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -12,9 +12,11 @@ #include "device/FaceCameraController.h" #include "device/face/FaceDetectRegistProcess.h" +#include "device/face/FaceDetectRecogProcess.h" class FaceCameraController; class FaceDetectRegistProcess; +class FaceDetectRecogProcess; class ProMemory { @@ -41,7 +43,8 @@ bool isIrisQueueEmpty(); void clearIrisQueue(); - volatile int widgeFrame; + volatile int widgeFrame = 0; // 当前显示的界面 + volatile int appState = 0; // 当前程序所处的状态 QString capFaceOrIris; // 注册虹膜或者人脸 void initFaceFeatures(); // 初始化人脸特征值集合 @@ -51,6 +54,8 @@ FaceCameraController * faceCam; FaceDetectRegistProcess * faceRegistPro; + FaceDetectRecogProcess * faceRecogPro; + private: ProMemory(); diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index 5e09b86..cb4d3bd 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -402,6 +402,42 @@ return rect.at(0); } +bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} +bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) +{ + // 构建openCV自带的眼睛分类器 + if (this->eyeCascade == nullptr) + { + this->eyeCascade = new cv::CascadeClassifier(); + this->eyeCascade->load(cvEyeCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minEyeSize, minEyeSize); + cv::Size maxRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + eyeCascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} + void casic::face::CasicFaceInterface::setMinFaceSize(int minFaceSize) { this->minFaceSize = minFaceSize; diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index d6d4494..8a1c564 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -50,6 +50,8 @@ cv::Rect faceDetectByCVCascade(cv::Mat frame); cv::Rect eyeDetectByCVCascade(cv::Mat frame); + bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); + bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); private: diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 5f0e2ae..493fdb7 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -6,7 +6,18 @@ FaceCameraController::FaceCameraController(QObject *parent) : QObject(parent) { + this->faceCap = new cv::VideoCapture(SettingConfig::getInstance().FACE_CAMERA_INDEX, cv::CAP_DSHOW); + faceCap->set(cv::CAP_PROP_FRAME_WIDTH, SettingConfig::getInstance().FACE_FRAME_WIDTH); + faceCap->set(cv::CAP_PROP_FRAME_HEIGHT, SettingConfig::getInstance().FACE_FRAME_HEIGHT); + LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]初始化相机[%1][%2 * %3]") + .arg(SettingConfig::getInstance().FACE_CAMERA_INDEX) + .arg(SettingConfig::getInstance().FACE_FRAME_WIDTH) + .arg(SettingConfig::getInstance().FACE_FRAME_HEIGHT).toStdString(); + + // 获取定时器, 绑定定时函数 + connect(TimeCounterUtil::getInstance().faceCapCounter, &QTimer::timeout, + this, &FaceCameraController::getOneFaceFrm); } FaceCameraController::~FaceCameraController() @@ -15,25 +26,11 @@ } -void FaceCameraController::openFaceCamera() +void FaceCameraController::openFaceCamera(int mInterval) { - // 获取定时器, 绑定定时函数 - connect(TimeCounterUtil::getInstance().faceCapCounter, &QTimer::timeout, - this, &FaceCameraController::getOneFaceFrm); - - this->faceCap = new cv::VideoCapture(SettingConfig::getInstance().FACE_CAMERA_INDEX, cv::CAP_DSHOW); - faceCap->set(cv::CAP_PROP_FRAME_WIDTH, SettingConfig::getInstance().FACE_FRAME_WIDTH); - faceCap->set(cv::CAP_PROP_FRAME_HEIGHT, SettingConfig::getInstance().FACE_FRAME_HEIGHT); - - LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]打开相机[%1][%2 * %3]") - .arg(SettingConfig::getInstance().FACE_CAMERA_INDEX) - .arg(SettingConfig::getInstance().FACE_FRAME_WIDTH) - .arg(SettingConfig::getInstance().FACE_FRAME_HEIGHT).toStdString(); - // 启动定时器 - TimeCounterUtil::getInstance().faceCapCounter->start(SettingConfig::getInstance().FACE_FRAME_INTERVAL); - LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]相机开始拍图[%1ms]") - .arg(SettingConfig::getInstance().FACE_FRAME_INTERVAL).toStdString(); + TimeCounterUtil::getInstance().faceCapCounter->start(mInterval); + LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]相机开始拍图[%1ms]").arg(mInterval).toStdString(); } void FaceCameraController::stopTakingPhoto() @@ -87,5 +84,39 @@ // 发送信号用于界面显示 emit sendImageToDraw(imgDisplay); + } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM) + { + // 拍图 + faceCap->read(faceMat); + + LOG(TRACE) << "TAKE ONE FACE FRAME " << faceMat.cols << " * " << faceMat.rows; + + // 左右翻转 + cv::Mat imageMatMiir; + flip(faceMat, imageMatMiir, 1); + + // clone一个mat, 用于界面显示 + cv::Mat faceMatDisp = imageMatMiir.clone(); + + CasicFaceInfo faceInfo; + faceInfo.hasFace = false; + faceInfo.matData = imageMatMiir; + + // 将图片数据压入堆栈 + ProMemory::getInstance().pushCasicFace(faceInfo); + + // 将mat转成QImage + QImage imgDisplay = ImageUtil::MatImageToQImage(faceMatDisp); + + // 发送信号用于界面显示 + emit sendImageToDrawForRecognize(imgDisplay); } } + +cv::Mat FaceCameraController::takeOneRawFrame() +{ + // 拍图 + cv::Mat camMat; + faceCap->read(camMat); + return camMat; +} diff --git a/device/FaceCameraController.h b/device/FaceCameraController.h index 6570cfb..b6dfd61 100644 --- a/device/FaceCameraController.h +++ b/device/FaceCameraController.h @@ -6,9 +6,6 @@ #include "opencv2/opencv.hpp" #include "casic/ProMemory.h" -//#include "casic/face/CasicFaceInterface.h" -//#include "process/memory/ProMemory.h" -//#include "process/face/CasicFaceRecState.h" #include "utils/ImageUtil.h" #include "utils/SettingConfig.h" #include "utils/TimeCounterUtil.h" @@ -22,7 +19,8 @@ ~FaceCameraController(); // 初始化并打开人脸相机 - void openFaceCamera(); + void openFaceCamera(int mInterval); + cv::Mat takeOneRawFrame(); void stopTakingPhoto(); void closeFaceCamera(); @@ -36,6 +34,7 @@ signals: void sendImageToDraw(QImage imageDisp); + void sendImageToDrawForRecognize(QImage imageDisp); void sendImageToDetect(cv::Mat imgMat); }; diff --git a/device/device.pri b/device/device.pri index 71d9dfa..274ba60 100644 --- a/device/device.pri +++ b/device/device.pri @@ -1,10 +1,12 @@ HEADERS += $$PWD/FaceCameraController.h HEADERS += $$PWD/face/FaceDetectRegistProcess.h +HEADERS += $$PWD/face/FaceDetectRecogProcess.h HEADERS += $$PWD/face/CasicFaceRecState.h SOURCES += $$PWD/FaceCameraController.cpp SOURCES += $$PWD/face/FaceDetectRegistProcess.cpp +SOURCES += $$PWD/face/FaceDetectRecogProcess.cpp SOURCES += $$PWD/face/CasicFaceRecState.cpp #HEADERS += $$PWD/IrisCameraController.h diff --git a/device/face/FaceDetectRecogProcess.cpp b/device/face/FaceDetectRecogProcess.cpp new file mode 100644 index 0000000..00e45ff --- /dev/null +++ b/device/face/FaceDetectRecogProcess.cpp @@ -0,0 +1,198 @@ +#include "FaceDetectRecogProcess.h" + +FaceDetectRecogProcess::FaceDetectRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; +} + +FaceDetectRecogProcess::~FaceDetectRecogProcess() +{ + this->setWorking(false); +} + +void FaceDetectRecogProcess::setWorking(bool working) +{ + this->working = working; +} +void FaceDetectRecogProcess::exitThread() +{ + this->exit = true; +} +void FaceDetectRecogProcess::startThread() +{ + this->exit = false; + this->start(); +} + +void FaceDetectRecogProcess::addOneTryCount() +{ + LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); + if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) + { + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + } else + { + CasicFaceRecState::getInstance().tryCount = 0; + CasicFaceRecState::getInstance().noFaceCount = 0; + emit matchFailure(); + + this->setWorking(false); // 返回后则线程暂停工作 + } +} + +void FaceDetectRecogProcess::addOneNoFaceCount() +{ + CasicFaceRecState::getInstance().noFaceCount++; + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) + { + CasicFaceRecState::getInstance().noFaceCount = 0; + emit matchFailure(); + + this->setWorking(false); // 返回后则暂停工作 + } +} + +void FaceDetectRecogProcess::run() +{ + while (exit == false) + { + if (this->working == false) + { + this->msleep(100); // 100ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isFaceQueueEmpty() == true) + { + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) + { + LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 取出人脸图像栈中的一条数据 + CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); + + // 调用人脸检测算法 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); + + // 没有找到人脸则返回 + if (faceInfo.hasFace == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 找到人脸则开始一次识别 + if (CasicFaceRecState::getInstance().recoginzeId == "0") + { + CasicFaceRecState::getInstance().initRecognize(); + } + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 + CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 + + // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 + casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); + faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); + + // 活体检测判断为假脸 + if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) + { + // 表示本次识别结束, 可以开始下一次识别过程 + LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); + + addOneTryCount(); // 判断是否超过次数, 重置识别状态 + this->msleep(200); // 200ms后再判断 + continue; + } + + // 设置识别状态值=通过活体检测 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; + + // 调用算法提取特征值, 1024个字节的float数组 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); + + // 设置识别状态值=特征值提取 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + + LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + this->setWorking(false); + // 特征值提取成功的人脸 与人脸库中的人脸进行比较 + compareFaceInCollection(); + } +} + +void FaceDetectRecogProcess::compareFaceInCollection() +{ + ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 + QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); + for (int i = 0; i < faceFeatures.size(); i++) + { + QVariantMap ffMap = faceFeatures.at(i); + + QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); + float ffArr[1024]; + for (int i = 0; i < 1024; i++) + { + QByteArray tempBa; + tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); + ffArr[i] = ByteUtil::binToFloat(tempBa); + } + + float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); + + LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); + if (sim > 0.62) + { + CasicFaceRecState::getInstance().faceInfo->sim = sim; + CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); + CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; + + // 找到匹配的人脸图像 + this->afterRecogAction(ffMap.value("person_id").toString()); + return ; + } + } + + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + this->addOneTryCount(); +} + +void FaceDetectRecogProcess::afterRecogAction(QString personId) +{ + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + + LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + // 发送信号, 在主界面上显示 + emit matchSuccess(personId); +} + diff --git a/device/face/FaceDetectRecogProcess.h b/device/face/FaceDetectRecogProcess.h new file mode 100644 index 0000000..b1051b7 --- /dev/null +++ b/device/face/FaceDetectRecogProcess.h @@ -0,0 +1,50 @@ +#ifndef FACEDETECTRECOGPROCESS_H +#define FACEDETECTRECOGPROCESS_H + +#include +#include +#include "opencv2/opencv.hpp" + +#include "dao/RecognitionRecordDao.h" + +#include "utils/easyloggingpp/easylogging++.h" +#include "utils/ImageUtil.h" +#include "utils/SettingConfig.h" +#include "utils/ByteUtil.h" + +#include "CasicFaceRecState.h" +#include "casic/ProMemory.h" +#include "casic/face/CasicFaceInterface.h" + +class FaceDetectRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit FaceDetectRecogProcess(QObject *parent = nullptr); + ~FaceDetectRecogProcess(); + + void setWorking(bool working); + void exitThread(); + void startThread(); + + void addOneTryCount(); + void addOneNoFaceCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + void compareFaceInCollection(); + void afterRecogAction(QString personId); + + volatile bool working; + volatile bool exit; + +signals: + void matchSuccess(QString personId); // 匹配成功 + void matchFailure(); // 匹配失败 + +}; + +#endif // FACEDETECTRECOGPROCESS_H diff --git a/device/face/FaceDetectRegistProcess.h b/device/face/FaceDetectRegistProcess.h index 9ffa91d..99a504c 100644 --- a/device/face/FaceDetectRegistProcess.h +++ b/device/face/FaceDetectRegistProcess.h @@ -14,8 +14,6 @@ #include "casic/ProMemory.h" #include "casic/face/CasicFaceInterface.h" -static bool FACE_DETECT_FLAG = false; - class FaceDetectRegistProcess : public QThread { Q_OBJECT @@ -40,10 +38,8 @@ volatile bool exit; signals: - void extractFeatureSuccess(); void failedCaptureFace(); void successCaptureFace(QString personIdByFace); - void findSimFace(QString personId); }; diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index fe3819d..934dfad 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -1,7 +1,5 @@ #include "CasicBioRecWin.h" #include "ui_CasicBioRecWin.h" -#include -#include CasicBioRecWin::CasicBioRecWin(QWidget *parent) : QMainWindow(parent) @@ -26,11 +24,15 @@ // 初始化识别和注册的各个线程 initFaceRegistThread(); // 人脸注册线程 + initFaceRecogThread(); // 人脸识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); + ProMemory::getInstance().faceCam->openFaceCamera(1000); connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDraw, addPersonForm, &AddPersonForm::drawImageOnForm); + connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDrawForRecognize, + recogResultForm, &RecognizeResultForm::drawImageOnHomeForm); // 打印日志 LOG(INFO) << QString("应用程序启动成功[Application Startup Success]").toStdString(); @@ -43,8 +45,13 @@ ProMemory::getInstance().faceRegistPro->deleteLater(); ProMemory::getInstance().faceRegistPro->wait(); + ProMemory::getInstance().faceRecogPro->exitThread(); + ProMemory::getInstance().faceRecogPro->deleteLater(); + ProMemory::getInstance().faceRecogPro->wait(); + delete ui; delete ProMemory::getInstance().faceRegistPro; + delete ProMemory::getInstance().faceRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -94,6 +101,13 @@ ui->stacked->setCurrentWidget(addPersonForm); ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::ADD_PERSON_FORM; } +void CasicBioRecWin::switchToRecognizeForm() +{ + ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM; + ui->stacked->setCurrentWidget(recogResultForm); + + recogResultForm->startWorkingRecognize(); +} void CasicBioRecWin::initFormsPtr() { @@ -101,18 +115,21 @@ personListForm = new PersonListForm(this); settingForm = new SettingForm(this); addPersonForm = new AddPersonForm(this); + recogResultForm = new RecognizeResultForm(this); ui->stacked->addWidget(startForm); ui->stacked->addWidget(personListForm); ui->stacked->addWidget(settingForm); ui->stacked->addWidget(addPersonForm); - + ui->stacked->addWidget(recogResultForm); // 绑定按钮函数 connect(startForm, &StartupForm::switchToUserListForm, this, &CasicBioRecWin::switchToUserListForm); connect(startForm, &StartupForm::switchToSettingForm, this, &CasicBioRecWin::switchToSettingForm); + connect(startForm, &StartupForm::startRecognize, + this, &CasicBioRecWin::switchToRecognizeForm); connect(personListForm, &PersonListForm::switchToRegistForm, this, &CasicBioRecWin::switchToRegistForm); @@ -146,3 +163,20 @@ ProMemory::getInstance().faceRegistPro->start(); } + +void CasicBioRecWin::initFaceRecogThread() +{ + // 人脸识别处理过程 + ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().faceRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index 3e706fe..f0b47bf 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -2,19 +2,20 @@ #define CASICBIORECWIN_H #include +#include +#include #include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SettingConfig.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" #include "StartupForm.h" #include "PersonListForm.h" #include "SettingForm.h" #include "AddPersonForm.h" +#include "RecognizeResultForm.h" #include "device/FaceCameraController.h" -#include "device/face/FaceDetectRegistProcess.h" QT_BEGIN_NAMESPACE namespace Ui { class CasicBioRecWin; } @@ -33,6 +34,7 @@ void switchToUserListForm(); void switchToSettingForm(); void switchToRegistForm(QString personId); + void switchToRecognizeForm(); private: Ui::CasicBioRecWin *ui; @@ -41,11 +43,13 @@ PersonListForm * personListForm; SettingForm * settingForm; AddPersonForm * addPersonForm; + RecognizeResultForm * recogResultForm; void keyPressEvent(QKeyEvent *event); void initFormsPtr(); void initCacheData(); void initFaceRegistThread(); + void initFaceRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/PersonListForm.h b/PersonListForm.h index db352c6..65bd3f5 100644 --- a/PersonListForm.h +++ b/PersonListForm.h @@ -7,7 +7,7 @@ #include "ConfirmTipsDialog.h" #include "OperationTipsDialog.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" +#include "utils/UtilInclude.h" namespace Ui { class PersonListForm; diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp new file mode 100644 index 0000000..b6790a9 --- /dev/null +++ b/RecognizeResultForm.cpp @@ -0,0 +1,60 @@ +#include "RecognizeResultForm.h" +#include "ui_RecognizeResultForm.h" + +RecognizeResultForm::RecognizeResultForm(QWidget *parent) : + QWidget(parent), + ui(new Ui::RecognizeResultForm) +{ + ui->setupUi(this); + ui->labVideo->hide(); + + // 加载css文件设置控件样式 + QFile file(QApplication::applicationDirPath() + "/qss/recognize.css"); + if (file.open(QFile::ReadOnly)) + { + QString qssStr = QLatin1String(file.readAll()); + this->setStyleSheet(qssStr); + file.close(); + } +} + +RecognizeResultForm::~RecognizeResultForm() +{ + delete ui; +} + +void RecognizeResultForm::startWorkingRecognize() +{ + // 开始人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + + // 将界面切换到识别界面 RecognizeResultForm + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + + // 1人脸图像显示的容器 + ui->labVideo->resize(1060, 607); + ui->labVideo->move(110, 100); + ui->labVideo->raise(); + ui->labVideo->show(); +} + + +void RecognizeResultForm::drawImageOnHomeForm(QImage imageDisp) +{ + if (ui->labVideo->isVisible() == true) + { + LOG(TRACE) << "DRAW IMAGE ON FORM " << imageDisp.width() << "*" << imageDisp.height(); + imageDisp = imageDisp.scaled(1040, 585); + ui->labVideo->setPixmap(QPixmap::fromImage(imageDisp)); + } +} + +void RecognizeResultForm::showRecogFailure() +{ + +} +void RecognizeResultForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功"); +// ui->labVideo->hide(); +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h new file mode 100644 index 0000000..3be5410 --- /dev/null +++ b/RecognizeResultForm.h @@ -0,0 +1,34 @@ +#ifndef RECOGNIZERESULTFORM_H +#define RECOGNIZERESULTFORM_H + +#include + +#include "utils/UtilInclude.h" + +#include "casic/ProMemory.h" + +namespace Ui { +class RecognizeResultForm; +} + +class RecognizeResultForm : public QWidget +{ + Q_OBJECT + +public: + explicit RecognizeResultForm(QWidget *parent = nullptr); + ~RecognizeResultForm(); + +public slots: + void showRecogFailure(); + void showRecognizeResult(QString personId); + + void startWorkingRecognize(); // 开始工作 + void drawImageOnHomeForm(QImage imageDisp); + +private: + Ui::RecognizeResultForm *ui; + +}; + +#endif // RECOGNIZERESULTFORM_H diff --git a/RecognizeResultForm.ui b/RecognizeResultForm.ui new file mode 100644 index 0000000..9d08547 --- /dev/null +++ b/RecognizeResultForm.ui @@ -0,0 +1,212 @@ + + + RecognizeResultForm + + + + 0 + 0 + 1280 + 800 + + + + Form + + + + + 0 + 0 + 1280 + 800 + + + + + + + :/images/bg_recognize_result.png + + + + + + 0 + 0 + 0 + 0 + + + + + + + Qt::AlignCenter + + + + + + 0 + 0 + 1280 + 90 + + + + + + + 人员识别 + + + Qt::AlignCenter + + + + + + 109 + 119 + 551 + 431 + + + + + + -110 + -70 + 280 + 380 + + + + :/images/photoFace.png + + + Qt::AlignCenter + + + + + + 240 + 220 + 54 + 12 + + + + TextLabel + + + + + + 240 + 10 + 54 + 12 + + + + TextLabel + + + + + + 240 + 160 + 54 + 12 + + + + TextLabel + + + + + + 240 + 90 + 54 + 12 + + + + TextLabel + + + + + + 440 + 260 + 54 + 12 + + + + TextLabel + + + + + + 430 + 130 + 54 + 12 + + + + TextLabel + + + + + + 440 + 200 + 54 + 12 + + + + TextLabel + + + + + + 430 + 50 + 54 + 12 + + + + TextLabel + + + + + + + 550 + 470 + 120 + 80 + + + + + + + + + diff --git a/StartupForm.cpp b/StartupForm.cpp index af51bcc..c8b9c64 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -26,12 +26,13 @@ ui->hsMidd->changeSize(150, 0); // 初始化更新界面的定时器 - // 每分钟执行一次 + // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); - TimeCounterUtil::getInstance().clockCounter->setInterval(1000); - TimeCounterUtil::getInstance().clockCounter->start(); + TimeCounterUtil::getInstance().clockCounter->start(1000); } StartupForm::~StartupForm() @@ -45,6 +46,30 @@ ui->labDate->setText(QDate::currentDate().toString("yyyy-MM-dd")); } +void StartupForm::takeOneFrameForCheckStatus() +{ + if (ProMemory::getInstance().appState != CasicBioRecConst::ApplicationState::STATE_WAIT) + { + // 非待机状态直接返回 + return; + } + + cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); + bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + if (hasFace == true) + { + LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; + + // 启动识别线程 + // 槽函数 CasicBioRecWin::switchToRecognizeForm + emit startRecognize(); + + // 退出 + return ; + } +} + void StartupForm::on_btnUser_clicked() { emit switchToUserListForm(); diff --git a/StartupForm.h b/StartupForm.h index 6aed14d..f2850e9 100644 --- a/StartupForm.h +++ b/StartupForm.h @@ -4,9 +4,10 @@ #include #include #include +#include -#include "utils/SettingConfig.h" -#include "utils/TimeCounterUtil.h" +#include "casic/ProMemory.h" +#include "utils/UtilInclude.h" namespace Ui { class StartupForm; @@ -25,12 +26,15 @@ private slots: void updateDateAndTime(); + void takeOneFrameForCheckStatus(); void on_btnUser_clicked(); void on_btnSetting_clicked(); signals: void switchToUserListForm(); void switchToSettingForm(); + + void startRecognize(); }; #endif // STARTUPFORM_H diff --git a/casic/CasicBioRecConst.h b/casic/CasicBioRecConst.h index f55c84f..78d150b 100644 --- a/casic/CasicBioRecConst.h +++ b/casic/CasicBioRecConst.h @@ -12,7 +12,13 @@ ADD_PERSON_CAPTURE_FACE = 21, // 添加/编辑人员时进行人脸拍图 ADD_PERSON_CAPTURE_IRIS = 22, // 添加/编辑人员时进行虹膜拍图 SETTING_FORM = 3, // 设置页面 - RECOGNIZE_SUCCESS_FORM = 4 // 识别成功界面 + RECOGNIZE_RESULT_FORM = 4 // 识别结果界面 + }; + + enum ApplicationState + { + STATE_WAIT = 0, // 待机 + STATE_WORKING = 1, // 工作状态 }; }; diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 33010d2..6454343 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -12,9 +12,11 @@ #include "device/FaceCameraController.h" #include "device/face/FaceDetectRegistProcess.h" +#include "device/face/FaceDetectRecogProcess.h" class FaceCameraController; class FaceDetectRegistProcess; +class FaceDetectRecogProcess; class ProMemory { @@ -41,7 +43,8 @@ bool isIrisQueueEmpty(); void clearIrisQueue(); - volatile int widgeFrame; + volatile int widgeFrame = 0; // 当前显示的界面 + volatile int appState = 0; // 当前程序所处的状态 QString capFaceOrIris; // 注册虹膜或者人脸 void initFaceFeatures(); // 初始化人脸特征值集合 @@ -51,6 +54,8 @@ FaceCameraController * faceCam; FaceDetectRegistProcess * faceRegistPro; + FaceDetectRecogProcess * faceRecogPro; + private: ProMemory(); diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index 5e09b86..cb4d3bd 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -402,6 +402,42 @@ return rect.at(0); } +bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} +bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) +{ + // 构建openCV自带的眼睛分类器 + if (this->eyeCascade == nullptr) + { + this->eyeCascade = new cv::CascadeClassifier(); + this->eyeCascade->load(cvEyeCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minEyeSize, minEyeSize); + cv::Size maxRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + eyeCascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} + void casic::face::CasicFaceInterface::setMinFaceSize(int minFaceSize) { this->minFaceSize = minFaceSize; diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index d6d4494..8a1c564 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -50,6 +50,8 @@ cv::Rect faceDetectByCVCascade(cv::Mat frame); cv::Rect eyeDetectByCVCascade(cv::Mat frame); + bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); + bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); private: diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 5f0e2ae..493fdb7 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -6,7 +6,18 @@ FaceCameraController::FaceCameraController(QObject *parent) : QObject(parent) { + this->faceCap = new cv::VideoCapture(SettingConfig::getInstance().FACE_CAMERA_INDEX, cv::CAP_DSHOW); + faceCap->set(cv::CAP_PROP_FRAME_WIDTH, SettingConfig::getInstance().FACE_FRAME_WIDTH); + faceCap->set(cv::CAP_PROP_FRAME_HEIGHT, SettingConfig::getInstance().FACE_FRAME_HEIGHT); + LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]初始化相机[%1][%2 * %3]") + .arg(SettingConfig::getInstance().FACE_CAMERA_INDEX) + .arg(SettingConfig::getInstance().FACE_FRAME_WIDTH) + .arg(SettingConfig::getInstance().FACE_FRAME_HEIGHT).toStdString(); + + // 获取定时器, 绑定定时函数 + connect(TimeCounterUtil::getInstance().faceCapCounter, &QTimer::timeout, + this, &FaceCameraController::getOneFaceFrm); } FaceCameraController::~FaceCameraController() @@ -15,25 +26,11 @@ } -void FaceCameraController::openFaceCamera() +void FaceCameraController::openFaceCamera(int mInterval) { - // 获取定时器, 绑定定时函数 - connect(TimeCounterUtil::getInstance().faceCapCounter, &QTimer::timeout, - this, &FaceCameraController::getOneFaceFrm); - - this->faceCap = new cv::VideoCapture(SettingConfig::getInstance().FACE_CAMERA_INDEX, cv::CAP_DSHOW); - faceCap->set(cv::CAP_PROP_FRAME_WIDTH, SettingConfig::getInstance().FACE_FRAME_WIDTH); - faceCap->set(cv::CAP_PROP_FRAME_HEIGHT, SettingConfig::getInstance().FACE_FRAME_HEIGHT); - - LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]打开相机[%1][%2 * %3]") - .arg(SettingConfig::getInstance().FACE_CAMERA_INDEX) - .arg(SettingConfig::getInstance().FACE_FRAME_WIDTH) - .arg(SettingConfig::getInstance().FACE_FRAME_HEIGHT).toStdString(); - // 启动定时器 - TimeCounterUtil::getInstance().faceCapCounter->start(SettingConfig::getInstance().FACE_FRAME_INTERVAL); - LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]相机开始拍图[%1ms]") - .arg(SettingConfig::getInstance().FACE_FRAME_INTERVAL).toStdString(); + TimeCounterUtil::getInstance().faceCapCounter->start(mInterval); + LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]相机开始拍图[%1ms]").arg(mInterval).toStdString(); } void FaceCameraController::stopTakingPhoto() @@ -87,5 +84,39 @@ // 发送信号用于界面显示 emit sendImageToDraw(imgDisplay); + } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM) + { + // 拍图 + faceCap->read(faceMat); + + LOG(TRACE) << "TAKE ONE FACE FRAME " << faceMat.cols << " * " << faceMat.rows; + + // 左右翻转 + cv::Mat imageMatMiir; + flip(faceMat, imageMatMiir, 1); + + // clone一个mat, 用于界面显示 + cv::Mat faceMatDisp = imageMatMiir.clone(); + + CasicFaceInfo faceInfo; + faceInfo.hasFace = false; + faceInfo.matData = imageMatMiir; + + // 将图片数据压入堆栈 + ProMemory::getInstance().pushCasicFace(faceInfo); + + // 将mat转成QImage + QImage imgDisplay = ImageUtil::MatImageToQImage(faceMatDisp); + + // 发送信号用于界面显示 + emit sendImageToDrawForRecognize(imgDisplay); } } + +cv::Mat FaceCameraController::takeOneRawFrame() +{ + // 拍图 + cv::Mat camMat; + faceCap->read(camMat); + return camMat; +} diff --git a/device/FaceCameraController.h b/device/FaceCameraController.h index 6570cfb..b6dfd61 100644 --- a/device/FaceCameraController.h +++ b/device/FaceCameraController.h @@ -6,9 +6,6 @@ #include "opencv2/opencv.hpp" #include "casic/ProMemory.h" -//#include "casic/face/CasicFaceInterface.h" -//#include "process/memory/ProMemory.h" -//#include "process/face/CasicFaceRecState.h" #include "utils/ImageUtil.h" #include "utils/SettingConfig.h" #include "utils/TimeCounterUtil.h" @@ -22,7 +19,8 @@ ~FaceCameraController(); // 初始化并打开人脸相机 - void openFaceCamera(); + void openFaceCamera(int mInterval); + cv::Mat takeOneRawFrame(); void stopTakingPhoto(); void closeFaceCamera(); @@ -36,6 +34,7 @@ signals: void sendImageToDraw(QImage imageDisp); + void sendImageToDrawForRecognize(QImage imageDisp); void sendImageToDetect(cv::Mat imgMat); }; diff --git a/device/device.pri b/device/device.pri index 71d9dfa..274ba60 100644 --- a/device/device.pri +++ b/device/device.pri @@ -1,10 +1,12 @@ HEADERS += $$PWD/FaceCameraController.h HEADERS += $$PWD/face/FaceDetectRegistProcess.h +HEADERS += $$PWD/face/FaceDetectRecogProcess.h HEADERS += $$PWD/face/CasicFaceRecState.h SOURCES += $$PWD/FaceCameraController.cpp SOURCES += $$PWD/face/FaceDetectRegistProcess.cpp +SOURCES += $$PWD/face/FaceDetectRecogProcess.cpp SOURCES += $$PWD/face/CasicFaceRecState.cpp #HEADERS += $$PWD/IrisCameraController.h diff --git a/device/face/FaceDetectRecogProcess.cpp b/device/face/FaceDetectRecogProcess.cpp new file mode 100644 index 0000000..00e45ff --- /dev/null +++ b/device/face/FaceDetectRecogProcess.cpp @@ -0,0 +1,198 @@ +#include "FaceDetectRecogProcess.h" + +FaceDetectRecogProcess::FaceDetectRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; +} + +FaceDetectRecogProcess::~FaceDetectRecogProcess() +{ + this->setWorking(false); +} + +void FaceDetectRecogProcess::setWorking(bool working) +{ + this->working = working; +} +void FaceDetectRecogProcess::exitThread() +{ + this->exit = true; +} +void FaceDetectRecogProcess::startThread() +{ + this->exit = false; + this->start(); +} + +void FaceDetectRecogProcess::addOneTryCount() +{ + LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); + if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) + { + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + } else + { + CasicFaceRecState::getInstance().tryCount = 0; + CasicFaceRecState::getInstance().noFaceCount = 0; + emit matchFailure(); + + this->setWorking(false); // 返回后则线程暂停工作 + } +} + +void FaceDetectRecogProcess::addOneNoFaceCount() +{ + CasicFaceRecState::getInstance().noFaceCount++; + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) + { + CasicFaceRecState::getInstance().noFaceCount = 0; + emit matchFailure(); + + this->setWorking(false); // 返回后则暂停工作 + } +} + +void FaceDetectRecogProcess::run() +{ + while (exit == false) + { + if (this->working == false) + { + this->msleep(100); // 100ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isFaceQueueEmpty() == true) + { + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) + { + LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 取出人脸图像栈中的一条数据 + CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); + + // 调用人脸检测算法 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); + + // 没有找到人脸则返回 + if (faceInfo.hasFace == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 找到人脸则开始一次识别 + if (CasicFaceRecState::getInstance().recoginzeId == "0") + { + CasicFaceRecState::getInstance().initRecognize(); + } + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 + CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 + + // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 + casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); + faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); + + // 活体检测判断为假脸 + if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) + { + // 表示本次识别结束, 可以开始下一次识别过程 + LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); + + addOneTryCount(); // 判断是否超过次数, 重置识别状态 + this->msleep(200); // 200ms后再判断 + continue; + } + + // 设置识别状态值=通过活体检测 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; + + // 调用算法提取特征值, 1024个字节的float数组 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); + + // 设置识别状态值=特征值提取 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + + LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + this->setWorking(false); + // 特征值提取成功的人脸 与人脸库中的人脸进行比较 + compareFaceInCollection(); + } +} + +void FaceDetectRecogProcess::compareFaceInCollection() +{ + ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 + QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); + for (int i = 0; i < faceFeatures.size(); i++) + { + QVariantMap ffMap = faceFeatures.at(i); + + QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); + float ffArr[1024]; + for (int i = 0; i < 1024; i++) + { + QByteArray tempBa; + tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); + ffArr[i] = ByteUtil::binToFloat(tempBa); + } + + float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); + + LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); + if (sim > 0.62) + { + CasicFaceRecState::getInstance().faceInfo->sim = sim; + CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); + CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; + + // 找到匹配的人脸图像 + this->afterRecogAction(ffMap.value("person_id").toString()); + return ; + } + } + + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + this->addOneTryCount(); +} + +void FaceDetectRecogProcess::afterRecogAction(QString personId) +{ + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + + LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + // 发送信号, 在主界面上显示 + emit matchSuccess(personId); +} + diff --git a/device/face/FaceDetectRecogProcess.h b/device/face/FaceDetectRecogProcess.h new file mode 100644 index 0000000..b1051b7 --- /dev/null +++ b/device/face/FaceDetectRecogProcess.h @@ -0,0 +1,50 @@ +#ifndef FACEDETECTRECOGPROCESS_H +#define FACEDETECTRECOGPROCESS_H + +#include +#include +#include "opencv2/opencv.hpp" + +#include "dao/RecognitionRecordDao.h" + +#include "utils/easyloggingpp/easylogging++.h" +#include "utils/ImageUtil.h" +#include "utils/SettingConfig.h" +#include "utils/ByteUtil.h" + +#include "CasicFaceRecState.h" +#include "casic/ProMemory.h" +#include "casic/face/CasicFaceInterface.h" + +class FaceDetectRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit FaceDetectRecogProcess(QObject *parent = nullptr); + ~FaceDetectRecogProcess(); + + void setWorking(bool working); + void exitThread(); + void startThread(); + + void addOneTryCount(); + void addOneNoFaceCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + void compareFaceInCollection(); + void afterRecogAction(QString personId); + + volatile bool working; + volatile bool exit; + +signals: + void matchSuccess(QString personId); // 匹配成功 + void matchFailure(); // 匹配失败 + +}; + +#endif // FACEDETECTRECOGPROCESS_H diff --git a/device/face/FaceDetectRegistProcess.h b/device/face/FaceDetectRegistProcess.h index 9ffa91d..99a504c 100644 --- a/device/face/FaceDetectRegistProcess.h +++ b/device/face/FaceDetectRegistProcess.h @@ -14,8 +14,6 @@ #include "casic/ProMemory.h" #include "casic/face/CasicFaceInterface.h" -static bool FACE_DETECT_FLAG = false; - class FaceDetectRegistProcess : public QThread { Q_OBJECT @@ -40,10 +38,8 @@ volatile bool exit; signals: - void extractFeatureSuccess(); void failedCaptureFace(); void successCaptureFace(QString personIdByFace); - void findSimFace(QString personId); }; diff --git a/images/bg_recognize_result.png b/images/bg_recognize_result.png new file mode 100644 index 0000000..068b55b --- /dev/null +++ b/images/bg_recognize_result.png Binary files differ diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index fe3819d..934dfad 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -1,7 +1,5 @@ #include "CasicBioRecWin.h" #include "ui_CasicBioRecWin.h" -#include -#include CasicBioRecWin::CasicBioRecWin(QWidget *parent) : QMainWindow(parent) @@ -26,11 +24,15 @@ // 初始化识别和注册的各个线程 initFaceRegistThread(); // 人脸注册线程 + initFaceRecogThread(); // 人脸识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); + ProMemory::getInstance().faceCam->openFaceCamera(1000); connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDraw, addPersonForm, &AddPersonForm::drawImageOnForm); + connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDrawForRecognize, + recogResultForm, &RecognizeResultForm::drawImageOnHomeForm); // 打印日志 LOG(INFO) << QString("应用程序启动成功[Application Startup Success]").toStdString(); @@ -43,8 +45,13 @@ ProMemory::getInstance().faceRegistPro->deleteLater(); ProMemory::getInstance().faceRegistPro->wait(); + ProMemory::getInstance().faceRecogPro->exitThread(); + ProMemory::getInstance().faceRecogPro->deleteLater(); + ProMemory::getInstance().faceRecogPro->wait(); + delete ui; delete ProMemory::getInstance().faceRegistPro; + delete ProMemory::getInstance().faceRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -94,6 +101,13 @@ ui->stacked->setCurrentWidget(addPersonForm); ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::ADD_PERSON_FORM; } +void CasicBioRecWin::switchToRecognizeForm() +{ + ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM; + ui->stacked->setCurrentWidget(recogResultForm); + + recogResultForm->startWorkingRecognize(); +} void CasicBioRecWin::initFormsPtr() { @@ -101,18 +115,21 @@ personListForm = new PersonListForm(this); settingForm = new SettingForm(this); addPersonForm = new AddPersonForm(this); + recogResultForm = new RecognizeResultForm(this); ui->stacked->addWidget(startForm); ui->stacked->addWidget(personListForm); ui->stacked->addWidget(settingForm); ui->stacked->addWidget(addPersonForm); - + ui->stacked->addWidget(recogResultForm); // 绑定按钮函数 connect(startForm, &StartupForm::switchToUserListForm, this, &CasicBioRecWin::switchToUserListForm); connect(startForm, &StartupForm::switchToSettingForm, this, &CasicBioRecWin::switchToSettingForm); + connect(startForm, &StartupForm::startRecognize, + this, &CasicBioRecWin::switchToRecognizeForm); connect(personListForm, &PersonListForm::switchToRegistForm, this, &CasicBioRecWin::switchToRegistForm); @@ -146,3 +163,20 @@ ProMemory::getInstance().faceRegistPro->start(); } + +void CasicBioRecWin::initFaceRecogThread() +{ + // 人脸识别处理过程 + ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().faceRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index 3e706fe..f0b47bf 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -2,19 +2,20 @@ #define CASICBIORECWIN_H #include +#include +#include #include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SettingConfig.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" #include "StartupForm.h" #include "PersonListForm.h" #include "SettingForm.h" #include "AddPersonForm.h" +#include "RecognizeResultForm.h" #include "device/FaceCameraController.h" -#include "device/face/FaceDetectRegistProcess.h" QT_BEGIN_NAMESPACE namespace Ui { class CasicBioRecWin; } @@ -33,6 +34,7 @@ void switchToUserListForm(); void switchToSettingForm(); void switchToRegistForm(QString personId); + void switchToRecognizeForm(); private: Ui::CasicBioRecWin *ui; @@ -41,11 +43,13 @@ PersonListForm * personListForm; SettingForm * settingForm; AddPersonForm * addPersonForm; + RecognizeResultForm * recogResultForm; void keyPressEvent(QKeyEvent *event); void initFormsPtr(); void initCacheData(); void initFaceRegistThread(); + void initFaceRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/PersonListForm.h b/PersonListForm.h index db352c6..65bd3f5 100644 --- a/PersonListForm.h +++ b/PersonListForm.h @@ -7,7 +7,7 @@ #include "ConfirmTipsDialog.h" #include "OperationTipsDialog.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" +#include "utils/UtilInclude.h" namespace Ui { class PersonListForm; diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp new file mode 100644 index 0000000..b6790a9 --- /dev/null +++ b/RecognizeResultForm.cpp @@ -0,0 +1,60 @@ +#include "RecognizeResultForm.h" +#include "ui_RecognizeResultForm.h" + +RecognizeResultForm::RecognizeResultForm(QWidget *parent) : + QWidget(parent), + ui(new Ui::RecognizeResultForm) +{ + ui->setupUi(this); + ui->labVideo->hide(); + + // 加载css文件设置控件样式 + QFile file(QApplication::applicationDirPath() + "/qss/recognize.css"); + if (file.open(QFile::ReadOnly)) + { + QString qssStr = QLatin1String(file.readAll()); + this->setStyleSheet(qssStr); + file.close(); + } +} + +RecognizeResultForm::~RecognizeResultForm() +{ + delete ui; +} + +void RecognizeResultForm::startWorkingRecognize() +{ + // 开始人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + + // 将界面切换到识别界面 RecognizeResultForm + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + + // 1人脸图像显示的容器 + ui->labVideo->resize(1060, 607); + ui->labVideo->move(110, 100); + ui->labVideo->raise(); + ui->labVideo->show(); +} + + +void RecognizeResultForm::drawImageOnHomeForm(QImage imageDisp) +{ + if (ui->labVideo->isVisible() == true) + { + LOG(TRACE) << "DRAW IMAGE ON FORM " << imageDisp.width() << "*" << imageDisp.height(); + imageDisp = imageDisp.scaled(1040, 585); + ui->labVideo->setPixmap(QPixmap::fromImage(imageDisp)); + } +} + +void RecognizeResultForm::showRecogFailure() +{ + +} +void RecognizeResultForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功"); +// ui->labVideo->hide(); +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h new file mode 100644 index 0000000..3be5410 --- /dev/null +++ b/RecognizeResultForm.h @@ -0,0 +1,34 @@ +#ifndef RECOGNIZERESULTFORM_H +#define RECOGNIZERESULTFORM_H + +#include + +#include "utils/UtilInclude.h" + +#include "casic/ProMemory.h" + +namespace Ui { +class RecognizeResultForm; +} + +class RecognizeResultForm : public QWidget +{ + Q_OBJECT + +public: + explicit RecognizeResultForm(QWidget *parent = nullptr); + ~RecognizeResultForm(); + +public slots: + void showRecogFailure(); + void showRecognizeResult(QString personId); + + void startWorkingRecognize(); // 开始工作 + void drawImageOnHomeForm(QImage imageDisp); + +private: + Ui::RecognizeResultForm *ui; + +}; + +#endif // RECOGNIZERESULTFORM_H diff --git a/RecognizeResultForm.ui b/RecognizeResultForm.ui new file mode 100644 index 0000000..9d08547 --- /dev/null +++ b/RecognizeResultForm.ui @@ -0,0 +1,212 @@ + + + RecognizeResultForm + + + + 0 + 0 + 1280 + 800 + + + + Form + + + + + 0 + 0 + 1280 + 800 + + + + + + + :/images/bg_recognize_result.png + + + + + + 0 + 0 + 0 + 0 + + + + + + + Qt::AlignCenter + + + + + + 0 + 0 + 1280 + 90 + + + + + + + 人员识别 + + + Qt::AlignCenter + + + + + + 109 + 119 + 551 + 431 + + + + + + -110 + -70 + 280 + 380 + + + + :/images/photoFace.png + + + Qt::AlignCenter + + + + + + 240 + 220 + 54 + 12 + + + + TextLabel + + + + + + 240 + 10 + 54 + 12 + + + + TextLabel + + + + + + 240 + 160 + 54 + 12 + + + + TextLabel + + + + + + 240 + 90 + 54 + 12 + + + + TextLabel + + + + + + 440 + 260 + 54 + 12 + + + + TextLabel + + + + + + 430 + 130 + 54 + 12 + + + + TextLabel + + + + + + 440 + 200 + 54 + 12 + + + + TextLabel + + + + + + 430 + 50 + 54 + 12 + + + + TextLabel + + + + + + + 550 + 470 + 120 + 80 + + + + + + + + + diff --git a/StartupForm.cpp b/StartupForm.cpp index af51bcc..c8b9c64 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -26,12 +26,13 @@ ui->hsMidd->changeSize(150, 0); // 初始化更新界面的定时器 - // 每分钟执行一次 + // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); - TimeCounterUtil::getInstance().clockCounter->setInterval(1000); - TimeCounterUtil::getInstance().clockCounter->start(); + TimeCounterUtil::getInstance().clockCounter->start(1000); } StartupForm::~StartupForm() @@ -45,6 +46,30 @@ ui->labDate->setText(QDate::currentDate().toString("yyyy-MM-dd")); } +void StartupForm::takeOneFrameForCheckStatus() +{ + if (ProMemory::getInstance().appState != CasicBioRecConst::ApplicationState::STATE_WAIT) + { + // 非待机状态直接返回 + return; + } + + cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); + bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + if (hasFace == true) + { + LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; + + // 启动识别线程 + // 槽函数 CasicBioRecWin::switchToRecognizeForm + emit startRecognize(); + + // 退出 + return ; + } +} + void StartupForm::on_btnUser_clicked() { emit switchToUserListForm(); diff --git a/StartupForm.h b/StartupForm.h index 6aed14d..f2850e9 100644 --- a/StartupForm.h +++ b/StartupForm.h @@ -4,9 +4,10 @@ #include #include #include +#include -#include "utils/SettingConfig.h" -#include "utils/TimeCounterUtil.h" +#include "casic/ProMemory.h" +#include "utils/UtilInclude.h" namespace Ui { class StartupForm; @@ -25,12 +26,15 @@ private slots: void updateDateAndTime(); + void takeOneFrameForCheckStatus(); void on_btnUser_clicked(); void on_btnSetting_clicked(); signals: void switchToUserListForm(); void switchToSettingForm(); + + void startRecognize(); }; #endif // STARTUPFORM_H diff --git a/casic/CasicBioRecConst.h b/casic/CasicBioRecConst.h index f55c84f..78d150b 100644 --- a/casic/CasicBioRecConst.h +++ b/casic/CasicBioRecConst.h @@ -12,7 +12,13 @@ ADD_PERSON_CAPTURE_FACE = 21, // 添加/编辑人员时进行人脸拍图 ADD_PERSON_CAPTURE_IRIS = 22, // 添加/编辑人员时进行虹膜拍图 SETTING_FORM = 3, // 设置页面 - RECOGNIZE_SUCCESS_FORM = 4 // 识别成功界面 + RECOGNIZE_RESULT_FORM = 4 // 识别结果界面 + }; + + enum ApplicationState + { + STATE_WAIT = 0, // 待机 + STATE_WORKING = 1, // 工作状态 }; }; diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 33010d2..6454343 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -12,9 +12,11 @@ #include "device/FaceCameraController.h" #include "device/face/FaceDetectRegistProcess.h" +#include "device/face/FaceDetectRecogProcess.h" class FaceCameraController; class FaceDetectRegistProcess; +class FaceDetectRecogProcess; class ProMemory { @@ -41,7 +43,8 @@ bool isIrisQueueEmpty(); void clearIrisQueue(); - volatile int widgeFrame; + volatile int widgeFrame = 0; // 当前显示的界面 + volatile int appState = 0; // 当前程序所处的状态 QString capFaceOrIris; // 注册虹膜或者人脸 void initFaceFeatures(); // 初始化人脸特征值集合 @@ -51,6 +54,8 @@ FaceCameraController * faceCam; FaceDetectRegistProcess * faceRegistPro; + FaceDetectRecogProcess * faceRecogPro; + private: ProMemory(); diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index 5e09b86..cb4d3bd 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -402,6 +402,42 @@ return rect.at(0); } +bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} +bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) +{ + // 构建openCV自带的眼睛分类器 + if (this->eyeCascade == nullptr) + { + this->eyeCascade = new cv::CascadeClassifier(); + this->eyeCascade->load(cvEyeCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minEyeSize, minEyeSize); + cv::Size maxRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + eyeCascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} + void casic::face::CasicFaceInterface::setMinFaceSize(int minFaceSize) { this->minFaceSize = minFaceSize; diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index d6d4494..8a1c564 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -50,6 +50,8 @@ cv::Rect faceDetectByCVCascade(cv::Mat frame); cv::Rect eyeDetectByCVCascade(cv::Mat frame); + bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); + bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); private: diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 5f0e2ae..493fdb7 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -6,7 +6,18 @@ FaceCameraController::FaceCameraController(QObject *parent) : QObject(parent) { + this->faceCap = new cv::VideoCapture(SettingConfig::getInstance().FACE_CAMERA_INDEX, cv::CAP_DSHOW); + faceCap->set(cv::CAP_PROP_FRAME_WIDTH, SettingConfig::getInstance().FACE_FRAME_WIDTH); + faceCap->set(cv::CAP_PROP_FRAME_HEIGHT, SettingConfig::getInstance().FACE_FRAME_HEIGHT); + LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]初始化相机[%1][%2 * %3]") + .arg(SettingConfig::getInstance().FACE_CAMERA_INDEX) + .arg(SettingConfig::getInstance().FACE_FRAME_WIDTH) + .arg(SettingConfig::getInstance().FACE_FRAME_HEIGHT).toStdString(); + + // 获取定时器, 绑定定时函数 + connect(TimeCounterUtil::getInstance().faceCapCounter, &QTimer::timeout, + this, &FaceCameraController::getOneFaceFrm); } FaceCameraController::~FaceCameraController() @@ -15,25 +26,11 @@ } -void FaceCameraController::openFaceCamera() +void FaceCameraController::openFaceCamera(int mInterval) { - // 获取定时器, 绑定定时函数 - connect(TimeCounterUtil::getInstance().faceCapCounter, &QTimer::timeout, - this, &FaceCameraController::getOneFaceFrm); - - this->faceCap = new cv::VideoCapture(SettingConfig::getInstance().FACE_CAMERA_INDEX, cv::CAP_DSHOW); - faceCap->set(cv::CAP_PROP_FRAME_WIDTH, SettingConfig::getInstance().FACE_FRAME_WIDTH); - faceCap->set(cv::CAP_PROP_FRAME_HEIGHT, SettingConfig::getInstance().FACE_FRAME_HEIGHT); - - LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]打开相机[%1][%2 * %3]") - .arg(SettingConfig::getInstance().FACE_CAMERA_INDEX) - .arg(SettingConfig::getInstance().FACE_FRAME_WIDTH) - .arg(SettingConfig::getInstance().FACE_FRAME_HEIGHT).toStdString(); - // 启动定时器 - TimeCounterUtil::getInstance().faceCapCounter->start(SettingConfig::getInstance().FACE_FRAME_INTERVAL); - LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]相机开始拍图[%1ms]") - .arg(SettingConfig::getInstance().FACE_FRAME_INTERVAL).toStdString(); + TimeCounterUtil::getInstance().faceCapCounter->start(mInterval); + LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]相机开始拍图[%1ms]").arg(mInterval).toStdString(); } void FaceCameraController::stopTakingPhoto() @@ -87,5 +84,39 @@ // 发送信号用于界面显示 emit sendImageToDraw(imgDisplay); + } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM) + { + // 拍图 + faceCap->read(faceMat); + + LOG(TRACE) << "TAKE ONE FACE FRAME " << faceMat.cols << " * " << faceMat.rows; + + // 左右翻转 + cv::Mat imageMatMiir; + flip(faceMat, imageMatMiir, 1); + + // clone一个mat, 用于界面显示 + cv::Mat faceMatDisp = imageMatMiir.clone(); + + CasicFaceInfo faceInfo; + faceInfo.hasFace = false; + faceInfo.matData = imageMatMiir; + + // 将图片数据压入堆栈 + ProMemory::getInstance().pushCasicFace(faceInfo); + + // 将mat转成QImage + QImage imgDisplay = ImageUtil::MatImageToQImage(faceMatDisp); + + // 发送信号用于界面显示 + emit sendImageToDrawForRecognize(imgDisplay); } } + +cv::Mat FaceCameraController::takeOneRawFrame() +{ + // 拍图 + cv::Mat camMat; + faceCap->read(camMat); + return camMat; +} diff --git a/device/FaceCameraController.h b/device/FaceCameraController.h index 6570cfb..b6dfd61 100644 --- a/device/FaceCameraController.h +++ b/device/FaceCameraController.h @@ -6,9 +6,6 @@ #include "opencv2/opencv.hpp" #include "casic/ProMemory.h" -//#include "casic/face/CasicFaceInterface.h" -//#include "process/memory/ProMemory.h" -//#include "process/face/CasicFaceRecState.h" #include "utils/ImageUtil.h" #include "utils/SettingConfig.h" #include "utils/TimeCounterUtil.h" @@ -22,7 +19,8 @@ ~FaceCameraController(); // 初始化并打开人脸相机 - void openFaceCamera(); + void openFaceCamera(int mInterval); + cv::Mat takeOneRawFrame(); void stopTakingPhoto(); void closeFaceCamera(); @@ -36,6 +34,7 @@ signals: void sendImageToDraw(QImage imageDisp); + void sendImageToDrawForRecognize(QImage imageDisp); void sendImageToDetect(cv::Mat imgMat); }; diff --git a/device/device.pri b/device/device.pri index 71d9dfa..274ba60 100644 --- a/device/device.pri +++ b/device/device.pri @@ -1,10 +1,12 @@ HEADERS += $$PWD/FaceCameraController.h HEADERS += $$PWD/face/FaceDetectRegistProcess.h +HEADERS += $$PWD/face/FaceDetectRecogProcess.h HEADERS += $$PWD/face/CasicFaceRecState.h SOURCES += $$PWD/FaceCameraController.cpp SOURCES += $$PWD/face/FaceDetectRegistProcess.cpp +SOURCES += $$PWD/face/FaceDetectRecogProcess.cpp SOURCES += $$PWD/face/CasicFaceRecState.cpp #HEADERS += $$PWD/IrisCameraController.h diff --git a/device/face/FaceDetectRecogProcess.cpp b/device/face/FaceDetectRecogProcess.cpp new file mode 100644 index 0000000..00e45ff --- /dev/null +++ b/device/face/FaceDetectRecogProcess.cpp @@ -0,0 +1,198 @@ +#include "FaceDetectRecogProcess.h" + +FaceDetectRecogProcess::FaceDetectRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; +} + +FaceDetectRecogProcess::~FaceDetectRecogProcess() +{ + this->setWorking(false); +} + +void FaceDetectRecogProcess::setWorking(bool working) +{ + this->working = working; +} +void FaceDetectRecogProcess::exitThread() +{ + this->exit = true; +} +void FaceDetectRecogProcess::startThread() +{ + this->exit = false; + this->start(); +} + +void FaceDetectRecogProcess::addOneTryCount() +{ + LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); + if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) + { + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + } else + { + CasicFaceRecState::getInstance().tryCount = 0; + CasicFaceRecState::getInstance().noFaceCount = 0; + emit matchFailure(); + + this->setWorking(false); // 返回后则线程暂停工作 + } +} + +void FaceDetectRecogProcess::addOneNoFaceCount() +{ + CasicFaceRecState::getInstance().noFaceCount++; + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) + { + CasicFaceRecState::getInstance().noFaceCount = 0; + emit matchFailure(); + + this->setWorking(false); // 返回后则暂停工作 + } +} + +void FaceDetectRecogProcess::run() +{ + while (exit == false) + { + if (this->working == false) + { + this->msleep(100); // 100ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isFaceQueueEmpty() == true) + { + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) + { + LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 取出人脸图像栈中的一条数据 + CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); + + // 调用人脸检测算法 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); + + // 没有找到人脸则返回 + if (faceInfo.hasFace == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 找到人脸则开始一次识别 + if (CasicFaceRecState::getInstance().recoginzeId == "0") + { + CasicFaceRecState::getInstance().initRecognize(); + } + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 + CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 + + // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 + casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); + faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); + + // 活体检测判断为假脸 + if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) + { + // 表示本次识别结束, 可以开始下一次识别过程 + LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); + + addOneTryCount(); // 判断是否超过次数, 重置识别状态 + this->msleep(200); // 200ms后再判断 + continue; + } + + // 设置识别状态值=通过活体检测 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; + + // 调用算法提取特征值, 1024个字节的float数组 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); + + // 设置识别状态值=特征值提取 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + + LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + this->setWorking(false); + // 特征值提取成功的人脸 与人脸库中的人脸进行比较 + compareFaceInCollection(); + } +} + +void FaceDetectRecogProcess::compareFaceInCollection() +{ + ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 + QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); + for (int i = 0; i < faceFeatures.size(); i++) + { + QVariantMap ffMap = faceFeatures.at(i); + + QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); + float ffArr[1024]; + for (int i = 0; i < 1024; i++) + { + QByteArray tempBa; + tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); + ffArr[i] = ByteUtil::binToFloat(tempBa); + } + + float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); + + LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); + if (sim > 0.62) + { + CasicFaceRecState::getInstance().faceInfo->sim = sim; + CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); + CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; + + // 找到匹配的人脸图像 + this->afterRecogAction(ffMap.value("person_id").toString()); + return ; + } + } + + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + this->addOneTryCount(); +} + +void FaceDetectRecogProcess::afterRecogAction(QString personId) +{ + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + + LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + // 发送信号, 在主界面上显示 + emit matchSuccess(personId); +} + diff --git a/device/face/FaceDetectRecogProcess.h b/device/face/FaceDetectRecogProcess.h new file mode 100644 index 0000000..b1051b7 --- /dev/null +++ b/device/face/FaceDetectRecogProcess.h @@ -0,0 +1,50 @@ +#ifndef FACEDETECTRECOGPROCESS_H +#define FACEDETECTRECOGPROCESS_H + +#include +#include +#include "opencv2/opencv.hpp" + +#include "dao/RecognitionRecordDao.h" + +#include "utils/easyloggingpp/easylogging++.h" +#include "utils/ImageUtil.h" +#include "utils/SettingConfig.h" +#include "utils/ByteUtil.h" + +#include "CasicFaceRecState.h" +#include "casic/ProMemory.h" +#include "casic/face/CasicFaceInterface.h" + +class FaceDetectRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit FaceDetectRecogProcess(QObject *parent = nullptr); + ~FaceDetectRecogProcess(); + + void setWorking(bool working); + void exitThread(); + void startThread(); + + void addOneTryCount(); + void addOneNoFaceCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + void compareFaceInCollection(); + void afterRecogAction(QString personId); + + volatile bool working; + volatile bool exit; + +signals: + void matchSuccess(QString personId); // 匹配成功 + void matchFailure(); // 匹配失败 + +}; + +#endif // FACEDETECTRECOGPROCESS_H diff --git a/device/face/FaceDetectRegistProcess.h b/device/face/FaceDetectRegistProcess.h index 9ffa91d..99a504c 100644 --- a/device/face/FaceDetectRegistProcess.h +++ b/device/face/FaceDetectRegistProcess.h @@ -14,8 +14,6 @@ #include "casic/ProMemory.h" #include "casic/face/CasicFaceInterface.h" -static bool FACE_DETECT_FLAG = false; - class FaceDetectRegistProcess : public QThread { Q_OBJECT @@ -40,10 +38,8 @@ volatile bool exit; signals: - void extractFeatureSuccess(); void failedCaptureFace(); void successCaptureFace(QString personIdByFace); - void findSimFace(QString personId); }; diff --git a/images/bg_recognize_result.png b/images/bg_recognize_result.png new file mode 100644 index 0000000..068b55b --- /dev/null +++ b/images/bg_recognize_result.png Binary files differ diff --git a/images/bg_video.png b/images/bg_video.png new file mode 100644 index 0000000..3ed9dae --- /dev/null +++ b/images/bg_video.png Binary files differ diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index fe3819d..934dfad 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -1,7 +1,5 @@ #include "CasicBioRecWin.h" #include "ui_CasicBioRecWin.h" -#include -#include CasicBioRecWin::CasicBioRecWin(QWidget *parent) : QMainWindow(parent) @@ -26,11 +24,15 @@ // 初始化识别和注册的各个线程 initFaceRegistThread(); // 人脸注册线程 + initFaceRecogThread(); // 人脸识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); + ProMemory::getInstance().faceCam->openFaceCamera(1000); connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDraw, addPersonForm, &AddPersonForm::drawImageOnForm); + connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDrawForRecognize, + recogResultForm, &RecognizeResultForm::drawImageOnHomeForm); // 打印日志 LOG(INFO) << QString("应用程序启动成功[Application Startup Success]").toStdString(); @@ -43,8 +45,13 @@ ProMemory::getInstance().faceRegistPro->deleteLater(); ProMemory::getInstance().faceRegistPro->wait(); + ProMemory::getInstance().faceRecogPro->exitThread(); + ProMemory::getInstance().faceRecogPro->deleteLater(); + ProMemory::getInstance().faceRecogPro->wait(); + delete ui; delete ProMemory::getInstance().faceRegistPro; + delete ProMemory::getInstance().faceRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -94,6 +101,13 @@ ui->stacked->setCurrentWidget(addPersonForm); ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::ADD_PERSON_FORM; } +void CasicBioRecWin::switchToRecognizeForm() +{ + ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM; + ui->stacked->setCurrentWidget(recogResultForm); + + recogResultForm->startWorkingRecognize(); +} void CasicBioRecWin::initFormsPtr() { @@ -101,18 +115,21 @@ personListForm = new PersonListForm(this); settingForm = new SettingForm(this); addPersonForm = new AddPersonForm(this); + recogResultForm = new RecognizeResultForm(this); ui->stacked->addWidget(startForm); ui->stacked->addWidget(personListForm); ui->stacked->addWidget(settingForm); ui->stacked->addWidget(addPersonForm); - + ui->stacked->addWidget(recogResultForm); // 绑定按钮函数 connect(startForm, &StartupForm::switchToUserListForm, this, &CasicBioRecWin::switchToUserListForm); connect(startForm, &StartupForm::switchToSettingForm, this, &CasicBioRecWin::switchToSettingForm); + connect(startForm, &StartupForm::startRecognize, + this, &CasicBioRecWin::switchToRecognizeForm); connect(personListForm, &PersonListForm::switchToRegistForm, this, &CasicBioRecWin::switchToRegistForm); @@ -146,3 +163,20 @@ ProMemory::getInstance().faceRegistPro->start(); } + +void CasicBioRecWin::initFaceRecogThread() +{ + // 人脸识别处理过程 + ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().faceRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index 3e706fe..f0b47bf 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -2,19 +2,20 @@ #define CASICBIORECWIN_H #include +#include +#include #include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SettingConfig.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" #include "StartupForm.h" #include "PersonListForm.h" #include "SettingForm.h" #include "AddPersonForm.h" +#include "RecognizeResultForm.h" #include "device/FaceCameraController.h" -#include "device/face/FaceDetectRegistProcess.h" QT_BEGIN_NAMESPACE namespace Ui { class CasicBioRecWin; } @@ -33,6 +34,7 @@ void switchToUserListForm(); void switchToSettingForm(); void switchToRegistForm(QString personId); + void switchToRecognizeForm(); private: Ui::CasicBioRecWin *ui; @@ -41,11 +43,13 @@ PersonListForm * personListForm; SettingForm * settingForm; AddPersonForm * addPersonForm; + RecognizeResultForm * recogResultForm; void keyPressEvent(QKeyEvent *event); void initFormsPtr(); void initCacheData(); void initFaceRegistThread(); + void initFaceRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/PersonListForm.h b/PersonListForm.h index db352c6..65bd3f5 100644 --- a/PersonListForm.h +++ b/PersonListForm.h @@ -7,7 +7,7 @@ #include "ConfirmTipsDialog.h" #include "OperationTipsDialog.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" +#include "utils/UtilInclude.h" namespace Ui { class PersonListForm; diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp new file mode 100644 index 0000000..b6790a9 --- /dev/null +++ b/RecognizeResultForm.cpp @@ -0,0 +1,60 @@ +#include "RecognizeResultForm.h" +#include "ui_RecognizeResultForm.h" + +RecognizeResultForm::RecognizeResultForm(QWidget *parent) : + QWidget(parent), + ui(new Ui::RecognizeResultForm) +{ + ui->setupUi(this); + ui->labVideo->hide(); + + // 加载css文件设置控件样式 + QFile file(QApplication::applicationDirPath() + "/qss/recognize.css"); + if (file.open(QFile::ReadOnly)) + { + QString qssStr = QLatin1String(file.readAll()); + this->setStyleSheet(qssStr); + file.close(); + } +} + +RecognizeResultForm::~RecognizeResultForm() +{ + delete ui; +} + +void RecognizeResultForm::startWorkingRecognize() +{ + // 开始人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + + // 将界面切换到识别界面 RecognizeResultForm + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + + // 1人脸图像显示的容器 + ui->labVideo->resize(1060, 607); + ui->labVideo->move(110, 100); + ui->labVideo->raise(); + ui->labVideo->show(); +} + + +void RecognizeResultForm::drawImageOnHomeForm(QImage imageDisp) +{ + if (ui->labVideo->isVisible() == true) + { + LOG(TRACE) << "DRAW IMAGE ON FORM " << imageDisp.width() << "*" << imageDisp.height(); + imageDisp = imageDisp.scaled(1040, 585); + ui->labVideo->setPixmap(QPixmap::fromImage(imageDisp)); + } +} + +void RecognizeResultForm::showRecogFailure() +{ + +} +void RecognizeResultForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功"); +// ui->labVideo->hide(); +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h new file mode 100644 index 0000000..3be5410 --- /dev/null +++ b/RecognizeResultForm.h @@ -0,0 +1,34 @@ +#ifndef RECOGNIZERESULTFORM_H +#define RECOGNIZERESULTFORM_H + +#include + +#include "utils/UtilInclude.h" + +#include "casic/ProMemory.h" + +namespace Ui { +class RecognizeResultForm; +} + +class RecognizeResultForm : public QWidget +{ + Q_OBJECT + +public: + explicit RecognizeResultForm(QWidget *parent = nullptr); + ~RecognizeResultForm(); + +public slots: + void showRecogFailure(); + void showRecognizeResult(QString personId); + + void startWorkingRecognize(); // 开始工作 + void drawImageOnHomeForm(QImage imageDisp); + +private: + Ui::RecognizeResultForm *ui; + +}; + +#endif // RECOGNIZERESULTFORM_H diff --git a/RecognizeResultForm.ui b/RecognizeResultForm.ui new file mode 100644 index 0000000..9d08547 --- /dev/null +++ b/RecognizeResultForm.ui @@ -0,0 +1,212 @@ + + + RecognizeResultForm + + + + 0 + 0 + 1280 + 800 + + + + Form + + + + + 0 + 0 + 1280 + 800 + + + + + + + :/images/bg_recognize_result.png + + + + + + 0 + 0 + 0 + 0 + + + + + + + Qt::AlignCenter + + + + + + 0 + 0 + 1280 + 90 + + + + + + + 人员识别 + + + Qt::AlignCenter + + + + + + 109 + 119 + 551 + 431 + + + + + + -110 + -70 + 280 + 380 + + + + :/images/photoFace.png + + + Qt::AlignCenter + + + + + + 240 + 220 + 54 + 12 + + + + TextLabel + + + + + + 240 + 10 + 54 + 12 + + + + TextLabel + + + + + + 240 + 160 + 54 + 12 + + + + TextLabel + + + + + + 240 + 90 + 54 + 12 + + + + TextLabel + + + + + + 440 + 260 + 54 + 12 + + + + TextLabel + + + + + + 430 + 130 + 54 + 12 + + + + TextLabel + + + + + + 440 + 200 + 54 + 12 + + + + TextLabel + + + + + + 430 + 50 + 54 + 12 + + + + TextLabel + + + + + + + 550 + 470 + 120 + 80 + + + + + + + + + diff --git a/StartupForm.cpp b/StartupForm.cpp index af51bcc..c8b9c64 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -26,12 +26,13 @@ ui->hsMidd->changeSize(150, 0); // 初始化更新界面的定时器 - // 每分钟执行一次 + // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); - TimeCounterUtil::getInstance().clockCounter->setInterval(1000); - TimeCounterUtil::getInstance().clockCounter->start(); + TimeCounterUtil::getInstance().clockCounter->start(1000); } StartupForm::~StartupForm() @@ -45,6 +46,30 @@ ui->labDate->setText(QDate::currentDate().toString("yyyy-MM-dd")); } +void StartupForm::takeOneFrameForCheckStatus() +{ + if (ProMemory::getInstance().appState != CasicBioRecConst::ApplicationState::STATE_WAIT) + { + // 非待机状态直接返回 + return; + } + + cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); + bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + if (hasFace == true) + { + LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; + + // 启动识别线程 + // 槽函数 CasicBioRecWin::switchToRecognizeForm + emit startRecognize(); + + // 退出 + return ; + } +} + void StartupForm::on_btnUser_clicked() { emit switchToUserListForm(); diff --git a/StartupForm.h b/StartupForm.h index 6aed14d..f2850e9 100644 --- a/StartupForm.h +++ b/StartupForm.h @@ -4,9 +4,10 @@ #include #include #include +#include -#include "utils/SettingConfig.h" -#include "utils/TimeCounterUtil.h" +#include "casic/ProMemory.h" +#include "utils/UtilInclude.h" namespace Ui { class StartupForm; @@ -25,12 +26,15 @@ private slots: void updateDateAndTime(); + void takeOneFrameForCheckStatus(); void on_btnUser_clicked(); void on_btnSetting_clicked(); signals: void switchToUserListForm(); void switchToSettingForm(); + + void startRecognize(); }; #endif // STARTUPFORM_H diff --git a/casic/CasicBioRecConst.h b/casic/CasicBioRecConst.h index f55c84f..78d150b 100644 --- a/casic/CasicBioRecConst.h +++ b/casic/CasicBioRecConst.h @@ -12,7 +12,13 @@ ADD_PERSON_CAPTURE_FACE = 21, // 添加/编辑人员时进行人脸拍图 ADD_PERSON_CAPTURE_IRIS = 22, // 添加/编辑人员时进行虹膜拍图 SETTING_FORM = 3, // 设置页面 - RECOGNIZE_SUCCESS_FORM = 4 // 识别成功界面 + RECOGNIZE_RESULT_FORM = 4 // 识别结果界面 + }; + + enum ApplicationState + { + STATE_WAIT = 0, // 待机 + STATE_WORKING = 1, // 工作状态 }; }; diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 33010d2..6454343 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -12,9 +12,11 @@ #include "device/FaceCameraController.h" #include "device/face/FaceDetectRegistProcess.h" +#include "device/face/FaceDetectRecogProcess.h" class FaceCameraController; class FaceDetectRegistProcess; +class FaceDetectRecogProcess; class ProMemory { @@ -41,7 +43,8 @@ bool isIrisQueueEmpty(); void clearIrisQueue(); - volatile int widgeFrame; + volatile int widgeFrame = 0; // 当前显示的界面 + volatile int appState = 0; // 当前程序所处的状态 QString capFaceOrIris; // 注册虹膜或者人脸 void initFaceFeatures(); // 初始化人脸特征值集合 @@ -51,6 +54,8 @@ FaceCameraController * faceCam; FaceDetectRegistProcess * faceRegistPro; + FaceDetectRecogProcess * faceRecogPro; + private: ProMemory(); diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index 5e09b86..cb4d3bd 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -402,6 +402,42 @@ return rect.at(0); } +bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} +bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) +{ + // 构建openCV自带的眼睛分类器 + if (this->eyeCascade == nullptr) + { + this->eyeCascade = new cv::CascadeClassifier(); + this->eyeCascade->load(cvEyeCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minEyeSize, minEyeSize); + cv::Size maxRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + eyeCascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} + void casic::face::CasicFaceInterface::setMinFaceSize(int minFaceSize) { this->minFaceSize = minFaceSize; diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index d6d4494..8a1c564 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -50,6 +50,8 @@ cv::Rect faceDetectByCVCascade(cv::Mat frame); cv::Rect eyeDetectByCVCascade(cv::Mat frame); + bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); + bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); private: diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 5f0e2ae..493fdb7 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -6,7 +6,18 @@ FaceCameraController::FaceCameraController(QObject *parent) : QObject(parent) { + this->faceCap = new cv::VideoCapture(SettingConfig::getInstance().FACE_CAMERA_INDEX, cv::CAP_DSHOW); + faceCap->set(cv::CAP_PROP_FRAME_WIDTH, SettingConfig::getInstance().FACE_FRAME_WIDTH); + faceCap->set(cv::CAP_PROP_FRAME_HEIGHT, SettingConfig::getInstance().FACE_FRAME_HEIGHT); + LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]初始化相机[%1][%2 * %3]") + .arg(SettingConfig::getInstance().FACE_CAMERA_INDEX) + .arg(SettingConfig::getInstance().FACE_FRAME_WIDTH) + .arg(SettingConfig::getInstance().FACE_FRAME_HEIGHT).toStdString(); + + // 获取定时器, 绑定定时函数 + connect(TimeCounterUtil::getInstance().faceCapCounter, &QTimer::timeout, + this, &FaceCameraController::getOneFaceFrm); } FaceCameraController::~FaceCameraController() @@ -15,25 +26,11 @@ } -void FaceCameraController::openFaceCamera() +void FaceCameraController::openFaceCamera(int mInterval) { - // 获取定时器, 绑定定时函数 - connect(TimeCounterUtil::getInstance().faceCapCounter, &QTimer::timeout, - this, &FaceCameraController::getOneFaceFrm); - - this->faceCap = new cv::VideoCapture(SettingConfig::getInstance().FACE_CAMERA_INDEX, cv::CAP_DSHOW); - faceCap->set(cv::CAP_PROP_FRAME_WIDTH, SettingConfig::getInstance().FACE_FRAME_WIDTH); - faceCap->set(cv::CAP_PROP_FRAME_HEIGHT, SettingConfig::getInstance().FACE_FRAME_HEIGHT); - - LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]打开相机[%1][%2 * %3]") - .arg(SettingConfig::getInstance().FACE_CAMERA_INDEX) - .arg(SettingConfig::getInstance().FACE_FRAME_WIDTH) - .arg(SettingConfig::getInstance().FACE_FRAME_HEIGHT).toStdString(); - // 启动定时器 - TimeCounterUtil::getInstance().faceCapCounter->start(SettingConfig::getInstance().FACE_FRAME_INTERVAL); - LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]相机开始拍图[%1ms]") - .arg(SettingConfig::getInstance().FACE_FRAME_INTERVAL).toStdString(); + TimeCounterUtil::getInstance().faceCapCounter->start(mInterval); + LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]相机开始拍图[%1ms]").arg(mInterval).toStdString(); } void FaceCameraController::stopTakingPhoto() @@ -87,5 +84,39 @@ // 发送信号用于界面显示 emit sendImageToDraw(imgDisplay); + } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM) + { + // 拍图 + faceCap->read(faceMat); + + LOG(TRACE) << "TAKE ONE FACE FRAME " << faceMat.cols << " * " << faceMat.rows; + + // 左右翻转 + cv::Mat imageMatMiir; + flip(faceMat, imageMatMiir, 1); + + // clone一个mat, 用于界面显示 + cv::Mat faceMatDisp = imageMatMiir.clone(); + + CasicFaceInfo faceInfo; + faceInfo.hasFace = false; + faceInfo.matData = imageMatMiir; + + // 将图片数据压入堆栈 + ProMemory::getInstance().pushCasicFace(faceInfo); + + // 将mat转成QImage + QImage imgDisplay = ImageUtil::MatImageToQImage(faceMatDisp); + + // 发送信号用于界面显示 + emit sendImageToDrawForRecognize(imgDisplay); } } + +cv::Mat FaceCameraController::takeOneRawFrame() +{ + // 拍图 + cv::Mat camMat; + faceCap->read(camMat); + return camMat; +} diff --git a/device/FaceCameraController.h b/device/FaceCameraController.h index 6570cfb..b6dfd61 100644 --- a/device/FaceCameraController.h +++ b/device/FaceCameraController.h @@ -6,9 +6,6 @@ #include "opencv2/opencv.hpp" #include "casic/ProMemory.h" -//#include "casic/face/CasicFaceInterface.h" -//#include "process/memory/ProMemory.h" -//#include "process/face/CasicFaceRecState.h" #include "utils/ImageUtil.h" #include "utils/SettingConfig.h" #include "utils/TimeCounterUtil.h" @@ -22,7 +19,8 @@ ~FaceCameraController(); // 初始化并打开人脸相机 - void openFaceCamera(); + void openFaceCamera(int mInterval); + cv::Mat takeOneRawFrame(); void stopTakingPhoto(); void closeFaceCamera(); @@ -36,6 +34,7 @@ signals: void sendImageToDraw(QImage imageDisp); + void sendImageToDrawForRecognize(QImage imageDisp); void sendImageToDetect(cv::Mat imgMat); }; diff --git a/device/device.pri b/device/device.pri index 71d9dfa..274ba60 100644 --- a/device/device.pri +++ b/device/device.pri @@ -1,10 +1,12 @@ HEADERS += $$PWD/FaceCameraController.h HEADERS += $$PWD/face/FaceDetectRegistProcess.h +HEADERS += $$PWD/face/FaceDetectRecogProcess.h HEADERS += $$PWD/face/CasicFaceRecState.h SOURCES += $$PWD/FaceCameraController.cpp SOURCES += $$PWD/face/FaceDetectRegistProcess.cpp +SOURCES += $$PWD/face/FaceDetectRecogProcess.cpp SOURCES += $$PWD/face/CasicFaceRecState.cpp #HEADERS += $$PWD/IrisCameraController.h diff --git a/device/face/FaceDetectRecogProcess.cpp b/device/face/FaceDetectRecogProcess.cpp new file mode 100644 index 0000000..00e45ff --- /dev/null +++ b/device/face/FaceDetectRecogProcess.cpp @@ -0,0 +1,198 @@ +#include "FaceDetectRecogProcess.h" + +FaceDetectRecogProcess::FaceDetectRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; +} + +FaceDetectRecogProcess::~FaceDetectRecogProcess() +{ + this->setWorking(false); +} + +void FaceDetectRecogProcess::setWorking(bool working) +{ + this->working = working; +} +void FaceDetectRecogProcess::exitThread() +{ + this->exit = true; +} +void FaceDetectRecogProcess::startThread() +{ + this->exit = false; + this->start(); +} + +void FaceDetectRecogProcess::addOneTryCount() +{ + LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); + if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) + { + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + } else + { + CasicFaceRecState::getInstance().tryCount = 0; + CasicFaceRecState::getInstance().noFaceCount = 0; + emit matchFailure(); + + this->setWorking(false); // 返回后则线程暂停工作 + } +} + +void FaceDetectRecogProcess::addOneNoFaceCount() +{ + CasicFaceRecState::getInstance().noFaceCount++; + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) + { + CasicFaceRecState::getInstance().noFaceCount = 0; + emit matchFailure(); + + this->setWorking(false); // 返回后则暂停工作 + } +} + +void FaceDetectRecogProcess::run() +{ + while (exit == false) + { + if (this->working == false) + { + this->msleep(100); // 100ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isFaceQueueEmpty() == true) + { + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) + { + LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 取出人脸图像栈中的一条数据 + CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); + + // 调用人脸检测算法 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); + + // 没有找到人脸则返回 + if (faceInfo.hasFace == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 找到人脸则开始一次识别 + if (CasicFaceRecState::getInstance().recoginzeId == "0") + { + CasicFaceRecState::getInstance().initRecognize(); + } + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 + CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 + + // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 + casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); + faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); + + // 活体检测判断为假脸 + if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) + { + // 表示本次识别结束, 可以开始下一次识别过程 + LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); + + addOneTryCount(); // 判断是否超过次数, 重置识别状态 + this->msleep(200); // 200ms后再判断 + continue; + } + + // 设置识别状态值=通过活体检测 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; + + // 调用算法提取特征值, 1024个字节的float数组 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); + + // 设置识别状态值=特征值提取 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + + LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + this->setWorking(false); + // 特征值提取成功的人脸 与人脸库中的人脸进行比较 + compareFaceInCollection(); + } +} + +void FaceDetectRecogProcess::compareFaceInCollection() +{ + ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 + QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); + for (int i = 0; i < faceFeatures.size(); i++) + { + QVariantMap ffMap = faceFeatures.at(i); + + QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); + float ffArr[1024]; + for (int i = 0; i < 1024; i++) + { + QByteArray tempBa; + tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); + ffArr[i] = ByteUtil::binToFloat(tempBa); + } + + float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); + + LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); + if (sim > 0.62) + { + CasicFaceRecState::getInstance().faceInfo->sim = sim; + CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); + CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; + + // 找到匹配的人脸图像 + this->afterRecogAction(ffMap.value("person_id").toString()); + return ; + } + } + + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + this->addOneTryCount(); +} + +void FaceDetectRecogProcess::afterRecogAction(QString personId) +{ + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + + LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + // 发送信号, 在主界面上显示 + emit matchSuccess(personId); +} + diff --git a/device/face/FaceDetectRecogProcess.h b/device/face/FaceDetectRecogProcess.h new file mode 100644 index 0000000..b1051b7 --- /dev/null +++ b/device/face/FaceDetectRecogProcess.h @@ -0,0 +1,50 @@ +#ifndef FACEDETECTRECOGPROCESS_H +#define FACEDETECTRECOGPROCESS_H + +#include +#include +#include "opencv2/opencv.hpp" + +#include "dao/RecognitionRecordDao.h" + +#include "utils/easyloggingpp/easylogging++.h" +#include "utils/ImageUtil.h" +#include "utils/SettingConfig.h" +#include "utils/ByteUtil.h" + +#include "CasicFaceRecState.h" +#include "casic/ProMemory.h" +#include "casic/face/CasicFaceInterface.h" + +class FaceDetectRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit FaceDetectRecogProcess(QObject *parent = nullptr); + ~FaceDetectRecogProcess(); + + void setWorking(bool working); + void exitThread(); + void startThread(); + + void addOneTryCount(); + void addOneNoFaceCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + void compareFaceInCollection(); + void afterRecogAction(QString personId); + + volatile bool working; + volatile bool exit; + +signals: + void matchSuccess(QString personId); // 匹配成功 + void matchFailure(); // 匹配失败 + +}; + +#endif // FACEDETECTRECOGPROCESS_H diff --git a/device/face/FaceDetectRegistProcess.h b/device/face/FaceDetectRegistProcess.h index 9ffa91d..99a504c 100644 --- a/device/face/FaceDetectRegistProcess.h +++ b/device/face/FaceDetectRegistProcess.h @@ -14,8 +14,6 @@ #include "casic/ProMemory.h" #include "casic/face/CasicFaceInterface.h" -static bool FACE_DETECT_FLAG = false; - class FaceDetectRegistProcess : public QThread { Q_OBJECT @@ -40,10 +38,8 @@ volatile bool exit; signals: - void extractFeatureSuccess(); void failedCaptureFace(); void successCaptureFace(QString personIdByFace); - void findSimFace(QString personId); }; diff --git a/images/bg_recognize_result.png b/images/bg_recognize_result.png new file mode 100644 index 0000000..068b55b --- /dev/null +++ b/images/bg_recognize_result.png Binary files differ diff --git a/images/bg_video.png b/images/bg_video.png new file mode 100644 index 0000000..3ed9dae --- /dev/null +++ b/images/bg_video.png Binary files differ diff --git a/qss/recognize.css b/qss/recognize.css new file mode 100644 index 0000000..9c9b4d6 --- /dev/null +++ b/qss/recognize.css @@ -0,0 +1,20 @@ +QLabel { + color: #6868A6; + font-family: "Microsoft YaHei"; +} + +QLabel#labDate { + font-size: 36px; +} + +QLabel#labTime { + font-size: 100px; +} + +QToolButton { + color: #6868A6; + font-family: "Microsoft YaHei"; + font-size: 48px; + background: transparent; + border-style: none; +} diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index fe3819d..934dfad 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -1,7 +1,5 @@ #include "CasicBioRecWin.h" #include "ui_CasicBioRecWin.h" -#include -#include CasicBioRecWin::CasicBioRecWin(QWidget *parent) : QMainWindow(parent) @@ -26,11 +24,15 @@ // 初始化识别和注册的各个线程 initFaceRegistThread(); // 人脸注册线程 + initFaceRecogThread(); // 人脸识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); + ProMemory::getInstance().faceCam->openFaceCamera(1000); connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDraw, addPersonForm, &AddPersonForm::drawImageOnForm); + connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDrawForRecognize, + recogResultForm, &RecognizeResultForm::drawImageOnHomeForm); // 打印日志 LOG(INFO) << QString("应用程序启动成功[Application Startup Success]").toStdString(); @@ -43,8 +45,13 @@ ProMemory::getInstance().faceRegistPro->deleteLater(); ProMemory::getInstance().faceRegistPro->wait(); + ProMemory::getInstance().faceRecogPro->exitThread(); + ProMemory::getInstance().faceRecogPro->deleteLater(); + ProMemory::getInstance().faceRecogPro->wait(); + delete ui; delete ProMemory::getInstance().faceRegistPro; + delete ProMemory::getInstance().faceRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -94,6 +101,13 @@ ui->stacked->setCurrentWidget(addPersonForm); ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::ADD_PERSON_FORM; } +void CasicBioRecWin::switchToRecognizeForm() +{ + ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM; + ui->stacked->setCurrentWidget(recogResultForm); + + recogResultForm->startWorkingRecognize(); +} void CasicBioRecWin::initFormsPtr() { @@ -101,18 +115,21 @@ personListForm = new PersonListForm(this); settingForm = new SettingForm(this); addPersonForm = new AddPersonForm(this); + recogResultForm = new RecognizeResultForm(this); ui->stacked->addWidget(startForm); ui->stacked->addWidget(personListForm); ui->stacked->addWidget(settingForm); ui->stacked->addWidget(addPersonForm); - + ui->stacked->addWidget(recogResultForm); // 绑定按钮函数 connect(startForm, &StartupForm::switchToUserListForm, this, &CasicBioRecWin::switchToUserListForm); connect(startForm, &StartupForm::switchToSettingForm, this, &CasicBioRecWin::switchToSettingForm); + connect(startForm, &StartupForm::startRecognize, + this, &CasicBioRecWin::switchToRecognizeForm); connect(personListForm, &PersonListForm::switchToRegistForm, this, &CasicBioRecWin::switchToRegistForm); @@ -146,3 +163,20 @@ ProMemory::getInstance().faceRegistPro->start(); } + +void CasicBioRecWin::initFaceRecogThread() +{ + // 人脸识别处理过程 + ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().faceRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index 3e706fe..f0b47bf 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -2,19 +2,20 @@ #define CASICBIORECWIN_H #include +#include +#include #include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SettingConfig.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" #include "StartupForm.h" #include "PersonListForm.h" #include "SettingForm.h" #include "AddPersonForm.h" +#include "RecognizeResultForm.h" #include "device/FaceCameraController.h" -#include "device/face/FaceDetectRegistProcess.h" QT_BEGIN_NAMESPACE namespace Ui { class CasicBioRecWin; } @@ -33,6 +34,7 @@ void switchToUserListForm(); void switchToSettingForm(); void switchToRegistForm(QString personId); + void switchToRecognizeForm(); private: Ui::CasicBioRecWin *ui; @@ -41,11 +43,13 @@ PersonListForm * personListForm; SettingForm * settingForm; AddPersonForm * addPersonForm; + RecognizeResultForm * recogResultForm; void keyPressEvent(QKeyEvent *event); void initFormsPtr(); void initCacheData(); void initFaceRegistThread(); + void initFaceRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/PersonListForm.h b/PersonListForm.h index db352c6..65bd3f5 100644 --- a/PersonListForm.h +++ b/PersonListForm.h @@ -7,7 +7,7 @@ #include "ConfirmTipsDialog.h" #include "OperationTipsDialog.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" +#include "utils/UtilInclude.h" namespace Ui { class PersonListForm; diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp new file mode 100644 index 0000000..b6790a9 --- /dev/null +++ b/RecognizeResultForm.cpp @@ -0,0 +1,60 @@ +#include "RecognizeResultForm.h" +#include "ui_RecognizeResultForm.h" + +RecognizeResultForm::RecognizeResultForm(QWidget *parent) : + QWidget(parent), + ui(new Ui::RecognizeResultForm) +{ + ui->setupUi(this); + ui->labVideo->hide(); + + // 加载css文件设置控件样式 + QFile file(QApplication::applicationDirPath() + "/qss/recognize.css"); + if (file.open(QFile::ReadOnly)) + { + QString qssStr = QLatin1String(file.readAll()); + this->setStyleSheet(qssStr); + file.close(); + } +} + +RecognizeResultForm::~RecognizeResultForm() +{ + delete ui; +} + +void RecognizeResultForm::startWorkingRecognize() +{ + // 开始人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + + // 将界面切换到识别界面 RecognizeResultForm + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + + // 1人脸图像显示的容器 + ui->labVideo->resize(1060, 607); + ui->labVideo->move(110, 100); + ui->labVideo->raise(); + ui->labVideo->show(); +} + + +void RecognizeResultForm::drawImageOnHomeForm(QImage imageDisp) +{ + if (ui->labVideo->isVisible() == true) + { + LOG(TRACE) << "DRAW IMAGE ON FORM " << imageDisp.width() << "*" << imageDisp.height(); + imageDisp = imageDisp.scaled(1040, 585); + ui->labVideo->setPixmap(QPixmap::fromImage(imageDisp)); + } +} + +void RecognizeResultForm::showRecogFailure() +{ + +} +void RecognizeResultForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功"); +// ui->labVideo->hide(); +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h new file mode 100644 index 0000000..3be5410 --- /dev/null +++ b/RecognizeResultForm.h @@ -0,0 +1,34 @@ +#ifndef RECOGNIZERESULTFORM_H +#define RECOGNIZERESULTFORM_H + +#include + +#include "utils/UtilInclude.h" + +#include "casic/ProMemory.h" + +namespace Ui { +class RecognizeResultForm; +} + +class RecognizeResultForm : public QWidget +{ + Q_OBJECT + +public: + explicit RecognizeResultForm(QWidget *parent = nullptr); + ~RecognizeResultForm(); + +public slots: + void showRecogFailure(); + void showRecognizeResult(QString personId); + + void startWorkingRecognize(); // 开始工作 + void drawImageOnHomeForm(QImage imageDisp); + +private: + Ui::RecognizeResultForm *ui; + +}; + +#endif // RECOGNIZERESULTFORM_H diff --git a/RecognizeResultForm.ui b/RecognizeResultForm.ui new file mode 100644 index 0000000..9d08547 --- /dev/null +++ b/RecognizeResultForm.ui @@ -0,0 +1,212 @@ + + + RecognizeResultForm + + + + 0 + 0 + 1280 + 800 + + + + Form + + + + + 0 + 0 + 1280 + 800 + + + + + + + :/images/bg_recognize_result.png + + + + + + 0 + 0 + 0 + 0 + + + + + + + Qt::AlignCenter + + + + + + 0 + 0 + 1280 + 90 + + + + + + + 人员识别 + + + Qt::AlignCenter + + + + + + 109 + 119 + 551 + 431 + + + + + + -110 + -70 + 280 + 380 + + + + :/images/photoFace.png + + + Qt::AlignCenter + + + + + + 240 + 220 + 54 + 12 + + + + TextLabel + + + + + + 240 + 10 + 54 + 12 + + + + TextLabel + + + + + + 240 + 160 + 54 + 12 + + + + TextLabel + + + + + + 240 + 90 + 54 + 12 + + + + TextLabel + + + + + + 440 + 260 + 54 + 12 + + + + TextLabel + + + + + + 430 + 130 + 54 + 12 + + + + TextLabel + + + + + + 440 + 200 + 54 + 12 + + + + TextLabel + + + + + + 430 + 50 + 54 + 12 + + + + TextLabel + + + + + + + 550 + 470 + 120 + 80 + + + + + + + + + diff --git a/StartupForm.cpp b/StartupForm.cpp index af51bcc..c8b9c64 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -26,12 +26,13 @@ ui->hsMidd->changeSize(150, 0); // 初始化更新界面的定时器 - // 每分钟执行一次 + // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); - TimeCounterUtil::getInstance().clockCounter->setInterval(1000); - TimeCounterUtil::getInstance().clockCounter->start(); + TimeCounterUtil::getInstance().clockCounter->start(1000); } StartupForm::~StartupForm() @@ -45,6 +46,30 @@ ui->labDate->setText(QDate::currentDate().toString("yyyy-MM-dd")); } +void StartupForm::takeOneFrameForCheckStatus() +{ + if (ProMemory::getInstance().appState != CasicBioRecConst::ApplicationState::STATE_WAIT) + { + // 非待机状态直接返回 + return; + } + + cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); + bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + if (hasFace == true) + { + LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; + + // 启动识别线程 + // 槽函数 CasicBioRecWin::switchToRecognizeForm + emit startRecognize(); + + // 退出 + return ; + } +} + void StartupForm::on_btnUser_clicked() { emit switchToUserListForm(); diff --git a/StartupForm.h b/StartupForm.h index 6aed14d..f2850e9 100644 --- a/StartupForm.h +++ b/StartupForm.h @@ -4,9 +4,10 @@ #include #include #include +#include -#include "utils/SettingConfig.h" -#include "utils/TimeCounterUtil.h" +#include "casic/ProMemory.h" +#include "utils/UtilInclude.h" namespace Ui { class StartupForm; @@ -25,12 +26,15 @@ private slots: void updateDateAndTime(); + void takeOneFrameForCheckStatus(); void on_btnUser_clicked(); void on_btnSetting_clicked(); signals: void switchToUserListForm(); void switchToSettingForm(); + + void startRecognize(); }; #endif // STARTUPFORM_H diff --git a/casic/CasicBioRecConst.h b/casic/CasicBioRecConst.h index f55c84f..78d150b 100644 --- a/casic/CasicBioRecConst.h +++ b/casic/CasicBioRecConst.h @@ -12,7 +12,13 @@ ADD_PERSON_CAPTURE_FACE = 21, // 添加/编辑人员时进行人脸拍图 ADD_PERSON_CAPTURE_IRIS = 22, // 添加/编辑人员时进行虹膜拍图 SETTING_FORM = 3, // 设置页面 - RECOGNIZE_SUCCESS_FORM = 4 // 识别成功界面 + RECOGNIZE_RESULT_FORM = 4 // 识别结果界面 + }; + + enum ApplicationState + { + STATE_WAIT = 0, // 待机 + STATE_WORKING = 1, // 工作状态 }; }; diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 33010d2..6454343 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -12,9 +12,11 @@ #include "device/FaceCameraController.h" #include "device/face/FaceDetectRegistProcess.h" +#include "device/face/FaceDetectRecogProcess.h" class FaceCameraController; class FaceDetectRegistProcess; +class FaceDetectRecogProcess; class ProMemory { @@ -41,7 +43,8 @@ bool isIrisQueueEmpty(); void clearIrisQueue(); - volatile int widgeFrame; + volatile int widgeFrame = 0; // 当前显示的界面 + volatile int appState = 0; // 当前程序所处的状态 QString capFaceOrIris; // 注册虹膜或者人脸 void initFaceFeatures(); // 初始化人脸特征值集合 @@ -51,6 +54,8 @@ FaceCameraController * faceCam; FaceDetectRegistProcess * faceRegistPro; + FaceDetectRecogProcess * faceRecogPro; + private: ProMemory(); diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index 5e09b86..cb4d3bd 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -402,6 +402,42 @@ return rect.at(0); } +bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} +bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) +{ + // 构建openCV自带的眼睛分类器 + if (this->eyeCascade == nullptr) + { + this->eyeCascade = new cv::CascadeClassifier(); + this->eyeCascade->load(cvEyeCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minEyeSize, minEyeSize); + cv::Size maxRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + eyeCascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} + void casic::face::CasicFaceInterface::setMinFaceSize(int minFaceSize) { this->minFaceSize = minFaceSize; diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index d6d4494..8a1c564 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -50,6 +50,8 @@ cv::Rect faceDetectByCVCascade(cv::Mat frame); cv::Rect eyeDetectByCVCascade(cv::Mat frame); + bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); + bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); private: diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 5f0e2ae..493fdb7 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -6,7 +6,18 @@ FaceCameraController::FaceCameraController(QObject *parent) : QObject(parent) { + this->faceCap = new cv::VideoCapture(SettingConfig::getInstance().FACE_CAMERA_INDEX, cv::CAP_DSHOW); + faceCap->set(cv::CAP_PROP_FRAME_WIDTH, SettingConfig::getInstance().FACE_FRAME_WIDTH); + faceCap->set(cv::CAP_PROP_FRAME_HEIGHT, SettingConfig::getInstance().FACE_FRAME_HEIGHT); + LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]初始化相机[%1][%2 * %3]") + .arg(SettingConfig::getInstance().FACE_CAMERA_INDEX) + .arg(SettingConfig::getInstance().FACE_FRAME_WIDTH) + .arg(SettingConfig::getInstance().FACE_FRAME_HEIGHT).toStdString(); + + // 获取定时器, 绑定定时函数 + connect(TimeCounterUtil::getInstance().faceCapCounter, &QTimer::timeout, + this, &FaceCameraController::getOneFaceFrm); } FaceCameraController::~FaceCameraController() @@ -15,25 +26,11 @@ } -void FaceCameraController::openFaceCamera() +void FaceCameraController::openFaceCamera(int mInterval) { - // 获取定时器, 绑定定时函数 - connect(TimeCounterUtil::getInstance().faceCapCounter, &QTimer::timeout, - this, &FaceCameraController::getOneFaceFrm); - - this->faceCap = new cv::VideoCapture(SettingConfig::getInstance().FACE_CAMERA_INDEX, cv::CAP_DSHOW); - faceCap->set(cv::CAP_PROP_FRAME_WIDTH, SettingConfig::getInstance().FACE_FRAME_WIDTH); - faceCap->set(cv::CAP_PROP_FRAME_HEIGHT, SettingConfig::getInstance().FACE_FRAME_HEIGHT); - - LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]打开相机[%1][%2 * %3]") - .arg(SettingConfig::getInstance().FACE_CAMERA_INDEX) - .arg(SettingConfig::getInstance().FACE_FRAME_WIDTH) - .arg(SettingConfig::getInstance().FACE_FRAME_HEIGHT).toStdString(); - // 启动定时器 - TimeCounterUtil::getInstance().faceCapCounter->start(SettingConfig::getInstance().FACE_FRAME_INTERVAL); - LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]相机开始拍图[%1ms]") - .arg(SettingConfig::getInstance().FACE_FRAME_INTERVAL).toStdString(); + TimeCounterUtil::getInstance().faceCapCounter->start(mInterval); + LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]相机开始拍图[%1ms]").arg(mInterval).toStdString(); } void FaceCameraController::stopTakingPhoto() @@ -87,5 +84,39 @@ // 发送信号用于界面显示 emit sendImageToDraw(imgDisplay); + } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM) + { + // 拍图 + faceCap->read(faceMat); + + LOG(TRACE) << "TAKE ONE FACE FRAME " << faceMat.cols << " * " << faceMat.rows; + + // 左右翻转 + cv::Mat imageMatMiir; + flip(faceMat, imageMatMiir, 1); + + // clone一个mat, 用于界面显示 + cv::Mat faceMatDisp = imageMatMiir.clone(); + + CasicFaceInfo faceInfo; + faceInfo.hasFace = false; + faceInfo.matData = imageMatMiir; + + // 将图片数据压入堆栈 + ProMemory::getInstance().pushCasicFace(faceInfo); + + // 将mat转成QImage + QImage imgDisplay = ImageUtil::MatImageToQImage(faceMatDisp); + + // 发送信号用于界面显示 + emit sendImageToDrawForRecognize(imgDisplay); } } + +cv::Mat FaceCameraController::takeOneRawFrame() +{ + // 拍图 + cv::Mat camMat; + faceCap->read(camMat); + return camMat; +} diff --git a/device/FaceCameraController.h b/device/FaceCameraController.h index 6570cfb..b6dfd61 100644 --- a/device/FaceCameraController.h +++ b/device/FaceCameraController.h @@ -6,9 +6,6 @@ #include "opencv2/opencv.hpp" #include "casic/ProMemory.h" -//#include "casic/face/CasicFaceInterface.h" -//#include "process/memory/ProMemory.h" -//#include "process/face/CasicFaceRecState.h" #include "utils/ImageUtil.h" #include "utils/SettingConfig.h" #include "utils/TimeCounterUtil.h" @@ -22,7 +19,8 @@ ~FaceCameraController(); // 初始化并打开人脸相机 - void openFaceCamera(); + void openFaceCamera(int mInterval); + cv::Mat takeOneRawFrame(); void stopTakingPhoto(); void closeFaceCamera(); @@ -36,6 +34,7 @@ signals: void sendImageToDraw(QImage imageDisp); + void sendImageToDrawForRecognize(QImage imageDisp); void sendImageToDetect(cv::Mat imgMat); }; diff --git a/device/device.pri b/device/device.pri index 71d9dfa..274ba60 100644 --- a/device/device.pri +++ b/device/device.pri @@ -1,10 +1,12 @@ HEADERS += $$PWD/FaceCameraController.h HEADERS += $$PWD/face/FaceDetectRegistProcess.h +HEADERS += $$PWD/face/FaceDetectRecogProcess.h HEADERS += $$PWD/face/CasicFaceRecState.h SOURCES += $$PWD/FaceCameraController.cpp SOURCES += $$PWD/face/FaceDetectRegistProcess.cpp +SOURCES += $$PWD/face/FaceDetectRecogProcess.cpp SOURCES += $$PWD/face/CasicFaceRecState.cpp #HEADERS += $$PWD/IrisCameraController.h diff --git a/device/face/FaceDetectRecogProcess.cpp b/device/face/FaceDetectRecogProcess.cpp new file mode 100644 index 0000000..00e45ff --- /dev/null +++ b/device/face/FaceDetectRecogProcess.cpp @@ -0,0 +1,198 @@ +#include "FaceDetectRecogProcess.h" + +FaceDetectRecogProcess::FaceDetectRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; +} + +FaceDetectRecogProcess::~FaceDetectRecogProcess() +{ + this->setWorking(false); +} + +void FaceDetectRecogProcess::setWorking(bool working) +{ + this->working = working; +} +void FaceDetectRecogProcess::exitThread() +{ + this->exit = true; +} +void FaceDetectRecogProcess::startThread() +{ + this->exit = false; + this->start(); +} + +void FaceDetectRecogProcess::addOneTryCount() +{ + LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); + if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) + { + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + } else + { + CasicFaceRecState::getInstance().tryCount = 0; + CasicFaceRecState::getInstance().noFaceCount = 0; + emit matchFailure(); + + this->setWorking(false); // 返回后则线程暂停工作 + } +} + +void FaceDetectRecogProcess::addOneNoFaceCount() +{ + CasicFaceRecState::getInstance().noFaceCount++; + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) + { + CasicFaceRecState::getInstance().noFaceCount = 0; + emit matchFailure(); + + this->setWorking(false); // 返回后则暂停工作 + } +} + +void FaceDetectRecogProcess::run() +{ + while (exit == false) + { + if (this->working == false) + { + this->msleep(100); // 100ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isFaceQueueEmpty() == true) + { + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) + { + LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 取出人脸图像栈中的一条数据 + CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); + + // 调用人脸检测算法 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); + + // 没有找到人脸则返回 + if (faceInfo.hasFace == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 找到人脸则开始一次识别 + if (CasicFaceRecState::getInstance().recoginzeId == "0") + { + CasicFaceRecState::getInstance().initRecognize(); + } + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 + CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 + + // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 + casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); + faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); + + // 活体检测判断为假脸 + if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) + { + // 表示本次识别结束, 可以开始下一次识别过程 + LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); + + addOneTryCount(); // 判断是否超过次数, 重置识别状态 + this->msleep(200); // 200ms后再判断 + continue; + } + + // 设置识别状态值=通过活体检测 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; + + // 调用算法提取特征值, 1024个字节的float数组 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); + + // 设置识别状态值=特征值提取 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + + LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + this->setWorking(false); + // 特征值提取成功的人脸 与人脸库中的人脸进行比较 + compareFaceInCollection(); + } +} + +void FaceDetectRecogProcess::compareFaceInCollection() +{ + ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 + QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); + for (int i = 0; i < faceFeatures.size(); i++) + { + QVariantMap ffMap = faceFeatures.at(i); + + QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); + float ffArr[1024]; + for (int i = 0; i < 1024; i++) + { + QByteArray tempBa; + tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); + ffArr[i] = ByteUtil::binToFloat(tempBa); + } + + float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); + + LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); + if (sim > 0.62) + { + CasicFaceRecState::getInstance().faceInfo->sim = sim; + CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); + CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; + + // 找到匹配的人脸图像 + this->afterRecogAction(ffMap.value("person_id").toString()); + return ; + } + } + + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + this->addOneTryCount(); +} + +void FaceDetectRecogProcess::afterRecogAction(QString personId) +{ + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + + LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + // 发送信号, 在主界面上显示 + emit matchSuccess(personId); +} + diff --git a/device/face/FaceDetectRecogProcess.h b/device/face/FaceDetectRecogProcess.h new file mode 100644 index 0000000..b1051b7 --- /dev/null +++ b/device/face/FaceDetectRecogProcess.h @@ -0,0 +1,50 @@ +#ifndef FACEDETECTRECOGPROCESS_H +#define FACEDETECTRECOGPROCESS_H + +#include +#include +#include "opencv2/opencv.hpp" + +#include "dao/RecognitionRecordDao.h" + +#include "utils/easyloggingpp/easylogging++.h" +#include "utils/ImageUtil.h" +#include "utils/SettingConfig.h" +#include "utils/ByteUtil.h" + +#include "CasicFaceRecState.h" +#include "casic/ProMemory.h" +#include "casic/face/CasicFaceInterface.h" + +class FaceDetectRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit FaceDetectRecogProcess(QObject *parent = nullptr); + ~FaceDetectRecogProcess(); + + void setWorking(bool working); + void exitThread(); + void startThread(); + + void addOneTryCount(); + void addOneNoFaceCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + void compareFaceInCollection(); + void afterRecogAction(QString personId); + + volatile bool working; + volatile bool exit; + +signals: + void matchSuccess(QString personId); // 匹配成功 + void matchFailure(); // 匹配失败 + +}; + +#endif // FACEDETECTRECOGPROCESS_H diff --git a/device/face/FaceDetectRegistProcess.h b/device/face/FaceDetectRegistProcess.h index 9ffa91d..99a504c 100644 --- a/device/face/FaceDetectRegistProcess.h +++ b/device/face/FaceDetectRegistProcess.h @@ -14,8 +14,6 @@ #include "casic/ProMemory.h" #include "casic/face/CasicFaceInterface.h" -static bool FACE_DETECT_FLAG = false; - class FaceDetectRegistProcess : public QThread { Q_OBJECT @@ -40,10 +38,8 @@ volatile bool exit; signals: - void extractFeatureSuccess(); void failedCaptureFace(); void successCaptureFace(QString personIdByFace); - void findSimFace(QString personId); }; diff --git a/images/bg_recognize_result.png b/images/bg_recognize_result.png new file mode 100644 index 0000000..068b55b --- /dev/null +++ b/images/bg_recognize_result.png Binary files differ diff --git a/images/bg_video.png b/images/bg_video.png new file mode 100644 index 0000000..3ed9dae --- /dev/null +++ b/images/bg_video.png Binary files differ diff --git a/qss/recognize.css b/qss/recognize.css new file mode 100644 index 0000000..9c9b4d6 --- /dev/null +++ b/qss/recognize.css @@ -0,0 +1,20 @@ +QLabel { + color: #6868A6; + font-family: "Microsoft YaHei"; +} + +QLabel#labDate { + font-size: 36px; +} + +QLabel#labTime { + font-size: 100px; +} + +QToolButton { + color: #6868A6; + font-family: "Microsoft YaHei"; + font-size: 48px; + background: transparent; + border-style: none; +} diff --git a/resource.qrc b/resource.qrc index 1d26f80..b63a46b 100644 --- a/resource.qrc +++ b/resource.qrc @@ -22,5 +22,7 @@ images/tipsFailure.png images/tipsSuccess.png images/tipsConfirm.png + images/bg_recognize_result.png + images/bg_video.png diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index fe3819d..934dfad 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -1,7 +1,5 @@ #include "CasicBioRecWin.h" #include "ui_CasicBioRecWin.h" -#include -#include CasicBioRecWin::CasicBioRecWin(QWidget *parent) : QMainWindow(parent) @@ -26,11 +24,15 @@ // 初始化识别和注册的各个线程 initFaceRegistThread(); // 人脸注册线程 + initFaceRecogThread(); // 人脸识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); + ProMemory::getInstance().faceCam->openFaceCamera(1000); connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDraw, addPersonForm, &AddPersonForm::drawImageOnForm); + connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDrawForRecognize, + recogResultForm, &RecognizeResultForm::drawImageOnHomeForm); // 打印日志 LOG(INFO) << QString("应用程序启动成功[Application Startup Success]").toStdString(); @@ -43,8 +45,13 @@ ProMemory::getInstance().faceRegistPro->deleteLater(); ProMemory::getInstance().faceRegistPro->wait(); + ProMemory::getInstance().faceRecogPro->exitThread(); + ProMemory::getInstance().faceRecogPro->deleteLater(); + ProMemory::getInstance().faceRecogPro->wait(); + delete ui; delete ProMemory::getInstance().faceRegistPro; + delete ProMemory::getInstance().faceRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -94,6 +101,13 @@ ui->stacked->setCurrentWidget(addPersonForm); ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::ADD_PERSON_FORM; } +void CasicBioRecWin::switchToRecognizeForm() +{ + ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM; + ui->stacked->setCurrentWidget(recogResultForm); + + recogResultForm->startWorkingRecognize(); +} void CasicBioRecWin::initFormsPtr() { @@ -101,18 +115,21 @@ personListForm = new PersonListForm(this); settingForm = new SettingForm(this); addPersonForm = new AddPersonForm(this); + recogResultForm = new RecognizeResultForm(this); ui->stacked->addWidget(startForm); ui->stacked->addWidget(personListForm); ui->stacked->addWidget(settingForm); ui->stacked->addWidget(addPersonForm); - + ui->stacked->addWidget(recogResultForm); // 绑定按钮函数 connect(startForm, &StartupForm::switchToUserListForm, this, &CasicBioRecWin::switchToUserListForm); connect(startForm, &StartupForm::switchToSettingForm, this, &CasicBioRecWin::switchToSettingForm); + connect(startForm, &StartupForm::startRecognize, + this, &CasicBioRecWin::switchToRecognizeForm); connect(personListForm, &PersonListForm::switchToRegistForm, this, &CasicBioRecWin::switchToRegistForm); @@ -146,3 +163,20 @@ ProMemory::getInstance().faceRegistPro->start(); } + +void CasicBioRecWin::initFaceRecogThread() +{ + // 人脸识别处理过程 + ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().faceRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index 3e706fe..f0b47bf 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -2,19 +2,20 @@ #define CASICBIORECWIN_H #include +#include +#include #include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SettingConfig.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" #include "StartupForm.h" #include "PersonListForm.h" #include "SettingForm.h" #include "AddPersonForm.h" +#include "RecognizeResultForm.h" #include "device/FaceCameraController.h" -#include "device/face/FaceDetectRegistProcess.h" QT_BEGIN_NAMESPACE namespace Ui { class CasicBioRecWin; } @@ -33,6 +34,7 @@ void switchToUserListForm(); void switchToSettingForm(); void switchToRegistForm(QString personId); + void switchToRecognizeForm(); private: Ui::CasicBioRecWin *ui; @@ -41,11 +43,13 @@ PersonListForm * personListForm; SettingForm * settingForm; AddPersonForm * addPersonForm; + RecognizeResultForm * recogResultForm; void keyPressEvent(QKeyEvent *event); void initFormsPtr(); void initCacheData(); void initFaceRegistThread(); + void initFaceRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/PersonListForm.h b/PersonListForm.h index db352c6..65bd3f5 100644 --- a/PersonListForm.h +++ b/PersonListForm.h @@ -7,7 +7,7 @@ #include "ConfirmTipsDialog.h" #include "OperationTipsDialog.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" +#include "utils/UtilInclude.h" namespace Ui { class PersonListForm; diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp new file mode 100644 index 0000000..b6790a9 --- /dev/null +++ b/RecognizeResultForm.cpp @@ -0,0 +1,60 @@ +#include "RecognizeResultForm.h" +#include "ui_RecognizeResultForm.h" + +RecognizeResultForm::RecognizeResultForm(QWidget *parent) : + QWidget(parent), + ui(new Ui::RecognizeResultForm) +{ + ui->setupUi(this); + ui->labVideo->hide(); + + // 加载css文件设置控件样式 + QFile file(QApplication::applicationDirPath() + "/qss/recognize.css"); + if (file.open(QFile::ReadOnly)) + { + QString qssStr = QLatin1String(file.readAll()); + this->setStyleSheet(qssStr); + file.close(); + } +} + +RecognizeResultForm::~RecognizeResultForm() +{ + delete ui; +} + +void RecognizeResultForm::startWorkingRecognize() +{ + // 开始人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + + // 将界面切换到识别界面 RecognizeResultForm + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + + // 1人脸图像显示的容器 + ui->labVideo->resize(1060, 607); + ui->labVideo->move(110, 100); + ui->labVideo->raise(); + ui->labVideo->show(); +} + + +void RecognizeResultForm::drawImageOnHomeForm(QImage imageDisp) +{ + if (ui->labVideo->isVisible() == true) + { + LOG(TRACE) << "DRAW IMAGE ON FORM " << imageDisp.width() << "*" << imageDisp.height(); + imageDisp = imageDisp.scaled(1040, 585); + ui->labVideo->setPixmap(QPixmap::fromImage(imageDisp)); + } +} + +void RecognizeResultForm::showRecogFailure() +{ + +} +void RecognizeResultForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功"); +// ui->labVideo->hide(); +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h new file mode 100644 index 0000000..3be5410 --- /dev/null +++ b/RecognizeResultForm.h @@ -0,0 +1,34 @@ +#ifndef RECOGNIZERESULTFORM_H +#define RECOGNIZERESULTFORM_H + +#include + +#include "utils/UtilInclude.h" + +#include "casic/ProMemory.h" + +namespace Ui { +class RecognizeResultForm; +} + +class RecognizeResultForm : public QWidget +{ + Q_OBJECT + +public: + explicit RecognizeResultForm(QWidget *parent = nullptr); + ~RecognizeResultForm(); + +public slots: + void showRecogFailure(); + void showRecognizeResult(QString personId); + + void startWorkingRecognize(); // 开始工作 + void drawImageOnHomeForm(QImage imageDisp); + +private: + Ui::RecognizeResultForm *ui; + +}; + +#endif // RECOGNIZERESULTFORM_H diff --git a/RecognizeResultForm.ui b/RecognizeResultForm.ui new file mode 100644 index 0000000..9d08547 --- /dev/null +++ b/RecognizeResultForm.ui @@ -0,0 +1,212 @@ + + + RecognizeResultForm + + + + 0 + 0 + 1280 + 800 + + + + Form + + + + + 0 + 0 + 1280 + 800 + + + + + + + :/images/bg_recognize_result.png + + + + + + 0 + 0 + 0 + 0 + + + + + + + Qt::AlignCenter + + + + + + 0 + 0 + 1280 + 90 + + + + + + + 人员识别 + + + Qt::AlignCenter + + + + + + 109 + 119 + 551 + 431 + + + + + + -110 + -70 + 280 + 380 + + + + :/images/photoFace.png + + + Qt::AlignCenter + + + + + + 240 + 220 + 54 + 12 + + + + TextLabel + + + + + + 240 + 10 + 54 + 12 + + + + TextLabel + + + + + + 240 + 160 + 54 + 12 + + + + TextLabel + + + + + + 240 + 90 + 54 + 12 + + + + TextLabel + + + + + + 440 + 260 + 54 + 12 + + + + TextLabel + + + + + + 430 + 130 + 54 + 12 + + + + TextLabel + + + + + + 440 + 200 + 54 + 12 + + + + TextLabel + + + + + + 430 + 50 + 54 + 12 + + + + TextLabel + + + + + + + 550 + 470 + 120 + 80 + + + + + + + + + diff --git a/StartupForm.cpp b/StartupForm.cpp index af51bcc..c8b9c64 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -26,12 +26,13 @@ ui->hsMidd->changeSize(150, 0); // 初始化更新界面的定时器 - // 每分钟执行一次 + // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); - TimeCounterUtil::getInstance().clockCounter->setInterval(1000); - TimeCounterUtil::getInstance().clockCounter->start(); + TimeCounterUtil::getInstance().clockCounter->start(1000); } StartupForm::~StartupForm() @@ -45,6 +46,30 @@ ui->labDate->setText(QDate::currentDate().toString("yyyy-MM-dd")); } +void StartupForm::takeOneFrameForCheckStatus() +{ + if (ProMemory::getInstance().appState != CasicBioRecConst::ApplicationState::STATE_WAIT) + { + // 非待机状态直接返回 + return; + } + + cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); + bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + if (hasFace == true) + { + LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; + + // 启动识别线程 + // 槽函数 CasicBioRecWin::switchToRecognizeForm + emit startRecognize(); + + // 退出 + return ; + } +} + void StartupForm::on_btnUser_clicked() { emit switchToUserListForm(); diff --git a/StartupForm.h b/StartupForm.h index 6aed14d..f2850e9 100644 --- a/StartupForm.h +++ b/StartupForm.h @@ -4,9 +4,10 @@ #include #include #include +#include -#include "utils/SettingConfig.h" -#include "utils/TimeCounterUtil.h" +#include "casic/ProMemory.h" +#include "utils/UtilInclude.h" namespace Ui { class StartupForm; @@ -25,12 +26,15 @@ private slots: void updateDateAndTime(); + void takeOneFrameForCheckStatus(); void on_btnUser_clicked(); void on_btnSetting_clicked(); signals: void switchToUserListForm(); void switchToSettingForm(); + + void startRecognize(); }; #endif // STARTUPFORM_H diff --git a/casic/CasicBioRecConst.h b/casic/CasicBioRecConst.h index f55c84f..78d150b 100644 --- a/casic/CasicBioRecConst.h +++ b/casic/CasicBioRecConst.h @@ -12,7 +12,13 @@ ADD_PERSON_CAPTURE_FACE = 21, // 添加/编辑人员时进行人脸拍图 ADD_PERSON_CAPTURE_IRIS = 22, // 添加/编辑人员时进行虹膜拍图 SETTING_FORM = 3, // 设置页面 - RECOGNIZE_SUCCESS_FORM = 4 // 识别成功界面 + RECOGNIZE_RESULT_FORM = 4 // 识别结果界面 + }; + + enum ApplicationState + { + STATE_WAIT = 0, // 待机 + STATE_WORKING = 1, // 工作状态 }; }; diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 33010d2..6454343 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -12,9 +12,11 @@ #include "device/FaceCameraController.h" #include "device/face/FaceDetectRegistProcess.h" +#include "device/face/FaceDetectRecogProcess.h" class FaceCameraController; class FaceDetectRegistProcess; +class FaceDetectRecogProcess; class ProMemory { @@ -41,7 +43,8 @@ bool isIrisQueueEmpty(); void clearIrisQueue(); - volatile int widgeFrame; + volatile int widgeFrame = 0; // 当前显示的界面 + volatile int appState = 0; // 当前程序所处的状态 QString capFaceOrIris; // 注册虹膜或者人脸 void initFaceFeatures(); // 初始化人脸特征值集合 @@ -51,6 +54,8 @@ FaceCameraController * faceCam; FaceDetectRegistProcess * faceRegistPro; + FaceDetectRecogProcess * faceRecogPro; + private: ProMemory(); diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index 5e09b86..cb4d3bd 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -402,6 +402,42 @@ return rect.at(0); } +bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} +bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) +{ + // 构建openCV自带的眼睛分类器 + if (this->eyeCascade == nullptr) + { + this->eyeCascade = new cv::CascadeClassifier(); + this->eyeCascade->load(cvEyeCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minEyeSize, minEyeSize); + cv::Size maxRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + eyeCascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} + void casic::face::CasicFaceInterface::setMinFaceSize(int minFaceSize) { this->minFaceSize = minFaceSize; diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index d6d4494..8a1c564 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -50,6 +50,8 @@ cv::Rect faceDetectByCVCascade(cv::Mat frame); cv::Rect eyeDetectByCVCascade(cv::Mat frame); + bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); + bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); private: diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 5f0e2ae..493fdb7 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -6,7 +6,18 @@ FaceCameraController::FaceCameraController(QObject *parent) : QObject(parent) { + this->faceCap = new cv::VideoCapture(SettingConfig::getInstance().FACE_CAMERA_INDEX, cv::CAP_DSHOW); + faceCap->set(cv::CAP_PROP_FRAME_WIDTH, SettingConfig::getInstance().FACE_FRAME_WIDTH); + faceCap->set(cv::CAP_PROP_FRAME_HEIGHT, SettingConfig::getInstance().FACE_FRAME_HEIGHT); + LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]初始化相机[%1][%2 * %3]") + .arg(SettingConfig::getInstance().FACE_CAMERA_INDEX) + .arg(SettingConfig::getInstance().FACE_FRAME_WIDTH) + .arg(SettingConfig::getInstance().FACE_FRAME_HEIGHT).toStdString(); + + // 获取定时器, 绑定定时函数 + connect(TimeCounterUtil::getInstance().faceCapCounter, &QTimer::timeout, + this, &FaceCameraController::getOneFaceFrm); } FaceCameraController::~FaceCameraController() @@ -15,25 +26,11 @@ } -void FaceCameraController::openFaceCamera() +void FaceCameraController::openFaceCamera(int mInterval) { - // 获取定时器, 绑定定时函数 - connect(TimeCounterUtil::getInstance().faceCapCounter, &QTimer::timeout, - this, &FaceCameraController::getOneFaceFrm); - - this->faceCap = new cv::VideoCapture(SettingConfig::getInstance().FACE_CAMERA_INDEX, cv::CAP_DSHOW); - faceCap->set(cv::CAP_PROP_FRAME_WIDTH, SettingConfig::getInstance().FACE_FRAME_WIDTH); - faceCap->set(cv::CAP_PROP_FRAME_HEIGHT, SettingConfig::getInstance().FACE_FRAME_HEIGHT); - - LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]打开相机[%1][%2 * %3]") - .arg(SettingConfig::getInstance().FACE_CAMERA_INDEX) - .arg(SettingConfig::getInstance().FACE_FRAME_WIDTH) - .arg(SettingConfig::getInstance().FACE_FRAME_HEIGHT).toStdString(); - // 启动定时器 - TimeCounterUtil::getInstance().faceCapCounter->start(SettingConfig::getInstance().FACE_FRAME_INTERVAL); - LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]相机开始拍图[%1ms]") - .arg(SettingConfig::getInstance().FACE_FRAME_INTERVAL).toStdString(); + TimeCounterUtil::getInstance().faceCapCounter->start(mInterval); + LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]相机开始拍图[%1ms]").arg(mInterval).toStdString(); } void FaceCameraController::stopTakingPhoto() @@ -87,5 +84,39 @@ // 发送信号用于界面显示 emit sendImageToDraw(imgDisplay); + } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM) + { + // 拍图 + faceCap->read(faceMat); + + LOG(TRACE) << "TAKE ONE FACE FRAME " << faceMat.cols << " * " << faceMat.rows; + + // 左右翻转 + cv::Mat imageMatMiir; + flip(faceMat, imageMatMiir, 1); + + // clone一个mat, 用于界面显示 + cv::Mat faceMatDisp = imageMatMiir.clone(); + + CasicFaceInfo faceInfo; + faceInfo.hasFace = false; + faceInfo.matData = imageMatMiir; + + // 将图片数据压入堆栈 + ProMemory::getInstance().pushCasicFace(faceInfo); + + // 将mat转成QImage + QImage imgDisplay = ImageUtil::MatImageToQImage(faceMatDisp); + + // 发送信号用于界面显示 + emit sendImageToDrawForRecognize(imgDisplay); } } + +cv::Mat FaceCameraController::takeOneRawFrame() +{ + // 拍图 + cv::Mat camMat; + faceCap->read(camMat); + return camMat; +} diff --git a/device/FaceCameraController.h b/device/FaceCameraController.h index 6570cfb..b6dfd61 100644 --- a/device/FaceCameraController.h +++ b/device/FaceCameraController.h @@ -6,9 +6,6 @@ #include "opencv2/opencv.hpp" #include "casic/ProMemory.h" -//#include "casic/face/CasicFaceInterface.h" -//#include "process/memory/ProMemory.h" -//#include "process/face/CasicFaceRecState.h" #include "utils/ImageUtil.h" #include "utils/SettingConfig.h" #include "utils/TimeCounterUtil.h" @@ -22,7 +19,8 @@ ~FaceCameraController(); // 初始化并打开人脸相机 - void openFaceCamera(); + void openFaceCamera(int mInterval); + cv::Mat takeOneRawFrame(); void stopTakingPhoto(); void closeFaceCamera(); @@ -36,6 +34,7 @@ signals: void sendImageToDraw(QImage imageDisp); + void sendImageToDrawForRecognize(QImage imageDisp); void sendImageToDetect(cv::Mat imgMat); }; diff --git a/device/device.pri b/device/device.pri index 71d9dfa..274ba60 100644 --- a/device/device.pri +++ b/device/device.pri @@ -1,10 +1,12 @@ HEADERS += $$PWD/FaceCameraController.h HEADERS += $$PWD/face/FaceDetectRegistProcess.h +HEADERS += $$PWD/face/FaceDetectRecogProcess.h HEADERS += $$PWD/face/CasicFaceRecState.h SOURCES += $$PWD/FaceCameraController.cpp SOURCES += $$PWD/face/FaceDetectRegistProcess.cpp +SOURCES += $$PWD/face/FaceDetectRecogProcess.cpp SOURCES += $$PWD/face/CasicFaceRecState.cpp #HEADERS += $$PWD/IrisCameraController.h diff --git a/device/face/FaceDetectRecogProcess.cpp b/device/face/FaceDetectRecogProcess.cpp new file mode 100644 index 0000000..00e45ff --- /dev/null +++ b/device/face/FaceDetectRecogProcess.cpp @@ -0,0 +1,198 @@ +#include "FaceDetectRecogProcess.h" + +FaceDetectRecogProcess::FaceDetectRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; +} + +FaceDetectRecogProcess::~FaceDetectRecogProcess() +{ + this->setWorking(false); +} + +void FaceDetectRecogProcess::setWorking(bool working) +{ + this->working = working; +} +void FaceDetectRecogProcess::exitThread() +{ + this->exit = true; +} +void FaceDetectRecogProcess::startThread() +{ + this->exit = false; + this->start(); +} + +void FaceDetectRecogProcess::addOneTryCount() +{ + LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); + if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) + { + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + } else + { + CasicFaceRecState::getInstance().tryCount = 0; + CasicFaceRecState::getInstance().noFaceCount = 0; + emit matchFailure(); + + this->setWorking(false); // 返回后则线程暂停工作 + } +} + +void FaceDetectRecogProcess::addOneNoFaceCount() +{ + CasicFaceRecState::getInstance().noFaceCount++; + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) + { + CasicFaceRecState::getInstance().noFaceCount = 0; + emit matchFailure(); + + this->setWorking(false); // 返回后则暂停工作 + } +} + +void FaceDetectRecogProcess::run() +{ + while (exit == false) + { + if (this->working == false) + { + this->msleep(100); // 100ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isFaceQueueEmpty() == true) + { + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) + { + LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 取出人脸图像栈中的一条数据 + CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); + + // 调用人脸检测算法 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); + + // 没有找到人脸则返回 + if (faceInfo.hasFace == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 找到人脸则开始一次识别 + if (CasicFaceRecState::getInstance().recoginzeId == "0") + { + CasicFaceRecState::getInstance().initRecognize(); + } + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 + CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 + + // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 + casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); + faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); + + // 活体检测判断为假脸 + if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) + { + // 表示本次识别结束, 可以开始下一次识别过程 + LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); + + addOneTryCount(); // 判断是否超过次数, 重置识别状态 + this->msleep(200); // 200ms后再判断 + continue; + } + + // 设置识别状态值=通过活体检测 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; + + // 调用算法提取特征值, 1024个字节的float数组 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); + + // 设置识别状态值=特征值提取 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + + LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + this->setWorking(false); + // 特征值提取成功的人脸 与人脸库中的人脸进行比较 + compareFaceInCollection(); + } +} + +void FaceDetectRecogProcess::compareFaceInCollection() +{ + ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 + QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); + for (int i = 0; i < faceFeatures.size(); i++) + { + QVariantMap ffMap = faceFeatures.at(i); + + QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); + float ffArr[1024]; + for (int i = 0; i < 1024; i++) + { + QByteArray tempBa; + tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); + ffArr[i] = ByteUtil::binToFloat(tempBa); + } + + float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); + + LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); + if (sim > 0.62) + { + CasicFaceRecState::getInstance().faceInfo->sim = sim; + CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); + CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; + + // 找到匹配的人脸图像 + this->afterRecogAction(ffMap.value("person_id").toString()); + return ; + } + } + + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + this->addOneTryCount(); +} + +void FaceDetectRecogProcess::afterRecogAction(QString personId) +{ + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + + LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + // 发送信号, 在主界面上显示 + emit matchSuccess(personId); +} + diff --git a/device/face/FaceDetectRecogProcess.h b/device/face/FaceDetectRecogProcess.h new file mode 100644 index 0000000..b1051b7 --- /dev/null +++ b/device/face/FaceDetectRecogProcess.h @@ -0,0 +1,50 @@ +#ifndef FACEDETECTRECOGPROCESS_H +#define FACEDETECTRECOGPROCESS_H + +#include +#include +#include "opencv2/opencv.hpp" + +#include "dao/RecognitionRecordDao.h" + +#include "utils/easyloggingpp/easylogging++.h" +#include "utils/ImageUtil.h" +#include "utils/SettingConfig.h" +#include "utils/ByteUtil.h" + +#include "CasicFaceRecState.h" +#include "casic/ProMemory.h" +#include "casic/face/CasicFaceInterface.h" + +class FaceDetectRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit FaceDetectRecogProcess(QObject *parent = nullptr); + ~FaceDetectRecogProcess(); + + void setWorking(bool working); + void exitThread(); + void startThread(); + + void addOneTryCount(); + void addOneNoFaceCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + void compareFaceInCollection(); + void afterRecogAction(QString personId); + + volatile bool working; + volatile bool exit; + +signals: + void matchSuccess(QString personId); // 匹配成功 + void matchFailure(); // 匹配失败 + +}; + +#endif // FACEDETECTRECOGPROCESS_H diff --git a/device/face/FaceDetectRegistProcess.h b/device/face/FaceDetectRegistProcess.h index 9ffa91d..99a504c 100644 --- a/device/face/FaceDetectRegistProcess.h +++ b/device/face/FaceDetectRegistProcess.h @@ -14,8 +14,6 @@ #include "casic/ProMemory.h" #include "casic/face/CasicFaceInterface.h" -static bool FACE_DETECT_FLAG = false; - class FaceDetectRegistProcess : public QThread { Q_OBJECT @@ -40,10 +38,8 @@ volatile bool exit; signals: - void extractFeatureSuccess(); void failedCaptureFace(); void successCaptureFace(QString personIdByFace); - void findSimFace(QString personId); }; diff --git a/images/bg_recognize_result.png b/images/bg_recognize_result.png new file mode 100644 index 0000000..068b55b --- /dev/null +++ b/images/bg_recognize_result.png Binary files differ diff --git a/images/bg_video.png b/images/bg_video.png new file mode 100644 index 0000000..3ed9dae --- /dev/null +++ b/images/bg_video.png Binary files differ diff --git a/qss/recognize.css b/qss/recognize.css new file mode 100644 index 0000000..9c9b4d6 --- /dev/null +++ b/qss/recognize.css @@ -0,0 +1,20 @@ +QLabel { + color: #6868A6; + font-family: "Microsoft YaHei"; +} + +QLabel#labDate { + font-size: 36px; +} + +QLabel#labTime { + font-size: 100px; +} + +QToolButton { + color: #6868A6; + font-family: "Microsoft YaHei"; + font-size: 48px; + background: transparent; + border-style: none; +} diff --git a/resource.qrc b/resource.qrc index 1d26f80..b63a46b 100644 --- a/resource.qrc +++ b/resource.qrc @@ -22,5 +22,7 @@ images/tipsFailure.png images/tipsSuccess.png images/tipsConfirm.png + images/bg_recognize_result.png + images/bg_video.png diff --git a/utils/UtilInclude.h b/utils/UtilInclude.h new file mode 100644 index 0000000..f3ded58 --- /dev/null +++ b/utils/UtilInclude.h @@ -0,0 +1,12 @@ +#ifndef UTILINCLUDE_H +#define UTILINCLUDE_H + +#include "easyloggingpp/easylogging++.h" +#include "ByteUtil.h" +#include "ImageUtil.h" +#include "SelectDeptUtil.h" +#include "SettingConfig.h" +#include "SpeakerUtil.h" +#include "TimeCounterUtil.h" + +#endif // UTILINCLUDE_H diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index adbcaa8..86f0a73 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -1,6 +1,5 @@ #include "AddPersonForm.h" #include "ui_AddPersonForm.h" -#include "CasicBioRecWin.h" AddPersonForm::AddPersonForm(QWidget *parent) : QWidget(parent), @@ -455,7 +454,7 @@ void AddPersonForm::onPhotoFaceDoubleClicked() { - ProMemory::getInstance().faceCam->openFaceCamera(); + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); // 1人脸图像显示的容器 faceLabel->resize(1280, 720); diff --git a/AddPersonForm.h b/AddPersonForm.h index de41459..e552bdf 100644 --- a/AddPersonForm.h +++ b/AddPersonForm.h @@ -6,11 +6,10 @@ #include "QDblClickLabel.h" #include "OperationTipsDialog.h" + +#include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" -#include "utils/SettingConfig.h" -#include "utils/SpeakerUtil.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" namespace Ui { class AddPersonForm; diff --git a/CasicBioRecNew.pro b/CasicBioRecNew.pro index cd4a9bc..65f1946 100644 --- a/CasicBioRecNew.pro +++ b/CasicBioRecNew.pro @@ -28,6 +28,7 @@ SOURCES += AddPersonForm.cpp SOURCES += OperationTipsDialog.cpp SOURCES += ConfirmTipsDialog.cpp +SOURCES += RecognizeResultForm.cpp HEADERS += CasicBioRecWin.h HEADERS += StartupForm.h @@ -36,6 +37,7 @@ HEADERS += AddPersonForm.h HEADERS += OperationTipsDialog.h HEADERS += ConfirmTipsDialog.h +HEADERS += RecognizeResultForm.h HEADERS += $$PWD/QDblClickLabel.h SOURCES += $$PWD/QDblClickLabel.cpp @@ -47,6 +49,7 @@ FORMS += AddPersonForm.ui FORMS += OperationTipsDialog.ui FORMS += ConfirmTipsDialog.ui +FORMS += RecognizeResultForm.ui DISTFILES += conf/config.ini DISTFILES += conf/log.conf @@ -54,6 +57,7 @@ DISTFILES += qss/personList.css DISTFILES += qss/addPerson.css DISTFILES += qss/dialogTips.css +DISTFILES += qss/recognize.css RESOURCES += resource.qrc diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index fe3819d..934dfad 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -1,7 +1,5 @@ #include "CasicBioRecWin.h" #include "ui_CasicBioRecWin.h" -#include -#include CasicBioRecWin::CasicBioRecWin(QWidget *parent) : QMainWindow(parent) @@ -26,11 +24,15 @@ // 初始化识别和注册的各个线程 initFaceRegistThread(); // 人脸注册线程 + initFaceRecogThread(); // 人脸识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); + ProMemory::getInstance().faceCam->openFaceCamera(1000); connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDraw, addPersonForm, &AddPersonForm::drawImageOnForm); + connect(ProMemory::getInstance().faceCam, &FaceCameraController::sendImageToDrawForRecognize, + recogResultForm, &RecognizeResultForm::drawImageOnHomeForm); // 打印日志 LOG(INFO) << QString("应用程序启动成功[Application Startup Success]").toStdString(); @@ -43,8 +45,13 @@ ProMemory::getInstance().faceRegistPro->deleteLater(); ProMemory::getInstance().faceRegistPro->wait(); + ProMemory::getInstance().faceRecogPro->exitThread(); + ProMemory::getInstance().faceRecogPro->deleteLater(); + ProMemory::getInstance().faceRecogPro->wait(); + delete ui; delete ProMemory::getInstance().faceRegistPro; + delete ProMemory::getInstance().faceRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -94,6 +101,13 @@ ui->stacked->setCurrentWidget(addPersonForm); ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::ADD_PERSON_FORM; } +void CasicBioRecWin::switchToRecognizeForm() +{ + ProMemory::getInstance().widgeFrame = CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM; + ui->stacked->setCurrentWidget(recogResultForm); + + recogResultForm->startWorkingRecognize(); +} void CasicBioRecWin::initFormsPtr() { @@ -101,18 +115,21 @@ personListForm = new PersonListForm(this); settingForm = new SettingForm(this); addPersonForm = new AddPersonForm(this); + recogResultForm = new RecognizeResultForm(this); ui->stacked->addWidget(startForm); ui->stacked->addWidget(personListForm); ui->stacked->addWidget(settingForm); ui->stacked->addWidget(addPersonForm); - + ui->stacked->addWidget(recogResultForm); // 绑定按钮函数 connect(startForm, &StartupForm::switchToUserListForm, this, &CasicBioRecWin::switchToUserListForm); connect(startForm, &StartupForm::switchToSettingForm, this, &CasicBioRecWin::switchToSettingForm); + connect(startForm, &StartupForm::startRecognize, + this, &CasicBioRecWin::switchToRecognizeForm); connect(personListForm, &PersonListForm::switchToRegistForm, this, &CasicBioRecWin::switchToRegistForm); @@ -146,3 +163,20 @@ ProMemory::getInstance().faceRegistPro->start(); } + +void CasicBioRecWin::initFaceRecogThread() +{ + // 人脸识别处理过程 + ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().faceRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index 3e706fe..f0b47bf 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -2,19 +2,20 @@ #define CASICBIORECWIN_H #include +#include +#include #include "casic/ProMemory.h" #include "dao/util/CacheManager.h" -#include "utils/SettingConfig.h" -#include "utils/easyloggingpp/easylogging++.h" +#include "utils/UtilInclude.h" #include "StartupForm.h" #include "PersonListForm.h" #include "SettingForm.h" #include "AddPersonForm.h" +#include "RecognizeResultForm.h" #include "device/FaceCameraController.h" -#include "device/face/FaceDetectRegistProcess.h" QT_BEGIN_NAMESPACE namespace Ui { class CasicBioRecWin; } @@ -33,6 +34,7 @@ void switchToUserListForm(); void switchToSettingForm(); void switchToRegistForm(QString personId); + void switchToRecognizeForm(); private: Ui::CasicBioRecWin *ui; @@ -41,11 +43,13 @@ PersonListForm * personListForm; SettingForm * settingForm; AddPersonForm * addPersonForm; + RecognizeResultForm * recogResultForm; void keyPressEvent(QKeyEvent *event); void initFormsPtr(); void initCacheData(); void initFaceRegistThread(); + void initFaceRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/PersonListForm.h b/PersonListForm.h index db352c6..65bd3f5 100644 --- a/PersonListForm.h +++ b/PersonListForm.h @@ -7,7 +7,7 @@ #include "ConfirmTipsDialog.h" #include "OperationTipsDialog.h" #include "dao/util/CacheManager.h" -#include "utils/SelectDeptUtil.h" +#include "utils/UtilInclude.h" namespace Ui { class PersonListForm; diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp new file mode 100644 index 0000000..b6790a9 --- /dev/null +++ b/RecognizeResultForm.cpp @@ -0,0 +1,60 @@ +#include "RecognizeResultForm.h" +#include "ui_RecognizeResultForm.h" + +RecognizeResultForm::RecognizeResultForm(QWidget *parent) : + QWidget(parent), + ui(new Ui::RecognizeResultForm) +{ + ui->setupUi(this); + ui->labVideo->hide(); + + // 加载css文件设置控件样式 + QFile file(QApplication::applicationDirPath() + "/qss/recognize.css"); + if (file.open(QFile::ReadOnly)) + { + QString qssStr = QLatin1String(file.readAll()); + this->setStyleSheet(qssStr); + file.close(); + } +} + +RecognizeResultForm::~RecognizeResultForm() +{ + delete ui; +} + +void RecognizeResultForm::startWorkingRecognize() +{ + // 开始人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + + // 将界面切换到识别界面 RecognizeResultForm + ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + + // 1人脸图像显示的容器 + ui->labVideo->resize(1060, 607); + ui->labVideo->move(110, 100); + ui->labVideo->raise(); + ui->labVideo->show(); +} + + +void RecognizeResultForm::drawImageOnHomeForm(QImage imageDisp) +{ + if (ui->labVideo->isVisible() == true) + { + LOG(TRACE) << "DRAW IMAGE ON FORM " << imageDisp.width() << "*" << imageDisp.height(); + imageDisp = imageDisp.scaled(1040, 585); + ui->labVideo->setPixmap(QPixmap::fromImage(imageDisp)); + } +} + +void RecognizeResultForm::showRecogFailure() +{ + +} +void RecognizeResultForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功"); +// ui->labVideo->hide(); +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h new file mode 100644 index 0000000..3be5410 --- /dev/null +++ b/RecognizeResultForm.h @@ -0,0 +1,34 @@ +#ifndef RECOGNIZERESULTFORM_H +#define RECOGNIZERESULTFORM_H + +#include + +#include "utils/UtilInclude.h" + +#include "casic/ProMemory.h" + +namespace Ui { +class RecognizeResultForm; +} + +class RecognizeResultForm : public QWidget +{ + Q_OBJECT + +public: + explicit RecognizeResultForm(QWidget *parent = nullptr); + ~RecognizeResultForm(); + +public slots: + void showRecogFailure(); + void showRecognizeResult(QString personId); + + void startWorkingRecognize(); // 开始工作 + void drawImageOnHomeForm(QImage imageDisp); + +private: + Ui::RecognizeResultForm *ui; + +}; + +#endif // RECOGNIZERESULTFORM_H diff --git a/RecognizeResultForm.ui b/RecognizeResultForm.ui new file mode 100644 index 0000000..9d08547 --- /dev/null +++ b/RecognizeResultForm.ui @@ -0,0 +1,212 @@ + + + RecognizeResultForm + + + + 0 + 0 + 1280 + 800 + + + + Form + + + + + 0 + 0 + 1280 + 800 + + + + + + + :/images/bg_recognize_result.png + + + + + + 0 + 0 + 0 + 0 + + + + + + + Qt::AlignCenter + + + + + + 0 + 0 + 1280 + 90 + + + + + + + 人员识别 + + + Qt::AlignCenter + + + + + + 109 + 119 + 551 + 431 + + + + + + -110 + -70 + 280 + 380 + + + + :/images/photoFace.png + + + Qt::AlignCenter + + + + + + 240 + 220 + 54 + 12 + + + + TextLabel + + + + + + 240 + 10 + 54 + 12 + + + + TextLabel + + + + + + 240 + 160 + 54 + 12 + + + + TextLabel + + + + + + 240 + 90 + 54 + 12 + + + + TextLabel + + + + + + 440 + 260 + 54 + 12 + + + + TextLabel + + + + + + 430 + 130 + 54 + 12 + + + + TextLabel + + + + + + 440 + 200 + 54 + 12 + + + + TextLabel + + + + + + 430 + 50 + 54 + 12 + + + + TextLabel + + + + + + + 550 + 470 + 120 + 80 + + + + + + + + + diff --git a/StartupForm.cpp b/StartupForm.cpp index af51bcc..c8b9c64 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -26,12 +26,13 @@ ui->hsMidd->changeSize(150, 0); // 初始化更新界面的定时器 - // 每分钟执行一次 + // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); - TimeCounterUtil::getInstance().clockCounter->setInterval(1000); - TimeCounterUtil::getInstance().clockCounter->start(); + TimeCounterUtil::getInstance().clockCounter->start(1000); } StartupForm::~StartupForm() @@ -45,6 +46,30 @@ ui->labDate->setText(QDate::currentDate().toString("yyyy-MM-dd")); } +void StartupForm::takeOneFrameForCheckStatus() +{ + if (ProMemory::getInstance().appState != CasicBioRecConst::ApplicationState::STATE_WAIT) + { + // 非待机状态直接返回 + return; + } + + cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); + bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + if (hasFace == true) + { + LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; + + // 启动识别线程 + // 槽函数 CasicBioRecWin::switchToRecognizeForm + emit startRecognize(); + + // 退出 + return ; + } +} + void StartupForm::on_btnUser_clicked() { emit switchToUserListForm(); diff --git a/StartupForm.h b/StartupForm.h index 6aed14d..f2850e9 100644 --- a/StartupForm.h +++ b/StartupForm.h @@ -4,9 +4,10 @@ #include #include #include +#include -#include "utils/SettingConfig.h" -#include "utils/TimeCounterUtil.h" +#include "casic/ProMemory.h" +#include "utils/UtilInclude.h" namespace Ui { class StartupForm; @@ -25,12 +26,15 @@ private slots: void updateDateAndTime(); + void takeOneFrameForCheckStatus(); void on_btnUser_clicked(); void on_btnSetting_clicked(); signals: void switchToUserListForm(); void switchToSettingForm(); + + void startRecognize(); }; #endif // STARTUPFORM_H diff --git a/casic/CasicBioRecConst.h b/casic/CasicBioRecConst.h index f55c84f..78d150b 100644 --- a/casic/CasicBioRecConst.h +++ b/casic/CasicBioRecConst.h @@ -12,7 +12,13 @@ ADD_PERSON_CAPTURE_FACE = 21, // 添加/编辑人员时进行人脸拍图 ADD_PERSON_CAPTURE_IRIS = 22, // 添加/编辑人员时进行虹膜拍图 SETTING_FORM = 3, // 设置页面 - RECOGNIZE_SUCCESS_FORM = 4 // 识别成功界面 + RECOGNIZE_RESULT_FORM = 4 // 识别结果界面 + }; + + enum ApplicationState + { + STATE_WAIT = 0, // 待机 + STATE_WORKING = 1, // 工作状态 }; }; diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 33010d2..6454343 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -12,9 +12,11 @@ #include "device/FaceCameraController.h" #include "device/face/FaceDetectRegistProcess.h" +#include "device/face/FaceDetectRecogProcess.h" class FaceCameraController; class FaceDetectRegistProcess; +class FaceDetectRecogProcess; class ProMemory { @@ -41,7 +43,8 @@ bool isIrisQueueEmpty(); void clearIrisQueue(); - volatile int widgeFrame; + volatile int widgeFrame = 0; // 当前显示的界面 + volatile int appState = 0; // 当前程序所处的状态 QString capFaceOrIris; // 注册虹膜或者人脸 void initFaceFeatures(); // 初始化人脸特征值集合 @@ -51,6 +54,8 @@ FaceCameraController * faceCam; FaceDetectRegistProcess * faceRegistPro; + FaceDetectRecogProcess * faceRecogPro; + private: ProMemory(); diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index 5e09b86..cb4d3bd 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -402,6 +402,42 @@ return rect.at(0); } +bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} +bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) +{ + // 构建openCV自带的眼睛分类器 + if (this->eyeCascade == nullptr) + { + this->eyeCascade = new cv::CascadeClassifier(); + this->eyeCascade->load(cvEyeCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minEyeSize, minEyeSize); + cv::Size maxRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + eyeCascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + return rect.size() == 0 ? false : true; +} + void casic::face::CasicFaceInterface::setMinFaceSize(int minFaceSize) { this->minFaceSize = minFaceSize; diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index d6d4494..8a1c564 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -50,6 +50,8 @@ cv::Rect faceDetectByCVCascade(cv::Mat frame); cv::Rect eyeDetectByCVCascade(cv::Mat frame); + bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); + bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); private: diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 5f0e2ae..493fdb7 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -6,7 +6,18 @@ FaceCameraController::FaceCameraController(QObject *parent) : QObject(parent) { + this->faceCap = new cv::VideoCapture(SettingConfig::getInstance().FACE_CAMERA_INDEX, cv::CAP_DSHOW); + faceCap->set(cv::CAP_PROP_FRAME_WIDTH, SettingConfig::getInstance().FACE_FRAME_WIDTH); + faceCap->set(cv::CAP_PROP_FRAME_HEIGHT, SettingConfig::getInstance().FACE_FRAME_HEIGHT); + LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]初始化相机[%1][%2 * %3]") + .arg(SettingConfig::getInstance().FACE_CAMERA_INDEX) + .arg(SettingConfig::getInstance().FACE_FRAME_WIDTH) + .arg(SettingConfig::getInstance().FACE_FRAME_HEIGHT).toStdString(); + + // 获取定时器, 绑定定时函数 + connect(TimeCounterUtil::getInstance().faceCapCounter, &QTimer::timeout, + this, &FaceCameraController::getOneFaceFrm); } FaceCameraController::~FaceCameraController() @@ -15,25 +26,11 @@ } -void FaceCameraController::openFaceCamera() +void FaceCameraController::openFaceCamera(int mInterval) { - // 获取定时器, 绑定定时函数 - connect(TimeCounterUtil::getInstance().faceCapCounter, &QTimer::timeout, - this, &FaceCameraController::getOneFaceFrm); - - this->faceCap = new cv::VideoCapture(SettingConfig::getInstance().FACE_CAMERA_INDEX, cv::CAP_DSHOW); - faceCap->set(cv::CAP_PROP_FRAME_WIDTH, SettingConfig::getInstance().FACE_FRAME_WIDTH); - faceCap->set(cv::CAP_PROP_FRAME_HEIGHT, SettingConfig::getInstance().FACE_FRAME_HEIGHT); - - LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]打开相机[%1][%2 * %3]") - .arg(SettingConfig::getInstance().FACE_CAMERA_INDEX) - .arg(SettingConfig::getInstance().FACE_FRAME_WIDTH) - .arg(SettingConfig::getInstance().FACE_FRAME_HEIGHT).toStdString(); - // 启动定时器 - TimeCounterUtil::getInstance().faceCapCounter->start(SettingConfig::getInstance().FACE_FRAME_INTERVAL); - LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]相机开始拍图[%1ms]") - .arg(SettingConfig::getInstance().FACE_FRAME_INTERVAL).toStdString(); + TimeCounterUtil::getInstance().faceCapCounter->start(mInterval); + LOG(DEBUG) << QString("[FaceCameraController][openFaceCamera]相机开始拍图[%1ms]").arg(mInterval).toStdString(); } void FaceCameraController::stopTakingPhoto() @@ -87,5 +84,39 @@ // 发送信号用于界面显示 emit sendImageToDraw(imgDisplay); + } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::WidgeFrameName::RECOGNIZE_RESULT_FORM) + { + // 拍图 + faceCap->read(faceMat); + + LOG(TRACE) << "TAKE ONE FACE FRAME " << faceMat.cols << " * " << faceMat.rows; + + // 左右翻转 + cv::Mat imageMatMiir; + flip(faceMat, imageMatMiir, 1); + + // clone一个mat, 用于界面显示 + cv::Mat faceMatDisp = imageMatMiir.clone(); + + CasicFaceInfo faceInfo; + faceInfo.hasFace = false; + faceInfo.matData = imageMatMiir; + + // 将图片数据压入堆栈 + ProMemory::getInstance().pushCasicFace(faceInfo); + + // 将mat转成QImage + QImage imgDisplay = ImageUtil::MatImageToQImage(faceMatDisp); + + // 发送信号用于界面显示 + emit sendImageToDrawForRecognize(imgDisplay); } } + +cv::Mat FaceCameraController::takeOneRawFrame() +{ + // 拍图 + cv::Mat camMat; + faceCap->read(camMat); + return camMat; +} diff --git a/device/FaceCameraController.h b/device/FaceCameraController.h index 6570cfb..b6dfd61 100644 --- a/device/FaceCameraController.h +++ b/device/FaceCameraController.h @@ -6,9 +6,6 @@ #include "opencv2/opencv.hpp" #include "casic/ProMemory.h" -//#include "casic/face/CasicFaceInterface.h" -//#include "process/memory/ProMemory.h" -//#include "process/face/CasicFaceRecState.h" #include "utils/ImageUtil.h" #include "utils/SettingConfig.h" #include "utils/TimeCounterUtil.h" @@ -22,7 +19,8 @@ ~FaceCameraController(); // 初始化并打开人脸相机 - void openFaceCamera(); + void openFaceCamera(int mInterval); + cv::Mat takeOneRawFrame(); void stopTakingPhoto(); void closeFaceCamera(); @@ -36,6 +34,7 @@ signals: void sendImageToDraw(QImage imageDisp); + void sendImageToDrawForRecognize(QImage imageDisp); void sendImageToDetect(cv::Mat imgMat); }; diff --git a/device/device.pri b/device/device.pri index 71d9dfa..274ba60 100644 --- a/device/device.pri +++ b/device/device.pri @@ -1,10 +1,12 @@ HEADERS += $$PWD/FaceCameraController.h HEADERS += $$PWD/face/FaceDetectRegistProcess.h +HEADERS += $$PWD/face/FaceDetectRecogProcess.h HEADERS += $$PWD/face/CasicFaceRecState.h SOURCES += $$PWD/FaceCameraController.cpp SOURCES += $$PWD/face/FaceDetectRegistProcess.cpp +SOURCES += $$PWD/face/FaceDetectRecogProcess.cpp SOURCES += $$PWD/face/CasicFaceRecState.cpp #HEADERS += $$PWD/IrisCameraController.h diff --git a/device/face/FaceDetectRecogProcess.cpp b/device/face/FaceDetectRecogProcess.cpp new file mode 100644 index 0000000..00e45ff --- /dev/null +++ b/device/face/FaceDetectRecogProcess.cpp @@ -0,0 +1,198 @@ +#include "FaceDetectRecogProcess.h" + +FaceDetectRecogProcess::FaceDetectRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; +} + +FaceDetectRecogProcess::~FaceDetectRecogProcess() +{ + this->setWorking(false); +} + +void FaceDetectRecogProcess::setWorking(bool working) +{ + this->working = working; +} +void FaceDetectRecogProcess::exitThread() +{ + this->exit = true; +} +void FaceDetectRecogProcess::startThread() +{ + this->exit = false; + this->start(); +} + +void FaceDetectRecogProcess::addOneTryCount() +{ + LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); + if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) + { + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + } else + { + CasicFaceRecState::getInstance().tryCount = 0; + CasicFaceRecState::getInstance().noFaceCount = 0; + emit matchFailure(); + + this->setWorking(false); // 返回后则线程暂停工作 + } +} + +void FaceDetectRecogProcess::addOneNoFaceCount() +{ + CasicFaceRecState::getInstance().noFaceCount++; + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) + { + CasicFaceRecState::getInstance().noFaceCount = 0; + emit matchFailure(); + + this->setWorking(false); // 返回后则暂停工作 + } +} + +void FaceDetectRecogProcess::run() +{ + while (exit == false) + { + if (this->working == false) + { + this->msleep(100); // 100ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isFaceQueueEmpty() == true) + { + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) + { + LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 取出人脸图像栈中的一条数据 + CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); + + // 调用人脸检测算法 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); + + // 没有找到人脸则返回 + if (faceInfo.hasFace == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 找到人脸则开始一次识别 + if (CasicFaceRecState::getInstance().recoginzeId == "0") + { + CasicFaceRecState::getInstance().initRecognize(); + } + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 + CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 + + // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 + casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); + faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); + + // 活体检测判断为假脸 + if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) + { + // 表示本次识别结束, 可以开始下一次识别过程 + LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); + + addOneTryCount(); // 判断是否超过次数, 重置识别状态 + this->msleep(200); // 200ms后再判断 + continue; + } + + // 设置识别状态值=通过活体检测 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; + + // 调用算法提取特征值, 1024个字节的float数组 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); + + // 设置识别状态值=特征值提取 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + + LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + this->setWorking(false); + // 特征值提取成功的人脸 与人脸库中的人脸进行比较 + compareFaceInCollection(); + } +} + +void FaceDetectRecogProcess::compareFaceInCollection() +{ + ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 + QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); + for (int i = 0; i < faceFeatures.size(); i++) + { + QVariantMap ffMap = faceFeatures.at(i); + + QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); + float ffArr[1024]; + for (int i = 0; i < 1024; i++) + { + QByteArray tempBa; + tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); + ffArr[i] = ByteUtil::binToFloat(tempBa); + } + + float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); + + LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); + if (sim > 0.62) + { + CasicFaceRecState::getInstance().faceInfo->sim = sim; + CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); + CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; + + // 找到匹配的人脸图像 + this->afterRecogAction(ffMap.value("person_id").toString()); + return ; + } + } + + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + this->addOneTryCount(); +} + +void FaceDetectRecogProcess::afterRecogAction(QString personId) +{ + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + + LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + // 发送信号, 在主界面上显示 + emit matchSuccess(personId); +} + diff --git a/device/face/FaceDetectRecogProcess.h b/device/face/FaceDetectRecogProcess.h new file mode 100644 index 0000000..b1051b7 --- /dev/null +++ b/device/face/FaceDetectRecogProcess.h @@ -0,0 +1,50 @@ +#ifndef FACEDETECTRECOGPROCESS_H +#define FACEDETECTRECOGPROCESS_H + +#include +#include +#include "opencv2/opencv.hpp" + +#include "dao/RecognitionRecordDao.h" + +#include "utils/easyloggingpp/easylogging++.h" +#include "utils/ImageUtil.h" +#include "utils/SettingConfig.h" +#include "utils/ByteUtil.h" + +#include "CasicFaceRecState.h" +#include "casic/ProMemory.h" +#include "casic/face/CasicFaceInterface.h" + +class FaceDetectRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit FaceDetectRecogProcess(QObject *parent = nullptr); + ~FaceDetectRecogProcess(); + + void setWorking(bool working); + void exitThread(); + void startThread(); + + void addOneTryCount(); + void addOneNoFaceCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + void compareFaceInCollection(); + void afterRecogAction(QString personId); + + volatile bool working; + volatile bool exit; + +signals: + void matchSuccess(QString personId); // 匹配成功 + void matchFailure(); // 匹配失败 + +}; + +#endif // FACEDETECTRECOGPROCESS_H diff --git a/device/face/FaceDetectRegistProcess.h b/device/face/FaceDetectRegistProcess.h index 9ffa91d..99a504c 100644 --- a/device/face/FaceDetectRegistProcess.h +++ b/device/face/FaceDetectRegistProcess.h @@ -14,8 +14,6 @@ #include "casic/ProMemory.h" #include "casic/face/CasicFaceInterface.h" -static bool FACE_DETECT_FLAG = false; - class FaceDetectRegistProcess : public QThread { Q_OBJECT @@ -40,10 +38,8 @@ volatile bool exit; signals: - void extractFeatureSuccess(); void failedCaptureFace(); void successCaptureFace(QString personIdByFace); - void findSimFace(QString personId); }; diff --git a/images/bg_recognize_result.png b/images/bg_recognize_result.png new file mode 100644 index 0000000..068b55b --- /dev/null +++ b/images/bg_recognize_result.png Binary files differ diff --git a/images/bg_video.png b/images/bg_video.png new file mode 100644 index 0000000..3ed9dae --- /dev/null +++ b/images/bg_video.png Binary files differ diff --git a/qss/recognize.css b/qss/recognize.css new file mode 100644 index 0000000..9c9b4d6 --- /dev/null +++ b/qss/recognize.css @@ -0,0 +1,20 @@ +QLabel { + color: #6868A6; + font-family: "Microsoft YaHei"; +} + +QLabel#labDate { + font-size: 36px; +} + +QLabel#labTime { + font-size: 100px; +} + +QToolButton { + color: #6868A6; + font-family: "Microsoft YaHei"; + font-size: 48px; + background: transparent; + border-style: none; +} diff --git a/resource.qrc b/resource.qrc index 1d26f80..b63a46b 100644 --- a/resource.qrc +++ b/resource.qrc @@ -22,5 +22,7 @@ images/tipsFailure.png images/tipsSuccess.png images/tipsConfirm.png + images/bg_recognize_result.png + images/bg_video.png diff --git a/utils/UtilInclude.h b/utils/UtilInclude.h new file mode 100644 index 0000000..f3ded58 --- /dev/null +++ b/utils/UtilInclude.h @@ -0,0 +1,12 @@ +#ifndef UTILINCLUDE_H +#define UTILINCLUDE_H + +#include "easyloggingpp/easylogging++.h" +#include "ByteUtil.h" +#include "ImageUtil.h" +#include "SelectDeptUtil.h" +#include "SettingConfig.h" +#include "SpeakerUtil.h" +#include "TimeCounterUtil.h" + +#endif // UTILINCLUDE_H diff --git a/utils/utils.pri b/utils/utils.pri index d4f4e4a..54ecc1c 100644 --- a/utils/utils.pri +++ b/utils/utils.pri @@ -1,4 +1,6 @@ +HEADERS += $$PWD/UtilInclude.h + HEADERS += $$PWD/id/IdWorker.h HEADERS += $$PWD/id/Noncopyable.h HEADERS += $$PWD/id/Singleton.h