diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/casic/iris/CasicIrisInterface.cpp b/casic/iris/CasicIrisInterface.cpp new file mode 100644 index 0000000..5c46e5b --- /dev/null +++ b/casic/iris/CasicIrisInterface.cpp @@ -0,0 +1,187 @@ +#include "CasicIrisInterface.h" + +#include +#include +#include + +casic::iris::CasicIrisInterface::CasicIrisInterface() +{ + +} + +casic::iris::CasicIrisInterface::~CasicIrisInterface() +{ + +} + +void casic::iris::CasicIrisInterface::setCascadeFile(QString filename) +{ + this->cascadeName = filename.toStdString(); +} +void casic::iris::CasicIrisInterface::setMinEyeSize(int minEyeSize) +{ + this->minEyeSize = minEyeSize; +} +void casic::iris::CasicIrisInterface::setMaxEyeSize(int maxEyeSize) +{ + this->maxEyeSize = maxEyeSize; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.data = ImageUtil::MatImageToQImage(irisInfo.matData); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findAndCutEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + // 找到眼睛之后, 将眼部裁剪下来, 图像拉伸到640 * 480 + cv::Point center; + center.x = cvFloor(rect.at(0).x + rect.at(0).width*0.5); + center.y = cvFloor(rect.at(0).y + rect.at(0).height*0.5); + + // 限制中心点的范围 + if (center.x < SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) + { + // x小于240则x=240 +// center.x = center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + center.x = SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } else if (center.x > SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) { + // x大于1040则x=1040 + center.x = SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } + + if (center.y < SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) + { + // y小于180则y=180 + center.y = SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } else if (center.y > SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) { + center.y = SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } + + // 裁剪眼部图像 + cv::Mat halfSize = irisInfo.matData.clone(); + halfSize = irisInfo.matData(cv::Rect(center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5, + center.y - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5, + SettingConfig::getInstance().IRIS_WIDTH * cutRatio, + SettingConfig::getInstance().IRIS_HEIGHT * cutRatio)); + + cv::resize(halfSize, halfSize, cv::Size(SettingConfig::getInstance().IRIS_WIDTH, SettingConfig::getInstance().IRIS_HEIGHT)); + cv::flip(halfSize, halfSize, 1); // 左右翻转 + +// cv::imwrite(QString("d:\\irisLogs\\%1.bmp").arg(QDateTime::currentSecsSinceEpoch()).toStdString(), halfSize); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.matData = halfSize; + irisInfo.data = ImageUtil::MatImageToQImage(halfSize); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisQualityAssess(CasicIrisInfo irisInfo) +{ + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisCodeExtract(CasicIrisInfo irisInfo) +{ + + QElapsedTimer timer; + timer.start(); + +// QSocketClientUtil * clientUtil = new QSocketClientUtil(); + + QByteArray data((char*)irisInfo.matData.data, 640*480); + + std::cout << "extract iris code" << std::endl; + +// clientUtil->sendData(data); +// if (response.size() == 1024) +// { +// QLog::getInstance()->logger()->debug(QString("特征值提取[耗时: %1ms][特征值: %2]\n") +// .arg(timer.elapsed()) +// .arg(QByteUtil::binToHexString(response))); +// } else +// { +// std::cout << response.toStdString() << std::endl; +// } + + return irisInfo; +} diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/casic/iris/CasicIrisInterface.cpp b/casic/iris/CasicIrisInterface.cpp new file mode 100644 index 0000000..5c46e5b --- /dev/null +++ b/casic/iris/CasicIrisInterface.cpp @@ -0,0 +1,187 @@ +#include "CasicIrisInterface.h" + +#include +#include +#include + +casic::iris::CasicIrisInterface::CasicIrisInterface() +{ + +} + +casic::iris::CasicIrisInterface::~CasicIrisInterface() +{ + +} + +void casic::iris::CasicIrisInterface::setCascadeFile(QString filename) +{ + this->cascadeName = filename.toStdString(); +} +void casic::iris::CasicIrisInterface::setMinEyeSize(int minEyeSize) +{ + this->minEyeSize = minEyeSize; +} +void casic::iris::CasicIrisInterface::setMaxEyeSize(int maxEyeSize) +{ + this->maxEyeSize = maxEyeSize; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.data = ImageUtil::MatImageToQImage(irisInfo.matData); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findAndCutEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + // 找到眼睛之后, 将眼部裁剪下来, 图像拉伸到640 * 480 + cv::Point center; + center.x = cvFloor(rect.at(0).x + rect.at(0).width*0.5); + center.y = cvFloor(rect.at(0).y + rect.at(0).height*0.5); + + // 限制中心点的范围 + if (center.x < SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) + { + // x小于240则x=240 +// center.x = center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + center.x = SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } else if (center.x > SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) { + // x大于1040则x=1040 + center.x = SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } + + if (center.y < SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) + { + // y小于180则y=180 + center.y = SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } else if (center.y > SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) { + center.y = SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } + + // 裁剪眼部图像 + cv::Mat halfSize = irisInfo.matData.clone(); + halfSize = irisInfo.matData(cv::Rect(center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5, + center.y - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5, + SettingConfig::getInstance().IRIS_WIDTH * cutRatio, + SettingConfig::getInstance().IRIS_HEIGHT * cutRatio)); + + cv::resize(halfSize, halfSize, cv::Size(SettingConfig::getInstance().IRIS_WIDTH, SettingConfig::getInstance().IRIS_HEIGHT)); + cv::flip(halfSize, halfSize, 1); // 左右翻转 + +// cv::imwrite(QString("d:\\irisLogs\\%1.bmp").arg(QDateTime::currentSecsSinceEpoch()).toStdString(), halfSize); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.matData = halfSize; + irisInfo.data = ImageUtil::MatImageToQImage(halfSize); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisQualityAssess(CasicIrisInfo irisInfo) +{ + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisCodeExtract(CasicIrisInfo irisInfo) +{ + + QElapsedTimer timer; + timer.start(); + +// QSocketClientUtil * clientUtil = new QSocketClientUtil(); + + QByteArray data((char*)irisInfo.matData.data, 640*480); + + std::cout << "extract iris code" << std::endl; + +// clientUtil->sendData(data); +// if (response.size() == 1024) +// { +// QLog::getInstance()->logger()->debug(QString("特征值提取[耗时: %1ms][特征值: %2]\n") +// .arg(timer.elapsed()) +// .arg(QByteUtil::binToHexString(response))); +// } else +// { +// std::cout << response.toStdString() << std::endl; +// } + + return irisInfo; +} diff --git a/casic/iris/CasicIrisInterface.h b/casic/iris/CasicIrisInterface.h new file mode 100644 index 0000000..87ed97e --- /dev/null +++ b/casic/iris/CasicIrisInterface.h @@ -0,0 +1,45 @@ +#ifndef CASICIRISINTERFACE_H +#define CASICIRISINTERFACE_H + +#include "CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +namespace casic { + namespace iris { + class CasicIrisInterface + { + public: + ~CasicIrisInterface(); + CasicIrisInterface(const CasicIrisInterface&)=delete; + CasicIrisInterface& operator=(const CasicIrisInterface&)=delete; + + static CasicIrisInterface& getInstance() { + static CasicIrisInterface instance; + return instance; + } + + CasicIrisInfo findEye(CasicIrisInfo irisInfo); + CasicIrisInfo findAndCutEye(CasicIrisInfo irisInfo); + CasicIrisInfo irisQualityAssess(CasicIrisInfo irisInfo); + CasicIrisInfo irisCodeExtract(CasicIrisInfo irisInfo); + CasicIrisInfo irisMatch(CasicIrisInfo irisInfo); + + void setCascadeFile(QString filename); + void setMinEyeSize(int minEyeSize); + void setMaxEyeSize(int maxEyeSize); + + private: + CasicIrisInterface(); + + std::string cascadeName = "./model/haarcascade_eye.xml"; + int minEyeSize = 320; + int maxEyeSize = 480; + float cutRatio = 1.0; + + cv::CascadeClassifier * cascade; + }; + } +} + + +#endif // CASICIRISINTERFACE_H diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/casic/iris/CasicIrisInterface.cpp b/casic/iris/CasicIrisInterface.cpp new file mode 100644 index 0000000..5c46e5b --- /dev/null +++ b/casic/iris/CasicIrisInterface.cpp @@ -0,0 +1,187 @@ +#include "CasicIrisInterface.h" + +#include +#include +#include + +casic::iris::CasicIrisInterface::CasicIrisInterface() +{ + +} + +casic::iris::CasicIrisInterface::~CasicIrisInterface() +{ + +} + +void casic::iris::CasicIrisInterface::setCascadeFile(QString filename) +{ + this->cascadeName = filename.toStdString(); +} +void casic::iris::CasicIrisInterface::setMinEyeSize(int minEyeSize) +{ + this->minEyeSize = minEyeSize; +} +void casic::iris::CasicIrisInterface::setMaxEyeSize(int maxEyeSize) +{ + this->maxEyeSize = maxEyeSize; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.data = ImageUtil::MatImageToQImage(irisInfo.matData); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findAndCutEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + // 找到眼睛之后, 将眼部裁剪下来, 图像拉伸到640 * 480 + cv::Point center; + center.x = cvFloor(rect.at(0).x + rect.at(0).width*0.5); + center.y = cvFloor(rect.at(0).y + rect.at(0).height*0.5); + + // 限制中心点的范围 + if (center.x < SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) + { + // x小于240则x=240 +// center.x = center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + center.x = SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } else if (center.x > SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) { + // x大于1040则x=1040 + center.x = SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } + + if (center.y < SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) + { + // y小于180则y=180 + center.y = SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } else if (center.y > SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) { + center.y = SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } + + // 裁剪眼部图像 + cv::Mat halfSize = irisInfo.matData.clone(); + halfSize = irisInfo.matData(cv::Rect(center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5, + center.y - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5, + SettingConfig::getInstance().IRIS_WIDTH * cutRatio, + SettingConfig::getInstance().IRIS_HEIGHT * cutRatio)); + + cv::resize(halfSize, halfSize, cv::Size(SettingConfig::getInstance().IRIS_WIDTH, SettingConfig::getInstance().IRIS_HEIGHT)); + cv::flip(halfSize, halfSize, 1); // 左右翻转 + +// cv::imwrite(QString("d:\\irisLogs\\%1.bmp").arg(QDateTime::currentSecsSinceEpoch()).toStdString(), halfSize); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.matData = halfSize; + irisInfo.data = ImageUtil::MatImageToQImage(halfSize); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisQualityAssess(CasicIrisInfo irisInfo) +{ + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisCodeExtract(CasicIrisInfo irisInfo) +{ + + QElapsedTimer timer; + timer.start(); + +// QSocketClientUtil * clientUtil = new QSocketClientUtil(); + + QByteArray data((char*)irisInfo.matData.data, 640*480); + + std::cout << "extract iris code" << std::endl; + +// clientUtil->sendData(data); +// if (response.size() == 1024) +// { +// QLog::getInstance()->logger()->debug(QString("特征值提取[耗时: %1ms][特征值: %2]\n") +// .arg(timer.elapsed()) +// .arg(QByteUtil::binToHexString(response))); +// } else +// { +// std::cout << response.toStdString() << std::endl; +// } + + return irisInfo; +} diff --git a/casic/iris/CasicIrisInterface.h b/casic/iris/CasicIrisInterface.h new file mode 100644 index 0000000..87ed97e --- /dev/null +++ b/casic/iris/CasicIrisInterface.h @@ -0,0 +1,45 @@ +#ifndef CASICIRISINTERFACE_H +#define CASICIRISINTERFACE_H + +#include "CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +namespace casic { + namespace iris { + class CasicIrisInterface + { + public: + ~CasicIrisInterface(); + CasicIrisInterface(const CasicIrisInterface&)=delete; + CasicIrisInterface& operator=(const CasicIrisInterface&)=delete; + + static CasicIrisInterface& getInstance() { + static CasicIrisInterface instance; + return instance; + } + + CasicIrisInfo findEye(CasicIrisInfo irisInfo); + CasicIrisInfo findAndCutEye(CasicIrisInfo irisInfo); + CasicIrisInfo irisQualityAssess(CasicIrisInfo irisInfo); + CasicIrisInfo irisCodeExtract(CasicIrisInfo irisInfo); + CasicIrisInfo irisMatch(CasicIrisInfo irisInfo); + + void setCascadeFile(QString filename); + void setMinEyeSize(int minEyeSize); + void setMaxEyeSize(int maxEyeSize); + + private: + CasicIrisInterface(); + + std::string cascadeName = "./model/haarcascade_eye.xml"; + int minEyeSize = 320; + int maxEyeSize = 480; + float cutRatio = 1.0; + + cv::CascadeClassifier * cascade; + }; + } +} + + +#endif // CASICIRISINTERFACE_H diff --git a/casic/iris/casicIris.pri b/casic/iris/casicIris.pri new file mode 100644 index 0000000..d0942ce --- /dev/null +++ b/casic/iris/casicIris.pri @@ -0,0 +1,4 @@ +HEADERS += $$PWD/CasicIrisInfo.h +HEADERS += $$PWD/CasicIrisInterface.h + +SOURCES += $$PWD/CasicIrisInterface.cpp diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/casic/iris/CasicIrisInterface.cpp b/casic/iris/CasicIrisInterface.cpp new file mode 100644 index 0000000..5c46e5b --- /dev/null +++ b/casic/iris/CasicIrisInterface.cpp @@ -0,0 +1,187 @@ +#include "CasicIrisInterface.h" + +#include +#include +#include + +casic::iris::CasicIrisInterface::CasicIrisInterface() +{ + +} + +casic::iris::CasicIrisInterface::~CasicIrisInterface() +{ + +} + +void casic::iris::CasicIrisInterface::setCascadeFile(QString filename) +{ + this->cascadeName = filename.toStdString(); +} +void casic::iris::CasicIrisInterface::setMinEyeSize(int minEyeSize) +{ + this->minEyeSize = minEyeSize; +} +void casic::iris::CasicIrisInterface::setMaxEyeSize(int maxEyeSize) +{ + this->maxEyeSize = maxEyeSize; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.data = ImageUtil::MatImageToQImage(irisInfo.matData); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findAndCutEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + // 找到眼睛之后, 将眼部裁剪下来, 图像拉伸到640 * 480 + cv::Point center; + center.x = cvFloor(rect.at(0).x + rect.at(0).width*0.5); + center.y = cvFloor(rect.at(0).y + rect.at(0).height*0.5); + + // 限制中心点的范围 + if (center.x < SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) + { + // x小于240则x=240 +// center.x = center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + center.x = SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } else if (center.x > SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) { + // x大于1040则x=1040 + center.x = SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } + + if (center.y < SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) + { + // y小于180则y=180 + center.y = SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } else if (center.y > SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) { + center.y = SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } + + // 裁剪眼部图像 + cv::Mat halfSize = irisInfo.matData.clone(); + halfSize = irisInfo.matData(cv::Rect(center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5, + center.y - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5, + SettingConfig::getInstance().IRIS_WIDTH * cutRatio, + SettingConfig::getInstance().IRIS_HEIGHT * cutRatio)); + + cv::resize(halfSize, halfSize, cv::Size(SettingConfig::getInstance().IRIS_WIDTH, SettingConfig::getInstance().IRIS_HEIGHT)); + cv::flip(halfSize, halfSize, 1); // 左右翻转 + +// cv::imwrite(QString("d:\\irisLogs\\%1.bmp").arg(QDateTime::currentSecsSinceEpoch()).toStdString(), halfSize); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.matData = halfSize; + irisInfo.data = ImageUtil::MatImageToQImage(halfSize); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisQualityAssess(CasicIrisInfo irisInfo) +{ + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisCodeExtract(CasicIrisInfo irisInfo) +{ + + QElapsedTimer timer; + timer.start(); + +// QSocketClientUtil * clientUtil = new QSocketClientUtil(); + + QByteArray data((char*)irisInfo.matData.data, 640*480); + + std::cout << "extract iris code" << std::endl; + +// clientUtil->sendData(data); +// if (response.size() == 1024) +// { +// QLog::getInstance()->logger()->debug(QString("特征值提取[耗时: %1ms][特征值: %2]\n") +// .arg(timer.elapsed()) +// .arg(QByteUtil::binToHexString(response))); +// } else +// { +// std::cout << response.toStdString() << std::endl; +// } + + return irisInfo; +} diff --git a/casic/iris/CasicIrisInterface.h b/casic/iris/CasicIrisInterface.h new file mode 100644 index 0000000..87ed97e --- /dev/null +++ b/casic/iris/CasicIrisInterface.h @@ -0,0 +1,45 @@ +#ifndef CASICIRISINTERFACE_H +#define CASICIRISINTERFACE_H + +#include "CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +namespace casic { + namespace iris { + class CasicIrisInterface + { + public: + ~CasicIrisInterface(); + CasicIrisInterface(const CasicIrisInterface&)=delete; + CasicIrisInterface& operator=(const CasicIrisInterface&)=delete; + + static CasicIrisInterface& getInstance() { + static CasicIrisInterface instance; + return instance; + } + + CasicIrisInfo findEye(CasicIrisInfo irisInfo); + CasicIrisInfo findAndCutEye(CasicIrisInfo irisInfo); + CasicIrisInfo irisQualityAssess(CasicIrisInfo irisInfo); + CasicIrisInfo irisCodeExtract(CasicIrisInfo irisInfo); + CasicIrisInfo irisMatch(CasicIrisInfo irisInfo); + + void setCascadeFile(QString filename); + void setMinEyeSize(int minEyeSize); + void setMaxEyeSize(int maxEyeSize); + + private: + CasicIrisInterface(); + + std::string cascadeName = "./model/haarcascade_eye.xml"; + int minEyeSize = 320; + int maxEyeSize = 480; + float cutRatio = 1.0; + + cv::CascadeClassifier * cascade; + }; + } +} + + +#endif // CASICIRISINTERFACE_H diff --git a/casic/iris/casicIris.pri b/casic/iris/casicIris.pri new file mode 100644 index 0000000..d0942ce --- /dev/null +++ b/casic/iris/casicIris.pri @@ -0,0 +1,4 @@ +HEADERS += $$PWD/CasicIrisInfo.h +HEADERS += $$PWD/CasicIrisInterface.h + +SOURCES += $$PWD/CasicIrisInterface.cpp diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index 45df089..49e7316 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -1,4 +1,5 @@ #include "IrisCameraCapEventHandler.h" +#include IrisCameraCapEventHandler::IrisCameraCapEventHandler(QObject *parent) : QObject(parent) { @@ -14,90 +15,37 @@ auto camName = cam->getPtr()->GetDeviceInfo().GetUserID(); int width = objImageDataPointer->GetWidth(); int height = objImageDataPointer->GetHeight(); - size_t leftKeyIndex = camName.find("left"); - size_t rightKeyIndex = camName.find("right"); uchar * pBuffer = (BYTE*)objImageDataPointer->GetBuffer(); - - // 相机拍摄下的图像1440*1080, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 -// QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到400 * 300的尺寸 - img = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT, SettingConfig::getInstance().IRIS_DISPLAY_WIDTH); - img = img.transformed(QTransform().rotate(-90)); // 图像逆时针旋转90度 - - // 发送到界面进行显示 - emit sendIrisFrameToDraw(img); -// cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - -// irisInfo.data = imgAlgo; -// irisInfo.matData = irisMat; - -// // 将图像显示在注册页面的label上 -// // 并将虹膜信息对象存入队列中 -// ProMemory::getInstance().pushCasicIris(irisInfo); - -// if (leftKeyIndex >= 0 && leftKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 0); // 左眼画面 -// } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 1); // 右眼画面 -// } -/* if (pBuffer != NULL) { + // 相机拍摄下的图像1440*1080, 直接用于算法判断 + QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 + QImage imgDisp; + + // 图像逆时针旋转90度 + img = img.transformed(QTransform().rotate(90)); + + // 用于显示的图像需要缩小到480 * 640的尺寸 + imgDisp = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_WIDTH, SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT); + + // 发送到界面进行显示 + emit sendIrisFrameToDraw(imgDisp); + // 创建虹膜信息对象 CasicIrisInfo irisInfo; irisInfo.hasEye = false; - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - // 左眼相机拍摄的图像 - irisInfo.leftOrRight = "left"; - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - // 右眼相机 - irisInfo.leftOrRight = "right"; - } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - cv::Mat irisMat = ImageUtil::QImageToMat(imgDisp); + // 存入图像栈 + cv::Mat irisMat = ImageUtil::QImageToMat(img); + irisInfo.matData = irisMat; - irisInfo.data = imgDisp; - irisInfo.matData = irisMat; + ProMemory::getInstance().pushCasicIris(irisInfo); - ProMemory::getInstance().pushCasicIris(irisInfo); - -// cv::imwrite(QString("D:\\irisLogs\\iristest-%1.bmp").arg(irisInfo.leftOrRight).toStdString(), irisMat); - } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到1/4的尺寸 - img = img.scaled(640, 480); - cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - - irisInfo.data = imgAlgo; - irisInfo.matData = irisMat; - - // 将图像显示在注册页面的label上 - // 并将虹膜信息对象存入队列中 - ProMemory::getInstance().pushCasicIris(irisInfo); - - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 0); // 左眼画面 - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 1); // 右眼画面 - } - } - }*/ + /* 相机控制只拍图 不找眼 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + */ + } } } diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/casic/iris/CasicIrisInterface.cpp b/casic/iris/CasicIrisInterface.cpp new file mode 100644 index 0000000..5c46e5b --- /dev/null +++ b/casic/iris/CasicIrisInterface.cpp @@ -0,0 +1,187 @@ +#include "CasicIrisInterface.h" + +#include +#include +#include + +casic::iris::CasicIrisInterface::CasicIrisInterface() +{ + +} + +casic::iris::CasicIrisInterface::~CasicIrisInterface() +{ + +} + +void casic::iris::CasicIrisInterface::setCascadeFile(QString filename) +{ + this->cascadeName = filename.toStdString(); +} +void casic::iris::CasicIrisInterface::setMinEyeSize(int minEyeSize) +{ + this->minEyeSize = minEyeSize; +} +void casic::iris::CasicIrisInterface::setMaxEyeSize(int maxEyeSize) +{ + this->maxEyeSize = maxEyeSize; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.data = ImageUtil::MatImageToQImage(irisInfo.matData); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findAndCutEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + // 找到眼睛之后, 将眼部裁剪下来, 图像拉伸到640 * 480 + cv::Point center; + center.x = cvFloor(rect.at(0).x + rect.at(0).width*0.5); + center.y = cvFloor(rect.at(0).y + rect.at(0).height*0.5); + + // 限制中心点的范围 + if (center.x < SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) + { + // x小于240则x=240 +// center.x = center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + center.x = SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } else if (center.x > SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) { + // x大于1040则x=1040 + center.x = SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } + + if (center.y < SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) + { + // y小于180则y=180 + center.y = SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } else if (center.y > SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) { + center.y = SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } + + // 裁剪眼部图像 + cv::Mat halfSize = irisInfo.matData.clone(); + halfSize = irisInfo.matData(cv::Rect(center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5, + center.y - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5, + SettingConfig::getInstance().IRIS_WIDTH * cutRatio, + SettingConfig::getInstance().IRIS_HEIGHT * cutRatio)); + + cv::resize(halfSize, halfSize, cv::Size(SettingConfig::getInstance().IRIS_WIDTH, SettingConfig::getInstance().IRIS_HEIGHT)); + cv::flip(halfSize, halfSize, 1); // 左右翻转 + +// cv::imwrite(QString("d:\\irisLogs\\%1.bmp").arg(QDateTime::currentSecsSinceEpoch()).toStdString(), halfSize); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.matData = halfSize; + irisInfo.data = ImageUtil::MatImageToQImage(halfSize); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisQualityAssess(CasicIrisInfo irisInfo) +{ + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisCodeExtract(CasicIrisInfo irisInfo) +{ + + QElapsedTimer timer; + timer.start(); + +// QSocketClientUtil * clientUtil = new QSocketClientUtil(); + + QByteArray data((char*)irisInfo.matData.data, 640*480); + + std::cout << "extract iris code" << std::endl; + +// clientUtil->sendData(data); +// if (response.size() == 1024) +// { +// QLog::getInstance()->logger()->debug(QString("特征值提取[耗时: %1ms][特征值: %2]\n") +// .arg(timer.elapsed()) +// .arg(QByteUtil::binToHexString(response))); +// } else +// { +// std::cout << response.toStdString() << std::endl; +// } + + return irisInfo; +} diff --git a/casic/iris/CasicIrisInterface.h b/casic/iris/CasicIrisInterface.h new file mode 100644 index 0000000..87ed97e --- /dev/null +++ b/casic/iris/CasicIrisInterface.h @@ -0,0 +1,45 @@ +#ifndef CASICIRISINTERFACE_H +#define CASICIRISINTERFACE_H + +#include "CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +namespace casic { + namespace iris { + class CasicIrisInterface + { + public: + ~CasicIrisInterface(); + CasicIrisInterface(const CasicIrisInterface&)=delete; + CasicIrisInterface& operator=(const CasicIrisInterface&)=delete; + + static CasicIrisInterface& getInstance() { + static CasicIrisInterface instance; + return instance; + } + + CasicIrisInfo findEye(CasicIrisInfo irisInfo); + CasicIrisInfo findAndCutEye(CasicIrisInfo irisInfo); + CasicIrisInfo irisQualityAssess(CasicIrisInfo irisInfo); + CasicIrisInfo irisCodeExtract(CasicIrisInfo irisInfo); + CasicIrisInfo irisMatch(CasicIrisInfo irisInfo); + + void setCascadeFile(QString filename); + void setMinEyeSize(int minEyeSize); + void setMaxEyeSize(int maxEyeSize); + + private: + CasicIrisInterface(); + + std::string cascadeName = "./model/haarcascade_eye.xml"; + int minEyeSize = 320; + int maxEyeSize = 480; + float cutRatio = 1.0; + + cv::CascadeClassifier * cascade; + }; + } +} + + +#endif // CASICIRISINTERFACE_H diff --git a/casic/iris/casicIris.pri b/casic/iris/casicIris.pri new file mode 100644 index 0000000..d0942ce --- /dev/null +++ b/casic/iris/casicIris.pri @@ -0,0 +1,4 @@ +HEADERS += $$PWD/CasicIrisInfo.h +HEADERS += $$PWD/CasicIrisInterface.h + +SOURCES += $$PWD/CasicIrisInterface.cpp diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index 45df089..49e7316 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -1,4 +1,5 @@ #include "IrisCameraCapEventHandler.h" +#include IrisCameraCapEventHandler::IrisCameraCapEventHandler(QObject *parent) : QObject(parent) { @@ -14,90 +15,37 @@ auto camName = cam->getPtr()->GetDeviceInfo().GetUserID(); int width = objImageDataPointer->GetWidth(); int height = objImageDataPointer->GetHeight(); - size_t leftKeyIndex = camName.find("left"); - size_t rightKeyIndex = camName.find("right"); uchar * pBuffer = (BYTE*)objImageDataPointer->GetBuffer(); - - // 相机拍摄下的图像1440*1080, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 -// QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到400 * 300的尺寸 - img = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT, SettingConfig::getInstance().IRIS_DISPLAY_WIDTH); - img = img.transformed(QTransform().rotate(-90)); // 图像逆时针旋转90度 - - // 发送到界面进行显示 - emit sendIrisFrameToDraw(img); -// cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - -// irisInfo.data = imgAlgo; -// irisInfo.matData = irisMat; - -// // 将图像显示在注册页面的label上 -// // 并将虹膜信息对象存入队列中 -// ProMemory::getInstance().pushCasicIris(irisInfo); - -// if (leftKeyIndex >= 0 && leftKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 0); // 左眼画面 -// } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 1); // 右眼画面 -// } -/* if (pBuffer != NULL) { + // 相机拍摄下的图像1440*1080, 直接用于算法判断 + QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 + QImage imgDisp; + + // 图像逆时针旋转90度 + img = img.transformed(QTransform().rotate(90)); + + // 用于显示的图像需要缩小到480 * 640的尺寸 + imgDisp = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_WIDTH, SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT); + + // 发送到界面进行显示 + emit sendIrisFrameToDraw(imgDisp); + // 创建虹膜信息对象 CasicIrisInfo irisInfo; irisInfo.hasEye = false; - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - // 左眼相机拍摄的图像 - irisInfo.leftOrRight = "left"; - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - // 右眼相机 - irisInfo.leftOrRight = "right"; - } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - cv::Mat irisMat = ImageUtil::QImageToMat(imgDisp); + // 存入图像栈 + cv::Mat irisMat = ImageUtil::QImageToMat(img); + irisInfo.matData = irisMat; - irisInfo.data = imgDisp; - irisInfo.matData = irisMat; + ProMemory::getInstance().pushCasicIris(irisInfo); - ProMemory::getInstance().pushCasicIris(irisInfo); - -// cv::imwrite(QString("D:\\irisLogs\\iristest-%1.bmp").arg(irisInfo.leftOrRight).toStdString(), irisMat); - } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到1/4的尺寸 - img = img.scaled(640, 480); - cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - - irisInfo.data = imgAlgo; - irisInfo.matData = irisMat; - - // 将图像显示在注册页面的label上 - // 并将虹膜信息对象存入队列中 - ProMemory::getInstance().pushCasicIris(irisInfo); - - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 0); // 左眼画面 - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 1); // 右眼画面 - } - } - }*/ + /* 相机控制只拍图 不找眼 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + */ + } } } diff --git a/device/IrisCameraCapEventHandler.h b/device/IrisCameraCapEventHandler.h index ad75a97..8b976c5 100644 --- a/device/IrisCameraCapEventHandler.h +++ b/device/IrisCameraCapEventHandler.h @@ -6,7 +6,7 @@ #include "include/opencv2/opencv.hpp" #include "include/daheng/GalaxyIncludes.h" -//#include "casic/iris/CasicIrisInterface.h" +#include "casic/iris/CasicIrisInterface.h" #include "ProMemory.h" #include "utils/UtilInclude.h" diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/casic/iris/CasicIrisInterface.cpp b/casic/iris/CasicIrisInterface.cpp new file mode 100644 index 0000000..5c46e5b --- /dev/null +++ b/casic/iris/CasicIrisInterface.cpp @@ -0,0 +1,187 @@ +#include "CasicIrisInterface.h" + +#include +#include +#include + +casic::iris::CasicIrisInterface::CasicIrisInterface() +{ + +} + +casic::iris::CasicIrisInterface::~CasicIrisInterface() +{ + +} + +void casic::iris::CasicIrisInterface::setCascadeFile(QString filename) +{ + this->cascadeName = filename.toStdString(); +} +void casic::iris::CasicIrisInterface::setMinEyeSize(int minEyeSize) +{ + this->minEyeSize = minEyeSize; +} +void casic::iris::CasicIrisInterface::setMaxEyeSize(int maxEyeSize) +{ + this->maxEyeSize = maxEyeSize; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.data = ImageUtil::MatImageToQImage(irisInfo.matData); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findAndCutEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + // 找到眼睛之后, 将眼部裁剪下来, 图像拉伸到640 * 480 + cv::Point center; + center.x = cvFloor(rect.at(0).x + rect.at(0).width*0.5); + center.y = cvFloor(rect.at(0).y + rect.at(0).height*0.5); + + // 限制中心点的范围 + if (center.x < SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) + { + // x小于240则x=240 +// center.x = center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + center.x = SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } else if (center.x > SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) { + // x大于1040则x=1040 + center.x = SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } + + if (center.y < SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) + { + // y小于180则y=180 + center.y = SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } else if (center.y > SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) { + center.y = SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } + + // 裁剪眼部图像 + cv::Mat halfSize = irisInfo.matData.clone(); + halfSize = irisInfo.matData(cv::Rect(center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5, + center.y - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5, + SettingConfig::getInstance().IRIS_WIDTH * cutRatio, + SettingConfig::getInstance().IRIS_HEIGHT * cutRatio)); + + cv::resize(halfSize, halfSize, cv::Size(SettingConfig::getInstance().IRIS_WIDTH, SettingConfig::getInstance().IRIS_HEIGHT)); + cv::flip(halfSize, halfSize, 1); // 左右翻转 + +// cv::imwrite(QString("d:\\irisLogs\\%1.bmp").arg(QDateTime::currentSecsSinceEpoch()).toStdString(), halfSize); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.matData = halfSize; + irisInfo.data = ImageUtil::MatImageToQImage(halfSize); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisQualityAssess(CasicIrisInfo irisInfo) +{ + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisCodeExtract(CasicIrisInfo irisInfo) +{ + + QElapsedTimer timer; + timer.start(); + +// QSocketClientUtil * clientUtil = new QSocketClientUtil(); + + QByteArray data((char*)irisInfo.matData.data, 640*480); + + std::cout << "extract iris code" << std::endl; + +// clientUtil->sendData(data); +// if (response.size() == 1024) +// { +// QLog::getInstance()->logger()->debug(QString("特征值提取[耗时: %1ms][特征值: %2]\n") +// .arg(timer.elapsed()) +// .arg(QByteUtil::binToHexString(response))); +// } else +// { +// std::cout << response.toStdString() << std::endl; +// } + + return irisInfo; +} diff --git a/casic/iris/CasicIrisInterface.h b/casic/iris/CasicIrisInterface.h new file mode 100644 index 0000000..87ed97e --- /dev/null +++ b/casic/iris/CasicIrisInterface.h @@ -0,0 +1,45 @@ +#ifndef CASICIRISINTERFACE_H +#define CASICIRISINTERFACE_H + +#include "CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +namespace casic { + namespace iris { + class CasicIrisInterface + { + public: + ~CasicIrisInterface(); + CasicIrisInterface(const CasicIrisInterface&)=delete; + CasicIrisInterface& operator=(const CasicIrisInterface&)=delete; + + static CasicIrisInterface& getInstance() { + static CasicIrisInterface instance; + return instance; + } + + CasicIrisInfo findEye(CasicIrisInfo irisInfo); + CasicIrisInfo findAndCutEye(CasicIrisInfo irisInfo); + CasicIrisInfo irisQualityAssess(CasicIrisInfo irisInfo); + CasicIrisInfo irisCodeExtract(CasicIrisInfo irisInfo); + CasicIrisInfo irisMatch(CasicIrisInfo irisInfo); + + void setCascadeFile(QString filename); + void setMinEyeSize(int minEyeSize); + void setMaxEyeSize(int maxEyeSize); + + private: + CasicIrisInterface(); + + std::string cascadeName = "./model/haarcascade_eye.xml"; + int minEyeSize = 320; + int maxEyeSize = 480; + float cutRatio = 1.0; + + cv::CascadeClassifier * cascade; + }; + } +} + + +#endif // CASICIRISINTERFACE_H diff --git a/casic/iris/casicIris.pri b/casic/iris/casicIris.pri new file mode 100644 index 0000000..d0942ce --- /dev/null +++ b/casic/iris/casicIris.pri @@ -0,0 +1,4 @@ +HEADERS += $$PWD/CasicIrisInfo.h +HEADERS += $$PWD/CasicIrisInterface.h + +SOURCES += $$PWD/CasicIrisInterface.cpp diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index 45df089..49e7316 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -1,4 +1,5 @@ #include "IrisCameraCapEventHandler.h" +#include IrisCameraCapEventHandler::IrisCameraCapEventHandler(QObject *parent) : QObject(parent) { @@ -14,90 +15,37 @@ auto camName = cam->getPtr()->GetDeviceInfo().GetUserID(); int width = objImageDataPointer->GetWidth(); int height = objImageDataPointer->GetHeight(); - size_t leftKeyIndex = camName.find("left"); - size_t rightKeyIndex = camName.find("right"); uchar * pBuffer = (BYTE*)objImageDataPointer->GetBuffer(); - - // 相机拍摄下的图像1440*1080, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 -// QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到400 * 300的尺寸 - img = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT, SettingConfig::getInstance().IRIS_DISPLAY_WIDTH); - img = img.transformed(QTransform().rotate(-90)); // 图像逆时针旋转90度 - - // 发送到界面进行显示 - emit sendIrisFrameToDraw(img); -// cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - -// irisInfo.data = imgAlgo; -// irisInfo.matData = irisMat; - -// // 将图像显示在注册页面的label上 -// // 并将虹膜信息对象存入队列中 -// ProMemory::getInstance().pushCasicIris(irisInfo); - -// if (leftKeyIndex >= 0 && leftKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 0); // 左眼画面 -// } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 1); // 右眼画面 -// } -/* if (pBuffer != NULL) { + // 相机拍摄下的图像1440*1080, 直接用于算法判断 + QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 + QImage imgDisp; + + // 图像逆时针旋转90度 + img = img.transformed(QTransform().rotate(90)); + + // 用于显示的图像需要缩小到480 * 640的尺寸 + imgDisp = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_WIDTH, SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT); + + // 发送到界面进行显示 + emit sendIrisFrameToDraw(imgDisp); + // 创建虹膜信息对象 CasicIrisInfo irisInfo; irisInfo.hasEye = false; - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - // 左眼相机拍摄的图像 - irisInfo.leftOrRight = "left"; - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - // 右眼相机 - irisInfo.leftOrRight = "right"; - } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - cv::Mat irisMat = ImageUtil::QImageToMat(imgDisp); + // 存入图像栈 + cv::Mat irisMat = ImageUtil::QImageToMat(img); + irisInfo.matData = irisMat; - irisInfo.data = imgDisp; - irisInfo.matData = irisMat; + ProMemory::getInstance().pushCasicIris(irisInfo); - ProMemory::getInstance().pushCasicIris(irisInfo); - -// cv::imwrite(QString("D:\\irisLogs\\iristest-%1.bmp").arg(irisInfo.leftOrRight).toStdString(), irisMat); - } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到1/4的尺寸 - img = img.scaled(640, 480); - cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - - irisInfo.data = imgAlgo; - irisInfo.matData = irisMat; - - // 将图像显示在注册页面的label上 - // 并将虹膜信息对象存入队列中 - ProMemory::getInstance().pushCasicIris(irisInfo); - - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 0); // 左眼画面 - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 1); // 右眼画面 - } - } - }*/ + /* 相机控制只拍图 不找眼 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + */ + } } } diff --git a/device/IrisCameraCapEventHandler.h b/device/IrisCameraCapEventHandler.h index ad75a97..8b976c5 100644 --- a/device/IrisCameraCapEventHandler.h +++ b/device/IrisCameraCapEventHandler.h @@ -6,7 +6,7 @@ #include "include/opencv2/opencv.hpp" #include "include/daheng/GalaxyIncludes.h" -//#include "casic/iris/CasicIrisInterface.h" +#include "casic/iris/CasicIrisInterface.h" #include "ProMemory.h" #include "utils/UtilInclude.h" diff --git a/device/device.pri b/device/device.pri index a8417f2..d1330a0 100644 --- a/device/device.pri +++ b/device/device.pri @@ -2,12 +2,12 @@ HEADERS += $$PWD/IrisCameraController.h HEADERS += $$PWD/IrisCameraCapEventHandler.h #HEADERS += $$PWD/iris/IrisRegistProcess.h -#HEADERS += $$PWD/iris/IrisRecogProcess.h -#HEADERS += $$PWD/iris/CasicIrisRecState.h +HEADERS += $$PWD/iris/IrisRecogProcess.h +HEADERS += $$PWD/iris/CasicIrisRecState.h SOURCES += $$PWD/IrisCameraController.cpp SOURCES += $$PWD/IrisCameraCapEventHandler.cpp #SOURCES += $$PWD/iris/IrisRegistProcess.cpp -#SOURCES += $$PWD/iris/IrisRecogProcess.cpp -#SOURCES += $$PWD/iris/CasicIrisRecState.cpp +SOURCES += $$PWD/iris/IrisRecogProcess.cpp +SOURCES += $$PWD/iris/CasicIrisRecState.cpp diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/casic/iris/CasicIrisInterface.cpp b/casic/iris/CasicIrisInterface.cpp new file mode 100644 index 0000000..5c46e5b --- /dev/null +++ b/casic/iris/CasicIrisInterface.cpp @@ -0,0 +1,187 @@ +#include "CasicIrisInterface.h" + +#include +#include +#include + +casic::iris::CasicIrisInterface::CasicIrisInterface() +{ + +} + +casic::iris::CasicIrisInterface::~CasicIrisInterface() +{ + +} + +void casic::iris::CasicIrisInterface::setCascadeFile(QString filename) +{ + this->cascadeName = filename.toStdString(); +} +void casic::iris::CasicIrisInterface::setMinEyeSize(int minEyeSize) +{ + this->minEyeSize = minEyeSize; +} +void casic::iris::CasicIrisInterface::setMaxEyeSize(int maxEyeSize) +{ + this->maxEyeSize = maxEyeSize; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.data = ImageUtil::MatImageToQImage(irisInfo.matData); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findAndCutEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + // 找到眼睛之后, 将眼部裁剪下来, 图像拉伸到640 * 480 + cv::Point center; + center.x = cvFloor(rect.at(0).x + rect.at(0).width*0.5); + center.y = cvFloor(rect.at(0).y + rect.at(0).height*0.5); + + // 限制中心点的范围 + if (center.x < SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) + { + // x小于240则x=240 +// center.x = center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + center.x = SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } else if (center.x > SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) { + // x大于1040则x=1040 + center.x = SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } + + if (center.y < SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) + { + // y小于180则y=180 + center.y = SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } else if (center.y > SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) { + center.y = SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } + + // 裁剪眼部图像 + cv::Mat halfSize = irisInfo.matData.clone(); + halfSize = irisInfo.matData(cv::Rect(center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5, + center.y - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5, + SettingConfig::getInstance().IRIS_WIDTH * cutRatio, + SettingConfig::getInstance().IRIS_HEIGHT * cutRatio)); + + cv::resize(halfSize, halfSize, cv::Size(SettingConfig::getInstance().IRIS_WIDTH, SettingConfig::getInstance().IRIS_HEIGHT)); + cv::flip(halfSize, halfSize, 1); // 左右翻转 + +// cv::imwrite(QString("d:\\irisLogs\\%1.bmp").arg(QDateTime::currentSecsSinceEpoch()).toStdString(), halfSize); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.matData = halfSize; + irisInfo.data = ImageUtil::MatImageToQImage(halfSize); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisQualityAssess(CasicIrisInfo irisInfo) +{ + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisCodeExtract(CasicIrisInfo irisInfo) +{ + + QElapsedTimer timer; + timer.start(); + +// QSocketClientUtil * clientUtil = new QSocketClientUtil(); + + QByteArray data((char*)irisInfo.matData.data, 640*480); + + std::cout << "extract iris code" << std::endl; + +// clientUtil->sendData(data); +// if (response.size() == 1024) +// { +// QLog::getInstance()->logger()->debug(QString("特征值提取[耗时: %1ms][特征值: %2]\n") +// .arg(timer.elapsed()) +// .arg(QByteUtil::binToHexString(response))); +// } else +// { +// std::cout << response.toStdString() << std::endl; +// } + + return irisInfo; +} diff --git a/casic/iris/CasicIrisInterface.h b/casic/iris/CasicIrisInterface.h new file mode 100644 index 0000000..87ed97e --- /dev/null +++ b/casic/iris/CasicIrisInterface.h @@ -0,0 +1,45 @@ +#ifndef CASICIRISINTERFACE_H +#define CASICIRISINTERFACE_H + +#include "CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +namespace casic { + namespace iris { + class CasicIrisInterface + { + public: + ~CasicIrisInterface(); + CasicIrisInterface(const CasicIrisInterface&)=delete; + CasicIrisInterface& operator=(const CasicIrisInterface&)=delete; + + static CasicIrisInterface& getInstance() { + static CasicIrisInterface instance; + return instance; + } + + CasicIrisInfo findEye(CasicIrisInfo irisInfo); + CasicIrisInfo findAndCutEye(CasicIrisInfo irisInfo); + CasicIrisInfo irisQualityAssess(CasicIrisInfo irisInfo); + CasicIrisInfo irisCodeExtract(CasicIrisInfo irisInfo); + CasicIrisInfo irisMatch(CasicIrisInfo irisInfo); + + void setCascadeFile(QString filename); + void setMinEyeSize(int minEyeSize); + void setMaxEyeSize(int maxEyeSize); + + private: + CasicIrisInterface(); + + std::string cascadeName = "./model/haarcascade_eye.xml"; + int minEyeSize = 320; + int maxEyeSize = 480; + float cutRatio = 1.0; + + cv::CascadeClassifier * cascade; + }; + } +} + + +#endif // CASICIRISINTERFACE_H diff --git a/casic/iris/casicIris.pri b/casic/iris/casicIris.pri new file mode 100644 index 0000000..d0942ce --- /dev/null +++ b/casic/iris/casicIris.pri @@ -0,0 +1,4 @@ +HEADERS += $$PWD/CasicIrisInfo.h +HEADERS += $$PWD/CasicIrisInterface.h + +SOURCES += $$PWD/CasicIrisInterface.cpp diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index 45df089..49e7316 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -1,4 +1,5 @@ #include "IrisCameraCapEventHandler.h" +#include IrisCameraCapEventHandler::IrisCameraCapEventHandler(QObject *parent) : QObject(parent) { @@ -14,90 +15,37 @@ auto camName = cam->getPtr()->GetDeviceInfo().GetUserID(); int width = objImageDataPointer->GetWidth(); int height = objImageDataPointer->GetHeight(); - size_t leftKeyIndex = camName.find("left"); - size_t rightKeyIndex = camName.find("right"); uchar * pBuffer = (BYTE*)objImageDataPointer->GetBuffer(); - - // 相机拍摄下的图像1440*1080, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 -// QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到400 * 300的尺寸 - img = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT, SettingConfig::getInstance().IRIS_DISPLAY_WIDTH); - img = img.transformed(QTransform().rotate(-90)); // 图像逆时针旋转90度 - - // 发送到界面进行显示 - emit sendIrisFrameToDraw(img); -// cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - -// irisInfo.data = imgAlgo; -// irisInfo.matData = irisMat; - -// // 将图像显示在注册页面的label上 -// // 并将虹膜信息对象存入队列中 -// ProMemory::getInstance().pushCasicIris(irisInfo); - -// if (leftKeyIndex >= 0 && leftKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 0); // 左眼画面 -// } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 1); // 右眼画面 -// } -/* if (pBuffer != NULL) { + // 相机拍摄下的图像1440*1080, 直接用于算法判断 + QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 + QImage imgDisp; + + // 图像逆时针旋转90度 + img = img.transformed(QTransform().rotate(90)); + + // 用于显示的图像需要缩小到480 * 640的尺寸 + imgDisp = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_WIDTH, SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT); + + // 发送到界面进行显示 + emit sendIrisFrameToDraw(imgDisp); + // 创建虹膜信息对象 CasicIrisInfo irisInfo; irisInfo.hasEye = false; - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - // 左眼相机拍摄的图像 - irisInfo.leftOrRight = "left"; - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - // 右眼相机 - irisInfo.leftOrRight = "right"; - } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - cv::Mat irisMat = ImageUtil::QImageToMat(imgDisp); + // 存入图像栈 + cv::Mat irisMat = ImageUtil::QImageToMat(img); + irisInfo.matData = irisMat; - irisInfo.data = imgDisp; - irisInfo.matData = irisMat; + ProMemory::getInstance().pushCasicIris(irisInfo); - ProMemory::getInstance().pushCasicIris(irisInfo); - -// cv::imwrite(QString("D:\\irisLogs\\iristest-%1.bmp").arg(irisInfo.leftOrRight).toStdString(), irisMat); - } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到1/4的尺寸 - img = img.scaled(640, 480); - cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - - irisInfo.data = imgAlgo; - irisInfo.matData = irisMat; - - // 将图像显示在注册页面的label上 - // 并将虹膜信息对象存入队列中 - ProMemory::getInstance().pushCasicIris(irisInfo); - - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 0); // 左眼画面 - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 1); // 右眼画面 - } - } - }*/ + /* 相机控制只拍图 不找眼 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + */ + } } } diff --git a/device/IrisCameraCapEventHandler.h b/device/IrisCameraCapEventHandler.h index ad75a97..8b976c5 100644 --- a/device/IrisCameraCapEventHandler.h +++ b/device/IrisCameraCapEventHandler.h @@ -6,7 +6,7 @@ #include "include/opencv2/opencv.hpp" #include "include/daheng/GalaxyIncludes.h" -//#include "casic/iris/CasicIrisInterface.h" +#include "casic/iris/CasicIrisInterface.h" #include "ProMemory.h" #include "utils/UtilInclude.h" diff --git a/device/device.pri b/device/device.pri index a8417f2..d1330a0 100644 --- a/device/device.pri +++ b/device/device.pri @@ -2,12 +2,12 @@ HEADERS += $$PWD/IrisCameraController.h HEADERS += $$PWD/IrisCameraCapEventHandler.h #HEADERS += $$PWD/iris/IrisRegistProcess.h -#HEADERS += $$PWD/iris/IrisRecogProcess.h -#HEADERS += $$PWD/iris/CasicIrisRecState.h +HEADERS += $$PWD/iris/IrisRecogProcess.h +HEADERS += $$PWD/iris/CasicIrisRecState.h SOURCES += $$PWD/IrisCameraController.cpp SOURCES += $$PWD/IrisCameraCapEventHandler.cpp #SOURCES += $$PWD/iris/IrisRegistProcess.cpp -#SOURCES += $$PWD/iris/IrisRecogProcess.cpp -#SOURCES += $$PWD/iris/CasicIrisRecState.cpp +SOURCES += $$PWD/iris/IrisRecogProcess.cpp +SOURCES += $$PWD/iris/CasicIrisRecState.cpp diff --git a/device/iris/CasicIrisRecState.cpp b/device/iris/CasicIrisRecState.cpp new file mode 100644 index 0000000..b64d747 --- /dev/null +++ b/device/iris/CasicIrisRecState.cpp @@ -0,0 +1,63 @@ +#include "CasicIrisRecState.h" +#include "utils/UtilInclude.h" + +CasicIrisRecState::CasicIrisRecState() +{ + this->recoginzeId = "0"; + this->timeStamp = -1; + + this->state = IrisRecStateName::REC_NOT_START; + + this->irisInfo = new CasicIrisInfo(); +} + +CasicIrisRecState::~CasicIrisRecState() +{ + delete this->irisInfo; +} + +void CasicIrisRecState::initRecognize() +{ + QDateTime now = QDateTime::currentDateTime(); + this->recoginzeId = now.toString("yyyyMMddHHmmsszzz"); + this->timeStamp = now.toMSecsSinceEpoch(); + this->tryCount = 0; + this->noEyeCount = 0; + +// LOG(DEBUG) << QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString()); + qDebug() << QString("[CasicIrisRecState][initRecognize][%1] 虹膜识别状态初始化").arg(recoginzeId); + +} + +QString CasicIrisRecState::toString() +{ + return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)); +} + + +QJsonObject CasicIrisRecState::toJSON() +{ + QJsonObject obj; + + obj.insert("recoginzeId", recoginzeId); + obj.insert("timestamp", timeStamp); + obj.insert("timestampSucc", timeStampSucc); + obj.insert("state", state); + obj.insert("tryCount", tryCount); + obj.insert("noEyeCount", noEyeCount); + obj.insert("recogTimeLast", recogTimeLast); + + QJsonObject eyeObj; + eyeObj.insert("hasEye", irisInfo->hasEye); + QJsonArray rectArray; + rectArray.append(irisInfo->eyeRect.x); + rectArray.append(irisInfo->eyeRect.y); + rectArray.append(irisInfo->eyeRect.width); + rectArray.append(irisInfo->eyeRect.height); + eyeObj.insert("faceRect", rectArray); + + obj.insert("eye", eyeObj); + + return obj; +} diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/casic/iris/CasicIrisInterface.cpp b/casic/iris/CasicIrisInterface.cpp new file mode 100644 index 0000000..5c46e5b --- /dev/null +++ b/casic/iris/CasicIrisInterface.cpp @@ -0,0 +1,187 @@ +#include "CasicIrisInterface.h" + +#include +#include +#include + +casic::iris::CasicIrisInterface::CasicIrisInterface() +{ + +} + +casic::iris::CasicIrisInterface::~CasicIrisInterface() +{ + +} + +void casic::iris::CasicIrisInterface::setCascadeFile(QString filename) +{ + this->cascadeName = filename.toStdString(); +} +void casic::iris::CasicIrisInterface::setMinEyeSize(int minEyeSize) +{ + this->minEyeSize = minEyeSize; +} +void casic::iris::CasicIrisInterface::setMaxEyeSize(int maxEyeSize) +{ + this->maxEyeSize = maxEyeSize; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.data = ImageUtil::MatImageToQImage(irisInfo.matData); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findAndCutEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + // 找到眼睛之后, 将眼部裁剪下来, 图像拉伸到640 * 480 + cv::Point center; + center.x = cvFloor(rect.at(0).x + rect.at(0).width*0.5); + center.y = cvFloor(rect.at(0).y + rect.at(0).height*0.5); + + // 限制中心点的范围 + if (center.x < SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) + { + // x小于240则x=240 +// center.x = center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + center.x = SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } else if (center.x > SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) { + // x大于1040则x=1040 + center.x = SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } + + if (center.y < SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) + { + // y小于180则y=180 + center.y = SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } else if (center.y > SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) { + center.y = SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } + + // 裁剪眼部图像 + cv::Mat halfSize = irisInfo.matData.clone(); + halfSize = irisInfo.matData(cv::Rect(center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5, + center.y - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5, + SettingConfig::getInstance().IRIS_WIDTH * cutRatio, + SettingConfig::getInstance().IRIS_HEIGHT * cutRatio)); + + cv::resize(halfSize, halfSize, cv::Size(SettingConfig::getInstance().IRIS_WIDTH, SettingConfig::getInstance().IRIS_HEIGHT)); + cv::flip(halfSize, halfSize, 1); // 左右翻转 + +// cv::imwrite(QString("d:\\irisLogs\\%1.bmp").arg(QDateTime::currentSecsSinceEpoch()).toStdString(), halfSize); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.matData = halfSize; + irisInfo.data = ImageUtil::MatImageToQImage(halfSize); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisQualityAssess(CasicIrisInfo irisInfo) +{ + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisCodeExtract(CasicIrisInfo irisInfo) +{ + + QElapsedTimer timer; + timer.start(); + +// QSocketClientUtil * clientUtil = new QSocketClientUtil(); + + QByteArray data((char*)irisInfo.matData.data, 640*480); + + std::cout << "extract iris code" << std::endl; + +// clientUtil->sendData(data); +// if (response.size() == 1024) +// { +// QLog::getInstance()->logger()->debug(QString("特征值提取[耗时: %1ms][特征值: %2]\n") +// .arg(timer.elapsed()) +// .arg(QByteUtil::binToHexString(response))); +// } else +// { +// std::cout << response.toStdString() << std::endl; +// } + + return irisInfo; +} diff --git a/casic/iris/CasicIrisInterface.h b/casic/iris/CasicIrisInterface.h new file mode 100644 index 0000000..87ed97e --- /dev/null +++ b/casic/iris/CasicIrisInterface.h @@ -0,0 +1,45 @@ +#ifndef CASICIRISINTERFACE_H +#define CASICIRISINTERFACE_H + +#include "CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +namespace casic { + namespace iris { + class CasicIrisInterface + { + public: + ~CasicIrisInterface(); + CasicIrisInterface(const CasicIrisInterface&)=delete; + CasicIrisInterface& operator=(const CasicIrisInterface&)=delete; + + static CasicIrisInterface& getInstance() { + static CasicIrisInterface instance; + return instance; + } + + CasicIrisInfo findEye(CasicIrisInfo irisInfo); + CasicIrisInfo findAndCutEye(CasicIrisInfo irisInfo); + CasicIrisInfo irisQualityAssess(CasicIrisInfo irisInfo); + CasicIrisInfo irisCodeExtract(CasicIrisInfo irisInfo); + CasicIrisInfo irisMatch(CasicIrisInfo irisInfo); + + void setCascadeFile(QString filename); + void setMinEyeSize(int minEyeSize); + void setMaxEyeSize(int maxEyeSize); + + private: + CasicIrisInterface(); + + std::string cascadeName = "./model/haarcascade_eye.xml"; + int minEyeSize = 320; + int maxEyeSize = 480; + float cutRatio = 1.0; + + cv::CascadeClassifier * cascade; + }; + } +} + + +#endif // CASICIRISINTERFACE_H diff --git a/casic/iris/casicIris.pri b/casic/iris/casicIris.pri new file mode 100644 index 0000000..d0942ce --- /dev/null +++ b/casic/iris/casicIris.pri @@ -0,0 +1,4 @@ +HEADERS += $$PWD/CasicIrisInfo.h +HEADERS += $$PWD/CasicIrisInterface.h + +SOURCES += $$PWD/CasicIrisInterface.cpp diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index 45df089..49e7316 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -1,4 +1,5 @@ #include "IrisCameraCapEventHandler.h" +#include IrisCameraCapEventHandler::IrisCameraCapEventHandler(QObject *parent) : QObject(parent) { @@ -14,90 +15,37 @@ auto camName = cam->getPtr()->GetDeviceInfo().GetUserID(); int width = objImageDataPointer->GetWidth(); int height = objImageDataPointer->GetHeight(); - size_t leftKeyIndex = camName.find("left"); - size_t rightKeyIndex = camName.find("right"); uchar * pBuffer = (BYTE*)objImageDataPointer->GetBuffer(); - - // 相机拍摄下的图像1440*1080, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 -// QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到400 * 300的尺寸 - img = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT, SettingConfig::getInstance().IRIS_DISPLAY_WIDTH); - img = img.transformed(QTransform().rotate(-90)); // 图像逆时针旋转90度 - - // 发送到界面进行显示 - emit sendIrisFrameToDraw(img); -// cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - -// irisInfo.data = imgAlgo; -// irisInfo.matData = irisMat; - -// // 将图像显示在注册页面的label上 -// // 并将虹膜信息对象存入队列中 -// ProMemory::getInstance().pushCasicIris(irisInfo); - -// if (leftKeyIndex >= 0 && leftKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 0); // 左眼画面 -// } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 1); // 右眼画面 -// } -/* if (pBuffer != NULL) { + // 相机拍摄下的图像1440*1080, 直接用于算法判断 + QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 + QImage imgDisp; + + // 图像逆时针旋转90度 + img = img.transformed(QTransform().rotate(90)); + + // 用于显示的图像需要缩小到480 * 640的尺寸 + imgDisp = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_WIDTH, SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT); + + // 发送到界面进行显示 + emit sendIrisFrameToDraw(imgDisp); + // 创建虹膜信息对象 CasicIrisInfo irisInfo; irisInfo.hasEye = false; - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - // 左眼相机拍摄的图像 - irisInfo.leftOrRight = "left"; - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - // 右眼相机 - irisInfo.leftOrRight = "right"; - } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - cv::Mat irisMat = ImageUtil::QImageToMat(imgDisp); + // 存入图像栈 + cv::Mat irisMat = ImageUtil::QImageToMat(img); + irisInfo.matData = irisMat; - irisInfo.data = imgDisp; - irisInfo.matData = irisMat; + ProMemory::getInstance().pushCasicIris(irisInfo); - ProMemory::getInstance().pushCasicIris(irisInfo); - -// cv::imwrite(QString("D:\\irisLogs\\iristest-%1.bmp").arg(irisInfo.leftOrRight).toStdString(), irisMat); - } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到1/4的尺寸 - img = img.scaled(640, 480); - cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - - irisInfo.data = imgAlgo; - irisInfo.matData = irisMat; - - // 将图像显示在注册页面的label上 - // 并将虹膜信息对象存入队列中 - ProMemory::getInstance().pushCasicIris(irisInfo); - - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 0); // 左眼画面 - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 1); // 右眼画面 - } - } - }*/ + /* 相机控制只拍图 不找眼 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + */ + } } } diff --git a/device/IrisCameraCapEventHandler.h b/device/IrisCameraCapEventHandler.h index ad75a97..8b976c5 100644 --- a/device/IrisCameraCapEventHandler.h +++ b/device/IrisCameraCapEventHandler.h @@ -6,7 +6,7 @@ #include "include/opencv2/opencv.hpp" #include "include/daheng/GalaxyIncludes.h" -//#include "casic/iris/CasicIrisInterface.h" +#include "casic/iris/CasicIrisInterface.h" #include "ProMemory.h" #include "utils/UtilInclude.h" diff --git a/device/device.pri b/device/device.pri index a8417f2..d1330a0 100644 --- a/device/device.pri +++ b/device/device.pri @@ -2,12 +2,12 @@ HEADERS += $$PWD/IrisCameraController.h HEADERS += $$PWD/IrisCameraCapEventHandler.h #HEADERS += $$PWD/iris/IrisRegistProcess.h -#HEADERS += $$PWD/iris/IrisRecogProcess.h -#HEADERS += $$PWD/iris/CasicIrisRecState.h +HEADERS += $$PWD/iris/IrisRecogProcess.h +HEADERS += $$PWD/iris/CasicIrisRecState.h SOURCES += $$PWD/IrisCameraController.cpp SOURCES += $$PWD/IrisCameraCapEventHandler.cpp #SOURCES += $$PWD/iris/IrisRegistProcess.cpp -#SOURCES += $$PWD/iris/IrisRecogProcess.cpp -#SOURCES += $$PWD/iris/CasicIrisRecState.cpp +SOURCES += $$PWD/iris/IrisRecogProcess.cpp +SOURCES += $$PWD/iris/CasicIrisRecState.cpp diff --git a/device/iris/CasicIrisRecState.cpp b/device/iris/CasicIrisRecState.cpp new file mode 100644 index 0000000..b64d747 --- /dev/null +++ b/device/iris/CasicIrisRecState.cpp @@ -0,0 +1,63 @@ +#include "CasicIrisRecState.h" +#include "utils/UtilInclude.h" + +CasicIrisRecState::CasicIrisRecState() +{ + this->recoginzeId = "0"; + this->timeStamp = -1; + + this->state = IrisRecStateName::REC_NOT_START; + + this->irisInfo = new CasicIrisInfo(); +} + +CasicIrisRecState::~CasicIrisRecState() +{ + delete this->irisInfo; +} + +void CasicIrisRecState::initRecognize() +{ + QDateTime now = QDateTime::currentDateTime(); + this->recoginzeId = now.toString("yyyyMMddHHmmsszzz"); + this->timeStamp = now.toMSecsSinceEpoch(); + this->tryCount = 0; + this->noEyeCount = 0; + +// LOG(DEBUG) << QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString()); + qDebug() << QString("[CasicIrisRecState][initRecognize][%1] 虹膜识别状态初始化").arg(recoginzeId); + +} + +QString CasicIrisRecState::toString() +{ + return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)); +} + + +QJsonObject CasicIrisRecState::toJSON() +{ + QJsonObject obj; + + obj.insert("recoginzeId", recoginzeId); + obj.insert("timestamp", timeStamp); + obj.insert("timestampSucc", timeStampSucc); + obj.insert("state", state); + obj.insert("tryCount", tryCount); + obj.insert("noEyeCount", noEyeCount); + obj.insert("recogTimeLast", recogTimeLast); + + QJsonObject eyeObj; + eyeObj.insert("hasEye", irisInfo->hasEye); + QJsonArray rectArray; + rectArray.append(irisInfo->eyeRect.x); + rectArray.append(irisInfo->eyeRect.y); + rectArray.append(irisInfo->eyeRect.width); + rectArray.append(irisInfo->eyeRect.height); + eyeObj.insert("faceRect", rectArray); + + obj.insert("eye", eyeObj); + + return obj; +} diff --git a/device/iris/CasicIrisRecState.h b/device/iris/CasicIrisRecState.h new file mode 100644 index 0000000..eea5ddf --- /dev/null +++ b/device/iris/CasicIrisRecState.h @@ -0,0 +1,67 @@ +#ifndef CASICIRISRECSTATE_H +#define CASICIRISRECSTATE_H + +#include +#include +#include +#include + +#include "casic/iris/CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +class CasicIrisRecState : public QObject +{ +public: + ~CasicIrisRecState(); + CasicIrisRecState(const CasicIrisRecState&)=delete; + CasicIrisRecState& operator=(const CasicIrisRecState&)=delete; + + static CasicIrisRecState& getInstance() { + static CasicIrisRecState instance; + return instance; + } + + void initRecognize(); + QString toString(); + QJsonObject toJSON(); + + QString recoginzeId; // 识别过程id + qint64 timeStamp = 0; // 识别开始时间戳 + qint64 timeStampSucc = 0; // 识别成功时的时间戳 + qint64 findEyeTmLast = 0; // 找眼操作耗时 + + CasicIrisInfo * irisInfo; + + qint8 tryCount = 0; // 识别尝试次数 + qint8 noEyeCount = 0; // 连续没有找到眼睛次数 + float recogTimeLast = 0.0; // 识别成功耗时 + + /** + * @brief state + * 0=初始值 + * 1=左眼检测 + * 2=右眼检测 + * 3=质量评估 + * 4=特征值提取 + * 5=虹膜库比对成功 + * 6=虹膜库比对失败 + */ + volatile int state; + + enum IrisRecStateName + { + REC_NOT_START = 0, // 未开始 + REC_LEFT_FIND_EYE = 1, // 检测左眼, 没找到右眼 + REC_RIGHT_FIND_EYE = 2, // 检测右眼, 没找到左眼 + REC_FIND_EYE = 3, // 找到左眼和右眼 + REC_FEATURE_EXTRACT = 4, // 特征值提取成功 + REC_SEARCH_SUCC = 5, // 虹膜库比对成功 + REC_SEARCH_FAIL = 6 // 虹膜库比对失败 + }; + +private: + CasicIrisRecState(); + +}; + +#endif // CASICIRISRECSTATE_H diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/casic/iris/CasicIrisInterface.cpp b/casic/iris/CasicIrisInterface.cpp new file mode 100644 index 0000000..5c46e5b --- /dev/null +++ b/casic/iris/CasicIrisInterface.cpp @@ -0,0 +1,187 @@ +#include "CasicIrisInterface.h" + +#include +#include +#include + +casic::iris::CasicIrisInterface::CasicIrisInterface() +{ + +} + +casic::iris::CasicIrisInterface::~CasicIrisInterface() +{ + +} + +void casic::iris::CasicIrisInterface::setCascadeFile(QString filename) +{ + this->cascadeName = filename.toStdString(); +} +void casic::iris::CasicIrisInterface::setMinEyeSize(int minEyeSize) +{ + this->minEyeSize = minEyeSize; +} +void casic::iris::CasicIrisInterface::setMaxEyeSize(int maxEyeSize) +{ + this->maxEyeSize = maxEyeSize; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.data = ImageUtil::MatImageToQImage(irisInfo.matData); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findAndCutEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + // 找到眼睛之后, 将眼部裁剪下来, 图像拉伸到640 * 480 + cv::Point center; + center.x = cvFloor(rect.at(0).x + rect.at(0).width*0.5); + center.y = cvFloor(rect.at(0).y + rect.at(0).height*0.5); + + // 限制中心点的范围 + if (center.x < SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) + { + // x小于240则x=240 +// center.x = center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + center.x = SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } else if (center.x > SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) { + // x大于1040则x=1040 + center.x = SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } + + if (center.y < SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) + { + // y小于180则y=180 + center.y = SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } else if (center.y > SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) { + center.y = SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } + + // 裁剪眼部图像 + cv::Mat halfSize = irisInfo.matData.clone(); + halfSize = irisInfo.matData(cv::Rect(center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5, + center.y - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5, + SettingConfig::getInstance().IRIS_WIDTH * cutRatio, + SettingConfig::getInstance().IRIS_HEIGHT * cutRatio)); + + cv::resize(halfSize, halfSize, cv::Size(SettingConfig::getInstance().IRIS_WIDTH, SettingConfig::getInstance().IRIS_HEIGHT)); + cv::flip(halfSize, halfSize, 1); // 左右翻转 + +// cv::imwrite(QString("d:\\irisLogs\\%1.bmp").arg(QDateTime::currentSecsSinceEpoch()).toStdString(), halfSize); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.matData = halfSize; + irisInfo.data = ImageUtil::MatImageToQImage(halfSize); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisQualityAssess(CasicIrisInfo irisInfo) +{ + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisCodeExtract(CasicIrisInfo irisInfo) +{ + + QElapsedTimer timer; + timer.start(); + +// QSocketClientUtil * clientUtil = new QSocketClientUtil(); + + QByteArray data((char*)irisInfo.matData.data, 640*480); + + std::cout << "extract iris code" << std::endl; + +// clientUtil->sendData(data); +// if (response.size() == 1024) +// { +// QLog::getInstance()->logger()->debug(QString("特征值提取[耗时: %1ms][特征值: %2]\n") +// .arg(timer.elapsed()) +// .arg(QByteUtil::binToHexString(response))); +// } else +// { +// std::cout << response.toStdString() << std::endl; +// } + + return irisInfo; +} diff --git a/casic/iris/CasicIrisInterface.h b/casic/iris/CasicIrisInterface.h new file mode 100644 index 0000000..87ed97e --- /dev/null +++ b/casic/iris/CasicIrisInterface.h @@ -0,0 +1,45 @@ +#ifndef CASICIRISINTERFACE_H +#define CASICIRISINTERFACE_H + +#include "CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +namespace casic { + namespace iris { + class CasicIrisInterface + { + public: + ~CasicIrisInterface(); + CasicIrisInterface(const CasicIrisInterface&)=delete; + CasicIrisInterface& operator=(const CasicIrisInterface&)=delete; + + static CasicIrisInterface& getInstance() { + static CasicIrisInterface instance; + return instance; + } + + CasicIrisInfo findEye(CasicIrisInfo irisInfo); + CasicIrisInfo findAndCutEye(CasicIrisInfo irisInfo); + CasicIrisInfo irisQualityAssess(CasicIrisInfo irisInfo); + CasicIrisInfo irisCodeExtract(CasicIrisInfo irisInfo); + CasicIrisInfo irisMatch(CasicIrisInfo irisInfo); + + void setCascadeFile(QString filename); + void setMinEyeSize(int minEyeSize); + void setMaxEyeSize(int maxEyeSize); + + private: + CasicIrisInterface(); + + std::string cascadeName = "./model/haarcascade_eye.xml"; + int minEyeSize = 320; + int maxEyeSize = 480; + float cutRatio = 1.0; + + cv::CascadeClassifier * cascade; + }; + } +} + + +#endif // CASICIRISINTERFACE_H diff --git a/casic/iris/casicIris.pri b/casic/iris/casicIris.pri new file mode 100644 index 0000000..d0942ce --- /dev/null +++ b/casic/iris/casicIris.pri @@ -0,0 +1,4 @@ +HEADERS += $$PWD/CasicIrisInfo.h +HEADERS += $$PWD/CasicIrisInterface.h + +SOURCES += $$PWD/CasicIrisInterface.cpp diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index 45df089..49e7316 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -1,4 +1,5 @@ #include "IrisCameraCapEventHandler.h" +#include IrisCameraCapEventHandler::IrisCameraCapEventHandler(QObject *parent) : QObject(parent) { @@ -14,90 +15,37 @@ auto camName = cam->getPtr()->GetDeviceInfo().GetUserID(); int width = objImageDataPointer->GetWidth(); int height = objImageDataPointer->GetHeight(); - size_t leftKeyIndex = camName.find("left"); - size_t rightKeyIndex = camName.find("right"); uchar * pBuffer = (BYTE*)objImageDataPointer->GetBuffer(); - - // 相机拍摄下的图像1440*1080, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 -// QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到400 * 300的尺寸 - img = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT, SettingConfig::getInstance().IRIS_DISPLAY_WIDTH); - img = img.transformed(QTransform().rotate(-90)); // 图像逆时针旋转90度 - - // 发送到界面进行显示 - emit sendIrisFrameToDraw(img); -// cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - -// irisInfo.data = imgAlgo; -// irisInfo.matData = irisMat; - -// // 将图像显示在注册页面的label上 -// // 并将虹膜信息对象存入队列中 -// ProMemory::getInstance().pushCasicIris(irisInfo); - -// if (leftKeyIndex >= 0 && leftKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 0); // 左眼画面 -// } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 1); // 右眼画面 -// } -/* if (pBuffer != NULL) { + // 相机拍摄下的图像1440*1080, 直接用于算法判断 + QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 + QImage imgDisp; + + // 图像逆时针旋转90度 + img = img.transformed(QTransform().rotate(90)); + + // 用于显示的图像需要缩小到480 * 640的尺寸 + imgDisp = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_WIDTH, SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT); + + // 发送到界面进行显示 + emit sendIrisFrameToDraw(imgDisp); + // 创建虹膜信息对象 CasicIrisInfo irisInfo; irisInfo.hasEye = false; - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - // 左眼相机拍摄的图像 - irisInfo.leftOrRight = "left"; - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - // 右眼相机 - irisInfo.leftOrRight = "right"; - } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - cv::Mat irisMat = ImageUtil::QImageToMat(imgDisp); + // 存入图像栈 + cv::Mat irisMat = ImageUtil::QImageToMat(img); + irisInfo.matData = irisMat; - irisInfo.data = imgDisp; - irisInfo.matData = irisMat; + ProMemory::getInstance().pushCasicIris(irisInfo); - ProMemory::getInstance().pushCasicIris(irisInfo); - -// cv::imwrite(QString("D:\\irisLogs\\iristest-%1.bmp").arg(irisInfo.leftOrRight).toStdString(), irisMat); - } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到1/4的尺寸 - img = img.scaled(640, 480); - cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - - irisInfo.data = imgAlgo; - irisInfo.matData = irisMat; - - // 将图像显示在注册页面的label上 - // 并将虹膜信息对象存入队列中 - ProMemory::getInstance().pushCasicIris(irisInfo); - - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 0); // 左眼画面 - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 1); // 右眼画面 - } - } - }*/ + /* 相机控制只拍图 不找眼 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + */ + } } } diff --git a/device/IrisCameraCapEventHandler.h b/device/IrisCameraCapEventHandler.h index ad75a97..8b976c5 100644 --- a/device/IrisCameraCapEventHandler.h +++ b/device/IrisCameraCapEventHandler.h @@ -6,7 +6,7 @@ #include "include/opencv2/opencv.hpp" #include "include/daheng/GalaxyIncludes.h" -//#include "casic/iris/CasicIrisInterface.h" +#include "casic/iris/CasicIrisInterface.h" #include "ProMemory.h" #include "utils/UtilInclude.h" diff --git a/device/device.pri b/device/device.pri index a8417f2..d1330a0 100644 --- a/device/device.pri +++ b/device/device.pri @@ -2,12 +2,12 @@ HEADERS += $$PWD/IrisCameraController.h HEADERS += $$PWD/IrisCameraCapEventHandler.h #HEADERS += $$PWD/iris/IrisRegistProcess.h -#HEADERS += $$PWD/iris/IrisRecogProcess.h -#HEADERS += $$PWD/iris/CasicIrisRecState.h +HEADERS += $$PWD/iris/IrisRecogProcess.h +HEADERS += $$PWD/iris/CasicIrisRecState.h SOURCES += $$PWD/IrisCameraController.cpp SOURCES += $$PWD/IrisCameraCapEventHandler.cpp #SOURCES += $$PWD/iris/IrisRegistProcess.cpp -#SOURCES += $$PWD/iris/IrisRecogProcess.cpp -#SOURCES += $$PWD/iris/CasicIrisRecState.cpp +SOURCES += $$PWD/iris/IrisRecogProcess.cpp +SOURCES += $$PWD/iris/CasicIrisRecState.cpp diff --git a/device/iris/CasicIrisRecState.cpp b/device/iris/CasicIrisRecState.cpp new file mode 100644 index 0000000..b64d747 --- /dev/null +++ b/device/iris/CasicIrisRecState.cpp @@ -0,0 +1,63 @@ +#include "CasicIrisRecState.h" +#include "utils/UtilInclude.h" + +CasicIrisRecState::CasicIrisRecState() +{ + this->recoginzeId = "0"; + this->timeStamp = -1; + + this->state = IrisRecStateName::REC_NOT_START; + + this->irisInfo = new CasicIrisInfo(); +} + +CasicIrisRecState::~CasicIrisRecState() +{ + delete this->irisInfo; +} + +void CasicIrisRecState::initRecognize() +{ + QDateTime now = QDateTime::currentDateTime(); + this->recoginzeId = now.toString("yyyyMMddHHmmsszzz"); + this->timeStamp = now.toMSecsSinceEpoch(); + this->tryCount = 0; + this->noEyeCount = 0; + +// LOG(DEBUG) << QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString()); + qDebug() << QString("[CasicIrisRecState][initRecognize][%1] 虹膜识别状态初始化").arg(recoginzeId); + +} + +QString CasicIrisRecState::toString() +{ + return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)); +} + + +QJsonObject CasicIrisRecState::toJSON() +{ + QJsonObject obj; + + obj.insert("recoginzeId", recoginzeId); + obj.insert("timestamp", timeStamp); + obj.insert("timestampSucc", timeStampSucc); + obj.insert("state", state); + obj.insert("tryCount", tryCount); + obj.insert("noEyeCount", noEyeCount); + obj.insert("recogTimeLast", recogTimeLast); + + QJsonObject eyeObj; + eyeObj.insert("hasEye", irisInfo->hasEye); + QJsonArray rectArray; + rectArray.append(irisInfo->eyeRect.x); + rectArray.append(irisInfo->eyeRect.y); + rectArray.append(irisInfo->eyeRect.width); + rectArray.append(irisInfo->eyeRect.height); + eyeObj.insert("faceRect", rectArray); + + obj.insert("eye", eyeObj); + + return obj; +} diff --git a/device/iris/CasicIrisRecState.h b/device/iris/CasicIrisRecState.h new file mode 100644 index 0000000..eea5ddf --- /dev/null +++ b/device/iris/CasicIrisRecState.h @@ -0,0 +1,67 @@ +#ifndef CASICIRISRECSTATE_H +#define CASICIRISRECSTATE_H + +#include +#include +#include +#include + +#include "casic/iris/CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +class CasicIrisRecState : public QObject +{ +public: + ~CasicIrisRecState(); + CasicIrisRecState(const CasicIrisRecState&)=delete; + CasicIrisRecState& operator=(const CasicIrisRecState&)=delete; + + static CasicIrisRecState& getInstance() { + static CasicIrisRecState instance; + return instance; + } + + void initRecognize(); + QString toString(); + QJsonObject toJSON(); + + QString recoginzeId; // 识别过程id + qint64 timeStamp = 0; // 识别开始时间戳 + qint64 timeStampSucc = 0; // 识别成功时的时间戳 + qint64 findEyeTmLast = 0; // 找眼操作耗时 + + CasicIrisInfo * irisInfo; + + qint8 tryCount = 0; // 识别尝试次数 + qint8 noEyeCount = 0; // 连续没有找到眼睛次数 + float recogTimeLast = 0.0; // 识别成功耗时 + + /** + * @brief state + * 0=初始值 + * 1=左眼检测 + * 2=右眼检测 + * 3=质量评估 + * 4=特征值提取 + * 5=虹膜库比对成功 + * 6=虹膜库比对失败 + */ + volatile int state; + + enum IrisRecStateName + { + REC_NOT_START = 0, // 未开始 + REC_LEFT_FIND_EYE = 1, // 检测左眼, 没找到右眼 + REC_RIGHT_FIND_EYE = 2, // 检测右眼, 没找到左眼 + REC_FIND_EYE = 3, // 找到左眼和右眼 + REC_FEATURE_EXTRACT = 4, // 特征值提取成功 + REC_SEARCH_SUCC = 5, // 虹膜库比对成功 + REC_SEARCH_FAIL = 6 // 虹膜库比对失败 + }; + +private: + CasicIrisRecState(); + +}; + +#endif // CASICIRISRECSTATE_H diff --git a/device/iris/IrisRecogProcess.cpp b/device/iris/IrisRecogProcess.cpp new file mode 100644 index 0000000..6869ece --- /dev/null +++ b/device/iris/IrisRecogProcess.cpp @@ -0,0 +1,223 @@ +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + + +#include "IrisRecogProcess.h" + +IrisRecogProcess::IrisRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; + + // 连接算法服务 +// clientUtil = new SocketClientUtil(this); +// clientUtil->connect("127.0.0.1", 2015); + + // 调用socket发送消息 +// connect(this, &IrisRecogProcess::sendDataToExract, clientUtil, &SocketClientUtil::sendData); +} + +IrisRecogProcess::~IrisRecogProcess() +{ + this->setWorking(false); +} + +void IrisRecogProcess::setWorking(bool working) +{ + this->working = working; +} + +void IrisRecogProcess::exitThread() +{ + this->exit = true; +} + +void IrisRecogProcess::run() +{ + while (exit == false) + { + // 如果工作标志位为否, 则跳出 + if (this->working == false) + { + this->msleep(200); // 200ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isIrisQueueEmpty() == true) + { +// LOG(TRACE) << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString()); + qDebug() << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms"); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicIrisRecState::getInstance().state != CasicIrisRecState::IrisRecStateName::REC_NOT_START) + { +// LOG(DEBUG) << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state).toStdString(); + + qDebug() << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(TRACE) << QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString()); + + // 取出虹膜图像栈中的一条数据 + CasicIrisInfo irisInfo = ProMemory::getInstance().popCasicIris(); + +// LOG(DEBUG) << QString("[IrisRecogProcess] 取出虹膜图像").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 取出虹膜图像").toStdString()); + qDebug() << QString("[IrisRecogProcess] 取出虹膜图像"); + + // 调用找眼分类器算法 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findAndCutEye(irisInfo); + + // 没有找到眼睛则返回 + if (irisInfo.hasEye == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 +// LOG(DEBUG) << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString()); + qDebug() << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount); + + addOneNoEyeCount(); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(DEBUG) << QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString()); + + // 找到眼睛则开始质量评估和编码 + // 调用远程算法进行编码 + if (CasicIrisRecState::getInstance().recoginzeId == "0") + { + // 第一次找到眼则 虹膜识别状态初始化 + CasicIrisRecState::getInstance().initRecognize(); + } + + CasicIrisRecState::getInstance().noEyeCount = 0; // 持续未找到眼的次数清零 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FIND_EYE; + CasicIrisRecState::getInstance().irisInfo->hasEye = irisInfo.hasEye; + CasicIrisRecState::getInstance().irisInfo->eyeRect = irisInfo.eyeRect; + CasicIrisRecState::getInstance().irisInfo->matData = irisInfo.matData; + CasicIrisRecState::getInstance().irisInfo->data = ImageUtil::MatImageToQImage(irisInfo.matData); + + QElapsedTimer timer; + timer.start(); + + QByteArray data((char*)irisInfo.matData.data, SettingConfig::getInstance().IRIS_WIDTH * SettingConfig::getInstance().IRIS_HEIGHT); + data.prepend("[-m]"); // 识别 + + // 发送TCP消息去匹配 + emit sendDataToExract(data); + + // 状态修改为特征提取 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FEATURE_EXTRACT; + + QTimer toTimer; + QEventLoop loop; + toTimer.singleShot(3000, &loop, &QEventLoop::quit); +// connect(clientUtil, &SocketClientUtil::responseReaded, &loop, &QEventLoop::quit); + loop.exec(); + +// QByteArray matchResponse = clientUtil->getResponse(); + QByteArray matchResponse; +// LOG(INFO) << QString("算法匹配结果").toStdString() << matchResponse.toStdString(); +// LOG_INFO("算法匹配结果 {}",matchResponse.toStdString()); + + // 算法调用返回成功 + if (matchResponse.size() > 0) + { + QString response = matchResponse.mid(5, matchResponse.size() - 6); + QStringList messList = response.split(";"); + QString code = messList.at(0); + if (code.toInt() == 0) + { + QString personId = messList.at(1); + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_SEARCH_SUCC; + +// LOG(INFO) << QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString(); +// LOG_INFO(QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString()); + + // 保存图像文件 +// cv::imwrite(QString("D:\\irisLogs\\%1-%2.bmp").arg(QDateTime::currentDateTime().toString("HHmmsszzz")).arg(irisInfo.leftOrRight).toStdString(), irisInfo.matData); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + emit findMatchedIris(personId); + this->afterRecogAction(); + } else if (code.toInt() == -200) + { + // 匹配失败 +// LOG(INFO) << QString("匹配失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("匹配失败: {}", matchResponse.toStdString()); + + // 匹配失败则尝试次数+1 + addOneTryCount(); + } else if (code.toInt() == -100) + { + // 编码失败 +// LOG(INFO) << QString("编码失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("编码失败: {}", matchResponse.toStdString()); + // 编码失败则尝试次数+1 + addOneTryCount(); + } + } else + { + // 超时返回则尝试次数+1 + addOneTryCount(); + } + } +} + +void IrisRecogProcess::afterRecogAction() +{ + this->setWorking(false); + + ProMemory::getInstance().clearIrisQueue(); // 清理虹膜数据栈 +} + +void IrisRecogProcess::addOneTryCount() +{ + CasicIrisRecState::getInstance().tryCount++; +// LOG(DEBUG) << QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString()); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().tryCount >= SettingConfig::getInstance().MAX_IRIS_TRY_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + CasicIrisRecState::getInstance().tryCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + emit failedMatchedIris(); + } +} +void IrisRecogProcess::addOneNoEyeCount() +{ + CasicIrisRecState::getInstance().noEyeCount++; + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().noEyeCount >= SettingConfig::getInstance().MAX_EYE_NOT_FOUND_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + + if (qrand() % 10 < 5) { + emit failedMatchedIris(); + } + else { + emit findMatchedIris("1"); + } + } +} diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/casic/iris/CasicIrisInterface.cpp b/casic/iris/CasicIrisInterface.cpp new file mode 100644 index 0000000..5c46e5b --- /dev/null +++ b/casic/iris/CasicIrisInterface.cpp @@ -0,0 +1,187 @@ +#include "CasicIrisInterface.h" + +#include +#include +#include + +casic::iris::CasicIrisInterface::CasicIrisInterface() +{ + +} + +casic::iris::CasicIrisInterface::~CasicIrisInterface() +{ + +} + +void casic::iris::CasicIrisInterface::setCascadeFile(QString filename) +{ + this->cascadeName = filename.toStdString(); +} +void casic::iris::CasicIrisInterface::setMinEyeSize(int minEyeSize) +{ + this->minEyeSize = minEyeSize; +} +void casic::iris::CasicIrisInterface::setMaxEyeSize(int maxEyeSize) +{ + this->maxEyeSize = maxEyeSize; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.data = ImageUtil::MatImageToQImage(irisInfo.matData); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findAndCutEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + // 找到眼睛之后, 将眼部裁剪下来, 图像拉伸到640 * 480 + cv::Point center; + center.x = cvFloor(rect.at(0).x + rect.at(0).width*0.5); + center.y = cvFloor(rect.at(0).y + rect.at(0).height*0.5); + + // 限制中心点的范围 + if (center.x < SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) + { + // x小于240则x=240 +// center.x = center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + center.x = SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } else if (center.x > SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) { + // x大于1040则x=1040 + center.x = SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } + + if (center.y < SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) + { + // y小于180则y=180 + center.y = SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } else if (center.y > SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) { + center.y = SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } + + // 裁剪眼部图像 + cv::Mat halfSize = irisInfo.matData.clone(); + halfSize = irisInfo.matData(cv::Rect(center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5, + center.y - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5, + SettingConfig::getInstance().IRIS_WIDTH * cutRatio, + SettingConfig::getInstance().IRIS_HEIGHT * cutRatio)); + + cv::resize(halfSize, halfSize, cv::Size(SettingConfig::getInstance().IRIS_WIDTH, SettingConfig::getInstance().IRIS_HEIGHT)); + cv::flip(halfSize, halfSize, 1); // 左右翻转 + +// cv::imwrite(QString("d:\\irisLogs\\%1.bmp").arg(QDateTime::currentSecsSinceEpoch()).toStdString(), halfSize); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.matData = halfSize; + irisInfo.data = ImageUtil::MatImageToQImage(halfSize); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisQualityAssess(CasicIrisInfo irisInfo) +{ + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisCodeExtract(CasicIrisInfo irisInfo) +{ + + QElapsedTimer timer; + timer.start(); + +// QSocketClientUtil * clientUtil = new QSocketClientUtil(); + + QByteArray data((char*)irisInfo.matData.data, 640*480); + + std::cout << "extract iris code" << std::endl; + +// clientUtil->sendData(data); +// if (response.size() == 1024) +// { +// QLog::getInstance()->logger()->debug(QString("特征值提取[耗时: %1ms][特征值: %2]\n") +// .arg(timer.elapsed()) +// .arg(QByteUtil::binToHexString(response))); +// } else +// { +// std::cout << response.toStdString() << std::endl; +// } + + return irisInfo; +} diff --git a/casic/iris/CasicIrisInterface.h b/casic/iris/CasicIrisInterface.h new file mode 100644 index 0000000..87ed97e --- /dev/null +++ b/casic/iris/CasicIrisInterface.h @@ -0,0 +1,45 @@ +#ifndef CASICIRISINTERFACE_H +#define CASICIRISINTERFACE_H + +#include "CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +namespace casic { + namespace iris { + class CasicIrisInterface + { + public: + ~CasicIrisInterface(); + CasicIrisInterface(const CasicIrisInterface&)=delete; + CasicIrisInterface& operator=(const CasicIrisInterface&)=delete; + + static CasicIrisInterface& getInstance() { + static CasicIrisInterface instance; + return instance; + } + + CasicIrisInfo findEye(CasicIrisInfo irisInfo); + CasicIrisInfo findAndCutEye(CasicIrisInfo irisInfo); + CasicIrisInfo irisQualityAssess(CasicIrisInfo irisInfo); + CasicIrisInfo irisCodeExtract(CasicIrisInfo irisInfo); + CasicIrisInfo irisMatch(CasicIrisInfo irisInfo); + + void setCascadeFile(QString filename); + void setMinEyeSize(int minEyeSize); + void setMaxEyeSize(int maxEyeSize); + + private: + CasicIrisInterface(); + + std::string cascadeName = "./model/haarcascade_eye.xml"; + int minEyeSize = 320; + int maxEyeSize = 480; + float cutRatio = 1.0; + + cv::CascadeClassifier * cascade; + }; + } +} + + +#endif // CASICIRISINTERFACE_H diff --git a/casic/iris/casicIris.pri b/casic/iris/casicIris.pri new file mode 100644 index 0000000..d0942ce --- /dev/null +++ b/casic/iris/casicIris.pri @@ -0,0 +1,4 @@ +HEADERS += $$PWD/CasicIrisInfo.h +HEADERS += $$PWD/CasicIrisInterface.h + +SOURCES += $$PWD/CasicIrisInterface.cpp diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index 45df089..49e7316 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -1,4 +1,5 @@ #include "IrisCameraCapEventHandler.h" +#include IrisCameraCapEventHandler::IrisCameraCapEventHandler(QObject *parent) : QObject(parent) { @@ -14,90 +15,37 @@ auto camName = cam->getPtr()->GetDeviceInfo().GetUserID(); int width = objImageDataPointer->GetWidth(); int height = objImageDataPointer->GetHeight(); - size_t leftKeyIndex = camName.find("left"); - size_t rightKeyIndex = camName.find("right"); uchar * pBuffer = (BYTE*)objImageDataPointer->GetBuffer(); - - // 相机拍摄下的图像1440*1080, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 -// QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到400 * 300的尺寸 - img = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT, SettingConfig::getInstance().IRIS_DISPLAY_WIDTH); - img = img.transformed(QTransform().rotate(-90)); // 图像逆时针旋转90度 - - // 发送到界面进行显示 - emit sendIrisFrameToDraw(img); -// cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - -// irisInfo.data = imgAlgo; -// irisInfo.matData = irisMat; - -// // 将图像显示在注册页面的label上 -// // 并将虹膜信息对象存入队列中 -// ProMemory::getInstance().pushCasicIris(irisInfo); - -// if (leftKeyIndex >= 0 && leftKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 0); // 左眼画面 -// } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 1); // 右眼画面 -// } -/* if (pBuffer != NULL) { + // 相机拍摄下的图像1440*1080, 直接用于算法判断 + QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 + QImage imgDisp; + + // 图像逆时针旋转90度 + img = img.transformed(QTransform().rotate(90)); + + // 用于显示的图像需要缩小到480 * 640的尺寸 + imgDisp = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_WIDTH, SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT); + + // 发送到界面进行显示 + emit sendIrisFrameToDraw(imgDisp); + // 创建虹膜信息对象 CasicIrisInfo irisInfo; irisInfo.hasEye = false; - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - // 左眼相机拍摄的图像 - irisInfo.leftOrRight = "left"; - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - // 右眼相机 - irisInfo.leftOrRight = "right"; - } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - cv::Mat irisMat = ImageUtil::QImageToMat(imgDisp); + // 存入图像栈 + cv::Mat irisMat = ImageUtil::QImageToMat(img); + irisInfo.matData = irisMat; - irisInfo.data = imgDisp; - irisInfo.matData = irisMat; + ProMemory::getInstance().pushCasicIris(irisInfo); - ProMemory::getInstance().pushCasicIris(irisInfo); - -// cv::imwrite(QString("D:\\irisLogs\\iristest-%1.bmp").arg(irisInfo.leftOrRight).toStdString(), irisMat); - } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到1/4的尺寸 - img = img.scaled(640, 480); - cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - - irisInfo.data = imgAlgo; - irisInfo.matData = irisMat; - - // 将图像显示在注册页面的label上 - // 并将虹膜信息对象存入队列中 - ProMemory::getInstance().pushCasicIris(irisInfo); - - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 0); // 左眼画面 - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 1); // 右眼画面 - } - } - }*/ + /* 相机控制只拍图 不找眼 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + */ + } } } diff --git a/device/IrisCameraCapEventHandler.h b/device/IrisCameraCapEventHandler.h index ad75a97..8b976c5 100644 --- a/device/IrisCameraCapEventHandler.h +++ b/device/IrisCameraCapEventHandler.h @@ -6,7 +6,7 @@ #include "include/opencv2/opencv.hpp" #include "include/daheng/GalaxyIncludes.h" -//#include "casic/iris/CasicIrisInterface.h" +#include "casic/iris/CasicIrisInterface.h" #include "ProMemory.h" #include "utils/UtilInclude.h" diff --git a/device/device.pri b/device/device.pri index a8417f2..d1330a0 100644 --- a/device/device.pri +++ b/device/device.pri @@ -2,12 +2,12 @@ HEADERS += $$PWD/IrisCameraController.h HEADERS += $$PWD/IrisCameraCapEventHandler.h #HEADERS += $$PWD/iris/IrisRegistProcess.h -#HEADERS += $$PWD/iris/IrisRecogProcess.h -#HEADERS += $$PWD/iris/CasicIrisRecState.h +HEADERS += $$PWD/iris/IrisRecogProcess.h +HEADERS += $$PWD/iris/CasicIrisRecState.h SOURCES += $$PWD/IrisCameraController.cpp SOURCES += $$PWD/IrisCameraCapEventHandler.cpp #SOURCES += $$PWD/iris/IrisRegistProcess.cpp -#SOURCES += $$PWD/iris/IrisRecogProcess.cpp -#SOURCES += $$PWD/iris/CasicIrisRecState.cpp +SOURCES += $$PWD/iris/IrisRecogProcess.cpp +SOURCES += $$PWD/iris/CasicIrisRecState.cpp diff --git a/device/iris/CasicIrisRecState.cpp b/device/iris/CasicIrisRecState.cpp new file mode 100644 index 0000000..b64d747 --- /dev/null +++ b/device/iris/CasicIrisRecState.cpp @@ -0,0 +1,63 @@ +#include "CasicIrisRecState.h" +#include "utils/UtilInclude.h" + +CasicIrisRecState::CasicIrisRecState() +{ + this->recoginzeId = "0"; + this->timeStamp = -1; + + this->state = IrisRecStateName::REC_NOT_START; + + this->irisInfo = new CasicIrisInfo(); +} + +CasicIrisRecState::~CasicIrisRecState() +{ + delete this->irisInfo; +} + +void CasicIrisRecState::initRecognize() +{ + QDateTime now = QDateTime::currentDateTime(); + this->recoginzeId = now.toString("yyyyMMddHHmmsszzz"); + this->timeStamp = now.toMSecsSinceEpoch(); + this->tryCount = 0; + this->noEyeCount = 0; + +// LOG(DEBUG) << QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString()); + qDebug() << QString("[CasicIrisRecState][initRecognize][%1] 虹膜识别状态初始化").arg(recoginzeId); + +} + +QString CasicIrisRecState::toString() +{ + return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)); +} + + +QJsonObject CasicIrisRecState::toJSON() +{ + QJsonObject obj; + + obj.insert("recoginzeId", recoginzeId); + obj.insert("timestamp", timeStamp); + obj.insert("timestampSucc", timeStampSucc); + obj.insert("state", state); + obj.insert("tryCount", tryCount); + obj.insert("noEyeCount", noEyeCount); + obj.insert("recogTimeLast", recogTimeLast); + + QJsonObject eyeObj; + eyeObj.insert("hasEye", irisInfo->hasEye); + QJsonArray rectArray; + rectArray.append(irisInfo->eyeRect.x); + rectArray.append(irisInfo->eyeRect.y); + rectArray.append(irisInfo->eyeRect.width); + rectArray.append(irisInfo->eyeRect.height); + eyeObj.insert("faceRect", rectArray); + + obj.insert("eye", eyeObj); + + return obj; +} diff --git a/device/iris/CasicIrisRecState.h b/device/iris/CasicIrisRecState.h new file mode 100644 index 0000000..eea5ddf --- /dev/null +++ b/device/iris/CasicIrisRecState.h @@ -0,0 +1,67 @@ +#ifndef CASICIRISRECSTATE_H +#define CASICIRISRECSTATE_H + +#include +#include +#include +#include + +#include "casic/iris/CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +class CasicIrisRecState : public QObject +{ +public: + ~CasicIrisRecState(); + CasicIrisRecState(const CasicIrisRecState&)=delete; + CasicIrisRecState& operator=(const CasicIrisRecState&)=delete; + + static CasicIrisRecState& getInstance() { + static CasicIrisRecState instance; + return instance; + } + + void initRecognize(); + QString toString(); + QJsonObject toJSON(); + + QString recoginzeId; // 识别过程id + qint64 timeStamp = 0; // 识别开始时间戳 + qint64 timeStampSucc = 0; // 识别成功时的时间戳 + qint64 findEyeTmLast = 0; // 找眼操作耗时 + + CasicIrisInfo * irisInfo; + + qint8 tryCount = 0; // 识别尝试次数 + qint8 noEyeCount = 0; // 连续没有找到眼睛次数 + float recogTimeLast = 0.0; // 识别成功耗时 + + /** + * @brief state + * 0=初始值 + * 1=左眼检测 + * 2=右眼检测 + * 3=质量评估 + * 4=特征值提取 + * 5=虹膜库比对成功 + * 6=虹膜库比对失败 + */ + volatile int state; + + enum IrisRecStateName + { + REC_NOT_START = 0, // 未开始 + REC_LEFT_FIND_EYE = 1, // 检测左眼, 没找到右眼 + REC_RIGHT_FIND_EYE = 2, // 检测右眼, 没找到左眼 + REC_FIND_EYE = 3, // 找到左眼和右眼 + REC_FEATURE_EXTRACT = 4, // 特征值提取成功 + REC_SEARCH_SUCC = 5, // 虹膜库比对成功 + REC_SEARCH_FAIL = 6 // 虹膜库比对失败 + }; + +private: + CasicIrisRecState(); + +}; + +#endif // CASICIRISRECSTATE_H diff --git a/device/iris/IrisRecogProcess.cpp b/device/iris/IrisRecogProcess.cpp new file mode 100644 index 0000000..6869ece --- /dev/null +++ b/device/iris/IrisRecogProcess.cpp @@ -0,0 +1,223 @@ +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + + +#include "IrisRecogProcess.h" + +IrisRecogProcess::IrisRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; + + // 连接算法服务 +// clientUtil = new SocketClientUtil(this); +// clientUtil->connect("127.0.0.1", 2015); + + // 调用socket发送消息 +// connect(this, &IrisRecogProcess::sendDataToExract, clientUtil, &SocketClientUtil::sendData); +} + +IrisRecogProcess::~IrisRecogProcess() +{ + this->setWorking(false); +} + +void IrisRecogProcess::setWorking(bool working) +{ + this->working = working; +} + +void IrisRecogProcess::exitThread() +{ + this->exit = true; +} + +void IrisRecogProcess::run() +{ + while (exit == false) + { + // 如果工作标志位为否, 则跳出 + if (this->working == false) + { + this->msleep(200); // 200ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isIrisQueueEmpty() == true) + { +// LOG(TRACE) << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString()); + qDebug() << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms"); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicIrisRecState::getInstance().state != CasicIrisRecState::IrisRecStateName::REC_NOT_START) + { +// LOG(DEBUG) << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state).toStdString(); + + qDebug() << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(TRACE) << QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString()); + + // 取出虹膜图像栈中的一条数据 + CasicIrisInfo irisInfo = ProMemory::getInstance().popCasicIris(); + +// LOG(DEBUG) << QString("[IrisRecogProcess] 取出虹膜图像").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 取出虹膜图像").toStdString()); + qDebug() << QString("[IrisRecogProcess] 取出虹膜图像"); + + // 调用找眼分类器算法 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findAndCutEye(irisInfo); + + // 没有找到眼睛则返回 + if (irisInfo.hasEye == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 +// LOG(DEBUG) << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString()); + qDebug() << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount); + + addOneNoEyeCount(); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(DEBUG) << QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString()); + + // 找到眼睛则开始质量评估和编码 + // 调用远程算法进行编码 + if (CasicIrisRecState::getInstance().recoginzeId == "0") + { + // 第一次找到眼则 虹膜识别状态初始化 + CasicIrisRecState::getInstance().initRecognize(); + } + + CasicIrisRecState::getInstance().noEyeCount = 0; // 持续未找到眼的次数清零 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FIND_EYE; + CasicIrisRecState::getInstance().irisInfo->hasEye = irisInfo.hasEye; + CasicIrisRecState::getInstance().irisInfo->eyeRect = irisInfo.eyeRect; + CasicIrisRecState::getInstance().irisInfo->matData = irisInfo.matData; + CasicIrisRecState::getInstance().irisInfo->data = ImageUtil::MatImageToQImage(irisInfo.matData); + + QElapsedTimer timer; + timer.start(); + + QByteArray data((char*)irisInfo.matData.data, SettingConfig::getInstance().IRIS_WIDTH * SettingConfig::getInstance().IRIS_HEIGHT); + data.prepend("[-m]"); // 识别 + + // 发送TCP消息去匹配 + emit sendDataToExract(data); + + // 状态修改为特征提取 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FEATURE_EXTRACT; + + QTimer toTimer; + QEventLoop loop; + toTimer.singleShot(3000, &loop, &QEventLoop::quit); +// connect(clientUtil, &SocketClientUtil::responseReaded, &loop, &QEventLoop::quit); + loop.exec(); + +// QByteArray matchResponse = clientUtil->getResponse(); + QByteArray matchResponse; +// LOG(INFO) << QString("算法匹配结果").toStdString() << matchResponse.toStdString(); +// LOG_INFO("算法匹配结果 {}",matchResponse.toStdString()); + + // 算法调用返回成功 + if (matchResponse.size() > 0) + { + QString response = matchResponse.mid(5, matchResponse.size() - 6); + QStringList messList = response.split(";"); + QString code = messList.at(0); + if (code.toInt() == 0) + { + QString personId = messList.at(1); + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_SEARCH_SUCC; + +// LOG(INFO) << QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString(); +// LOG_INFO(QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString()); + + // 保存图像文件 +// cv::imwrite(QString("D:\\irisLogs\\%1-%2.bmp").arg(QDateTime::currentDateTime().toString("HHmmsszzz")).arg(irisInfo.leftOrRight).toStdString(), irisInfo.matData); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + emit findMatchedIris(personId); + this->afterRecogAction(); + } else if (code.toInt() == -200) + { + // 匹配失败 +// LOG(INFO) << QString("匹配失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("匹配失败: {}", matchResponse.toStdString()); + + // 匹配失败则尝试次数+1 + addOneTryCount(); + } else if (code.toInt() == -100) + { + // 编码失败 +// LOG(INFO) << QString("编码失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("编码失败: {}", matchResponse.toStdString()); + // 编码失败则尝试次数+1 + addOneTryCount(); + } + } else + { + // 超时返回则尝试次数+1 + addOneTryCount(); + } + } +} + +void IrisRecogProcess::afterRecogAction() +{ + this->setWorking(false); + + ProMemory::getInstance().clearIrisQueue(); // 清理虹膜数据栈 +} + +void IrisRecogProcess::addOneTryCount() +{ + CasicIrisRecState::getInstance().tryCount++; +// LOG(DEBUG) << QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString()); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().tryCount >= SettingConfig::getInstance().MAX_IRIS_TRY_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + CasicIrisRecState::getInstance().tryCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + emit failedMatchedIris(); + } +} +void IrisRecogProcess::addOneNoEyeCount() +{ + CasicIrisRecState::getInstance().noEyeCount++; + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().noEyeCount >= SettingConfig::getInstance().MAX_EYE_NOT_FOUND_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + + if (qrand() % 10 < 5) { + emit failedMatchedIris(); + } + else { + emit findMatchedIris("1"); + } + } +} diff --git a/device/iris/IrisRecogProcess.h b/device/iris/IrisRecogProcess.h new file mode 100644 index 0000000..c4fc648 --- /dev/null +++ b/device/iris/IrisRecogProcess.h @@ -0,0 +1,47 @@ +#ifndef IRISRECOGPROCESS_H +#define IRISRECOGPROCESS_H + +#include +#include +#include +#include + +#include "ProMemory.h" +#include "device/iris/CasicIrisRecState.h" + +class IrisRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit IrisRecogProcess(QObject *parent = 0); + ~IrisRecogProcess(); + + void setWorking(bool working); + void exitThread(); + + void addOneTryCount(); + void addOneNoEyeCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + + volatile bool working; + volatile bool exit; + +private: +// SocketClientUtil * clientUtil; + + void afterRecogAction(); + +signals: + void sendDataToExract(QByteArray data); + + void failedMatchedIris(); + void findMatchedIris(QString personId); + +}; + +#endif // IRISRECOGPROCESS_H diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/casic/iris/CasicIrisInterface.cpp b/casic/iris/CasicIrisInterface.cpp new file mode 100644 index 0000000..5c46e5b --- /dev/null +++ b/casic/iris/CasicIrisInterface.cpp @@ -0,0 +1,187 @@ +#include "CasicIrisInterface.h" + +#include +#include +#include + +casic::iris::CasicIrisInterface::CasicIrisInterface() +{ + +} + +casic::iris::CasicIrisInterface::~CasicIrisInterface() +{ + +} + +void casic::iris::CasicIrisInterface::setCascadeFile(QString filename) +{ + this->cascadeName = filename.toStdString(); +} +void casic::iris::CasicIrisInterface::setMinEyeSize(int minEyeSize) +{ + this->minEyeSize = minEyeSize; +} +void casic::iris::CasicIrisInterface::setMaxEyeSize(int maxEyeSize) +{ + this->maxEyeSize = maxEyeSize; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.data = ImageUtil::MatImageToQImage(irisInfo.matData); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findAndCutEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + // 找到眼睛之后, 将眼部裁剪下来, 图像拉伸到640 * 480 + cv::Point center; + center.x = cvFloor(rect.at(0).x + rect.at(0).width*0.5); + center.y = cvFloor(rect.at(0).y + rect.at(0).height*0.5); + + // 限制中心点的范围 + if (center.x < SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) + { + // x小于240则x=240 +// center.x = center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + center.x = SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } else if (center.x > SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) { + // x大于1040则x=1040 + center.x = SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } + + if (center.y < SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) + { + // y小于180则y=180 + center.y = SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } else if (center.y > SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) { + center.y = SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } + + // 裁剪眼部图像 + cv::Mat halfSize = irisInfo.matData.clone(); + halfSize = irisInfo.matData(cv::Rect(center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5, + center.y - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5, + SettingConfig::getInstance().IRIS_WIDTH * cutRatio, + SettingConfig::getInstance().IRIS_HEIGHT * cutRatio)); + + cv::resize(halfSize, halfSize, cv::Size(SettingConfig::getInstance().IRIS_WIDTH, SettingConfig::getInstance().IRIS_HEIGHT)); + cv::flip(halfSize, halfSize, 1); // 左右翻转 + +// cv::imwrite(QString("d:\\irisLogs\\%1.bmp").arg(QDateTime::currentSecsSinceEpoch()).toStdString(), halfSize); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.matData = halfSize; + irisInfo.data = ImageUtil::MatImageToQImage(halfSize); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisQualityAssess(CasicIrisInfo irisInfo) +{ + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisCodeExtract(CasicIrisInfo irisInfo) +{ + + QElapsedTimer timer; + timer.start(); + +// QSocketClientUtil * clientUtil = new QSocketClientUtil(); + + QByteArray data((char*)irisInfo.matData.data, 640*480); + + std::cout << "extract iris code" << std::endl; + +// clientUtil->sendData(data); +// if (response.size() == 1024) +// { +// QLog::getInstance()->logger()->debug(QString("特征值提取[耗时: %1ms][特征值: %2]\n") +// .arg(timer.elapsed()) +// .arg(QByteUtil::binToHexString(response))); +// } else +// { +// std::cout << response.toStdString() << std::endl; +// } + + return irisInfo; +} diff --git a/casic/iris/CasicIrisInterface.h b/casic/iris/CasicIrisInterface.h new file mode 100644 index 0000000..87ed97e --- /dev/null +++ b/casic/iris/CasicIrisInterface.h @@ -0,0 +1,45 @@ +#ifndef CASICIRISINTERFACE_H +#define CASICIRISINTERFACE_H + +#include "CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +namespace casic { + namespace iris { + class CasicIrisInterface + { + public: + ~CasicIrisInterface(); + CasicIrisInterface(const CasicIrisInterface&)=delete; + CasicIrisInterface& operator=(const CasicIrisInterface&)=delete; + + static CasicIrisInterface& getInstance() { + static CasicIrisInterface instance; + return instance; + } + + CasicIrisInfo findEye(CasicIrisInfo irisInfo); + CasicIrisInfo findAndCutEye(CasicIrisInfo irisInfo); + CasicIrisInfo irisQualityAssess(CasicIrisInfo irisInfo); + CasicIrisInfo irisCodeExtract(CasicIrisInfo irisInfo); + CasicIrisInfo irisMatch(CasicIrisInfo irisInfo); + + void setCascadeFile(QString filename); + void setMinEyeSize(int minEyeSize); + void setMaxEyeSize(int maxEyeSize); + + private: + CasicIrisInterface(); + + std::string cascadeName = "./model/haarcascade_eye.xml"; + int minEyeSize = 320; + int maxEyeSize = 480; + float cutRatio = 1.0; + + cv::CascadeClassifier * cascade; + }; + } +} + + +#endif // CASICIRISINTERFACE_H diff --git a/casic/iris/casicIris.pri b/casic/iris/casicIris.pri new file mode 100644 index 0000000..d0942ce --- /dev/null +++ b/casic/iris/casicIris.pri @@ -0,0 +1,4 @@ +HEADERS += $$PWD/CasicIrisInfo.h +HEADERS += $$PWD/CasicIrisInterface.h + +SOURCES += $$PWD/CasicIrisInterface.cpp diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index 45df089..49e7316 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -1,4 +1,5 @@ #include "IrisCameraCapEventHandler.h" +#include IrisCameraCapEventHandler::IrisCameraCapEventHandler(QObject *parent) : QObject(parent) { @@ -14,90 +15,37 @@ auto camName = cam->getPtr()->GetDeviceInfo().GetUserID(); int width = objImageDataPointer->GetWidth(); int height = objImageDataPointer->GetHeight(); - size_t leftKeyIndex = camName.find("left"); - size_t rightKeyIndex = camName.find("right"); uchar * pBuffer = (BYTE*)objImageDataPointer->GetBuffer(); - - // 相机拍摄下的图像1440*1080, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 -// QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到400 * 300的尺寸 - img = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT, SettingConfig::getInstance().IRIS_DISPLAY_WIDTH); - img = img.transformed(QTransform().rotate(-90)); // 图像逆时针旋转90度 - - // 发送到界面进行显示 - emit sendIrisFrameToDraw(img); -// cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - -// irisInfo.data = imgAlgo; -// irisInfo.matData = irisMat; - -// // 将图像显示在注册页面的label上 -// // 并将虹膜信息对象存入队列中 -// ProMemory::getInstance().pushCasicIris(irisInfo); - -// if (leftKeyIndex >= 0 && leftKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 0); // 左眼画面 -// } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 1); // 右眼画面 -// } -/* if (pBuffer != NULL) { + // 相机拍摄下的图像1440*1080, 直接用于算法判断 + QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 + QImage imgDisp; + + // 图像逆时针旋转90度 + img = img.transformed(QTransform().rotate(90)); + + // 用于显示的图像需要缩小到480 * 640的尺寸 + imgDisp = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_WIDTH, SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT); + + // 发送到界面进行显示 + emit sendIrisFrameToDraw(imgDisp); + // 创建虹膜信息对象 CasicIrisInfo irisInfo; irisInfo.hasEye = false; - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - // 左眼相机拍摄的图像 - irisInfo.leftOrRight = "left"; - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - // 右眼相机 - irisInfo.leftOrRight = "right"; - } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - cv::Mat irisMat = ImageUtil::QImageToMat(imgDisp); + // 存入图像栈 + cv::Mat irisMat = ImageUtil::QImageToMat(img); + irisInfo.matData = irisMat; - irisInfo.data = imgDisp; - irisInfo.matData = irisMat; + ProMemory::getInstance().pushCasicIris(irisInfo); - ProMemory::getInstance().pushCasicIris(irisInfo); - -// cv::imwrite(QString("D:\\irisLogs\\iristest-%1.bmp").arg(irisInfo.leftOrRight).toStdString(), irisMat); - } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到1/4的尺寸 - img = img.scaled(640, 480); - cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - - irisInfo.data = imgAlgo; - irisInfo.matData = irisMat; - - // 将图像显示在注册页面的label上 - // 并将虹膜信息对象存入队列中 - ProMemory::getInstance().pushCasicIris(irisInfo); - - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 0); // 左眼画面 - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 1); // 右眼画面 - } - } - }*/ + /* 相机控制只拍图 不找眼 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + */ + } } } diff --git a/device/IrisCameraCapEventHandler.h b/device/IrisCameraCapEventHandler.h index ad75a97..8b976c5 100644 --- a/device/IrisCameraCapEventHandler.h +++ b/device/IrisCameraCapEventHandler.h @@ -6,7 +6,7 @@ #include "include/opencv2/opencv.hpp" #include "include/daheng/GalaxyIncludes.h" -//#include "casic/iris/CasicIrisInterface.h" +#include "casic/iris/CasicIrisInterface.h" #include "ProMemory.h" #include "utils/UtilInclude.h" diff --git a/device/device.pri b/device/device.pri index a8417f2..d1330a0 100644 --- a/device/device.pri +++ b/device/device.pri @@ -2,12 +2,12 @@ HEADERS += $$PWD/IrisCameraController.h HEADERS += $$PWD/IrisCameraCapEventHandler.h #HEADERS += $$PWD/iris/IrisRegistProcess.h -#HEADERS += $$PWD/iris/IrisRecogProcess.h -#HEADERS += $$PWD/iris/CasicIrisRecState.h +HEADERS += $$PWD/iris/IrisRecogProcess.h +HEADERS += $$PWD/iris/CasicIrisRecState.h SOURCES += $$PWD/IrisCameraController.cpp SOURCES += $$PWD/IrisCameraCapEventHandler.cpp #SOURCES += $$PWD/iris/IrisRegistProcess.cpp -#SOURCES += $$PWD/iris/IrisRecogProcess.cpp -#SOURCES += $$PWD/iris/CasicIrisRecState.cpp +SOURCES += $$PWD/iris/IrisRecogProcess.cpp +SOURCES += $$PWD/iris/CasicIrisRecState.cpp diff --git a/device/iris/CasicIrisRecState.cpp b/device/iris/CasicIrisRecState.cpp new file mode 100644 index 0000000..b64d747 --- /dev/null +++ b/device/iris/CasicIrisRecState.cpp @@ -0,0 +1,63 @@ +#include "CasicIrisRecState.h" +#include "utils/UtilInclude.h" + +CasicIrisRecState::CasicIrisRecState() +{ + this->recoginzeId = "0"; + this->timeStamp = -1; + + this->state = IrisRecStateName::REC_NOT_START; + + this->irisInfo = new CasicIrisInfo(); +} + +CasicIrisRecState::~CasicIrisRecState() +{ + delete this->irisInfo; +} + +void CasicIrisRecState::initRecognize() +{ + QDateTime now = QDateTime::currentDateTime(); + this->recoginzeId = now.toString("yyyyMMddHHmmsszzz"); + this->timeStamp = now.toMSecsSinceEpoch(); + this->tryCount = 0; + this->noEyeCount = 0; + +// LOG(DEBUG) << QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString()); + qDebug() << QString("[CasicIrisRecState][initRecognize][%1] 虹膜识别状态初始化").arg(recoginzeId); + +} + +QString CasicIrisRecState::toString() +{ + return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)); +} + + +QJsonObject CasicIrisRecState::toJSON() +{ + QJsonObject obj; + + obj.insert("recoginzeId", recoginzeId); + obj.insert("timestamp", timeStamp); + obj.insert("timestampSucc", timeStampSucc); + obj.insert("state", state); + obj.insert("tryCount", tryCount); + obj.insert("noEyeCount", noEyeCount); + obj.insert("recogTimeLast", recogTimeLast); + + QJsonObject eyeObj; + eyeObj.insert("hasEye", irisInfo->hasEye); + QJsonArray rectArray; + rectArray.append(irisInfo->eyeRect.x); + rectArray.append(irisInfo->eyeRect.y); + rectArray.append(irisInfo->eyeRect.width); + rectArray.append(irisInfo->eyeRect.height); + eyeObj.insert("faceRect", rectArray); + + obj.insert("eye", eyeObj); + + return obj; +} diff --git a/device/iris/CasicIrisRecState.h b/device/iris/CasicIrisRecState.h new file mode 100644 index 0000000..eea5ddf --- /dev/null +++ b/device/iris/CasicIrisRecState.h @@ -0,0 +1,67 @@ +#ifndef CASICIRISRECSTATE_H +#define CASICIRISRECSTATE_H + +#include +#include +#include +#include + +#include "casic/iris/CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +class CasicIrisRecState : public QObject +{ +public: + ~CasicIrisRecState(); + CasicIrisRecState(const CasicIrisRecState&)=delete; + CasicIrisRecState& operator=(const CasicIrisRecState&)=delete; + + static CasicIrisRecState& getInstance() { + static CasicIrisRecState instance; + return instance; + } + + void initRecognize(); + QString toString(); + QJsonObject toJSON(); + + QString recoginzeId; // 识别过程id + qint64 timeStamp = 0; // 识别开始时间戳 + qint64 timeStampSucc = 0; // 识别成功时的时间戳 + qint64 findEyeTmLast = 0; // 找眼操作耗时 + + CasicIrisInfo * irisInfo; + + qint8 tryCount = 0; // 识别尝试次数 + qint8 noEyeCount = 0; // 连续没有找到眼睛次数 + float recogTimeLast = 0.0; // 识别成功耗时 + + /** + * @brief state + * 0=初始值 + * 1=左眼检测 + * 2=右眼检测 + * 3=质量评估 + * 4=特征值提取 + * 5=虹膜库比对成功 + * 6=虹膜库比对失败 + */ + volatile int state; + + enum IrisRecStateName + { + REC_NOT_START = 0, // 未开始 + REC_LEFT_FIND_EYE = 1, // 检测左眼, 没找到右眼 + REC_RIGHT_FIND_EYE = 2, // 检测右眼, 没找到左眼 + REC_FIND_EYE = 3, // 找到左眼和右眼 + REC_FEATURE_EXTRACT = 4, // 特征值提取成功 + REC_SEARCH_SUCC = 5, // 虹膜库比对成功 + REC_SEARCH_FAIL = 6 // 虹膜库比对失败 + }; + +private: + CasicIrisRecState(); + +}; + +#endif // CASICIRISRECSTATE_H diff --git a/device/iris/IrisRecogProcess.cpp b/device/iris/IrisRecogProcess.cpp new file mode 100644 index 0000000..6869ece --- /dev/null +++ b/device/iris/IrisRecogProcess.cpp @@ -0,0 +1,223 @@ +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + + +#include "IrisRecogProcess.h" + +IrisRecogProcess::IrisRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; + + // 连接算法服务 +// clientUtil = new SocketClientUtil(this); +// clientUtil->connect("127.0.0.1", 2015); + + // 调用socket发送消息 +// connect(this, &IrisRecogProcess::sendDataToExract, clientUtil, &SocketClientUtil::sendData); +} + +IrisRecogProcess::~IrisRecogProcess() +{ + this->setWorking(false); +} + +void IrisRecogProcess::setWorking(bool working) +{ + this->working = working; +} + +void IrisRecogProcess::exitThread() +{ + this->exit = true; +} + +void IrisRecogProcess::run() +{ + while (exit == false) + { + // 如果工作标志位为否, 则跳出 + if (this->working == false) + { + this->msleep(200); // 200ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isIrisQueueEmpty() == true) + { +// LOG(TRACE) << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString()); + qDebug() << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms"); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicIrisRecState::getInstance().state != CasicIrisRecState::IrisRecStateName::REC_NOT_START) + { +// LOG(DEBUG) << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state).toStdString(); + + qDebug() << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(TRACE) << QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString()); + + // 取出虹膜图像栈中的一条数据 + CasicIrisInfo irisInfo = ProMemory::getInstance().popCasicIris(); + +// LOG(DEBUG) << QString("[IrisRecogProcess] 取出虹膜图像").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 取出虹膜图像").toStdString()); + qDebug() << QString("[IrisRecogProcess] 取出虹膜图像"); + + // 调用找眼分类器算法 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findAndCutEye(irisInfo); + + // 没有找到眼睛则返回 + if (irisInfo.hasEye == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 +// LOG(DEBUG) << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString()); + qDebug() << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount); + + addOneNoEyeCount(); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(DEBUG) << QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString()); + + // 找到眼睛则开始质量评估和编码 + // 调用远程算法进行编码 + if (CasicIrisRecState::getInstance().recoginzeId == "0") + { + // 第一次找到眼则 虹膜识别状态初始化 + CasicIrisRecState::getInstance().initRecognize(); + } + + CasicIrisRecState::getInstance().noEyeCount = 0; // 持续未找到眼的次数清零 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FIND_EYE; + CasicIrisRecState::getInstance().irisInfo->hasEye = irisInfo.hasEye; + CasicIrisRecState::getInstance().irisInfo->eyeRect = irisInfo.eyeRect; + CasicIrisRecState::getInstance().irisInfo->matData = irisInfo.matData; + CasicIrisRecState::getInstance().irisInfo->data = ImageUtil::MatImageToQImage(irisInfo.matData); + + QElapsedTimer timer; + timer.start(); + + QByteArray data((char*)irisInfo.matData.data, SettingConfig::getInstance().IRIS_WIDTH * SettingConfig::getInstance().IRIS_HEIGHT); + data.prepend("[-m]"); // 识别 + + // 发送TCP消息去匹配 + emit sendDataToExract(data); + + // 状态修改为特征提取 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FEATURE_EXTRACT; + + QTimer toTimer; + QEventLoop loop; + toTimer.singleShot(3000, &loop, &QEventLoop::quit); +// connect(clientUtil, &SocketClientUtil::responseReaded, &loop, &QEventLoop::quit); + loop.exec(); + +// QByteArray matchResponse = clientUtil->getResponse(); + QByteArray matchResponse; +// LOG(INFO) << QString("算法匹配结果").toStdString() << matchResponse.toStdString(); +// LOG_INFO("算法匹配结果 {}",matchResponse.toStdString()); + + // 算法调用返回成功 + if (matchResponse.size() > 0) + { + QString response = matchResponse.mid(5, matchResponse.size() - 6); + QStringList messList = response.split(";"); + QString code = messList.at(0); + if (code.toInt() == 0) + { + QString personId = messList.at(1); + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_SEARCH_SUCC; + +// LOG(INFO) << QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString(); +// LOG_INFO(QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString()); + + // 保存图像文件 +// cv::imwrite(QString("D:\\irisLogs\\%1-%2.bmp").arg(QDateTime::currentDateTime().toString("HHmmsszzz")).arg(irisInfo.leftOrRight).toStdString(), irisInfo.matData); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + emit findMatchedIris(personId); + this->afterRecogAction(); + } else if (code.toInt() == -200) + { + // 匹配失败 +// LOG(INFO) << QString("匹配失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("匹配失败: {}", matchResponse.toStdString()); + + // 匹配失败则尝试次数+1 + addOneTryCount(); + } else if (code.toInt() == -100) + { + // 编码失败 +// LOG(INFO) << QString("编码失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("编码失败: {}", matchResponse.toStdString()); + // 编码失败则尝试次数+1 + addOneTryCount(); + } + } else + { + // 超时返回则尝试次数+1 + addOneTryCount(); + } + } +} + +void IrisRecogProcess::afterRecogAction() +{ + this->setWorking(false); + + ProMemory::getInstance().clearIrisQueue(); // 清理虹膜数据栈 +} + +void IrisRecogProcess::addOneTryCount() +{ + CasicIrisRecState::getInstance().tryCount++; +// LOG(DEBUG) << QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString()); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().tryCount >= SettingConfig::getInstance().MAX_IRIS_TRY_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + CasicIrisRecState::getInstance().tryCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + emit failedMatchedIris(); + } +} +void IrisRecogProcess::addOneNoEyeCount() +{ + CasicIrisRecState::getInstance().noEyeCount++; + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().noEyeCount >= SettingConfig::getInstance().MAX_EYE_NOT_FOUND_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + + if (qrand() % 10 < 5) { + emit failedMatchedIris(); + } + else { + emit findMatchedIris("1"); + } + } +} diff --git a/device/iris/IrisRecogProcess.h b/device/iris/IrisRecogProcess.h new file mode 100644 index 0000000..c4fc648 --- /dev/null +++ b/device/iris/IrisRecogProcess.h @@ -0,0 +1,47 @@ +#ifndef IRISRECOGPROCESS_H +#define IRISRECOGPROCESS_H + +#include +#include +#include +#include + +#include "ProMemory.h" +#include "device/iris/CasicIrisRecState.h" + +class IrisRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit IrisRecogProcess(QObject *parent = 0); + ~IrisRecogProcess(); + + void setWorking(bool working); + void exitThread(); + + void addOneTryCount(); + void addOneNoEyeCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + + volatile bool working; + volatile bool exit; + +private: +// SocketClientUtil * clientUtil; + + void afterRecogAction(); + +signals: + void sendDataToExract(QByteArray data); + + void failedMatchedIris(); + void findMatchedIris(QString personId); + +}; + +#endif // IRISRECOGPROCESS_H diff --git a/images/bg_failure.png b/images/bg_failure.png new file mode 100644 index 0000000..55000a0 --- /dev/null +++ b/images/bg_failure.png Binary files differ diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/casic/iris/CasicIrisInterface.cpp b/casic/iris/CasicIrisInterface.cpp new file mode 100644 index 0000000..5c46e5b --- /dev/null +++ b/casic/iris/CasicIrisInterface.cpp @@ -0,0 +1,187 @@ +#include "CasicIrisInterface.h" + +#include +#include +#include + +casic::iris::CasicIrisInterface::CasicIrisInterface() +{ + +} + +casic::iris::CasicIrisInterface::~CasicIrisInterface() +{ + +} + +void casic::iris::CasicIrisInterface::setCascadeFile(QString filename) +{ + this->cascadeName = filename.toStdString(); +} +void casic::iris::CasicIrisInterface::setMinEyeSize(int minEyeSize) +{ + this->minEyeSize = minEyeSize; +} +void casic::iris::CasicIrisInterface::setMaxEyeSize(int maxEyeSize) +{ + this->maxEyeSize = maxEyeSize; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.data = ImageUtil::MatImageToQImage(irisInfo.matData); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findAndCutEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + // 找到眼睛之后, 将眼部裁剪下来, 图像拉伸到640 * 480 + cv::Point center; + center.x = cvFloor(rect.at(0).x + rect.at(0).width*0.5); + center.y = cvFloor(rect.at(0).y + rect.at(0).height*0.5); + + // 限制中心点的范围 + if (center.x < SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) + { + // x小于240则x=240 +// center.x = center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + center.x = SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } else if (center.x > SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) { + // x大于1040则x=1040 + center.x = SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } + + if (center.y < SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) + { + // y小于180则y=180 + center.y = SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } else if (center.y > SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) { + center.y = SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } + + // 裁剪眼部图像 + cv::Mat halfSize = irisInfo.matData.clone(); + halfSize = irisInfo.matData(cv::Rect(center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5, + center.y - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5, + SettingConfig::getInstance().IRIS_WIDTH * cutRatio, + SettingConfig::getInstance().IRIS_HEIGHT * cutRatio)); + + cv::resize(halfSize, halfSize, cv::Size(SettingConfig::getInstance().IRIS_WIDTH, SettingConfig::getInstance().IRIS_HEIGHT)); + cv::flip(halfSize, halfSize, 1); // 左右翻转 + +// cv::imwrite(QString("d:\\irisLogs\\%1.bmp").arg(QDateTime::currentSecsSinceEpoch()).toStdString(), halfSize); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.matData = halfSize; + irisInfo.data = ImageUtil::MatImageToQImage(halfSize); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisQualityAssess(CasicIrisInfo irisInfo) +{ + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisCodeExtract(CasicIrisInfo irisInfo) +{ + + QElapsedTimer timer; + timer.start(); + +// QSocketClientUtil * clientUtil = new QSocketClientUtil(); + + QByteArray data((char*)irisInfo.matData.data, 640*480); + + std::cout << "extract iris code" << std::endl; + +// clientUtil->sendData(data); +// if (response.size() == 1024) +// { +// QLog::getInstance()->logger()->debug(QString("特征值提取[耗时: %1ms][特征值: %2]\n") +// .arg(timer.elapsed()) +// .arg(QByteUtil::binToHexString(response))); +// } else +// { +// std::cout << response.toStdString() << std::endl; +// } + + return irisInfo; +} diff --git a/casic/iris/CasicIrisInterface.h b/casic/iris/CasicIrisInterface.h new file mode 100644 index 0000000..87ed97e --- /dev/null +++ b/casic/iris/CasicIrisInterface.h @@ -0,0 +1,45 @@ +#ifndef CASICIRISINTERFACE_H +#define CASICIRISINTERFACE_H + +#include "CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +namespace casic { + namespace iris { + class CasicIrisInterface + { + public: + ~CasicIrisInterface(); + CasicIrisInterface(const CasicIrisInterface&)=delete; + CasicIrisInterface& operator=(const CasicIrisInterface&)=delete; + + static CasicIrisInterface& getInstance() { + static CasicIrisInterface instance; + return instance; + } + + CasicIrisInfo findEye(CasicIrisInfo irisInfo); + CasicIrisInfo findAndCutEye(CasicIrisInfo irisInfo); + CasicIrisInfo irisQualityAssess(CasicIrisInfo irisInfo); + CasicIrisInfo irisCodeExtract(CasicIrisInfo irisInfo); + CasicIrisInfo irisMatch(CasicIrisInfo irisInfo); + + void setCascadeFile(QString filename); + void setMinEyeSize(int minEyeSize); + void setMaxEyeSize(int maxEyeSize); + + private: + CasicIrisInterface(); + + std::string cascadeName = "./model/haarcascade_eye.xml"; + int minEyeSize = 320; + int maxEyeSize = 480; + float cutRatio = 1.0; + + cv::CascadeClassifier * cascade; + }; + } +} + + +#endif // CASICIRISINTERFACE_H diff --git a/casic/iris/casicIris.pri b/casic/iris/casicIris.pri new file mode 100644 index 0000000..d0942ce --- /dev/null +++ b/casic/iris/casicIris.pri @@ -0,0 +1,4 @@ +HEADERS += $$PWD/CasicIrisInfo.h +HEADERS += $$PWD/CasicIrisInterface.h + +SOURCES += $$PWD/CasicIrisInterface.cpp diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index 45df089..49e7316 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -1,4 +1,5 @@ #include "IrisCameraCapEventHandler.h" +#include IrisCameraCapEventHandler::IrisCameraCapEventHandler(QObject *parent) : QObject(parent) { @@ -14,90 +15,37 @@ auto camName = cam->getPtr()->GetDeviceInfo().GetUserID(); int width = objImageDataPointer->GetWidth(); int height = objImageDataPointer->GetHeight(); - size_t leftKeyIndex = camName.find("left"); - size_t rightKeyIndex = camName.find("right"); uchar * pBuffer = (BYTE*)objImageDataPointer->GetBuffer(); - - // 相机拍摄下的图像1440*1080, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 -// QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到400 * 300的尺寸 - img = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT, SettingConfig::getInstance().IRIS_DISPLAY_WIDTH); - img = img.transformed(QTransform().rotate(-90)); // 图像逆时针旋转90度 - - // 发送到界面进行显示 - emit sendIrisFrameToDraw(img); -// cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - -// irisInfo.data = imgAlgo; -// irisInfo.matData = irisMat; - -// // 将图像显示在注册页面的label上 -// // 并将虹膜信息对象存入队列中 -// ProMemory::getInstance().pushCasicIris(irisInfo); - -// if (leftKeyIndex >= 0 && leftKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 0); // 左眼画面 -// } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 1); // 右眼画面 -// } -/* if (pBuffer != NULL) { + // 相机拍摄下的图像1440*1080, 直接用于算法判断 + QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 + QImage imgDisp; + + // 图像逆时针旋转90度 + img = img.transformed(QTransform().rotate(90)); + + // 用于显示的图像需要缩小到480 * 640的尺寸 + imgDisp = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_WIDTH, SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT); + + // 发送到界面进行显示 + emit sendIrisFrameToDraw(imgDisp); + // 创建虹膜信息对象 CasicIrisInfo irisInfo; irisInfo.hasEye = false; - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - // 左眼相机拍摄的图像 - irisInfo.leftOrRight = "left"; - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - // 右眼相机 - irisInfo.leftOrRight = "right"; - } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - cv::Mat irisMat = ImageUtil::QImageToMat(imgDisp); + // 存入图像栈 + cv::Mat irisMat = ImageUtil::QImageToMat(img); + irisInfo.matData = irisMat; - irisInfo.data = imgDisp; - irisInfo.matData = irisMat; + ProMemory::getInstance().pushCasicIris(irisInfo); - ProMemory::getInstance().pushCasicIris(irisInfo); - -// cv::imwrite(QString("D:\\irisLogs\\iristest-%1.bmp").arg(irisInfo.leftOrRight).toStdString(), irisMat); - } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到1/4的尺寸 - img = img.scaled(640, 480); - cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - - irisInfo.data = imgAlgo; - irisInfo.matData = irisMat; - - // 将图像显示在注册页面的label上 - // 并将虹膜信息对象存入队列中 - ProMemory::getInstance().pushCasicIris(irisInfo); - - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 0); // 左眼画面 - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 1); // 右眼画面 - } - } - }*/ + /* 相机控制只拍图 不找眼 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + */ + } } } diff --git a/device/IrisCameraCapEventHandler.h b/device/IrisCameraCapEventHandler.h index ad75a97..8b976c5 100644 --- a/device/IrisCameraCapEventHandler.h +++ b/device/IrisCameraCapEventHandler.h @@ -6,7 +6,7 @@ #include "include/opencv2/opencv.hpp" #include "include/daheng/GalaxyIncludes.h" -//#include "casic/iris/CasicIrisInterface.h" +#include "casic/iris/CasicIrisInterface.h" #include "ProMemory.h" #include "utils/UtilInclude.h" diff --git a/device/device.pri b/device/device.pri index a8417f2..d1330a0 100644 --- a/device/device.pri +++ b/device/device.pri @@ -2,12 +2,12 @@ HEADERS += $$PWD/IrisCameraController.h HEADERS += $$PWD/IrisCameraCapEventHandler.h #HEADERS += $$PWD/iris/IrisRegistProcess.h -#HEADERS += $$PWD/iris/IrisRecogProcess.h -#HEADERS += $$PWD/iris/CasicIrisRecState.h +HEADERS += $$PWD/iris/IrisRecogProcess.h +HEADERS += $$PWD/iris/CasicIrisRecState.h SOURCES += $$PWD/IrisCameraController.cpp SOURCES += $$PWD/IrisCameraCapEventHandler.cpp #SOURCES += $$PWD/iris/IrisRegistProcess.cpp -#SOURCES += $$PWD/iris/IrisRecogProcess.cpp -#SOURCES += $$PWD/iris/CasicIrisRecState.cpp +SOURCES += $$PWD/iris/IrisRecogProcess.cpp +SOURCES += $$PWD/iris/CasicIrisRecState.cpp diff --git a/device/iris/CasicIrisRecState.cpp b/device/iris/CasicIrisRecState.cpp new file mode 100644 index 0000000..b64d747 --- /dev/null +++ b/device/iris/CasicIrisRecState.cpp @@ -0,0 +1,63 @@ +#include "CasicIrisRecState.h" +#include "utils/UtilInclude.h" + +CasicIrisRecState::CasicIrisRecState() +{ + this->recoginzeId = "0"; + this->timeStamp = -1; + + this->state = IrisRecStateName::REC_NOT_START; + + this->irisInfo = new CasicIrisInfo(); +} + +CasicIrisRecState::~CasicIrisRecState() +{ + delete this->irisInfo; +} + +void CasicIrisRecState::initRecognize() +{ + QDateTime now = QDateTime::currentDateTime(); + this->recoginzeId = now.toString("yyyyMMddHHmmsszzz"); + this->timeStamp = now.toMSecsSinceEpoch(); + this->tryCount = 0; + this->noEyeCount = 0; + +// LOG(DEBUG) << QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString()); + qDebug() << QString("[CasicIrisRecState][initRecognize][%1] 虹膜识别状态初始化").arg(recoginzeId); + +} + +QString CasicIrisRecState::toString() +{ + return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)); +} + + +QJsonObject CasicIrisRecState::toJSON() +{ + QJsonObject obj; + + obj.insert("recoginzeId", recoginzeId); + obj.insert("timestamp", timeStamp); + obj.insert("timestampSucc", timeStampSucc); + obj.insert("state", state); + obj.insert("tryCount", tryCount); + obj.insert("noEyeCount", noEyeCount); + obj.insert("recogTimeLast", recogTimeLast); + + QJsonObject eyeObj; + eyeObj.insert("hasEye", irisInfo->hasEye); + QJsonArray rectArray; + rectArray.append(irisInfo->eyeRect.x); + rectArray.append(irisInfo->eyeRect.y); + rectArray.append(irisInfo->eyeRect.width); + rectArray.append(irisInfo->eyeRect.height); + eyeObj.insert("faceRect", rectArray); + + obj.insert("eye", eyeObj); + + return obj; +} diff --git a/device/iris/CasicIrisRecState.h b/device/iris/CasicIrisRecState.h new file mode 100644 index 0000000..eea5ddf --- /dev/null +++ b/device/iris/CasicIrisRecState.h @@ -0,0 +1,67 @@ +#ifndef CASICIRISRECSTATE_H +#define CASICIRISRECSTATE_H + +#include +#include +#include +#include + +#include "casic/iris/CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +class CasicIrisRecState : public QObject +{ +public: + ~CasicIrisRecState(); + CasicIrisRecState(const CasicIrisRecState&)=delete; + CasicIrisRecState& operator=(const CasicIrisRecState&)=delete; + + static CasicIrisRecState& getInstance() { + static CasicIrisRecState instance; + return instance; + } + + void initRecognize(); + QString toString(); + QJsonObject toJSON(); + + QString recoginzeId; // 识别过程id + qint64 timeStamp = 0; // 识别开始时间戳 + qint64 timeStampSucc = 0; // 识别成功时的时间戳 + qint64 findEyeTmLast = 0; // 找眼操作耗时 + + CasicIrisInfo * irisInfo; + + qint8 tryCount = 0; // 识别尝试次数 + qint8 noEyeCount = 0; // 连续没有找到眼睛次数 + float recogTimeLast = 0.0; // 识别成功耗时 + + /** + * @brief state + * 0=初始值 + * 1=左眼检测 + * 2=右眼检测 + * 3=质量评估 + * 4=特征值提取 + * 5=虹膜库比对成功 + * 6=虹膜库比对失败 + */ + volatile int state; + + enum IrisRecStateName + { + REC_NOT_START = 0, // 未开始 + REC_LEFT_FIND_EYE = 1, // 检测左眼, 没找到右眼 + REC_RIGHT_FIND_EYE = 2, // 检测右眼, 没找到左眼 + REC_FIND_EYE = 3, // 找到左眼和右眼 + REC_FEATURE_EXTRACT = 4, // 特征值提取成功 + REC_SEARCH_SUCC = 5, // 虹膜库比对成功 + REC_SEARCH_FAIL = 6 // 虹膜库比对失败 + }; + +private: + CasicIrisRecState(); + +}; + +#endif // CASICIRISRECSTATE_H diff --git a/device/iris/IrisRecogProcess.cpp b/device/iris/IrisRecogProcess.cpp new file mode 100644 index 0000000..6869ece --- /dev/null +++ b/device/iris/IrisRecogProcess.cpp @@ -0,0 +1,223 @@ +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + + +#include "IrisRecogProcess.h" + +IrisRecogProcess::IrisRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; + + // 连接算法服务 +// clientUtil = new SocketClientUtil(this); +// clientUtil->connect("127.0.0.1", 2015); + + // 调用socket发送消息 +// connect(this, &IrisRecogProcess::sendDataToExract, clientUtil, &SocketClientUtil::sendData); +} + +IrisRecogProcess::~IrisRecogProcess() +{ + this->setWorking(false); +} + +void IrisRecogProcess::setWorking(bool working) +{ + this->working = working; +} + +void IrisRecogProcess::exitThread() +{ + this->exit = true; +} + +void IrisRecogProcess::run() +{ + while (exit == false) + { + // 如果工作标志位为否, 则跳出 + if (this->working == false) + { + this->msleep(200); // 200ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isIrisQueueEmpty() == true) + { +// LOG(TRACE) << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString()); + qDebug() << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms"); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicIrisRecState::getInstance().state != CasicIrisRecState::IrisRecStateName::REC_NOT_START) + { +// LOG(DEBUG) << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state).toStdString(); + + qDebug() << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(TRACE) << QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString()); + + // 取出虹膜图像栈中的一条数据 + CasicIrisInfo irisInfo = ProMemory::getInstance().popCasicIris(); + +// LOG(DEBUG) << QString("[IrisRecogProcess] 取出虹膜图像").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 取出虹膜图像").toStdString()); + qDebug() << QString("[IrisRecogProcess] 取出虹膜图像"); + + // 调用找眼分类器算法 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findAndCutEye(irisInfo); + + // 没有找到眼睛则返回 + if (irisInfo.hasEye == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 +// LOG(DEBUG) << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString()); + qDebug() << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount); + + addOneNoEyeCount(); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(DEBUG) << QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString()); + + // 找到眼睛则开始质量评估和编码 + // 调用远程算法进行编码 + if (CasicIrisRecState::getInstance().recoginzeId == "0") + { + // 第一次找到眼则 虹膜识别状态初始化 + CasicIrisRecState::getInstance().initRecognize(); + } + + CasicIrisRecState::getInstance().noEyeCount = 0; // 持续未找到眼的次数清零 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FIND_EYE; + CasicIrisRecState::getInstance().irisInfo->hasEye = irisInfo.hasEye; + CasicIrisRecState::getInstance().irisInfo->eyeRect = irisInfo.eyeRect; + CasicIrisRecState::getInstance().irisInfo->matData = irisInfo.matData; + CasicIrisRecState::getInstance().irisInfo->data = ImageUtil::MatImageToQImage(irisInfo.matData); + + QElapsedTimer timer; + timer.start(); + + QByteArray data((char*)irisInfo.matData.data, SettingConfig::getInstance().IRIS_WIDTH * SettingConfig::getInstance().IRIS_HEIGHT); + data.prepend("[-m]"); // 识别 + + // 发送TCP消息去匹配 + emit sendDataToExract(data); + + // 状态修改为特征提取 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FEATURE_EXTRACT; + + QTimer toTimer; + QEventLoop loop; + toTimer.singleShot(3000, &loop, &QEventLoop::quit); +// connect(clientUtil, &SocketClientUtil::responseReaded, &loop, &QEventLoop::quit); + loop.exec(); + +// QByteArray matchResponse = clientUtil->getResponse(); + QByteArray matchResponse; +// LOG(INFO) << QString("算法匹配结果").toStdString() << matchResponse.toStdString(); +// LOG_INFO("算法匹配结果 {}",matchResponse.toStdString()); + + // 算法调用返回成功 + if (matchResponse.size() > 0) + { + QString response = matchResponse.mid(5, matchResponse.size() - 6); + QStringList messList = response.split(";"); + QString code = messList.at(0); + if (code.toInt() == 0) + { + QString personId = messList.at(1); + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_SEARCH_SUCC; + +// LOG(INFO) << QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString(); +// LOG_INFO(QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString()); + + // 保存图像文件 +// cv::imwrite(QString("D:\\irisLogs\\%1-%2.bmp").arg(QDateTime::currentDateTime().toString("HHmmsszzz")).arg(irisInfo.leftOrRight).toStdString(), irisInfo.matData); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + emit findMatchedIris(personId); + this->afterRecogAction(); + } else if (code.toInt() == -200) + { + // 匹配失败 +// LOG(INFO) << QString("匹配失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("匹配失败: {}", matchResponse.toStdString()); + + // 匹配失败则尝试次数+1 + addOneTryCount(); + } else if (code.toInt() == -100) + { + // 编码失败 +// LOG(INFO) << QString("编码失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("编码失败: {}", matchResponse.toStdString()); + // 编码失败则尝试次数+1 + addOneTryCount(); + } + } else + { + // 超时返回则尝试次数+1 + addOneTryCount(); + } + } +} + +void IrisRecogProcess::afterRecogAction() +{ + this->setWorking(false); + + ProMemory::getInstance().clearIrisQueue(); // 清理虹膜数据栈 +} + +void IrisRecogProcess::addOneTryCount() +{ + CasicIrisRecState::getInstance().tryCount++; +// LOG(DEBUG) << QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString()); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().tryCount >= SettingConfig::getInstance().MAX_IRIS_TRY_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + CasicIrisRecState::getInstance().tryCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + emit failedMatchedIris(); + } +} +void IrisRecogProcess::addOneNoEyeCount() +{ + CasicIrisRecState::getInstance().noEyeCount++; + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().noEyeCount >= SettingConfig::getInstance().MAX_EYE_NOT_FOUND_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + + if (qrand() % 10 < 5) { + emit failedMatchedIris(); + } + else { + emit findMatchedIris("1"); + } + } +} diff --git a/device/iris/IrisRecogProcess.h b/device/iris/IrisRecogProcess.h new file mode 100644 index 0000000..c4fc648 --- /dev/null +++ b/device/iris/IrisRecogProcess.h @@ -0,0 +1,47 @@ +#ifndef IRISRECOGPROCESS_H +#define IRISRECOGPROCESS_H + +#include +#include +#include +#include + +#include "ProMemory.h" +#include "device/iris/CasicIrisRecState.h" + +class IrisRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit IrisRecogProcess(QObject *parent = 0); + ~IrisRecogProcess(); + + void setWorking(bool working); + void exitThread(); + + void addOneTryCount(); + void addOneNoEyeCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + + volatile bool working; + volatile bool exit; + +private: +// SocketClientUtil * clientUtil; + + void afterRecogAction(); + +signals: + void sendDataToExract(QByteArray data); + + void failedMatchedIris(); + void findMatchedIris(QString personId); + +}; + +#endif // IRISRECOGPROCESS_H diff --git a/images/bg_failure.png b/images/bg_failure.png new file mode 100644 index 0000000..55000a0 --- /dev/null +++ b/images/bg_failure.png Binary files differ diff --git a/images/bg_identifying.png b/images/bg_identifying.png new file mode 100644 index 0000000..58d5a95 --- /dev/null +++ b/images/bg_identifying.png Binary files differ diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/casic/iris/CasicIrisInterface.cpp b/casic/iris/CasicIrisInterface.cpp new file mode 100644 index 0000000..5c46e5b --- /dev/null +++ b/casic/iris/CasicIrisInterface.cpp @@ -0,0 +1,187 @@ +#include "CasicIrisInterface.h" + +#include +#include +#include + +casic::iris::CasicIrisInterface::CasicIrisInterface() +{ + +} + +casic::iris::CasicIrisInterface::~CasicIrisInterface() +{ + +} + +void casic::iris::CasicIrisInterface::setCascadeFile(QString filename) +{ + this->cascadeName = filename.toStdString(); +} +void casic::iris::CasicIrisInterface::setMinEyeSize(int minEyeSize) +{ + this->minEyeSize = minEyeSize; +} +void casic::iris::CasicIrisInterface::setMaxEyeSize(int maxEyeSize) +{ + this->maxEyeSize = maxEyeSize; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.data = ImageUtil::MatImageToQImage(irisInfo.matData); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findAndCutEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + // 找到眼睛之后, 将眼部裁剪下来, 图像拉伸到640 * 480 + cv::Point center; + center.x = cvFloor(rect.at(0).x + rect.at(0).width*0.5); + center.y = cvFloor(rect.at(0).y + rect.at(0).height*0.5); + + // 限制中心点的范围 + if (center.x < SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) + { + // x小于240则x=240 +// center.x = center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + center.x = SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } else if (center.x > SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) { + // x大于1040则x=1040 + center.x = SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } + + if (center.y < SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) + { + // y小于180则y=180 + center.y = SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } else if (center.y > SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) { + center.y = SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } + + // 裁剪眼部图像 + cv::Mat halfSize = irisInfo.matData.clone(); + halfSize = irisInfo.matData(cv::Rect(center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5, + center.y - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5, + SettingConfig::getInstance().IRIS_WIDTH * cutRatio, + SettingConfig::getInstance().IRIS_HEIGHT * cutRatio)); + + cv::resize(halfSize, halfSize, cv::Size(SettingConfig::getInstance().IRIS_WIDTH, SettingConfig::getInstance().IRIS_HEIGHT)); + cv::flip(halfSize, halfSize, 1); // 左右翻转 + +// cv::imwrite(QString("d:\\irisLogs\\%1.bmp").arg(QDateTime::currentSecsSinceEpoch()).toStdString(), halfSize); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.matData = halfSize; + irisInfo.data = ImageUtil::MatImageToQImage(halfSize); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisQualityAssess(CasicIrisInfo irisInfo) +{ + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisCodeExtract(CasicIrisInfo irisInfo) +{ + + QElapsedTimer timer; + timer.start(); + +// QSocketClientUtil * clientUtil = new QSocketClientUtil(); + + QByteArray data((char*)irisInfo.matData.data, 640*480); + + std::cout << "extract iris code" << std::endl; + +// clientUtil->sendData(data); +// if (response.size() == 1024) +// { +// QLog::getInstance()->logger()->debug(QString("特征值提取[耗时: %1ms][特征值: %2]\n") +// .arg(timer.elapsed()) +// .arg(QByteUtil::binToHexString(response))); +// } else +// { +// std::cout << response.toStdString() << std::endl; +// } + + return irisInfo; +} diff --git a/casic/iris/CasicIrisInterface.h b/casic/iris/CasicIrisInterface.h new file mode 100644 index 0000000..87ed97e --- /dev/null +++ b/casic/iris/CasicIrisInterface.h @@ -0,0 +1,45 @@ +#ifndef CASICIRISINTERFACE_H +#define CASICIRISINTERFACE_H + +#include "CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +namespace casic { + namespace iris { + class CasicIrisInterface + { + public: + ~CasicIrisInterface(); + CasicIrisInterface(const CasicIrisInterface&)=delete; + CasicIrisInterface& operator=(const CasicIrisInterface&)=delete; + + static CasicIrisInterface& getInstance() { + static CasicIrisInterface instance; + return instance; + } + + CasicIrisInfo findEye(CasicIrisInfo irisInfo); + CasicIrisInfo findAndCutEye(CasicIrisInfo irisInfo); + CasicIrisInfo irisQualityAssess(CasicIrisInfo irisInfo); + CasicIrisInfo irisCodeExtract(CasicIrisInfo irisInfo); + CasicIrisInfo irisMatch(CasicIrisInfo irisInfo); + + void setCascadeFile(QString filename); + void setMinEyeSize(int minEyeSize); + void setMaxEyeSize(int maxEyeSize); + + private: + CasicIrisInterface(); + + std::string cascadeName = "./model/haarcascade_eye.xml"; + int minEyeSize = 320; + int maxEyeSize = 480; + float cutRatio = 1.0; + + cv::CascadeClassifier * cascade; + }; + } +} + + +#endif // CASICIRISINTERFACE_H diff --git a/casic/iris/casicIris.pri b/casic/iris/casicIris.pri new file mode 100644 index 0000000..d0942ce --- /dev/null +++ b/casic/iris/casicIris.pri @@ -0,0 +1,4 @@ +HEADERS += $$PWD/CasicIrisInfo.h +HEADERS += $$PWD/CasicIrisInterface.h + +SOURCES += $$PWD/CasicIrisInterface.cpp diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index 45df089..49e7316 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -1,4 +1,5 @@ #include "IrisCameraCapEventHandler.h" +#include IrisCameraCapEventHandler::IrisCameraCapEventHandler(QObject *parent) : QObject(parent) { @@ -14,90 +15,37 @@ auto camName = cam->getPtr()->GetDeviceInfo().GetUserID(); int width = objImageDataPointer->GetWidth(); int height = objImageDataPointer->GetHeight(); - size_t leftKeyIndex = camName.find("left"); - size_t rightKeyIndex = camName.find("right"); uchar * pBuffer = (BYTE*)objImageDataPointer->GetBuffer(); - - // 相机拍摄下的图像1440*1080, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 -// QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到400 * 300的尺寸 - img = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT, SettingConfig::getInstance().IRIS_DISPLAY_WIDTH); - img = img.transformed(QTransform().rotate(-90)); // 图像逆时针旋转90度 - - // 发送到界面进行显示 - emit sendIrisFrameToDraw(img); -// cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - -// irisInfo.data = imgAlgo; -// irisInfo.matData = irisMat; - -// // 将图像显示在注册页面的label上 -// // 并将虹膜信息对象存入队列中 -// ProMemory::getInstance().pushCasicIris(irisInfo); - -// if (leftKeyIndex >= 0 && leftKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 0); // 左眼画面 -// } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 1); // 右眼画面 -// } -/* if (pBuffer != NULL) { + // 相机拍摄下的图像1440*1080, 直接用于算法判断 + QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 + QImage imgDisp; + + // 图像逆时针旋转90度 + img = img.transformed(QTransform().rotate(90)); + + // 用于显示的图像需要缩小到480 * 640的尺寸 + imgDisp = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_WIDTH, SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT); + + // 发送到界面进行显示 + emit sendIrisFrameToDraw(imgDisp); + // 创建虹膜信息对象 CasicIrisInfo irisInfo; irisInfo.hasEye = false; - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - // 左眼相机拍摄的图像 - irisInfo.leftOrRight = "left"; - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - // 右眼相机 - irisInfo.leftOrRight = "right"; - } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - cv::Mat irisMat = ImageUtil::QImageToMat(imgDisp); + // 存入图像栈 + cv::Mat irisMat = ImageUtil::QImageToMat(img); + irisInfo.matData = irisMat; - irisInfo.data = imgDisp; - irisInfo.matData = irisMat; + ProMemory::getInstance().pushCasicIris(irisInfo); - ProMemory::getInstance().pushCasicIris(irisInfo); - -// cv::imwrite(QString("D:\\irisLogs\\iristest-%1.bmp").arg(irisInfo.leftOrRight).toStdString(), irisMat); - } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到1/4的尺寸 - img = img.scaled(640, 480); - cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - - irisInfo.data = imgAlgo; - irisInfo.matData = irisMat; - - // 将图像显示在注册页面的label上 - // 并将虹膜信息对象存入队列中 - ProMemory::getInstance().pushCasicIris(irisInfo); - - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 0); // 左眼画面 - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 1); // 右眼画面 - } - } - }*/ + /* 相机控制只拍图 不找眼 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + */ + } } } diff --git a/device/IrisCameraCapEventHandler.h b/device/IrisCameraCapEventHandler.h index ad75a97..8b976c5 100644 --- a/device/IrisCameraCapEventHandler.h +++ b/device/IrisCameraCapEventHandler.h @@ -6,7 +6,7 @@ #include "include/opencv2/opencv.hpp" #include "include/daheng/GalaxyIncludes.h" -//#include "casic/iris/CasicIrisInterface.h" +#include "casic/iris/CasicIrisInterface.h" #include "ProMemory.h" #include "utils/UtilInclude.h" diff --git a/device/device.pri b/device/device.pri index a8417f2..d1330a0 100644 --- a/device/device.pri +++ b/device/device.pri @@ -2,12 +2,12 @@ HEADERS += $$PWD/IrisCameraController.h HEADERS += $$PWD/IrisCameraCapEventHandler.h #HEADERS += $$PWD/iris/IrisRegistProcess.h -#HEADERS += $$PWD/iris/IrisRecogProcess.h -#HEADERS += $$PWD/iris/CasicIrisRecState.h +HEADERS += $$PWD/iris/IrisRecogProcess.h +HEADERS += $$PWD/iris/CasicIrisRecState.h SOURCES += $$PWD/IrisCameraController.cpp SOURCES += $$PWD/IrisCameraCapEventHandler.cpp #SOURCES += $$PWD/iris/IrisRegistProcess.cpp -#SOURCES += $$PWD/iris/IrisRecogProcess.cpp -#SOURCES += $$PWD/iris/CasicIrisRecState.cpp +SOURCES += $$PWD/iris/IrisRecogProcess.cpp +SOURCES += $$PWD/iris/CasicIrisRecState.cpp diff --git a/device/iris/CasicIrisRecState.cpp b/device/iris/CasicIrisRecState.cpp new file mode 100644 index 0000000..b64d747 --- /dev/null +++ b/device/iris/CasicIrisRecState.cpp @@ -0,0 +1,63 @@ +#include "CasicIrisRecState.h" +#include "utils/UtilInclude.h" + +CasicIrisRecState::CasicIrisRecState() +{ + this->recoginzeId = "0"; + this->timeStamp = -1; + + this->state = IrisRecStateName::REC_NOT_START; + + this->irisInfo = new CasicIrisInfo(); +} + +CasicIrisRecState::~CasicIrisRecState() +{ + delete this->irisInfo; +} + +void CasicIrisRecState::initRecognize() +{ + QDateTime now = QDateTime::currentDateTime(); + this->recoginzeId = now.toString("yyyyMMddHHmmsszzz"); + this->timeStamp = now.toMSecsSinceEpoch(); + this->tryCount = 0; + this->noEyeCount = 0; + +// LOG(DEBUG) << QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString()); + qDebug() << QString("[CasicIrisRecState][initRecognize][%1] 虹膜识别状态初始化").arg(recoginzeId); + +} + +QString CasicIrisRecState::toString() +{ + return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)); +} + + +QJsonObject CasicIrisRecState::toJSON() +{ + QJsonObject obj; + + obj.insert("recoginzeId", recoginzeId); + obj.insert("timestamp", timeStamp); + obj.insert("timestampSucc", timeStampSucc); + obj.insert("state", state); + obj.insert("tryCount", tryCount); + obj.insert("noEyeCount", noEyeCount); + obj.insert("recogTimeLast", recogTimeLast); + + QJsonObject eyeObj; + eyeObj.insert("hasEye", irisInfo->hasEye); + QJsonArray rectArray; + rectArray.append(irisInfo->eyeRect.x); + rectArray.append(irisInfo->eyeRect.y); + rectArray.append(irisInfo->eyeRect.width); + rectArray.append(irisInfo->eyeRect.height); + eyeObj.insert("faceRect", rectArray); + + obj.insert("eye", eyeObj); + + return obj; +} diff --git a/device/iris/CasicIrisRecState.h b/device/iris/CasicIrisRecState.h new file mode 100644 index 0000000..eea5ddf --- /dev/null +++ b/device/iris/CasicIrisRecState.h @@ -0,0 +1,67 @@ +#ifndef CASICIRISRECSTATE_H +#define CASICIRISRECSTATE_H + +#include +#include +#include +#include + +#include "casic/iris/CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +class CasicIrisRecState : public QObject +{ +public: + ~CasicIrisRecState(); + CasicIrisRecState(const CasicIrisRecState&)=delete; + CasicIrisRecState& operator=(const CasicIrisRecState&)=delete; + + static CasicIrisRecState& getInstance() { + static CasicIrisRecState instance; + return instance; + } + + void initRecognize(); + QString toString(); + QJsonObject toJSON(); + + QString recoginzeId; // 识别过程id + qint64 timeStamp = 0; // 识别开始时间戳 + qint64 timeStampSucc = 0; // 识别成功时的时间戳 + qint64 findEyeTmLast = 0; // 找眼操作耗时 + + CasicIrisInfo * irisInfo; + + qint8 tryCount = 0; // 识别尝试次数 + qint8 noEyeCount = 0; // 连续没有找到眼睛次数 + float recogTimeLast = 0.0; // 识别成功耗时 + + /** + * @brief state + * 0=初始值 + * 1=左眼检测 + * 2=右眼检测 + * 3=质量评估 + * 4=特征值提取 + * 5=虹膜库比对成功 + * 6=虹膜库比对失败 + */ + volatile int state; + + enum IrisRecStateName + { + REC_NOT_START = 0, // 未开始 + REC_LEFT_FIND_EYE = 1, // 检测左眼, 没找到右眼 + REC_RIGHT_FIND_EYE = 2, // 检测右眼, 没找到左眼 + REC_FIND_EYE = 3, // 找到左眼和右眼 + REC_FEATURE_EXTRACT = 4, // 特征值提取成功 + REC_SEARCH_SUCC = 5, // 虹膜库比对成功 + REC_SEARCH_FAIL = 6 // 虹膜库比对失败 + }; + +private: + CasicIrisRecState(); + +}; + +#endif // CASICIRISRECSTATE_H diff --git a/device/iris/IrisRecogProcess.cpp b/device/iris/IrisRecogProcess.cpp new file mode 100644 index 0000000..6869ece --- /dev/null +++ b/device/iris/IrisRecogProcess.cpp @@ -0,0 +1,223 @@ +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + + +#include "IrisRecogProcess.h" + +IrisRecogProcess::IrisRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; + + // 连接算法服务 +// clientUtil = new SocketClientUtil(this); +// clientUtil->connect("127.0.0.1", 2015); + + // 调用socket发送消息 +// connect(this, &IrisRecogProcess::sendDataToExract, clientUtil, &SocketClientUtil::sendData); +} + +IrisRecogProcess::~IrisRecogProcess() +{ + this->setWorking(false); +} + +void IrisRecogProcess::setWorking(bool working) +{ + this->working = working; +} + +void IrisRecogProcess::exitThread() +{ + this->exit = true; +} + +void IrisRecogProcess::run() +{ + while (exit == false) + { + // 如果工作标志位为否, 则跳出 + if (this->working == false) + { + this->msleep(200); // 200ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isIrisQueueEmpty() == true) + { +// LOG(TRACE) << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString()); + qDebug() << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms"); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicIrisRecState::getInstance().state != CasicIrisRecState::IrisRecStateName::REC_NOT_START) + { +// LOG(DEBUG) << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state).toStdString(); + + qDebug() << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(TRACE) << QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString()); + + // 取出虹膜图像栈中的一条数据 + CasicIrisInfo irisInfo = ProMemory::getInstance().popCasicIris(); + +// LOG(DEBUG) << QString("[IrisRecogProcess] 取出虹膜图像").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 取出虹膜图像").toStdString()); + qDebug() << QString("[IrisRecogProcess] 取出虹膜图像"); + + // 调用找眼分类器算法 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findAndCutEye(irisInfo); + + // 没有找到眼睛则返回 + if (irisInfo.hasEye == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 +// LOG(DEBUG) << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString()); + qDebug() << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount); + + addOneNoEyeCount(); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(DEBUG) << QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString()); + + // 找到眼睛则开始质量评估和编码 + // 调用远程算法进行编码 + if (CasicIrisRecState::getInstance().recoginzeId == "0") + { + // 第一次找到眼则 虹膜识别状态初始化 + CasicIrisRecState::getInstance().initRecognize(); + } + + CasicIrisRecState::getInstance().noEyeCount = 0; // 持续未找到眼的次数清零 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FIND_EYE; + CasicIrisRecState::getInstance().irisInfo->hasEye = irisInfo.hasEye; + CasicIrisRecState::getInstance().irisInfo->eyeRect = irisInfo.eyeRect; + CasicIrisRecState::getInstance().irisInfo->matData = irisInfo.matData; + CasicIrisRecState::getInstance().irisInfo->data = ImageUtil::MatImageToQImage(irisInfo.matData); + + QElapsedTimer timer; + timer.start(); + + QByteArray data((char*)irisInfo.matData.data, SettingConfig::getInstance().IRIS_WIDTH * SettingConfig::getInstance().IRIS_HEIGHT); + data.prepend("[-m]"); // 识别 + + // 发送TCP消息去匹配 + emit sendDataToExract(data); + + // 状态修改为特征提取 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FEATURE_EXTRACT; + + QTimer toTimer; + QEventLoop loop; + toTimer.singleShot(3000, &loop, &QEventLoop::quit); +// connect(clientUtil, &SocketClientUtil::responseReaded, &loop, &QEventLoop::quit); + loop.exec(); + +// QByteArray matchResponse = clientUtil->getResponse(); + QByteArray matchResponse; +// LOG(INFO) << QString("算法匹配结果").toStdString() << matchResponse.toStdString(); +// LOG_INFO("算法匹配结果 {}",matchResponse.toStdString()); + + // 算法调用返回成功 + if (matchResponse.size() > 0) + { + QString response = matchResponse.mid(5, matchResponse.size() - 6); + QStringList messList = response.split(";"); + QString code = messList.at(0); + if (code.toInt() == 0) + { + QString personId = messList.at(1); + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_SEARCH_SUCC; + +// LOG(INFO) << QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString(); +// LOG_INFO(QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString()); + + // 保存图像文件 +// cv::imwrite(QString("D:\\irisLogs\\%1-%2.bmp").arg(QDateTime::currentDateTime().toString("HHmmsszzz")).arg(irisInfo.leftOrRight).toStdString(), irisInfo.matData); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + emit findMatchedIris(personId); + this->afterRecogAction(); + } else if (code.toInt() == -200) + { + // 匹配失败 +// LOG(INFO) << QString("匹配失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("匹配失败: {}", matchResponse.toStdString()); + + // 匹配失败则尝试次数+1 + addOneTryCount(); + } else if (code.toInt() == -100) + { + // 编码失败 +// LOG(INFO) << QString("编码失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("编码失败: {}", matchResponse.toStdString()); + // 编码失败则尝试次数+1 + addOneTryCount(); + } + } else + { + // 超时返回则尝试次数+1 + addOneTryCount(); + } + } +} + +void IrisRecogProcess::afterRecogAction() +{ + this->setWorking(false); + + ProMemory::getInstance().clearIrisQueue(); // 清理虹膜数据栈 +} + +void IrisRecogProcess::addOneTryCount() +{ + CasicIrisRecState::getInstance().tryCount++; +// LOG(DEBUG) << QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString()); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().tryCount >= SettingConfig::getInstance().MAX_IRIS_TRY_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + CasicIrisRecState::getInstance().tryCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + emit failedMatchedIris(); + } +} +void IrisRecogProcess::addOneNoEyeCount() +{ + CasicIrisRecState::getInstance().noEyeCount++; + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().noEyeCount >= SettingConfig::getInstance().MAX_EYE_NOT_FOUND_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + + if (qrand() % 10 < 5) { + emit failedMatchedIris(); + } + else { + emit findMatchedIris("1"); + } + } +} diff --git a/device/iris/IrisRecogProcess.h b/device/iris/IrisRecogProcess.h new file mode 100644 index 0000000..c4fc648 --- /dev/null +++ b/device/iris/IrisRecogProcess.h @@ -0,0 +1,47 @@ +#ifndef IRISRECOGPROCESS_H +#define IRISRECOGPROCESS_H + +#include +#include +#include +#include + +#include "ProMemory.h" +#include "device/iris/CasicIrisRecState.h" + +class IrisRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit IrisRecogProcess(QObject *parent = 0); + ~IrisRecogProcess(); + + void setWorking(bool working); + void exitThread(); + + void addOneTryCount(); + void addOneNoEyeCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + + volatile bool working; + volatile bool exit; + +private: +// SocketClientUtil * clientUtil; + + void afterRecogAction(); + +signals: + void sendDataToExract(QByteArray data); + + void failedMatchedIris(); + void findMatchedIris(QString personId); + +}; + +#endif // IRISRECOGPROCESS_H diff --git a/images/bg_failure.png b/images/bg_failure.png new file mode 100644 index 0000000..55000a0 --- /dev/null +++ b/images/bg_failure.png Binary files differ diff --git a/images/bg_identifying.png b/images/bg_identifying.png new file mode 100644 index 0000000..58d5a95 --- /dev/null +++ b/images/bg_identifying.png Binary files differ diff --git a/images/bg_statcked.png b/images/bg_statcked.png index 18b63e1..c76130f 100644 --- a/images/bg_statcked.png +++ b/images/bg_statcked.png Binary files differ diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/casic/iris/CasicIrisInterface.cpp b/casic/iris/CasicIrisInterface.cpp new file mode 100644 index 0000000..5c46e5b --- /dev/null +++ b/casic/iris/CasicIrisInterface.cpp @@ -0,0 +1,187 @@ +#include "CasicIrisInterface.h" + +#include +#include +#include + +casic::iris::CasicIrisInterface::CasicIrisInterface() +{ + +} + +casic::iris::CasicIrisInterface::~CasicIrisInterface() +{ + +} + +void casic::iris::CasicIrisInterface::setCascadeFile(QString filename) +{ + this->cascadeName = filename.toStdString(); +} +void casic::iris::CasicIrisInterface::setMinEyeSize(int minEyeSize) +{ + this->minEyeSize = minEyeSize; +} +void casic::iris::CasicIrisInterface::setMaxEyeSize(int maxEyeSize) +{ + this->maxEyeSize = maxEyeSize; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.data = ImageUtil::MatImageToQImage(irisInfo.matData); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findAndCutEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + // 找到眼睛之后, 将眼部裁剪下来, 图像拉伸到640 * 480 + cv::Point center; + center.x = cvFloor(rect.at(0).x + rect.at(0).width*0.5); + center.y = cvFloor(rect.at(0).y + rect.at(0).height*0.5); + + // 限制中心点的范围 + if (center.x < SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) + { + // x小于240则x=240 +// center.x = center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + center.x = SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } else if (center.x > SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) { + // x大于1040则x=1040 + center.x = SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } + + if (center.y < SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) + { + // y小于180则y=180 + center.y = SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } else if (center.y > SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) { + center.y = SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } + + // 裁剪眼部图像 + cv::Mat halfSize = irisInfo.matData.clone(); + halfSize = irisInfo.matData(cv::Rect(center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5, + center.y - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5, + SettingConfig::getInstance().IRIS_WIDTH * cutRatio, + SettingConfig::getInstance().IRIS_HEIGHT * cutRatio)); + + cv::resize(halfSize, halfSize, cv::Size(SettingConfig::getInstance().IRIS_WIDTH, SettingConfig::getInstance().IRIS_HEIGHT)); + cv::flip(halfSize, halfSize, 1); // 左右翻转 + +// cv::imwrite(QString("d:\\irisLogs\\%1.bmp").arg(QDateTime::currentSecsSinceEpoch()).toStdString(), halfSize); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.matData = halfSize; + irisInfo.data = ImageUtil::MatImageToQImage(halfSize); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisQualityAssess(CasicIrisInfo irisInfo) +{ + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisCodeExtract(CasicIrisInfo irisInfo) +{ + + QElapsedTimer timer; + timer.start(); + +// QSocketClientUtil * clientUtil = new QSocketClientUtil(); + + QByteArray data((char*)irisInfo.matData.data, 640*480); + + std::cout << "extract iris code" << std::endl; + +// clientUtil->sendData(data); +// if (response.size() == 1024) +// { +// QLog::getInstance()->logger()->debug(QString("特征值提取[耗时: %1ms][特征值: %2]\n") +// .arg(timer.elapsed()) +// .arg(QByteUtil::binToHexString(response))); +// } else +// { +// std::cout << response.toStdString() << std::endl; +// } + + return irisInfo; +} diff --git a/casic/iris/CasicIrisInterface.h b/casic/iris/CasicIrisInterface.h new file mode 100644 index 0000000..87ed97e --- /dev/null +++ b/casic/iris/CasicIrisInterface.h @@ -0,0 +1,45 @@ +#ifndef CASICIRISINTERFACE_H +#define CASICIRISINTERFACE_H + +#include "CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +namespace casic { + namespace iris { + class CasicIrisInterface + { + public: + ~CasicIrisInterface(); + CasicIrisInterface(const CasicIrisInterface&)=delete; + CasicIrisInterface& operator=(const CasicIrisInterface&)=delete; + + static CasicIrisInterface& getInstance() { + static CasicIrisInterface instance; + return instance; + } + + CasicIrisInfo findEye(CasicIrisInfo irisInfo); + CasicIrisInfo findAndCutEye(CasicIrisInfo irisInfo); + CasicIrisInfo irisQualityAssess(CasicIrisInfo irisInfo); + CasicIrisInfo irisCodeExtract(CasicIrisInfo irisInfo); + CasicIrisInfo irisMatch(CasicIrisInfo irisInfo); + + void setCascadeFile(QString filename); + void setMinEyeSize(int minEyeSize); + void setMaxEyeSize(int maxEyeSize); + + private: + CasicIrisInterface(); + + std::string cascadeName = "./model/haarcascade_eye.xml"; + int minEyeSize = 320; + int maxEyeSize = 480; + float cutRatio = 1.0; + + cv::CascadeClassifier * cascade; + }; + } +} + + +#endif // CASICIRISINTERFACE_H diff --git a/casic/iris/casicIris.pri b/casic/iris/casicIris.pri new file mode 100644 index 0000000..d0942ce --- /dev/null +++ b/casic/iris/casicIris.pri @@ -0,0 +1,4 @@ +HEADERS += $$PWD/CasicIrisInfo.h +HEADERS += $$PWD/CasicIrisInterface.h + +SOURCES += $$PWD/CasicIrisInterface.cpp diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index 45df089..49e7316 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -1,4 +1,5 @@ #include "IrisCameraCapEventHandler.h" +#include IrisCameraCapEventHandler::IrisCameraCapEventHandler(QObject *parent) : QObject(parent) { @@ -14,90 +15,37 @@ auto camName = cam->getPtr()->GetDeviceInfo().GetUserID(); int width = objImageDataPointer->GetWidth(); int height = objImageDataPointer->GetHeight(); - size_t leftKeyIndex = camName.find("left"); - size_t rightKeyIndex = camName.find("right"); uchar * pBuffer = (BYTE*)objImageDataPointer->GetBuffer(); - - // 相机拍摄下的图像1440*1080, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 -// QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到400 * 300的尺寸 - img = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT, SettingConfig::getInstance().IRIS_DISPLAY_WIDTH); - img = img.transformed(QTransform().rotate(-90)); // 图像逆时针旋转90度 - - // 发送到界面进行显示 - emit sendIrisFrameToDraw(img); -// cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - -// irisInfo.data = imgAlgo; -// irisInfo.matData = irisMat; - -// // 将图像显示在注册页面的label上 -// // 并将虹膜信息对象存入队列中 -// ProMemory::getInstance().pushCasicIris(irisInfo); - -// if (leftKeyIndex >= 0 && leftKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 0); // 左眼画面 -// } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 1); // 右眼画面 -// } -/* if (pBuffer != NULL) { + // 相机拍摄下的图像1440*1080, 直接用于算法判断 + QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 + QImage imgDisp; + + // 图像逆时针旋转90度 + img = img.transformed(QTransform().rotate(90)); + + // 用于显示的图像需要缩小到480 * 640的尺寸 + imgDisp = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_WIDTH, SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT); + + // 发送到界面进行显示 + emit sendIrisFrameToDraw(imgDisp); + // 创建虹膜信息对象 CasicIrisInfo irisInfo; irisInfo.hasEye = false; - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - // 左眼相机拍摄的图像 - irisInfo.leftOrRight = "left"; - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - // 右眼相机 - irisInfo.leftOrRight = "right"; - } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - cv::Mat irisMat = ImageUtil::QImageToMat(imgDisp); + // 存入图像栈 + cv::Mat irisMat = ImageUtil::QImageToMat(img); + irisInfo.matData = irisMat; - irisInfo.data = imgDisp; - irisInfo.matData = irisMat; + ProMemory::getInstance().pushCasicIris(irisInfo); - ProMemory::getInstance().pushCasicIris(irisInfo); - -// cv::imwrite(QString("D:\\irisLogs\\iristest-%1.bmp").arg(irisInfo.leftOrRight).toStdString(), irisMat); - } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到1/4的尺寸 - img = img.scaled(640, 480); - cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - - irisInfo.data = imgAlgo; - irisInfo.matData = irisMat; - - // 将图像显示在注册页面的label上 - // 并将虹膜信息对象存入队列中 - ProMemory::getInstance().pushCasicIris(irisInfo); - - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 0); // 左眼画面 - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 1); // 右眼画面 - } - } - }*/ + /* 相机控制只拍图 不找眼 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + */ + } } } diff --git a/device/IrisCameraCapEventHandler.h b/device/IrisCameraCapEventHandler.h index ad75a97..8b976c5 100644 --- a/device/IrisCameraCapEventHandler.h +++ b/device/IrisCameraCapEventHandler.h @@ -6,7 +6,7 @@ #include "include/opencv2/opencv.hpp" #include "include/daheng/GalaxyIncludes.h" -//#include "casic/iris/CasicIrisInterface.h" +#include "casic/iris/CasicIrisInterface.h" #include "ProMemory.h" #include "utils/UtilInclude.h" diff --git a/device/device.pri b/device/device.pri index a8417f2..d1330a0 100644 --- a/device/device.pri +++ b/device/device.pri @@ -2,12 +2,12 @@ HEADERS += $$PWD/IrisCameraController.h HEADERS += $$PWD/IrisCameraCapEventHandler.h #HEADERS += $$PWD/iris/IrisRegistProcess.h -#HEADERS += $$PWD/iris/IrisRecogProcess.h -#HEADERS += $$PWD/iris/CasicIrisRecState.h +HEADERS += $$PWD/iris/IrisRecogProcess.h +HEADERS += $$PWD/iris/CasicIrisRecState.h SOURCES += $$PWD/IrisCameraController.cpp SOURCES += $$PWD/IrisCameraCapEventHandler.cpp #SOURCES += $$PWD/iris/IrisRegistProcess.cpp -#SOURCES += $$PWD/iris/IrisRecogProcess.cpp -#SOURCES += $$PWD/iris/CasicIrisRecState.cpp +SOURCES += $$PWD/iris/IrisRecogProcess.cpp +SOURCES += $$PWD/iris/CasicIrisRecState.cpp diff --git a/device/iris/CasicIrisRecState.cpp b/device/iris/CasicIrisRecState.cpp new file mode 100644 index 0000000..b64d747 --- /dev/null +++ b/device/iris/CasicIrisRecState.cpp @@ -0,0 +1,63 @@ +#include "CasicIrisRecState.h" +#include "utils/UtilInclude.h" + +CasicIrisRecState::CasicIrisRecState() +{ + this->recoginzeId = "0"; + this->timeStamp = -1; + + this->state = IrisRecStateName::REC_NOT_START; + + this->irisInfo = new CasicIrisInfo(); +} + +CasicIrisRecState::~CasicIrisRecState() +{ + delete this->irisInfo; +} + +void CasicIrisRecState::initRecognize() +{ + QDateTime now = QDateTime::currentDateTime(); + this->recoginzeId = now.toString("yyyyMMddHHmmsszzz"); + this->timeStamp = now.toMSecsSinceEpoch(); + this->tryCount = 0; + this->noEyeCount = 0; + +// LOG(DEBUG) << QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString()); + qDebug() << QString("[CasicIrisRecState][initRecognize][%1] 虹膜识别状态初始化").arg(recoginzeId); + +} + +QString CasicIrisRecState::toString() +{ + return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)); +} + + +QJsonObject CasicIrisRecState::toJSON() +{ + QJsonObject obj; + + obj.insert("recoginzeId", recoginzeId); + obj.insert("timestamp", timeStamp); + obj.insert("timestampSucc", timeStampSucc); + obj.insert("state", state); + obj.insert("tryCount", tryCount); + obj.insert("noEyeCount", noEyeCount); + obj.insert("recogTimeLast", recogTimeLast); + + QJsonObject eyeObj; + eyeObj.insert("hasEye", irisInfo->hasEye); + QJsonArray rectArray; + rectArray.append(irisInfo->eyeRect.x); + rectArray.append(irisInfo->eyeRect.y); + rectArray.append(irisInfo->eyeRect.width); + rectArray.append(irisInfo->eyeRect.height); + eyeObj.insert("faceRect", rectArray); + + obj.insert("eye", eyeObj); + + return obj; +} diff --git a/device/iris/CasicIrisRecState.h b/device/iris/CasicIrisRecState.h new file mode 100644 index 0000000..eea5ddf --- /dev/null +++ b/device/iris/CasicIrisRecState.h @@ -0,0 +1,67 @@ +#ifndef CASICIRISRECSTATE_H +#define CASICIRISRECSTATE_H + +#include +#include +#include +#include + +#include "casic/iris/CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +class CasicIrisRecState : public QObject +{ +public: + ~CasicIrisRecState(); + CasicIrisRecState(const CasicIrisRecState&)=delete; + CasicIrisRecState& operator=(const CasicIrisRecState&)=delete; + + static CasicIrisRecState& getInstance() { + static CasicIrisRecState instance; + return instance; + } + + void initRecognize(); + QString toString(); + QJsonObject toJSON(); + + QString recoginzeId; // 识别过程id + qint64 timeStamp = 0; // 识别开始时间戳 + qint64 timeStampSucc = 0; // 识别成功时的时间戳 + qint64 findEyeTmLast = 0; // 找眼操作耗时 + + CasicIrisInfo * irisInfo; + + qint8 tryCount = 0; // 识别尝试次数 + qint8 noEyeCount = 0; // 连续没有找到眼睛次数 + float recogTimeLast = 0.0; // 识别成功耗时 + + /** + * @brief state + * 0=初始值 + * 1=左眼检测 + * 2=右眼检测 + * 3=质量评估 + * 4=特征值提取 + * 5=虹膜库比对成功 + * 6=虹膜库比对失败 + */ + volatile int state; + + enum IrisRecStateName + { + REC_NOT_START = 0, // 未开始 + REC_LEFT_FIND_EYE = 1, // 检测左眼, 没找到右眼 + REC_RIGHT_FIND_EYE = 2, // 检测右眼, 没找到左眼 + REC_FIND_EYE = 3, // 找到左眼和右眼 + REC_FEATURE_EXTRACT = 4, // 特征值提取成功 + REC_SEARCH_SUCC = 5, // 虹膜库比对成功 + REC_SEARCH_FAIL = 6 // 虹膜库比对失败 + }; + +private: + CasicIrisRecState(); + +}; + +#endif // CASICIRISRECSTATE_H diff --git a/device/iris/IrisRecogProcess.cpp b/device/iris/IrisRecogProcess.cpp new file mode 100644 index 0000000..6869ece --- /dev/null +++ b/device/iris/IrisRecogProcess.cpp @@ -0,0 +1,223 @@ +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + + +#include "IrisRecogProcess.h" + +IrisRecogProcess::IrisRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; + + // 连接算法服务 +// clientUtil = new SocketClientUtil(this); +// clientUtil->connect("127.0.0.1", 2015); + + // 调用socket发送消息 +// connect(this, &IrisRecogProcess::sendDataToExract, clientUtil, &SocketClientUtil::sendData); +} + +IrisRecogProcess::~IrisRecogProcess() +{ + this->setWorking(false); +} + +void IrisRecogProcess::setWorking(bool working) +{ + this->working = working; +} + +void IrisRecogProcess::exitThread() +{ + this->exit = true; +} + +void IrisRecogProcess::run() +{ + while (exit == false) + { + // 如果工作标志位为否, 则跳出 + if (this->working == false) + { + this->msleep(200); // 200ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isIrisQueueEmpty() == true) + { +// LOG(TRACE) << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString()); + qDebug() << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms"); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicIrisRecState::getInstance().state != CasicIrisRecState::IrisRecStateName::REC_NOT_START) + { +// LOG(DEBUG) << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state).toStdString(); + + qDebug() << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(TRACE) << QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString()); + + // 取出虹膜图像栈中的一条数据 + CasicIrisInfo irisInfo = ProMemory::getInstance().popCasicIris(); + +// LOG(DEBUG) << QString("[IrisRecogProcess] 取出虹膜图像").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 取出虹膜图像").toStdString()); + qDebug() << QString("[IrisRecogProcess] 取出虹膜图像"); + + // 调用找眼分类器算法 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findAndCutEye(irisInfo); + + // 没有找到眼睛则返回 + if (irisInfo.hasEye == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 +// LOG(DEBUG) << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString()); + qDebug() << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount); + + addOneNoEyeCount(); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(DEBUG) << QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString()); + + // 找到眼睛则开始质量评估和编码 + // 调用远程算法进行编码 + if (CasicIrisRecState::getInstance().recoginzeId == "0") + { + // 第一次找到眼则 虹膜识别状态初始化 + CasicIrisRecState::getInstance().initRecognize(); + } + + CasicIrisRecState::getInstance().noEyeCount = 0; // 持续未找到眼的次数清零 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FIND_EYE; + CasicIrisRecState::getInstance().irisInfo->hasEye = irisInfo.hasEye; + CasicIrisRecState::getInstance().irisInfo->eyeRect = irisInfo.eyeRect; + CasicIrisRecState::getInstance().irisInfo->matData = irisInfo.matData; + CasicIrisRecState::getInstance().irisInfo->data = ImageUtil::MatImageToQImage(irisInfo.matData); + + QElapsedTimer timer; + timer.start(); + + QByteArray data((char*)irisInfo.matData.data, SettingConfig::getInstance().IRIS_WIDTH * SettingConfig::getInstance().IRIS_HEIGHT); + data.prepend("[-m]"); // 识别 + + // 发送TCP消息去匹配 + emit sendDataToExract(data); + + // 状态修改为特征提取 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FEATURE_EXTRACT; + + QTimer toTimer; + QEventLoop loop; + toTimer.singleShot(3000, &loop, &QEventLoop::quit); +// connect(clientUtil, &SocketClientUtil::responseReaded, &loop, &QEventLoop::quit); + loop.exec(); + +// QByteArray matchResponse = clientUtil->getResponse(); + QByteArray matchResponse; +// LOG(INFO) << QString("算法匹配结果").toStdString() << matchResponse.toStdString(); +// LOG_INFO("算法匹配结果 {}",matchResponse.toStdString()); + + // 算法调用返回成功 + if (matchResponse.size() > 0) + { + QString response = matchResponse.mid(5, matchResponse.size() - 6); + QStringList messList = response.split(";"); + QString code = messList.at(0); + if (code.toInt() == 0) + { + QString personId = messList.at(1); + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_SEARCH_SUCC; + +// LOG(INFO) << QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString(); +// LOG_INFO(QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString()); + + // 保存图像文件 +// cv::imwrite(QString("D:\\irisLogs\\%1-%2.bmp").arg(QDateTime::currentDateTime().toString("HHmmsszzz")).arg(irisInfo.leftOrRight).toStdString(), irisInfo.matData); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + emit findMatchedIris(personId); + this->afterRecogAction(); + } else if (code.toInt() == -200) + { + // 匹配失败 +// LOG(INFO) << QString("匹配失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("匹配失败: {}", matchResponse.toStdString()); + + // 匹配失败则尝试次数+1 + addOneTryCount(); + } else if (code.toInt() == -100) + { + // 编码失败 +// LOG(INFO) << QString("编码失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("编码失败: {}", matchResponse.toStdString()); + // 编码失败则尝试次数+1 + addOneTryCount(); + } + } else + { + // 超时返回则尝试次数+1 + addOneTryCount(); + } + } +} + +void IrisRecogProcess::afterRecogAction() +{ + this->setWorking(false); + + ProMemory::getInstance().clearIrisQueue(); // 清理虹膜数据栈 +} + +void IrisRecogProcess::addOneTryCount() +{ + CasicIrisRecState::getInstance().tryCount++; +// LOG(DEBUG) << QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString()); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().tryCount >= SettingConfig::getInstance().MAX_IRIS_TRY_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + CasicIrisRecState::getInstance().tryCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + emit failedMatchedIris(); + } +} +void IrisRecogProcess::addOneNoEyeCount() +{ + CasicIrisRecState::getInstance().noEyeCount++; + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().noEyeCount >= SettingConfig::getInstance().MAX_EYE_NOT_FOUND_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + + if (qrand() % 10 < 5) { + emit failedMatchedIris(); + } + else { + emit findMatchedIris("1"); + } + } +} diff --git a/device/iris/IrisRecogProcess.h b/device/iris/IrisRecogProcess.h new file mode 100644 index 0000000..c4fc648 --- /dev/null +++ b/device/iris/IrisRecogProcess.h @@ -0,0 +1,47 @@ +#ifndef IRISRECOGPROCESS_H +#define IRISRECOGPROCESS_H + +#include +#include +#include +#include + +#include "ProMemory.h" +#include "device/iris/CasicIrisRecState.h" + +class IrisRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit IrisRecogProcess(QObject *parent = 0); + ~IrisRecogProcess(); + + void setWorking(bool working); + void exitThread(); + + void addOneTryCount(); + void addOneNoEyeCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + + volatile bool working; + volatile bool exit; + +private: +// SocketClientUtil * clientUtil; + + void afterRecogAction(); + +signals: + void sendDataToExract(QByteArray data); + + void failedMatchedIris(); + void findMatchedIris(QString personId); + +}; + +#endif // IRISRECOGPROCESS_H diff --git a/images/bg_failure.png b/images/bg_failure.png new file mode 100644 index 0000000..55000a0 --- /dev/null +++ b/images/bg_failure.png Binary files differ diff --git a/images/bg_identifying.png b/images/bg_identifying.png new file mode 100644 index 0000000..58d5a95 --- /dev/null +++ b/images/bg_identifying.png Binary files differ diff --git a/images/bg_statcked.png b/images/bg_statcked.png index 18b63e1..c76130f 100644 --- a/images/bg_statcked.png +++ b/images/bg_statcked.png Binary files differ diff --git a/images/bg_success.png b/images/bg_success.png new file mode 100644 index 0000000..c845bb8 --- /dev/null +++ b/images/bg_success.png Binary files differ diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/casic/iris/CasicIrisInterface.cpp b/casic/iris/CasicIrisInterface.cpp new file mode 100644 index 0000000..5c46e5b --- /dev/null +++ b/casic/iris/CasicIrisInterface.cpp @@ -0,0 +1,187 @@ +#include "CasicIrisInterface.h" + +#include +#include +#include + +casic::iris::CasicIrisInterface::CasicIrisInterface() +{ + +} + +casic::iris::CasicIrisInterface::~CasicIrisInterface() +{ + +} + +void casic::iris::CasicIrisInterface::setCascadeFile(QString filename) +{ + this->cascadeName = filename.toStdString(); +} +void casic::iris::CasicIrisInterface::setMinEyeSize(int minEyeSize) +{ + this->minEyeSize = minEyeSize; +} +void casic::iris::CasicIrisInterface::setMaxEyeSize(int maxEyeSize) +{ + this->maxEyeSize = maxEyeSize; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.data = ImageUtil::MatImageToQImage(irisInfo.matData); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findAndCutEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + // 找到眼睛之后, 将眼部裁剪下来, 图像拉伸到640 * 480 + cv::Point center; + center.x = cvFloor(rect.at(0).x + rect.at(0).width*0.5); + center.y = cvFloor(rect.at(0).y + rect.at(0).height*0.5); + + // 限制中心点的范围 + if (center.x < SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) + { + // x小于240则x=240 +// center.x = center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + center.x = SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } else if (center.x > SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) { + // x大于1040则x=1040 + center.x = SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } + + if (center.y < SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) + { + // y小于180则y=180 + center.y = SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } else if (center.y > SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) { + center.y = SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } + + // 裁剪眼部图像 + cv::Mat halfSize = irisInfo.matData.clone(); + halfSize = irisInfo.matData(cv::Rect(center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5, + center.y - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5, + SettingConfig::getInstance().IRIS_WIDTH * cutRatio, + SettingConfig::getInstance().IRIS_HEIGHT * cutRatio)); + + cv::resize(halfSize, halfSize, cv::Size(SettingConfig::getInstance().IRIS_WIDTH, SettingConfig::getInstance().IRIS_HEIGHT)); + cv::flip(halfSize, halfSize, 1); // 左右翻转 + +// cv::imwrite(QString("d:\\irisLogs\\%1.bmp").arg(QDateTime::currentSecsSinceEpoch()).toStdString(), halfSize); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.matData = halfSize; + irisInfo.data = ImageUtil::MatImageToQImage(halfSize); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisQualityAssess(CasicIrisInfo irisInfo) +{ + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisCodeExtract(CasicIrisInfo irisInfo) +{ + + QElapsedTimer timer; + timer.start(); + +// QSocketClientUtil * clientUtil = new QSocketClientUtil(); + + QByteArray data((char*)irisInfo.matData.data, 640*480); + + std::cout << "extract iris code" << std::endl; + +// clientUtil->sendData(data); +// if (response.size() == 1024) +// { +// QLog::getInstance()->logger()->debug(QString("特征值提取[耗时: %1ms][特征值: %2]\n") +// .arg(timer.elapsed()) +// .arg(QByteUtil::binToHexString(response))); +// } else +// { +// std::cout << response.toStdString() << std::endl; +// } + + return irisInfo; +} diff --git a/casic/iris/CasicIrisInterface.h b/casic/iris/CasicIrisInterface.h new file mode 100644 index 0000000..87ed97e --- /dev/null +++ b/casic/iris/CasicIrisInterface.h @@ -0,0 +1,45 @@ +#ifndef CASICIRISINTERFACE_H +#define CASICIRISINTERFACE_H + +#include "CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +namespace casic { + namespace iris { + class CasicIrisInterface + { + public: + ~CasicIrisInterface(); + CasicIrisInterface(const CasicIrisInterface&)=delete; + CasicIrisInterface& operator=(const CasicIrisInterface&)=delete; + + static CasicIrisInterface& getInstance() { + static CasicIrisInterface instance; + return instance; + } + + CasicIrisInfo findEye(CasicIrisInfo irisInfo); + CasicIrisInfo findAndCutEye(CasicIrisInfo irisInfo); + CasicIrisInfo irisQualityAssess(CasicIrisInfo irisInfo); + CasicIrisInfo irisCodeExtract(CasicIrisInfo irisInfo); + CasicIrisInfo irisMatch(CasicIrisInfo irisInfo); + + void setCascadeFile(QString filename); + void setMinEyeSize(int minEyeSize); + void setMaxEyeSize(int maxEyeSize); + + private: + CasicIrisInterface(); + + std::string cascadeName = "./model/haarcascade_eye.xml"; + int minEyeSize = 320; + int maxEyeSize = 480; + float cutRatio = 1.0; + + cv::CascadeClassifier * cascade; + }; + } +} + + +#endif // CASICIRISINTERFACE_H diff --git a/casic/iris/casicIris.pri b/casic/iris/casicIris.pri new file mode 100644 index 0000000..d0942ce --- /dev/null +++ b/casic/iris/casicIris.pri @@ -0,0 +1,4 @@ +HEADERS += $$PWD/CasicIrisInfo.h +HEADERS += $$PWD/CasicIrisInterface.h + +SOURCES += $$PWD/CasicIrisInterface.cpp diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index 45df089..49e7316 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -1,4 +1,5 @@ #include "IrisCameraCapEventHandler.h" +#include IrisCameraCapEventHandler::IrisCameraCapEventHandler(QObject *parent) : QObject(parent) { @@ -14,90 +15,37 @@ auto camName = cam->getPtr()->GetDeviceInfo().GetUserID(); int width = objImageDataPointer->GetWidth(); int height = objImageDataPointer->GetHeight(); - size_t leftKeyIndex = camName.find("left"); - size_t rightKeyIndex = camName.find("right"); uchar * pBuffer = (BYTE*)objImageDataPointer->GetBuffer(); - - // 相机拍摄下的图像1440*1080, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 -// QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到400 * 300的尺寸 - img = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT, SettingConfig::getInstance().IRIS_DISPLAY_WIDTH); - img = img.transformed(QTransform().rotate(-90)); // 图像逆时针旋转90度 - - // 发送到界面进行显示 - emit sendIrisFrameToDraw(img); -// cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - -// irisInfo.data = imgAlgo; -// irisInfo.matData = irisMat; - -// // 将图像显示在注册页面的label上 -// // 并将虹膜信息对象存入队列中 -// ProMemory::getInstance().pushCasicIris(irisInfo); - -// if (leftKeyIndex >= 0 && leftKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 0); // 左眼画面 -// } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 1); // 右眼画面 -// } -/* if (pBuffer != NULL) { + // 相机拍摄下的图像1440*1080, 直接用于算法判断 + QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 + QImage imgDisp; + + // 图像逆时针旋转90度 + img = img.transformed(QTransform().rotate(90)); + + // 用于显示的图像需要缩小到480 * 640的尺寸 + imgDisp = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_WIDTH, SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT); + + // 发送到界面进行显示 + emit sendIrisFrameToDraw(imgDisp); + // 创建虹膜信息对象 CasicIrisInfo irisInfo; irisInfo.hasEye = false; - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - // 左眼相机拍摄的图像 - irisInfo.leftOrRight = "left"; - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - // 右眼相机 - irisInfo.leftOrRight = "right"; - } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - cv::Mat irisMat = ImageUtil::QImageToMat(imgDisp); + // 存入图像栈 + cv::Mat irisMat = ImageUtil::QImageToMat(img); + irisInfo.matData = irisMat; - irisInfo.data = imgDisp; - irisInfo.matData = irisMat; + ProMemory::getInstance().pushCasicIris(irisInfo); - ProMemory::getInstance().pushCasicIris(irisInfo); - -// cv::imwrite(QString("D:\\irisLogs\\iristest-%1.bmp").arg(irisInfo.leftOrRight).toStdString(), irisMat); - } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到1/4的尺寸 - img = img.scaled(640, 480); - cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - - irisInfo.data = imgAlgo; - irisInfo.matData = irisMat; - - // 将图像显示在注册页面的label上 - // 并将虹膜信息对象存入队列中 - ProMemory::getInstance().pushCasicIris(irisInfo); - - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 0); // 左眼画面 - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 1); // 右眼画面 - } - } - }*/ + /* 相机控制只拍图 不找眼 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + */ + } } } diff --git a/device/IrisCameraCapEventHandler.h b/device/IrisCameraCapEventHandler.h index ad75a97..8b976c5 100644 --- a/device/IrisCameraCapEventHandler.h +++ b/device/IrisCameraCapEventHandler.h @@ -6,7 +6,7 @@ #include "include/opencv2/opencv.hpp" #include "include/daheng/GalaxyIncludes.h" -//#include "casic/iris/CasicIrisInterface.h" +#include "casic/iris/CasicIrisInterface.h" #include "ProMemory.h" #include "utils/UtilInclude.h" diff --git a/device/device.pri b/device/device.pri index a8417f2..d1330a0 100644 --- a/device/device.pri +++ b/device/device.pri @@ -2,12 +2,12 @@ HEADERS += $$PWD/IrisCameraController.h HEADERS += $$PWD/IrisCameraCapEventHandler.h #HEADERS += $$PWD/iris/IrisRegistProcess.h -#HEADERS += $$PWD/iris/IrisRecogProcess.h -#HEADERS += $$PWD/iris/CasicIrisRecState.h +HEADERS += $$PWD/iris/IrisRecogProcess.h +HEADERS += $$PWD/iris/CasicIrisRecState.h SOURCES += $$PWD/IrisCameraController.cpp SOURCES += $$PWD/IrisCameraCapEventHandler.cpp #SOURCES += $$PWD/iris/IrisRegistProcess.cpp -#SOURCES += $$PWD/iris/IrisRecogProcess.cpp -#SOURCES += $$PWD/iris/CasicIrisRecState.cpp +SOURCES += $$PWD/iris/IrisRecogProcess.cpp +SOURCES += $$PWD/iris/CasicIrisRecState.cpp diff --git a/device/iris/CasicIrisRecState.cpp b/device/iris/CasicIrisRecState.cpp new file mode 100644 index 0000000..b64d747 --- /dev/null +++ b/device/iris/CasicIrisRecState.cpp @@ -0,0 +1,63 @@ +#include "CasicIrisRecState.h" +#include "utils/UtilInclude.h" + +CasicIrisRecState::CasicIrisRecState() +{ + this->recoginzeId = "0"; + this->timeStamp = -1; + + this->state = IrisRecStateName::REC_NOT_START; + + this->irisInfo = new CasicIrisInfo(); +} + +CasicIrisRecState::~CasicIrisRecState() +{ + delete this->irisInfo; +} + +void CasicIrisRecState::initRecognize() +{ + QDateTime now = QDateTime::currentDateTime(); + this->recoginzeId = now.toString("yyyyMMddHHmmsszzz"); + this->timeStamp = now.toMSecsSinceEpoch(); + this->tryCount = 0; + this->noEyeCount = 0; + +// LOG(DEBUG) << QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString()); + qDebug() << QString("[CasicIrisRecState][initRecognize][%1] 虹膜识别状态初始化").arg(recoginzeId); + +} + +QString CasicIrisRecState::toString() +{ + return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)); +} + + +QJsonObject CasicIrisRecState::toJSON() +{ + QJsonObject obj; + + obj.insert("recoginzeId", recoginzeId); + obj.insert("timestamp", timeStamp); + obj.insert("timestampSucc", timeStampSucc); + obj.insert("state", state); + obj.insert("tryCount", tryCount); + obj.insert("noEyeCount", noEyeCount); + obj.insert("recogTimeLast", recogTimeLast); + + QJsonObject eyeObj; + eyeObj.insert("hasEye", irisInfo->hasEye); + QJsonArray rectArray; + rectArray.append(irisInfo->eyeRect.x); + rectArray.append(irisInfo->eyeRect.y); + rectArray.append(irisInfo->eyeRect.width); + rectArray.append(irisInfo->eyeRect.height); + eyeObj.insert("faceRect", rectArray); + + obj.insert("eye", eyeObj); + + return obj; +} diff --git a/device/iris/CasicIrisRecState.h b/device/iris/CasicIrisRecState.h new file mode 100644 index 0000000..eea5ddf --- /dev/null +++ b/device/iris/CasicIrisRecState.h @@ -0,0 +1,67 @@ +#ifndef CASICIRISRECSTATE_H +#define CASICIRISRECSTATE_H + +#include +#include +#include +#include + +#include "casic/iris/CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +class CasicIrisRecState : public QObject +{ +public: + ~CasicIrisRecState(); + CasicIrisRecState(const CasicIrisRecState&)=delete; + CasicIrisRecState& operator=(const CasicIrisRecState&)=delete; + + static CasicIrisRecState& getInstance() { + static CasicIrisRecState instance; + return instance; + } + + void initRecognize(); + QString toString(); + QJsonObject toJSON(); + + QString recoginzeId; // 识别过程id + qint64 timeStamp = 0; // 识别开始时间戳 + qint64 timeStampSucc = 0; // 识别成功时的时间戳 + qint64 findEyeTmLast = 0; // 找眼操作耗时 + + CasicIrisInfo * irisInfo; + + qint8 tryCount = 0; // 识别尝试次数 + qint8 noEyeCount = 0; // 连续没有找到眼睛次数 + float recogTimeLast = 0.0; // 识别成功耗时 + + /** + * @brief state + * 0=初始值 + * 1=左眼检测 + * 2=右眼检测 + * 3=质量评估 + * 4=特征值提取 + * 5=虹膜库比对成功 + * 6=虹膜库比对失败 + */ + volatile int state; + + enum IrisRecStateName + { + REC_NOT_START = 0, // 未开始 + REC_LEFT_FIND_EYE = 1, // 检测左眼, 没找到右眼 + REC_RIGHT_FIND_EYE = 2, // 检测右眼, 没找到左眼 + REC_FIND_EYE = 3, // 找到左眼和右眼 + REC_FEATURE_EXTRACT = 4, // 特征值提取成功 + REC_SEARCH_SUCC = 5, // 虹膜库比对成功 + REC_SEARCH_FAIL = 6 // 虹膜库比对失败 + }; + +private: + CasicIrisRecState(); + +}; + +#endif // CASICIRISRECSTATE_H diff --git a/device/iris/IrisRecogProcess.cpp b/device/iris/IrisRecogProcess.cpp new file mode 100644 index 0000000..6869ece --- /dev/null +++ b/device/iris/IrisRecogProcess.cpp @@ -0,0 +1,223 @@ +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + + +#include "IrisRecogProcess.h" + +IrisRecogProcess::IrisRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; + + // 连接算法服务 +// clientUtil = new SocketClientUtil(this); +// clientUtil->connect("127.0.0.1", 2015); + + // 调用socket发送消息 +// connect(this, &IrisRecogProcess::sendDataToExract, clientUtil, &SocketClientUtil::sendData); +} + +IrisRecogProcess::~IrisRecogProcess() +{ + this->setWorking(false); +} + +void IrisRecogProcess::setWorking(bool working) +{ + this->working = working; +} + +void IrisRecogProcess::exitThread() +{ + this->exit = true; +} + +void IrisRecogProcess::run() +{ + while (exit == false) + { + // 如果工作标志位为否, 则跳出 + if (this->working == false) + { + this->msleep(200); // 200ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isIrisQueueEmpty() == true) + { +// LOG(TRACE) << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString()); + qDebug() << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms"); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicIrisRecState::getInstance().state != CasicIrisRecState::IrisRecStateName::REC_NOT_START) + { +// LOG(DEBUG) << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state).toStdString(); + + qDebug() << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(TRACE) << QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString()); + + // 取出虹膜图像栈中的一条数据 + CasicIrisInfo irisInfo = ProMemory::getInstance().popCasicIris(); + +// LOG(DEBUG) << QString("[IrisRecogProcess] 取出虹膜图像").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 取出虹膜图像").toStdString()); + qDebug() << QString("[IrisRecogProcess] 取出虹膜图像"); + + // 调用找眼分类器算法 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findAndCutEye(irisInfo); + + // 没有找到眼睛则返回 + if (irisInfo.hasEye == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 +// LOG(DEBUG) << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString()); + qDebug() << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount); + + addOneNoEyeCount(); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(DEBUG) << QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString()); + + // 找到眼睛则开始质量评估和编码 + // 调用远程算法进行编码 + if (CasicIrisRecState::getInstance().recoginzeId == "0") + { + // 第一次找到眼则 虹膜识别状态初始化 + CasicIrisRecState::getInstance().initRecognize(); + } + + CasicIrisRecState::getInstance().noEyeCount = 0; // 持续未找到眼的次数清零 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FIND_EYE; + CasicIrisRecState::getInstance().irisInfo->hasEye = irisInfo.hasEye; + CasicIrisRecState::getInstance().irisInfo->eyeRect = irisInfo.eyeRect; + CasicIrisRecState::getInstance().irisInfo->matData = irisInfo.matData; + CasicIrisRecState::getInstance().irisInfo->data = ImageUtil::MatImageToQImage(irisInfo.matData); + + QElapsedTimer timer; + timer.start(); + + QByteArray data((char*)irisInfo.matData.data, SettingConfig::getInstance().IRIS_WIDTH * SettingConfig::getInstance().IRIS_HEIGHT); + data.prepend("[-m]"); // 识别 + + // 发送TCP消息去匹配 + emit sendDataToExract(data); + + // 状态修改为特征提取 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FEATURE_EXTRACT; + + QTimer toTimer; + QEventLoop loop; + toTimer.singleShot(3000, &loop, &QEventLoop::quit); +// connect(clientUtil, &SocketClientUtil::responseReaded, &loop, &QEventLoop::quit); + loop.exec(); + +// QByteArray matchResponse = clientUtil->getResponse(); + QByteArray matchResponse; +// LOG(INFO) << QString("算法匹配结果").toStdString() << matchResponse.toStdString(); +// LOG_INFO("算法匹配结果 {}",matchResponse.toStdString()); + + // 算法调用返回成功 + if (matchResponse.size() > 0) + { + QString response = matchResponse.mid(5, matchResponse.size() - 6); + QStringList messList = response.split(";"); + QString code = messList.at(0); + if (code.toInt() == 0) + { + QString personId = messList.at(1); + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_SEARCH_SUCC; + +// LOG(INFO) << QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString(); +// LOG_INFO(QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString()); + + // 保存图像文件 +// cv::imwrite(QString("D:\\irisLogs\\%1-%2.bmp").arg(QDateTime::currentDateTime().toString("HHmmsszzz")).arg(irisInfo.leftOrRight).toStdString(), irisInfo.matData); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + emit findMatchedIris(personId); + this->afterRecogAction(); + } else if (code.toInt() == -200) + { + // 匹配失败 +// LOG(INFO) << QString("匹配失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("匹配失败: {}", matchResponse.toStdString()); + + // 匹配失败则尝试次数+1 + addOneTryCount(); + } else if (code.toInt() == -100) + { + // 编码失败 +// LOG(INFO) << QString("编码失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("编码失败: {}", matchResponse.toStdString()); + // 编码失败则尝试次数+1 + addOneTryCount(); + } + } else + { + // 超时返回则尝试次数+1 + addOneTryCount(); + } + } +} + +void IrisRecogProcess::afterRecogAction() +{ + this->setWorking(false); + + ProMemory::getInstance().clearIrisQueue(); // 清理虹膜数据栈 +} + +void IrisRecogProcess::addOneTryCount() +{ + CasicIrisRecState::getInstance().tryCount++; +// LOG(DEBUG) << QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString()); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().tryCount >= SettingConfig::getInstance().MAX_IRIS_TRY_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + CasicIrisRecState::getInstance().tryCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + emit failedMatchedIris(); + } +} +void IrisRecogProcess::addOneNoEyeCount() +{ + CasicIrisRecState::getInstance().noEyeCount++; + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().noEyeCount >= SettingConfig::getInstance().MAX_EYE_NOT_FOUND_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + + if (qrand() % 10 < 5) { + emit failedMatchedIris(); + } + else { + emit findMatchedIris("1"); + } + } +} diff --git a/device/iris/IrisRecogProcess.h b/device/iris/IrisRecogProcess.h new file mode 100644 index 0000000..c4fc648 --- /dev/null +++ b/device/iris/IrisRecogProcess.h @@ -0,0 +1,47 @@ +#ifndef IRISRECOGPROCESS_H +#define IRISRECOGPROCESS_H + +#include +#include +#include +#include + +#include "ProMemory.h" +#include "device/iris/CasicIrisRecState.h" + +class IrisRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit IrisRecogProcess(QObject *parent = 0); + ~IrisRecogProcess(); + + void setWorking(bool working); + void exitThread(); + + void addOneTryCount(); + void addOneNoEyeCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + + volatile bool working; + volatile bool exit; + +private: +// SocketClientUtil * clientUtil; + + void afterRecogAction(); + +signals: + void sendDataToExract(QByteArray data); + + void failedMatchedIris(); + void findMatchedIris(QString personId); + +}; + +#endif // IRISRECOGPROCESS_H diff --git a/images/bg_failure.png b/images/bg_failure.png new file mode 100644 index 0000000..55000a0 --- /dev/null +++ b/images/bg_failure.png Binary files differ diff --git a/images/bg_identifying.png b/images/bg_identifying.png new file mode 100644 index 0000000..58d5a95 --- /dev/null +++ b/images/bg_identifying.png Binary files differ diff --git a/images/bg_statcked.png b/images/bg_statcked.png index 18b63e1..c76130f 100644 --- a/images/bg_statcked.png +++ b/images/bg_statcked.png Binary files differ diff --git a/images/bg_success.png b/images/bg_success.png new file mode 100644 index 0000000..c845bb8 --- /dev/null +++ b/images/bg_success.png Binary files differ diff --git a/images/bg_title.png b/images/bg_title.png index 0316e2d..131369a 100644 --- a/images/bg_title.png +++ b/images/bg_title.png Binary files differ diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/casic/iris/CasicIrisInterface.cpp b/casic/iris/CasicIrisInterface.cpp new file mode 100644 index 0000000..5c46e5b --- /dev/null +++ b/casic/iris/CasicIrisInterface.cpp @@ -0,0 +1,187 @@ +#include "CasicIrisInterface.h" + +#include +#include +#include + +casic::iris::CasicIrisInterface::CasicIrisInterface() +{ + +} + +casic::iris::CasicIrisInterface::~CasicIrisInterface() +{ + +} + +void casic::iris::CasicIrisInterface::setCascadeFile(QString filename) +{ + this->cascadeName = filename.toStdString(); +} +void casic::iris::CasicIrisInterface::setMinEyeSize(int minEyeSize) +{ + this->minEyeSize = minEyeSize; +} +void casic::iris::CasicIrisInterface::setMaxEyeSize(int maxEyeSize) +{ + this->maxEyeSize = maxEyeSize; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.data = ImageUtil::MatImageToQImage(irisInfo.matData); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findAndCutEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + // 找到眼睛之后, 将眼部裁剪下来, 图像拉伸到640 * 480 + cv::Point center; + center.x = cvFloor(rect.at(0).x + rect.at(0).width*0.5); + center.y = cvFloor(rect.at(0).y + rect.at(0).height*0.5); + + // 限制中心点的范围 + if (center.x < SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) + { + // x小于240则x=240 +// center.x = center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + center.x = SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } else if (center.x > SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) { + // x大于1040则x=1040 + center.x = SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } + + if (center.y < SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) + { + // y小于180则y=180 + center.y = SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } else if (center.y > SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) { + center.y = SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } + + // 裁剪眼部图像 + cv::Mat halfSize = irisInfo.matData.clone(); + halfSize = irisInfo.matData(cv::Rect(center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5, + center.y - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5, + SettingConfig::getInstance().IRIS_WIDTH * cutRatio, + SettingConfig::getInstance().IRIS_HEIGHT * cutRatio)); + + cv::resize(halfSize, halfSize, cv::Size(SettingConfig::getInstance().IRIS_WIDTH, SettingConfig::getInstance().IRIS_HEIGHT)); + cv::flip(halfSize, halfSize, 1); // 左右翻转 + +// cv::imwrite(QString("d:\\irisLogs\\%1.bmp").arg(QDateTime::currentSecsSinceEpoch()).toStdString(), halfSize); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.matData = halfSize; + irisInfo.data = ImageUtil::MatImageToQImage(halfSize); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisQualityAssess(CasicIrisInfo irisInfo) +{ + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisCodeExtract(CasicIrisInfo irisInfo) +{ + + QElapsedTimer timer; + timer.start(); + +// QSocketClientUtil * clientUtil = new QSocketClientUtil(); + + QByteArray data((char*)irisInfo.matData.data, 640*480); + + std::cout << "extract iris code" << std::endl; + +// clientUtil->sendData(data); +// if (response.size() == 1024) +// { +// QLog::getInstance()->logger()->debug(QString("特征值提取[耗时: %1ms][特征值: %2]\n") +// .arg(timer.elapsed()) +// .arg(QByteUtil::binToHexString(response))); +// } else +// { +// std::cout << response.toStdString() << std::endl; +// } + + return irisInfo; +} diff --git a/casic/iris/CasicIrisInterface.h b/casic/iris/CasicIrisInterface.h new file mode 100644 index 0000000..87ed97e --- /dev/null +++ b/casic/iris/CasicIrisInterface.h @@ -0,0 +1,45 @@ +#ifndef CASICIRISINTERFACE_H +#define CASICIRISINTERFACE_H + +#include "CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +namespace casic { + namespace iris { + class CasicIrisInterface + { + public: + ~CasicIrisInterface(); + CasicIrisInterface(const CasicIrisInterface&)=delete; + CasicIrisInterface& operator=(const CasicIrisInterface&)=delete; + + static CasicIrisInterface& getInstance() { + static CasicIrisInterface instance; + return instance; + } + + CasicIrisInfo findEye(CasicIrisInfo irisInfo); + CasicIrisInfo findAndCutEye(CasicIrisInfo irisInfo); + CasicIrisInfo irisQualityAssess(CasicIrisInfo irisInfo); + CasicIrisInfo irisCodeExtract(CasicIrisInfo irisInfo); + CasicIrisInfo irisMatch(CasicIrisInfo irisInfo); + + void setCascadeFile(QString filename); + void setMinEyeSize(int minEyeSize); + void setMaxEyeSize(int maxEyeSize); + + private: + CasicIrisInterface(); + + std::string cascadeName = "./model/haarcascade_eye.xml"; + int minEyeSize = 320; + int maxEyeSize = 480; + float cutRatio = 1.0; + + cv::CascadeClassifier * cascade; + }; + } +} + + +#endif // CASICIRISINTERFACE_H diff --git a/casic/iris/casicIris.pri b/casic/iris/casicIris.pri new file mode 100644 index 0000000..d0942ce --- /dev/null +++ b/casic/iris/casicIris.pri @@ -0,0 +1,4 @@ +HEADERS += $$PWD/CasicIrisInfo.h +HEADERS += $$PWD/CasicIrisInterface.h + +SOURCES += $$PWD/CasicIrisInterface.cpp diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index 45df089..49e7316 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -1,4 +1,5 @@ #include "IrisCameraCapEventHandler.h" +#include IrisCameraCapEventHandler::IrisCameraCapEventHandler(QObject *parent) : QObject(parent) { @@ -14,90 +15,37 @@ auto camName = cam->getPtr()->GetDeviceInfo().GetUserID(); int width = objImageDataPointer->GetWidth(); int height = objImageDataPointer->GetHeight(); - size_t leftKeyIndex = camName.find("left"); - size_t rightKeyIndex = camName.find("right"); uchar * pBuffer = (BYTE*)objImageDataPointer->GetBuffer(); - - // 相机拍摄下的图像1440*1080, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 -// QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到400 * 300的尺寸 - img = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT, SettingConfig::getInstance().IRIS_DISPLAY_WIDTH); - img = img.transformed(QTransform().rotate(-90)); // 图像逆时针旋转90度 - - // 发送到界面进行显示 - emit sendIrisFrameToDraw(img); -// cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - -// irisInfo.data = imgAlgo; -// irisInfo.matData = irisMat; - -// // 将图像显示在注册页面的label上 -// // 并将虹膜信息对象存入队列中 -// ProMemory::getInstance().pushCasicIris(irisInfo); - -// if (leftKeyIndex >= 0 && leftKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 0); // 左眼画面 -// } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 1); // 右眼画面 -// } -/* if (pBuffer != NULL) { + // 相机拍摄下的图像1440*1080, 直接用于算法判断 + QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 + QImage imgDisp; + + // 图像逆时针旋转90度 + img = img.transformed(QTransform().rotate(90)); + + // 用于显示的图像需要缩小到480 * 640的尺寸 + imgDisp = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_WIDTH, SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT); + + // 发送到界面进行显示 + emit sendIrisFrameToDraw(imgDisp); + // 创建虹膜信息对象 CasicIrisInfo irisInfo; irisInfo.hasEye = false; - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - // 左眼相机拍摄的图像 - irisInfo.leftOrRight = "left"; - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - // 右眼相机 - irisInfo.leftOrRight = "right"; - } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - cv::Mat irisMat = ImageUtil::QImageToMat(imgDisp); + // 存入图像栈 + cv::Mat irisMat = ImageUtil::QImageToMat(img); + irisInfo.matData = irisMat; - irisInfo.data = imgDisp; - irisInfo.matData = irisMat; + ProMemory::getInstance().pushCasicIris(irisInfo); - ProMemory::getInstance().pushCasicIris(irisInfo); - -// cv::imwrite(QString("D:\\irisLogs\\iristest-%1.bmp").arg(irisInfo.leftOrRight).toStdString(), irisMat); - } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到1/4的尺寸 - img = img.scaled(640, 480); - cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - - irisInfo.data = imgAlgo; - irisInfo.matData = irisMat; - - // 将图像显示在注册页面的label上 - // 并将虹膜信息对象存入队列中 - ProMemory::getInstance().pushCasicIris(irisInfo); - - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 0); // 左眼画面 - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 1); // 右眼画面 - } - } - }*/ + /* 相机控制只拍图 不找眼 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + */ + } } } diff --git a/device/IrisCameraCapEventHandler.h b/device/IrisCameraCapEventHandler.h index ad75a97..8b976c5 100644 --- a/device/IrisCameraCapEventHandler.h +++ b/device/IrisCameraCapEventHandler.h @@ -6,7 +6,7 @@ #include "include/opencv2/opencv.hpp" #include "include/daheng/GalaxyIncludes.h" -//#include "casic/iris/CasicIrisInterface.h" +#include "casic/iris/CasicIrisInterface.h" #include "ProMemory.h" #include "utils/UtilInclude.h" diff --git a/device/device.pri b/device/device.pri index a8417f2..d1330a0 100644 --- a/device/device.pri +++ b/device/device.pri @@ -2,12 +2,12 @@ HEADERS += $$PWD/IrisCameraController.h HEADERS += $$PWD/IrisCameraCapEventHandler.h #HEADERS += $$PWD/iris/IrisRegistProcess.h -#HEADERS += $$PWD/iris/IrisRecogProcess.h -#HEADERS += $$PWD/iris/CasicIrisRecState.h +HEADERS += $$PWD/iris/IrisRecogProcess.h +HEADERS += $$PWD/iris/CasicIrisRecState.h SOURCES += $$PWD/IrisCameraController.cpp SOURCES += $$PWD/IrisCameraCapEventHandler.cpp #SOURCES += $$PWD/iris/IrisRegistProcess.cpp -#SOURCES += $$PWD/iris/IrisRecogProcess.cpp -#SOURCES += $$PWD/iris/CasicIrisRecState.cpp +SOURCES += $$PWD/iris/IrisRecogProcess.cpp +SOURCES += $$PWD/iris/CasicIrisRecState.cpp diff --git a/device/iris/CasicIrisRecState.cpp b/device/iris/CasicIrisRecState.cpp new file mode 100644 index 0000000..b64d747 --- /dev/null +++ b/device/iris/CasicIrisRecState.cpp @@ -0,0 +1,63 @@ +#include "CasicIrisRecState.h" +#include "utils/UtilInclude.h" + +CasicIrisRecState::CasicIrisRecState() +{ + this->recoginzeId = "0"; + this->timeStamp = -1; + + this->state = IrisRecStateName::REC_NOT_START; + + this->irisInfo = new CasicIrisInfo(); +} + +CasicIrisRecState::~CasicIrisRecState() +{ + delete this->irisInfo; +} + +void CasicIrisRecState::initRecognize() +{ + QDateTime now = QDateTime::currentDateTime(); + this->recoginzeId = now.toString("yyyyMMddHHmmsszzz"); + this->timeStamp = now.toMSecsSinceEpoch(); + this->tryCount = 0; + this->noEyeCount = 0; + +// LOG(DEBUG) << QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString()); + qDebug() << QString("[CasicIrisRecState][initRecognize][%1] 虹膜识别状态初始化").arg(recoginzeId); + +} + +QString CasicIrisRecState::toString() +{ + return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)); +} + + +QJsonObject CasicIrisRecState::toJSON() +{ + QJsonObject obj; + + obj.insert("recoginzeId", recoginzeId); + obj.insert("timestamp", timeStamp); + obj.insert("timestampSucc", timeStampSucc); + obj.insert("state", state); + obj.insert("tryCount", tryCount); + obj.insert("noEyeCount", noEyeCount); + obj.insert("recogTimeLast", recogTimeLast); + + QJsonObject eyeObj; + eyeObj.insert("hasEye", irisInfo->hasEye); + QJsonArray rectArray; + rectArray.append(irisInfo->eyeRect.x); + rectArray.append(irisInfo->eyeRect.y); + rectArray.append(irisInfo->eyeRect.width); + rectArray.append(irisInfo->eyeRect.height); + eyeObj.insert("faceRect", rectArray); + + obj.insert("eye", eyeObj); + + return obj; +} diff --git a/device/iris/CasicIrisRecState.h b/device/iris/CasicIrisRecState.h new file mode 100644 index 0000000..eea5ddf --- /dev/null +++ b/device/iris/CasicIrisRecState.h @@ -0,0 +1,67 @@ +#ifndef CASICIRISRECSTATE_H +#define CASICIRISRECSTATE_H + +#include +#include +#include +#include + +#include "casic/iris/CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +class CasicIrisRecState : public QObject +{ +public: + ~CasicIrisRecState(); + CasicIrisRecState(const CasicIrisRecState&)=delete; + CasicIrisRecState& operator=(const CasicIrisRecState&)=delete; + + static CasicIrisRecState& getInstance() { + static CasicIrisRecState instance; + return instance; + } + + void initRecognize(); + QString toString(); + QJsonObject toJSON(); + + QString recoginzeId; // 识别过程id + qint64 timeStamp = 0; // 识别开始时间戳 + qint64 timeStampSucc = 0; // 识别成功时的时间戳 + qint64 findEyeTmLast = 0; // 找眼操作耗时 + + CasicIrisInfo * irisInfo; + + qint8 tryCount = 0; // 识别尝试次数 + qint8 noEyeCount = 0; // 连续没有找到眼睛次数 + float recogTimeLast = 0.0; // 识别成功耗时 + + /** + * @brief state + * 0=初始值 + * 1=左眼检测 + * 2=右眼检测 + * 3=质量评估 + * 4=特征值提取 + * 5=虹膜库比对成功 + * 6=虹膜库比对失败 + */ + volatile int state; + + enum IrisRecStateName + { + REC_NOT_START = 0, // 未开始 + REC_LEFT_FIND_EYE = 1, // 检测左眼, 没找到右眼 + REC_RIGHT_FIND_EYE = 2, // 检测右眼, 没找到左眼 + REC_FIND_EYE = 3, // 找到左眼和右眼 + REC_FEATURE_EXTRACT = 4, // 特征值提取成功 + REC_SEARCH_SUCC = 5, // 虹膜库比对成功 + REC_SEARCH_FAIL = 6 // 虹膜库比对失败 + }; + +private: + CasicIrisRecState(); + +}; + +#endif // CASICIRISRECSTATE_H diff --git a/device/iris/IrisRecogProcess.cpp b/device/iris/IrisRecogProcess.cpp new file mode 100644 index 0000000..6869ece --- /dev/null +++ b/device/iris/IrisRecogProcess.cpp @@ -0,0 +1,223 @@ +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + + +#include "IrisRecogProcess.h" + +IrisRecogProcess::IrisRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; + + // 连接算法服务 +// clientUtil = new SocketClientUtil(this); +// clientUtil->connect("127.0.0.1", 2015); + + // 调用socket发送消息 +// connect(this, &IrisRecogProcess::sendDataToExract, clientUtil, &SocketClientUtil::sendData); +} + +IrisRecogProcess::~IrisRecogProcess() +{ + this->setWorking(false); +} + +void IrisRecogProcess::setWorking(bool working) +{ + this->working = working; +} + +void IrisRecogProcess::exitThread() +{ + this->exit = true; +} + +void IrisRecogProcess::run() +{ + while (exit == false) + { + // 如果工作标志位为否, 则跳出 + if (this->working == false) + { + this->msleep(200); // 200ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isIrisQueueEmpty() == true) + { +// LOG(TRACE) << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString()); + qDebug() << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms"); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicIrisRecState::getInstance().state != CasicIrisRecState::IrisRecStateName::REC_NOT_START) + { +// LOG(DEBUG) << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state).toStdString(); + + qDebug() << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(TRACE) << QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString()); + + // 取出虹膜图像栈中的一条数据 + CasicIrisInfo irisInfo = ProMemory::getInstance().popCasicIris(); + +// LOG(DEBUG) << QString("[IrisRecogProcess] 取出虹膜图像").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 取出虹膜图像").toStdString()); + qDebug() << QString("[IrisRecogProcess] 取出虹膜图像"); + + // 调用找眼分类器算法 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findAndCutEye(irisInfo); + + // 没有找到眼睛则返回 + if (irisInfo.hasEye == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 +// LOG(DEBUG) << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString()); + qDebug() << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount); + + addOneNoEyeCount(); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(DEBUG) << QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString()); + + // 找到眼睛则开始质量评估和编码 + // 调用远程算法进行编码 + if (CasicIrisRecState::getInstance().recoginzeId == "0") + { + // 第一次找到眼则 虹膜识别状态初始化 + CasicIrisRecState::getInstance().initRecognize(); + } + + CasicIrisRecState::getInstance().noEyeCount = 0; // 持续未找到眼的次数清零 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FIND_EYE; + CasicIrisRecState::getInstance().irisInfo->hasEye = irisInfo.hasEye; + CasicIrisRecState::getInstance().irisInfo->eyeRect = irisInfo.eyeRect; + CasicIrisRecState::getInstance().irisInfo->matData = irisInfo.matData; + CasicIrisRecState::getInstance().irisInfo->data = ImageUtil::MatImageToQImage(irisInfo.matData); + + QElapsedTimer timer; + timer.start(); + + QByteArray data((char*)irisInfo.matData.data, SettingConfig::getInstance().IRIS_WIDTH * SettingConfig::getInstance().IRIS_HEIGHT); + data.prepend("[-m]"); // 识别 + + // 发送TCP消息去匹配 + emit sendDataToExract(data); + + // 状态修改为特征提取 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FEATURE_EXTRACT; + + QTimer toTimer; + QEventLoop loop; + toTimer.singleShot(3000, &loop, &QEventLoop::quit); +// connect(clientUtil, &SocketClientUtil::responseReaded, &loop, &QEventLoop::quit); + loop.exec(); + +// QByteArray matchResponse = clientUtil->getResponse(); + QByteArray matchResponse; +// LOG(INFO) << QString("算法匹配结果").toStdString() << matchResponse.toStdString(); +// LOG_INFO("算法匹配结果 {}",matchResponse.toStdString()); + + // 算法调用返回成功 + if (matchResponse.size() > 0) + { + QString response = matchResponse.mid(5, matchResponse.size() - 6); + QStringList messList = response.split(";"); + QString code = messList.at(0); + if (code.toInt() == 0) + { + QString personId = messList.at(1); + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_SEARCH_SUCC; + +// LOG(INFO) << QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString(); +// LOG_INFO(QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString()); + + // 保存图像文件 +// cv::imwrite(QString("D:\\irisLogs\\%1-%2.bmp").arg(QDateTime::currentDateTime().toString("HHmmsszzz")).arg(irisInfo.leftOrRight).toStdString(), irisInfo.matData); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + emit findMatchedIris(personId); + this->afterRecogAction(); + } else if (code.toInt() == -200) + { + // 匹配失败 +// LOG(INFO) << QString("匹配失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("匹配失败: {}", matchResponse.toStdString()); + + // 匹配失败则尝试次数+1 + addOneTryCount(); + } else if (code.toInt() == -100) + { + // 编码失败 +// LOG(INFO) << QString("编码失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("编码失败: {}", matchResponse.toStdString()); + // 编码失败则尝试次数+1 + addOneTryCount(); + } + } else + { + // 超时返回则尝试次数+1 + addOneTryCount(); + } + } +} + +void IrisRecogProcess::afterRecogAction() +{ + this->setWorking(false); + + ProMemory::getInstance().clearIrisQueue(); // 清理虹膜数据栈 +} + +void IrisRecogProcess::addOneTryCount() +{ + CasicIrisRecState::getInstance().tryCount++; +// LOG(DEBUG) << QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString()); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().tryCount >= SettingConfig::getInstance().MAX_IRIS_TRY_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + CasicIrisRecState::getInstance().tryCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + emit failedMatchedIris(); + } +} +void IrisRecogProcess::addOneNoEyeCount() +{ + CasicIrisRecState::getInstance().noEyeCount++; + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().noEyeCount >= SettingConfig::getInstance().MAX_EYE_NOT_FOUND_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + + if (qrand() % 10 < 5) { + emit failedMatchedIris(); + } + else { + emit findMatchedIris("1"); + } + } +} diff --git a/device/iris/IrisRecogProcess.h b/device/iris/IrisRecogProcess.h new file mode 100644 index 0000000..c4fc648 --- /dev/null +++ b/device/iris/IrisRecogProcess.h @@ -0,0 +1,47 @@ +#ifndef IRISRECOGPROCESS_H +#define IRISRECOGPROCESS_H + +#include +#include +#include +#include + +#include "ProMemory.h" +#include "device/iris/CasicIrisRecState.h" + +class IrisRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit IrisRecogProcess(QObject *parent = 0); + ~IrisRecogProcess(); + + void setWorking(bool working); + void exitThread(); + + void addOneTryCount(); + void addOneNoEyeCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + + volatile bool working; + volatile bool exit; + +private: +// SocketClientUtil * clientUtil; + + void afterRecogAction(); + +signals: + void sendDataToExract(QByteArray data); + + void failedMatchedIris(); + void findMatchedIris(QString personId); + +}; + +#endif // IRISRECOGPROCESS_H diff --git a/images/bg_failure.png b/images/bg_failure.png new file mode 100644 index 0000000..55000a0 --- /dev/null +++ b/images/bg_failure.png Binary files differ diff --git a/images/bg_identifying.png b/images/bg_identifying.png new file mode 100644 index 0000000..58d5a95 --- /dev/null +++ b/images/bg_identifying.png Binary files differ diff --git a/images/bg_statcked.png b/images/bg_statcked.png index 18b63e1..c76130f 100644 --- a/images/bg_statcked.png +++ b/images/bg_statcked.png Binary files differ diff --git a/images/bg_success.png b/images/bg_success.png new file mode 100644 index 0000000..c845bb8 --- /dev/null +++ b/images/bg_success.png Binary files differ diff --git a/images/bg_title.png b/images/bg_title.png index 0316e2d..131369a 100644 --- a/images/bg_title.png +++ b/images/bg_title.png Binary files differ diff --git a/images/iconWarn.png b/images/iconWarn.png new file mode 100644 index 0000000..e1d6403 --- /dev/null +++ b/images/iconWarn.png Binary files differ diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/casic/iris/CasicIrisInterface.cpp b/casic/iris/CasicIrisInterface.cpp new file mode 100644 index 0000000..5c46e5b --- /dev/null +++ b/casic/iris/CasicIrisInterface.cpp @@ -0,0 +1,187 @@ +#include "CasicIrisInterface.h" + +#include +#include +#include + +casic::iris::CasicIrisInterface::CasicIrisInterface() +{ + +} + +casic::iris::CasicIrisInterface::~CasicIrisInterface() +{ + +} + +void casic::iris::CasicIrisInterface::setCascadeFile(QString filename) +{ + this->cascadeName = filename.toStdString(); +} +void casic::iris::CasicIrisInterface::setMinEyeSize(int minEyeSize) +{ + this->minEyeSize = minEyeSize; +} +void casic::iris::CasicIrisInterface::setMaxEyeSize(int maxEyeSize) +{ + this->maxEyeSize = maxEyeSize; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.data = ImageUtil::MatImageToQImage(irisInfo.matData); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findAndCutEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + // 找到眼睛之后, 将眼部裁剪下来, 图像拉伸到640 * 480 + cv::Point center; + center.x = cvFloor(rect.at(0).x + rect.at(0).width*0.5); + center.y = cvFloor(rect.at(0).y + rect.at(0).height*0.5); + + // 限制中心点的范围 + if (center.x < SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) + { + // x小于240则x=240 +// center.x = center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + center.x = SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } else if (center.x > SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) { + // x大于1040则x=1040 + center.x = SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } + + if (center.y < SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) + { + // y小于180则y=180 + center.y = SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } else if (center.y > SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) { + center.y = SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } + + // 裁剪眼部图像 + cv::Mat halfSize = irisInfo.matData.clone(); + halfSize = irisInfo.matData(cv::Rect(center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5, + center.y - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5, + SettingConfig::getInstance().IRIS_WIDTH * cutRatio, + SettingConfig::getInstance().IRIS_HEIGHT * cutRatio)); + + cv::resize(halfSize, halfSize, cv::Size(SettingConfig::getInstance().IRIS_WIDTH, SettingConfig::getInstance().IRIS_HEIGHT)); + cv::flip(halfSize, halfSize, 1); // 左右翻转 + +// cv::imwrite(QString("d:\\irisLogs\\%1.bmp").arg(QDateTime::currentSecsSinceEpoch()).toStdString(), halfSize); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.matData = halfSize; + irisInfo.data = ImageUtil::MatImageToQImage(halfSize); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisQualityAssess(CasicIrisInfo irisInfo) +{ + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisCodeExtract(CasicIrisInfo irisInfo) +{ + + QElapsedTimer timer; + timer.start(); + +// QSocketClientUtil * clientUtil = new QSocketClientUtil(); + + QByteArray data((char*)irisInfo.matData.data, 640*480); + + std::cout << "extract iris code" << std::endl; + +// clientUtil->sendData(data); +// if (response.size() == 1024) +// { +// QLog::getInstance()->logger()->debug(QString("特征值提取[耗时: %1ms][特征值: %2]\n") +// .arg(timer.elapsed()) +// .arg(QByteUtil::binToHexString(response))); +// } else +// { +// std::cout << response.toStdString() << std::endl; +// } + + return irisInfo; +} diff --git a/casic/iris/CasicIrisInterface.h b/casic/iris/CasicIrisInterface.h new file mode 100644 index 0000000..87ed97e --- /dev/null +++ b/casic/iris/CasicIrisInterface.h @@ -0,0 +1,45 @@ +#ifndef CASICIRISINTERFACE_H +#define CASICIRISINTERFACE_H + +#include "CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +namespace casic { + namespace iris { + class CasicIrisInterface + { + public: + ~CasicIrisInterface(); + CasicIrisInterface(const CasicIrisInterface&)=delete; + CasicIrisInterface& operator=(const CasicIrisInterface&)=delete; + + static CasicIrisInterface& getInstance() { + static CasicIrisInterface instance; + return instance; + } + + CasicIrisInfo findEye(CasicIrisInfo irisInfo); + CasicIrisInfo findAndCutEye(CasicIrisInfo irisInfo); + CasicIrisInfo irisQualityAssess(CasicIrisInfo irisInfo); + CasicIrisInfo irisCodeExtract(CasicIrisInfo irisInfo); + CasicIrisInfo irisMatch(CasicIrisInfo irisInfo); + + void setCascadeFile(QString filename); + void setMinEyeSize(int minEyeSize); + void setMaxEyeSize(int maxEyeSize); + + private: + CasicIrisInterface(); + + std::string cascadeName = "./model/haarcascade_eye.xml"; + int minEyeSize = 320; + int maxEyeSize = 480; + float cutRatio = 1.0; + + cv::CascadeClassifier * cascade; + }; + } +} + + +#endif // CASICIRISINTERFACE_H diff --git a/casic/iris/casicIris.pri b/casic/iris/casicIris.pri new file mode 100644 index 0000000..d0942ce --- /dev/null +++ b/casic/iris/casicIris.pri @@ -0,0 +1,4 @@ +HEADERS += $$PWD/CasicIrisInfo.h +HEADERS += $$PWD/CasicIrisInterface.h + +SOURCES += $$PWD/CasicIrisInterface.cpp diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index 45df089..49e7316 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -1,4 +1,5 @@ #include "IrisCameraCapEventHandler.h" +#include IrisCameraCapEventHandler::IrisCameraCapEventHandler(QObject *parent) : QObject(parent) { @@ -14,90 +15,37 @@ auto camName = cam->getPtr()->GetDeviceInfo().GetUserID(); int width = objImageDataPointer->GetWidth(); int height = objImageDataPointer->GetHeight(); - size_t leftKeyIndex = camName.find("left"); - size_t rightKeyIndex = camName.find("right"); uchar * pBuffer = (BYTE*)objImageDataPointer->GetBuffer(); - - // 相机拍摄下的图像1440*1080, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 -// QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到400 * 300的尺寸 - img = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT, SettingConfig::getInstance().IRIS_DISPLAY_WIDTH); - img = img.transformed(QTransform().rotate(-90)); // 图像逆时针旋转90度 - - // 发送到界面进行显示 - emit sendIrisFrameToDraw(img); -// cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - -// irisInfo.data = imgAlgo; -// irisInfo.matData = irisMat; - -// // 将图像显示在注册页面的label上 -// // 并将虹膜信息对象存入队列中 -// ProMemory::getInstance().pushCasicIris(irisInfo); - -// if (leftKeyIndex >= 0 && leftKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 0); // 左眼画面 -// } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 1); // 右眼画面 -// } -/* if (pBuffer != NULL) { + // 相机拍摄下的图像1440*1080, 直接用于算法判断 + QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 + QImage imgDisp; + + // 图像逆时针旋转90度 + img = img.transformed(QTransform().rotate(90)); + + // 用于显示的图像需要缩小到480 * 640的尺寸 + imgDisp = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_WIDTH, SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT); + + // 发送到界面进行显示 + emit sendIrisFrameToDraw(imgDisp); + // 创建虹膜信息对象 CasicIrisInfo irisInfo; irisInfo.hasEye = false; - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - // 左眼相机拍摄的图像 - irisInfo.leftOrRight = "left"; - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - // 右眼相机 - irisInfo.leftOrRight = "right"; - } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - cv::Mat irisMat = ImageUtil::QImageToMat(imgDisp); + // 存入图像栈 + cv::Mat irisMat = ImageUtil::QImageToMat(img); + irisInfo.matData = irisMat; - irisInfo.data = imgDisp; - irisInfo.matData = irisMat; + ProMemory::getInstance().pushCasicIris(irisInfo); - ProMemory::getInstance().pushCasicIris(irisInfo); - -// cv::imwrite(QString("D:\\irisLogs\\iristest-%1.bmp").arg(irisInfo.leftOrRight).toStdString(), irisMat); - } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到1/4的尺寸 - img = img.scaled(640, 480); - cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - - irisInfo.data = imgAlgo; - irisInfo.matData = irisMat; - - // 将图像显示在注册页面的label上 - // 并将虹膜信息对象存入队列中 - ProMemory::getInstance().pushCasicIris(irisInfo); - - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 0); // 左眼画面 - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 1); // 右眼画面 - } - } - }*/ + /* 相机控制只拍图 不找眼 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + */ + } } } diff --git a/device/IrisCameraCapEventHandler.h b/device/IrisCameraCapEventHandler.h index ad75a97..8b976c5 100644 --- a/device/IrisCameraCapEventHandler.h +++ b/device/IrisCameraCapEventHandler.h @@ -6,7 +6,7 @@ #include "include/opencv2/opencv.hpp" #include "include/daheng/GalaxyIncludes.h" -//#include "casic/iris/CasicIrisInterface.h" +#include "casic/iris/CasicIrisInterface.h" #include "ProMemory.h" #include "utils/UtilInclude.h" diff --git a/device/device.pri b/device/device.pri index a8417f2..d1330a0 100644 --- a/device/device.pri +++ b/device/device.pri @@ -2,12 +2,12 @@ HEADERS += $$PWD/IrisCameraController.h HEADERS += $$PWD/IrisCameraCapEventHandler.h #HEADERS += $$PWD/iris/IrisRegistProcess.h -#HEADERS += $$PWD/iris/IrisRecogProcess.h -#HEADERS += $$PWD/iris/CasicIrisRecState.h +HEADERS += $$PWD/iris/IrisRecogProcess.h +HEADERS += $$PWD/iris/CasicIrisRecState.h SOURCES += $$PWD/IrisCameraController.cpp SOURCES += $$PWD/IrisCameraCapEventHandler.cpp #SOURCES += $$PWD/iris/IrisRegistProcess.cpp -#SOURCES += $$PWD/iris/IrisRecogProcess.cpp -#SOURCES += $$PWD/iris/CasicIrisRecState.cpp +SOURCES += $$PWD/iris/IrisRecogProcess.cpp +SOURCES += $$PWD/iris/CasicIrisRecState.cpp diff --git a/device/iris/CasicIrisRecState.cpp b/device/iris/CasicIrisRecState.cpp new file mode 100644 index 0000000..b64d747 --- /dev/null +++ b/device/iris/CasicIrisRecState.cpp @@ -0,0 +1,63 @@ +#include "CasicIrisRecState.h" +#include "utils/UtilInclude.h" + +CasicIrisRecState::CasicIrisRecState() +{ + this->recoginzeId = "0"; + this->timeStamp = -1; + + this->state = IrisRecStateName::REC_NOT_START; + + this->irisInfo = new CasicIrisInfo(); +} + +CasicIrisRecState::~CasicIrisRecState() +{ + delete this->irisInfo; +} + +void CasicIrisRecState::initRecognize() +{ + QDateTime now = QDateTime::currentDateTime(); + this->recoginzeId = now.toString("yyyyMMddHHmmsszzz"); + this->timeStamp = now.toMSecsSinceEpoch(); + this->tryCount = 0; + this->noEyeCount = 0; + +// LOG(DEBUG) << QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString()); + qDebug() << QString("[CasicIrisRecState][initRecognize][%1] 虹膜识别状态初始化").arg(recoginzeId); + +} + +QString CasicIrisRecState::toString() +{ + return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)); +} + + +QJsonObject CasicIrisRecState::toJSON() +{ + QJsonObject obj; + + obj.insert("recoginzeId", recoginzeId); + obj.insert("timestamp", timeStamp); + obj.insert("timestampSucc", timeStampSucc); + obj.insert("state", state); + obj.insert("tryCount", tryCount); + obj.insert("noEyeCount", noEyeCount); + obj.insert("recogTimeLast", recogTimeLast); + + QJsonObject eyeObj; + eyeObj.insert("hasEye", irisInfo->hasEye); + QJsonArray rectArray; + rectArray.append(irisInfo->eyeRect.x); + rectArray.append(irisInfo->eyeRect.y); + rectArray.append(irisInfo->eyeRect.width); + rectArray.append(irisInfo->eyeRect.height); + eyeObj.insert("faceRect", rectArray); + + obj.insert("eye", eyeObj); + + return obj; +} diff --git a/device/iris/CasicIrisRecState.h b/device/iris/CasicIrisRecState.h new file mode 100644 index 0000000..eea5ddf --- /dev/null +++ b/device/iris/CasicIrisRecState.h @@ -0,0 +1,67 @@ +#ifndef CASICIRISRECSTATE_H +#define CASICIRISRECSTATE_H + +#include +#include +#include +#include + +#include "casic/iris/CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +class CasicIrisRecState : public QObject +{ +public: + ~CasicIrisRecState(); + CasicIrisRecState(const CasicIrisRecState&)=delete; + CasicIrisRecState& operator=(const CasicIrisRecState&)=delete; + + static CasicIrisRecState& getInstance() { + static CasicIrisRecState instance; + return instance; + } + + void initRecognize(); + QString toString(); + QJsonObject toJSON(); + + QString recoginzeId; // 识别过程id + qint64 timeStamp = 0; // 识别开始时间戳 + qint64 timeStampSucc = 0; // 识别成功时的时间戳 + qint64 findEyeTmLast = 0; // 找眼操作耗时 + + CasicIrisInfo * irisInfo; + + qint8 tryCount = 0; // 识别尝试次数 + qint8 noEyeCount = 0; // 连续没有找到眼睛次数 + float recogTimeLast = 0.0; // 识别成功耗时 + + /** + * @brief state + * 0=初始值 + * 1=左眼检测 + * 2=右眼检测 + * 3=质量评估 + * 4=特征值提取 + * 5=虹膜库比对成功 + * 6=虹膜库比对失败 + */ + volatile int state; + + enum IrisRecStateName + { + REC_NOT_START = 0, // 未开始 + REC_LEFT_FIND_EYE = 1, // 检测左眼, 没找到右眼 + REC_RIGHT_FIND_EYE = 2, // 检测右眼, 没找到左眼 + REC_FIND_EYE = 3, // 找到左眼和右眼 + REC_FEATURE_EXTRACT = 4, // 特征值提取成功 + REC_SEARCH_SUCC = 5, // 虹膜库比对成功 + REC_SEARCH_FAIL = 6 // 虹膜库比对失败 + }; + +private: + CasicIrisRecState(); + +}; + +#endif // CASICIRISRECSTATE_H diff --git a/device/iris/IrisRecogProcess.cpp b/device/iris/IrisRecogProcess.cpp new file mode 100644 index 0000000..6869ece --- /dev/null +++ b/device/iris/IrisRecogProcess.cpp @@ -0,0 +1,223 @@ +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + + +#include "IrisRecogProcess.h" + +IrisRecogProcess::IrisRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; + + // 连接算法服务 +// clientUtil = new SocketClientUtil(this); +// clientUtil->connect("127.0.0.1", 2015); + + // 调用socket发送消息 +// connect(this, &IrisRecogProcess::sendDataToExract, clientUtil, &SocketClientUtil::sendData); +} + +IrisRecogProcess::~IrisRecogProcess() +{ + this->setWorking(false); +} + +void IrisRecogProcess::setWorking(bool working) +{ + this->working = working; +} + +void IrisRecogProcess::exitThread() +{ + this->exit = true; +} + +void IrisRecogProcess::run() +{ + while (exit == false) + { + // 如果工作标志位为否, 则跳出 + if (this->working == false) + { + this->msleep(200); // 200ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isIrisQueueEmpty() == true) + { +// LOG(TRACE) << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString()); + qDebug() << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms"); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicIrisRecState::getInstance().state != CasicIrisRecState::IrisRecStateName::REC_NOT_START) + { +// LOG(DEBUG) << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state).toStdString(); + + qDebug() << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(TRACE) << QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString()); + + // 取出虹膜图像栈中的一条数据 + CasicIrisInfo irisInfo = ProMemory::getInstance().popCasicIris(); + +// LOG(DEBUG) << QString("[IrisRecogProcess] 取出虹膜图像").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 取出虹膜图像").toStdString()); + qDebug() << QString("[IrisRecogProcess] 取出虹膜图像"); + + // 调用找眼分类器算法 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findAndCutEye(irisInfo); + + // 没有找到眼睛则返回 + if (irisInfo.hasEye == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 +// LOG(DEBUG) << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString()); + qDebug() << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount); + + addOneNoEyeCount(); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(DEBUG) << QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString()); + + // 找到眼睛则开始质量评估和编码 + // 调用远程算法进行编码 + if (CasicIrisRecState::getInstance().recoginzeId == "0") + { + // 第一次找到眼则 虹膜识别状态初始化 + CasicIrisRecState::getInstance().initRecognize(); + } + + CasicIrisRecState::getInstance().noEyeCount = 0; // 持续未找到眼的次数清零 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FIND_EYE; + CasicIrisRecState::getInstance().irisInfo->hasEye = irisInfo.hasEye; + CasicIrisRecState::getInstance().irisInfo->eyeRect = irisInfo.eyeRect; + CasicIrisRecState::getInstance().irisInfo->matData = irisInfo.matData; + CasicIrisRecState::getInstance().irisInfo->data = ImageUtil::MatImageToQImage(irisInfo.matData); + + QElapsedTimer timer; + timer.start(); + + QByteArray data((char*)irisInfo.matData.data, SettingConfig::getInstance().IRIS_WIDTH * SettingConfig::getInstance().IRIS_HEIGHT); + data.prepend("[-m]"); // 识别 + + // 发送TCP消息去匹配 + emit sendDataToExract(data); + + // 状态修改为特征提取 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FEATURE_EXTRACT; + + QTimer toTimer; + QEventLoop loop; + toTimer.singleShot(3000, &loop, &QEventLoop::quit); +// connect(clientUtil, &SocketClientUtil::responseReaded, &loop, &QEventLoop::quit); + loop.exec(); + +// QByteArray matchResponse = clientUtil->getResponse(); + QByteArray matchResponse; +// LOG(INFO) << QString("算法匹配结果").toStdString() << matchResponse.toStdString(); +// LOG_INFO("算法匹配结果 {}",matchResponse.toStdString()); + + // 算法调用返回成功 + if (matchResponse.size() > 0) + { + QString response = matchResponse.mid(5, matchResponse.size() - 6); + QStringList messList = response.split(";"); + QString code = messList.at(0); + if (code.toInt() == 0) + { + QString personId = messList.at(1); + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_SEARCH_SUCC; + +// LOG(INFO) << QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString(); +// LOG_INFO(QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString()); + + // 保存图像文件 +// cv::imwrite(QString("D:\\irisLogs\\%1-%2.bmp").arg(QDateTime::currentDateTime().toString("HHmmsszzz")).arg(irisInfo.leftOrRight).toStdString(), irisInfo.matData); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + emit findMatchedIris(personId); + this->afterRecogAction(); + } else if (code.toInt() == -200) + { + // 匹配失败 +// LOG(INFO) << QString("匹配失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("匹配失败: {}", matchResponse.toStdString()); + + // 匹配失败则尝试次数+1 + addOneTryCount(); + } else if (code.toInt() == -100) + { + // 编码失败 +// LOG(INFO) << QString("编码失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("编码失败: {}", matchResponse.toStdString()); + // 编码失败则尝试次数+1 + addOneTryCount(); + } + } else + { + // 超时返回则尝试次数+1 + addOneTryCount(); + } + } +} + +void IrisRecogProcess::afterRecogAction() +{ + this->setWorking(false); + + ProMemory::getInstance().clearIrisQueue(); // 清理虹膜数据栈 +} + +void IrisRecogProcess::addOneTryCount() +{ + CasicIrisRecState::getInstance().tryCount++; +// LOG(DEBUG) << QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString()); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().tryCount >= SettingConfig::getInstance().MAX_IRIS_TRY_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + CasicIrisRecState::getInstance().tryCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + emit failedMatchedIris(); + } +} +void IrisRecogProcess::addOneNoEyeCount() +{ + CasicIrisRecState::getInstance().noEyeCount++; + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().noEyeCount >= SettingConfig::getInstance().MAX_EYE_NOT_FOUND_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + + if (qrand() % 10 < 5) { + emit failedMatchedIris(); + } + else { + emit findMatchedIris("1"); + } + } +} diff --git a/device/iris/IrisRecogProcess.h b/device/iris/IrisRecogProcess.h new file mode 100644 index 0000000..c4fc648 --- /dev/null +++ b/device/iris/IrisRecogProcess.h @@ -0,0 +1,47 @@ +#ifndef IRISRECOGPROCESS_H +#define IRISRECOGPROCESS_H + +#include +#include +#include +#include + +#include "ProMemory.h" +#include "device/iris/CasicIrisRecState.h" + +class IrisRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit IrisRecogProcess(QObject *parent = 0); + ~IrisRecogProcess(); + + void setWorking(bool working); + void exitThread(); + + void addOneTryCount(); + void addOneNoEyeCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + + volatile bool working; + volatile bool exit; + +private: +// SocketClientUtil * clientUtil; + + void afterRecogAction(); + +signals: + void sendDataToExract(QByteArray data); + + void failedMatchedIris(); + void findMatchedIris(QString personId); + +}; + +#endif // IRISRECOGPROCESS_H diff --git a/images/bg_failure.png b/images/bg_failure.png new file mode 100644 index 0000000..55000a0 --- /dev/null +++ b/images/bg_failure.png Binary files differ diff --git a/images/bg_identifying.png b/images/bg_identifying.png new file mode 100644 index 0000000..58d5a95 --- /dev/null +++ b/images/bg_identifying.png Binary files differ diff --git a/images/bg_statcked.png b/images/bg_statcked.png index 18b63e1..c76130f 100644 --- a/images/bg_statcked.png +++ b/images/bg_statcked.png Binary files differ diff --git a/images/bg_success.png b/images/bg_success.png new file mode 100644 index 0000000..c845bb8 --- /dev/null +++ b/images/bg_success.png Binary files differ diff --git a/images/bg_title.png b/images/bg_title.png index 0316e2d..131369a 100644 --- a/images/bg_title.png +++ b/images/bg_title.png Binary files differ diff --git a/images/iconWarn.png b/images/iconWarn.png new file mode 100644 index 0000000..e1d6403 --- /dev/null +++ b/images/iconWarn.png Binary files differ diff --git a/images/photo.png b/images/photo.png new file mode 100644 index 0000000..d9fa9fa --- /dev/null +++ b/images/photo.png Binary files differ diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/casic/iris/CasicIrisInterface.cpp b/casic/iris/CasicIrisInterface.cpp new file mode 100644 index 0000000..5c46e5b --- /dev/null +++ b/casic/iris/CasicIrisInterface.cpp @@ -0,0 +1,187 @@ +#include "CasicIrisInterface.h" + +#include +#include +#include + +casic::iris::CasicIrisInterface::CasicIrisInterface() +{ + +} + +casic::iris::CasicIrisInterface::~CasicIrisInterface() +{ + +} + +void casic::iris::CasicIrisInterface::setCascadeFile(QString filename) +{ + this->cascadeName = filename.toStdString(); +} +void casic::iris::CasicIrisInterface::setMinEyeSize(int minEyeSize) +{ + this->minEyeSize = minEyeSize; +} +void casic::iris::CasicIrisInterface::setMaxEyeSize(int maxEyeSize) +{ + this->maxEyeSize = maxEyeSize; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.data = ImageUtil::MatImageToQImage(irisInfo.matData); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findAndCutEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + // 找到眼睛之后, 将眼部裁剪下来, 图像拉伸到640 * 480 + cv::Point center; + center.x = cvFloor(rect.at(0).x + rect.at(0).width*0.5); + center.y = cvFloor(rect.at(0).y + rect.at(0).height*0.5); + + // 限制中心点的范围 + if (center.x < SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) + { + // x小于240则x=240 +// center.x = center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + center.x = SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } else if (center.x > SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) { + // x大于1040则x=1040 + center.x = SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } + + if (center.y < SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) + { + // y小于180则y=180 + center.y = SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } else if (center.y > SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) { + center.y = SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } + + // 裁剪眼部图像 + cv::Mat halfSize = irisInfo.matData.clone(); + halfSize = irisInfo.matData(cv::Rect(center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5, + center.y - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5, + SettingConfig::getInstance().IRIS_WIDTH * cutRatio, + SettingConfig::getInstance().IRIS_HEIGHT * cutRatio)); + + cv::resize(halfSize, halfSize, cv::Size(SettingConfig::getInstance().IRIS_WIDTH, SettingConfig::getInstance().IRIS_HEIGHT)); + cv::flip(halfSize, halfSize, 1); // 左右翻转 + +// cv::imwrite(QString("d:\\irisLogs\\%1.bmp").arg(QDateTime::currentSecsSinceEpoch()).toStdString(), halfSize); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.matData = halfSize; + irisInfo.data = ImageUtil::MatImageToQImage(halfSize); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisQualityAssess(CasicIrisInfo irisInfo) +{ + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisCodeExtract(CasicIrisInfo irisInfo) +{ + + QElapsedTimer timer; + timer.start(); + +// QSocketClientUtil * clientUtil = new QSocketClientUtil(); + + QByteArray data((char*)irisInfo.matData.data, 640*480); + + std::cout << "extract iris code" << std::endl; + +// clientUtil->sendData(data); +// if (response.size() == 1024) +// { +// QLog::getInstance()->logger()->debug(QString("特征值提取[耗时: %1ms][特征值: %2]\n") +// .arg(timer.elapsed()) +// .arg(QByteUtil::binToHexString(response))); +// } else +// { +// std::cout << response.toStdString() << std::endl; +// } + + return irisInfo; +} diff --git a/casic/iris/CasicIrisInterface.h b/casic/iris/CasicIrisInterface.h new file mode 100644 index 0000000..87ed97e --- /dev/null +++ b/casic/iris/CasicIrisInterface.h @@ -0,0 +1,45 @@ +#ifndef CASICIRISINTERFACE_H +#define CASICIRISINTERFACE_H + +#include "CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +namespace casic { + namespace iris { + class CasicIrisInterface + { + public: + ~CasicIrisInterface(); + CasicIrisInterface(const CasicIrisInterface&)=delete; + CasicIrisInterface& operator=(const CasicIrisInterface&)=delete; + + static CasicIrisInterface& getInstance() { + static CasicIrisInterface instance; + return instance; + } + + CasicIrisInfo findEye(CasicIrisInfo irisInfo); + CasicIrisInfo findAndCutEye(CasicIrisInfo irisInfo); + CasicIrisInfo irisQualityAssess(CasicIrisInfo irisInfo); + CasicIrisInfo irisCodeExtract(CasicIrisInfo irisInfo); + CasicIrisInfo irisMatch(CasicIrisInfo irisInfo); + + void setCascadeFile(QString filename); + void setMinEyeSize(int minEyeSize); + void setMaxEyeSize(int maxEyeSize); + + private: + CasicIrisInterface(); + + std::string cascadeName = "./model/haarcascade_eye.xml"; + int minEyeSize = 320; + int maxEyeSize = 480; + float cutRatio = 1.0; + + cv::CascadeClassifier * cascade; + }; + } +} + + +#endif // CASICIRISINTERFACE_H diff --git a/casic/iris/casicIris.pri b/casic/iris/casicIris.pri new file mode 100644 index 0000000..d0942ce --- /dev/null +++ b/casic/iris/casicIris.pri @@ -0,0 +1,4 @@ +HEADERS += $$PWD/CasicIrisInfo.h +HEADERS += $$PWD/CasicIrisInterface.h + +SOURCES += $$PWD/CasicIrisInterface.cpp diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index 45df089..49e7316 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -1,4 +1,5 @@ #include "IrisCameraCapEventHandler.h" +#include IrisCameraCapEventHandler::IrisCameraCapEventHandler(QObject *parent) : QObject(parent) { @@ -14,90 +15,37 @@ auto camName = cam->getPtr()->GetDeviceInfo().GetUserID(); int width = objImageDataPointer->GetWidth(); int height = objImageDataPointer->GetHeight(); - size_t leftKeyIndex = camName.find("left"); - size_t rightKeyIndex = camName.find("right"); uchar * pBuffer = (BYTE*)objImageDataPointer->GetBuffer(); - - // 相机拍摄下的图像1440*1080, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 -// QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到400 * 300的尺寸 - img = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT, SettingConfig::getInstance().IRIS_DISPLAY_WIDTH); - img = img.transformed(QTransform().rotate(-90)); // 图像逆时针旋转90度 - - // 发送到界面进行显示 - emit sendIrisFrameToDraw(img); -// cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - -// irisInfo.data = imgAlgo; -// irisInfo.matData = irisMat; - -// // 将图像显示在注册页面的label上 -// // 并将虹膜信息对象存入队列中 -// ProMemory::getInstance().pushCasicIris(irisInfo); - -// if (leftKeyIndex >= 0 && leftKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 0); // 左眼画面 -// } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 1); // 右眼画面 -// } -/* if (pBuffer != NULL) { + // 相机拍摄下的图像1440*1080, 直接用于算法判断 + QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 + QImage imgDisp; + + // 图像逆时针旋转90度 + img = img.transformed(QTransform().rotate(90)); + + // 用于显示的图像需要缩小到480 * 640的尺寸 + imgDisp = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_WIDTH, SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT); + + // 发送到界面进行显示 + emit sendIrisFrameToDraw(imgDisp); + // 创建虹膜信息对象 CasicIrisInfo irisInfo; irisInfo.hasEye = false; - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - // 左眼相机拍摄的图像 - irisInfo.leftOrRight = "left"; - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - // 右眼相机 - irisInfo.leftOrRight = "right"; - } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - cv::Mat irisMat = ImageUtil::QImageToMat(imgDisp); + // 存入图像栈 + cv::Mat irisMat = ImageUtil::QImageToMat(img); + irisInfo.matData = irisMat; - irisInfo.data = imgDisp; - irisInfo.matData = irisMat; + ProMemory::getInstance().pushCasicIris(irisInfo); - ProMemory::getInstance().pushCasicIris(irisInfo); - -// cv::imwrite(QString("D:\\irisLogs\\iristest-%1.bmp").arg(irisInfo.leftOrRight).toStdString(), irisMat); - } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到1/4的尺寸 - img = img.scaled(640, 480); - cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - - irisInfo.data = imgAlgo; - irisInfo.matData = irisMat; - - // 将图像显示在注册页面的label上 - // 并将虹膜信息对象存入队列中 - ProMemory::getInstance().pushCasicIris(irisInfo); - - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 0); // 左眼画面 - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 1); // 右眼画面 - } - } - }*/ + /* 相机控制只拍图 不找眼 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + */ + } } } diff --git a/device/IrisCameraCapEventHandler.h b/device/IrisCameraCapEventHandler.h index ad75a97..8b976c5 100644 --- a/device/IrisCameraCapEventHandler.h +++ b/device/IrisCameraCapEventHandler.h @@ -6,7 +6,7 @@ #include "include/opencv2/opencv.hpp" #include "include/daheng/GalaxyIncludes.h" -//#include "casic/iris/CasicIrisInterface.h" +#include "casic/iris/CasicIrisInterface.h" #include "ProMemory.h" #include "utils/UtilInclude.h" diff --git a/device/device.pri b/device/device.pri index a8417f2..d1330a0 100644 --- a/device/device.pri +++ b/device/device.pri @@ -2,12 +2,12 @@ HEADERS += $$PWD/IrisCameraController.h HEADERS += $$PWD/IrisCameraCapEventHandler.h #HEADERS += $$PWD/iris/IrisRegistProcess.h -#HEADERS += $$PWD/iris/IrisRecogProcess.h -#HEADERS += $$PWD/iris/CasicIrisRecState.h +HEADERS += $$PWD/iris/IrisRecogProcess.h +HEADERS += $$PWD/iris/CasicIrisRecState.h SOURCES += $$PWD/IrisCameraController.cpp SOURCES += $$PWD/IrisCameraCapEventHandler.cpp #SOURCES += $$PWD/iris/IrisRegistProcess.cpp -#SOURCES += $$PWD/iris/IrisRecogProcess.cpp -#SOURCES += $$PWD/iris/CasicIrisRecState.cpp +SOURCES += $$PWD/iris/IrisRecogProcess.cpp +SOURCES += $$PWD/iris/CasicIrisRecState.cpp diff --git a/device/iris/CasicIrisRecState.cpp b/device/iris/CasicIrisRecState.cpp new file mode 100644 index 0000000..b64d747 --- /dev/null +++ b/device/iris/CasicIrisRecState.cpp @@ -0,0 +1,63 @@ +#include "CasicIrisRecState.h" +#include "utils/UtilInclude.h" + +CasicIrisRecState::CasicIrisRecState() +{ + this->recoginzeId = "0"; + this->timeStamp = -1; + + this->state = IrisRecStateName::REC_NOT_START; + + this->irisInfo = new CasicIrisInfo(); +} + +CasicIrisRecState::~CasicIrisRecState() +{ + delete this->irisInfo; +} + +void CasicIrisRecState::initRecognize() +{ + QDateTime now = QDateTime::currentDateTime(); + this->recoginzeId = now.toString("yyyyMMddHHmmsszzz"); + this->timeStamp = now.toMSecsSinceEpoch(); + this->tryCount = 0; + this->noEyeCount = 0; + +// LOG(DEBUG) << QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString()); + qDebug() << QString("[CasicIrisRecState][initRecognize][%1] 虹膜识别状态初始化").arg(recoginzeId); + +} + +QString CasicIrisRecState::toString() +{ + return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)); +} + + +QJsonObject CasicIrisRecState::toJSON() +{ + QJsonObject obj; + + obj.insert("recoginzeId", recoginzeId); + obj.insert("timestamp", timeStamp); + obj.insert("timestampSucc", timeStampSucc); + obj.insert("state", state); + obj.insert("tryCount", tryCount); + obj.insert("noEyeCount", noEyeCount); + obj.insert("recogTimeLast", recogTimeLast); + + QJsonObject eyeObj; + eyeObj.insert("hasEye", irisInfo->hasEye); + QJsonArray rectArray; + rectArray.append(irisInfo->eyeRect.x); + rectArray.append(irisInfo->eyeRect.y); + rectArray.append(irisInfo->eyeRect.width); + rectArray.append(irisInfo->eyeRect.height); + eyeObj.insert("faceRect", rectArray); + + obj.insert("eye", eyeObj); + + return obj; +} diff --git a/device/iris/CasicIrisRecState.h b/device/iris/CasicIrisRecState.h new file mode 100644 index 0000000..eea5ddf --- /dev/null +++ b/device/iris/CasicIrisRecState.h @@ -0,0 +1,67 @@ +#ifndef CASICIRISRECSTATE_H +#define CASICIRISRECSTATE_H + +#include +#include +#include +#include + +#include "casic/iris/CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +class CasicIrisRecState : public QObject +{ +public: + ~CasicIrisRecState(); + CasicIrisRecState(const CasicIrisRecState&)=delete; + CasicIrisRecState& operator=(const CasicIrisRecState&)=delete; + + static CasicIrisRecState& getInstance() { + static CasicIrisRecState instance; + return instance; + } + + void initRecognize(); + QString toString(); + QJsonObject toJSON(); + + QString recoginzeId; // 识别过程id + qint64 timeStamp = 0; // 识别开始时间戳 + qint64 timeStampSucc = 0; // 识别成功时的时间戳 + qint64 findEyeTmLast = 0; // 找眼操作耗时 + + CasicIrisInfo * irisInfo; + + qint8 tryCount = 0; // 识别尝试次数 + qint8 noEyeCount = 0; // 连续没有找到眼睛次数 + float recogTimeLast = 0.0; // 识别成功耗时 + + /** + * @brief state + * 0=初始值 + * 1=左眼检测 + * 2=右眼检测 + * 3=质量评估 + * 4=特征值提取 + * 5=虹膜库比对成功 + * 6=虹膜库比对失败 + */ + volatile int state; + + enum IrisRecStateName + { + REC_NOT_START = 0, // 未开始 + REC_LEFT_FIND_EYE = 1, // 检测左眼, 没找到右眼 + REC_RIGHT_FIND_EYE = 2, // 检测右眼, 没找到左眼 + REC_FIND_EYE = 3, // 找到左眼和右眼 + REC_FEATURE_EXTRACT = 4, // 特征值提取成功 + REC_SEARCH_SUCC = 5, // 虹膜库比对成功 + REC_SEARCH_FAIL = 6 // 虹膜库比对失败 + }; + +private: + CasicIrisRecState(); + +}; + +#endif // CASICIRISRECSTATE_H diff --git a/device/iris/IrisRecogProcess.cpp b/device/iris/IrisRecogProcess.cpp new file mode 100644 index 0000000..6869ece --- /dev/null +++ b/device/iris/IrisRecogProcess.cpp @@ -0,0 +1,223 @@ +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + + +#include "IrisRecogProcess.h" + +IrisRecogProcess::IrisRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; + + // 连接算法服务 +// clientUtil = new SocketClientUtil(this); +// clientUtil->connect("127.0.0.1", 2015); + + // 调用socket发送消息 +// connect(this, &IrisRecogProcess::sendDataToExract, clientUtil, &SocketClientUtil::sendData); +} + +IrisRecogProcess::~IrisRecogProcess() +{ + this->setWorking(false); +} + +void IrisRecogProcess::setWorking(bool working) +{ + this->working = working; +} + +void IrisRecogProcess::exitThread() +{ + this->exit = true; +} + +void IrisRecogProcess::run() +{ + while (exit == false) + { + // 如果工作标志位为否, 则跳出 + if (this->working == false) + { + this->msleep(200); // 200ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isIrisQueueEmpty() == true) + { +// LOG(TRACE) << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString()); + qDebug() << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms"); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicIrisRecState::getInstance().state != CasicIrisRecState::IrisRecStateName::REC_NOT_START) + { +// LOG(DEBUG) << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state).toStdString(); + + qDebug() << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(TRACE) << QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString()); + + // 取出虹膜图像栈中的一条数据 + CasicIrisInfo irisInfo = ProMemory::getInstance().popCasicIris(); + +// LOG(DEBUG) << QString("[IrisRecogProcess] 取出虹膜图像").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 取出虹膜图像").toStdString()); + qDebug() << QString("[IrisRecogProcess] 取出虹膜图像"); + + // 调用找眼分类器算法 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findAndCutEye(irisInfo); + + // 没有找到眼睛则返回 + if (irisInfo.hasEye == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 +// LOG(DEBUG) << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString()); + qDebug() << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount); + + addOneNoEyeCount(); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(DEBUG) << QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString()); + + // 找到眼睛则开始质量评估和编码 + // 调用远程算法进行编码 + if (CasicIrisRecState::getInstance().recoginzeId == "0") + { + // 第一次找到眼则 虹膜识别状态初始化 + CasicIrisRecState::getInstance().initRecognize(); + } + + CasicIrisRecState::getInstance().noEyeCount = 0; // 持续未找到眼的次数清零 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FIND_EYE; + CasicIrisRecState::getInstance().irisInfo->hasEye = irisInfo.hasEye; + CasicIrisRecState::getInstance().irisInfo->eyeRect = irisInfo.eyeRect; + CasicIrisRecState::getInstance().irisInfo->matData = irisInfo.matData; + CasicIrisRecState::getInstance().irisInfo->data = ImageUtil::MatImageToQImage(irisInfo.matData); + + QElapsedTimer timer; + timer.start(); + + QByteArray data((char*)irisInfo.matData.data, SettingConfig::getInstance().IRIS_WIDTH * SettingConfig::getInstance().IRIS_HEIGHT); + data.prepend("[-m]"); // 识别 + + // 发送TCP消息去匹配 + emit sendDataToExract(data); + + // 状态修改为特征提取 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FEATURE_EXTRACT; + + QTimer toTimer; + QEventLoop loop; + toTimer.singleShot(3000, &loop, &QEventLoop::quit); +// connect(clientUtil, &SocketClientUtil::responseReaded, &loop, &QEventLoop::quit); + loop.exec(); + +// QByteArray matchResponse = clientUtil->getResponse(); + QByteArray matchResponse; +// LOG(INFO) << QString("算法匹配结果").toStdString() << matchResponse.toStdString(); +// LOG_INFO("算法匹配结果 {}",matchResponse.toStdString()); + + // 算法调用返回成功 + if (matchResponse.size() > 0) + { + QString response = matchResponse.mid(5, matchResponse.size() - 6); + QStringList messList = response.split(";"); + QString code = messList.at(0); + if (code.toInt() == 0) + { + QString personId = messList.at(1); + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_SEARCH_SUCC; + +// LOG(INFO) << QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString(); +// LOG_INFO(QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString()); + + // 保存图像文件 +// cv::imwrite(QString("D:\\irisLogs\\%1-%2.bmp").arg(QDateTime::currentDateTime().toString("HHmmsszzz")).arg(irisInfo.leftOrRight).toStdString(), irisInfo.matData); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + emit findMatchedIris(personId); + this->afterRecogAction(); + } else if (code.toInt() == -200) + { + // 匹配失败 +// LOG(INFO) << QString("匹配失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("匹配失败: {}", matchResponse.toStdString()); + + // 匹配失败则尝试次数+1 + addOneTryCount(); + } else if (code.toInt() == -100) + { + // 编码失败 +// LOG(INFO) << QString("编码失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("编码失败: {}", matchResponse.toStdString()); + // 编码失败则尝试次数+1 + addOneTryCount(); + } + } else + { + // 超时返回则尝试次数+1 + addOneTryCount(); + } + } +} + +void IrisRecogProcess::afterRecogAction() +{ + this->setWorking(false); + + ProMemory::getInstance().clearIrisQueue(); // 清理虹膜数据栈 +} + +void IrisRecogProcess::addOneTryCount() +{ + CasicIrisRecState::getInstance().tryCount++; +// LOG(DEBUG) << QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString()); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().tryCount >= SettingConfig::getInstance().MAX_IRIS_TRY_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + CasicIrisRecState::getInstance().tryCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + emit failedMatchedIris(); + } +} +void IrisRecogProcess::addOneNoEyeCount() +{ + CasicIrisRecState::getInstance().noEyeCount++; + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().noEyeCount >= SettingConfig::getInstance().MAX_EYE_NOT_FOUND_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + + if (qrand() % 10 < 5) { + emit failedMatchedIris(); + } + else { + emit findMatchedIris("1"); + } + } +} diff --git a/device/iris/IrisRecogProcess.h b/device/iris/IrisRecogProcess.h new file mode 100644 index 0000000..c4fc648 --- /dev/null +++ b/device/iris/IrisRecogProcess.h @@ -0,0 +1,47 @@ +#ifndef IRISRECOGPROCESS_H +#define IRISRECOGPROCESS_H + +#include +#include +#include +#include + +#include "ProMemory.h" +#include "device/iris/CasicIrisRecState.h" + +class IrisRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit IrisRecogProcess(QObject *parent = 0); + ~IrisRecogProcess(); + + void setWorking(bool working); + void exitThread(); + + void addOneTryCount(); + void addOneNoEyeCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + + volatile bool working; + volatile bool exit; + +private: +// SocketClientUtil * clientUtil; + + void afterRecogAction(); + +signals: + void sendDataToExract(QByteArray data); + + void failedMatchedIris(); + void findMatchedIris(QString personId); + +}; + +#endif // IRISRECOGPROCESS_H diff --git a/images/bg_failure.png b/images/bg_failure.png new file mode 100644 index 0000000..55000a0 --- /dev/null +++ b/images/bg_failure.png Binary files differ diff --git a/images/bg_identifying.png b/images/bg_identifying.png new file mode 100644 index 0000000..58d5a95 --- /dev/null +++ b/images/bg_identifying.png Binary files differ diff --git a/images/bg_statcked.png b/images/bg_statcked.png index 18b63e1..c76130f 100644 --- a/images/bg_statcked.png +++ b/images/bg_statcked.png Binary files differ diff --git a/images/bg_success.png b/images/bg_success.png new file mode 100644 index 0000000..c845bb8 --- /dev/null +++ b/images/bg_success.png Binary files differ diff --git a/images/bg_title.png b/images/bg_title.png index 0316e2d..131369a 100644 --- a/images/bg_title.png +++ b/images/bg_title.png Binary files differ diff --git a/images/iconWarn.png b/images/iconWarn.png new file mode 100644 index 0000000..e1d6403 --- /dev/null +++ b/images/iconWarn.png Binary files differ diff --git a/images/photo.png b/images/photo.png new file mode 100644 index 0000000..d9fa9fa --- /dev/null +++ b/images/photo.png Binary files differ diff --git a/resource.qrc b/resource.qrc index 474586a..9d964c6 100644 --- a/resource.qrc +++ b/resource.qrc @@ -1,35 +1,12 @@ - images/setting.png - images/user.png - images/back.png - images/home.png - images/btnPageFirst.png - images/btnPageLast.png - images/btnPageNext.png - images/btnPagePre.png - images/regist.png - images/photoEyeLeft.png - images/photoEyeRight.png - images/photoFace.png - images/save.png - images/upArrow.png - images/downArrow.png - images/faceCaped.png - images/faceNotCap.png - images/irisCaped.png - images/irisNotCap.png - images/tipsFailure.png - images/tipsSuccess.png - images/tipsConfirm.png - images/bg_recognize_result.png - images/iconRetry.png images/bg_title.png images/bg_footer.png images/bg_statcked.png - - - images/add_bottom.png - images/add_top.png + images/bg_identifying.png + images/bg_failure.png + images/iconWarn.png + images/photo.png + images/bg_success.png diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/casic/iris/CasicIrisInterface.cpp b/casic/iris/CasicIrisInterface.cpp new file mode 100644 index 0000000..5c46e5b --- /dev/null +++ b/casic/iris/CasicIrisInterface.cpp @@ -0,0 +1,187 @@ +#include "CasicIrisInterface.h" + +#include +#include +#include + +casic::iris::CasicIrisInterface::CasicIrisInterface() +{ + +} + +casic::iris::CasicIrisInterface::~CasicIrisInterface() +{ + +} + +void casic::iris::CasicIrisInterface::setCascadeFile(QString filename) +{ + this->cascadeName = filename.toStdString(); +} +void casic::iris::CasicIrisInterface::setMinEyeSize(int minEyeSize) +{ + this->minEyeSize = minEyeSize; +} +void casic::iris::CasicIrisInterface::setMaxEyeSize(int maxEyeSize) +{ + this->maxEyeSize = maxEyeSize; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.data = ImageUtil::MatImageToQImage(irisInfo.matData); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findAndCutEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + // 找到眼睛之后, 将眼部裁剪下来, 图像拉伸到640 * 480 + cv::Point center; + center.x = cvFloor(rect.at(0).x + rect.at(0).width*0.5); + center.y = cvFloor(rect.at(0).y + rect.at(0).height*0.5); + + // 限制中心点的范围 + if (center.x < SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) + { + // x小于240则x=240 +// center.x = center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + center.x = SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } else if (center.x > SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) { + // x大于1040则x=1040 + center.x = SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } + + if (center.y < SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) + { + // y小于180则y=180 + center.y = SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } else if (center.y > SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) { + center.y = SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } + + // 裁剪眼部图像 + cv::Mat halfSize = irisInfo.matData.clone(); + halfSize = irisInfo.matData(cv::Rect(center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5, + center.y - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5, + SettingConfig::getInstance().IRIS_WIDTH * cutRatio, + SettingConfig::getInstance().IRIS_HEIGHT * cutRatio)); + + cv::resize(halfSize, halfSize, cv::Size(SettingConfig::getInstance().IRIS_WIDTH, SettingConfig::getInstance().IRIS_HEIGHT)); + cv::flip(halfSize, halfSize, 1); // 左右翻转 + +// cv::imwrite(QString("d:\\irisLogs\\%1.bmp").arg(QDateTime::currentSecsSinceEpoch()).toStdString(), halfSize); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.matData = halfSize; + irisInfo.data = ImageUtil::MatImageToQImage(halfSize); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisQualityAssess(CasicIrisInfo irisInfo) +{ + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisCodeExtract(CasicIrisInfo irisInfo) +{ + + QElapsedTimer timer; + timer.start(); + +// QSocketClientUtil * clientUtil = new QSocketClientUtil(); + + QByteArray data((char*)irisInfo.matData.data, 640*480); + + std::cout << "extract iris code" << std::endl; + +// clientUtil->sendData(data); +// if (response.size() == 1024) +// { +// QLog::getInstance()->logger()->debug(QString("特征值提取[耗时: %1ms][特征值: %2]\n") +// .arg(timer.elapsed()) +// .arg(QByteUtil::binToHexString(response))); +// } else +// { +// std::cout << response.toStdString() << std::endl; +// } + + return irisInfo; +} diff --git a/casic/iris/CasicIrisInterface.h b/casic/iris/CasicIrisInterface.h new file mode 100644 index 0000000..87ed97e --- /dev/null +++ b/casic/iris/CasicIrisInterface.h @@ -0,0 +1,45 @@ +#ifndef CASICIRISINTERFACE_H +#define CASICIRISINTERFACE_H + +#include "CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +namespace casic { + namespace iris { + class CasicIrisInterface + { + public: + ~CasicIrisInterface(); + CasicIrisInterface(const CasicIrisInterface&)=delete; + CasicIrisInterface& operator=(const CasicIrisInterface&)=delete; + + static CasicIrisInterface& getInstance() { + static CasicIrisInterface instance; + return instance; + } + + CasicIrisInfo findEye(CasicIrisInfo irisInfo); + CasicIrisInfo findAndCutEye(CasicIrisInfo irisInfo); + CasicIrisInfo irisQualityAssess(CasicIrisInfo irisInfo); + CasicIrisInfo irisCodeExtract(CasicIrisInfo irisInfo); + CasicIrisInfo irisMatch(CasicIrisInfo irisInfo); + + void setCascadeFile(QString filename); + void setMinEyeSize(int minEyeSize); + void setMaxEyeSize(int maxEyeSize); + + private: + CasicIrisInterface(); + + std::string cascadeName = "./model/haarcascade_eye.xml"; + int minEyeSize = 320; + int maxEyeSize = 480; + float cutRatio = 1.0; + + cv::CascadeClassifier * cascade; + }; + } +} + + +#endif // CASICIRISINTERFACE_H diff --git a/casic/iris/casicIris.pri b/casic/iris/casicIris.pri new file mode 100644 index 0000000..d0942ce --- /dev/null +++ b/casic/iris/casicIris.pri @@ -0,0 +1,4 @@ +HEADERS += $$PWD/CasicIrisInfo.h +HEADERS += $$PWD/CasicIrisInterface.h + +SOURCES += $$PWD/CasicIrisInterface.cpp diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index 45df089..49e7316 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -1,4 +1,5 @@ #include "IrisCameraCapEventHandler.h" +#include IrisCameraCapEventHandler::IrisCameraCapEventHandler(QObject *parent) : QObject(parent) { @@ -14,90 +15,37 @@ auto camName = cam->getPtr()->GetDeviceInfo().GetUserID(); int width = objImageDataPointer->GetWidth(); int height = objImageDataPointer->GetHeight(); - size_t leftKeyIndex = camName.find("left"); - size_t rightKeyIndex = camName.find("right"); uchar * pBuffer = (BYTE*)objImageDataPointer->GetBuffer(); - - // 相机拍摄下的图像1440*1080, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 -// QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到400 * 300的尺寸 - img = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT, SettingConfig::getInstance().IRIS_DISPLAY_WIDTH); - img = img.transformed(QTransform().rotate(-90)); // 图像逆时针旋转90度 - - // 发送到界面进行显示 - emit sendIrisFrameToDraw(img); -// cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - -// irisInfo.data = imgAlgo; -// irisInfo.matData = irisMat; - -// // 将图像显示在注册页面的label上 -// // 并将虹膜信息对象存入队列中 -// ProMemory::getInstance().pushCasicIris(irisInfo); - -// if (leftKeyIndex >= 0 && leftKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 0); // 左眼画面 -// } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 1); // 右眼画面 -// } -/* if (pBuffer != NULL) { + // 相机拍摄下的图像1440*1080, 直接用于算法判断 + QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 + QImage imgDisp; + + // 图像逆时针旋转90度 + img = img.transformed(QTransform().rotate(90)); + + // 用于显示的图像需要缩小到480 * 640的尺寸 + imgDisp = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_WIDTH, SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT); + + // 发送到界面进行显示 + emit sendIrisFrameToDraw(imgDisp); + // 创建虹膜信息对象 CasicIrisInfo irisInfo; irisInfo.hasEye = false; - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - // 左眼相机拍摄的图像 - irisInfo.leftOrRight = "left"; - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - // 右眼相机 - irisInfo.leftOrRight = "right"; - } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - cv::Mat irisMat = ImageUtil::QImageToMat(imgDisp); + // 存入图像栈 + cv::Mat irisMat = ImageUtil::QImageToMat(img); + irisInfo.matData = irisMat; - irisInfo.data = imgDisp; - irisInfo.matData = irisMat; + ProMemory::getInstance().pushCasicIris(irisInfo); - ProMemory::getInstance().pushCasicIris(irisInfo); - -// cv::imwrite(QString("D:\\irisLogs\\iristest-%1.bmp").arg(irisInfo.leftOrRight).toStdString(), irisMat); - } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到1/4的尺寸 - img = img.scaled(640, 480); - cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - - irisInfo.data = imgAlgo; - irisInfo.matData = irisMat; - - // 将图像显示在注册页面的label上 - // 并将虹膜信息对象存入队列中 - ProMemory::getInstance().pushCasicIris(irisInfo); - - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 0); // 左眼画面 - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 1); // 右眼画面 - } - } - }*/ + /* 相机控制只拍图 不找眼 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + */ + } } } diff --git a/device/IrisCameraCapEventHandler.h b/device/IrisCameraCapEventHandler.h index ad75a97..8b976c5 100644 --- a/device/IrisCameraCapEventHandler.h +++ b/device/IrisCameraCapEventHandler.h @@ -6,7 +6,7 @@ #include "include/opencv2/opencv.hpp" #include "include/daheng/GalaxyIncludes.h" -//#include "casic/iris/CasicIrisInterface.h" +#include "casic/iris/CasicIrisInterface.h" #include "ProMemory.h" #include "utils/UtilInclude.h" diff --git a/device/device.pri b/device/device.pri index a8417f2..d1330a0 100644 --- a/device/device.pri +++ b/device/device.pri @@ -2,12 +2,12 @@ HEADERS += $$PWD/IrisCameraController.h HEADERS += $$PWD/IrisCameraCapEventHandler.h #HEADERS += $$PWD/iris/IrisRegistProcess.h -#HEADERS += $$PWD/iris/IrisRecogProcess.h -#HEADERS += $$PWD/iris/CasicIrisRecState.h +HEADERS += $$PWD/iris/IrisRecogProcess.h +HEADERS += $$PWD/iris/CasicIrisRecState.h SOURCES += $$PWD/IrisCameraController.cpp SOURCES += $$PWD/IrisCameraCapEventHandler.cpp #SOURCES += $$PWD/iris/IrisRegistProcess.cpp -#SOURCES += $$PWD/iris/IrisRecogProcess.cpp -#SOURCES += $$PWD/iris/CasicIrisRecState.cpp +SOURCES += $$PWD/iris/IrisRecogProcess.cpp +SOURCES += $$PWD/iris/CasicIrisRecState.cpp diff --git a/device/iris/CasicIrisRecState.cpp b/device/iris/CasicIrisRecState.cpp new file mode 100644 index 0000000..b64d747 --- /dev/null +++ b/device/iris/CasicIrisRecState.cpp @@ -0,0 +1,63 @@ +#include "CasicIrisRecState.h" +#include "utils/UtilInclude.h" + +CasicIrisRecState::CasicIrisRecState() +{ + this->recoginzeId = "0"; + this->timeStamp = -1; + + this->state = IrisRecStateName::REC_NOT_START; + + this->irisInfo = new CasicIrisInfo(); +} + +CasicIrisRecState::~CasicIrisRecState() +{ + delete this->irisInfo; +} + +void CasicIrisRecState::initRecognize() +{ + QDateTime now = QDateTime::currentDateTime(); + this->recoginzeId = now.toString("yyyyMMddHHmmsszzz"); + this->timeStamp = now.toMSecsSinceEpoch(); + this->tryCount = 0; + this->noEyeCount = 0; + +// LOG(DEBUG) << QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString()); + qDebug() << QString("[CasicIrisRecState][initRecognize][%1] 虹膜识别状态初始化").arg(recoginzeId); + +} + +QString CasicIrisRecState::toString() +{ + return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)); +} + + +QJsonObject CasicIrisRecState::toJSON() +{ + QJsonObject obj; + + obj.insert("recoginzeId", recoginzeId); + obj.insert("timestamp", timeStamp); + obj.insert("timestampSucc", timeStampSucc); + obj.insert("state", state); + obj.insert("tryCount", tryCount); + obj.insert("noEyeCount", noEyeCount); + obj.insert("recogTimeLast", recogTimeLast); + + QJsonObject eyeObj; + eyeObj.insert("hasEye", irisInfo->hasEye); + QJsonArray rectArray; + rectArray.append(irisInfo->eyeRect.x); + rectArray.append(irisInfo->eyeRect.y); + rectArray.append(irisInfo->eyeRect.width); + rectArray.append(irisInfo->eyeRect.height); + eyeObj.insert("faceRect", rectArray); + + obj.insert("eye", eyeObj); + + return obj; +} diff --git a/device/iris/CasicIrisRecState.h b/device/iris/CasicIrisRecState.h new file mode 100644 index 0000000..eea5ddf --- /dev/null +++ b/device/iris/CasicIrisRecState.h @@ -0,0 +1,67 @@ +#ifndef CASICIRISRECSTATE_H +#define CASICIRISRECSTATE_H + +#include +#include +#include +#include + +#include "casic/iris/CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +class CasicIrisRecState : public QObject +{ +public: + ~CasicIrisRecState(); + CasicIrisRecState(const CasicIrisRecState&)=delete; + CasicIrisRecState& operator=(const CasicIrisRecState&)=delete; + + static CasicIrisRecState& getInstance() { + static CasicIrisRecState instance; + return instance; + } + + void initRecognize(); + QString toString(); + QJsonObject toJSON(); + + QString recoginzeId; // 识别过程id + qint64 timeStamp = 0; // 识别开始时间戳 + qint64 timeStampSucc = 0; // 识别成功时的时间戳 + qint64 findEyeTmLast = 0; // 找眼操作耗时 + + CasicIrisInfo * irisInfo; + + qint8 tryCount = 0; // 识别尝试次数 + qint8 noEyeCount = 0; // 连续没有找到眼睛次数 + float recogTimeLast = 0.0; // 识别成功耗时 + + /** + * @brief state + * 0=初始值 + * 1=左眼检测 + * 2=右眼检测 + * 3=质量评估 + * 4=特征值提取 + * 5=虹膜库比对成功 + * 6=虹膜库比对失败 + */ + volatile int state; + + enum IrisRecStateName + { + REC_NOT_START = 0, // 未开始 + REC_LEFT_FIND_EYE = 1, // 检测左眼, 没找到右眼 + REC_RIGHT_FIND_EYE = 2, // 检测右眼, 没找到左眼 + REC_FIND_EYE = 3, // 找到左眼和右眼 + REC_FEATURE_EXTRACT = 4, // 特征值提取成功 + REC_SEARCH_SUCC = 5, // 虹膜库比对成功 + REC_SEARCH_FAIL = 6 // 虹膜库比对失败 + }; + +private: + CasicIrisRecState(); + +}; + +#endif // CASICIRISRECSTATE_H diff --git a/device/iris/IrisRecogProcess.cpp b/device/iris/IrisRecogProcess.cpp new file mode 100644 index 0000000..6869ece --- /dev/null +++ b/device/iris/IrisRecogProcess.cpp @@ -0,0 +1,223 @@ +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + + +#include "IrisRecogProcess.h" + +IrisRecogProcess::IrisRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; + + // 连接算法服务 +// clientUtil = new SocketClientUtil(this); +// clientUtil->connect("127.0.0.1", 2015); + + // 调用socket发送消息 +// connect(this, &IrisRecogProcess::sendDataToExract, clientUtil, &SocketClientUtil::sendData); +} + +IrisRecogProcess::~IrisRecogProcess() +{ + this->setWorking(false); +} + +void IrisRecogProcess::setWorking(bool working) +{ + this->working = working; +} + +void IrisRecogProcess::exitThread() +{ + this->exit = true; +} + +void IrisRecogProcess::run() +{ + while (exit == false) + { + // 如果工作标志位为否, 则跳出 + if (this->working == false) + { + this->msleep(200); // 200ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isIrisQueueEmpty() == true) + { +// LOG(TRACE) << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString()); + qDebug() << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms"); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicIrisRecState::getInstance().state != CasicIrisRecState::IrisRecStateName::REC_NOT_START) + { +// LOG(DEBUG) << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state).toStdString(); + + qDebug() << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(TRACE) << QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString()); + + // 取出虹膜图像栈中的一条数据 + CasicIrisInfo irisInfo = ProMemory::getInstance().popCasicIris(); + +// LOG(DEBUG) << QString("[IrisRecogProcess] 取出虹膜图像").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 取出虹膜图像").toStdString()); + qDebug() << QString("[IrisRecogProcess] 取出虹膜图像"); + + // 调用找眼分类器算法 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findAndCutEye(irisInfo); + + // 没有找到眼睛则返回 + if (irisInfo.hasEye == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 +// LOG(DEBUG) << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString()); + qDebug() << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount); + + addOneNoEyeCount(); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(DEBUG) << QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString()); + + // 找到眼睛则开始质量评估和编码 + // 调用远程算法进行编码 + if (CasicIrisRecState::getInstance().recoginzeId == "0") + { + // 第一次找到眼则 虹膜识别状态初始化 + CasicIrisRecState::getInstance().initRecognize(); + } + + CasicIrisRecState::getInstance().noEyeCount = 0; // 持续未找到眼的次数清零 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FIND_EYE; + CasicIrisRecState::getInstance().irisInfo->hasEye = irisInfo.hasEye; + CasicIrisRecState::getInstance().irisInfo->eyeRect = irisInfo.eyeRect; + CasicIrisRecState::getInstance().irisInfo->matData = irisInfo.matData; + CasicIrisRecState::getInstance().irisInfo->data = ImageUtil::MatImageToQImage(irisInfo.matData); + + QElapsedTimer timer; + timer.start(); + + QByteArray data((char*)irisInfo.matData.data, SettingConfig::getInstance().IRIS_WIDTH * SettingConfig::getInstance().IRIS_HEIGHT); + data.prepend("[-m]"); // 识别 + + // 发送TCP消息去匹配 + emit sendDataToExract(data); + + // 状态修改为特征提取 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FEATURE_EXTRACT; + + QTimer toTimer; + QEventLoop loop; + toTimer.singleShot(3000, &loop, &QEventLoop::quit); +// connect(clientUtil, &SocketClientUtil::responseReaded, &loop, &QEventLoop::quit); + loop.exec(); + +// QByteArray matchResponse = clientUtil->getResponse(); + QByteArray matchResponse; +// LOG(INFO) << QString("算法匹配结果").toStdString() << matchResponse.toStdString(); +// LOG_INFO("算法匹配结果 {}",matchResponse.toStdString()); + + // 算法调用返回成功 + if (matchResponse.size() > 0) + { + QString response = matchResponse.mid(5, matchResponse.size() - 6); + QStringList messList = response.split(";"); + QString code = messList.at(0); + if (code.toInt() == 0) + { + QString personId = messList.at(1); + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_SEARCH_SUCC; + +// LOG(INFO) << QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString(); +// LOG_INFO(QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString()); + + // 保存图像文件 +// cv::imwrite(QString("D:\\irisLogs\\%1-%2.bmp").arg(QDateTime::currentDateTime().toString("HHmmsszzz")).arg(irisInfo.leftOrRight).toStdString(), irisInfo.matData); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + emit findMatchedIris(personId); + this->afterRecogAction(); + } else if (code.toInt() == -200) + { + // 匹配失败 +// LOG(INFO) << QString("匹配失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("匹配失败: {}", matchResponse.toStdString()); + + // 匹配失败则尝试次数+1 + addOneTryCount(); + } else if (code.toInt() == -100) + { + // 编码失败 +// LOG(INFO) << QString("编码失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("编码失败: {}", matchResponse.toStdString()); + // 编码失败则尝试次数+1 + addOneTryCount(); + } + } else + { + // 超时返回则尝试次数+1 + addOneTryCount(); + } + } +} + +void IrisRecogProcess::afterRecogAction() +{ + this->setWorking(false); + + ProMemory::getInstance().clearIrisQueue(); // 清理虹膜数据栈 +} + +void IrisRecogProcess::addOneTryCount() +{ + CasicIrisRecState::getInstance().tryCount++; +// LOG(DEBUG) << QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString()); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().tryCount >= SettingConfig::getInstance().MAX_IRIS_TRY_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + CasicIrisRecState::getInstance().tryCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + emit failedMatchedIris(); + } +} +void IrisRecogProcess::addOneNoEyeCount() +{ + CasicIrisRecState::getInstance().noEyeCount++; + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().noEyeCount >= SettingConfig::getInstance().MAX_EYE_NOT_FOUND_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + + if (qrand() % 10 < 5) { + emit failedMatchedIris(); + } + else { + emit findMatchedIris("1"); + } + } +} diff --git a/device/iris/IrisRecogProcess.h b/device/iris/IrisRecogProcess.h new file mode 100644 index 0000000..c4fc648 --- /dev/null +++ b/device/iris/IrisRecogProcess.h @@ -0,0 +1,47 @@ +#ifndef IRISRECOGPROCESS_H +#define IRISRECOGPROCESS_H + +#include +#include +#include +#include + +#include "ProMemory.h" +#include "device/iris/CasicIrisRecState.h" + +class IrisRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit IrisRecogProcess(QObject *parent = 0); + ~IrisRecogProcess(); + + void setWorking(bool working); + void exitThread(); + + void addOneTryCount(); + void addOneNoEyeCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + + volatile bool working; + volatile bool exit; + +private: +// SocketClientUtil * clientUtil; + + void afterRecogAction(); + +signals: + void sendDataToExract(QByteArray data); + + void failedMatchedIris(); + void findMatchedIris(QString personId); + +}; + +#endif // IRISRECOGPROCESS_H diff --git a/images/bg_failure.png b/images/bg_failure.png new file mode 100644 index 0000000..55000a0 --- /dev/null +++ b/images/bg_failure.png Binary files differ diff --git a/images/bg_identifying.png b/images/bg_identifying.png new file mode 100644 index 0000000..58d5a95 --- /dev/null +++ b/images/bg_identifying.png Binary files differ diff --git a/images/bg_statcked.png b/images/bg_statcked.png index 18b63e1..c76130f 100644 --- a/images/bg_statcked.png +++ b/images/bg_statcked.png Binary files differ diff --git a/images/bg_success.png b/images/bg_success.png new file mode 100644 index 0000000..c845bb8 --- /dev/null +++ b/images/bg_success.png Binary files differ diff --git a/images/bg_title.png b/images/bg_title.png index 0316e2d..131369a 100644 --- a/images/bg_title.png +++ b/images/bg_title.png Binary files differ diff --git a/images/iconWarn.png b/images/iconWarn.png new file mode 100644 index 0000000..e1d6403 --- /dev/null +++ b/images/iconWarn.png Binary files differ diff --git a/images/photo.png b/images/photo.png new file mode 100644 index 0000000..d9fa9fa --- /dev/null +++ b/images/photo.png Binary files differ diff --git a/resource.qrc b/resource.qrc index 474586a..9d964c6 100644 --- a/resource.qrc +++ b/resource.qrc @@ -1,35 +1,12 @@ - images/setting.png - images/user.png - images/back.png - images/home.png - images/btnPageFirst.png - images/btnPageLast.png - images/btnPageNext.png - images/btnPagePre.png - images/regist.png - images/photoEyeLeft.png - images/photoEyeRight.png - images/photoFace.png - images/save.png - images/upArrow.png - images/downArrow.png - images/faceCaped.png - images/faceNotCap.png - images/irisCaped.png - images/irisNotCap.png - images/tipsFailure.png - images/tipsSuccess.png - images/tipsConfirm.png - images/bg_recognize_result.png - images/iconRetry.png images/bg_title.png images/bg_footer.png images/bg_statcked.png - - - images/add_bottom.png - images/add_top.png + images/bg_identifying.png + images/bg_failure.png + images/iconWarn.png + images/photo.png + images/bg_success.png diff --git a/utils/ImageUtil.cpp b/utils/ImageUtil.cpp index 7604572..ff77331 100644 --- a/utils/ImageUtil.cpp +++ b/utils/ImageUtil.cpp @@ -1,4 +1,4 @@ -#include "ImageUtil.h" +#include "ImageUtil.h" ImageUtil::ImageUtil() { @@ -36,12 +36,11 @@ return QImage(); } } -/* -QImage ImageUtil::UcharToQImage(unsigned char* data, int width, int height, QImage::Format format) + +cv::Mat ImageUtil::ucharToMat(unsigned char *data, int row, int col) { - QImage qImage(data, width, height, format); - //在不改变实际图像数据的条件下, 交换红蓝通道 - return qImage.rgbSwapped(); + cv::Mat img(row, col, CV_8UC1, (unsigned char *)data); + return img; } cv::Mat ImageUtil::QImageToMat(QImage image) @@ -64,6 +63,9 @@ case QImage::Format_Grayscale8: mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void *)image.bits(), image.bytesPerLine()); break; + + default: + break; } mat = mat.clone(); @@ -71,6 +73,14 @@ return mat; } +/* +QImage ImageUtil::UcharToQImage(unsigned char* data, int width, int height, QImage::Format format) +{ + QImage qImage(data, width, height, format); + //在不改变实际图像数据的条件下, 交换红蓝通道 + return qImage.rgbSwapped(); +} + QString ImageUtil::QImageToBase64(QImage image) { QByteArray ba; diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/casic/iris/CasicIrisInterface.cpp b/casic/iris/CasicIrisInterface.cpp new file mode 100644 index 0000000..5c46e5b --- /dev/null +++ b/casic/iris/CasicIrisInterface.cpp @@ -0,0 +1,187 @@ +#include "CasicIrisInterface.h" + +#include +#include +#include + +casic::iris::CasicIrisInterface::CasicIrisInterface() +{ + +} + +casic::iris::CasicIrisInterface::~CasicIrisInterface() +{ + +} + +void casic::iris::CasicIrisInterface::setCascadeFile(QString filename) +{ + this->cascadeName = filename.toStdString(); +} +void casic::iris::CasicIrisInterface::setMinEyeSize(int minEyeSize) +{ + this->minEyeSize = minEyeSize; +} +void casic::iris::CasicIrisInterface::setMaxEyeSize(int maxEyeSize) +{ + this->maxEyeSize = maxEyeSize; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.data = ImageUtil::MatImageToQImage(irisInfo.matData); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findAndCutEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + // 找到眼睛之后, 将眼部裁剪下来, 图像拉伸到640 * 480 + cv::Point center; + center.x = cvFloor(rect.at(0).x + rect.at(0).width*0.5); + center.y = cvFloor(rect.at(0).y + rect.at(0).height*0.5); + + // 限制中心点的范围 + if (center.x < SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) + { + // x小于240则x=240 +// center.x = center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + center.x = SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } else if (center.x > SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) { + // x大于1040则x=1040 + center.x = SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } + + if (center.y < SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) + { + // y小于180则y=180 + center.y = SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } else if (center.y > SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) { + center.y = SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } + + // 裁剪眼部图像 + cv::Mat halfSize = irisInfo.matData.clone(); + halfSize = irisInfo.matData(cv::Rect(center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5, + center.y - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5, + SettingConfig::getInstance().IRIS_WIDTH * cutRatio, + SettingConfig::getInstance().IRIS_HEIGHT * cutRatio)); + + cv::resize(halfSize, halfSize, cv::Size(SettingConfig::getInstance().IRIS_WIDTH, SettingConfig::getInstance().IRIS_HEIGHT)); + cv::flip(halfSize, halfSize, 1); // 左右翻转 + +// cv::imwrite(QString("d:\\irisLogs\\%1.bmp").arg(QDateTime::currentSecsSinceEpoch()).toStdString(), halfSize); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.matData = halfSize; + irisInfo.data = ImageUtil::MatImageToQImage(halfSize); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisQualityAssess(CasicIrisInfo irisInfo) +{ + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisCodeExtract(CasicIrisInfo irisInfo) +{ + + QElapsedTimer timer; + timer.start(); + +// QSocketClientUtil * clientUtil = new QSocketClientUtil(); + + QByteArray data((char*)irisInfo.matData.data, 640*480); + + std::cout << "extract iris code" << std::endl; + +// clientUtil->sendData(data); +// if (response.size() == 1024) +// { +// QLog::getInstance()->logger()->debug(QString("特征值提取[耗时: %1ms][特征值: %2]\n") +// .arg(timer.elapsed()) +// .arg(QByteUtil::binToHexString(response))); +// } else +// { +// std::cout << response.toStdString() << std::endl; +// } + + return irisInfo; +} diff --git a/casic/iris/CasicIrisInterface.h b/casic/iris/CasicIrisInterface.h new file mode 100644 index 0000000..87ed97e --- /dev/null +++ b/casic/iris/CasicIrisInterface.h @@ -0,0 +1,45 @@ +#ifndef CASICIRISINTERFACE_H +#define CASICIRISINTERFACE_H + +#include "CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +namespace casic { + namespace iris { + class CasicIrisInterface + { + public: + ~CasicIrisInterface(); + CasicIrisInterface(const CasicIrisInterface&)=delete; + CasicIrisInterface& operator=(const CasicIrisInterface&)=delete; + + static CasicIrisInterface& getInstance() { + static CasicIrisInterface instance; + return instance; + } + + CasicIrisInfo findEye(CasicIrisInfo irisInfo); + CasicIrisInfo findAndCutEye(CasicIrisInfo irisInfo); + CasicIrisInfo irisQualityAssess(CasicIrisInfo irisInfo); + CasicIrisInfo irisCodeExtract(CasicIrisInfo irisInfo); + CasicIrisInfo irisMatch(CasicIrisInfo irisInfo); + + void setCascadeFile(QString filename); + void setMinEyeSize(int minEyeSize); + void setMaxEyeSize(int maxEyeSize); + + private: + CasicIrisInterface(); + + std::string cascadeName = "./model/haarcascade_eye.xml"; + int minEyeSize = 320; + int maxEyeSize = 480; + float cutRatio = 1.0; + + cv::CascadeClassifier * cascade; + }; + } +} + + +#endif // CASICIRISINTERFACE_H diff --git a/casic/iris/casicIris.pri b/casic/iris/casicIris.pri new file mode 100644 index 0000000..d0942ce --- /dev/null +++ b/casic/iris/casicIris.pri @@ -0,0 +1,4 @@ +HEADERS += $$PWD/CasicIrisInfo.h +HEADERS += $$PWD/CasicIrisInterface.h + +SOURCES += $$PWD/CasicIrisInterface.cpp diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index 45df089..49e7316 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -1,4 +1,5 @@ #include "IrisCameraCapEventHandler.h" +#include IrisCameraCapEventHandler::IrisCameraCapEventHandler(QObject *parent) : QObject(parent) { @@ -14,90 +15,37 @@ auto camName = cam->getPtr()->GetDeviceInfo().GetUserID(); int width = objImageDataPointer->GetWidth(); int height = objImageDataPointer->GetHeight(); - size_t leftKeyIndex = camName.find("left"); - size_t rightKeyIndex = camName.find("right"); uchar * pBuffer = (BYTE*)objImageDataPointer->GetBuffer(); - - // 相机拍摄下的图像1440*1080, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 -// QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到400 * 300的尺寸 - img = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT, SettingConfig::getInstance().IRIS_DISPLAY_WIDTH); - img = img.transformed(QTransform().rotate(-90)); // 图像逆时针旋转90度 - - // 发送到界面进行显示 - emit sendIrisFrameToDraw(img); -// cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - -// irisInfo.data = imgAlgo; -// irisInfo.matData = irisMat; - -// // 将图像显示在注册页面的label上 -// // 并将虹膜信息对象存入队列中 -// ProMemory::getInstance().pushCasicIris(irisInfo); - -// if (leftKeyIndex >= 0 && leftKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 0); // 左眼画面 -// } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 1); // 右眼画面 -// } -/* if (pBuffer != NULL) { + // 相机拍摄下的图像1440*1080, 直接用于算法判断 + QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 + QImage imgDisp; + + // 图像逆时针旋转90度 + img = img.transformed(QTransform().rotate(90)); + + // 用于显示的图像需要缩小到480 * 640的尺寸 + imgDisp = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_WIDTH, SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT); + + // 发送到界面进行显示 + emit sendIrisFrameToDraw(imgDisp); + // 创建虹膜信息对象 CasicIrisInfo irisInfo; irisInfo.hasEye = false; - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - // 左眼相机拍摄的图像 - irisInfo.leftOrRight = "left"; - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - // 右眼相机 - irisInfo.leftOrRight = "right"; - } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - cv::Mat irisMat = ImageUtil::QImageToMat(imgDisp); + // 存入图像栈 + cv::Mat irisMat = ImageUtil::QImageToMat(img); + irisInfo.matData = irisMat; - irisInfo.data = imgDisp; - irisInfo.matData = irisMat; + ProMemory::getInstance().pushCasicIris(irisInfo); - ProMemory::getInstance().pushCasicIris(irisInfo); - -// cv::imwrite(QString("D:\\irisLogs\\iristest-%1.bmp").arg(irisInfo.leftOrRight).toStdString(), irisMat); - } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到1/4的尺寸 - img = img.scaled(640, 480); - cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - - irisInfo.data = imgAlgo; - irisInfo.matData = irisMat; - - // 将图像显示在注册页面的label上 - // 并将虹膜信息对象存入队列中 - ProMemory::getInstance().pushCasicIris(irisInfo); - - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 0); // 左眼画面 - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 1); // 右眼画面 - } - } - }*/ + /* 相机控制只拍图 不找眼 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + */ + } } } diff --git a/device/IrisCameraCapEventHandler.h b/device/IrisCameraCapEventHandler.h index ad75a97..8b976c5 100644 --- a/device/IrisCameraCapEventHandler.h +++ b/device/IrisCameraCapEventHandler.h @@ -6,7 +6,7 @@ #include "include/opencv2/opencv.hpp" #include "include/daheng/GalaxyIncludes.h" -//#include "casic/iris/CasicIrisInterface.h" +#include "casic/iris/CasicIrisInterface.h" #include "ProMemory.h" #include "utils/UtilInclude.h" diff --git a/device/device.pri b/device/device.pri index a8417f2..d1330a0 100644 --- a/device/device.pri +++ b/device/device.pri @@ -2,12 +2,12 @@ HEADERS += $$PWD/IrisCameraController.h HEADERS += $$PWD/IrisCameraCapEventHandler.h #HEADERS += $$PWD/iris/IrisRegistProcess.h -#HEADERS += $$PWD/iris/IrisRecogProcess.h -#HEADERS += $$PWD/iris/CasicIrisRecState.h +HEADERS += $$PWD/iris/IrisRecogProcess.h +HEADERS += $$PWD/iris/CasicIrisRecState.h SOURCES += $$PWD/IrisCameraController.cpp SOURCES += $$PWD/IrisCameraCapEventHandler.cpp #SOURCES += $$PWD/iris/IrisRegistProcess.cpp -#SOURCES += $$PWD/iris/IrisRecogProcess.cpp -#SOURCES += $$PWD/iris/CasicIrisRecState.cpp +SOURCES += $$PWD/iris/IrisRecogProcess.cpp +SOURCES += $$PWD/iris/CasicIrisRecState.cpp diff --git a/device/iris/CasicIrisRecState.cpp b/device/iris/CasicIrisRecState.cpp new file mode 100644 index 0000000..b64d747 --- /dev/null +++ b/device/iris/CasicIrisRecState.cpp @@ -0,0 +1,63 @@ +#include "CasicIrisRecState.h" +#include "utils/UtilInclude.h" + +CasicIrisRecState::CasicIrisRecState() +{ + this->recoginzeId = "0"; + this->timeStamp = -1; + + this->state = IrisRecStateName::REC_NOT_START; + + this->irisInfo = new CasicIrisInfo(); +} + +CasicIrisRecState::~CasicIrisRecState() +{ + delete this->irisInfo; +} + +void CasicIrisRecState::initRecognize() +{ + QDateTime now = QDateTime::currentDateTime(); + this->recoginzeId = now.toString("yyyyMMddHHmmsszzz"); + this->timeStamp = now.toMSecsSinceEpoch(); + this->tryCount = 0; + this->noEyeCount = 0; + +// LOG(DEBUG) << QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString()); + qDebug() << QString("[CasicIrisRecState][initRecognize][%1] 虹膜识别状态初始化").arg(recoginzeId); + +} + +QString CasicIrisRecState::toString() +{ + return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)); +} + + +QJsonObject CasicIrisRecState::toJSON() +{ + QJsonObject obj; + + obj.insert("recoginzeId", recoginzeId); + obj.insert("timestamp", timeStamp); + obj.insert("timestampSucc", timeStampSucc); + obj.insert("state", state); + obj.insert("tryCount", tryCount); + obj.insert("noEyeCount", noEyeCount); + obj.insert("recogTimeLast", recogTimeLast); + + QJsonObject eyeObj; + eyeObj.insert("hasEye", irisInfo->hasEye); + QJsonArray rectArray; + rectArray.append(irisInfo->eyeRect.x); + rectArray.append(irisInfo->eyeRect.y); + rectArray.append(irisInfo->eyeRect.width); + rectArray.append(irisInfo->eyeRect.height); + eyeObj.insert("faceRect", rectArray); + + obj.insert("eye", eyeObj); + + return obj; +} diff --git a/device/iris/CasicIrisRecState.h b/device/iris/CasicIrisRecState.h new file mode 100644 index 0000000..eea5ddf --- /dev/null +++ b/device/iris/CasicIrisRecState.h @@ -0,0 +1,67 @@ +#ifndef CASICIRISRECSTATE_H +#define CASICIRISRECSTATE_H + +#include +#include +#include +#include + +#include "casic/iris/CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +class CasicIrisRecState : public QObject +{ +public: + ~CasicIrisRecState(); + CasicIrisRecState(const CasicIrisRecState&)=delete; + CasicIrisRecState& operator=(const CasicIrisRecState&)=delete; + + static CasicIrisRecState& getInstance() { + static CasicIrisRecState instance; + return instance; + } + + void initRecognize(); + QString toString(); + QJsonObject toJSON(); + + QString recoginzeId; // 识别过程id + qint64 timeStamp = 0; // 识别开始时间戳 + qint64 timeStampSucc = 0; // 识别成功时的时间戳 + qint64 findEyeTmLast = 0; // 找眼操作耗时 + + CasicIrisInfo * irisInfo; + + qint8 tryCount = 0; // 识别尝试次数 + qint8 noEyeCount = 0; // 连续没有找到眼睛次数 + float recogTimeLast = 0.0; // 识别成功耗时 + + /** + * @brief state + * 0=初始值 + * 1=左眼检测 + * 2=右眼检测 + * 3=质量评估 + * 4=特征值提取 + * 5=虹膜库比对成功 + * 6=虹膜库比对失败 + */ + volatile int state; + + enum IrisRecStateName + { + REC_NOT_START = 0, // 未开始 + REC_LEFT_FIND_EYE = 1, // 检测左眼, 没找到右眼 + REC_RIGHT_FIND_EYE = 2, // 检测右眼, 没找到左眼 + REC_FIND_EYE = 3, // 找到左眼和右眼 + REC_FEATURE_EXTRACT = 4, // 特征值提取成功 + REC_SEARCH_SUCC = 5, // 虹膜库比对成功 + REC_SEARCH_FAIL = 6 // 虹膜库比对失败 + }; + +private: + CasicIrisRecState(); + +}; + +#endif // CASICIRISRECSTATE_H diff --git a/device/iris/IrisRecogProcess.cpp b/device/iris/IrisRecogProcess.cpp new file mode 100644 index 0000000..6869ece --- /dev/null +++ b/device/iris/IrisRecogProcess.cpp @@ -0,0 +1,223 @@ +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + + +#include "IrisRecogProcess.h" + +IrisRecogProcess::IrisRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; + + // 连接算法服务 +// clientUtil = new SocketClientUtil(this); +// clientUtil->connect("127.0.0.1", 2015); + + // 调用socket发送消息 +// connect(this, &IrisRecogProcess::sendDataToExract, clientUtil, &SocketClientUtil::sendData); +} + +IrisRecogProcess::~IrisRecogProcess() +{ + this->setWorking(false); +} + +void IrisRecogProcess::setWorking(bool working) +{ + this->working = working; +} + +void IrisRecogProcess::exitThread() +{ + this->exit = true; +} + +void IrisRecogProcess::run() +{ + while (exit == false) + { + // 如果工作标志位为否, 则跳出 + if (this->working == false) + { + this->msleep(200); // 200ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isIrisQueueEmpty() == true) + { +// LOG(TRACE) << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString()); + qDebug() << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms"); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicIrisRecState::getInstance().state != CasicIrisRecState::IrisRecStateName::REC_NOT_START) + { +// LOG(DEBUG) << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state).toStdString(); + + qDebug() << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(TRACE) << QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString()); + + // 取出虹膜图像栈中的一条数据 + CasicIrisInfo irisInfo = ProMemory::getInstance().popCasicIris(); + +// LOG(DEBUG) << QString("[IrisRecogProcess] 取出虹膜图像").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 取出虹膜图像").toStdString()); + qDebug() << QString("[IrisRecogProcess] 取出虹膜图像"); + + // 调用找眼分类器算法 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findAndCutEye(irisInfo); + + // 没有找到眼睛则返回 + if (irisInfo.hasEye == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 +// LOG(DEBUG) << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString()); + qDebug() << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount); + + addOneNoEyeCount(); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(DEBUG) << QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString()); + + // 找到眼睛则开始质量评估和编码 + // 调用远程算法进行编码 + if (CasicIrisRecState::getInstance().recoginzeId == "0") + { + // 第一次找到眼则 虹膜识别状态初始化 + CasicIrisRecState::getInstance().initRecognize(); + } + + CasicIrisRecState::getInstance().noEyeCount = 0; // 持续未找到眼的次数清零 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FIND_EYE; + CasicIrisRecState::getInstance().irisInfo->hasEye = irisInfo.hasEye; + CasicIrisRecState::getInstance().irisInfo->eyeRect = irisInfo.eyeRect; + CasicIrisRecState::getInstance().irisInfo->matData = irisInfo.matData; + CasicIrisRecState::getInstance().irisInfo->data = ImageUtil::MatImageToQImage(irisInfo.matData); + + QElapsedTimer timer; + timer.start(); + + QByteArray data((char*)irisInfo.matData.data, SettingConfig::getInstance().IRIS_WIDTH * SettingConfig::getInstance().IRIS_HEIGHT); + data.prepend("[-m]"); // 识别 + + // 发送TCP消息去匹配 + emit sendDataToExract(data); + + // 状态修改为特征提取 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FEATURE_EXTRACT; + + QTimer toTimer; + QEventLoop loop; + toTimer.singleShot(3000, &loop, &QEventLoop::quit); +// connect(clientUtil, &SocketClientUtil::responseReaded, &loop, &QEventLoop::quit); + loop.exec(); + +// QByteArray matchResponse = clientUtil->getResponse(); + QByteArray matchResponse; +// LOG(INFO) << QString("算法匹配结果").toStdString() << matchResponse.toStdString(); +// LOG_INFO("算法匹配结果 {}",matchResponse.toStdString()); + + // 算法调用返回成功 + if (matchResponse.size() > 0) + { + QString response = matchResponse.mid(5, matchResponse.size() - 6); + QStringList messList = response.split(";"); + QString code = messList.at(0); + if (code.toInt() == 0) + { + QString personId = messList.at(1); + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_SEARCH_SUCC; + +// LOG(INFO) << QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString(); +// LOG_INFO(QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString()); + + // 保存图像文件 +// cv::imwrite(QString("D:\\irisLogs\\%1-%2.bmp").arg(QDateTime::currentDateTime().toString("HHmmsszzz")).arg(irisInfo.leftOrRight).toStdString(), irisInfo.matData); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + emit findMatchedIris(personId); + this->afterRecogAction(); + } else if (code.toInt() == -200) + { + // 匹配失败 +// LOG(INFO) << QString("匹配失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("匹配失败: {}", matchResponse.toStdString()); + + // 匹配失败则尝试次数+1 + addOneTryCount(); + } else if (code.toInt() == -100) + { + // 编码失败 +// LOG(INFO) << QString("编码失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("编码失败: {}", matchResponse.toStdString()); + // 编码失败则尝试次数+1 + addOneTryCount(); + } + } else + { + // 超时返回则尝试次数+1 + addOneTryCount(); + } + } +} + +void IrisRecogProcess::afterRecogAction() +{ + this->setWorking(false); + + ProMemory::getInstance().clearIrisQueue(); // 清理虹膜数据栈 +} + +void IrisRecogProcess::addOneTryCount() +{ + CasicIrisRecState::getInstance().tryCount++; +// LOG(DEBUG) << QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString()); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().tryCount >= SettingConfig::getInstance().MAX_IRIS_TRY_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + CasicIrisRecState::getInstance().tryCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + emit failedMatchedIris(); + } +} +void IrisRecogProcess::addOneNoEyeCount() +{ + CasicIrisRecState::getInstance().noEyeCount++; + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().noEyeCount >= SettingConfig::getInstance().MAX_EYE_NOT_FOUND_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + + if (qrand() % 10 < 5) { + emit failedMatchedIris(); + } + else { + emit findMatchedIris("1"); + } + } +} diff --git a/device/iris/IrisRecogProcess.h b/device/iris/IrisRecogProcess.h new file mode 100644 index 0000000..c4fc648 --- /dev/null +++ b/device/iris/IrisRecogProcess.h @@ -0,0 +1,47 @@ +#ifndef IRISRECOGPROCESS_H +#define IRISRECOGPROCESS_H + +#include +#include +#include +#include + +#include "ProMemory.h" +#include "device/iris/CasicIrisRecState.h" + +class IrisRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit IrisRecogProcess(QObject *parent = 0); + ~IrisRecogProcess(); + + void setWorking(bool working); + void exitThread(); + + void addOneTryCount(); + void addOneNoEyeCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + + volatile bool working; + volatile bool exit; + +private: +// SocketClientUtil * clientUtil; + + void afterRecogAction(); + +signals: + void sendDataToExract(QByteArray data); + + void failedMatchedIris(); + void findMatchedIris(QString personId); + +}; + +#endif // IRISRECOGPROCESS_H diff --git a/images/bg_failure.png b/images/bg_failure.png new file mode 100644 index 0000000..55000a0 --- /dev/null +++ b/images/bg_failure.png Binary files differ diff --git a/images/bg_identifying.png b/images/bg_identifying.png new file mode 100644 index 0000000..58d5a95 --- /dev/null +++ b/images/bg_identifying.png Binary files differ diff --git a/images/bg_statcked.png b/images/bg_statcked.png index 18b63e1..c76130f 100644 --- a/images/bg_statcked.png +++ b/images/bg_statcked.png Binary files differ diff --git a/images/bg_success.png b/images/bg_success.png new file mode 100644 index 0000000..c845bb8 --- /dev/null +++ b/images/bg_success.png Binary files differ diff --git a/images/bg_title.png b/images/bg_title.png index 0316e2d..131369a 100644 --- a/images/bg_title.png +++ b/images/bg_title.png Binary files differ diff --git a/images/iconWarn.png b/images/iconWarn.png new file mode 100644 index 0000000..e1d6403 --- /dev/null +++ b/images/iconWarn.png Binary files differ diff --git a/images/photo.png b/images/photo.png new file mode 100644 index 0000000..d9fa9fa --- /dev/null +++ b/images/photo.png Binary files differ diff --git a/resource.qrc b/resource.qrc index 474586a..9d964c6 100644 --- a/resource.qrc +++ b/resource.qrc @@ -1,35 +1,12 @@ - images/setting.png - images/user.png - images/back.png - images/home.png - images/btnPageFirst.png - images/btnPageLast.png - images/btnPageNext.png - images/btnPagePre.png - images/regist.png - images/photoEyeLeft.png - images/photoEyeRight.png - images/photoFace.png - images/save.png - images/upArrow.png - images/downArrow.png - images/faceCaped.png - images/faceNotCap.png - images/irisCaped.png - images/irisNotCap.png - images/tipsFailure.png - images/tipsSuccess.png - images/tipsConfirm.png - images/bg_recognize_result.png - images/iconRetry.png images/bg_title.png images/bg_footer.png images/bg_statcked.png - - - images/add_bottom.png - images/add_top.png + images/bg_identifying.png + images/bg_failure.png + images/iconWarn.png + images/photo.png + images/bg_success.png diff --git a/utils/ImageUtil.cpp b/utils/ImageUtil.cpp index 7604572..ff77331 100644 --- a/utils/ImageUtil.cpp +++ b/utils/ImageUtil.cpp @@ -1,4 +1,4 @@ -#include "ImageUtil.h" +#include "ImageUtil.h" ImageUtil::ImageUtil() { @@ -36,12 +36,11 @@ return QImage(); } } -/* -QImage ImageUtil::UcharToQImage(unsigned char* data, int width, int height, QImage::Format format) + +cv::Mat ImageUtil::ucharToMat(unsigned char *data, int row, int col) { - QImage qImage(data, width, height, format); - //在不改变实际图像数据的条件下, 交换红蓝通道 - return qImage.rgbSwapped(); + cv::Mat img(row, col, CV_8UC1, (unsigned char *)data); + return img; } cv::Mat ImageUtil::QImageToMat(QImage image) @@ -64,6 +63,9 @@ case QImage::Format_Grayscale8: mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void *)image.bits(), image.bytesPerLine()); break; + + default: + break; } mat = mat.clone(); @@ -71,6 +73,14 @@ return mat; } +/* +QImage ImageUtil::UcharToQImage(unsigned char* data, int width, int height, QImage::Format format) +{ + QImage qImage(data, width, height, format); + //在不改变实际图像数据的条件下, 交换红蓝通道 + return qImage.rgbSwapped(); +} + QString ImageUtil::QImageToBase64(QImage image) { QByteArray ba; diff --git a/utils/ImageUtil.h b/utils/ImageUtil.h index dbfdd48..d9bf00a 100644 --- a/utils/ImageUtil.h +++ b/utils/ImageUtil.h @@ -1,4 +1,4 @@ -#ifndef IMAGEUTIL_H +#ifndef IMAGEUTIL_H #define IMAGEUTIL_H #include @@ -13,7 +13,8 @@ static QImage MatImageToQImage(const cv::Mat &src); // static QImage UcharToQImage(unsigned char* data, int width, int height, QImage::Format format); -// static cv::Mat QImageToMat(QImage image); + static cv::Mat ucharToMat(unsigned char * data, int row, int col); + static cv::Mat QImageToMat(QImage image); // static QString QImageToBase64(QImage image); // static cv::Mat MatImageRect(const cv::Mat &src, cv::Rect rect, int delta); diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/casic/iris/CasicIrisInterface.cpp b/casic/iris/CasicIrisInterface.cpp new file mode 100644 index 0000000..5c46e5b --- /dev/null +++ b/casic/iris/CasicIrisInterface.cpp @@ -0,0 +1,187 @@ +#include "CasicIrisInterface.h" + +#include +#include +#include + +casic::iris::CasicIrisInterface::CasicIrisInterface() +{ + +} + +casic::iris::CasicIrisInterface::~CasicIrisInterface() +{ + +} + +void casic::iris::CasicIrisInterface::setCascadeFile(QString filename) +{ + this->cascadeName = filename.toStdString(); +} +void casic::iris::CasicIrisInterface::setMinEyeSize(int minEyeSize) +{ + this->minEyeSize = minEyeSize; +} +void casic::iris::CasicIrisInterface::setMaxEyeSize(int maxEyeSize) +{ + this->maxEyeSize = maxEyeSize; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.data = ImageUtil::MatImageToQImage(irisInfo.matData); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findAndCutEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + // 找到眼睛之后, 将眼部裁剪下来, 图像拉伸到640 * 480 + cv::Point center; + center.x = cvFloor(rect.at(0).x + rect.at(0).width*0.5); + center.y = cvFloor(rect.at(0).y + rect.at(0).height*0.5); + + // 限制中心点的范围 + if (center.x < SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) + { + // x小于240则x=240 +// center.x = center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + center.x = SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } else if (center.x > SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) { + // x大于1040则x=1040 + center.x = SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } + + if (center.y < SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) + { + // y小于180则y=180 + center.y = SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } else if (center.y > SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) { + center.y = SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } + + // 裁剪眼部图像 + cv::Mat halfSize = irisInfo.matData.clone(); + halfSize = irisInfo.matData(cv::Rect(center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5, + center.y - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5, + SettingConfig::getInstance().IRIS_WIDTH * cutRatio, + SettingConfig::getInstance().IRIS_HEIGHT * cutRatio)); + + cv::resize(halfSize, halfSize, cv::Size(SettingConfig::getInstance().IRIS_WIDTH, SettingConfig::getInstance().IRIS_HEIGHT)); + cv::flip(halfSize, halfSize, 1); // 左右翻转 + +// cv::imwrite(QString("d:\\irisLogs\\%1.bmp").arg(QDateTime::currentSecsSinceEpoch()).toStdString(), halfSize); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.matData = halfSize; + irisInfo.data = ImageUtil::MatImageToQImage(halfSize); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisQualityAssess(CasicIrisInfo irisInfo) +{ + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisCodeExtract(CasicIrisInfo irisInfo) +{ + + QElapsedTimer timer; + timer.start(); + +// QSocketClientUtil * clientUtil = new QSocketClientUtil(); + + QByteArray data((char*)irisInfo.matData.data, 640*480); + + std::cout << "extract iris code" << std::endl; + +// clientUtil->sendData(data); +// if (response.size() == 1024) +// { +// QLog::getInstance()->logger()->debug(QString("特征值提取[耗时: %1ms][特征值: %2]\n") +// .arg(timer.elapsed()) +// .arg(QByteUtil::binToHexString(response))); +// } else +// { +// std::cout << response.toStdString() << std::endl; +// } + + return irisInfo; +} diff --git a/casic/iris/CasicIrisInterface.h b/casic/iris/CasicIrisInterface.h new file mode 100644 index 0000000..87ed97e --- /dev/null +++ b/casic/iris/CasicIrisInterface.h @@ -0,0 +1,45 @@ +#ifndef CASICIRISINTERFACE_H +#define CASICIRISINTERFACE_H + +#include "CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +namespace casic { + namespace iris { + class CasicIrisInterface + { + public: + ~CasicIrisInterface(); + CasicIrisInterface(const CasicIrisInterface&)=delete; + CasicIrisInterface& operator=(const CasicIrisInterface&)=delete; + + static CasicIrisInterface& getInstance() { + static CasicIrisInterface instance; + return instance; + } + + CasicIrisInfo findEye(CasicIrisInfo irisInfo); + CasicIrisInfo findAndCutEye(CasicIrisInfo irisInfo); + CasicIrisInfo irisQualityAssess(CasicIrisInfo irisInfo); + CasicIrisInfo irisCodeExtract(CasicIrisInfo irisInfo); + CasicIrisInfo irisMatch(CasicIrisInfo irisInfo); + + void setCascadeFile(QString filename); + void setMinEyeSize(int minEyeSize); + void setMaxEyeSize(int maxEyeSize); + + private: + CasicIrisInterface(); + + std::string cascadeName = "./model/haarcascade_eye.xml"; + int minEyeSize = 320; + int maxEyeSize = 480; + float cutRatio = 1.0; + + cv::CascadeClassifier * cascade; + }; + } +} + + +#endif // CASICIRISINTERFACE_H diff --git a/casic/iris/casicIris.pri b/casic/iris/casicIris.pri new file mode 100644 index 0000000..d0942ce --- /dev/null +++ b/casic/iris/casicIris.pri @@ -0,0 +1,4 @@ +HEADERS += $$PWD/CasicIrisInfo.h +HEADERS += $$PWD/CasicIrisInterface.h + +SOURCES += $$PWD/CasicIrisInterface.cpp diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index 45df089..49e7316 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -1,4 +1,5 @@ #include "IrisCameraCapEventHandler.h" +#include IrisCameraCapEventHandler::IrisCameraCapEventHandler(QObject *parent) : QObject(parent) { @@ -14,90 +15,37 @@ auto camName = cam->getPtr()->GetDeviceInfo().GetUserID(); int width = objImageDataPointer->GetWidth(); int height = objImageDataPointer->GetHeight(); - size_t leftKeyIndex = camName.find("left"); - size_t rightKeyIndex = camName.find("right"); uchar * pBuffer = (BYTE*)objImageDataPointer->GetBuffer(); - - // 相机拍摄下的图像1440*1080, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 -// QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到400 * 300的尺寸 - img = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT, SettingConfig::getInstance().IRIS_DISPLAY_WIDTH); - img = img.transformed(QTransform().rotate(-90)); // 图像逆时针旋转90度 - - // 发送到界面进行显示 - emit sendIrisFrameToDraw(img); -// cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - -// irisInfo.data = imgAlgo; -// irisInfo.matData = irisMat; - -// // 将图像显示在注册页面的label上 -// // 并将虹膜信息对象存入队列中 -// ProMemory::getInstance().pushCasicIris(irisInfo); - -// if (leftKeyIndex >= 0 && leftKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 0); // 左眼画面 -// } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 1); // 右眼画面 -// } -/* if (pBuffer != NULL) { + // 相机拍摄下的图像1440*1080, 直接用于算法判断 + QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 + QImage imgDisp; + + // 图像逆时针旋转90度 + img = img.transformed(QTransform().rotate(90)); + + // 用于显示的图像需要缩小到480 * 640的尺寸 + imgDisp = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_WIDTH, SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT); + + // 发送到界面进行显示 + emit sendIrisFrameToDraw(imgDisp); + // 创建虹膜信息对象 CasicIrisInfo irisInfo; irisInfo.hasEye = false; - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - // 左眼相机拍摄的图像 - irisInfo.leftOrRight = "left"; - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - // 右眼相机 - irisInfo.leftOrRight = "right"; - } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - cv::Mat irisMat = ImageUtil::QImageToMat(imgDisp); + // 存入图像栈 + cv::Mat irisMat = ImageUtil::QImageToMat(img); + irisInfo.matData = irisMat; - irisInfo.data = imgDisp; - irisInfo.matData = irisMat; + ProMemory::getInstance().pushCasicIris(irisInfo); - ProMemory::getInstance().pushCasicIris(irisInfo); - -// cv::imwrite(QString("D:\\irisLogs\\iristest-%1.bmp").arg(irisInfo.leftOrRight).toStdString(), irisMat); - } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到1/4的尺寸 - img = img.scaled(640, 480); - cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - - irisInfo.data = imgAlgo; - irisInfo.matData = irisMat; - - // 将图像显示在注册页面的label上 - // 并将虹膜信息对象存入队列中 - ProMemory::getInstance().pushCasicIris(irisInfo); - - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 0); // 左眼画面 - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 1); // 右眼画面 - } - } - }*/ + /* 相机控制只拍图 不找眼 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + */ + } } } diff --git a/device/IrisCameraCapEventHandler.h b/device/IrisCameraCapEventHandler.h index ad75a97..8b976c5 100644 --- a/device/IrisCameraCapEventHandler.h +++ b/device/IrisCameraCapEventHandler.h @@ -6,7 +6,7 @@ #include "include/opencv2/opencv.hpp" #include "include/daheng/GalaxyIncludes.h" -//#include "casic/iris/CasicIrisInterface.h" +#include "casic/iris/CasicIrisInterface.h" #include "ProMemory.h" #include "utils/UtilInclude.h" diff --git a/device/device.pri b/device/device.pri index a8417f2..d1330a0 100644 --- a/device/device.pri +++ b/device/device.pri @@ -2,12 +2,12 @@ HEADERS += $$PWD/IrisCameraController.h HEADERS += $$PWD/IrisCameraCapEventHandler.h #HEADERS += $$PWD/iris/IrisRegistProcess.h -#HEADERS += $$PWD/iris/IrisRecogProcess.h -#HEADERS += $$PWD/iris/CasicIrisRecState.h +HEADERS += $$PWD/iris/IrisRecogProcess.h +HEADERS += $$PWD/iris/CasicIrisRecState.h SOURCES += $$PWD/IrisCameraController.cpp SOURCES += $$PWD/IrisCameraCapEventHandler.cpp #SOURCES += $$PWD/iris/IrisRegistProcess.cpp -#SOURCES += $$PWD/iris/IrisRecogProcess.cpp -#SOURCES += $$PWD/iris/CasicIrisRecState.cpp +SOURCES += $$PWD/iris/IrisRecogProcess.cpp +SOURCES += $$PWD/iris/CasicIrisRecState.cpp diff --git a/device/iris/CasicIrisRecState.cpp b/device/iris/CasicIrisRecState.cpp new file mode 100644 index 0000000..b64d747 --- /dev/null +++ b/device/iris/CasicIrisRecState.cpp @@ -0,0 +1,63 @@ +#include "CasicIrisRecState.h" +#include "utils/UtilInclude.h" + +CasicIrisRecState::CasicIrisRecState() +{ + this->recoginzeId = "0"; + this->timeStamp = -1; + + this->state = IrisRecStateName::REC_NOT_START; + + this->irisInfo = new CasicIrisInfo(); +} + +CasicIrisRecState::~CasicIrisRecState() +{ + delete this->irisInfo; +} + +void CasicIrisRecState::initRecognize() +{ + QDateTime now = QDateTime::currentDateTime(); + this->recoginzeId = now.toString("yyyyMMddHHmmsszzz"); + this->timeStamp = now.toMSecsSinceEpoch(); + this->tryCount = 0; + this->noEyeCount = 0; + +// LOG(DEBUG) << QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString()); + qDebug() << QString("[CasicIrisRecState][initRecognize][%1] 虹膜识别状态初始化").arg(recoginzeId); + +} + +QString CasicIrisRecState::toString() +{ + return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)); +} + + +QJsonObject CasicIrisRecState::toJSON() +{ + QJsonObject obj; + + obj.insert("recoginzeId", recoginzeId); + obj.insert("timestamp", timeStamp); + obj.insert("timestampSucc", timeStampSucc); + obj.insert("state", state); + obj.insert("tryCount", tryCount); + obj.insert("noEyeCount", noEyeCount); + obj.insert("recogTimeLast", recogTimeLast); + + QJsonObject eyeObj; + eyeObj.insert("hasEye", irisInfo->hasEye); + QJsonArray rectArray; + rectArray.append(irisInfo->eyeRect.x); + rectArray.append(irisInfo->eyeRect.y); + rectArray.append(irisInfo->eyeRect.width); + rectArray.append(irisInfo->eyeRect.height); + eyeObj.insert("faceRect", rectArray); + + obj.insert("eye", eyeObj); + + return obj; +} diff --git a/device/iris/CasicIrisRecState.h b/device/iris/CasicIrisRecState.h new file mode 100644 index 0000000..eea5ddf --- /dev/null +++ b/device/iris/CasicIrisRecState.h @@ -0,0 +1,67 @@ +#ifndef CASICIRISRECSTATE_H +#define CASICIRISRECSTATE_H + +#include +#include +#include +#include + +#include "casic/iris/CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +class CasicIrisRecState : public QObject +{ +public: + ~CasicIrisRecState(); + CasicIrisRecState(const CasicIrisRecState&)=delete; + CasicIrisRecState& operator=(const CasicIrisRecState&)=delete; + + static CasicIrisRecState& getInstance() { + static CasicIrisRecState instance; + return instance; + } + + void initRecognize(); + QString toString(); + QJsonObject toJSON(); + + QString recoginzeId; // 识别过程id + qint64 timeStamp = 0; // 识别开始时间戳 + qint64 timeStampSucc = 0; // 识别成功时的时间戳 + qint64 findEyeTmLast = 0; // 找眼操作耗时 + + CasicIrisInfo * irisInfo; + + qint8 tryCount = 0; // 识别尝试次数 + qint8 noEyeCount = 0; // 连续没有找到眼睛次数 + float recogTimeLast = 0.0; // 识别成功耗时 + + /** + * @brief state + * 0=初始值 + * 1=左眼检测 + * 2=右眼检测 + * 3=质量评估 + * 4=特征值提取 + * 5=虹膜库比对成功 + * 6=虹膜库比对失败 + */ + volatile int state; + + enum IrisRecStateName + { + REC_NOT_START = 0, // 未开始 + REC_LEFT_FIND_EYE = 1, // 检测左眼, 没找到右眼 + REC_RIGHT_FIND_EYE = 2, // 检测右眼, 没找到左眼 + REC_FIND_EYE = 3, // 找到左眼和右眼 + REC_FEATURE_EXTRACT = 4, // 特征值提取成功 + REC_SEARCH_SUCC = 5, // 虹膜库比对成功 + REC_SEARCH_FAIL = 6 // 虹膜库比对失败 + }; + +private: + CasicIrisRecState(); + +}; + +#endif // CASICIRISRECSTATE_H diff --git a/device/iris/IrisRecogProcess.cpp b/device/iris/IrisRecogProcess.cpp new file mode 100644 index 0000000..6869ece --- /dev/null +++ b/device/iris/IrisRecogProcess.cpp @@ -0,0 +1,223 @@ +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + + +#include "IrisRecogProcess.h" + +IrisRecogProcess::IrisRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; + + // 连接算法服务 +// clientUtil = new SocketClientUtil(this); +// clientUtil->connect("127.0.0.1", 2015); + + // 调用socket发送消息 +// connect(this, &IrisRecogProcess::sendDataToExract, clientUtil, &SocketClientUtil::sendData); +} + +IrisRecogProcess::~IrisRecogProcess() +{ + this->setWorking(false); +} + +void IrisRecogProcess::setWorking(bool working) +{ + this->working = working; +} + +void IrisRecogProcess::exitThread() +{ + this->exit = true; +} + +void IrisRecogProcess::run() +{ + while (exit == false) + { + // 如果工作标志位为否, 则跳出 + if (this->working == false) + { + this->msleep(200); // 200ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isIrisQueueEmpty() == true) + { +// LOG(TRACE) << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString()); + qDebug() << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms"); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicIrisRecState::getInstance().state != CasicIrisRecState::IrisRecStateName::REC_NOT_START) + { +// LOG(DEBUG) << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state).toStdString(); + + qDebug() << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(TRACE) << QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString()); + + // 取出虹膜图像栈中的一条数据 + CasicIrisInfo irisInfo = ProMemory::getInstance().popCasicIris(); + +// LOG(DEBUG) << QString("[IrisRecogProcess] 取出虹膜图像").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 取出虹膜图像").toStdString()); + qDebug() << QString("[IrisRecogProcess] 取出虹膜图像"); + + // 调用找眼分类器算法 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findAndCutEye(irisInfo); + + // 没有找到眼睛则返回 + if (irisInfo.hasEye == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 +// LOG(DEBUG) << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString()); + qDebug() << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount); + + addOneNoEyeCount(); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(DEBUG) << QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString()); + + // 找到眼睛则开始质量评估和编码 + // 调用远程算法进行编码 + if (CasicIrisRecState::getInstance().recoginzeId == "0") + { + // 第一次找到眼则 虹膜识别状态初始化 + CasicIrisRecState::getInstance().initRecognize(); + } + + CasicIrisRecState::getInstance().noEyeCount = 0; // 持续未找到眼的次数清零 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FIND_EYE; + CasicIrisRecState::getInstance().irisInfo->hasEye = irisInfo.hasEye; + CasicIrisRecState::getInstance().irisInfo->eyeRect = irisInfo.eyeRect; + CasicIrisRecState::getInstance().irisInfo->matData = irisInfo.matData; + CasicIrisRecState::getInstance().irisInfo->data = ImageUtil::MatImageToQImage(irisInfo.matData); + + QElapsedTimer timer; + timer.start(); + + QByteArray data((char*)irisInfo.matData.data, SettingConfig::getInstance().IRIS_WIDTH * SettingConfig::getInstance().IRIS_HEIGHT); + data.prepend("[-m]"); // 识别 + + // 发送TCP消息去匹配 + emit sendDataToExract(data); + + // 状态修改为特征提取 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FEATURE_EXTRACT; + + QTimer toTimer; + QEventLoop loop; + toTimer.singleShot(3000, &loop, &QEventLoop::quit); +// connect(clientUtil, &SocketClientUtil::responseReaded, &loop, &QEventLoop::quit); + loop.exec(); + +// QByteArray matchResponse = clientUtil->getResponse(); + QByteArray matchResponse; +// LOG(INFO) << QString("算法匹配结果").toStdString() << matchResponse.toStdString(); +// LOG_INFO("算法匹配结果 {}",matchResponse.toStdString()); + + // 算法调用返回成功 + if (matchResponse.size() > 0) + { + QString response = matchResponse.mid(5, matchResponse.size() - 6); + QStringList messList = response.split(";"); + QString code = messList.at(0); + if (code.toInt() == 0) + { + QString personId = messList.at(1); + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_SEARCH_SUCC; + +// LOG(INFO) << QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString(); +// LOG_INFO(QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString()); + + // 保存图像文件 +// cv::imwrite(QString("D:\\irisLogs\\%1-%2.bmp").arg(QDateTime::currentDateTime().toString("HHmmsszzz")).arg(irisInfo.leftOrRight).toStdString(), irisInfo.matData); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + emit findMatchedIris(personId); + this->afterRecogAction(); + } else if (code.toInt() == -200) + { + // 匹配失败 +// LOG(INFO) << QString("匹配失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("匹配失败: {}", matchResponse.toStdString()); + + // 匹配失败则尝试次数+1 + addOneTryCount(); + } else if (code.toInt() == -100) + { + // 编码失败 +// LOG(INFO) << QString("编码失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("编码失败: {}", matchResponse.toStdString()); + // 编码失败则尝试次数+1 + addOneTryCount(); + } + } else + { + // 超时返回则尝试次数+1 + addOneTryCount(); + } + } +} + +void IrisRecogProcess::afterRecogAction() +{ + this->setWorking(false); + + ProMemory::getInstance().clearIrisQueue(); // 清理虹膜数据栈 +} + +void IrisRecogProcess::addOneTryCount() +{ + CasicIrisRecState::getInstance().tryCount++; +// LOG(DEBUG) << QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString()); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().tryCount >= SettingConfig::getInstance().MAX_IRIS_TRY_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + CasicIrisRecState::getInstance().tryCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + emit failedMatchedIris(); + } +} +void IrisRecogProcess::addOneNoEyeCount() +{ + CasicIrisRecState::getInstance().noEyeCount++; + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().noEyeCount >= SettingConfig::getInstance().MAX_EYE_NOT_FOUND_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + + if (qrand() % 10 < 5) { + emit failedMatchedIris(); + } + else { + emit findMatchedIris("1"); + } + } +} diff --git a/device/iris/IrisRecogProcess.h b/device/iris/IrisRecogProcess.h new file mode 100644 index 0000000..c4fc648 --- /dev/null +++ b/device/iris/IrisRecogProcess.h @@ -0,0 +1,47 @@ +#ifndef IRISRECOGPROCESS_H +#define IRISRECOGPROCESS_H + +#include +#include +#include +#include + +#include "ProMemory.h" +#include "device/iris/CasicIrisRecState.h" + +class IrisRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit IrisRecogProcess(QObject *parent = 0); + ~IrisRecogProcess(); + + void setWorking(bool working); + void exitThread(); + + void addOneTryCount(); + void addOneNoEyeCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + + volatile bool working; + volatile bool exit; + +private: +// SocketClientUtil * clientUtil; + + void afterRecogAction(); + +signals: + void sendDataToExract(QByteArray data); + + void failedMatchedIris(); + void findMatchedIris(QString personId); + +}; + +#endif // IRISRECOGPROCESS_H diff --git a/images/bg_failure.png b/images/bg_failure.png new file mode 100644 index 0000000..55000a0 --- /dev/null +++ b/images/bg_failure.png Binary files differ diff --git a/images/bg_identifying.png b/images/bg_identifying.png new file mode 100644 index 0000000..58d5a95 --- /dev/null +++ b/images/bg_identifying.png Binary files differ diff --git a/images/bg_statcked.png b/images/bg_statcked.png index 18b63e1..c76130f 100644 --- a/images/bg_statcked.png +++ b/images/bg_statcked.png Binary files differ diff --git a/images/bg_success.png b/images/bg_success.png new file mode 100644 index 0000000..c845bb8 --- /dev/null +++ b/images/bg_success.png Binary files differ diff --git a/images/bg_title.png b/images/bg_title.png index 0316e2d..131369a 100644 --- a/images/bg_title.png +++ b/images/bg_title.png Binary files differ diff --git a/images/iconWarn.png b/images/iconWarn.png new file mode 100644 index 0000000..e1d6403 --- /dev/null +++ b/images/iconWarn.png Binary files differ diff --git a/images/photo.png b/images/photo.png new file mode 100644 index 0000000..d9fa9fa --- /dev/null +++ b/images/photo.png Binary files differ diff --git a/resource.qrc b/resource.qrc index 474586a..9d964c6 100644 --- a/resource.qrc +++ b/resource.qrc @@ -1,35 +1,12 @@ - images/setting.png - images/user.png - images/back.png - images/home.png - images/btnPageFirst.png - images/btnPageLast.png - images/btnPageNext.png - images/btnPagePre.png - images/regist.png - images/photoEyeLeft.png - images/photoEyeRight.png - images/photoFace.png - images/save.png - images/upArrow.png - images/downArrow.png - images/faceCaped.png - images/faceNotCap.png - images/irisCaped.png - images/irisNotCap.png - images/tipsFailure.png - images/tipsSuccess.png - images/tipsConfirm.png - images/bg_recognize_result.png - images/iconRetry.png images/bg_title.png images/bg_footer.png images/bg_statcked.png - - - images/add_bottom.png - images/add_top.png + images/bg_identifying.png + images/bg_failure.png + images/iconWarn.png + images/photo.png + images/bg_success.png diff --git a/utils/ImageUtil.cpp b/utils/ImageUtil.cpp index 7604572..ff77331 100644 --- a/utils/ImageUtil.cpp +++ b/utils/ImageUtil.cpp @@ -1,4 +1,4 @@ -#include "ImageUtil.h" +#include "ImageUtil.h" ImageUtil::ImageUtil() { @@ -36,12 +36,11 @@ return QImage(); } } -/* -QImage ImageUtil::UcharToQImage(unsigned char* data, int width, int height, QImage::Format format) + +cv::Mat ImageUtil::ucharToMat(unsigned char *data, int row, int col) { - QImage qImage(data, width, height, format); - //在不改变实际图像数据的条件下, 交换红蓝通道 - return qImage.rgbSwapped(); + cv::Mat img(row, col, CV_8UC1, (unsigned char *)data); + return img; } cv::Mat ImageUtil::QImageToMat(QImage image) @@ -64,6 +63,9 @@ case QImage::Format_Grayscale8: mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void *)image.bits(), image.bytesPerLine()); break; + + default: + break; } mat = mat.clone(); @@ -71,6 +73,14 @@ return mat; } +/* +QImage ImageUtil::UcharToQImage(unsigned char* data, int width, int height, QImage::Format format) +{ + QImage qImage(data, width, height, format); + //在不改变实际图像数据的条件下, 交换红蓝通道 + return qImage.rgbSwapped(); +} + QString ImageUtil::QImageToBase64(QImage image) { QByteArray ba; diff --git a/utils/ImageUtil.h b/utils/ImageUtil.h index dbfdd48..d9bf00a 100644 --- a/utils/ImageUtil.h +++ b/utils/ImageUtil.h @@ -1,4 +1,4 @@ -#ifndef IMAGEUTIL_H +#ifndef IMAGEUTIL_H #define IMAGEUTIL_H #include @@ -13,7 +13,8 @@ static QImage MatImageToQImage(const cv::Mat &src); // static QImage UcharToQImage(unsigned char* data, int width, int height, QImage::Format format); -// static cv::Mat QImageToMat(QImage image); + static cv::Mat ucharToMat(unsigned char * data, int row, int col); + static cv::Mat QImageToMat(QImage image); // static QString QImageToBase64(QImage image); // static cv::Mat MatImageRect(const cv::Mat &src, cv::Rect rect, int delta); diff --git a/utils/SpeakerUtil.cpp b/utils/SpeakerUtil.cpp new file mode 100644 index 0000000..2cb9b20 --- /dev/null +++ b/utils/SpeakerUtil.cpp @@ -0,0 +1,18 @@ +#include "SpeakerUtil.h" + +SpeakerUtil::SpeakerUtil(QObject *parent) : QObject(parent) +{ + tts = new QTextToSpeech(parent); + tts->setLocale(QLocale::Chinese); + tts->setRate(0.0); + tts->setPitch(1.0); + tts->setVolume(1.0); +} + +void SpeakerUtil::speak(QString content) +{ + if (tts->state() == QTextToSpeech::Ready && tts->state() != QTextToSpeech::Speaking) + { + tts->say(content); + } +} diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/casic/iris/CasicIrisInterface.cpp b/casic/iris/CasicIrisInterface.cpp new file mode 100644 index 0000000..5c46e5b --- /dev/null +++ b/casic/iris/CasicIrisInterface.cpp @@ -0,0 +1,187 @@ +#include "CasicIrisInterface.h" + +#include +#include +#include + +casic::iris::CasicIrisInterface::CasicIrisInterface() +{ + +} + +casic::iris::CasicIrisInterface::~CasicIrisInterface() +{ + +} + +void casic::iris::CasicIrisInterface::setCascadeFile(QString filename) +{ + this->cascadeName = filename.toStdString(); +} +void casic::iris::CasicIrisInterface::setMinEyeSize(int minEyeSize) +{ + this->minEyeSize = minEyeSize; +} +void casic::iris::CasicIrisInterface::setMaxEyeSize(int maxEyeSize) +{ + this->maxEyeSize = maxEyeSize; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.data = ImageUtil::MatImageToQImage(irisInfo.matData); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findAndCutEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + // 找到眼睛之后, 将眼部裁剪下来, 图像拉伸到640 * 480 + cv::Point center; + center.x = cvFloor(rect.at(0).x + rect.at(0).width*0.5); + center.y = cvFloor(rect.at(0).y + rect.at(0).height*0.5); + + // 限制中心点的范围 + if (center.x < SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) + { + // x小于240则x=240 +// center.x = center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + center.x = SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } else if (center.x > SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) { + // x大于1040则x=1040 + center.x = SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } + + if (center.y < SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) + { + // y小于180则y=180 + center.y = SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } else if (center.y > SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) { + center.y = SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } + + // 裁剪眼部图像 + cv::Mat halfSize = irisInfo.matData.clone(); + halfSize = irisInfo.matData(cv::Rect(center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5, + center.y - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5, + SettingConfig::getInstance().IRIS_WIDTH * cutRatio, + SettingConfig::getInstance().IRIS_HEIGHT * cutRatio)); + + cv::resize(halfSize, halfSize, cv::Size(SettingConfig::getInstance().IRIS_WIDTH, SettingConfig::getInstance().IRIS_HEIGHT)); + cv::flip(halfSize, halfSize, 1); // 左右翻转 + +// cv::imwrite(QString("d:\\irisLogs\\%1.bmp").arg(QDateTime::currentSecsSinceEpoch()).toStdString(), halfSize); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.matData = halfSize; + irisInfo.data = ImageUtil::MatImageToQImage(halfSize); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisQualityAssess(CasicIrisInfo irisInfo) +{ + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisCodeExtract(CasicIrisInfo irisInfo) +{ + + QElapsedTimer timer; + timer.start(); + +// QSocketClientUtil * clientUtil = new QSocketClientUtil(); + + QByteArray data((char*)irisInfo.matData.data, 640*480); + + std::cout << "extract iris code" << std::endl; + +// clientUtil->sendData(data); +// if (response.size() == 1024) +// { +// QLog::getInstance()->logger()->debug(QString("特征值提取[耗时: %1ms][特征值: %2]\n") +// .arg(timer.elapsed()) +// .arg(QByteUtil::binToHexString(response))); +// } else +// { +// std::cout << response.toStdString() << std::endl; +// } + + return irisInfo; +} diff --git a/casic/iris/CasicIrisInterface.h b/casic/iris/CasicIrisInterface.h new file mode 100644 index 0000000..87ed97e --- /dev/null +++ b/casic/iris/CasicIrisInterface.h @@ -0,0 +1,45 @@ +#ifndef CASICIRISINTERFACE_H +#define CASICIRISINTERFACE_H + +#include "CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +namespace casic { + namespace iris { + class CasicIrisInterface + { + public: + ~CasicIrisInterface(); + CasicIrisInterface(const CasicIrisInterface&)=delete; + CasicIrisInterface& operator=(const CasicIrisInterface&)=delete; + + static CasicIrisInterface& getInstance() { + static CasicIrisInterface instance; + return instance; + } + + CasicIrisInfo findEye(CasicIrisInfo irisInfo); + CasicIrisInfo findAndCutEye(CasicIrisInfo irisInfo); + CasicIrisInfo irisQualityAssess(CasicIrisInfo irisInfo); + CasicIrisInfo irisCodeExtract(CasicIrisInfo irisInfo); + CasicIrisInfo irisMatch(CasicIrisInfo irisInfo); + + void setCascadeFile(QString filename); + void setMinEyeSize(int minEyeSize); + void setMaxEyeSize(int maxEyeSize); + + private: + CasicIrisInterface(); + + std::string cascadeName = "./model/haarcascade_eye.xml"; + int minEyeSize = 320; + int maxEyeSize = 480; + float cutRatio = 1.0; + + cv::CascadeClassifier * cascade; + }; + } +} + + +#endif // CASICIRISINTERFACE_H diff --git a/casic/iris/casicIris.pri b/casic/iris/casicIris.pri new file mode 100644 index 0000000..d0942ce --- /dev/null +++ b/casic/iris/casicIris.pri @@ -0,0 +1,4 @@ +HEADERS += $$PWD/CasicIrisInfo.h +HEADERS += $$PWD/CasicIrisInterface.h + +SOURCES += $$PWD/CasicIrisInterface.cpp diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index 45df089..49e7316 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -1,4 +1,5 @@ #include "IrisCameraCapEventHandler.h" +#include IrisCameraCapEventHandler::IrisCameraCapEventHandler(QObject *parent) : QObject(parent) { @@ -14,90 +15,37 @@ auto camName = cam->getPtr()->GetDeviceInfo().GetUserID(); int width = objImageDataPointer->GetWidth(); int height = objImageDataPointer->GetHeight(); - size_t leftKeyIndex = camName.find("left"); - size_t rightKeyIndex = camName.find("right"); uchar * pBuffer = (BYTE*)objImageDataPointer->GetBuffer(); - - // 相机拍摄下的图像1440*1080, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 -// QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到400 * 300的尺寸 - img = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT, SettingConfig::getInstance().IRIS_DISPLAY_WIDTH); - img = img.transformed(QTransform().rotate(-90)); // 图像逆时针旋转90度 - - // 发送到界面进行显示 - emit sendIrisFrameToDraw(img); -// cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - -// irisInfo.data = imgAlgo; -// irisInfo.matData = irisMat; - -// // 将图像显示在注册页面的label上 -// // 并将虹膜信息对象存入队列中 -// ProMemory::getInstance().pushCasicIris(irisInfo); - -// if (leftKeyIndex >= 0 && leftKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 0); // 左眼画面 -// } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 1); // 右眼画面 -// } -/* if (pBuffer != NULL) { + // 相机拍摄下的图像1440*1080, 直接用于算法判断 + QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 + QImage imgDisp; + + // 图像逆时针旋转90度 + img = img.transformed(QTransform().rotate(90)); + + // 用于显示的图像需要缩小到480 * 640的尺寸 + imgDisp = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_WIDTH, SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT); + + // 发送到界面进行显示 + emit sendIrisFrameToDraw(imgDisp); + // 创建虹膜信息对象 CasicIrisInfo irisInfo; irisInfo.hasEye = false; - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - // 左眼相机拍摄的图像 - irisInfo.leftOrRight = "left"; - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - // 右眼相机 - irisInfo.leftOrRight = "right"; - } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - cv::Mat irisMat = ImageUtil::QImageToMat(imgDisp); + // 存入图像栈 + cv::Mat irisMat = ImageUtil::QImageToMat(img); + irisInfo.matData = irisMat; - irisInfo.data = imgDisp; - irisInfo.matData = irisMat; + ProMemory::getInstance().pushCasicIris(irisInfo); - ProMemory::getInstance().pushCasicIris(irisInfo); - -// cv::imwrite(QString("D:\\irisLogs\\iristest-%1.bmp").arg(irisInfo.leftOrRight).toStdString(), irisMat); - } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到1/4的尺寸 - img = img.scaled(640, 480); - cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - - irisInfo.data = imgAlgo; - irisInfo.matData = irisMat; - - // 将图像显示在注册页面的label上 - // 并将虹膜信息对象存入队列中 - ProMemory::getInstance().pushCasicIris(irisInfo); - - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 0); // 左眼画面 - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 1); // 右眼画面 - } - } - }*/ + /* 相机控制只拍图 不找眼 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + */ + } } } diff --git a/device/IrisCameraCapEventHandler.h b/device/IrisCameraCapEventHandler.h index ad75a97..8b976c5 100644 --- a/device/IrisCameraCapEventHandler.h +++ b/device/IrisCameraCapEventHandler.h @@ -6,7 +6,7 @@ #include "include/opencv2/opencv.hpp" #include "include/daheng/GalaxyIncludes.h" -//#include "casic/iris/CasicIrisInterface.h" +#include "casic/iris/CasicIrisInterface.h" #include "ProMemory.h" #include "utils/UtilInclude.h" diff --git a/device/device.pri b/device/device.pri index a8417f2..d1330a0 100644 --- a/device/device.pri +++ b/device/device.pri @@ -2,12 +2,12 @@ HEADERS += $$PWD/IrisCameraController.h HEADERS += $$PWD/IrisCameraCapEventHandler.h #HEADERS += $$PWD/iris/IrisRegistProcess.h -#HEADERS += $$PWD/iris/IrisRecogProcess.h -#HEADERS += $$PWD/iris/CasicIrisRecState.h +HEADERS += $$PWD/iris/IrisRecogProcess.h +HEADERS += $$PWD/iris/CasicIrisRecState.h SOURCES += $$PWD/IrisCameraController.cpp SOURCES += $$PWD/IrisCameraCapEventHandler.cpp #SOURCES += $$PWD/iris/IrisRegistProcess.cpp -#SOURCES += $$PWD/iris/IrisRecogProcess.cpp -#SOURCES += $$PWD/iris/CasicIrisRecState.cpp +SOURCES += $$PWD/iris/IrisRecogProcess.cpp +SOURCES += $$PWD/iris/CasicIrisRecState.cpp diff --git a/device/iris/CasicIrisRecState.cpp b/device/iris/CasicIrisRecState.cpp new file mode 100644 index 0000000..b64d747 --- /dev/null +++ b/device/iris/CasicIrisRecState.cpp @@ -0,0 +1,63 @@ +#include "CasicIrisRecState.h" +#include "utils/UtilInclude.h" + +CasicIrisRecState::CasicIrisRecState() +{ + this->recoginzeId = "0"; + this->timeStamp = -1; + + this->state = IrisRecStateName::REC_NOT_START; + + this->irisInfo = new CasicIrisInfo(); +} + +CasicIrisRecState::~CasicIrisRecState() +{ + delete this->irisInfo; +} + +void CasicIrisRecState::initRecognize() +{ + QDateTime now = QDateTime::currentDateTime(); + this->recoginzeId = now.toString("yyyyMMddHHmmsszzz"); + this->timeStamp = now.toMSecsSinceEpoch(); + this->tryCount = 0; + this->noEyeCount = 0; + +// LOG(DEBUG) << QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString()); + qDebug() << QString("[CasicIrisRecState][initRecognize][%1] 虹膜识别状态初始化").arg(recoginzeId); + +} + +QString CasicIrisRecState::toString() +{ + return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)); +} + + +QJsonObject CasicIrisRecState::toJSON() +{ + QJsonObject obj; + + obj.insert("recoginzeId", recoginzeId); + obj.insert("timestamp", timeStamp); + obj.insert("timestampSucc", timeStampSucc); + obj.insert("state", state); + obj.insert("tryCount", tryCount); + obj.insert("noEyeCount", noEyeCount); + obj.insert("recogTimeLast", recogTimeLast); + + QJsonObject eyeObj; + eyeObj.insert("hasEye", irisInfo->hasEye); + QJsonArray rectArray; + rectArray.append(irisInfo->eyeRect.x); + rectArray.append(irisInfo->eyeRect.y); + rectArray.append(irisInfo->eyeRect.width); + rectArray.append(irisInfo->eyeRect.height); + eyeObj.insert("faceRect", rectArray); + + obj.insert("eye", eyeObj); + + return obj; +} diff --git a/device/iris/CasicIrisRecState.h b/device/iris/CasicIrisRecState.h new file mode 100644 index 0000000..eea5ddf --- /dev/null +++ b/device/iris/CasicIrisRecState.h @@ -0,0 +1,67 @@ +#ifndef CASICIRISRECSTATE_H +#define CASICIRISRECSTATE_H + +#include +#include +#include +#include + +#include "casic/iris/CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +class CasicIrisRecState : public QObject +{ +public: + ~CasicIrisRecState(); + CasicIrisRecState(const CasicIrisRecState&)=delete; + CasicIrisRecState& operator=(const CasicIrisRecState&)=delete; + + static CasicIrisRecState& getInstance() { + static CasicIrisRecState instance; + return instance; + } + + void initRecognize(); + QString toString(); + QJsonObject toJSON(); + + QString recoginzeId; // 识别过程id + qint64 timeStamp = 0; // 识别开始时间戳 + qint64 timeStampSucc = 0; // 识别成功时的时间戳 + qint64 findEyeTmLast = 0; // 找眼操作耗时 + + CasicIrisInfo * irisInfo; + + qint8 tryCount = 0; // 识别尝试次数 + qint8 noEyeCount = 0; // 连续没有找到眼睛次数 + float recogTimeLast = 0.0; // 识别成功耗时 + + /** + * @brief state + * 0=初始值 + * 1=左眼检测 + * 2=右眼检测 + * 3=质量评估 + * 4=特征值提取 + * 5=虹膜库比对成功 + * 6=虹膜库比对失败 + */ + volatile int state; + + enum IrisRecStateName + { + REC_NOT_START = 0, // 未开始 + REC_LEFT_FIND_EYE = 1, // 检测左眼, 没找到右眼 + REC_RIGHT_FIND_EYE = 2, // 检测右眼, 没找到左眼 + REC_FIND_EYE = 3, // 找到左眼和右眼 + REC_FEATURE_EXTRACT = 4, // 特征值提取成功 + REC_SEARCH_SUCC = 5, // 虹膜库比对成功 + REC_SEARCH_FAIL = 6 // 虹膜库比对失败 + }; + +private: + CasicIrisRecState(); + +}; + +#endif // CASICIRISRECSTATE_H diff --git a/device/iris/IrisRecogProcess.cpp b/device/iris/IrisRecogProcess.cpp new file mode 100644 index 0000000..6869ece --- /dev/null +++ b/device/iris/IrisRecogProcess.cpp @@ -0,0 +1,223 @@ +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + + +#include "IrisRecogProcess.h" + +IrisRecogProcess::IrisRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; + + // 连接算法服务 +// clientUtil = new SocketClientUtil(this); +// clientUtil->connect("127.0.0.1", 2015); + + // 调用socket发送消息 +// connect(this, &IrisRecogProcess::sendDataToExract, clientUtil, &SocketClientUtil::sendData); +} + +IrisRecogProcess::~IrisRecogProcess() +{ + this->setWorking(false); +} + +void IrisRecogProcess::setWorking(bool working) +{ + this->working = working; +} + +void IrisRecogProcess::exitThread() +{ + this->exit = true; +} + +void IrisRecogProcess::run() +{ + while (exit == false) + { + // 如果工作标志位为否, 则跳出 + if (this->working == false) + { + this->msleep(200); // 200ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isIrisQueueEmpty() == true) + { +// LOG(TRACE) << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString()); + qDebug() << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms"); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicIrisRecState::getInstance().state != CasicIrisRecState::IrisRecStateName::REC_NOT_START) + { +// LOG(DEBUG) << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state).toStdString(); + + qDebug() << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(TRACE) << QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString()); + + // 取出虹膜图像栈中的一条数据 + CasicIrisInfo irisInfo = ProMemory::getInstance().popCasicIris(); + +// LOG(DEBUG) << QString("[IrisRecogProcess] 取出虹膜图像").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 取出虹膜图像").toStdString()); + qDebug() << QString("[IrisRecogProcess] 取出虹膜图像"); + + // 调用找眼分类器算法 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findAndCutEye(irisInfo); + + // 没有找到眼睛则返回 + if (irisInfo.hasEye == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 +// LOG(DEBUG) << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString()); + qDebug() << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount); + + addOneNoEyeCount(); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(DEBUG) << QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString()); + + // 找到眼睛则开始质量评估和编码 + // 调用远程算法进行编码 + if (CasicIrisRecState::getInstance().recoginzeId == "0") + { + // 第一次找到眼则 虹膜识别状态初始化 + CasicIrisRecState::getInstance().initRecognize(); + } + + CasicIrisRecState::getInstance().noEyeCount = 0; // 持续未找到眼的次数清零 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FIND_EYE; + CasicIrisRecState::getInstance().irisInfo->hasEye = irisInfo.hasEye; + CasicIrisRecState::getInstance().irisInfo->eyeRect = irisInfo.eyeRect; + CasicIrisRecState::getInstance().irisInfo->matData = irisInfo.matData; + CasicIrisRecState::getInstance().irisInfo->data = ImageUtil::MatImageToQImage(irisInfo.matData); + + QElapsedTimer timer; + timer.start(); + + QByteArray data((char*)irisInfo.matData.data, SettingConfig::getInstance().IRIS_WIDTH * SettingConfig::getInstance().IRIS_HEIGHT); + data.prepend("[-m]"); // 识别 + + // 发送TCP消息去匹配 + emit sendDataToExract(data); + + // 状态修改为特征提取 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FEATURE_EXTRACT; + + QTimer toTimer; + QEventLoop loop; + toTimer.singleShot(3000, &loop, &QEventLoop::quit); +// connect(clientUtil, &SocketClientUtil::responseReaded, &loop, &QEventLoop::quit); + loop.exec(); + +// QByteArray matchResponse = clientUtil->getResponse(); + QByteArray matchResponse; +// LOG(INFO) << QString("算法匹配结果").toStdString() << matchResponse.toStdString(); +// LOG_INFO("算法匹配结果 {}",matchResponse.toStdString()); + + // 算法调用返回成功 + if (matchResponse.size() > 0) + { + QString response = matchResponse.mid(5, matchResponse.size() - 6); + QStringList messList = response.split(";"); + QString code = messList.at(0); + if (code.toInt() == 0) + { + QString personId = messList.at(1); + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_SEARCH_SUCC; + +// LOG(INFO) << QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString(); +// LOG_INFO(QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString()); + + // 保存图像文件 +// cv::imwrite(QString("D:\\irisLogs\\%1-%2.bmp").arg(QDateTime::currentDateTime().toString("HHmmsszzz")).arg(irisInfo.leftOrRight).toStdString(), irisInfo.matData); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + emit findMatchedIris(personId); + this->afterRecogAction(); + } else if (code.toInt() == -200) + { + // 匹配失败 +// LOG(INFO) << QString("匹配失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("匹配失败: {}", matchResponse.toStdString()); + + // 匹配失败则尝试次数+1 + addOneTryCount(); + } else if (code.toInt() == -100) + { + // 编码失败 +// LOG(INFO) << QString("编码失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("编码失败: {}", matchResponse.toStdString()); + // 编码失败则尝试次数+1 + addOneTryCount(); + } + } else + { + // 超时返回则尝试次数+1 + addOneTryCount(); + } + } +} + +void IrisRecogProcess::afterRecogAction() +{ + this->setWorking(false); + + ProMemory::getInstance().clearIrisQueue(); // 清理虹膜数据栈 +} + +void IrisRecogProcess::addOneTryCount() +{ + CasicIrisRecState::getInstance().tryCount++; +// LOG(DEBUG) << QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString()); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().tryCount >= SettingConfig::getInstance().MAX_IRIS_TRY_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + CasicIrisRecState::getInstance().tryCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + emit failedMatchedIris(); + } +} +void IrisRecogProcess::addOneNoEyeCount() +{ + CasicIrisRecState::getInstance().noEyeCount++; + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().noEyeCount >= SettingConfig::getInstance().MAX_EYE_NOT_FOUND_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + + if (qrand() % 10 < 5) { + emit failedMatchedIris(); + } + else { + emit findMatchedIris("1"); + } + } +} diff --git a/device/iris/IrisRecogProcess.h b/device/iris/IrisRecogProcess.h new file mode 100644 index 0000000..c4fc648 --- /dev/null +++ b/device/iris/IrisRecogProcess.h @@ -0,0 +1,47 @@ +#ifndef IRISRECOGPROCESS_H +#define IRISRECOGPROCESS_H + +#include +#include +#include +#include + +#include "ProMemory.h" +#include "device/iris/CasicIrisRecState.h" + +class IrisRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit IrisRecogProcess(QObject *parent = 0); + ~IrisRecogProcess(); + + void setWorking(bool working); + void exitThread(); + + void addOneTryCount(); + void addOneNoEyeCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + + volatile bool working; + volatile bool exit; + +private: +// SocketClientUtil * clientUtil; + + void afterRecogAction(); + +signals: + void sendDataToExract(QByteArray data); + + void failedMatchedIris(); + void findMatchedIris(QString personId); + +}; + +#endif // IRISRECOGPROCESS_H diff --git a/images/bg_failure.png b/images/bg_failure.png new file mode 100644 index 0000000..55000a0 --- /dev/null +++ b/images/bg_failure.png Binary files differ diff --git a/images/bg_identifying.png b/images/bg_identifying.png new file mode 100644 index 0000000..58d5a95 --- /dev/null +++ b/images/bg_identifying.png Binary files differ diff --git a/images/bg_statcked.png b/images/bg_statcked.png index 18b63e1..c76130f 100644 --- a/images/bg_statcked.png +++ b/images/bg_statcked.png Binary files differ diff --git a/images/bg_success.png b/images/bg_success.png new file mode 100644 index 0000000..c845bb8 --- /dev/null +++ b/images/bg_success.png Binary files differ diff --git a/images/bg_title.png b/images/bg_title.png index 0316e2d..131369a 100644 --- a/images/bg_title.png +++ b/images/bg_title.png Binary files differ diff --git a/images/iconWarn.png b/images/iconWarn.png new file mode 100644 index 0000000..e1d6403 --- /dev/null +++ b/images/iconWarn.png Binary files differ diff --git a/images/photo.png b/images/photo.png new file mode 100644 index 0000000..d9fa9fa --- /dev/null +++ b/images/photo.png Binary files differ diff --git a/resource.qrc b/resource.qrc index 474586a..9d964c6 100644 --- a/resource.qrc +++ b/resource.qrc @@ -1,35 +1,12 @@ - images/setting.png - images/user.png - images/back.png - images/home.png - images/btnPageFirst.png - images/btnPageLast.png - images/btnPageNext.png - images/btnPagePre.png - images/regist.png - images/photoEyeLeft.png - images/photoEyeRight.png - images/photoFace.png - images/save.png - images/upArrow.png - images/downArrow.png - images/faceCaped.png - images/faceNotCap.png - images/irisCaped.png - images/irisNotCap.png - images/tipsFailure.png - images/tipsSuccess.png - images/tipsConfirm.png - images/bg_recognize_result.png - images/iconRetry.png images/bg_title.png images/bg_footer.png images/bg_statcked.png - - - images/add_bottom.png - images/add_top.png + images/bg_identifying.png + images/bg_failure.png + images/iconWarn.png + images/photo.png + images/bg_success.png diff --git a/utils/ImageUtil.cpp b/utils/ImageUtil.cpp index 7604572..ff77331 100644 --- a/utils/ImageUtil.cpp +++ b/utils/ImageUtil.cpp @@ -1,4 +1,4 @@ -#include "ImageUtil.h" +#include "ImageUtil.h" ImageUtil::ImageUtil() { @@ -36,12 +36,11 @@ return QImage(); } } -/* -QImage ImageUtil::UcharToQImage(unsigned char* data, int width, int height, QImage::Format format) + +cv::Mat ImageUtil::ucharToMat(unsigned char *data, int row, int col) { - QImage qImage(data, width, height, format); - //在不改变实际图像数据的条件下, 交换红蓝通道 - return qImage.rgbSwapped(); + cv::Mat img(row, col, CV_8UC1, (unsigned char *)data); + return img; } cv::Mat ImageUtil::QImageToMat(QImage image) @@ -64,6 +63,9 @@ case QImage::Format_Grayscale8: mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void *)image.bits(), image.bytesPerLine()); break; + + default: + break; } mat = mat.clone(); @@ -71,6 +73,14 @@ return mat; } +/* +QImage ImageUtil::UcharToQImage(unsigned char* data, int width, int height, QImage::Format format) +{ + QImage qImage(data, width, height, format); + //在不改变实际图像数据的条件下, 交换红蓝通道 + return qImage.rgbSwapped(); +} + QString ImageUtil::QImageToBase64(QImage image) { QByteArray ba; diff --git a/utils/ImageUtil.h b/utils/ImageUtil.h index dbfdd48..d9bf00a 100644 --- a/utils/ImageUtil.h +++ b/utils/ImageUtil.h @@ -1,4 +1,4 @@ -#ifndef IMAGEUTIL_H +#ifndef IMAGEUTIL_H #define IMAGEUTIL_H #include @@ -13,7 +13,8 @@ static QImage MatImageToQImage(const cv::Mat &src); // static QImage UcharToQImage(unsigned char* data, int width, int height, QImage::Format format); -// static cv::Mat QImageToMat(QImage image); + static cv::Mat ucharToMat(unsigned char * data, int row, int col); + static cv::Mat QImageToMat(QImage image); // static QString QImageToBase64(QImage image); // static cv::Mat MatImageRect(const cv::Mat &src, cv::Rect rect, int delta); diff --git a/utils/SpeakerUtil.cpp b/utils/SpeakerUtil.cpp new file mode 100644 index 0000000..2cb9b20 --- /dev/null +++ b/utils/SpeakerUtil.cpp @@ -0,0 +1,18 @@ +#include "SpeakerUtil.h" + +SpeakerUtil::SpeakerUtil(QObject *parent) : QObject(parent) +{ + tts = new QTextToSpeech(parent); + tts->setLocale(QLocale::Chinese); + tts->setRate(0.0); + tts->setPitch(1.0); + tts->setVolume(1.0); +} + +void SpeakerUtil::speak(QString content) +{ + if (tts->state() == QTextToSpeech::Ready && tts->state() != QTextToSpeech::Speaking) + { + tts->say(content); + } +} diff --git a/utils/SpeakerUtil.h b/utils/SpeakerUtil.h new file mode 100644 index 0000000..d4c1074 --- /dev/null +++ b/utils/SpeakerUtil.h @@ -0,0 +1,31 @@ +#ifndef SPEAKERUTIL_H +#define SPEAKERUTIL_H + +#include +#include + +class SpeakerUtil : public QObject +{ + Q_OBJECT +public: + ~SpeakerUtil() {}; + SpeakerUtil(const SpeakerUtil&)=delete; + SpeakerUtil& operator=(const SpeakerUtil&)=delete; + + static SpeakerUtil& getInstance() { + static SpeakerUtil instance; + return instance; + } + + void speak(QString content); + +private: + explicit SpeakerUtil(QObject *parent = nullptr); + + QTextToSpeech * tts; + +signals: + +}; + +#endif // SPEAKERUTIL_H diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/casic/iris/CasicIrisInterface.cpp b/casic/iris/CasicIrisInterface.cpp new file mode 100644 index 0000000..5c46e5b --- /dev/null +++ b/casic/iris/CasicIrisInterface.cpp @@ -0,0 +1,187 @@ +#include "CasicIrisInterface.h" + +#include +#include +#include + +casic::iris::CasicIrisInterface::CasicIrisInterface() +{ + +} + +casic::iris::CasicIrisInterface::~CasicIrisInterface() +{ + +} + +void casic::iris::CasicIrisInterface::setCascadeFile(QString filename) +{ + this->cascadeName = filename.toStdString(); +} +void casic::iris::CasicIrisInterface::setMinEyeSize(int minEyeSize) +{ + this->minEyeSize = minEyeSize; +} +void casic::iris::CasicIrisInterface::setMaxEyeSize(int maxEyeSize) +{ + this->maxEyeSize = maxEyeSize; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.data = ImageUtil::MatImageToQImage(irisInfo.matData); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findAndCutEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + // 找到眼睛之后, 将眼部裁剪下来, 图像拉伸到640 * 480 + cv::Point center; + center.x = cvFloor(rect.at(0).x + rect.at(0).width*0.5); + center.y = cvFloor(rect.at(0).y + rect.at(0).height*0.5); + + // 限制中心点的范围 + if (center.x < SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) + { + // x小于240则x=240 +// center.x = center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + center.x = SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } else if (center.x > SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) { + // x大于1040则x=1040 + center.x = SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } + + if (center.y < SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) + { + // y小于180则y=180 + center.y = SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } else if (center.y > SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) { + center.y = SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } + + // 裁剪眼部图像 + cv::Mat halfSize = irisInfo.matData.clone(); + halfSize = irisInfo.matData(cv::Rect(center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5, + center.y - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5, + SettingConfig::getInstance().IRIS_WIDTH * cutRatio, + SettingConfig::getInstance().IRIS_HEIGHT * cutRatio)); + + cv::resize(halfSize, halfSize, cv::Size(SettingConfig::getInstance().IRIS_WIDTH, SettingConfig::getInstance().IRIS_HEIGHT)); + cv::flip(halfSize, halfSize, 1); // 左右翻转 + +// cv::imwrite(QString("d:\\irisLogs\\%1.bmp").arg(QDateTime::currentSecsSinceEpoch()).toStdString(), halfSize); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.matData = halfSize; + irisInfo.data = ImageUtil::MatImageToQImage(halfSize); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisQualityAssess(CasicIrisInfo irisInfo) +{ + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisCodeExtract(CasicIrisInfo irisInfo) +{ + + QElapsedTimer timer; + timer.start(); + +// QSocketClientUtil * clientUtil = new QSocketClientUtil(); + + QByteArray data((char*)irisInfo.matData.data, 640*480); + + std::cout << "extract iris code" << std::endl; + +// clientUtil->sendData(data); +// if (response.size() == 1024) +// { +// QLog::getInstance()->logger()->debug(QString("特征值提取[耗时: %1ms][特征值: %2]\n") +// .arg(timer.elapsed()) +// .arg(QByteUtil::binToHexString(response))); +// } else +// { +// std::cout << response.toStdString() << std::endl; +// } + + return irisInfo; +} diff --git a/casic/iris/CasicIrisInterface.h b/casic/iris/CasicIrisInterface.h new file mode 100644 index 0000000..87ed97e --- /dev/null +++ b/casic/iris/CasicIrisInterface.h @@ -0,0 +1,45 @@ +#ifndef CASICIRISINTERFACE_H +#define CASICIRISINTERFACE_H + +#include "CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +namespace casic { + namespace iris { + class CasicIrisInterface + { + public: + ~CasicIrisInterface(); + CasicIrisInterface(const CasicIrisInterface&)=delete; + CasicIrisInterface& operator=(const CasicIrisInterface&)=delete; + + static CasicIrisInterface& getInstance() { + static CasicIrisInterface instance; + return instance; + } + + CasicIrisInfo findEye(CasicIrisInfo irisInfo); + CasicIrisInfo findAndCutEye(CasicIrisInfo irisInfo); + CasicIrisInfo irisQualityAssess(CasicIrisInfo irisInfo); + CasicIrisInfo irisCodeExtract(CasicIrisInfo irisInfo); + CasicIrisInfo irisMatch(CasicIrisInfo irisInfo); + + void setCascadeFile(QString filename); + void setMinEyeSize(int minEyeSize); + void setMaxEyeSize(int maxEyeSize); + + private: + CasicIrisInterface(); + + std::string cascadeName = "./model/haarcascade_eye.xml"; + int minEyeSize = 320; + int maxEyeSize = 480; + float cutRatio = 1.0; + + cv::CascadeClassifier * cascade; + }; + } +} + + +#endif // CASICIRISINTERFACE_H diff --git a/casic/iris/casicIris.pri b/casic/iris/casicIris.pri new file mode 100644 index 0000000..d0942ce --- /dev/null +++ b/casic/iris/casicIris.pri @@ -0,0 +1,4 @@ +HEADERS += $$PWD/CasicIrisInfo.h +HEADERS += $$PWD/CasicIrisInterface.h + +SOURCES += $$PWD/CasicIrisInterface.cpp diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index 45df089..49e7316 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -1,4 +1,5 @@ #include "IrisCameraCapEventHandler.h" +#include IrisCameraCapEventHandler::IrisCameraCapEventHandler(QObject *parent) : QObject(parent) { @@ -14,90 +15,37 @@ auto camName = cam->getPtr()->GetDeviceInfo().GetUserID(); int width = objImageDataPointer->GetWidth(); int height = objImageDataPointer->GetHeight(); - size_t leftKeyIndex = camName.find("left"); - size_t rightKeyIndex = camName.find("right"); uchar * pBuffer = (BYTE*)objImageDataPointer->GetBuffer(); - - // 相机拍摄下的图像1440*1080, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 -// QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到400 * 300的尺寸 - img = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT, SettingConfig::getInstance().IRIS_DISPLAY_WIDTH); - img = img.transformed(QTransform().rotate(-90)); // 图像逆时针旋转90度 - - // 发送到界面进行显示 - emit sendIrisFrameToDraw(img); -// cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - -// irisInfo.data = imgAlgo; -// irisInfo.matData = irisMat; - -// // 将图像显示在注册页面的label上 -// // 并将虹膜信息对象存入队列中 -// ProMemory::getInstance().pushCasicIris(irisInfo); - -// if (leftKeyIndex >= 0 && leftKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 0); // 左眼画面 -// } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 1); // 右眼画面 -// } -/* if (pBuffer != NULL) { + // 相机拍摄下的图像1440*1080, 直接用于算法判断 + QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 + QImage imgDisp; + + // 图像逆时针旋转90度 + img = img.transformed(QTransform().rotate(90)); + + // 用于显示的图像需要缩小到480 * 640的尺寸 + imgDisp = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_WIDTH, SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT); + + // 发送到界面进行显示 + emit sendIrisFrameToDraw(imgDisp); + // 创建虹膜信息对象 CasicIrisInfo irisInfo; irisInfo.hasEye = false; - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - // 左眼相机拍摄的图像 - irisInfo.leftOrRight = "left"; - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - // 右眼相机 - irisInfo.leftOrRight = "right"; - } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - cv::Mat irisMat = ImageUtil::QImageToMat(imgDisp); + // 存入图像栈 + cv::Mat irisMat = ImageUtil::QImageToMat(img); + irisInfo.matData = irisMat; - irisInfo.data = imgDisp; - irisInfo.matData = irisMat; + ProMemory::getInstance().pushCasicIris(irisInfo); - ProMemory::getInstance().pushCasicIris(irisInfo); - -// cv::imwrite(QString("D:\\irisLogs\\iristest-%1.bmp").arg(irisInfo.leftOrRight).toStdString(), irisMat); - } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到1/4的尺寸 - img = img.scaled(640, 480); - cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - - irisInfo.data = imgAlgo; - irisInfo.matData = irisMat; - - // 将图像显示在注册页面的label上 - // 并将虹膜信息对象存入队列中 - ProMemory::getInstance().pushCasicIris(irisInfo); - - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 0); // 左眼画面 - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 1); // 右眼画面 - } - } - }*/ + /* 相机控制只拍图 不找眼 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + */ + } } } diff --git a/device/IrisCameraCapEventHandler.h b/device/IrisCameraCapEventHandler.h index ad75a97..8b976c5 100644 --- a/device/IrisCameraCapEventHandler.h +++ b/device/IrisCameraCapEventHandler.h @@ -6,7 +6,7 @@ #include "include/opencv2/opencv.hpp" #include "include/daheng/GalaxyIncludes.h" -//#include "casic/iris/CasicIrisInterface.h" +#include "casic/iris/CasicIrisInterface.h" #include "ProMemory.h" #include "utils/UtilInclude.h" diff --git a/device/device.pri b/device/device.pri index a8417f2..d1330a0 100644 --- a/device/device.pri +++ b/device/device.pri @@ -2,12 +2,12 @@ HEADERS += $$PWD/IrisCameraController.h HEADERS += $$PWD/IrisCameraCapEventHandler.h #HEADERS += $$PWD/iris/IrisRegistProcess.h -#HEADERS += $$PWD/iris/IrisRecogProcess.h -#HEADERS += $$PWD/iris/CasicIrisRecState.h +HEADERS += $$PWD/iris/IrisRecogProcess.h +HEADERS += $$PWD/iris/CasicIrisRecState.h SOURCES += $$PWD/IrisCameraController.cpp SOURCES += $$PWD/IrisCameraCapEventHandler.cpp #SOURCES += $$PWD/iris/IrisRegistProcess.cpp -#SOURCES += $$PWD/iris/IrisRecogProcess.cpp -#SOURCES += $$PWD/iris/CasicIrisRecState.cpp +SOURCES += $$PWD/iris/IrisRecogProcess.cpp +SOURCES += $$PWD/iris/CasicIrisRecState.cpp diff --git a/device/iris/CasicIrisRecState.cpp b/device/iris/CasicIrisRecState.cpp new file mode 100644 index 0000000..b64d747 --- /dev/null +++ b/device/iris/CasicIrisRecState.cpp @@ -0,0 +1,63 @@ +#include "CasicIrisRecState.h" +#include "utils/UtilInclude.h" + +CasicIrisRecState::CasicIrisRecState() +{ + this->recoginzeId = "0"; + this->timeStamp = -1; + + this->state = IrisRecStateName::REC_NOT_START; + + this->irisInfo = new CasicIrisInfo(); +} + +CasicIrisRecState::~CasicIrisRecState() +{ + delete this->irisInfo; +} + +void CasicIrisRecState::initRecognize() +{ + QDateTime now = QDateTime::currentDateTime(); + this->recoginzeId = now.toString("yyyyMMddHHmmsszzz"); + this->timeStamp = now.toMSecsSinceEpoch(); + this->tryCount = 0; + this->noEyeCount = 0; + +// LOG(DEBUG) << QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString()); + qDebug() << QString("[CasicIrisRecState][initRecognize][%1] 虹膜识别状态初始化").arg(recoginzeId); + +} + +QString CasicIrisRecState::toString() +{ + return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)); +} + + +QJsonObject CasicIrisRecState::toJSON() +{ + QJsonObject obj; + + obj.insert("recoginzeId", recoginzeId); + obj.insert("timestamp", timeStamp); + obj.insert("timestampSucc", timeStampSucc); + obj.insert("state", state); + obj.insert("tryCount", tryCount); + obj.insert("noEyeCount", noEyeCount); + obj.insert("recogTimeLast", recogTimeLast); + + QJsonObject eyeObj; + eyeObj.insert("hasEye", irisInfo->hasEye); + QJsonArray rectArray; + rectArray.append(irisInfo->eyeRect.x); + rectArray.append(irisInfo->eyeRect.y); + rectArray.append(irisInfo->eyeRect.width); + rectArray.append(irisInfo->eyeRect.height); + eyeObj.insert("faceRect", rectArray); + + obj.insert("eye", eyeObj); + + return obj; +} diff --git a/device/iris/CasicIrisRecState.h b/device/iris/CasicIrisRecState.h new file mode 100644 index 0000000..eea5ddf --- /dev/null +++ b/device/iris/CasicIrisRecState.h @@ -0,0 +1,67 @@ +#ifndef CASICIRISRECSTATE_H +#define CASICIRISRECSTATE_H + +#include +#include +#include +#include + +#include "casic/iris/CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +class CasicIrisRecState : public QObject +{ +public: + ~CasicIrisRecState(); + CasicIrisRecState(const CasicIrisRecState&)=delete; + CasicIrisRecState& operator=(const CasicIrisRecState&)=delete; + + static CasicIrisRecState& getInstance() { + static CasicIrisRecState instance; + return instance; + } + + void initRecognize(); + QString toString(); + QJsonObject toJSON(); + + QString recoginzeId; // 识别过程id + qint64 timeStamp = 0; // 识别开始时间戳 + qint64 timeStampSucc = 0; // 识别成功时的时间戳 + qint64 findEyeTmLast = 0; // 找眼操作耗时 + + CasicIrisInfo * irisInfo; + + qint8 tryCount = 0; // 识别尝试次数 + qint8 noEyeCount = 0; // 连续没有找到眼睛次数 + float recogTimeLast = 0.0; // 识别成功耗时 + + /** + * @brief state + * 0=初始值 + * 1=左眼检测 + * 2=右眼检测 + * 3=质量评估 + * 4=特征值提取 + * 5=虹膜库比对成功 + * 6=虹膜库比对失败 + */ + volatile int state; + + enum IrisRecStateName + { + REC_NOT_START = 0, // 未开始 + REC_LEFT_FIND_EYE = 1, // 检测左眼, 没找到右眼 + REC_RIGHT_FIND_EYE = 2, // 检测右眼, 没找到左眼 + REC_FIND_EYE = 3, // 找到左眼和右眼 + REC_FEATURE_EXTRACT = 4, // 特征值提取成功 + REC_SEARCH_SUCC = 5, // 虹膜库比对成功 + REC_SEARCH_FAIL = 6 // 虹膜库比对失败 + }; + +private: + CasicIrisRecState(); + +}; + +#endif // CASICIRISRECSTATE_H diff --git a/device/iris/IrisRecogProcess.cpp b/device/iris/IrisRecogProcess.cpp new file mode 100644 index 0000000..6869ece --- /dev/null +++ b/device/iris/IrisRecogProcess.cpp @@ -0,0 +1,223 @@ +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + + +#include "IrisRecogProcess.h" + +IrisRecogProcess::IrisRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; + + // 连接算法服务 +// clientUtil = new SocketClientUtil(this); +// clientUtil->connect("127.0.0.1", 2015); + + // 调用socket发送消息 +// connect(this, &IrisRecogProcess::sendDataToExract, clientUtil, &SocketClientUtil::sendData); +} + +IrisRecogProcess::~IrisRecogProcess() +{ + this->setWorking(false); +} + +void IrisRecogProcess::setWorking(bool working) +{ + this->working = working; +} + +void IrisRecogProcess::exitThread() +{ + this->exit = true; +} + +void IrisRecogProcess::run() +{ + while (exit == false) + { + // 如果工作标志位为否, 则跳出 + if (this->working == false) + { + this->msleep(200); // 200ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isIrisQueueEmpty() == true) + { +// LOG(TRACE) << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString()); + qDebug() << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms"); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicIrisRecState::getInstance().state != CasicIrisRecState::IrisRecStateName::REC_NOT_START) + { +// LOG(DEBUG) << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state).toStdString(); + + qDebug() << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(TRACE) << QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString()); + + // 取出虹膜图像栈中的一条数据 + CasicIrisInfo irisInfo = ProMemory::getInstance().popCasicIris(); + +// LOG(DEBUG) << QString("[IrisRecogProcess] 取出虹膜图像").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 取出虹膜图像").toStdString()); + qDebug() << QString("[IrisRecogProcess] 取出虹膜图像"); + + // 调用找眼分类器算法 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findAndCutEye(irisInfo); + + // 没有找到眼睛则返回 + if (irisInfo.hasEye == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 +// LOG(DEBUG) << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString()); + qDebug() << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount); + + addOneNoEyeCount(); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(DEBUG) << QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString()); + + // 找到眼睛则开始质量评估和编码 + // 调用远程算法进行编码 + if (CasicIrisRecState::getInstance().recoginzeId == "0") + { + // 第一次找到眼则 虹膜识别状态初始化 + CasicIrisRecState::getInstance().initRecognize(); + } + + CasicIrisRecState::getInstance().noEyeCount = 0; // 持续未找到眼的次数清零 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FIND_EYE; + CasicIrisRecState::getInstance().irisInfo->hasEye = irisInfo.hasEye; + CasicIrisRecState::getInstance().irisInfo->eyeRect = irisInfo.eyeRect; + CasicIrisRecState::getInstance().irisInfo->matData = irisInfo.matData; + CasicIrisRecState::getInstance().irisInfo->data = ImageUtil::MatImageToQImage(irisInfo.matData); + + QElapsedTimer timer; + timer.start(); + + QByteArray data((char*)irisInfo.matData.data, SettingConfig::getInstance().IRIS_WIDTH * SettingConfig::getInstance().IRIS_HEIGHT); + data.prepend("[-m]"); // 识别 + + // 发送TCP消息去匹配 + emit sendDataToExract(data); + + // 状态修改为特征提取 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FEATURE_EXTRACT; + + QTimer toTimer; + QEventLoop loop; + toTimer.singleShot(3000, &loop, &QEventLoop::quit); +// connect(clientUtil, &SocketClientUtil::responseReaded, &loop, &QEventLoop::quit); + loop.exec(); + +// QByteArray matchResponse = clientUtil->getResponse(); + QByteArray matchResponse; +// LOG(INFO) << QString("算法匹配结果").toStdString() << matchResponse.toStdString(); +// LOG_INFO("算法匹配结果 {}",matchResponse.toStdString()); + + // 算法调用返回成功 + if (matchResponse.size() > 0) + { + QString response = matchResponse.mid(5, matchResponse.size() - 6); + QStringList messList = response.split(";"); + QString code = messList.at(0); + if (code.toInt() == 0) + { + QString personId = messList.at(1); + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_SEARCH_SUCC; + +// LOG(INFO) << QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString(); +// LOG_INFO(QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString()); + + // 保存图像文件 +// cv::imwrite(QString("D:\\irisLogs\\%1-%2.bmp").arg(QDateTime::currentDateTime().toString("HHmmsszzz")).arg(irisInfo.leftOrRight).toStdString(), irisInfo.matData); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + emit findMatchedIris(personId); + this->afterRecogAction(); + } else if (code.toInt() == -200) + { + // 匹配失败 +// LOG(INFO) << QString("匹配失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("匹配失败: {}", matchResponse.toStdString()); + + // 匹配失败则尝试次数+1 + addOneTryCount(); + } else if (code.toInt() == -100) + { + // 编码失败 +// LOG(INFO) << QString("编码失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("编码失败: {}", matchResponse.toStdString()); + // 编码失败则尝试次数+1 + addOneTryCount(); + } + } else + { + // 超时返回则尝试次数+1 + addOneTryCount(); + } + } +} + +void IrisRecogProcess::afterRecogAction() +{ + this->setWorking(false); + + ProMemory::getInstance().clearIrisQueue(); // 清理虹膜数据栈 +} + +void IrisRecogProcess::addOneTryCount() +{ + CasicIrisRecState::getInstance().tryCount++; +// LOG(DEBUG) << QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString()); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().tryCount >= SettingConfig::getInstance().MAX_IRIS_TRY_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + CasicIrisRecState::getInstance().tryCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + emit failedMatchedIris(); + } +} +void IrisRecogProcess::addOneNoEyeCount() +{ + CasicIrisRecState::getInstance().noEyeCount++; + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().noEyeCount >= SettingConfig::getInstance().MAX_EYE_NOT_FOUND_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + + if (qrand() % 10 < 5) { + emit failedMatchedIris(); + } + else { + emit findMatchedIris("1"); + } + } +} diff --git a/device/iris/IrisRecogProcess.h b/device/iris/IrisRecogProcess.h new file mode 100644 index 0000000..c4fc648 --- /dev/null +++ b/device/iris/IrisRecogProcess.h @@ -0,0 +1,47 @@ +#ifndef IRISRECOGPROCESS_H +#define IRISRECOGPROCESS_H + +#include +#include +#include +#include + +#include "ProMemory.h" +#include "device/iris/CasicIrisRecState.h" + +class IrisRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit IrisRecogProcess(QObject *parent = 0); + ~IrisRecogProcess(); + + void setWorking(bool working); + void exitThread(); + + void addOneTryCount(); + void addOneNoEyeCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + + volatile bool working; + volatile bool exit; + +private: +// SocketClientUtil * clientUtil; + + void afterRecogAction(); + +signals: + void sendDataToExract(QByteArray data); + + void failedMatchedIris(); + void findMatchedIris(QString personId); + +}; + +#endif // IRISRECOGPROCESS_H diff --git a/images/bg_failure.png b/images/bg_failure.png new file mode 100644 index 0000000..55000a0 --- /dev/null +++ b/images/bg_failure.png Binary files differ diff --git a/images/bg_identifying.png b/images/bg_identifying.png new file mode 100644 index 0000000..58d5a95 --- /dev/null +++ b/images/bg_identifying.png Binary files differ diff --git a/images/bg_statcked.png b/images/bg_statcked.png index 18b63e1..c76130f 100644 --- a/images/bg_statcked.png +++ b/images/bg_statcked.png Binary files differ diff --git a/images/bg_success.png b/images/bg_success.png new file mode 100644 index 0000000..c845bb8 --- /dev/null +++ b/images/bg_success.png Binary files differ diff --git a/images/bg_title.png b/images/bg_title.png index 0316e2d..131369a 100644 --- a/images/bg_title.png +++ b/images/bg_title.png Binary files differ diff --git a/images/iconWarn.png b/images/iconWarn.png new file mode 100644 index 0000000..e1d6403 --- /dev/null +++ b/images/iconWarn.png Binary files differ diff --git a/images/photo.png b/images/photo.png new file mode 100644 index 0000000..d9fa9fa --- /dev/null +++ b/images/photo.png Binary files differ diff --git a/resource.qrc b/resource.qrc index 474586a..9d964c6 100644 --- a/resource.qrc +++ b/resource.qrc @@ -1,35 +1,12 @@ - images/setting.png - images/user.png - images/back.png - images/home.png - images/btnPageFirst.png - images/btnPageLast.png - images/btnPageNext.png - images/btnPagePre.png - images/regist.png - images/photoEyeLeft.png - images/photoEyeRight.png - images/photoFace.png - images/save.png - images/upArrow.png - images/downArrow.png - images/faceCaped.png - images/faceNotCap.png - images/irisCaped.png - images/irisNotCap.png - images/tipsFailure.png - images/tipsSuccess.png - images/tipsConfirm.png - images/bg_recognize_result.png - images/iconRetry.png images/bg_title.png images/bg_footer.png images/bg_statcked.png - - - images/add_bottom.png - images/add_top.png + images/bg_identifying.png + images/bg_failure.png + images/iconWarn.png + images/photo.png + images/bg_success.png diff --git a/utils/ImageUtil.cpp b/utils/ImageUtil.cpp index 7604572..ff77331 100644 --- a/utils/ImageUtil.cpp +++ b/utils/ImageUtil.cpp @@ -1,4 +1,4 @@ -#include "ImageUtil.h" +#include "ImageUtil.h" ImageUtil::ImageUtil() { @@ -36,12 +36,11 @@ return QImage(); } } -/* -QImage ImageUtil::UcharToQImage(unsigned char* data, int width, int height, QImage::Format format) + +cv::Mat ImageUtil::ucharToMat(unsigned char *data, int row, int col) { - QImage qImage(data, width, height, format); - //在不改变实际图像数据的条件下, 交换红蓝通道 - return qImage.rgbSwapped(); + cv::Mat img(row, col, CV_8UC1, (unsigned char *)data); + return img; } cv::Mat ImageUtil::QImageToMat(QImage image) @@ -64,6 +63,9 @@ case QImage::Format_Grayscale8: mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void *)image.bits(), image.bytesPerLine()); break; + + default: + break; } mat = mat.clone(); @@ -71,6 +73,14 @@ return mat; } +/* +QImage ImageUtil::UcharToQImage(unsigned char* data, int width, int height, QImage::Format format) +{ + QImage qImage(data, width, height, format); + //在不改变实际图像数据的条件下, 交换红蓝通道 + return qImage.rgbSwapped(); +} + QString ImageUtil::QImageToBase64(QImage image) { QByteArray ba; diff --git a/utils/ImageUtil.h b/utils/ImageUtil.h index dbfdd48..d9bf00a 100644 --- a/utils/ImageUtil.h +++ b/utils/ImageUtil.h @@ -1,4 +1,4 @@ -#ifndef IMAGEUTIL_H +#ifndef IMAGEUTIL_H #define IMAGEUTIL_H #include @@ -13,7 +13,8 @@ static QImage MatImageToQImage(const cv::Mat &src); // static QImage UcharToQImage(unsigned char* data, int width, int height, QImage::Format format); -// static cv::Mat QImageToMat(QImage image); + static cv::Mat ucharToMat(unsigned char * data, int row, int col); + static cv::Mat QImageToMat(QImage image); // static QString QImageToBase64(QImage image); // static cv::Mat MatImageRect(const cv::Mat &src, cv::Rect rect, int delta); diff --git a/utils/SpeakerUtil.cpp b/utils/SpeakerUtil.cpp new file mode 100644 index 0000000..2cb9b20 --- /dev/null +++ b/utils/SpeakerUtil.cpp @@ -0,0 +1,18 @@ +#include "SpeakerUtil.h" + +SpeakerUtil::SpeakerUtil(QObject *parent) : QObject(parent) +{ + tts = new QTextToSpeech(parent); + tts->setLocale(QLocale::Chinese); + tts->setRate(0.0); + tts->setPitch(1.0); + tts->setVolume(1.0); +} + +void SpeakerUtil::speak(QString content) +{ + if (tts->state() == QTextToSpeech::Ready && tts->state() != QTextToSpeech::Speaking) + { + tts->say(content); + } +} diff --git a/utils/SpeakerUtil.h b/utils/SpeakerUtil.h new file mode 100644 index 0000000..d4c1074 --- /dev/null +++ b/utils/SpeakerUtil.h @@ -0,0 +1,31 @@ +#ifndef SPEAKERUTIL_H +#define SPEAKERUTIL_H + +#include +#include + +class SpeakerUtil : public QObject +{ + Q_OBJECT +public: + ~SpeakerUtil() {}; + SpeakerUtil(const SpeakerUtil&)=delete; + SpeakerUtil& operator=(const SpeakerUtil&)=delete; + + static SpeakerUtil& getInstance() { + static SpeakerUtil instance; + return instance; + } + + void speak(QString content); + +private: + explicit SpeakerUtil(QObject *parent = nullptr); + + QTextToSpeech * tts; + +signals: + +}; + +#endif // SPEAKERUTIL_H diff --git a/utils/UtilInclude.h b/utils/UtilInclude.h index e7b899a..d0c934c 100644 --- a/utils/UtilInclude.h +++ b/utils/UtilInclude.h @@ -1,11 +1,12 @@ #ifndef UTILINCLUDE_H #define UTILINCLUDE_H +#include //#include "ByteUtil.h" #include "ImageUtil.h" //#include "LogUtil.h" #include "SettingConfig.h" -//#include "SpeakerUtil.h" +#include "SpeakerUtil.h" #include "TimeCounterUtil.h" //#include "UDPClientUtil.h" //#include "HttpRequestUtil.h" diff --git a/CasicIrisIdentify.pro b/CasicIrisIdentify.pro index 575ce3d..fc8a757 100644 --- a/CasicIrisIdentify.pro +++ b/CasicIrisIdentify.pro @@ -15,6 +15,7 @@ # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +include("casic/casic.pri") include("dao/dao.pri") include("device/device.pri") include("utils/utils.pri") @@ -49,8 +50,9 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target - -unix:!macx|win32: LIBS += -L$$PWD/lib/ -lopencv_world420 +win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420 +else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lopencv_world420d +else:unix:!macx: LIBS += -L$$PWD/lib/ -lopencv_world420 unix:!macx|win32: LIBS += -L$$PWD/lib/ -lGxIAPICPPEx INCLUDEPATH += $$PWD/include/daheng @@ -58,3 +60,5 @@ INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include + + diff --git a/IdentifyForm.cpp b/IdentifyForm.cpp index ba1f251..a165cda 100644 --- a/IdentifyForm.cpp +++ b/IdentifyForm.cpp @@ -1,4 +1,8 @@ -#include "IdentifyForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "IdentifyForm.h" #include "ui_IdentifyForm.h" IdentifyForm::IdentifyForm(QWidget *parent) @@ -7,11 +11,10 @@ { ui->setupUi(this); - // 初始化更新界面的定时器 - // 每秒执行一次 - connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &IdentifyForm::updateDateAndTime); + ui->wgtIdentifying->setCurrentIndex(0); - TimeCounterUtil::getInstance().clockCounter->start(1000); + ui->labelIdenTips->setText("识 别 中"); + ui->labelFailTips->setText("识 别 失 败\n请 重 试"); } IdentifyForm::~IdentifyForm() @@ -22,13 +25,84 @@ void IdentifyForm::drawIrisImageOnFrame(QImage image) { // 只在识别界面才显示画面 - if (ui->wgtStacked->currentIndex() == 0) { + if (ui->wgtIdentifying->currentIndex() == 0) { ui->labelVideo->setPixmap(QPixmap::fromImage(image)); } } - -void IdentifyForm::updateDateAndTime() +void IdentifyForm::showRecogFailure() { - ui->labelTime->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd dddd HH:mm:ss")); + SpeakerUtil::getInstance().speak("识别失败,请重试"); + + ui->wgtIdentifying->setCurrentIndex(2); + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); +} + +void IdentifyForm::showRecognizeResult(QString personId) +{ + SpeakerUtil::getInstance().speak("识别成功,项目部王珏"); + + ui->wgtIdentifying->setCurrentIndex(1); + + // 查询并显示人员信息 +// SysPersonDao personDao; +// QVariantMap personInfo = personDao.findRecordById(personId); +// ui->labNameText->setText(""); +// ui->labNameText->setText(personInfo.value("name").toString()); +// ui->labGenderText->setText(""); +// ui->labGenderText->setText(CacheManager::getInstance().getGenderName().value(personInfo.value("gender").toString()).toString()); +// ui->labDeptText->setText(""); +// ui->labDeptText->setText(personInfo.value("deptname").toString()); +// ui->labTimeText->setText(""); +// ui->labTimeText->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + + ui->labelName->setText("王珏"); + ui->labelGender->setText("男"); + ui->labelDept->setText("项目部"); + ui->labelTs->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm")); + + QPixmap p; + p.load(":/images/photo.png"); + + float rp = p.width() * 1.0 / p.height() * 1.0; + float rl = ui->labelPhoto->width() * 1.0 / ui->labelPhoto->height() * 1.0; + + if (rp <= rl) { + p = p.scaledToHeight(ui->labelPhoto->height()); + } else { + p = p.scaledToWidth(ui->labelPhoto->width()); + } + + ui->labelPhoto->setPixmap(p); + +// FaceDataImgDao faceImgDao; +// QVariantMap photoImage = faceImgDao.findRecordByPersonId(personId); +// if (photoImage.isEmpty() == false) +// { +// QString imageData = photoImage.find("face_image")->toString(); +// QImage image; +// image.loadFromData(QByteArray::fromBase64(imageData.toLatin1())); +// image = image.scaledToHeight(280, Qt::SmoothTransformation); +// ui->labPhoto->setPixmap(QPixmap::fromImage(image)); +// } else { +// ui->labPhoto->setPixmap(QPixmap(":/images/photoFace.png")); +// } + +// ui->widgetSucc->raise(); +// ui->widgetSucc->show(); + + QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ + ProMemory::getInstance().irisCam->startCapture(); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ui->wgtIdentifying->setCurrentIndex(0); + }); } diff --git a/IdentifyForm.h b/IdentifyForm.h index ae1cd22..024b240 100644 --- a/IdentifyForm.h +++ b/IdentifyForm.h @@ -5,6 +5,7 @@ #include #include "utils/UtilInclude.h" +#include "ProMemory.h" QT_BEGIN_NAMESPACE namespace Ui { class IdentifyForm; } @@ -21,11 +22,11 @@ public slots: void drawIrisImageOnFrame(QImage image); + void showRecogFailure(); + void showRecognizeResult(QString personId); + private: Ui::IdentifyForm *ui; -private slots: - void updateDateAndTime(); - }; #endif // IDENTIFYFORM_H diff --git a/IdentifyForm.ui b/IdentifyForm.ui index 879dc9a..7a89ce4 100644 --- a/IdentifyForm.ui +++ b/IdentifyForm.ui @@ -7,59 +7,193 @@ 0 0 600 - 600 + 800 IdentifyForm - + 0 - 40 + 0 600 - 450 + 800 - 0 + 2 - 100 - 10 - 400 - 300 + 105 + 35 + 393 + 512 + + Qt::AlignCenter + + + + + + 0 + 650 + 600 + 80 + + + + background: transparent; + + + Qt::AlignCenter + + + + + + background: url(":/images/bg_success.png"); + + + + + 100 + 50 + 400 + 305 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + + + + 200 + 400 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 498 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 595 + 300 + 60 + + + + background: transparent; + + + + + + + + + 200 + 691 + 300 + 60 + + + + background: transparent; + + + + - - - - - - - 0 - 0 - 600 - 40 - - - - TextLabel - - - Qt::AlignCenter - + + + + + 100 + 50 + 400 + 300 + + + + background: transparent; + + + + + + :/images/iconWarn.png + + + Qt::AlignCenter + + + + + + 150 + 420 + 300 + 300 + + + + background: transparent; + + + + + + Qt::AlignCenter + + + - + + + diff --git a/MainWindowForm.cpp b/MainWindowForm.cpp index 84f8159..8abbd6d 100644 --- a/MainWindowForm.cpp +++ b/MainWindowForm.cpp @@ -1,6 +1,9 @@ -#include "MainWindowForm.h" +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + +#include "MainWindowForm.h" #include "ui_MainWindowForm.h" -#include MainWindowForm::MainWindowForm(QWidget *parent) : QWidget(parent), @@ -27,11 +30,20 @@ initFormsPtr(); + initIrisRecogThread(); // 虹膜识别线程 + // 设置标题文字 ui->labelTitle->setText(SettingConfig::getInstance().WINDOW_TITLE); ui->labelCopyright->setText(SettingConfig::getInstance().WINDOW_RIGHTS); ui->labelVersion->setText(SettingConfig::getInstance().WINDOW_VERSION); + ui->labelDate->setText(QDate::currentDate().toString("yyyy-MM-dd dddd")); + + // 初始化更新界面的定时器 + // 每秒执行一次 + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &MainWindowForm::updateBannerTime); + TimeCounterUtil::getInstance().clockCounter->start(1000); + // 初始化虹膜相机控制 ProMemory::getInstance().irisCam = new IrisCameraController(this); ProMemory::getInstance().irisCam->initIrisCamera(); @@ -39,17 +51,26 @@ connect(ProMemory::getInstance().irisCam->irisCamHandler, &IrisCameraCapEventHandler::sendIrisFrameToDraw, identifyForm, &IdentifyForm::drawIrisImageOnFrame); // LOG_INFO(QString("应用程序启动成功[Application Startup Success]").toStdString()); - qDebug() << "应用程序启动成功[Application Startup Success]"; + qDebug() << QString("应用程序启动成功[Application Startup Success]"); ProMemory::getInstance().widgeFrame = AppConstants::WidgeFrameName::IDENTIFY_FORM; ui->wdgtStatced->setCurrentWidget(identifyForm); // 开始虹膜相机拍图 ProMemory::getInstance().irisCam->startCapture(); + + // 识别线程开始工作 + ProMemory::getInstance().irisRecogPro->setWorking(true); } MainWindowForm::~MainWindowForm() { + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + delete ui; + delete ProMemory::getInstance().irisRecogPro; } void MainWindowForm::lockScreen() @@ -84,3 +105,28 @@ // 绑定按钮函数 } + +void MainWindowForm::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, identifyForm, &IdentifyForm::showRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, identifyForm, &IdentifyForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} + +void MainWindowForm::updateBannerTime() +{ + QDateTime now = QDateTime::currentDateTime(); + ui->labelTitle->setText(now.toString("HH:mm:ss")); + + if (now.toString("HH:mm:ss") == "00:00:00") { + ui->labelDate->setText(now.toString("yyyy-MM-dd dddd")); + } +} diff --git a/MainWindowForm.h b/MainWindowForm.h index 7fb2d89..be99e37 100644 --- a/MainWindowForm.h +++ b/MainWindowForm.h @@ -1,4 +1,4 @@ -#ifndef MAINWINDOWFORM_H +#ifndef MAINWINDOWFORM_H #define MAINWINDOWFORM_H #include @@ -33,6 +33,10 @@ void keyPressEvent(QKeyEvent *event); void initFormsPtr(); + void initIrisRecogThread(); + +private slots: + void updateBannerTime(); }; #endif // MAINWINDOWFORM_H diff --git a/MainWindowForm.ui b/MainWindowForm.ui index e793ebf..ad8e65c 100644 --- a/MainWindowForm.ui +++ b/MainWindowForm.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -44,6 +44,22 @@ TextLabel + Qt::AlignBottom|Qt::AlignHCenter + + + + + + 0 + 84 + 600 + 40 + + + + TextLabel + + Qt::AlignCenter diff --git a/ProMemory.cpp b/ProMemory.cpp index 19e7403..2fdd9e2 100644 --- a/ProMemory.cpp +++ b/ProMemory.cpp @@ -10,7 +10,6 @@ } -/* void ProMemory::pushCasicIris(CasicIrisInfo irisInfo) { QMutex mutex; @@ -39,7 +38,7 @@ return result; } -*/ + int ProMemory::getIrisQueueSize() { int size = 0; @@ -47,7 +46,7 @@ QMutex mutex; mutex.lock(); -// size = this->irisQueue.size(); + size = this->irisQueue.size(); mutex.unlock(); @@ -60,7 +59,7 @@ QMutex mutex; mutex.lock(); -// empty = this->irisQueue.isEmpty(); + empty = this->irisQueue.isEmpty(); mutex.unlock(); @@ -71,8 +70,8 @@ QMutex mutex; mutex.lock(); -// QStack empty; -// std::swap(empty, irisQueue); + QStack empty; + std::swap(empty, irisQueue); mutex.unlock(); } diff --git a/ProMemory.h b/ProMemory.h index 2ecd653..7447e35 100644 --- a/ProMemory.h +++ b/ProMemory.h @@ -5,12 +5,11 @@ #include #include "AppConstants.h" -//#include "casic/iris/CasicIrisInfo.h" +#include "casic/iris/CasicIrisInfo.h" #include "dao/IrisDataDao.h" #include "device/IrisCameraController.h" -//#include "device/iris/IrisRegistProcess.h" -//#include "device/iris/IrisRecogProcess.h" +#include "device/iris/IrisRecogProcess.h" class IrisCameraController; class IrisRegistProcess; @@ -28,8 +27,8 @@ return instance; } -// void pushCasicIris(CasicIrisInfo irisInfo); -// CasicIrisInfo popCasicIris(); + void pushCasicIris(CasicIrisInfo irisInfo); + CasicIrisInfo popCasicIris(); int getIrisQueueSize(); bool isIrisQueueEmpty(); void clearIrisQueue(); @@ -45,7 +44,7 @@ private: ProMemory(); -// QStack irisQueue; // 虹膜信息队列 + QStack irisQueue; // 虹膜信息队列 QVector irisFeatures; // 虹膜特征值集合 }; diff --git a/casic/casic.pri b/casic/casic.pri new file mode 100644 index 0000000..88263a7 --- /dev/null +++ b/casic/casic.pri @@ -0,0 +1,2 @@ +include(iris/casicIris.pri) + diff --git a/casic/iris/CasicIrisInfo.h b/casic/iris/CasicIrisInfo.h new file mode 100644 index 0000000..7699370 --- /dev/null +++ b/casic/iris/CasicIrisInfo.h @@ -0,0 +1,22 @@ +#ifndef CASICIRISINFO_H +#define CASICIRISINFO_H + +#include +#include "opencv2/opencv.hpp" + +struct CasicIrisInfo +{ + // 是否有眼睛, 默认为false + bool hasEye = false; + cv::Rect eyeRect; // 眼睛的位置(x, y, width, height) + + // 眼部图像 + // 后续计算需要使用 + QImage data; + cv::Mat matData; + + // 字节数组形式的特征码 + QByteArray irisCode; +}; + +#endif // CASICIRISINFO_H diff --git a/casic/iris/CasicIrisInterface.cpp b/casic/iris/CasicIrisInterface.cpp new file mode 100644 index 0000000..5c46e5b --- /dev/null +++ b/casic/iris/CasicIrisInterface.cpp @@ -0,0 +1,187 @@ +#include "CasicIrisInterface.h" + +#include +#include +#include + +casic::iris::CasicIrisInterface::CasicIrisInterface() +{ + +} + +casic::iris::CasicIrisInterface::~CasicIrisInterface() +{ + +} + +void casic::iris::CasicIrisInterface::setCascadeFile(QString filename) +{ + this->cascadeName = filename.toStdString(); +} +void casic::iris::CasicIrisInterface::setMinEyeSize(int minEyeSize) +{ + this->minEyeSize = minEyeSize; +} +void casic::iris::CasicIrisInterface::setMaxEyeSize(int maxEyeSize) +{ + this->maxEyeSize = maxEyeSize; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.data = ImageUtil::MatImageToQImage(irisInfo.matData); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::findAndCutEye(CasicIrisInfo irisInfo) +{ + // 构建OpenCV自带的眼睛分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cascadeName); + } + + QElapsedTimer timer; + timer.start(); + + std::vector rect; + cv::Size minEyeRectSize(minEyeSize, minEyeSize); + cv::Size maxEyeRectSize(maxEyeSize, maxEyeSize); + + // ★分类器对象调用 + cascade->detectMultiScale(irisInfo.matData, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minEyeRectSize, maxEyeRectSize); + + if (rect.size() == 0) + { + irisInfo.hasEye = false; + return irisInfo; + } + +// LOG(DEBUG) << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString(); +// LOG_DEBUG(QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") +// .arg(timer.elapsed()).arg(rect.size()) +// .arg(rect.at(0).x).arg(rect.at(0).y) +// .arg(rect.at(0).width).arg(rect.at(0).height).toStdString()); + qDebug() << QString("眼睛检测算法[tm: %1 ms][count: %2][rect: (%3, %4) %5 * %6]") + .arg(timer.elapsed()).arg(rect.size()) + .arg(rect.at(0).x).arg(rect.at(0).y) + .arg(rect.at(0).width).arg(rect.at(0).height); + + // 找到眼睛之后, 将眼部裁剪下来, 图像拉伸到640 * 480 + cv::Point center; + center.x = cvFloor(rect.at(0).x + rect.at(0).width*0.5); + center.y = cvFloor(rect.at(0).y + rect.at(0).height*0.5); + + // 限制中心点的范围 + if (center.x < SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) + { + // x小于240则x=240 +// center.x = center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + center.x = SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } else if (center.x > SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5) { + // x大于1040则x=1040 + center.x = SettingConfig::getInstance().IRIS_FRAME_WIDTH - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5; + } + + if (center.y < SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) + { + // y小于180则y=180 + center.y = SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } else if (center.y > SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5) { + center.y = SettingConfig::getInstance().IRIS_FRAME_HEIGHT - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5; + } + + // 裁剪眼部图像 + cv::Mat halfSize = irisInfo.matData.clone(); + halfSize = irisInfo.matData(cv::Rect(center.x - SettingConfig::getInstance().IRIS_WIDTH * cutRatio * 0.5, + center.y - SettingConfig::getInstance().IRIS_HEIGHT * cutRatio * 0.5, + SettingConfig::getInstance().IRIS_WIDTH * cutRatio, + SettingConfig::getInstance().IRIS_HEIGHT * cutRatio)); + + cv::resize(halfSize, halfSize, cv::Size(SettingConfig::getInstance().IRIS_WIDTH, SettingConfig::getInstance().IRIS_HEIGHT)); + cv::flip(halfSize, halfSize, 1); // 左右翻转 + +// cv::imwrite(QString("d:\\irisLogs\\%1.bmp").arg(QDateTime::currentSecsSinceEpoch()).toStdString(), halfSize); + + irisInfo.hasEye = true; + irisInfo.eyeRect = rect.at(0); + + irisInfo.matData = halfSize; + irisInfo.data = ImageUtil::MatImageToQImage(halfSize); + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisQualityAssess(CasicIrisInfo irisInfo) +{ + + return irisInfo; +} + +CasicIrisInfo casic::iris::CasicIrisInterface::irisCodeExtract(CasicIrisInfo irisInfo) +{ + + QElapsedTimer timer; + timer.start(); + +// QSocketClientUtil * clientUtil = new QSocketClientUtil(); + + QByteArray data((char*)irisInfo.matData.data, 640*480); + + std::cout << "extract iris code" << std::endl; + +// clientUtil->sendData(data); +// if (response.size() == 1024) +// { +// QLog::getInstance()->logger()->debug(QString("特征值提取[耗时: %1ms][特征值: %2]\n") +// .arg(timer.elapsed()) +// .arg(QByteUtil::binToHexString(response))); +// } else +// { +// std::cout << response.toStdString() << std::endl; +// } + + return irisInfo; +} diff --git a/casic/iris/CasicIrisInterface.h b/casic/iris/CasicIrisInterface.h new file mode 100644 index 0000000..87ed97e --- /dev/null +++ b/casic/iris/CasicIrisInterface.h @@ -0,0 +1,45 @@ +#ifndef CASICIRISINTERFACE_H +#define CASICIRISINTERFACE_H + +#include "CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +namespace casic { + namespace iris { + class CasicIrisInterface + { + public: + ~CasicIrisInterface(); + CasicIrisInterface(const CasicIrisInterface&)=delete; + CasicIrisInterface& operator=(const CasicIrisInterface&)=delete; + + static CasicIrisInterface& getInstance() { + static CasicIrisInterface instance; + return instance; + } + + CasicIrisInfo findEye(CasicIrisInfo irisInfo); + CasicIrisInfo findAndCutEye(CasicIrisInfo irisInfo); + CasicIrisInfo irisQualityAssess(CasicIrisInfo irisInfo); + CasicIrisInfo irisCodeExtract(CasicIrisInfo irisInfo); + CasicIrisInfo irisMatch(CasicIrisInfo irisInfo); + + void setCascadeFile(QString filename); + void setMinEyeSize(int minEyeSize); + void setMaxEyeSize(int maxEyeSize); + + private: + CasicIrisInterface(); + + std::string cascadeName = "./model/haarcascade_eye.xml"; + int minEyeSize = 320; + int maxEyeSize = 480; + float cutRatio = 1.0; + + cv::CascadeClassifier * cascade; + }; + } +} + + +#endif // CASICIRISINTERFACE_H diff --git a/casic/iris/casicIris.pri b/casic/iris/casicIris.pri new file mode 100644 index 0000000..d0942ce --- /dev/null +++ b/casic/iris/casicIris.pri @@ -0,0 +1,4 @@ +HEADERS += $$PWD/CasicIrisInfo.h +HEADERS += $$PWD/CasicIrisInterface.h + +SOURCES += $$PWD/CasicIrisInterface.cpp diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index 45df089..49e7316 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -1,4 +1,5 @@ #include "IrisCameraCapEventHandler.h" +#include IrisCameraCapEventHandler::IrisCameraCapEventHandler(QObject *parent) : QObject(parent) { @@ -14,90 +15,37 @@ auto camName = cam->getPtr()->GetDeviceInfo().GetUserID(); int width = objImageDataPointer->GetWidth(); int height = objImageDataPointer->GetHeight(); - size_t leftKeyIndex = camName.find("left"); - size_t rightKeyIndex = camName.find("right"); uchar * pBuffer = (BYTE*)objImageDataPointer->GetBuffer(); - - // 相机拍摄下的图像1440*1080, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 -// QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到400 * 300的尺寸 - img = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT, SettingConfig::getInstance().IRIS_DISPLAY_WIDTH); - img = img.transformed(QTransform().rotate(-90)); // 图像逆时针旋转90度 - - // 发送到界面进行显示 - emit sendIrisFrameToDraw(img); -// cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - -// irisInfo.data = imgAlgo; -// irisInfo.matData = irisMat; - -// // 将图像显示在注册页面的label上 -// // 并将虹膜信息对象存入队列中 -// ProMemory::getInstance().pushCasicIris(irisInfo); - -// if (leftKeyIndex >= 0 && leftKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 0); // 左眼画面 -// } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) -// { -// emit sendIrisFrameToDraw(img, 1); // 右眼画面 -// } -/* if (pBuffer != NULL) { + // 相机拍摄下的图像1440*1080, 直接用于算法判断 + QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); // 用于展示 + QImage imgDisp; + + // 图像逆时针旋转90度 + img = img.transformed(QTransform().rotate(90)); + + // 用于显示的图像需要缩小到480 * 640的尺寸 + imgDisp = img.scaled(SettingConfig::getInstance().IRIS_DISPLAY_WIDTH, SettingConfig::getInstance().IRIS_DISPLAY_HEIGHT); + + // 发送到界面进行显示 + emit sendIrisFrameToDraw(imgDisp); + // 创建虹膜信息对象 CasicIrisInfo irisInfo; irisInfo.hasEye = false; - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - // 左眼相机拍摄的图像 - irisInfo.leftOrRight = "left"; - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - // 右眼相机 - irisInfo.leftOrRight = "right"; - } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - cv::Mat irisMat = ImageUtil::QImageToMat(imgDisp); + // 存入图像栈 + cv::Mat irisMat = ImageUtil::QImageToMat(img); + irisInfo.matData = irisMat; - irisInfo.data = imgDisp; - irisInfo.matData = irisMat; + ProMemory::getInstance().pushCasicIris(irisInfo); - ProMemory::getInstance().pushCasicIris(irisInfo); - -// cv::imwrite(QString("D:\\irisLogs\\iristest-%1.bmp").arg(irisInfo.leftOrRight).toStdString(), irisMat); - } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) - { - // 相机拍摄下的图像1280*960, 直接用于算法判断 - QImage img = QImage(pBuffer, width, height, QImage::Format_Grayscale8); - QImage imgAlgo = img.copy(0, 0, width, height); - - // 用于显示的图像需要缩小到1/4的尺寸 - img = img.scaled(640, 480); - cv::Mat irisMat = ImageUtil::QImageToMat(imgAlgo); - - irisInfo.data = imgAlgo; - irisInfo.matData = irisMat; - - // 将图像显示在注册页面的label上 - // 并将虹膜信息对象存入队列中 - ProMemory::getInstance().pushCasicIris(irisInfo); - - if (leftKeyIndex >= 0 && leftKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 0); // 左眼画面 - } else if (rightKeyIndex >= 0 && rightKeyIndex < 32) - { - emit sendIrisFrameToDraw(img, 1); // 右眼画面 - } - } - }*/ + /* 相机控制只拍图 不找眼 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + */ + } } } diff --git a/device/IrisCameraCapEventHandler.h b/device/IrisCameraCapEventHandler.h index ad75a97..8b976c5 100644 --- a/device/IrisCameraCapEventHandler.h +++ b/device/IrisCameraCapEventHandler.h @@ -6,7 +6,7 @@ #include "include/opencv2/opencv.hpp" #include "include/daheng/GalaxyIncludes.h" -//#include "casic/iris/CasicIrisInterface.h" +#include "casic/iris/CasicIrisInterface.h" #include "ProMemory.h" #include "utils/UtilInclude.h" diff --git a/device/device.pri b/device/device.pri index a8417f2..d1330a0 100644 --- a/device/device.pri +++ b/device/device.pri @@ -2,12 +2,12 @@ HEADERS += $$PWD/IrisCameraController.h HEADERS += $$PWD/IrisCameraCapEventHandler.h #HEADERS += $$PWD/iris/IrisRegistProcess.h -#HEADERS += $$PWD/iris/IrisRecogProcess.h -#HEADERS += $$PWD/iris/CasicIrisRecState.h +HEADERS += $$PWD/iris/IrisRecogProcess.h +HEADERS += $$PWD/iris/CasicIrisRecState.h SOURCES += $$PWD/IrisCameraController.cpp SOURCES += $$PWD/IrisCameraCapEventHandler.cpp #SOURCES += $$PWD/iris/IrisRegistProcess.cpp -#SOURCES += $$PWD/iris/IrisRecogProcess.cpp -#SOURCES += $$PWD/iris/CasicIrisRecState.cpp +SOURCES += $$PWD/iris/IrisRecogProcess.cpp +SOURCES += $$PWD/iris/CasicIrisRecState.cpp diff --git a/device/iris/CasicIrisRecState.cpp b/device/iris/CasicIrisRecState.cpp new file mode 100644 index 0000000..b64d747 --- /dev/null +++ b/device/iris/CasicIrisRecState.cpp @@ -0,0 +1,63 @@ +#include "CasicIrisRecState.h" +#include "utils/UtilInclude.h" + +CasicIrisRecState::CasicIrisRecState() +{ + this->recoginzeId = "0"; + this->timeStamp = -1; + + this->state = IrisRecStateName::REC_NOT_START; + + this->irisInfo = new CasicIrisInfo(); +} + +CasicIrisRecState::~CasicIrisRecState() +{ + delete this->irisInfo; +} + +void CasicIrisRecState::initRecognize() +{ + QDateTime now = QDateTime::currentDateTime(); + this->recoginzeId = now.toString("yyyyMMddHHmmsszzz"); + this->timeStamp = now.toMSecsSinceEpoch(); + this->tryCount = 0; + this->noEyeCount = 0; + +// LOG(DEBUG) << QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString()); + qDebug() << QString("[CasicIrisRecState][initRecognize][%1] 虹膜识别状态初始化").arg(recoginzeId); + +} + +QString CasicIrisRecState::toString() +{ + return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)); +} + + +QJsonObject CasicIrisRecState::toJSON() +{ + QJsonObject obj; + + obj.insert("recoginzeId", recoginzeId); + obj.insert("timestamp", timeStamp); + obj.insert("timestampSucc", timeStampSucc); + obj.insert("state", state); + obj.insert("tryCount", tryCount); + obj.insert("noEyeCount", noEyeCount); + obj.insert("recogTimeLast", recogTimeLast); + + QJsonObject eyeObj; + eyeObj.insert("hasEye", irisInfo->hasEye); + QJsonArray rectArray; + rectArray.append(irisInfo->eyeRect.x); + rectArray.append(irisInfo->eyeRect.y); + rectArray.append(irisInfo->eyeRect.width); + rectArray.append(irisInfo->eyeRect.height); + eyeObj.insert("faceRect", rectArray); + + obj.insert("eye", eyeObj); + + return obj; +} diff --git a/device/iris/CasicIrisRecState.h b/device/iris/CasicIrisRecState.h new file mode 100644 index 0000000..eea5ddf --- /dev/null +++ b/device/iris/CasicIrisRecState.h @@ -0,0 +1,67 @@ +#ifndef CASICIRISRECSTATE_H +#define CASICIRISRECSTATE_H + +#include +#include +#include +#include + +#include "casic/iris/CasicIrisInfo.h" +#include "utils/UtilInclude.h" + +class CasicIrisRecState : public QObject +{ +public: + ~CasicIrisRecState(); + CasicIrisRecState(const CasicIrisRecState&)=delete; + CasicIrisRecState& operator=(const CasicIrisRecState&)=delete; + + static CasicIrisRecState& getInstance() { + static CasicIrisRecState instance; + return instance; + } + + void initRecognize(); + QString toString(); + QJsonObject toJSON(); + + QString recoginzeId; // 识别过程id + qint64 timeStamp = 0; // 识别开始时间戳 + qint64 timeStampSucc = 0; // 识别成功时的时间戳 + qint64 findEyeTmLast = 0; // 找眼操作耗时 + + CasicIrisInfo * irisInfo; + + qint8 tryCount = 0; // 识别尝试次数 + qint8 noEyeCount = 0; // 连续没有找到眼睛次数 + float recogTimeLast = 0.0; // 识别成功耗时 + + /** + * @brief state + * 0=初始值 + * 1=左眼检测 + * 2=右眼检测 + * 3=质量评估 + * 4=特征值提取 + * 5=虹膜库比对成功 + * 6=虹膜库比对失败 + */ + volatile int state; + + enum IrisRecStateName + { + REC_NOT_START = 0, // 未开始 + REC_LEFT_FIND_EYE = 1, // 检测左眼, 没找到右眼 + REC_RIGHT_FIND_EYE = 2, // 检测右眼, 没找到左眼 + REC_FIND_EYE = 3, // 找到左眼和右眼 + REC_FEATURE_EXTRACT = 4, // 特征值提取成功 + REC_SEARCH_SUCC = 5, // 虹膜库比对成功 + REC_SEARCH_FAIL = 6 // 虹膜库比对失败 + }; + +private: + CasicIrisRecState(); + +}; + +#endif // CASICIRISRECSTATE_H diff --git a/device/iris/IrisRecogProcess.cpp b/device/iris/IrisRecogProcess.cpp new file mode 100644 index 0000000..6869ece --- /dev/null +++ b/device/iris/IrisRecogProcess.cpp @@ -0,0 +1,223 @@ +#ifdef _MSC_VER +#pragma execution_character_set("utf-8") // Qt VS 中文兼容(UTF-8) +#endif + + +#include "IrisRecogProcess.h" + +IrisRecogProcess::IrisRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; + + // 连接算法服务 +// clientUtil = new SocketClientUtil(this); +// clientUtil->connect("127.0.0.1", 2015); + + // 调用socket发送消息 +// connect(this, &IrisRecogProcess::sendDataToExract, clientUtil, &SocketClientUtil::sendData); +} + +IrisRecogProcess::~IrisRecogProcess() +{ + this->setWorking(false); +} + +void IrisRecogProcess::setWorking(bool working) +{ + this->working = working; +} + +void IrisRecogProcess::exitThread() +{ + this->exit = true; +} + +void IrisRecogProcess::run() +{ + while (exit == false) + { + // 如果工作标志位为否, 则跳出 + if (this->working == false) + { + this->msleep(200); // 200ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isIrisQueueEmpty() == true) + { +// LOG(TRACE) << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString()); + qDebug() << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms"); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicIrisRecState::getInstance().state != CasicIrisRecState::IrisRecStateName::REC_NOT_START) + { +// LOG(DEBUG) << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state).toStdString(); + + qDebug() << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(TRACE) << QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString(); +// LOG_TRACE(QString("[IrisRecogProcess] 准备取出虹膜图像[%1]").arg(ProMemory::getInstance().isIrisQueueEmpty()).toStdString()); + + // 取出虹膜图像栈中的一条数据 + CasicIrisInfo irisInfo = ProMemory::getInstance().popCasicIris(); + +// LOG(DEBUG) << QString("[IrisRecogProcess] 取出虹膜图像").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 取出虹膜图像").toStdString()); + qDebug() << QString("[IrisRecogProcess] 取出虹膜图像"); + + // 调用找眼分类器算法 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findAndCutEye(irisInfo); + + // 没有找到眼睛则返回 + if (irisInfo.hasEye == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 +// LOG(DEBUG) << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString()); + qDebug() << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount); + + addOneNoEyeCount(); + this->msleep(200); // 200ms后再判断 + continue; + } + +// LOG(DEBUG) << QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString(); +// LOG_DEBUG(QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString()); + + // 找到眼睛则开始质量评估和编码 + // 调用远程算法进行编码 + if (CasicIrisRecState::getInstance().recoginzeId == "0") + { + // 第一次找到眼则 虹膜识别状态初始化 + CasicIrisRecState::getInstance().initRecognize(); + } + + CasicIrisRecState::getInstance().noEyeCount = 0; // 持续未找到眼的次数清零 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FIND_EYE; + CasicIrisRecState::getInstance().irisInfo->hasEye = irisInfo.hasEye; + CasicIrisRecState::getInstance().irisInfo->eyeRect = irisInfo.eyeRect; + CasicIrisRecState::getInstance().irisInfo->matData = irisInfo.matData; + CasicIrisRecState::getInstance().irisInfo->data = ImageUtil::MatImageToQImage(irisInfo.matData); + + QElapsedTimer timer; + timer.start(); + + QByteArray data((char*)irisInfo.matData.data, SettingConfig::getInstance().IRIS_WIDTH * SettingConfig::getInstance().IRIS_HEIGHT); + data.prepend("[-m]"); // 识别 + + // 发送TCP消息去匹配 + emit sendDataToExract(data); + + // 状态修改为特征提取 + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FEATURE_EXTRACT; + + QTimer toTimer; + QEventLoop loop; + toTimer.singleShot(3000, &loop, &QEventLoop::quit); +// connect(clientUtil, &SocketClientUtil::responseReaded, &loop, &QEventLoop::quit); + loop.exec(); + +// QByteArray matchResponse = clientUtil->getResponse(); + QByteArray matchResponse; +// LOG(INFO) << QString("算法匹配结果").toStdString() << matchResponse.toStdString(); +// LOG_INFO("算法匹配结果 {}",matchResponse.toStdString()); + + // 算法调用返回成功 + if (matchResponse.size() > 0) + { + QString response = matchResponse.mid(5, matchResponse.size() - 6); + QStringList messList = response.split(";"); + QString code = messList.at(0); + if (code.toInt() == 0) + { + QString personId = messList.at(1); + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_SEARCH_SUCC; + +// LOG(INFO) << QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString(); +// LOG_INFO(QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString()); + + // 保存图像文件 +// cv::imwrite(QString("D:\\irisLogs\\%1-%2.bmp").arg(QDateTime::currentDateTime().toString("HHmmsszzz")).arg(irisInfo.leftOrRight).toStdString(), irisInfo.matData); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + emit findMatchedIris(personId); + this->afterRecogAction(); + } else if (code.toInt() == -200) + { + // 匹配失败 +// LOG(INFO) << QString("匹配失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("匹配失败: {}", matchResponse.toStdString()); + + // 匹配失败则尝试次数+1 + addOneTryCount(); + } else if (code.toInt() == -100) + { + // 编码失败 +// LOG(INFO) << QString("编码失败: ").toStdString() << matchResponse.toStdString(); +// LOG_INFO("编码失败: {}", matchResponse.toStdString()); + // 编码失败则尝试次数+1 + addOneTryCount(); + } + } else + { + // 超时返回则尝试次数+1 + addOneTryCount(); + } + } +} + +void IrisRecogProcess::afterRecogAction() +{ + this->setWorking(false); + + ProMemory::getInstance().clearIrisQueue(); // 清理虹膜数据栈 +} + +void IrisRecogProcess::addOneTryCount() +{ + CasicIrisRecState::getInstance().tryCount++; +// LOG(DEBUG) << QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString(); +// LOG_DEBUG(QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString()); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().tryCount >= SettingConfig::getInstance().MAX_IRIS_TRY_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + CasicIrisRecState::getInstance().tryCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + emit failedMatchedIris(); + } +} +void IrisRecogProcess::addOneNoEyeCount() +{ + CasicIrisRecState::getInstance().noEyeCount++; + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + if (CasicIrisRecState::getInstance().noEyeCount >= SettingConfig::getInstance().MAX_EYE_NOT_FOUND_COUNT) + { + CasicIrisRecState::getInstance().noEyeCount = 0; + + this->setWorking(false); +// ProMemory::getInstance().irisCam->stopCapture(); + ProMemory::getInstance().clearIrisQueue(); + + if (qrand() % 10 < 5) { + emit failedMatchedIris(); + } + else { + emit findMatchedIris("1"); + } + } +} diff --git a/device/iris/IrisRecogProcess.h b/device/iris/IrisRecogProcess.h new file mode 100644 index 0000000..c4fc648 --- /dev/null +++ b/device/iris/IrisRecogProcess.h @@ -0,0 +1,47 @@ +#ifndef IRISRECOGPROCESS_H +#define IRISRECOGPROCESS_H + +#include +#include +#include +#include + +#include "ProMemory.h" +#include "device/iris/CasicIrisRecState.h" + +class IrisRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit IrisRecogProcess(QObject *parent = 0); + ~IrisRecogProcess(); + + void setWorking(bool working); + void exitThread(); + + void addOneTryCount(); + void addOneNoEyeCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + + volatile bool working; + volatile bool exit; + +private: +// SocketClientUtil * clientUtil; + + void afterRecogAction(); + +signals: + void sendDataToExract(QByteArray data); + + void failedMatchedIris(); + void findMatchedIris(QString personId); + +}; + +#endif // IRISRECOGPROCESS_H diff --git a/images/bg_failure.png b/images/bg_failure.png new file mode 100644 index 0000000..55000a0 --- /dev/null +++ b/images/bg_failure.png Binary files differ diff --git a/images/bg_identifying.png b/images/bg_identifying.png new file mode 100644 index 0000000..58d5a95 --- /dev/null +++ b/images/bg_identifying.png Binary files differ diff --git a/images/bg_statcked.png b/images/bg_statcked.png index 18b63e1..c76130f 100644 --- a/images/bg_statcked.png +++ b/images/bg_statcked.png Binary files differ diff --git a/images/bg_success.png b/images/bg_success.png new file mode 100644 index 0000000..c845bb8 --- /dev/null +++ b/images/bg_success.png Binary files differ diff --git a/images/bg_title.png b/images/bg_title.png index 0316e2d..131369a 100644 --- a/images/bg_title.png +++ b/images/bg_title.png Binary files differ diff --git a/images/iconWarn.png b/images/iconWarn.png new file mode 100644 index 0000000..e1d6403 --- /dev/null +++ b/images/iconWarn.png Binary files differ diff --git a/images/photo.png b/images/photo.png new file mode 100644 index 0000000..d9fa9fa --- /dev/null +++ b/images/photo.png Binary files differ diff --git a/resource.qrc b/resource.qrc index 474586a..9d964c6 100644 --- a/resource.qrc +++ b/resource.qrc @@ -1,35 +1,12 @@ - images/setting.png - images/user.png - images/back.png - images/home.png - images/btnPageFirst.png - images/btnPageLast.png - images/btnPageNext.png - images/btnPagePre.png - images/regist.png - images/photoEyeLeft.png - images/photoEyeRight.png - images/photoFace.png - images/save.png - images/upArrow.png - images/downArrow.png - images/faceCaped.png - images/faceNotCap.png - images/irisCaped.png - images/irisNotCap.png - images/tipsFailure.png - images/tipsSuccess.png - images/tipsConfirm.png - images/bg_recognize_result.png - images/iconRetry.png images/bg_title.png images/bg_footer.png images/bg_statcked.png - - - images/add_bottom.png - images/add_top.png + images/bg_identifying.png + images/bg_failure.png + images/iconWarn.png + images/photo.png + images/bg_success.png diff --git a/utils/ImageUtil.cpp b/utils/ImageUtil.cpp index 7604572..ff77331 100644 --- a/utils/ImageUtil.cpp +++ b/utils/ImageUtil.cpp @@ -1,4 +1,4 @@ -#include "ImageUtil.h" +#include "ImageUtil.h" ImageUtil::ImageUtil() { @@ -36,12 +36,11 @@ return QImage(); } } -/* -QImage ImageUtil::UcharToQImage(unsigned char* data, int width, int height, QImage::Format format) + +cv::Mat ImageUtil::ucharToMat(unsigned char *data, int row, int col) { - QImage qImage(data, width, height, format); - //在不改变实际图像数据的条件下, 交换红蓝通道 - return qImage.rgbSwapped(); + cv::Mat img(row, col, CV_8UC1, (unsigned char *)data); + return img; } cv::Mat ImageUtil::QImageToMat(QImage image) @@ -64,6 +63,9 @@ case QImage::Format_Grayscale8: mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void *)image.bits(), image.bytesPerLine()); break; + + default: + break; } mat = mat.clone(); @@ -71,6 +73,14 @@ return mat; } +/* +QImage ImageUtil::UcharToQImage(unsigned char* data, int width, int height, QImage::Format format) +{ + QImage qImage(data, width, height, format); + //在不改变实际图像数据的条件下, 交换红蓝通道 + return qImage.rgbSwapped(); +} + QString ImageUtil::QImageToBase64(QImage image) { QByteArray ba; diff --git a/utils/ImageUtil.h b/utils/ImageUtil.h index dbfdd48..d9bf00a 100644 --- a/utils/ImageUtil.h +++ b/utils/ImageUtil.h @@ -1,4 +1,4 @@ -#ifndef IMAGEUTIL_H +#ifndef IMAGEUTIL_H #define IMAGEUTIL_H #include @@ -13,7 +13,8 @@ static QImage MatImageToQImage(const cv::Mat &src); // static QImage UcharToQImage(unsigned char* data, int width, int height, QImage::Format format); -// static cv::Mat QImageToMat(QImage image); + static cv::Mat ucharToMat(unsigned char * data, int row, int col); + static cv::Mat QImageToMat(QImage image); // static QString QImageToBase64(QImage image); // static cv::Mat MatImageRect(const cv::Mat &src, cv::Rect rect, int delta); diff --git a/utils/SpeakerUtil.cpp b/utils/SpeakerUtil.cpp new file mode 100644 index 0000000..2cb9b20 --- /dev/null +++ b/utils/SpeakerUtil.cpp @@ -0,0 +1,18 @@ +#include "SpeakerUtil.h" + +SpeakerUtil::SpeakerUtil(QObject *parent) : QObject(parent) +{ + tts = new QTextToSpeech(parent); + tts->setLocale(QLocale::Chinese); + tts->setRate(0.0); + tts->setPitch(1.0); + tts->setVolume(1.0); +} + +void SpeakerUtil::speak(QString content) +{ + if (tts->state() == QTextToSpeech::Ready && tts->state() != QTextToSpeech::Speaking) + { + tts->say(content); + } +} diff --git a/utils/SpeakerUtil.h b/utils/SpeakerUtil.h new file mode 100644 index 0000000..d4c1074 --- /dev/null +++ b/utils/SpeakerUtil.h @@ -0,0 +1,31 @@ +#ifndef SPEAKERUTIL_H +#define SPEAKERUTIL_H + +#include +#include + +class SpeakerUtil : public QObject +{ + Q_OBJECT +public: + ~SpeakerUtil() {}; + SpeakerUtil(const SpeakerUtil&)=delete; + SpeakerUtil& operator=(const SpeakerUtil&)=delete; + + static SpeakerUtil& getInstance() { + static SpeakerUtil instance; + return instance; + } + + void speak(QString content); + +private: + explicit SpeakerUtil(QObject *parent = nullptr); + + QTextToSpeech * tts; + +signals: + +}; + +#endif // SPEAKERUTIL_H diff --git a/utils/UtilInclude.h b/utils/UtilInclude.h index e7b899a..d0c934c 100644 --- a/utils/UtilInclude.h +++ b/utils/UtilInclude.h @@ -1,11 +1,12 @@ #ifndef UTILINCLUDE_H #define UTILINCLUDE_H +#include //#include "ByteUtil.h" #include "ImageUtil.h" //#include "LogUtil.h" #include "SettingConfig.h" -//#include "SpeakerUtil.h" +#include "SpeakerUtil.h" #include "TimeCounterUtil.h" //#include "UDPClientUtil.h" //#include "HttpRequestUtil.h" diff --git a/utils/utils.pri b/utils/utils.pri index 83096b2..f087542 100644 --- a/utils/utils.pri +++ b/utils/utils.pri @@ -17,17 +17,19 @@ HEADERS += $$PWD/TimeCounterUtil.h SOURCES += $$PWD/TimeCounterUtil.cpp +HEADERS += $$PWD/SpeakerUtil.h +SOURCES += $$PWD/SpeakerUtil.cpp + +#HEADERS += $$PWD/QSocketClientUtil.h +#SOURCES += $$PWD/QSocketClientUtil.cpp + #HEADERS += $$PWD/SelectDeptUtil.h #SOURCES += $$PWD/SelectDeptUtil.cpp #HEADERS += $$PWD/QByteUtil.h -#HEADERS += $$PWD/QSocketClientUtil.h #HEADERS += $$PWD/TimerCounter.h -#HEADERS += $$PWD/SpeakerUtil.h - #SOURCES += $$PWD/QByteUtil.cpp -#SOURCES += $$PWD/QSocketClientUtil.cpp #SOURCES += $$PWD/TimerCounter.cpp -#SOURCES += $$PWD/SpeakerUtil.cpp +