diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index d14fd54..05fe5f1 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -258,8 +258,8 @@ // 情况3 编辑时非本人 人脸重复 // 语音提示 - SpeakerUtil::getInstance().speak(QString("人脸重复注册,请重试")); - LOG(DEBUG) << "人脸已经注册" << ui->inputName->text().toStdString(); + SpeakerUtil::getInstance().speak(QString("人脸已注册其他人,请重试")); + LOG(DEBUG) << "人脸已注册其他人" << ui->inputName->text().toStdString(); } } } @@ -288,19 +288,20 @@ // 停止拍图 ProMemory::getInstance().irisCam->stopCapture(); - ProMemory::getInstance().irisRegistPro->setWorking(false); - // 语音提示 - SpeakerUtil::getInstance().speak(QString("虹膜重复注册,请重试")); - if (this->personId.isEmpty() == true) { // 情况1 新注册 重复注册 loadPersonInfo(personIdByIris); + + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已经注册,请重试")); LOG(DEBUG) << "虹膜已经注册" << ui->inputName->text().toStdString(); } else { - LOG(DEBUG) << "虹膜已经注册" << personIdByIris.toStdString(); + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已注册其他人,请重试")); + LOG(DEBUG) << "虹膜已注册其他人" << personIdByIris.toStdString(); } } diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index d14fd54..05fe5f1 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -258,8 +258,8 @@ // 情况3 编辑时非本人 人脸重复 // 语音提示 - SpeakerUtil::getInstance().speak(QString("人脸重复注册,请重试")); - LOG(DEBUG) << "人脸已经注册" << ui->inputName->text().toStdString(); + SpeakerUtil::getInstance().speak(QString("人脸已注册其他人,请重试")); + LOG(DEBUG) << "人脸已注册其他人" << ui->inputName->text().toStdString(); } } } @@ -288,19 +288,20 @@ // 停止拍图 ProMemory::getInstance().irisCam->stopCapture(); - ProMemory::getInstance().irisRegistPro->setWorking(false); - // 语音提示 - SpeakerUtil::getInstance().speak(QString("虹膜重复注册,请重试")); - if (this->personId.isEmpty() == true) { // 情况1 新注册 重复注册 loadPersonInfo(personIdByIris); + + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已经注册,请重试")); LOG(DEBUG) << "虹膜已经注册" << ui->inputName->text().toStdString(); } else { - LOG(DEBUG) << "虹膜已经注册" << personIdByIris.toStdString(); + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已注册其他人,请重试")); + LOG(DEBUG) << "虹膜已注册其他人" << personIdByIris.toStdString(); } } diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index 45fe761..f202cfe 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -30,6 +30,7 @@ initFaceRegistThread(); // 人脸注册线程 initFaceRecogThread(); // 人脸识别线程 initIrisRegistThread(); // 虹膜注册线程 + initIrisRecogThread(); // 虹膜识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); @@ -67,6 +68,10 @@ ProMemory::getInstance().irisRegistPro->deleteLater(); ProMemory::getInstance().irisRegistPro->wait(); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + // 关闭自动启动的外部程序 // outExe->close(); // delete outExe; @@ -75,6 +80,7 @@ delete ProMemory::getInstance().faceRegistPro; delete ProMemory::getInstance().faceRecogPro; delete ProMemory::getInstance().irisRegistPro; + delete ProMemory::getInstance().irisRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -194,15 +200,17 @@ void CasicBioRecWin::initFaceRecogThread() { // 人脸识别处理过程 - ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + ProMemory::getInstance().faceRecogPro = new FaceRecogProcess(this); // 绑定信号与槽函数 // 识别成功 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, - recogResultForm, &RecognizeResultForm::showRecognizeResult); +// connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); // 识别失败 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchFailure, recogResultForm, &RecognizeResultForm::showRecogFailure); ProMemory::getInstance().faceRecogPro->start(); @@ -222,9 +230,28 @@ connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::captureIrisFailure, addPersonForm, &AddPersonForm::onFailedCaptureIris); - // 采集虹膜图像成功 有匹配到红魔库 + // 采集虹膜图像成功 有匹配到虹膜库 connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::findMatchedIris, addPersonForm, &AddPersonForm::onMatchedIris); ProMemory::getInstance().irisRegistPro->start(); } + +void CasicBioRecWin::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 +// connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index d14fd54..05fe5f1 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -258,8 +258,8 @@ // 情况3 编辑时非本人 人脸重复 // 语音提示 - SpeakerUtil::getInstance().speak(QString("人脸重复注册,请重试")); - LOG(DEBUG) << "人脸已经注册" << ui->inputName->text().toStdString(); + SpeakerUtil::getInstance().speak(QString("人脸已注册其他人,请重试")); + LOG(DEBUG) << "人脸已注册其他人" << ui->inputName->text().toStdString(); } } } @@ -288,19 +288,20 @@ // 停止拍图 ProMemory::getInstance().irisCam->stopCapture(); - ProMemory::getInstance().irisRegistPro->setWorking(false); - // 语音提示 - SpeakerUtil::getInstance().speak(QString("虹膜重复注册,请重试")); - if (this->personId.isEmpty() == true) { // 情况1 新注册 重复注册 loadPersonInfo(personIdByIris); + + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已经注册,请重试")); LOG(DEBUG) << "虹膜已经注册" << ui->inputName->text().toStdString(); } else { - LOG(DEBUG) << "虹膜已经注册" << personIdByIris.toStdString(); + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已注册其他人,请重试")); + LOG(DEBUG) << "虹膜已注册其他人" << personIdByIris.toStdString(); } } diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index 45fe761..f202cfe 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -30,6 +30,7 @@ initFaceRegistThread(); // 人脸注册线程 initFaceRecogThread(); // 人脸识别线程 initIrisRegistThread(); // 虹膜注册线程 + initIrisRecogThread(); // 虹膜识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); @@ -67,6 +68,10 @@ ProMemory::getInstance().irisRegistPro->deleteLater(); ProMemory::getInstance().irisRegistPro->wait(); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + // 关闭自动启动的外部程序 // outExe->close(); // delete outExe; @@ -75,6 +80,7 @@ delete ProMemory::getInstance().faceRegistPro; delete ProMemory::getInstance().faceRecogPro; delete ProMemory::getInstance().irisRegistPro; + delete ProMemory::getInstance().irisRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -194,15 +200,17 @@ void CasicBioRecWin::initFaceRecogThread() { // 人脸识别处理过程 - ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + ProMemory::getInstance().faceRecogPro = new FaceRecogProcess(this); // 绑定信号与槽函数 // 识别成功 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, - recogResultForm, &RecognizeResultForm::showRecognizeResult); +// connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); // 识别失败 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchFailure, recogResultForm, &RecognizeResultForm::showRecogFailure); ProMemory::getInstance().faceRecogPro->start(); @@ -222,9 +230,28 @@ connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::captureIrisFailure, addPersonForm, &AddPersonForm::onFailedCaptureIris); - // 采集虹膜图像成功 有匹配到红魔库 + // 采集虹膜图像成功 有匹配到虹膜库 connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::findMatchedIris, addPersonForm, &AddPersonForm::onMatchedIris); ProMemory::getInstance().irisRegistPro->start(); } + +void CasicBioRecWin::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 +// connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index ff2ed35..b70245a 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -53,6 +53,7 @@ void initFaceRegistThread(); void initFaceRecogThread(); void initIrisRegistThread(); + void initIrisRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index d14fd54..05fe5f1 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -258,8 +258,8 @@ // 情况3 编辑时非本人 人脸重复 // 语音提示 - SpeakerUtil::getInstance().speak(QString("人脸重复注册,请重试")); - LOG(DEBUG) << "人脸已经注册" << ui->inputName->text().toStdString(); + SpeakerUtil::getInstance().speak(QString("人脸已注册其他人,请重试")); + LOG(DEBUG) << "人脸已注册其他人" << ui->inputName->text().toStdString(); } } } @@ -288,19 +288,20 @@ // 停止拍图 ProMemory::getInstance().irisCam->stopCapture(); - ProMemory::getInstance().irisRegistPro->setWorking(false); - // 语音提示 - SpeakerUtil::getInstance().speak(QString("虹膜重复注册,请重试")); - if (this->personId.isEmpty() == true) { // 情况1 新注册 重复注册 loadPersonInfo(personIdByIris); + + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已经注册,请重试")); LOG(DEBUG) << "虹膜已经注册" << ui->inputName->text().toStdString(); } else { - LOG(DEBUG) << "虹膜已经注册" << personIdByIris.toStdString(); + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已注册其他人,请重试")); + LOG(DEBUG) << "虹膜已注册其他人" << personIdByIris.toStdString(); } } diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index 45fe761..f202cfe 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -30,6 +30,7 @@ initFaceRegistThread(); // 人脸注册线程 initFaceRecogThread(); // 人脸识别线程 initIrisRegistThread(); // 虹膜注册线程 + initIrisRecogThread(); // 虹膜识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); @@ -67,6 +68,10 @@ ProMemory::getInstance().irisRegistPro->deleteLater(); ProMemory::getInstance().irisRegistPro->wait(); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + // 关闭自动启动的外部程序 // outExe->close(); // delete outExe; @@ -75,6 +80,7 @@ delete ProMemory::getInstance().faceRegistPro; delete ProMemory::getInstance().faceRecogPro; delete ProMemory::getInstance().irisRegistPro; + delete ProMemory::getInstance().irisRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -194,15 +200,17 @@ void CasicBioRecWin::initFaceRecogThread() { // 人脸识别处理过程 - ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + ProMemory::getInstance().faceRecogPro = new FaceRecogProcess(this); // 绑定信号与槽函数 // 识别成功 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, - recogResultForm, &RecognizeResultForm::showRecognizeResult); +// connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); // 识别失败 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchFailure, recogResultForm, &RecognizeResultForm::showRecogFailure); ProMemory::getInstance().faceRecogPro->start(); @@ -222,9 +230,28 @@ connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::captureIrisFailure, addPersonForm, &AddPersonForm::onFailedCaptureIris); - // 采集虹膜图像成功 有匹配到红魔库 + // 采集虹膜图像成功 有匹配到虹膜库 connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::findMatchedIris, addPersonForm, &AddPersonForm::onMatchedIris); ProMemory::getInstance().irisRegistPro->start(); } + +void CasicBioRecWin::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 +// connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index ff2ed35..b70245a 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -53,6 +53,7 @@ void initFaceRegistThread(); void initFaceRecogThread(); void initIrisRegistThread(); + void initIrisRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp index b61cb09..e45a191 100644 --- a/RecognizeResultForm.cpp +++ b/RecognizeResultForm.cpp @@ -26,10 +26,28 @@ void RecognizeResultForm::startWorkingRecognize() { // 开始人脸识别 - ProMemory::getInstance().faceRecogPro->setWorking(true); + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + // 人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + break; + case 2: + // 虹膜识别 + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + case 3: + case 4: + // 人脸和虹膜都需要打开 + ProMemory::getInstance().faceRecogPro->setWorking(true); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + } // 将界面切换到识别界面 RecognizeResultForm ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + ui->labBackground->raise(); // 1人脸图像显示的容器 ui->labVideo->resize(1280, 720); @@ -63,13 +81,17 @@ ui->widgetFail->show(); QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ - emit backToHomeAndWait(); - CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; + + emit backToHomeAndWait(); }); } void RecognizeResultForm::showRecognizeResult(QString personId) { + personIdByFace = ""; + personIdByIris = ""; + SpeakerUtil::getInstance().speak("识别成功"); ui->labVideo->hide(); ui->labTitle->hide(); @@ -102,8 +124,131 @@ ui->widgetSucc->show(); QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ - emit backToHomeAndWait(); CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + + emit backToHomeAndWait(); }); } + +void RecognizeResultForm::checkRecognizeResult(QString personId, int faceOrIris) +{ + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + { + // 仅人脸识别 + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 人脸识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 2: + { + // 仅虹膜识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜识别成功 [%1]").arg(CasicIrisRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "2"); + record.insert("debug_info", CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 4: + { + // 任意识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + QString logStr = QString("[RecognizeResultForm]%1识别成功[%2]"); + if (faceOrIris == 1) + { + logStr.arg("人脸").arg(CasicFaceRecState::getInstance().toString()); + } else if (faceOrIris == 2) + { + logStr.arg("虹膜").arg(CasicIrisRecState::getInstance().toString()); + } + LOG(DEBUG) << logStr.toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", QString::number(faceOrIris)); + record.insert("debug_info", faceOrIris == 1 ? CasicFaceRecState::getInstance().toString() : CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 3: + if (faceOrIris == 1) + { + this->personIdByFace = personId; + } else if (faceOrIris == 2) + { + this->personIdByIris = personId; + } + + if (personIdByFace.isEmpty() || personIdByIris.isEmpty()) + { + // 只有一个成功的结果 需要等待下次 + return; + } else if (personIdByFace != personIdByIris) + { + // 人脸和虹膜识别的不是同一人 识别失败 + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜与人脸识别结果不一致,识别失败 [face: %1][iris: %2]").arg(personIdByFace).arg(personIdByIris).toStdString(); + SpeakerUtil::getInstance().speak("虹膜与人脸识别结果不一致,识别失败,请重试"); + showRecogFailure(); + } else + { + LOG(DEBUG) << QString("[RecognizeResultForm]人脸虹膜识别成功").toStdString(); + showRecognizeResult(personId); + } + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "4"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString() + " " + CasicIrisRecState::getInstance().toString()); + recDao.save(record); + } +} diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index d14fd54..05fe5f1 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -258,8 +258,8 @@ // 情况3 编辑时非本人 人脸重复 // 语音提示 - SpeakerUtil::getInstance().speak(QString("人脸重复注册,请重试")); - LOG(DEBUG) << "人脸已经注册" << ui->inputName->text().toStdString(); + SpeakerUtil::getInstance().speak(QString("人脸已注册其他人,请重试")); + LOG(DEBUG) << "人脸已注册其他人" << ui->inputName->text().toStdString(); } } } @@ -288,19 +288,20 @@ // 停止拍图 ProMemory::getInstance().irisCam->stopCapture(); - ProMemory::getInstance().irisRegistPro->setWorking(false); - // 语音提示 - SpeakerUtil::getInstance().speak(QString("虹膜重复注册,请重试")); - if (this->personId.isEmpty() == true) { // 情况1 新注册 重复注册 loadPersonInfo(personIdByIris); + + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已经注册,请重试")); LOG(DEBUG) << "虹膜已经注册" << ui->inputName->text().toStdString(); } else { - LOG(DEBUG) << "虹膜已经注册" << personIdByIris.toStdString(); + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已注册其他人,请重试")); + LOG(DEBUG) << "虹膜已注册其他人" << personIdByIris.toStdString(); } } diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index 45fe761..f202cfe 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -30,6 +30,7 @@ initFaceRegistThread(); // 人脸注册线程 initFaceRecogThread(); // 人脸识别线程 initIrisRegistThread(); // 虹膜注册线程 + initIrisRecogThread(); // 虹膜识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); @@ -67,6 +68,10 @@ ProMemory::getInstance().irisRegistPro->deleteLater(); ProMemory::getInstance().irisRegistPro->wait(); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + // 关闭自动启动的外部程序 // outExe->close(); // delete outExe; @@ -75,6 +80,7 @@ delete ProMemory::getInstance().faceRegistPro; delete ProMemory::getInstance().faceRecogPro; delete ProMemory::getInstance().irisRegistPro; + delete ProMemory::getInstance().irisRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -194,15 +200,17 @@ void CasicBioRecWin::initFaceRecogThread() { // 人脸识别处理过程 - ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + ProMemory::getInstance().faceRecogPro = new FaceRecogProcess(this); // 绑定信号与槽函数 // 识别成功 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, - recogResultForm, &RecognizeResultForm::showRecognizeResult); +// connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); // 识别失败 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchFailure, recogResultForm, &RecognizeResultForm::showRecogFailure); ProMemory::getInstance().faceRecogPro->start(); @@ -222,9 +230,28 @@ connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::captureIrisFailure, addPersonForm, &AddPersonForm::onFailedCaptureIris); - // 采集虹膜图像成功 有匹配到红魔库 + // 采集虹膜图像成功 有匹配到虹膜库 connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::findMatchedIris, addPersonForm, &AddPersonForm::onMatchedIris); ProMemory::getInstance().irisRegistPro->start(); } + +void CasicBioRecWin::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 +// connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index ff2ed35..b70245a 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -53,6 +53,7 @@ void initFaceRegistThread(); void initFaceRecogThread(); void initIrisRegistThread(); + void initIrisRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp index b61cb09..e45a191 100644 --- a/RecognizeResultForm.cpp +++ b/RecognizeResultForm.cpp @@ -26,10 +26,28 @@ void RecognizeResultForm::startWorkingRecognize() { // 开始人脸识别 - ProMemory::getInstance().faceRecogPro->setWorking(true); + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + // 人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + break; + case 2: + // 虹膜识别 + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + case 3: + case 4: + // 人脸和虹膜都需要打开 + ProMemory::getInstance().faceRecogPro->setWorking(true); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + } // 将界面切换到识别界面 RecognizeResultForm ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + ui->labBackground->raise(); // 1人脸图像显示的容器 ui->labVideo->resize(1280, 720); @@ -63,13 +81,17 @@ ui->widgetFail->show(); QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ - emit backToHomeAndWait(); - CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; + + emit backToHomeAndWait(); }); } void RecognizeResultForm::showRecognizeResult(QString personId) { + personIdByFace = ""; + personIdByIris = ""; + SpeakerUtil::getInstance().speak("识别成功"); ui->labVideo->hide(); ui->labTitle->hide(); @@ -102,8 +124,131 @@ ui->widgetSucc->show(); QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ - emit backToHomeAndWait(); CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + + emit backToHomeAndWait(); }); } + +void RecognizeResultForm::checkRecognizeResult(QString personId, int faceOrIris) +{ + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + { + // 仅人脸识别 + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 人脸识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 2: + { + // 仅虹膜识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜识别成功 [%1]").arg(CasicIrisRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "2"); + record.insert("debug_info", CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 4: + { + // 任意识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + QString logStr = QString("[RecognizeResultForm]%1识别成功[%2]"); + if (faceOrIris == 1) + { + logStr.arg("人脸").arg(CasicFaceRecState::getInstance().toString()); + } else if (faceOrIris == 2) + { + logStr.arg("虹膜").arg(CasicIrisRecState::getInstance().toString()); + } + LOG(DEBUG) << logStr.toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", QString::number(faceOrIris)); + record.insert("debug_info", faceOrIris == 1 ? CasicFaceRecState::getInstance().toString() : CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 3: + if (faceOrIris == 1) + { + this->personIdByFace = personId; + } else if (faceOrIris == 2) + { + this->personIdByIris = personId; + } + + if (personIdByFace.isEmpty() || personIdByIris.isEmpty()) + { + // 只有一个成功的结果 需要等待下次 + return; + } else if (personIdByFace != personIdByIris) + { + // 人脸和虹膜识别的不是同一人 识别失败 + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜与人脸识别结果不一致,识别失败 [face: %1][iris: %2]").arg(personIdByFace).arg(personIdByIris).toStdString(); + SpeakerUtil::getInstance().speak("虹膜与人脸识别结果不一致,识别失败,请重试"); + showRecogFailure(); + } else + { + LOG(DEBUG) << QString("[RecognizeResultForm]人脸虹膜识别成功").toStdString(); + showRecognizeResult(personId); + } + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "4"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString() + " " + CasicIrisRecState::getInstance().toString()); + recDao.save(record); + } +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h index f5ef019..2c51865 100644 --- a/RecognizeResultForm.h +++ b/RecognizeResultForm.h @@ -25,7 +25,8 @@ public slots: void showRecogFailure(); - void showRecognizeResult(QString personId); + + void checkRecognizeResult(QString personId, int faceOrIris); void startWorkingRecognize(); // 开始工作 void drawImageOnHomeForm(QImage imageDisp); @@ -33,6 +34,11 @@ private: Ui::RecognizeResultForm *ui; + QString personIdByFace; + QString personIdByIris; + + void showRecognizeResult(QString personId); + signals: void backToHomeAndWait(); // 识别结束 返回主界面并待机 diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index d14fd54..05fe5f1 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -258,8 +258,8 @@ // 情况3 编辑时非本人 人脸重复 // 语音提示 - SpeakerUtil::getInstance().speak(QString("人脸重复注册,请重试")); - LOG(DEBUG) << "人脸已经注册" << ui->inputName->text().toStdString(); + SpeakerUtil::getInstance().speak(QString("人脸已注册其他人,请重试")); + LOG(DEBUG) << "人脸已注册其他人" << ui->inputName->text().toStdString(); } } } @@ -288,19 +288,20 @@ // 停止拍图 ProMemory::getInstance().irisCam->stopCapture(); - ProMemory::getInstance().irisRegistPro->setWorking(false); - // 语音提示 - SpeakerUtil::getInstance().speak(QString("虹膜重复注册,请重试")); - if (this->personId.isEmpty() == true) { // 情况1 新注册 重复注册 loadPersonInfo(personIdByIris); + + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已经注册,请重试")); LOG(DEBUG) << "虹膜已经注册" << ui->inputName->text().toStdString(); } else { - LOG(DEBUG) << "虹膜已经注册" << personIdByIris.toStdString(); + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已注册其他人,请重试")); + LOG(DEBUG) << "虹膜已注册其他人" << personIdByIris.toStdString(); } } diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index 45fe761..f202cfe 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -30,6 +30,7 @@ initFaceRegistThread(); // 人脸注册线程 initFaceRecogThread(); // 人脸识别线程 initIrisRegistThread(); // 虹膜注册线程 + initIrisRecogThread(); // 虹膜识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); @@ -67,6 +68,10 @@ ProMemory::getInstance().irisRegistPro->deleteLater(); ProMemory::getInstance().irisRegistPro->wait(); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + // 关闭自动启动的外部程序 // outExe->close(); // delete outExe; @@ -75,6 +80,7 @@ delete ProMemory::getInstance().faceRegistPro; delete ProMemory::getInstance().faceRecogPro; delete ProMemory::getInstance().irisRegistPro; + delete ProMemory::getInstance().irisRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -194,15 +200,17 @@ void CasicBioRecWin::initFaceRecogThread() { // 人脸识别处理过程 - ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + ProMemory::getInstance().faceRecogPro = new FaceRecogProcess(this); // 绑定信号与槽函数 // 识别成功 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, - recogResultForm, &RecognizeResultForm::showRecognizeResult); +// connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); // 识别失败 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchFailure, recogResultForm, &RecognizeResultForm::showRecogFailure); ProMemory::getInstance().faceRecogPro->start(); @@ -222,9 +230,28 @@ connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::captureIrisFailure, addPersonForm, &AddPersonForm::onFailedCaptureIris); - // 采集虹膜图像成功 有匹配到红魔库 + // 采集虹膜图像成功 有匹配到虹膜库 connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::findMatchedIris, addPersonForm, &AddPersonForm::onMatchedIris); ProMemory::getInstance().irisRegistPro->start(); } + +void CasicBioRecWin::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 +// connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index ff2ed35..b70245a 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -53,6 +53,7 @@ void initFaceRegistThread(); void initFaceRecogThread(); void initIrisRegistThread(); + void initIrisRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp index b61cb09..e45a191 100644 --- a/RecognizeResultForm.cpp +++ b/RecognizeResultForm.cpp @@ -26,10 +26,28 @@ void RecognizeResultForm::startWorkingRecognize() { // 开始人脸识别 - ProMemory::getInstance().faceRecogPro->setWorking(true); + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + // 人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + break; + case 2: + // 虹膜识别 + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + case 3: + case 4: + // 人脸和虹膜都需要打开 + ProMemory::getInstance().faceRecogPro->setWorking(true); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + } // 将界面切换到识别界面 RecognizeResultForm ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + ui->labBackground->raise(); // 1人脸图像显示的容器 ui->labVideo->resize(1280, 720); @@ -63,13 +81,17 @@ ui->widgetFail->show(); QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ - emit backToHomeAndWait(); - CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; + + emit backToHomeAndWait(); }); } void RecognizeResultForm::showRecognizeResult(QString personId) { + personIdByFace = ""; + personIdByIris = ""; + SpeakerUtil::getInstance().speak("识别成功"); ui->labVideo->hide(); ui->labTitle->hide(); @@ -102,8 +124,131 @@ ui->widgetSucc->show(); QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ - emit backToHomeAndWait(); CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + + emit backToHomeAndWait(); }); } + +void RecognizeResultForm::checkRecognizeResult(QString personId, int faceOrIris) +{ + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + { + // 仅人脸识别 + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 人脸识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 2: + { + // 仅虹膜识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜识别成功 [%1]").arg(CasicIrisRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "2"); + record.insert("debug_info", CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 4: + { + // 任意识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + QString logStr = QString("[RecognizeResultForm]%1识别成功[%2]"); + if (faceOrIris == 1) + { + logStr.arg("人脸").arg(CasicFaceRecState::getInstance().toString()); + } else if (faceOrIris == 2) + { + logStr.arg("虹膜").arg(CasicIrisRecState::getInstance().toString()); + } + LOG(DEBUG) << logStr.toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", QString::number(faceOrIris)); + record.insert("debug_info", faceOrIris == 1 ? CasicFaceRecState::getInstance().toString() : CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 3: + if (faceOrIris == 1) + { + this->personIdByFace = personId; + } else if (faceOrIris == 2) + { + this->personIdByIris = personId; + } + + if (personIdByFace.isEmpty() || personIdByIris.isEmpty()) + { + // 只有一个成功的结果 需要等待下次 + return; + } else if (personIdByFace != personIdByIris) + { + // 人脸和虹膜识别的不是同一人 识别失败 + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜与人脸识别结果不一致,识别失败 [face: %1][iris: %2]").arg(personIdByFace).arg(personIdByIris).toStdString(); + SpeakerUtil::getInstance().speak("虹膜与人脸识别结果不一致,识别失败,请重试"); + showRecogFailure(); + } else + { + LOG(DEBUG) << QString("[RecognizeResultForm]人脸虹膜识别成功").toStdString(); + showRecognizeResult(personId); + } + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "4"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString() + " " + CasicIrisRecState::getInstance().toString()); + recDao.save(record); + } +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h index f5ef019..2c51865 100644 --- a/RecognizeResultForm.h +++ b/RecognizeResultForm.h @@ -25,7 +25,8 @@ public slots: void showRecogFailure(); - void showRecognizeResult(QString personId); + + void checkRecognizeResult(QString personId, int faceOrIris); void startWorkingRecognize(); // 开始工作 void drawImageOnHomeForm(QImage imageDisp); @@ -33,6 +34,11 @@ private: Ui::RecognizeResultForm *ui; + QString personIdByFace; + QString personIdByIris; + + void showRecognizeResult(QString personId); + signals: void backToHomeAndWait(); // 识别结束 返回主界面并待机 diff --git a/StartupForm.cpp b/StartupForm.cpp index 3d3dfad..16c4dfc 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -29,8 +29,8 @@ // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); -// connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, -// this, &StartupForm::takeOneFrameForCheckStatus); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); TimeCounterUtil::getInstance().clockCounter->start(1000); } @@ -54,6 +54,12 @@ return; } + if (this->isVisible() == false) + { + // 没有在这个页面直接返回 + return; + } + // 不在这个页面 则直接返回 不做后续判断 if (ProMemory::getInstance().widgeFrame != CasicBioRecConst::WidgeFrameName::MAIN_PAGE) { @@ -61,10 +67,25 @@ } cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); - bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + + // 判断是否开始工作时使用严格标准 人脸大小需要符合注册图像的尺寸 + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(rawFrame, SettingConfig::getInstance().MIN_WORK_FACE_SIZE); + if (faceRect.width == 0) + { + return ; + } + + bool hasFace = faceRect.width == 0 ? false : true; + if (faceRect.x < SettingConfig::getInstance().MIN_WORK_FACE_POSX || faceRect.x > SettingConfig::getInstance().MAX_WORK_FACE_POSX || + faceRect.y < SettingConfig::getInstance().MIN_WORK_FACE_POSY || faceRect.y > SettingConfig::getInstance().MAX_WORK_FACE_POSY) + { + // 检测到的人脸不在核心区则返回 + hasFace = false; + } + if (hasFace == true) { - LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + LOG(INFO) << QString("检测到人脸,START RECOGNIZE 线程").toStdString(); ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; // 启动识别线程 diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index d14fd54..05fe5f1 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -258,8 +258,8 @@ // 情况3 编辑时非本人 人脸重复 // 语音提示 - SpeakerUtil::getInstance().speak(QString("人脸重复注册,请重试")); - LOG(DEBUG) << "人脸已经注册" << ui->inputName->text().toStdString(); + SpeakerUtil::getInstance().speak(QString("人脸已注册其他人,请重试")); + LOG(DEBUG) << "人脸已注册其他人" << ui->inputName->text().toStdString(); } } } @@ -288,19 +288,20 @@ // 停止拍图 ProMemory::getInstance().irisCam->stopCapture(); - ProMemory::getInstance().irisRegistPro->setWorking(false); - // 语音提示 - SpeakerUtil::getInstance().speak(QString("虹膜重复注册,请重试")); - if (this->personId.isEmpty() == true) { // 情况1 新注册 重复注册 loadPersonInfo(personIdByIris); + + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已经注册,请重试")); LOG(DEBUG) << "虹膜已经注册" << ui->inputName->text().toStdString(); } else { - LOG(DEBUG) << "虹膜已经注册" << personIdByIris.toStdString(); + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已注册其他人,请重试")); + LOG(DEBUG) << "虹膜已注册其他人" << personIdByIris.toStdString(); } } diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index 45fe761..f202cfe 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -30,6 +30,7 @@ initFaceRegistThread(); // 人脸注册线程 initFaceRecogThread(); // 人脸识别线程 initIrisRegistThread(); // 虹膜注册线程 + initIrisRecogThread(); // 虹膜识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); @@ -67,6 +68,10 @@ ProMemory::getInstance().irisRegistPro->deleteLater(); ProMemory::getInstance().irisRegistPro->wait(); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + // 关闭自动启动的外部程序 // outExe->close(); // delete outExe; @@ -75,6 +80,7 @@ delete ProMemory::getInstance().faceRegistPro; delete ProMemory::getInstance().faceRecogPro; delete ProMemory::getInstance().irisRegistPro; + delete ProMemory::getInstance().irisRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -194,15 +200,17 @@ void CasicBioRecWin::initFaceRecogThread() { // 人脸识别处理过程 - ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + ProMemory::getInstance().faceRecogPro = new FaceRecogProcess(this); // 绑定信号与槽函数 // 识别成功 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, - recogResultForm, &RecognizeResultForm::showRecognizeResult); +// connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); // 识别失败 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchFailure, recogResultForm, &RecognizeResultForm::showRecogFailure); ProMemory::getInstance().faceRecogPro->start(); @@ -222,9 +230,28 @@ connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::captureIrisFailure, addPersonForm, &AddPersonForm::onFailedCaptureIris); - // 采集虹膜图像成功 有匹配到红魔库 + // 采集虹膜图像成功 有匹配到虹膜库 connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::findMatchedIris, addPersonForm, &AddPersonForm::onMatchedIris); ProMemory::getInstance().irisRegistPro->start(); } + +void CasicBioRecWin::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 +// connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index ff2ed35..b70245a 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -53,6 +53,7 @@ void initFaceRegistThread(); void initFaceRecogThread(); void initIrisRegistThread(); + void initIrisRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp index b61cb09..e45a191 100644 --- a/RecognizeResultForm.cpp +++ b/RecognizeResultForm.cpp @@ -26,10 +26,28 @@ void RecognizeResultForm::startWorkingRecognize() { // 开始人脸识别 - ProMemory::getInstance().faceRecogPro->setWorking(true); + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + // 人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + break; + case 2: + // 虹膜识别 + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + case 3: + case 4: + // 人脸和虹膜都需要打开 + ProMemory::getInstance().faceRecogPro->setWorking(true); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + } // 将界面切换到识别界面 RecognizeResultForm ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + ui->labBackground->raise(); // 1人脸图像显示的容器 ui->labVideo->resize(1280, 720); @@ -63,13 +81,17 @@ ui->widgetFail->show(); QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ - emit backToHomeAndWait(); - CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; + + emit backToHomeAndWait(); }); } void RecognizeResultForm::showRecognizeResult(QString personId) { + personIdByFace = ""; + personIdByIris = ""; + SpeakerUtil::getInstance().speak("识别成功"); ui->labVideo->hide(); ui->labTitle->hide(); @@ -102,8 +124,131 @@ ui->widgetSucc->show(); QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ - emit backToHomeAndWait(); CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + + emit backToHomeAndWait(); }); } + +void RecognizeResultForm::checkRecognizeResult(QString personId, int faceOrIris) +{ + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + { + // 仅人脸识别 + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 人脸识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 2: + { + // 仅虹膜识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜识别成功 [%1]").arg(CasicIrisRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "2"); + record.insert("debug_info", CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 4: + { + // 任意识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + QString logStr = QString("[RecognizeResultForm]%1识别成功[%2]"); + if (faceOrIris == 1) + { + logStr.arg("人脸").arg(CasicFaceRecState::getInstance().toString()); + } else if (faceOrIris == 2) + { + logStr.arg("虹膜").arg(CasicIrisRecState::getInstance().toString()); + } + LOG(DEBUG) << logStr.toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", QString::number(faceOrIris)); + record.insert("debug_info", faceOrIris == 1 ? CasicFaceRecState::getInstance().toString() : CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 3: + if (faceOrIris == 1) + { + this->personIdByFace = personId; + } else if (faceOrIris == 2) + { + this->personIdByIris = personId; + } + + if (personIdByFace.isEmpty() || personIdByIris.isEmpty()) + { + // 只有一个成功的结果 需要等待下次 + return; + } else if (personIdByFace != personIdByIris) + { + // 人脸和虹膜识别的不是同一人 识别失败 + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜与人脸识别结果不一致,识别失败 [face: %1][iris: %2]").arg(personIdByFace).arg(personIdByIris).toStdString(); + SpeakerUtil::getInstance().speak("虹膜与人脸识别结果不一致,识别失败,请重试"); + showRecogFailure(); + } else + { + LOG(DEBUG) << QString("[RecognizeResultForm]人脸虹膜识别成功").toStdString(); + showRecognizeResult(personId); + } + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "4"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString() + " " + CasicIrisRecState::getInstance().toString()); + recDao.save(record); + } +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h index f5ef019..2c51865 100644 --- a/RecognizeResultForm.h +++ b/RecognizeResultForm.h @@ -25,7 +25,8 @@ public slots: void showRecogFailure(); - void showRecognizeResult(QString personId); + + void checkRecognizeResult(QString personId, int faceOrIris); void startWorkingRecognize(); // 开始工作 void drawImageOnHomeForm(QImage imageDisp); @@ -33,6 +34,11 @@ private: Ui::RecognizeResultForm *ui; + QString personIdByFace; + QString personIdByIris; + + void showRecognizeResult(QString personId); + signals: void backToHomeAndWait(); // 识别结束 返回主界面并待机 diff --git a/StartupForm.cpp b/StartupForm.cpp index 3d3dfad..16c4dfc 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -29,8 +29,8 @@ // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); -// connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, -// this, &StartupForm::takeOneFrameForCheckStatus); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); TimeCounterUtil::getInstance().clockCounter->start(1000); } @@ -54,6 +54,12 @@ return; } + if (this->isVisible() == false) + { + // 没有在这个页面直接返回 + return; + } + // 不在这个页面 则直接返回 不做后续判断 if (ProMemory::getInstance().widgeFrame != CasicBioRecConst::WidgeFrameName::MAIN_PAGE) { @@ -61,10 +67,25 @@ } cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); - bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + + // 判断是否开始工作时使用严格标准 人脸大小需要符合注册图像的尺寸 + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(rawFrame, SettingConfig::getInstance().MIN_WORK_FACE_SIZE); + if (faceRect.width == 0) + { + return ; + } + + bool hasFace = faceRect.width == 0 ? false : true; + if (faceRect.x < SettingConfig::getInstance().MIN_WORK_FACE_POSX || faceRect.x > SettingConfig::getInstance().MAX_WORK_FACE_POSX || + faceRect.y < SettingConfig::getInstance().MIN_WORK_FACE_POSY || faceRect.y > SettingConfig::getInstance().MAX_WORK_FACE_POSY) + { + // 检测到的人脸不在核心区则返回 + hasFace = false; + } + if (hasFace == true) { - LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + LOG(INFO) << QString("检测到人脸,START RECOGNIZE 线程").toStdString(); ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; // 启动识别线程 diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 1bc7d3a..3e9fbd4 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -13,14 +13,16 @@ #include "device/FaceCameraController.h" #include "device/IrisCameraController.h" #include "device/face/FaceRegistProcess.h" -#include "device/face/FaceDetectRecogProcess.h" +#include "device/face/FaceRecogProcess.h" #include "device/iris/IrisRegistProcess.h" +#include "device/iris/IrisRecogProcess.h" class FaceCameraController; class IrisCameraController; class FaceRegistProcess; -class FaceDetectRecogProcess; +class FaceRecogProcess; class IrisRegistProcess; +class IrisRecogProcess; class ProMemory { @@ -58,18 +60,17 @@ FaceCameraController * faceCam; FaceRegistProcess * faceRegistPro; - FaceDetectRecogProcess * faceRecogPro; + FaceRecogProcess * faceRecogPro; IrisCameraController * irisCam; IrisRegistProcess * irisRegistPro; + IrisRecogProcess * irisRecogPro; private: ProMemory(); QStack faceQueue; // 人脸信息队列 QStack irisQueue; // 虹膜信息队列 -// QStack irisLeftQueue; // 左眼信息队列 -// QStack irisRightQueue; // 右眼信息队列 QVector faceFeatures; // 人脸特征值集合 QVector irisFeatures; // 虹膜特征值集合 diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index d14fd54..05fe5f1 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -258,8 +258,8 @@ // 情况3 编辑时非本人 人脸重复 // 语音提示 - SpeakerUtil::getInstance().speak(QString("人脸重复注册,请重试")); - LOG(DEBUG) << "人脸已经注册" << ui->inputName->text().toStdString(); + SpeakerUtil::getInstance().speak(QString("人脸已注册其他人,请重试")); + LOG(DEBUG) << "人脸已注册其他人" << ui->inputName->text().toStdString(); } } } @@ -288,19 +288,20 @@ // 停止拍图 ProMemory::getInstance().irisCam->stopCapture(); - ProMemory::getInstance().irisRegistPro->setWorking(false); - // 语音提示 - SpeakerUtil::getInstance().speak(QString("虹膜重复注册,请重试")); - if (this->personId.isEmpty() == true) { // 情况1 新注册 重复注册 loadPersonInfo(personIdByIris); + + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已经注册,请重试")); LOG(DEBUG) << "虹膜已经注册" << ui->inputName->text().toStdString(); } else { - LOG(DEBUG) << "虹膜已经注册" << personIdByIris.toStdString(); + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已注册其他人,请重试")); + LOG(DEBUG) << "虹膜已注册其他人" << personIdByIris.toStdString(); } } diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index 45fe761..f202cfe 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -30,6 +30,7 @@ initFaceRegistThread(); // 人脸注册线程 initFaceRecogThread(); // 人脸识别线程 initIrisRegistThread(); // 虹膜注册线程 + initIrisRecogThread(); // 虹膜识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); @@ -67,6 +68,10 @@ ProMemory::getInstance().irisRegistPro->deleteLater(); ProMemory::getInstance().irisRegistPro->wait(); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + // 关闭自动启动的外部程序 // outExe->close(); // delete outExe; @@ -75,6 +80,7 @@ delete ProMemory::getInstance().faceRegistPro; delete ProMemory::getInstance().faceRecogPro; delete ProMemory::getInstance().irisRegistPro; + delete ProMemory::getInstance().irisRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -194,15 +200,17 @@ void CasicBioRecWin::initFaceRecogThread() { // 人脸识别处理过程 - ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + ProMemory::getInstance().faceRecogPro = new FaceRecogProcess(this); // 绑定信号与槽函数 // 识别成功 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, - recogResultForm, &RecognizeResultForm::showRecognizeResult); +// connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); // 识别失败 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchFailure, recogResultForm, &RecognizeResultForm::showRecogFailure); ProMemory::getInstance().faceRecogPro->start(); @@ -222,9 +230,28 @@ connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::captureIrisFailure, addPersonForm, &AddPersonForm::onFailedCaptureIris); - // 采集虹膜图像成功 有匹配到红魔库 + // 采集虹膜图像成功 有匹配到虹膜库 connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::findMatchedIris, addPersonForm, &AddPersonForm::onMatchedIris); ProMemory::getInstance().irisRegistPro->start(); } + +void CasicBioRecWin::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 +// connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index ff2ed35..b70245a 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -53,6 +53,7 @@ void initFaceRegistThread(); void initFaceRecogThread(); void initIrisRegistThread(); + void initIrisRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp index b61cb09..e45a191 100644 --- a/RecognizeResultForm.cpp +++ b/RecognizeResultForm.cpp @@ -26,10 +26,28 @@ void RecognizeResultForm::startWorkingRecognize() { // 开始人脸识别 - ProMemory::getInstance().faceRecogPro->setWorking(true); + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + // 人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + break; + case 2: + // 虹膜识别 + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + case 3: + case 4: + // 人脸和虹膜都需要打开 + ProMemory::getInstance().faceRecogPro->setWorking(true); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + } // 将界面切换到识别界面 RecognizeResultForm ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + ui->labBackground->raise(); // 1人脸图像显示的容器 ui->labVideo->resize(1280, 720); @@ -63,13 +81,17 @@ ui->widgetFail->show(); QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ - emit backToHomeAndWait(); - CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; + + emit backToHomeAndWait(); }); } void RecognizeResultForm::showRecognizeResult(QString personId) { + personIdByFace = ""; + personIdByIris = ""; + SpeakerUtil::getInstance().speak("识别成功"); ui->labVideo->hide(); ui->labTitle->hide(); @@ -102,8 +124,131 @@ ui->widgetSucc->show(); QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ - emit backToHomeAndWait(); CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + + emit backToHomeAndWait(); }); } + +void RecognizeResultForm::checkRecognizeResult(QString personId, int faceOrIris) +{ + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + { + // 仅人脸识别 + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 人脸识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 2: + { + // 仅虹膜识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜识别成功 [%1]").arg(CasicIrisRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "2"); + record.insert("debug_info", CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 4: + { + // 任意识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + QString logStr = QString("[RecognizeResultForm]%1识别成功[%2]"); + if (faceOrIris == 1) + { + logStr.arg("人脸").arg(CasicFaceRecState::getInstance().toString()); + } else if (faceOrIris == 2) + { + logStr.arg("虹膜").arg(CasicIrisRecState::getInstance().toString()); + } + LOG(DEBUG) << logStr.toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", QString::number(faceOrIris)); + record.insert("debug_info", faceOrIris == 1 ? CasicFaceRecState::getInstance().toString() : CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 3: + if (faceOrIris == 1) + { + this->personIdByFace = personId; + } else if (faceOrIris == 2) + { + this->personIdByIris = personId; + } + + if (personIdByFace.isEmpty() || personIdByIris.isEmpty()) + { + // 只有一个成功的结果 需要等待下次 + return; + } else if (personIdByFace != personIdByIris) + { + // 人脸和虹膜识别的不是同一人 识别失败 + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜与人脸识别结果不一致,识别失败 [face: %1][iris: %2]").arg(personIdByFace).arg(personIdByIris).toStdString(); + SpeakerUtil::getInstance().speak("虹膜与人脸识别结果不一致,识别失败,请重试"); + showRecogFailure(); + } else + { + LOG(DEBUG) << QString("[RecognizeResultForm]人脸虹膜识别成功").toStdString(); + showRecognizeResult(personId); + } + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "4"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString() + " " + CasicIrisRecState::getInstance().toString()); + recDao.save(record); + } +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h index f5ef019..2c51865 100644 --- a/RecognizeResultForm.h +++ b/RecognizeResultForm.h @@ -25,7 +25,8 @@ public slots: void showRecogFailure(); - void showRecognizeResult(QString personId); + + void checkRecognizeResult(QString personId, int faceOrIris); void startWorkingRecognize(); // 开始工作 void drawImageOnHomeForm(QImage imageDisp); @@ -33,6 +34,11 @@ private: Ui::RecognizeResultForm *ui; + QString personIdByFace; + QString personIdByIris; + + void showRecognizeResult(QString personId); + signals: void backToHomeAndWait(); // 识别结束 返回主界面并待机 diff --git a/StartupForm.cpp b/StartupForm.cpp index 3d3dfad..16c4dfc 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -29,8 +29,8 @@ // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); -// connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, -// this, &StartupForm::takeOneFrameForCheckStatus); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); TimeCounterUtil::getInstance().clockCounter->start(1000); } @@ -54,6 +54,12 @@ return; } + if (this->isVisible() == false) + { + // 没有在这个页面直接返回 + return; + } + // 不在这个页面 则直接返回 不做后续判断 if (ProMemory::getInstance().widgeFrame != CasicBioRecConst::WidgeFrameName::MAIN_PAGE) { @@ -61,10 +67,25 @@ } cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); - bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + + // 判断是否开始工作时使用严格标准 人脸大小需要符合注册图像的尺寸 + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(rawFrame, SettingConfig::getInstance().MIN_WORK_FACE_SIZE); + if (faceRect.width == 0) + { + return ; + } + + bool hasFace = faceRect.width == 0 ? false : true; + if (faceRect.x < SettingConfig::getInstance().MIN_WORK_FACE_POSX || faceRect.x > SettingConfig::getInstance().MAX_WORK_FACE_POSX || + faceRect.y < SettingConfig::getInstance().MIN_WORK_FACE_POSY || faceRect.y > SettingConfig::getInstance().MAX_WORK_FACE_POSY) + { + // 检测到的人脸不在核心区则返回 + hasFace = false; + } + if (hasFace == true) { - LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + LOG(INFO) << QString("检测到人脸,START RECOGNIZE 线程").toStdString(); ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; // 启动识别线程 diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 1bc7d3a..3e9fbd4 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -13,14 +13,16 @@ #include "device/FaceCameraController.h" #include "device/IrisCameraController.h" #include "device/face/FaceRegistProcess.h" -#include "device/face/FaceDetectRecogProcess.h" +#include "device/face/FaceRecogProcess.h" #include "device/iris/IrisRegistProcess.h" +#include "device/iris/IrisRecogProcess.h" class FaceCameraController; class IrisCameraController; class FaceRegistProcess; -class FaceDetectRecogProcess; +class FaceRecogProcess; class IrisRegistProcess; +class IrisRecogProcess; class ProMemory { @@ -58,18 +60,17 @@ FaceCameraController * faceCam; FaceRegistProcess * faceRegistPro; - FaceDetectRecogProcess * faceRecogPro; + FaceRecogProcess * faceRecogPro; IrisCameraController * irisCam; IrisRegistProcess * irisRegistPro; + IrisRecogProcess * irisRecogPro; private: ProMemory(); QStack faceQueue; // 人脸信息队列 QStack irisQueue; // 虹膜信息队列 -// QStack irisLeftQueue; // 左眼信息队列 -// QStack irisRightQueue; // 右眼信息队列 QVector faceFeatures; // 人脸特征值集合 QVector irisFeatures; // 虹膜特征值集合 diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index cb4d3bd..f530212 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -372,6 +372,28 @@ return rect.at(0); } +cv::Rect casic::face::CasicFaceInterface::faceDetectByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + if (rect.size() == 0) + { + return cv::Rect(0, 0, 0, 0); + } + return rect.at(0); +} + cv::Rect casic::face::CasicFaceInterface::eyeDetectByCVCascade(cv::Mat frame) { // 构建openCV自带的眼睛分类器 @@ -402,23 +424,6 @@ return rect.at(0); } -bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) -{ - // 构建OpenCV自带的人脸分类器 - if (this->cascade == nullptr) { - this->cascade = new cv::CascadeClassifier(); - this->cascade->load(cvFaceCascadeName); - } - - std::vector rect; - cv::Size minRectSize(minFaceSize, minFaceSize); - cv::Size maxRectSize(maxFaceSize, maxFaceSize); - - // ★分类器对象调用 - cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); - - return rect.size() == 0 ? false : true; -} bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) { // 构建openCV自带的眼睛分类器 diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index d14fd54..05fe5f1 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -258,8 +258,8 @@ // 情况3 编辑时非本人 人脸重复 // 语音提示 - SpeakerUtil::getInstance().speak(QString("人脸重复注册,请重试")); - LOG(DEBUG) << "人脸已经注册" << ui->inputName->text().toStdString(); + SpeakerUtil::getInstance().speak(QString("人脸已注册其他人,请重试")); + LOG(DEBUG) << "人脸已注册其他人" << ui->inputName->text().toStdString(); } } } @@ -288,19 +288,20 @@ // 停止拍图 ProMemory::getInstance().irisCam->stopCapture(); - ProMemory::getInstance().irisRegistPro->setWorking(false); - // 语音提示 - SpeakerUtil::getInstance().speak(QString("虹膜重复注册,请重试")); - if (this->personId.isEmpty() == true) { // 情况1 新注册 重复注册 loadPersonInfo(personIdByIris); + + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已经注册,请重试")); LOG(DEBUG) << "虹膜已经注册" << ui->inputName->text().toStdString(); } else { - LOG(DEBUG) << "虹膜已经注册" << personIdByIris.toStdString(); + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已注册其他人,请重试")); + LOG(DEBUG) << "虹膜已注册其他人" << personIdByIris.toStdString(); } } diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index 45fe761..f202cfe 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -30,6 +30,7 @@ initFaceRegistThread(); // 人脸注册线程 initFaceRecogThread(); // 人脸识别线程 initIrisRegistThread(); // 虹膜注册线程 + initIrisRecogThread(); // 虹膜识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); @@ -67,6 +68,10 @@ ProMemory::getInstance().irisRegistPro->deleteLater(); ProMemory::getInstance().irisRegistPro->wait(); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + // 关闭自动启动的外部程序 // outExe->close(); // delete outExe; @@ -75,6 +80,7 @@ delete ProMemory::getInstance().faceRegistPro; delete ProMemory::getInstance().faceRecogPro; delete ProMemory::getInstance().irisRegistPro; + delete ProMemory::getInstance().irisRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -194,15 +200,17 @@ void CasicBioRecWin::initFaceRecogThread() { // 人脸识别处理过程 - ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + ProMemory::getInstance().faceRecogPro = new FaceRecogProcess(this); // 绑定信号与槽函数 // 识别成功 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, - recogResultForm, &RecognizeResultForm::showRecognizeResult); +// connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); // 识别失败 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchFailure, recogResultForm, &RecognizeResultForm::showRecogFailure); ProMemory::getInstance().faceRecogPro->start(); @@ -222,9 +230,28 @@ connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::captureIrisFailure, addPersonForm, &AddPersonForm::onFailedCaptureIris); - // 采集虹膜图像成功 有匹配到红魔库 + // 采集虹膜图像成功 有匹配到虹膜库 connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::findMatchedIris, addPersonForm, &AddPersonForm::onMatchedIris); ProMemory::getInstance().irisRegistPro->start(); } + +void CasicBioRecWin::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 +// connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index ff2ed35..b70245a 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -53,6 +53,7 @@ void initFaceRegistThread(); void initFaceRecogThread(); void initIrisRegistThread(); + void initIrisRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp index b61cb09..e45a191 100644 --- a/RecognizeResultForm.cpp +++ b/RecognizeResultForm.cpp @@ -26,10 +26,28 @@ void RecognizeResultForm::startWorkingRecognize() { // 开始人脸识别 - ProMemory::getInstance().faceRecogPro->setWorking(true); + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + // 人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + break; + case 2: + // 虹膜识别 + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + case 3: + case 4: + // 人脸和虹膜都需要打开 + ProMemory::getInstance().faceRecogPro->setWorking(true); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + } // 将界面切换到识别界面 RecognizeResultForm ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + ui->labBackground->raise(); // 1人脸图像显示的容器 ui->labVideo->resize(1280, 720); @@ -63,13 +81,17 @@ ui->widgetFail->show(); QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ - emit backToHomeAndWait(); - CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; + + emit backToHomeAndWait(); }); } void RecognizeResultForm::showRecognizeResult(QString personId) { + personIdByFace = ""; + personIdByIris = ""; + SpeakerUtil::getInstance().speak("识别成功"); ui->labVideo->hide(); ui->labTitle->hide(); @@ -102,8 +124,131 @@ ui->widgetSucc->show(); QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ - emit backToHomeAndWait(); CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + + emit backToHomeAndWait(); }); } + +void RecognizeResultForm::checkRecognizeResult(QString personId, int faceOrIris) +{ + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + { + // 仅人脸识别 + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 人脸识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 2: + { + // 仅虹膜识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜识别成功 [%1]").arg(CasicIrisRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "2"); + record.insert("debug_info", CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 4: + { + // 任意识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + QString logStr = QString("[RecognizeResultForm]%1识别成功[%2]"); + if (faceOrIris == 1) + { + logStr.arg("人脸").arg(CasicFaceRecState::getInstance().toString()); + } else if (faceOrIris == 2) + { + logStr.arg("虹膜").arg(CasicIrisRecState::getInstance().toString()); + } + LOG(DEBUG) << logStr.toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", QString::number(faceOrIris)); + record.insert("debug_info", faceOrIris == 1 ? CasicFaceRecState::getInstance().toString() : CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 3: + if (faceOrIris == 1) + { + this->personIdByFace = personId; + } else if (faceOrIris == 2) + { + this->personIdByIris = personId; + } + + if (personIdByFace.isEmpty() || personIdByIris.isEmpty()) + { + // 只有一个成功的结果 需要等待下次 + return; + } else if (personIdByFace != personIdByIris) + { + // 人脸和虹膜识别的不是同一人 识别失败 + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜与人脸识别结果不一致,识别失败 [face: %1][iris: %2]").arg(personIdByFace).arg(personIdByIris).toStdString(); + SpeakerUtil::getInstance().speak("虹膜与人脸识别结果不一致,识别失败,请重试"); + showRecogFailure(); + } else + { + LOG(DEBUG) << QString("[RecognizeResultForm]人脸虹膜识别成功").toStdString(); + showRecognizeResult(personId); + } + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "4"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString() + " " + CasicIrisRecState::getInstance().toString()); + recDao.save(record); + } +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h index f5ef019..2c51865 100644 --- a/RecognizeResultForm.h +++ b/RecognizeResultForm.h @@ -25,7 +25,8 @@ public slots: void showRecogFailure(); - void showRecognizeResult(QString personId); + + void checkRecognizeResult(QString personId, int faceOrIris); void startWorkingRecognize(); // 开始工作 void drawImageOnHomeForm(QImage imageDisp); @@ -33,6 +34,11 @@ private: Ui::RecognizeResultForm *ui; + QString personIdByFace; + QString personIdByIris; + + void showRecognizeResult(QString personId); + signals: void backToHomeAndWait(); // 识别结束 返回主界面并待机 diff --git a/StartupForm.cpp b/StartupForm.cpp index 3d3dfad..16c4dfc 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -29,8 +29,8 @@ // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); -// connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, -// this, &StartupForm::takeOneFrameForCheckStatus); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); TimeCounterUtil::getInstance().clockCounter->start(1000); } @@ -54,6 +54,12 @@ return; } + if (this->isVisible() == false) + { + // 没有在这个页面直接返回 + return; + } + // 不在这个页面 则直接返回 不做后续判断 if (ProMemory::getInstance().widgeFrame != CasicBioRecConst::WidgeFrameName::MAIN_PAGE) { @@ -61,10 +67,25 @@ } cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); - bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + + // 判断是否开始工作时使用严格标准 人脸大小需要符合注册图像的尺寸 + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(rawFrame, SettingConfig::getInstance().MIN_WORK_FACE_SIZE); + if (faceRect.width == 0) + { + return ; + } + + bool hasFace = faceRect.width == 0 ? false : true; + if (faceRect.x < SettingConfig::getInstance().MIN_WORK_FACE_POSX || faceRect.x > SettingConfig::getInstance().MAX_WORK_FACE_POSX || + faceRect.y < SettingConfig::getInstance().MIN_WORK_FACE_POSY || faceRect.y > SettingConfig::getInstance().MAX_WORK_FACE_POSY) + { + // 检测到的人脸不在核心区则返回 + hasFace = false; + } + if (hasFace == true) { - LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + LOG(INFO) << QString("检测到人脸,START RECOGNIZE 线程").toStdString(); ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; // 启动识别线程 diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 1bc7d3a..3e9fbd4 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -13,14 +13,16 @@ #include "device/FaceCameraController.h" #include "device/IrisCameraController.h" #include "device/face/FaceRegistProcess.h" -#include "device/face/FaceDetectRecogProcess.h" +#include "device/face/FaceRecogProcess.h" #include "device/iris/IrisRegistProcess.h" +#include "device/iris/IrisRecogProcess.h" class FaceCameraController; class IrisCameraController; class FaceRegistProcess; -class FaceDetectRecogProcess; +class FaceRecogProcess; class IrisRegistProcess; +class IrisRecogProcess; class ProMemory { @@ -58,18 +60,17 @@ FaceCameraController * faceCam; FaceRegistProcess * faceRegistPro; - FaceDetectRecogProcess * faceRecogPro; + FaceRecogProcess * faceRecogPro; IrisCameraController * irisCam; IrisRegistProcess * irisRegistPro; + IrisRecogProcess * irisRecogPro; private: ProMemory(); QStack faceQueue; // 人脸信息队列 QStack irisQueue; // 虹膜信息队列 -// QStack irisLeftQueue; // 左眼信息队列 -// QStack irisRightQueue; // 右眼信息队列 QVector faceFeatures; // 人脸特征值集合 QVector irisFeatures; // 虹膜特征值集合 diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index cb4d3bd..f530212 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -372,6 +372,28 @@ return rect.at(0); } +cv::Rect casic::face::CasicFaceInterface::faceDetectByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + if (rect.size() == 0) + { + return cv::Rect(0, 0, 0, 0); + } + return rect.at(0); +} + cv::Rect casic::face::CasicFaceInterface::eyeDetectByCVCascade(cv::Mat frame) { // 构建openCV自带的眼睛分类器 @@ -402,23 +424,6 @@ return rect.at(0); } -bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) -{ - // 构建OpenCV自带的人脸分类器 - if (this->cascade == nullptr) { - this->cascade = new cv::CascadeClassifier(); - this->cascade->load(cvFaceCascadeName); - } - - std::vector rect; - cv::Size minRectSize(minFaceSize, minFaceSize); - cv::Size maxRectSize(maxFaceSize, maxFaceSize); - - // ★分类器对象调用 - cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); - - return rect.size() == 0 ? false : true; -} bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) { // 构建openCV自带的眼睛分类器 diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index 8a1c564..9d8b8ea 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -1,4 +1,4 @@ -#ifndef CASICFACEINTERFACE_H +#ifndef CASICFACEINTERFACE_H #define CASICFACEINTERFACE_H #include "opencv2/opencv.hpp" @@ -49,8 +49,9 @@ float faceSimCalculate(float* feature, float* otherFeature); cv::Rect faceDetectByCVCascade(cv::Mat frame); + cv::Rect faceDetectByCVCascade(cv::Mat frame, int minFaceSize); + cv::Rect eyeDetectByCVCascade(cv::Mat frame); - bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); @@ -68,7 +69,7 @@ int minFaceSize = 320; int maxFaceSize = 720; int minEyeSize = 100; - int maxEyeSize = 600; + int maxEyeSize = 300; std::string detectorModelPath = "./model/face_detector.csta"; std::string markPts5ModelPath = "./model/face_landmarker_pts5.csta"; diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index d14fd54..05fe5f1 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -258,8 +258,8 @@ // 情况3 编辑时非本人 人脸重复 // 语音提示 - SpeakerUtil::getInstance().speak(QString("人脸重复注册,请重试")); - LOG(DEBUG) << "人脸已经注册" << ui->inputName->text().toStdString(); + SpeakerUtil::getInstance().speak(QString("人脸已注册其他人,请重试")); + LOG(DEBUG) << "人脸已注册其他人" << ui->inputName->text().toStdString(); } } } @@ -288,19 +288,20 @@ // 停止拍图 ProMemory::getInstance().irisCam->stopCapture(); - ProMemory::getInstance().irisRegistPro->setWorking(false); - // 语音提示 - SpeakerUtil::getInstance().speak(QString("虹膜重复注册,请重试")); - if (this->personId.isEmpty() == true) { // 情况1 新注册 重复注册 loadPersonInfo(personIdByIris); + + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已经注册,请重试")); LOG(DEBUG) << "虹膜已经注册" << ui->inputName->text().toStdString(); } else { - LOG(DEBUG) << "虹膜已经注册" << personIdByIris.toStdString(); + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已注册其他人,请重试")); + LOG(DEBUG) << "虹膜已注册其他人" << personIdByIris.toStdString(); } } diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index 45fe761..f202cfe 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -30,6 +30,7 @@ initFaceRegistThread(); // 人脸注册线程 initFaceRecogThread(); // 人脸识别线程 initIrisRegistThread(); // 虹膜注册线程 + initIrisRecogThread(); // 虹膜识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); @@ -67,6 +68,10 @@ ProMemory::getInstance().irisRegistPro->deleteLater(); ProMemory::getInstance().irisRegistPro->wait(); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + // 关闭自动启动的外部程序 // outExe->close(); // delete outExe; @@ -75,6 +80,7 @@ delete ProMemory::getInstance().faceRegistPro; delete ProMemory::getInstance().faceRecogPro; delete ProMemory::getInstance().irisRegistPro; + delete ProMemory::getInstance().irisRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -194,15 +200,17 @@ void CasicBioRecWin::initFaceRecogThread() { // 人脸识别处理过程 - ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + ProMemory::getInstance().faceRecogPro = new FaceRecogProcess(this); // 绑定信号与槽函数 // 识别成功 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, - recogResultForm, &RecognizeResultForm::showRecognizeResult); +// connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); // 识别失败 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchFailure, recogResultForm, &RecognizeResultForm::showRecogFailure); ProMemory::getInstance().faceRecogPro->start(); @@ -222,9 +230,28 @@ connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::captureIrisFailure, addPersonForm, &AddPersonForm::onFailedCaptureIris); - // 采集虹膜图像成功 有匹配到红魔库 + // 采集虹膜图像成功 有匹配到虹膜库 connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::findMatchedIris, addPersonForm, &AddPersonForm::onMatchedIris); ProMemory::getInstance().irisRegistPro->start(); } + +void CasicBioRecWin::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 +// connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index ff2ed35..b70245a 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -53,6 +53,7 @@ void initFaceRegistThread(); void initFaceRecogThread(); void initIrisRegistThread(); + void initIrisRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp index b61cb09..e45a191 100644 --- a/RecognizeResultForm.cpp +++ b/RecognizeResultForm.cpp @@ -26,10 +26,28 @@ void RecognizeResultForm::startWorkingRecognize() { // 开始人脸识别 - ProMemory::getInstance().faceRecogPro->setWorking(true); + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + // 人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + break; + case 2: + // 虹膜识别 + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + case 3: + case 4: + // 人脸和虹膜都需要打开 + ProMemory::getInstance().faceRecogPro->setWorking(true); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + } // 将界面切换到识别界面 RecognizeResultForm ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + ui->labBackground->raise(); // 1人脸图像显示的容器 ui->labVideo->resize(1280, 720); @@ -63,13 +81,17 @@ ui->widgetFail->show(); QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ - emit backToHomeAndWait(); - CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; + + emit backToHomeAndWait(); }); } void RecognizeResultForm::showRecognizeResult(QString personId) { + personIdByFace = ""; + personIdByIris = ""; + SpeakerUtil::getInstance().speak("识别成功"); ui->labVideo->hide(); ui->labTitle->hide(); @@ -102,8 +124,131 @@ ui->widgetSucc->show(); QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ - emit backToHomeAndWait(); CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + + emit backToHomeAndWait(); }); } + +void RecognizeResultForm::checkRecognizeResult(QString personId, int faceOrIris) +{ + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + { + // 仅人脸识别 + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 人脸识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 2: + { + // 仅虹膜识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜识别成功 [%1]").arg(CasicIrisRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "2"); + record.insert("debug_info", CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 4: + { + // 任意识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + QString logStr = QString("[RecognizeResultForm]%1识别成功[%2]"); + if (faceOrIris == 1) + { + logStr.arg("人脸").arg(CasicFaceRecState::getInstance().toString()); + } else if (faceOrIris == 2) + { + logStr.arg("虹膜").arg(CasicIrisRecState::getInstance().toString()); + } + LOG(DEBUG) << logStr.toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", QString::number(faceOrIris)); + record.insert("debug_info", faceOrIris == 1 ? CasicFaceRecState::getInstance().toString() : CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 3: + if (faceOrIris == 1) + { + this->personIdByFace = personId; + } else if (faceOrIris == 2) + { + this->personIdByIris = personId; + } + + if (personIdByFace.isEmpty() || personIdByIris.isEmpty()) + { + // 只有一个成功的结果 需要等待下次 + return; + } else if (personIdByFace != personIdByIris) + { + // 人脸和虹膜识别的不是同一人 识别失败 + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜与人脸识别结果不一致,识别失败 [face: %1][iris: %2]").arg(personIdByFace).arg(personIdByIris).toStdString(); + SpeakerUtil::getInstance().speak("虹膜与人脸识别结果不一致,识别失败,请重试"); + showRecogFailure(); + } else + { + LOG(DEBUG) << QString("[RecognizeResultForm]人脸虹膜识别成功").toStdString(); + showRecognizeResult(personId); + } + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "4"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString() + " " + CasicIrisRecState::getInstance().toString()); + recDao.save(record); + } +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h index f5ef019..2c51865 100644 --- a/RecognizeResultForm.h +++ b/RecognizeResultForm.h @@ -25,7 +25,8 @@ public slots: void showRecogFailure(); - void showRecognizeResult(QString personId); + + void checkRecognizeResult(QString personId, int faceOrIris); void startWorkingRecognize(); // 开始工作 void drawImageOnHomeForm(QImage imageDisp); @@ -33,6 +34,11 @@ private: Ui::RecognizeResultForm *ui; + QString personIdByFace; + QString personIdByIris; + + void showRecognizeResult(QString personId); + signals: void backToHomeAndWait(); // 识别结束 返回主界面并待机 diff --git a/StartupForm.cpp b/StartupForm.cpp index 3d3dfad..16c4dfc 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -29,8 +29,8 @@ // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); -// connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, -// this, &StartupForm::takeOneFrameForCheckStatus); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); TimeCounterUtil::getInstance().clockCounter->start(1000); } @@ -54,6 +54,12 @@ return; } + if (this->isVisible() == false) + { + // 没有在这个页面直接返回 + return; + } + // 不在这个页面 则直接返回 不做后续判断 if (ProMemory::getInstance().widgeFrame != CasicBioRecConst::WidgeFrameName::MAIN_PAGE) { @@ -61,10 +67,25 @@ } cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); - bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + + // 判断是否开始工作时使用严格标准 人脸大小需要符合注册图像的尺寸 + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(rawFrame, SettingConfig::getInstance().MIN_WORK_FACE_SIZE); + if (faceRect.width == 0) + { + return ; + } + + bool hasFace = faceRect.width == 0 ? false : true; + if (faceRect.x < SettingConfig::getInstance().MIN_WORK_FACE_POSX || faceRect.x > SettingConfig::getInstance().MAX_WORK_FACE_POSX || + faceRect.y < SettingConfig::getInstance().MIN_WORK_FACE_POSY || faceRect.y > SettingConfig::getInstance().MAX_WORK_FACE_POSY) + { + // 检测到的人脸不在核心区则返回 + hasFace = false; + } + if (hasFace == true) { - LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + LOG(INFO) << QString("检测到人脸,START RECOGNIZE 线程").toStdString(); ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; // 启动识别线程 diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 1bc7d3a..3e9fbd4 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -13,14 +13,16 @@ #include "device/FaceCameraController.h" #include "device/IrisCameraController.h" #include "device/face/FaceRegistProcess.h" -#include "device/face/FaceDetectRecogProcess.h" +#include "device/face/FaceRecogProcess.h" #include "device/iris/IrisRegistProcess.h" +#include "device/iris/IrisRecogProcess.h" class FaceCameraController; class IrisCameraController; class FaceRegistProcess; -class FaceDetectRecogProcess; +class FaceRecogProcess; class IrisRegistProcess; +class IrisRecogProcess; class ProMemory { @@ -58,18 +60,17 @@ FaceCameraController * faceCam; FaceRegistProcess * faceRegistPro; - FaceDetectRecogProcess * faceRecogPro; + FaceRecogProcess * faceRecogPro; IrisCameraController * irisCam; IrisRegistProcess * irisRegistPro; + IrisRecogProcess * irisRecogPro; private: ProMemory(); QStack faceQueue; // 人脸信息队列 QStack irisQueue; // 虹膜信息队列 -// QStack irisLeftQueue; // 左眼信息队列 -// QStack irisRightQueue; // 右眼信息队列 QVector faceFeatures; // 人脸特征值集合 QVector irisFeatures; // 虹膜特征值集合 diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index cb4d3bd..f530212 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -372,6 +372,28 @@ return rect.at(0); } +cv::Rect casic::face::CasicFaceInterface::faceDetectByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + if (rect.size() == 0) + { + return cv::Rect(0, 0, 0, 0); + } + return rect.at(0); +} + cv::Rect casic::face::CasicFaceInterface::eyeDetectByCVCascade(cv::Mat frame) { // 构建openCV自带的眼睛分类器 @@ -402,23 +424,6 @@ return rect.at(0); } -bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) -{ - // 构建OpenCV自带的人脸分类器 - if (this->cascade == nullptr) { - this->cascade = new cv::CascadeClassifier(); - this->cascade->load(cvFaceCascadeName); - } - - std::vector rect; - cv::Size minRectSize(minFaceSize, minFaceSize); - cv::Size maxRectSize(maxFaceSize, maxFaceSize); - - // ★分类器对象调用 - cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); - - return rect.size() == 0 ? false : true; -} bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) { // 构建openCV自带的眼睛分类器 diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index 8a1c564..9d8b8ea 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -1,4 +1,4 @@ -#ifndef CASICFACEINTERFACE_H +#ifndef CASICFACEINTERFACE_H #define CASICFACEINTERFACE_H #include "opencv2/opencv.hpp" @@ -49,8 +49,9 @@ float faceSimCalculate(float* feature, float* otherFeature); cv::Rect faceDetectByCVCascade(cv::Mat frame); + cv::Rect faceDetectByCVCascade(cv::Mat frame, int minFaceSize); + cv::Rect eyeDetectByCVCascade(cv::Mat frame); - bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); @@ -68,7 +69,7 @@ int minFaceSize = 320; int maxFaceSize = 720; int minEyeSize = 100; - int maxEyeSize = 600; + int maxEyeSize = 300; std::string detectorModelPath = "./model/face_detector.csta"; std::string markPts5ModelPath = "./model/face_landmarker_pts5.csta"; diff --git a/conf/config.ini b/conf/config.ini index 84e31c9..79045a6 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -1,4 +1,4 @@ -[com] +[com] #电机控制的串口名 motoPortName=COM3 @@ -17,6 +17,10 @@ maxFaceTryCount=20 #持续没找到人脸的最大次数 maxFaceNotFoundCount=500 +#注册时最小人脸 +minFaceRegist=240 +#识别时最小人脸 +minFaceRecog=100 #虹膜识别最大尝试次数 maxIrisTryCount=10 @@ -34,6 +38,18 @@ #统一背景色 backgroundColor="#FFFFFF" +[work] +#工作状态检测时最小人脸范围 +minFaceSize=160 +#人脸范围最小横坐标 +minFacePosX=320 +#人脸范围最大横坐标 +maxFacePosX=960 +#人脸范围最小纵坐标 +minFacePosY=180 +#人脸范围最大纵坐标 +maxFacePosY=540 + [camera] #人脸摄像头的编号 faceIndex=1 @@ -53,11 +69,3 @@ irisWidth=640 #虹膜图像高度 irisHeight=480 - -[stack] -#拍摄图像栈最大值 -capture=50 -#找到的眼睛图像栈最大值 -found=30 -#质量合格图像栈最大值 -qualified=30 diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index d14fd54..05fe5f1 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -258,8 +258,8 @@ // 情况3 编辑时非本人 人脸重复 // 语音提示 - SpeakerUtil::getInstance().speak(QString("人脸重复注册,请重试")); - LOG(DEBUG) << "人脸已经注册" << ui->inputName->text().toStdString(); + SpeakerUtil::getInstance().speak(QString("人脸已注册其他人,请重试")); + LOG(DEBUG) << "人脸已注册其他人" << ui->inputName->text().toStdString(); } } } @@ -288,19 +288,20 @@ // 停止拍图 ProMemory::getInstance().irisCam->stopCapture(); - ProMemory::getInstance().irisRegistPro->setWorking(false); - // 语音提示 - SpeakerUtil::getInstance().speak(QString("虹膜重复注册,请重试")); - if (this->personId.isEmpty() == true) { // 情况1 新注册 重复注册 loadPersonInfo(personIdByIris); + + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已经注册,请重试")); LOG(DEBUG) << "虹膜已经注册" << ui->inputName->text().toStdString(); } else { - LOG(DEBUG) << "虹膜已经注册" << personIdByIris.toStdString(); + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已注册其他人,请重试")); + LOG(DEBUG) << "虹膜已注册其他人" << personIdByIris.toStdString(); } } diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index 45fe761..f202cfe 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -30,6 +30,7 @@ initFaceRegistThread(); // 人脸注册线程 initFaceRecogThread(); // 人脸识别线程 initIrisRegistThread(); // 虹膜注册线程 + initIrisRecogThread(); // 虹膜识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); @@ -67,6 +68,10 @@ ProMemory::getInstance().irisRegistPro->deleteLater(); ProMemory::getInstance().irisRegistPro->wait(); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + // 关闭自动启动的外部程序 // outExe->close(); // delete outExe; @@ -75,6 +80,7 @@ delete ProMemory::getInstance().faceRegistPro; delete ProMemory::getInstance().faceRecogPro; delete ProMemory::getInstance().irisRegistPro; + delete ProMemory::getInstance().irisRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -194,15 +200,17 @@ void CasicBioRecWin::initFaceRecogThread() { // 人脸识别处理过程 - ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + ProMemory::getInstance().faceRecogPro = new FaceRecogProcess(this); // 绑定信号与槽函数 // 识别成功 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, - recogResultForm, &RecognizeResultForm::showRecognizeResult); +// connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); // 识别失败 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchFailure, recogResultForm, &RecognizeResultForm::showRecogFailure); ProMemory::getInstance().faceRecogPro->start(); @@ -222,9 +230,28 @@ connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::captureIrisFailure, addPersonForm, &AddPersonForm::onFailedCaptureIris); - // 采集虹膜图像成功 有匹配到红魔库 + // 采集虹膜图像成功 有匹配到虹膜库 connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::findMatchedIris, addPersonForm, &AddPersonForm::onMatchedIris); ProMemory::getInstance().irisRegistPro->start(); } + +void CasicBioRecWin::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 +// connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index ff2ed35..b70245a 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -53,6 +53,7 @@ void initFaceRegistThread(); void initFaceRecogThread(); void initIrisRegistThread(); + void initIrisRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp index b61cb09..e45a191 100644 --- a/RecognizeResultForm.cpp +++ b/RecognizeResultForm.cpp @@ -26,10 +26,28 @@ void RecognizeResultForm::startWorkingRecognize() { // 开始人脸识别 - ProMemory::getInstance().faceRecogPro->setWorking(true); + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + // 人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + break; + case 2: + // 虹膜识别 + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + case 3: + case 4: + // 人脸和虹膜都需要打开 + ProMemory::getInstance().faceRecogPro->setWorking(true); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + } // 将界面切换到识别界面 RecognizeResultForm ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + ui->labBackground->raise(); // 1人脸图像显示的容器 ui->labVideo->resize(1280, 720); @@ -63,13 +81,17 @@ ui->widgetFail->show(); QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ - emit backToHomeAndWait(); - CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; + + emit backToHomeAndWait(); }); } void RecognizeResultForm::showRecognizeResult(QString personId) { + personIdByFace = ""; + personIdByIris = ""; + SpeakerUtil::getInstance().speak("识别成功"); ui->labVideo->hide(); ui->labTitle->hide(); @@ -102,8 +124,131 @@ ui->widgetSucc->show(); QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ - emit backToHomeAndWait(); CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + + emit backToHomeAndWait(); }); } + +void RecognizeResultForm::checkRecognizeResult(QString personId, int faceOrIris) +{ + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + { + // 仅人脸识别 + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 人脸识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 2: + { + // 仅虹膜识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜识别成功 [%1]").arg(CasicIrisRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "2"); + record.insert("debug_info", CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 4: + { + // 任意识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + QString logStr = QString("[RecognizeResultForm]%1识别成功[%2]"); + if (faceOrIris == 1) + { + logStr.arg("人脸").arg(CasicFaceRecState::getInstance().toString()); + } else if (faceOrIris == 2) + { + logStr.arg("虹膜").arg(CasicIrisRecState::getInstance().toString()); + } + LOG(DEBUG) << logStr.toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", QString::number(faceOrIris)); + record.insert("debug_info", faceOrIris == 1 ? CasicFaceRecState::getInstance().toString() : CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 3: + if (faceOrIris == 1) + { + this->personIdByFace = personId; + } else if (faceOrIris == 2) + { + this->personIdByIris = personId; + } + + if (personIdByFace.isEmpty() || personIdByIris.isEmpty()) + { + // 只有一个成功的结果 需要等待下次 + return; + } else if (personIdByFace != personIdByIris) + { + // 人脸和虹膜识别的不是同一人 识别失败 + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜与人脸识别结果不一致,识别失败 [face: %1][iris: %2]").arg(personIdByFace).arg(personIdByIris).toStdString(); + SpeakerUtil::getInstance().speak("虹膜与人脸识别结果不一致,识别失败,请重试"); + showRecogFailure(); + } else + { + LOG(DEBUG) << QString("[RecognizeResultForm]人脸虹膜识别成功").toStdString(); + showRecognizeResult(personId); + } + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "4"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString() + " " + CasicIrisRecState::getInstance().toString()); + recDao.save(record); + } +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h index f5ef019..2c51865 100644 --- a/RecognizeResultForm.h +++ b/RecognizeResultForm.h @@ -25,7 +25,8 @@ public slots: void showRecogFailure(); - void showRecognizeResult(QString personId); + + void checkRecognizeResult(QString personId, int faceOrIris); void startWorkingRecognize(); // 开始工作 void drawImageOnHomeForm(QImage imageDisp); @@ -33,6 +34,11 @@ private: Ui::RecognizeResultForm *ui; + QString personIdByFace; + QString personIdByIris; + + void showRecognizeResult(QString personId); + signals: void backToHomeAndWait(); // 识别结束 返回主界面并待机 diff --git a/StartupForm.cpp b/StartupForm.cpp index 3d3dfad..16c4dfc 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -29,8 +29,8 @@ // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); -// connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, -// this, &StartupForm::takeOneFrameForCheckStatus); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); TimeCounterUtil::getInstance().clockCounter->start(1000); } @@ -54,6 +54,12 @@ return; } + if (this->isVisible() == false) + { + // 没有在这个页面直接返回 + return; + } + // 不在这个页面 则直接返回 不做后续判断 if (ProMemory::getInstance().widgeFrame != CasicBioRecConst::WidgeFrameName::MAIN_PAGE) { @@ -61,10 +67,25 @@ } cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); - bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + + // 判断是否开始工作时使用严格标准 人脸大小需要符合注册图像的尺寸 + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(rawFrame, SettingConfig::getInstance().MIN_WORK_FACE_SIZE); + if (faceRect.width == 0) + { + return ; + } + + bool hasFace = faceRect.width == 0 ? false : true; + if (faceRect.x < SettingConfig::getInstance().MIN_WORK_FACE_POSX || faceRect.x > SettingConfig::getInstance().MAX_WORK_FACE_POSX || + faceRect.y < SettingConfig::getInstance().MIN_WORK_FACE_POSY || faceRect.y > SettingConfig::getInstance().MAX_WORK_FACE_POSY) + { + // 检测到的人脸不在核心区则返回 + hasFace = false; + } + if (hasFace == true) { - LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + LOG(INFO) << QString("检测到人脸,START RECOGNIZE 线程").toStdString(); ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; // 启动识别线程 diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 1bc7d3a..3e9fbd4 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -13,14 +13,16 @@ #include "device/FaceCameraController.h" #include "device/IrisCameraController.h" #include "device/face/FaceRegistProcess.h" -#include "device/face/FaceDetectRecogProcess.h" +#include "device/face/FaceRecogProcess.h" #include "device/iris/IrisRegistProcess.h" +#include "device/iris/IrisRecogProcess.h" class FaceCameraController; class IrisCameraController; class FaceRegistProcess; -class FaceDetectRecogProcess; +class FaceRecogProcess; class IrisRegistProcess; +class IrisRecogProcess; class ProMemory { @@ -58,18 +60,17 @@ FaceCameraController * faceCam; FaceRegistProcess * faceRegistPro; - FaceDetectRecogProcess * faceRecogPro; + FaceRecogProcess * faceRecogPro; IrisCameraController * irisCam; IrisRegistProcess * irisRegistPro; + IrisRecogProcess * irisRecogPro; private: ProMemory(); QStack faceQueue; // 人脸信息队列 QStack irisQueue; // 虹膜信息队列 -// QStack irisLeftQueue; // 左眼信息队列 -// QStack irisRightQueue; // 右眼信息队列 QVector faceFeatures; // 人脸特征值集合 QVector irisFeatures; // 虹膜特征值集合 diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index cb4d3bd..f530212 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -372,6 +372,28 @@ return rect.at(0); } +cv::Rect casic::face::CasicFaceInterface::faceDetectByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + if (rect.size() == 0) + { + return cv::Rect(0, 0, 0, 0); + } + return rect.at(0); +} + cv::Rect casic::face::CasicFaceInterface::eyeDetectByCVCascade(cv::Mat frame) { // 构建openCV自带的眼睛分类器 @@ -402,23 +424,6 @@ return rect.at(0); } -bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) -{ - // 构建OpenCV自带的人脸分类器 - if (this->cascade == nullptr) { - this->cascade = new cv::CascadeClassifier(); - this->cascade->load(cvFaceCascadeName); - } - - std::vector rect; - cv::Size minRectSize(minFaceSize, minFaceSize); - cv::Size maxRectSize(maxFaceSize, maxFaceSize); - - // ★分类器对象调用 - cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); - - return rect.size() == 0 ? false : true; -} bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) { // 构建openCV自带的眼睛分类器 diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index 8a1c564..9d8b8ea 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -1,4 +1,4 @@ -#ifndef CASICFACEINTERFACE_H +#ifndef CASICFACEINTERFACE_H #define CASICFACEINTERFACE_H #include "opencv2/opencv.hpp" @@ -49,8 +49,9 @@ float faceSimCalculate(float* feature, float* otherFeature); cv::Rect faceDetectByCVCascade(cv::Mat frame); + cv::Rect faceDetectByCVCascade(cv::Mat frame, int minFaceSize); + cv::Rect eyeDetectByCVCascade(cv::Mat frame); - bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); @@ -68,7 +69,7 @@ int minFaceSize = 320; int maxFaceSize = 720; int minEyeSize = 100; - int maxEyeSize = 600; + int maxEyeSize = 300; std::string detectorModelPath = "./model/face_detector.csta"; std::string markPts5ModelPath = "./model/face_landmarker_pts5.csta"; diff --git a/conf/config.ini b/conf/config.ini index 84e31c9..79045a6 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -1,4 +1,4 @@ -[com] +[com] #电机控制的串口名 motoPortName=COM3 @@ -17,6 +17,10 @@ maxFaceTryCount=20 #持续没找到人脸的最大次数 maxFaceNotFoundCount=500 +#注册时最小人脸 +minFaceRegist=240 +#识别时最小人脸 +minFaceRecog=100 #虹膜识别最大尝试次数 maxIrisTryCount=10 @@ -34,6 +38,18 @@ #统一背景色 backgroundColor="#FFFFFF" +[work] +#工作状态检测时最小人脸范围 +minFaceSize=160 +#人脸范围最小横坐标 +minFacePosX=320 +#人脸范围最大横坐标 +maxFacePosX=960 +#人脸范围最小纵坐标 +minFacePosY=180 +#人脸范围最大纵坐标 +maxFacePosY=540 + [camera] #人脸摄像头的编号 faceIndex=1 @@ -53,11 +69,3 @@ irisWidth=640 #虹膜图像高度 irisHeight=480 - -[stack] -#拍摄图像栈最大值 -capture=50 -#找到的眼睛图像栈最大值 -found=30 -#质量合格图像栈最大值 -qualified=30 diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 25854c3..0fe4b4c 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -63,7 +63,7 @@ cv::Mat faceMatDisp = imageMatMiir.clone(); // 利用人脸分类器进行初步的检测 - cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp); + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp, SettingConfig::getInstance().MIN_FACE_REGIST_SIZE); if (faceRect.width > 0) { // 初筛检测到人脸时将图像入栈 diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index d14fd54..05fe5f1 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -258,8 +258,8 @@ // 情况3 编辑时非本人 人脸重复 // 语音提示 - SpeakerUtil::getInstance().speak(QString("人脸重复注册,请重试")); - LOG(DEBUG) << "人脸已经注册" << ui->inputName->text().toStdString(); + SpeakerUtil::getInstance().speak(QString("人脸已注册其他人,请重试")); + LOG(DEBUG) << "人脸已注册其他人" << ui->inputName->text().toStdString(); } } } @@ -288,19 +288,20 @@ // 停止拍图 ProMemory::getInstance().irisCam->stopCapture(); - ProMemory::getInstance().irisRegistPro->setWorking(false); - // 语音提示 - SpeakerUtil::getInstance().speak(QString("虹膜重复注册,请重试")); - if (this->personId.isEmpty() == true) { // 情况1 新注册 重复注册 loadPersonInfo(personIdByIris); + + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已经注册,请重试")); LOG(DEBUG) << "虹膜已经注册" << ui->inputName->text().toStdString(); } else { - LOG(DEBUG) << "虹膜已经注册" << personIdByIris.toStdString(); + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已注册其他人,请重试")); + LOG(DEBUG) << "虹膜已注册其他人" << personIdByIris.toStdString(); } } diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index 45fe761..f202cfe 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -30,6 +30,7 @@ initFaceRegistThread(); // 人脸注册线程 initFaceRecogThread(); // 人脸识别线程 initIrisRegistThread(); // 虹膜注册线程 + initIrisRecogThread(); // 虹膜识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); @@ -67,6 +68,10 @@ ProMemory::getInstance().irisRegistPro->deleteLater(); ProMemory::getInstance().irisRegistPro->wait(); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + // 关闭自动启动的外部程序 // outExe->close(); // delete outExe; @@ -75,6 +80,7 @@ delete ProMemory::getInstance().faceRegistPro; delete ProMemory::getInstance().faceRecogPro; delete ProMemory::getInstance().irisRegistPro; + delete ProMemory::getInstance().irisRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -194,15 +200,17 @@ void CasicBioRecWin::initFaceRecogThread() { // 人脸识别处理过程 - ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + ProMemory::getInstance().faceRecogPro = new FaceRecogProcess(this); // 绑定信号与槽函数 // 识别成功 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, - recogResultForm, &RecognizeResultForm::showRecognizeResult); +// connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); // 识别失败 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchFailure, recogResultForm, &RecognizeResultForm::showRecogFailure); ProMemory::getInstance().faceRecogPro->start(); @@ -222,9 +230,28 @@ connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::captureIrisFailure, addPersonForm, &AddPersonForm::onFailedCaptureIris); - // 采集虹膜图像成功 有匹配到红魔库 + // 采集虹膜图像成功 有匹配到虹膜库 connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::findMatchedIris, addPersonForm, &AddPersonForm::onMatchedIris); ProMemory::getInstance().irisRegistPro->start(); } + +void CasicBioRecWin::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 +// connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index ff2ed35..b70245a 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -53,6 +53,7 @@ void initFaceRegistThread(); void initFaceRecogThread(); void initIrisRegistThread(); + void initIrisRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp index b61cb09..e45a191 100644 --- a/RecognizeResultForm.cpp +++ b/RecognizeResultForm.cpp @@ -26,10 +26,28 @@ void RecognizeResultForm::startWorkingRecognize() { // 开始人脸识别 - ProMemory::getInstance().faceRecogPro->setWorking(true); + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + // 人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + break; + case 2: + // 虹膜识别 + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + case 3: + case 4: + // 人脸和虹膜都需要打开 + ProMemory::getInstance().faceRecogPro->setWorking(true); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + } // 将界面切换到识别界面 RecognizeResultForm ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + ui->labBackground->raise(); // 1人脸图像显示的容器 ui->labVideo->resize(1280, 720); @@ -63,13 +81,17 @@ ui->widgetFail->show(); QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ - emit backToHomeAndWait(); - CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; + + emit backToHomeAndWait(); }); } void RecognizeResultForm::showRecognizeResult(QString personId) { + personIdByFace = ""; + personIdByIris = ""; + SpeakerUtil::getInstance().speak("识别成功"); ui->labVideo->hide(); ui->labTitle->hide(); @@ -102,8 +124,131 @@ ui->widgetSucc->show(); QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ - emit backToHomeAndWait(); CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + + emit backToHomeAndWait(); }); } + +void RecognizeResultForm::checkRecognizeResult(QString personId, int faceOrIris) +{ + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + { + // 仅人脸识别 + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 人脸识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 2: + { + // 仅虹膜识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜识别成功 [%1]").arg(CasicIrisRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "2"); + record.insert("debug_info", CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 4: + { + // 任意识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + QString logStr = QString("[RecognizeResultForm]%1识别成功[%2]"); + if (faceOrIris == 1) + { + logStr.arg("人脸").arg(CasicFaceRecState::getInstance().toString()); + } else if (faceOrIris == 2) + { + logStr.arg("虹膜").arg(CasicIrisRecState::getInstance().toString()); + } + LOG(DEBUG) << logStr.toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", QString::number(faceOrIris)); + record.insert("debug_info", faceOrIris == 1 ? CasicFaceRecState::getInstance().toString() : CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 3: + if (faceOrIris == 1) + { + this->personIdByFace = personId; + } else if (faceOrIris == 2) + { + this->personIdByIris = personId; + } + + if (personIdByFace.isEmpty() || personIdByIris.isEmpty()) + { + // 只有一个成功的结果 需要等待下次 + return; + } else if (personIdByFace != personIdByIris) + { + // 人脸和虹膜识别的不是同一人 识别失败 + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜与人脸识别结果不一致,识别失败 [face: %1][iris: %2]").arg(personIdByFace).arg(personIdByIris).toStdString(); + SpeakerUtil::getInstance().speak("虹膜与人脸识别结果不一致,识别失败,请重试"); + showRecogFailure(); + } else + { + LOG(DEBUG) << QString("[RecognizeResultForm]人脸虹膜识别成功").toStdString(); + showRecognizeResult(personId); + } + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "4"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString() + " " + CasicIrisRecState::getInstance().toString()); + recDao.save(record); + } +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h index f5ef019..2c51865 100644 --- a/RecognizeResultForm.h +++ b/RecognizeResultForm.h @@ -25,7 +25,8 @@ public slots: void showRecogFailure(); - void showRecognizeResult(QString personId); + + void checkRecognizeResult(QString personId, int faceOrIris); void startWorkingRecognize(); // 开始工作 void drawImageOnHomeForm(QImage imageDisp); @@ -33,6 +34,11 @@ private: Ui::RecognizeResultForm *ui; + QString personIdByFace; + QString personIdByIris; + + void showRecognizeResult(QString personId); + signals: void backToHomeAndWait(); // 识别结束 返回主界面并待机 diff --git a/StartupForm.cpp b/StartupForm.cpp index 3d3dfad..16c4dfc 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -29,8 +29,8 @@ // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); -// connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, -// this, &StartupForm::takeOneFrameForCheckStatus); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); TimeCounterUtil::getInstance().clockCounter->start(1000); } @@ -54,6 +54,12 @@ return; } + if (this->isVisible() == false) + { + // 没有在这个页面直接返回 + return; + } + // 不在这个页面 则直接返回 不做后续判断 if (ProMemory::getInstance().widgeFrame != CasicBioRecConst::WidgeFrameName::MAIN_PAGE) { @@ -61,10 +67,25 @@ } cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); - bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + + // 判断是否开始工作时使用严格标准 人脸大小需要符合注册图像的尺寸 + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(rawFrame, SettingConfig::getInstance().MIN_WORK_FACE_SIZE); + if (faceRect.width == 0) + { + return ; + } + + bool hasFace = faceRect.width == 0 ? false : true; + if (faceRect.x < SettingConfig::getInstance().MIN_WORK_FACE_POSX || faceRect.x > SettingConfig::getInstance().MAX_WORK_FACE_POSX || + faceRect.y < SettingConfig::getInstance().MIN_WORK_FACE_POSY || faceRect.y > SettingConfig::getInstance().MAX_WORK_FACE_POSY) + { + // 检测到的人脸不在核心区则返回 + hasFace = false; + } + if (hasFace == true) { - LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + LOG(INFO) << QString("检测到人脸,START RECOGNIZE 线程").toStdString(); ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; // 启动识别线程 diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 1bc7d3a..3e9fbd4 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -13,14 +13,16 @@ #include "device/FaceCameraController.h" #include "device/IrisCameraController.h" #include "device/face/FaceRegistProcess.h" -#include "device/face/FaceDetectRecogProcess.h" +#include "device/face/FaceRecogProcess.h" #include "device/iris/IrisRegistProcess.h" +#include "device/iris/IrisRecogProcess.h" class FaceCameraController; class IrisCameraController; class FaceRegistProcess; -class FaceDetectRecogProcess; +class FaceRecogProcess; class IrisRegistProcess; +class IrisRecogProcess; class ProMemory { @@ -58,18 +60,17 @@ FaceCameraController * faceCam; FaceRegistProcess * faceRegistPro; - FaceDetectRecogProcess * faceRecogPro; + FaceRecogProcess * faceRecogPro; IrisCameraController * irisCam; IrisRegistProcess * irisRegistPro; + IrisRecogProcess * irisRecogPro; private: ProMemory(); QStack faceQueue; // 人脸信息队列 QStack irisQueue; // 虹膜信息队列 -// QStack irisLeftQueue; // 左眼信息队列 -// QStack irisRightQueue; // 右眼信息队列 QVector faceFeatures; // 人脸特征值集合 QVector irisFeatures; // 虹膜特征值集合 diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index cb4d3bd..f530212 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -372,6 +372,28 @@ return rect.at(0); } +cv::Rect casic::face::CasicFaceInterface::faceDetectByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + if (rect.size() == 0) + { + return cv::Rect(0, 0, 0, 0); + } + return rect.at(0); +} + cv::Rect casic::face::CasicFaceInterface::eyeDetectByCVCascade(cv::Mat frame) { // 构建openCV自带的眼睛分类器 @@ -402,23 +424,6 @@ return rect.at(0); } -bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) -{ - // 构建OpenCV自带的人脸分类器 - if (this->cascade == nullptr) { - this->cascade = new cv::CascadeClassifier(); - this->cascade->load(cvFaceCascadeName); - } - - std::vector rect; - cv::Size minRectSize(minFaceSize, minFaceSize); - cv::Size maxRectSize(maxFaceSize, maxFaceSize); - - // ★分类器对象调用 - cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); - - return rect.size() == 0 ? false : true; -} bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) { // 构建openCV自带的眼睛分类器 diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index 8a1c564..9d8b8ea 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -1,4 +1,4 @@ -#ifndef CASICFACEINTERFACE_H +#ifndef CASICFACEINTERFACE_H #define CASICFACEINTERFACE_H #include "opencv2/opencv.hpp" @@ -49,8 +49,9 @@ float faceSimCalculate(float* feature, float* otherFeature); cv::Rect faceDetectByCVCascade(cv::Mat frame); + cv::Rect faceDetectByCVCascade(cv::Mat frame, int minFaceSize); + cv::Rect eyeDetectByCVCascade(cv::Mat frame); - bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); @@ -68,7 +69,7 @@ int minFaceSize = 320; int maxFaceSize = 720; int minEyeSize = 100; - int maxEyeSize = 600; + int maxEyeSize = 300; std::string detectorModelPath = "./model/face_detector.csta"; std::string markPts5ModelPath = "./model/face_landmarker_pts5.csta"; diff --git a/conf/config.ini b/conf/config.ini index 84e31c9..79045a6 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -1,4 +1,4 @@ -[com] +[com] #电机控制的串口名 motoPortName=COM3 @@ -17,6 +17,10 @@ maxFaceTryCount=20 #持续没找到人脸的最大次数 maxFaceNotFoundCount=500 +#注册时最小人脸 +minFaceRegist=240 +#识别时最小人脸 +minFaceRecog=100 #虹膜识别最大尝试次数 maxIrisTryCount=10 @@ -34,6 +38,18 @@ #统一背景色 backgroundColor="#FFFFFF" +[work] +#工作状态检测时最小人脸范围 +minFaceSize=160 +#人脸范围最小横坐标 +minFacePosX=320 +#人脸范围最大横坐标 +maxFacePosX=960 +#人脸范围最小纵坐标 +minFacePosY=180 +#人脸范围最大纵坐标 +maxFacePosY=540 + [camera] #人脸摄像头的编号 faceIndex=1 @@ -53,11 +69,3 @@ irisWidth=640 #虹膜图像高度 irisHeight=480 - -[stack] -#拍摄图像栈最大值 -capture=50 -#找到的眼睛图像栈最大值 -found=30 -#质量合格图像栈最大值 -qualified=30 diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 25854c3..0fe4b4c 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -63,7 +63,7 @@ cv::Mat faceMatDisp = imageMatMiir.clone(); // 利用人脸分类器进行初步的检测 - cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp); + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp, SettingConfig::getInstance().MIN_FACE_REGIST_SIZE); if (faceRect.width > 0) { // 初筛检测到人脸时将图像入栈 diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index da744f5..151de09 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -34,7 +34,7 @@ irisInfo.leftOrRight = "right"; } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::MAIN_PAGE) + if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) { // 相机拍摄下的图像1280*960, 直接用于算法判断 QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); @@ -43,7 +43,6 @@ irisInfo.data = imgDisp; irisInfo.matData = irisMat; - // 识别过程任意一个眼睛都行, 全部存入左眼队列 ProMemory::getInstance().pushCasicIris(irisInfo); } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) { diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index d14fd54..05fe5f1 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -258,8 +258,8 @@ // 情况3 编辑时非本人 人脸重复 // 语音提示 - SpeakerUtil::getInstance().speak(QString("人脸重复注册,请重试")); - LOG(DEBUG) << "人脸已经注册" << ui->inputName->text().toStdString(); + SpeakerUtil::getInstance().speak(QString("人脸已注册其他人,请重试")); + LOG(DEBUG) << "人脸已注册其他人" << ui->inputName->text().toStdString(); } } } @@ -288,19 +288,20 @@ // 停止拍图 ProMemory::getInstance().irisCam->stopCapture(); - ProMemory::getInstance().irisRegistPro->setWorking(false); - // 语音提示 - SpeakerUtil::getInstance().speak(QString("虹膜重复注册,请重试")); - if (this->personId.isEmpty() == true) { // 情况1 新注册 重复注册 loadPersonInfo(personIdByIris); + + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已经注册,请重试")); LOG(DEBUG) << "虹膜已经注册" << ui->inputName->text().toStdString(); } else { - LOG(DEBUG) << "虹膜已经注册" << personIdByIris.toStdString(); + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已注册其他人,请重试")); + LOG(DEBUG) << "虹膜已注册其他人" << personIdByIris.toStdString(); } } diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index 45fe761..f202cfe 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -30,6 +30,7 @@ initFaceRegistThread(); // 人脸注册线程 initFaceRecogThread(); // 人脸识别线程 initIrisRegistThread(); // 虹膜注册线程 + initIrisRecogThread(); // 虹膜识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); @@ -67,6 +68,10 @@ ProMemory::getInstance().irisRegistPro->deleteLater(); ProMemory::getInstance().irisRegistPro->wait(); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + // 关闭自动启动的外部程序 // outExe->close(); // delete outExe; @@ -75,6 +80,7 @@ delete ProMemory::getInstance().faceRegistPro; delete ProMemory::getInstance().faceRecogPro; delete ProMemory::getInstance().irisRegistPro; + delete ProMemory::getInstance().irisRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -194,15 +200,17 @@ void CasicBioRecWin::initFaceRecogThread() { // 人脸识别处理过程 - ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + ProMemory::getInstance().faceRecogPro = new FaceRecogProcess(this); // 绑定信号与槽函数 // 识别成功 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, - recogResultForm, &RecognizeResultForm::showRecognizeResult); +// connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); // 识别失败 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchFailure, recogResultForm, &RecognizeResultForm::showRecogFailure); ProMemory::getInstance().faceRecogPro->start(); @@ -222,9 +230,28 @@ connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::captureIrisFailure, addPersonForm, &AddPersonForm::onFailedCaptureIris); - // 采集虹膜图像成功 有匹配到红魔库 + // 采集虹膜图像成功 有匹配到虹膜库 connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::findMatchedIris, addPersonForm, &AddPersonForm::onMatchedIris); ProMemory::getInstance().irisRegistPro->start(); } + +void CasicBioRecWin::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 +// connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index ff2ed35..b70245a 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -53,6 +53,7 @@ void initFaceRegistThread(); void initFaceRecogThread(); void initIrisRegistThread(); + void initIrisRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp index b61cb09..e45a191 100644 --- a/RecognizeResultForm.cpp +++ b/RecognizeResultForm.cpp @@ -26,10 +26,28 @@ void RecognizeResultForm::startWorkingRecognize() { // 开始人脸识别 - ProMemory::getInstance().faceRecogPro->setWorking(true); + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + // 人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + break; + case 2: + // 虹膜识别 + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + case 3: + case 4: + // 人脸和虹膜都需要打开 + ProMemory::getInstance().faceRecogPro->setWorking(true); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + } // 将界面切换到识别界面 RecognizeResultForm ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + ui->labBackground->raise(); // 1人脸图像显示的容器 ui->labVideo->resize(1280, 720); @@ -63,13 +81,17 @@ ui->widgetFail->show(); QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ - emit backToHomeAndWait(); - CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; + + emit backToHomeAndWait(); }); } void RecognizeResultForm::showRecognizeResult(QString personId) { + personIdByFace = ""; + personIdByIris = ""; + SpeakerUtil::getInstance().speak("识别成功"); ui->labVideo->hide(); ui->labTitle->hide(); @@ -102,8 +124,131 @@ ui->widgetSucc->show(); QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ - emit backToHomeAndWait(); CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + + emit backToHomeAndWait(); }); } + +void RecognizeResultForm::checkRecognizeResult(QString personId, int faceOrIris) +{ + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + { + // 仅人脸识别 + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 人脸识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 2: + { + // 仅虹膜识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜识别成功 [%1]").arg(CasicIrisRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "2"); + record.insert("debug_info", CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 4: + { + // 任意识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + QString logStr = QString("[RecognizeResultForm]%1识别成功[%2]"); + if (faceOrIris == 1) + { + logStr.arg("人脸").arg(CasicFaceRecState::getInstance().toString()); + } else if (faceOrIris == 2) + { + logStr.arg("虹膜").arg(CasicIrisRecState::getInstance().toString()); + } + LOG(DEBUG) << logStr.toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", QString::number(faceOrIris)); + record.insert("debug_info", faceOrIris == 1 ? CasicFaceRecState::getInstance().toString() : CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 3: + if (faceOrIris == 1) + { + this->personIdByFace = personId; + } else if (faceOrIris == 2) + { + this->personIdByIris = personId; + } + + if (personIdByFace.isEmpty() || personIdByIris.isEmpty()) + { + // 只有一个成功的结果 需要等待下次 + return; + } else if (personIdByFace != personIdByIris) + { + // 人脸和虹膜识别的不是同一人 识别失败 + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜与人脸识别结果不一致,识别失败 [face: %1][iris: %2]").arg(personIdByFace).arg(personIdByIris).toStdString(); + SpeakerUtil::getInstance().speak("虹膜与人脸识别结果不一致,识别失败,请重试"); + showRecogFailure(); + } else + { + LOG(DEBUG) << QString("[RecognizeResultForm]人脸虹膜识别成功").toStdString(); + showRecognizeResult(personId); + } + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "4"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString() + " " + CasicIrisRecState::getInstance().toString()); + recDao.save(record); + } +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h index f5ef019..2c51865 100644 --- a/RecognizeResultForm.h +++ b/RecognizeResultForm.h @@ -25,7 +25,8 @@ public slots: void showRecogFailure(); - void showRecognizeResult(QString personId); + + void checkRecognizeResult(QString personId, int faceOrIris); void startWorkingRecognize(); // 开始工作 void drawImageOnHomeForm(QImage imageDisp); @@ -33,6 +34,11 @@ private: Ui::RecognizeResultForm *ui; + QString personIdByFace; + QString personIdByIris; + + void showRecognizeResult(QString personId); + signals: void backToHomeAndWait(); // 识别结束 返回主界面并待机 diff --git a/StartupForm.cpp b/StartupForm.cpp index 3d3dfad..16c4dfc 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -29,8 +29,8 @@ // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); -// connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, -// this, &StartupForm::takeOneFrameForCheckStatus); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); TimeCounterUtil::getInstance().clockCounter->start(1000); } @@ -54,6 +54,12 @@ return; } + if (this->isVisible() == false) + { + // 没有在这个页面直接返回 + return; + } + // 不在这个页面 则直接返回 不做后续判断 if (ProMemory::getInstance().widgeFrame != CasicBioRecConst::WidgeFrameName::MAIN_PAGE) { @@ -61,10 +67,25 @@ } cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); - bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + + // 判断是否开始工作时使用严格标准 人脸大小需要符合注册图像的尺寸 + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(rawFrame, SettingConfig::getInstance().MIN_WORK_FACE_SIZE); + if (faceRect.width == 0) + { + return ; + } + + bool hasFace = faceRect.width == 0 ? false : true; + if (faceRect.x < SettingConfig::getInstance().MIN_WORK_FACE_POSX || faceRect.x > SettingConfig::getInstance().MAX_WORK_FACE_POSX || + faceRect.y < SettingConfig::getInstance().MIN_WORK_FACE_POSY || faceRect.y > SettingConfig::getInstance().MAX_WORK_FACE_POSY) + { + // 检测到的人脸不在核心区则返回 + hasFace = false; + } + if (hasFace == true) { - LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + LOG(INFO) << QString("检测到人脸,START RECOGNIZE 线程").toStdString(); ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; // 启动识别线程 diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 1bc7d3a..3e9fbd4 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -13,14 +13,16 @@ #include "device/FaceCameraController.h" #include "device/IrisCameraController.h" #include "device/face/FaceRegistProcess.h" -#include "device/face/FaceDetectRecogProcess.h" +#include "device/face/FaceRecogProcess.h" #include "device/iris/IrisRegistProcess.h" +#include "device/iris/IrisRecogProcess.h" class FaceCameraController; class IrisCameraController; class FaceRegistProcess; -class FaceDetectRecogProcess; +class FaceRecogProcess; class IrisRegistProcess; +class IrisRecogProcess; class ProMemory { @@ -58,18 +60,17 @@ FaceCameraController * faceCam; FaceRegistProcess * faceRegistPro; - FaceDetectRecogProcess * faceRecogPro; + FaceRecogProcess * faceRecogPro; IrisCameraController * irisCam; IrisRegistProcess * irisRegistPro; + IrisRecogProcess * irisRecogPro; private: ProMemory(); QStack faceQueue; // 人脸信息队列 QStack irisQueue; // 虹膜信息队列 -// QStack irisLeftQueue; // 左眼信息队列 -// QStack irisRightQueue; // 右眼信息队列 QVector faceFeatures; // 人脸特征值集合 QVector irisFeatures; // 虹膜特征值集合 diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index cb4d3bd..f530212 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -372,6 +372,28 @@ return rect.at(0); } +cv::Rect casic::face::CasicFaceInterface::faceDetectByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + if (rect.size() == 0) + { + return cv::Rect(0, 0, 0, 0); + } + return rect.at(0); +} + cv::Rect casic::face::CasicFaceInterface::eyeDetectByCVCascade(cv::Mat frame) { // 构建openCV自带的眼睛分类器 @@ -402,23 +424,6 @@ return rect.at(0); } -bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) -{ - // 构建OpenCV自带的人脸分类器 - if (this->cascade == nullptr) { - this->cascade = new cv::CascadeClassifier(); - this->cascade->load(cvFaceCascadeName); - } - - std::vector rect; - cv::Size minRectSize(minFaceSize, minFaceSize); - cv::Size maxRectSize(maxFaceSize, maxFaceSize); - - // ★分类器对象调用 - cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); - - return rect.size() == 0 ? false : true; -} bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) { // 构建openCV自带的眼睛分类器 diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index 8a1c564..9d8b8ea 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -1,4 +1,4 @@ -#ifndef CASICFACEINTERFACE_H +#ifndef CASICFACEINTERFACE_H #define CASICFACEINTERFACE_H #include "opencv2/opencv.hpp" @@ -49,8 +49,9 @@ float faceSimCalculate(float* feature, float* otherFeature); cv::Rect faceDetectByCVCascade(cv::Mat frame); + cv::Rect faceDetectByCVCascade(cv::Mat frame, int minFaceSize); + cv::Rect eyeDetectByCVCascade(cv::Mat frame); - bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); @@ -68,7 +69,7 @@ int minFaceSize = 320; int maxFaceSize = 720; int minEyeSize = 100; - int maxEyeSize = 600; + int maxEyeSize = 300; std::string detectorModelPath = "./model/face_detector.csta"; std::string markPts5ModelPath = "./model/face_landmarker_pts5.csta"; diff --git a/conf/config.ini b/conf/config.ini index 84e31c9..79045a6 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -1,4 +1,4 @@ -[com] +[com] #电机控制的串口名 motoPortName=COM3 @@ -17,6 +17,10 @@ maxFaceTryCount=20 #持续没找到人脸的最大次数 maxFaceNotFoundCount=500 +#注册时最小人脸 +minFaceRegist=240 +#识别时最小人脸 +minFaceRecog=100 #虹膜识别最大尝试次数 maxIrisTryCount=10 @@ -34,6 +38,18 @@ #统一背景色 backgroundColor="#FFFFFF" +[work] +#工作状态检测时最小人脸范围 +minFaceSize=160 +#人脸范围最小横坐标 +minFacePosX=320 +#人脸范围最大横坐标 +maxFacePosX=960 +#人脸范围最小纵坐标 +minFacePosY=180 +#人脸范围最大纵坐标 +maxFacePosY=540 + [camera] #人脸摄像头的编号 faceIndex=1 @@ -53,11 +69,3 @@ irisWidth=640 #虹膜图像高度 irisHeight=480 - -[stack] -#拍摄图像栈最大值 -capture=50 -#找到的眼睛图像栈最大值 -found=30 -#质量合格图像栈最大值 -qualified=30 diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 25854c3..0fe4b4c 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -63,7 +63,7 @@ cv::Mat faceMatDisp = imageMatMiir.clone(); // 利用人脸分类器进行初步的检测 - cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp); + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp, SettingConfig::getInstance().MIN_FACE_REGIST_SIZE); if (faceRect.width > 0) { // 初筛检测到人脸时将图像入栈 diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index da744f5..151de09 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -34,7 +34,7 @@ irisInfo.leftOrRight = "right"; } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::MAIN_PAGE) + if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) { // 相机拍摄下的图像1280*960, 直接用于算法判断 QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); @@ -43,7 +43,6 @@ irisInfo.data = imgDisp; irisInfo.matData = irisMat; - // 识别过程任意一个眼睛都行, 全部存入左眼队列 ProMemory::getInstance().pushCasicIris(irisInfo); } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) { diff --git a/device/device.pri b/device/device.pri index 6dc2f3c..64e6e17 100644 --- a/device/device.pri +++ b/device/device.pri @@ -1,24 +1,24 @@ -HEADERS += $$PWD/FaceCameraController.h \ - $$PWD/face/FaceRegistProcess.h -HEADERS += -HEADERS += $$PWD/face/FaceDetectRecogProcess.h +HEADERS += $$PWD/FaceCameraController.h +HEADERS += $$PWD/face/FaceRecogProcess.h +HEADERS += $$PWD/face/FaceRegistProcess.h HEADERS += $$PWD/face/CasicFaceRecState.h -SOURCES += $$PWD/FaceCameraController.cpp \ - $$PWD/face/FaceRegistProcess.cpp -SOURCES += -SOURCES += $$PWD/face/FaceDetectRecogProcess.cpp +SOURCES += $$PWD/FaceCameraController.cpp +SOURCES += $$PWD/face/FaceRecogProcess.cpp +SOURCES += $$PWD/face/FaceRegistProcess.cpp SOURCES += $$PWD/face/CasicFaceRecState.cpp 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/MotoController.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/MotoController.cpp diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index d14fd54..05fe5f1 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -258,8 +258,8 @@ // 情况3 编辑时非本人 人脸重复 // 语音提示 - SpeakerUtil::getInstance().speak(QString("人脸重复注册,请重试")); - LOG(DEBUG) << "人脸已经注册" << ui->inputName->text().toStdString(); + SpeakerUtil::getInstance().speak(QString("人脸已注册其他人,请重试")); + LOG(DEBUG) << "人脸已注册其他人" << ui->inputName->text().toStdString(); } } } @@ -288,19 +288,20 @@ // 停止拍图 ProMemory::getInstance().irisCam->stopCapture(); - ProMemory::getInstance().irisRegistPro->setWorking(false); - // 语音提示 - SpeakerUtil::getInstance().speak(QString("虹膜重复注册,请重试")); - if (this->personId.isEmpty() == true) { // 情况1 新注册 重复注册 loadPersonInfo(personIdByIris); + + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已经注册,请重试")); LOG(DEBUG) << "虹膜已经注册" << ui->inputName->text().toStdString(); } else { - LOG(DEBUG) << "虹膜已经注册" << personIdByIris.toStdString(); + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已注册其他人,请重试")); + LOG(DEBUG) << "虹膜已注册其他人" << personIdByIris.toStdString(); } } diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index 45fe761..f202cfe 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -30,6 +30,7 @@ initFaceRegistThread(); // 人脸注册线程 initFaceRecogThread(); // 人脸识别线程 initIrisRegistThread(); // 虹膜注册线程 + initIrisRecogThread(); // 虹膜识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); @@ -67,6 +68,10 @@ ProMemory::getInstance().irisRegistPro->deleteLater(); ProMemory::getInstance().irisRegistPro->wait(); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + // 关闭自动启动的外部程序 // outExe->close(); // delete outExe; @@ -75,6 +80,7 @@ delete ProMemory::getInstance().faceRegistPro; delete ProMemory::getInstance().faceRecogPro; delete ProMemory::getInstance().irisRegistPro; + delete ProMemory::getInstance().irisRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -194,15 +200,17 @@ void CasicBioRecWin::initFaceRecogThread() { // 人脸识别处理过程 - ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + ProMemory::getInstance().faceRecogPro = new FaceRecogProcess(this); // 绑定信号与槽函数 // 识别成功 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, - recogResultForm, &RecognizeResultForm::showRecognizeResult); +// connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); // 识别失败 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchFailure, recogResultForm, &RecognizeResultForm::showRecogFailure); ProMemory::getInstance().faceRecogPro->start(); @@ -222,9 +230,28 @@ connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::captureIrisFailure, addPersonForm, &AddPersonForm::onFailedCaptureIris); - // 采集虹膜图像成功 有匹配到红魔库 + // 采集虹膜图像成功 有匹配到虹膜库 connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::findMatchedIris, addPersonForm, &AddPersonForm::onMatchedIris); ProMemory::getInstance().irisRegistPro->start(); } + +void CasicBioRecWin::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 +// connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index ff2ed35..b70245a 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -53,6 +53,7 @@ void initFaceRegistThread(); void initFaceRecogThread(); void initIrisRegistThread(); + void initIrisRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp index b61cb09..e45a191 100644 --- a/RecognizeResultForm.cpp +++ b/RecognizeResultForm.cpp @@ -26,10 +26,28 @@ void RecognizeResultForm::startWorkingRecognize() { // 开始人脸识别 - ProMemory::getInstance().faceRecogPro->setWorking(true); + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + // 人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + break; + case 2: + // 虹膜识别 + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + case 3: + case 4: + // 人脸和虹膜都需要打开 + ProMemory::getInstance().faceRecogPro->setWorking(true); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + } // 将界面切换到识别界面 RecognizeResultForm ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + ui->labBackground->raise(); // 1人脸图像显示的容器 ui->labVideo->resize(1280, 720); @@ -63,13 +81,17 @@ ui->widgetFail->show(); QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ - emit backToHomeAndWait(); - CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; + + emit backToHomeAndWait(); }); } void RecognizeResultForm::showRecognizeResult(QString personId) { + personIdByFace = ""; + personIdByIris = ""; + SpeakerUtil::getInstance().speak("识别成功"); ui->labVideo->hide(); ui->labTitle->hide(); @@ -102,8 +124,131 @@ ui->widgetSucc->show(); QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ - emit backToHomeAndWait(); CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + + emit backToHomeAndWait(); }); } + +void RecognizeResultForm::checkRecognizeResult(QString personId, int faceOrIris) +{ + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + { + // 仅人脸识别 + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 人脸识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 2: + { + // 仅虹膜识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜识别成功 [%1]").arg(CasicIrisRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "2"); + record.insert("debug_info", CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 4: + { + // 任意识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + QString logStr = QString("[RecognizeResultForm]%1识别成功[%2]"); + if (faceOrIris == 1) + { + logStr.arg("人脸").arg(CasicFaceRecState::getInstance().toString()); + } else if (faceOrIris == 2) + { + logStr.arg("虹膜").arg(CasicIrisRecState::getInstance().toString()); + } + LOG(DEBUG) << logStr.toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", QString::number(faceOrIris)); + record.insert("debug_info", faceOrIris == 1 ? CasicFaceRecState::getInstance().toString() : CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 3: + if (faceOrIris == 1) + { + this->personIdByFace = personId; + } else if (faceOrIris == 2) + { + this->personIdByIris = personId; + } + + if (personIdByFace.isEmpty() || personIdByIris.isEmpty()) + { + // 只有一个成功的结果 需要等待下次 + return; + } else if (personIdByFace != personIdByIris) + { + // 人脸和虹膜识别的不是同一人 识别失败 + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜与人脸识别结果不一致,识别失败 [face: %1][iris: %2]").arg(personIdByFace).arg(personIdByIris).toStdString(); + SpeakerUtil::getInstance().speak("虹膜与人脸识别结果不一致,识别失败,请重试"); + showRecogFailure(); + } else + { + LOG(DEBUG) << QString("[RecognizeResultForm]人脸虹膜识别成功").toStdString(); + showRecognizeResult(personId); + } + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "4"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString() + " " + CasicIrisRecState::getInstance().toString()); + recDao.save(record); + } +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h index f5ef019..2c51865 100644 --- a/RecognizeResultForm.h +++ b/RecognizeResultForm.h @@ -25,7 +25,8 @@ public slots: void showRecogFailure(); - void showRecognizeResult(QString personId); + + void checkRecognizeResult(QString personId, int faceOrIris); void startWorkingRecognize(); // 开始工作 void drawImageOnHomeForm(QImage imageDisp); @@ -33,6 +34,11 @@ private: Ui::RecognizeResultForm *ui; + QString personIdByFace; + QString personIdByIris; + + void showRecognizeResult(QString personId); + signals: void backToHomeAndWait(); // 识别结束 返回主界面并待机 diff --git a/StartupForm.cpp b/StartupForm.cpp index 3d3dfad..16c4dfc 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -29,8 +29,8 @@ // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); -// connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, -// this, &StartupForm::takeOneFrameForCheckStatus); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); TimeCounterUtil::getInstance().clockCounter->start(1000); } @@ -54,6 +54,12 @@ return; } + if (this->isVisible() == false) + { + // 没有在这个页面直接返回 + return; + } + // 不在这个页面 则直接返回 不做后续判断 if (ProMemory::getInstance().widgeFrame != CasicBioRecConst::WidgeFrameName::MAIN_PAGE) { @@ -61,10 +67,25 @@ } cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); - bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + + // 判断是否开始工作时使用严格标准 人脸大小需要符合注册图像的尺寸 + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(rawFrame, SettingConfig::getInstance().MIN_WORK_FACE_SIZE); + if (faceRect.width == 0) + { + return ; + } + + bool hasFace = faceRect.width == 0 ? false : true; + if (faceRect.x < SettingConfig::getInstance().MIN_WORK_FACE_POSX || faceRect.x > SettingConfig::getInstance().MAX_WORK_FACE_POSX || + faceRect.y < SettingConfig::getInstance().MIN_WORK_FACE_POSY || faceRect.y > SettingConfig::getInstance().MAX_WORK_FACE_POSY) + { + // 检测到的人脸不在核心区则返回 + hasFace = false; + } + if (hasFace == true) { - LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + LOG(INFO) << QString("检测到人脸,START RECOGNIZE 线程").toStdString(); ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; // 启动识别线程 diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 1bc7d3a..3e9fbd4 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -13,14 +13,16 @@ #include "device/FaceCameraController.h" #include "device/IrisCameraController.h" #include "device/face/FaceRegistProcess.h" -#include "device/face/FaceDetectRecogProcess.h" +#include "device/face/FaceRecogProcess.h" #include "device/iris/IrisRegistProcess.h" +#include "device/iris/IrisRecogProcess.h" class FaceCameraController; class IrisCameraController; class FaceRegistProcess; -class FaceDetectRecogProcess; +class FaceRecogProcess; class IrisRegistProcess; +class IrisRecogProcess; class ProMemory { @@ -58,18 +60,17 @@ FaceCameraController * faceCam; FaceRegistProcess * faceRegistPro; - FaceDetectRecogProcess * faceRecogPro; + FaceRecogProcess * faceRecogPro; IrisCameraController * irisCam; IrisRegistProcess * irisRegistPro; + IrisRecogProcess * irisRecogPro; private: ProMemory(); QStack faceQueue; // 人脸信息队列 QStack irisQueue; // 虹膜信息队列 -// QStack irisLeftQueue; // 左眼信息队列 -// QStack irisRightQueue; // 右眼信息队列 QVector faceFeatures; // 人脸特征值集合 QVector irisFeatures; // 虹膜特征值集合 diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index cb4d3bd..f530212 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -372,6 +372,28 @@ return rect.at(0); } +cv::Rect casic::face::CasicFaceInterface::faceDetectByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + if (rect.size() == 0) + { + return cv::Rect(0, 0, 0, 0); + } + return rect.at(0); +} + cv::Rect casic::face::CasicFaceInterface::eyeDetectByCVCascade(cv::Mat frame) { // 构建openCV自带的眼睛分类器 @@ -402,23 +424,6 @@ return rect.at(0); } -bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) -{ - // 构建OpenCV自带的人脸分类器 - if (this->cascade == nullptr) { - this->cascade = new cv::CascadeClassifier(); - this->cascade->load(cvFaceCascadeName); - } - - std::vector rect; - cv::Size minRectSize(minFaceSize, minFaceSize); - cv::Size maxRectSize(maxFaceSize, maxFaceSize); - - // ★分类器对象调用 - cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); - - return rect.size() == 0 ? false : true; -} bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) { // 构建openCV自带的眼睛分类器 diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index 8a1c564..9d8b8ea 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -1,4 +1,4 @@ -#ifndef CASICFACEINTERFACE_H +#ifndef CASICFACEINTERFACE_H #define CASICFACEINTERFACE_H #include "opencv2/opencv.hpp" @@ -49,8 +49,9 @@ float faceSimCalculate(float* feature, float* otherFeature); cv::Rect faceDetectByCVCascade(cv::Mat frame); + cv::Rect faceDetectByCVCascade(cv::Mat frame, int minFaceSize); + cv::Rect eyeDetectByCVCascade(cv::Mat frame); - bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); @@ -68,7 +69,7 @@ int minFaceSize = 320; int maxFaceSize = 720; int minEyeSize = 100; - int maxEyeSize = 600; + int maxEyeSize = 300; std::string detectorModelPath = "./model/face_detector.csta"; std::string markPts5ModelPath = "./model/face_landmarker_pts5.csta"; diff --git a/conf/config.ini b/conf/config.ini index 84e31c9..79045a6 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -1,4 +1,4 @@ -[com] +[com] #电机控制的串口名 motoPortName=COM3 @@ -17,6 +17,10 @@ maxFaceTryCount=20 #持续没找到人脸的最大次数 maxFaceNotFoundCount=500 +#注册时最小人脸 +minFaceRegist=240 +#识别时最小人脸 +minFaceRecog=100 #虹膜识别最大尝试次数 maxIrisTryCount=10 @@ -34,6 +38,18 @@ #统一背景色 backgroundColor="#FFFFFF" +[work] +#工作状态检测时最小人脸范围 +minFaceSize=160 +#人脸范围最小横坐标 +minFacePosX=320 +#人脸范围最大横坐标 +maxFacePosX=960 +#人脸范围最小纵坐标 +minFacePosY=180 +#人脸范围最大纵坐标 +maxFacePosY=540 + [camera] #人脸摄像头的编号 faceIndex=1 @@ -53,11 +69,3 @@ irisWidth=640 #虹膜图像高度 irisHeight=480 - -[stack] -#拍摄图像栈最大值 -capture=50 -#找到的眼睛图像栈最大值 -found=30 -#质量合格图像栈最大值 -qualified=30 diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 25854c3..0fe4b4c 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -63,7 +63,7 @@ cv::Mat faceMatDisp = imageMatMiir.clone(); // 利用人脸分类器进行初步的检测 - cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp); + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp, SettingConfig::getInstance().MIN_FACE_REGIST_SIZE); if (faceRect.width > 0) { // 初筛检测到人脸时将图像入栈 diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index da744f5..151de09 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -34,7 +34,7 @@ irisInfo.leftOrRight = "right"; } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::MAIN_PAGE) + if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) { // 相机拍摄下的图像1280*960, 直接用于算法判断 QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); @@ -43,7 +43,6 @@ irisInfo.data = imgDisp; irisInfo.matData = irisMat; - // 识别过程任意一个眼睛都行, 全部存入左眼队列 ProMemory::getInstance().pushCasicIris(irisInfo); } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) { diff --git a/device/device.pri b/device/device.pri index 6dc2f3c..64e6e17 100644 --- a/device/device.pri +++ b/device/device.pri @@ -1,24 +1,24 @@ -HEADERS += $$PWD/FaceCameraController.h \ - $$PWD/face/FaceRegistProcess.h -HEADERS += -HEADERS += $$PWD/face/FaceDetectRecogProcess.h +HEADERS += $$PWD/FaceCameraController.h +HEADERS += $$PWD/face/FaceRecogProcess.h +HEADERS += $$PWD/face/FaceRegistProcess.h HEADERS += $$PWD/face/CasicFaceRecState.h -SOURCES += $$PWD/FaceCameraController.cpp \ - $$PWD/face/FaceRegistProcess.cpp -SOURCES += -SOURCES += $$PWD/face/FaceDetectRecogProcess.cpp +SOURCES += $$PWD/FaceCameraController.cpp +SOURCES += $$PWD/face/FaceRecogProcess.cpp +SOURCES += $$PWD/face/FaceRegistProcess.cpp SOURCES += $$PWD/face/CasicFaceRecState.cpp 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/MotoController.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/MotoController.cpp diff --git a/device/face/FaceDetectRecogProcess.cpp b/device/face/FaceDetectRecogProcess.cpp deleted file mode 100644 index d8d6d01..0000000 --- a/device/face/FaceDetectRecogProcess.cpp +++ /dev/null @@ -1,197 +0,0 @@ -#include "FaceDetectRecogProcess.h" - -FaceDetectRecogProcess::FaceDetectRecogProcess(QObject *parent) : QThread(parent) -{ - this->working = false; - this->exit = false; -} - -FaceDetectRecogProcess::~FaceDetectRecogProcess() -{ - this->setWorking(false); -} - -void FaceDetectRecogProcess::setWorking(bool working) -{ - this->working = working; -} -void FaceDetectRecogProcess::exitThread() -{ - this->exit = true; -} -void FaceDetectRecogProcess::startThread() -{ - this->exit = false; - this->start(); -} - -void FaceDetectRecogProcess::addOneTryCount() -{ - LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); - if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) - { - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; - } else - { - CasicFaceRecState::getInstance().tryCount = 0; - CasicFaceRecState::getInstance().noFaceCount = 0; - emit matchFailure(); - - this->setWorking(false); // 返回后则线程暂停工作 - } -} - -void FaceDetectRecogProcess::addOneNoFaceCount() -{ - CasicFaceRecState::getInstance().noFaceCount++; - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; - if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) - { - CasicFaceRecState::getInstance().noFaceCount = 0; - emit matchFailure(); - - this->setWorking(false); // 返回后则暂停工作 - } -} - -void FaceDetectRecogProcess::run() -{ - while (exit == false) - { - if (this->working == false) - { - this->msleep(100); // 100ms后再判断 - continue; - } - - // 图像栈中没有图像则直接返回 - if (ProMemory::getInstance().isFaceQueueEmpty() == true) - { - addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 - LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); - - this->msleep(200); // 200ms后再判断 - continue; - } - - // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 - if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) - { - LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); - this->msleep(200); // 200ms后再判断 - continue; - } - - // 取出人脸图像栈中的一条数据 - CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); - - // 调用人脸检测算法 - faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); - - // 没有找到人脸则返回 - if (faceInfo.hasFace == false) - { - // 表示本次识别结束, 可以开始下一次识别过程 - addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 - LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); - this->msleep(200); // 200ms后再判断 - continue; - } - - // 找到人脸则开始一次识别 - if (CasicFaceRecState::getInstance().recoginzeId == "0") - { - CasicFaceRecState::getInstance().initRecognize(); - } - CasicFaceRecState::getInstance().faceInfo = &faceInfo; - CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 - CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 - - // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 - casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); - faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); - - // 活体检测判断为假脸 - if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) - { - // 表示本次识别结束, 可以开始下一次识别过程 - LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); - - addOneTryCount(); // 判断是否超过次数, 重置识别状态 - this->msleep(200); // 200ms后再判断 - continue; - } - - // 设置识别状态值=通过活体检测 - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; - - // 调用算法提取特征值, 1024个字节的float数组 - faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); - - // 设置识别状态值=特征值提取 - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; - CasicFaceRecState::getInstance().faceInfo = &faceInfo; - - LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); - - // 特征值提取成功的人脸 与人脸库中的人脸进行比较 - compareFaceInCollection(); - } -} - -void FaceDetectRecogProcess::compareFaceInCollection() -{ - ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 - QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); - for (int i = 0; i < faceFeatures.size(); i++) - { - QVariantMap ffMap = faceFeatures.at(i); - - QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); - float ffArr[1024]; - for (int i = 0; i < 1024; i++) - { - QByteArray tempBa; - tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); - ffArr[i] = ByteUtil::binToFloat(tempBa); - } - - float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); - - LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); - if (sim > 0.62) - { - CasicFaceRecState::getInstance().faceInfo->sim = sim; - CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); - CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; - - // 找到匹配的人脸图像 - this->afterRecogAction(ffMap.value("person_id").toString()); - this->setWorking(false); // 找到匹配的人脸之后停止识别线程工作 - return ; - } - } - - this->addOneTryCount(); -} - -void FaceDetectRecogProcess::afterRecogAction(QString personId) -{ - ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 - - LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); - - // 识别记录存入数据库 - RecognitionRecordDao recDao; - QVariantMap record; - record.insert("person_id", personId); - record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); - record.insert("type", "1"); - record.insert("debug_info", CasicFaceRecState::getInstance().toString()); - recDao.save(record); - - // 发送信号, 在主界面上显示 - emit matchSuccess(personId); -} - diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index d14fd54..05fe5f1 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -258,8 +258,8 @@ // 情况3 编辑时非本人 人脸重复 // 语音提示 - SpeakerUtil::getInstance().speak(QString("人脸重复注册,请重试")); - LOG(DEBUG) << "人脸已经注册" << ui->inputName->text().toStdString(); + SpeakerUtil::getInstance().speak(QString("人脸已注册其他人,请重试")); + LOG(DEBUG) << "人脸已注册其他人" << ui->inputName->text().toStdString(); } } } @@ -288,19 +288,20 @@ // 停止拍图 ProMemory::getInstance().irisCam->stopCapture(); - ProMemory::getInstance().irisRegistPro->setWorking(false); - // 语音提示 - SpeakerUtil::getInstance().speak(QString("虹膜重复注册,请重试")); - if (this->personId.isEmpty() == true) { // 情况1 新注册 重复注册 loadPersonInfo(personIdByIris); + + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已经注册,请重试")); LOG(DEBUG) << "虹膜已经注册" << ui->inputName->text().toStdString(); } else { - LOG(DEBUG) << "虹膜已经注册" << personIdByIris.toStdString(); + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已注册其他人,请重试")); + LOG(DEBUG) << "虹膜已注册其他人" << personIdByIris.toStdString(); } } diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index 45fe761..f202cfe 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -30,6 +30,7 @@ initFaceRegistThread(); // 人脸注册线程 initFaceRecogThread(); // 人脸识别线程 initIrisRegistThread(); // 虹膜注册线程 + initIrisRecogThread(); // 虹膜识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); @@ -67,6 +68,10 @@ ProMemory::getInstance().irisRegistPro->deleteLater(); ProMemory::getInstance().irisRegistPro->wait(); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + // 关闭自动启动的外部程序 // outExe->close(); // delete outExe; @@ -75,6 +80,7 @@ delete ProMemory::getInstance().faceRegistPro; delete ProMemory::getInstance().faceRecogPro; delete ProMemory::getInstance().irisRegistPro; + delete ProMemory::getInstance().irisRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -194,15 +200,17 @@ void CasicBioRecWin::initFaceRecogThread() { // 人脸识别处理过程 - ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + ProMemory::getInstance().faceRecogPro = new FaceRecogProcess(this); // 绑定信号与槽函数 // 识别成功 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, - recogResultForm, &RecognizeResultForm::showRecognizeResult); +// connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); // 识别失败 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchFailure, recogResultForm, &RecognizeResultForm::showRecogFailure); ProMemory::getInstance().faceRecogPro->start(); @@ -222,9 +230,28 @@ connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::captureIrisFailure, addPersonForm, &AddPersonForm::onFailedCaptureIris); - // 采集虹膜图像成功 有匹配到红魔库 + // 采集虹膜图像成功 有匹配到虹膜库 connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::findMatchedIris, addPersonForm, &AddPersonForm::onMatchedIris); ProMemory::getInstance().irisRegistPro->start(); } + +void CasicBioRecWin::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 +// connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index ff2ed35..b70245a 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -53,6 +53,7 @@ void initFaceRegistThread(); void initFaceRecogThread(); void initIrisRegistThread(); + void initIrisRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp index b61cb09..e45a191 100644 --- a/RecognizeResultForm.cpp +++ b/RecognizeResultForm.cpp @@ -26,10 +26,28 @@ void RecognizeResultForm::startWorkingRecognize() { // 开始人脸识别 - ProMemory::getInstance().faceRecogPro->setWorking(true); + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + // 人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + break; + case 2: + // 虹膜识别 + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + case 3: + case 4: + // 人脸和虹膜都需要打开 + ProMemory::getInstance().faceRecogPro->setWorking(true); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + } // 将界面切换到识别界面 RecognizeResultForm ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + ui->labBackground->raise(); // 1人脸图像显示的容器 ui->labVideo->resize(1280, 720); @@ -63,13 +81,17 @@ ui->widgetFail->show(); QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ - emit backToHomeAndWait(); - CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; + + emit backToHomeAndWait(); }); } void RecognizeResultForm::showRecognizeResult(QString personId) { + personIdByFace = ""; + personIdByIris = ""; + SpeakerUtil::getInstance().speak("识别成功"); ui->labVideo->hide(); ui->labTitle->hide(); @@ -102,8 +124,131 @@ ui->widgetSucc->show(); QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ - emit backToHomeAndWait(); CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + + emit backToHomeAndWait(); }); } + +void RecognizeResultForm::checkRecognizeResult(QString personId, int faceOrIris) +{ + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + { + // 仅人脸识别 + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 人脸识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 2: + { + // 仅虹膜识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜识别成功 [%1]").arg(CasicIrisRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "2"); + record.insert("debug_info", CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 4: + { + // 任意识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + QString logStr = QString("[RecognizeResultForm]%1识别成功[%2]"); + if (faceOrIris == 1) + { + logStr.arg("人脸").arg(CasicFaceRecState::getInstance().toString()); + } else if (faceOrIris == 2) + { + logStr.arg("虹膜").arg(CasicIrisRecState::getInstance().toString()); + } + LOG(DEBUG) << logStr.toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", QString::number(faceOrIris)); + record.insert("debug_info", faceOrIris == 1 ? CasicFaceRecState::getInstance().toString() : CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 3: + if (faceOrIris == 1) + { + this->personIdByFace = personId; + } else if (faceOrIris == 2) + { + this->personIdByIris = personId; + } + + if (personIdByFace.isEmpty() || personIdByIris.isEmpty()) + { + // 只有一个成功的结果 需要等待下次 + return; + } else if (personIdByFace != personIdByIris) + { + // 人脸和虹膜识别的不是同一人 识别失败 + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜与人脸识别结果不一致,识别失败 [face: %1][iris: %2]").arg(personIdByFace).arg(personIdByIris).toStdString(); + SpeakerUtil::getInstance().speak("虹膜与人脸识别结果不一致,识别失败,请重试"); + showRecogFailure(); + } else + { + LOG(DEBUG) << QString("[RecognizeResultForm]人脸虹膜识别成功").toStdString(); + showRecognizeResult(personId); + } + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "4"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString() + " " + CasicIrisRecState::getInstance().toString()); + recDao.save(record); + } +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h index f5ef019..2c51865 100644 --- a/RecognizeResultForm.h +++ b/RecognizeResultForm.h @@ -25,7 +25,8 @@ public slots: void showRecogFailure(); - void showRecognizeResult(QString personId); + + void checkRecognizeResult(QString personId, int faceOrIris); void startWorkingRecognize(); // 开始工作 void drawImageOnHomeForm(QImage imageDisp); @@ -33,6 +34,11 @@ private: Ui::RecognizeResultForm *ui; + QString personIdByFace; + QString personIdByIris; + + void showRecognizeResult(QString personId); + signals: void backToHomeAndWait(); // 识别结束 返回主界面并待机 diff --git a/StartupForm.cpp b/StartupForm.cpp index 3d3dfad..16c4dfc 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -29,8 +29,8 @@ // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); -// connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, -// this, &StartupForm::takeOneFrameForCheckStatus); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); TimeCounterUtil::getInstance().clockCounter->start(1000); } @@ -54,6 +54,12 @@ return; } + if (this->isVisible() == false) + { + // 没有在这个页面直接返回 + return; + } + // 不在这个页面 则直接返回 不做后续判断 if (ProMemory::getInstance().widgeFrame != CasicBioRecConst::WidgeFrameName::MAIN_PAGE) { @@ -61,10 +67,25 @@ } cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); - bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + + // 判断是否开始工作时使用严格标准 人脸大小需要符合注册图像的尺寸 + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(rawFrame, SettingConfig::getInstance().MIN_WORK_FACE_SIZE); + if (faceRect.width == 0) + { + return ; + } + + bool hasFace = faceRect.width == 0 ? false : true; + if (faceRect.x < SettingConfig::getInstance().MIN_WORK_FACE_POSX || faceRect.x > SettingConfig::getInstance().MAX_WORK_FACE_POSX || + faceRect.y < SettingConfig::getInstance().MIN_WORK_FACE_POSY || faceRect.y > SettingConfig::getInstance().MAX_WORK_FACE_POSY) + { + // 检测到的人脸不在核心区则返回 + hasFace = false; + } + if (hasFace == true) { - LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + LOG(INFO) << QString("检测到人脸,START RECOGNIZE 线程").toStdString(); ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; // 启动识别线程 diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 1bc7d3a..3e9fbd4 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -13,14 +13,16 @@ #include "device/FaceCameraController.h" #include "device/IrisCameraController.h" #include "device/face/FaceRegistProcess.h" -#include "device/face/FaceDetectRecogProcess.h" +#include "device/face/FaceRecogProcess.h" #include "device/iris/IrisRegistProcess.h" +#include "device/iris/IrisRecogProcess.h" class FaceCameraController; class IrisCameraController; class FaceRegistProcess; -class FaceDetectRecogProcess; +class FaceRecogProcess; class IrisRegistProcess; +class IrisRecogProcess; class ProMemory { @@ -58,18 +60,17 @@ FaceCameraController * faceCam; FaceRegistProcess * faceRegistPro; - FaceDetectRecogProcess * faceRecogPro; + FaceRecogProcess * faceRecogPro; IrisCameraController * irisCam; IrisRegistProcess * irisRegistPro; + IrisRecogProcess * irisRecogPro; private: ProMemory(); QStack faceQueue; // 人脸信息队列 QStack irisQueue; // 虹膜信息队列 -// QStack irisLeftQueue; // 左眼信息队列 -// QStack irisRightQueue; // 右眼信息队列 QVector faceFeatures; // 人脸特征值集合 QVector irisFeatures; // 虹膜特征值集合 diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index cb4d3bd..f530212 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -372,6 +372,28 @@ return rect.at(0); } +cv::Rect casic::face::CasicFaceInterface::faceDetectByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + if (rect.size() == 0) + { + return cv::Rect(0, 0, 0, 0); + } + return rect.at(0); +} + cv::Rect casic::face::CasicFaceInterface::eyeDetectByCVCascade(cv::Mat frame) { // 构建openCV自带的眼睛分类器 @@ -402,23 +424,6 @@ return rect.at(0); } -bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) -{ - // 构建OpenCV自带的人脸分类器 - if (this->cascade == nullptr) { - this->cascade = new cv::CascadeClassifier(); - this->cascade->load(cvFaceCascadeName); - } - - std::vector rect; - cv::Size minRectSize(minFaceSize, minFaceSize); - cv::Size maxRectSize(maxFaceSize, maxFaceSize); - - // ★分类器对象调用 - cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); - - return rect.size() == 0 ? false : true; -} bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) { // 构建openCV自带的眼睛分类器 diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index 8a1c564..9d8b8ea 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -1,4 +1,4 @@ -#ifndef CASICFACEINTERFACE_H +#ifndef CASICFACEINTERFACE_H #define CASICFACEINTERFACE_H #include "opencv2/opencv.hpp" @@ -49,8 +49,9 @@ float faceSimCalculate(float* feature, float* otherFeature); cv::Rect faceDetectByCVCascade(cv::Mat frame); + cv::Rect faceDetectByCVCascade(cv::Mat frame, int minFaceSize); + cv::Rect eyeDetectByCVCascade(cv::Mat frame); - bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); @@ -68,7 +69,7 @@ int minFaceSize = 320; int maxFaceSize = 720; int minEyeSize = 100; - int maxEyeSize = 600; + int maxEyeSize = 300; std::string detectorModelPath = "./model/face_detector.csta"; std::string markPts5ModelPath = "./model/face_landmarker_pts5.csta"; diff --git a/conf/config.ini b/conf/config.ini index 84e31c9..79045a6 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -1,4 +1,4 @@ -[com] +[com] #电机控制的串口名 motoPortName=COM3 @@ -17,6 +17,10 @@ maxFaceTryCount=20 #持续没找到人脸的最大次数 maxFaceNotFoundCount=500 +#注册时最小人脸 +minFaceRegist=240 +#识别时最小人脸 +minFaceRecog=100 #虹膜识别最大尝试次数 maxIrisTryCount=10 @@ -34,6 +38,18 @@ #统一背景色 backgroundColor="#FFFFFF" +[work] +#工作状态检测时最小人脸范围 +minFaceSize=160 +#人脸范围最小横坐标 +minFacePosX=320 +#人脸范围最大横坐标 +maxFacePosX=960 +#人脸范围最小纵坐标 +minFacePosY=180 +#人脸范围最大纵坐标 +maxFacePosY=540 + [camera] #人脸摄像头的编号 faceIndex=1 @@ -53,11 +69,3 @@ irisWidth=640 #虹膜图像高度 irisHeight=480 - -[stack] -#拍摄图像栈最大值 -capture=50 -#找到的眼睛图像栈最大值 -found=30 -#质量合格图像栈最大值 -qualified=30 diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 25854c3..0fe4b4c 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -63,7 +63,7 @@ cv::Mat faceMatDisp = imageMatMiir.clone(); // 利用人脸分类器进行初步的检测 - cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp); + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp, SettingConfig::getInstance().MIN_FACE_REGIST_SIZE); if (faceRect.width > 0) { // 初筛检测到人脸时将图像入栈 diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index da744f5..151de09 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -34,7 +34,7 @@ irisInfo.leftOrRight = "right"; } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::MAIN_PAGE) + if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) { // 相机拍摄下的图像1280*960, 直接用于算法判断 QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); @@ -43,7 +43,6 @@ irisInfo.data = imgDisp; irisInfo.matData = irisMat; - // 识别过程任意一个眼睛都行, 全部存入左眼队列 ProMemory::getInstance().pushCasicIris(irisInfo); } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) { diff --git a/device/device.pri b/device/device.pri index 6dc2f3c..64e6e17 100644 --- a/device/device.pri +++ b/device/device.pri @@ -1,24 +1,24 @@ -HEADERS += $$PWD/FaceCameraController.h \ - $$PWD/face/FaceRegistProcess.h -HEADERS += -HEADERS += $$PWD/face/FaceDetectRecogProcess.h +HEADERS += $$PWD/FaceCameraController.h +HEADERS += $$PWD/face/FaceRecogProcess.h +HEADERS += $$PWD/face/FaceRegistProcess.h HEADERS += $$PWD/face/CasicFaceRecState.h -SOURCES += $$PWD/FaceCameraController.cpp \ - $$PWD/face/FaceRegistProcess.cpp -SOURCES += -SOURCES += $$PWD/face/FaceDetectRecogProcess.cpp +SOURCES += $$PWD/FaceCameraController.cpp +SOURCES += $$PWD/face/FaceRecogProcess.cpp +SOURCES += $$PWD/face/FaceRegistProcess.cpp SOURCES += $$PWD/face/CasicFaceRecState.cpp 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/MotoController.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/MotoController.cpp diff --git a/device/face/FaceDetectRecogProcess.cpp b/device/face/FaceDetectRecogProcess.cpp deleted file mode 100644 index d8d6d01..0000000 --- a/device/face/FaceDetectRecogProcess.cpp +++ /dev/null @@ -1,197 +0,0 @@ -#include "FaceDetectRecogProcess.h" - -FaceDetectRecogProcess::FaceDetectRecogProcess(QObject *parent) : QThread(parent) -{ - this->working = false; - this->exit = false; -} - -FaceDetectRecogProcess::~FaceDetectRecogProcess() -{ - this->setWorking(false); -} - -void FaceDetectRecogProcess::setWorking(bool working) -{ - this->working = working; -} -void FaceDetectRecogProcess::exitThread() -{ - this->exit = true; -} -void FaceDetectRecogProcess::startThread() -{ - this->exit = false; - this->start(); -} - -void FaceDetectRecogProcess::addOneTryCount() -{ - LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); - if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) - { - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; - } else - { - CasicFaceRecState::getInstance().tryCount = 0; - CasicFaceRecState::getInstance().noFaceCount = 0; - emit matchFailure(); - - this->setWorking(false); // 返回后则线程暂停工作 - } -} - -void FaceDetectRecogProcess::addOneNoFaceCount() -{ - CasicFaceRecState::getInstance().noFaceCount++; - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; - if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) - { - CasicFaceRecState::getInstance().noFaceCount = 0; - emit matchFailure(); - - this->setWorking(false); // 返回后则暂停工作 - } -} - -void FaceDetectRecogProcess::run() -{ - while (exit == false) - { - if (this->working == false) - { - this->msleep(100); // 100ms后再判断 - continue; - } - - // 图像栈中没有图像则直接返回 - if (ProMemory::getInstance().isFaceQueueEmpty() == true) - { - addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 - LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); - - this->msleep(200); // 200ms后再判断 - continue; - } - - // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 - if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) - { - LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); - this->msleep(200); // 200ms后再判断 - continue; - } - - // 取出人脸图像栈中的一条数据 - CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); - - // 调用人脸检测算法 - faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); - - // 没有找到人脸则返回 - if (faceInfo.hasFace == false) - { - // 表示本次识别结束, 可以开始下一次识别过程 - addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 - LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); - this->msleep(200); // 200ms后再判断 - continue; - } - - // 找到人脸则开始一次识别 - if (CasicFaceRecState::getInstance().recoginzeId == "0") - { - CasicFaceRecState::getInstance().initRecognize(); - } - CasicFaceRecState::getInstance().faceInfo = &faceInfo; - CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 - CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 - - // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 - casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); - faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); - - // 活体检测判断为假脸 - if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) - { - // 表示本次识别结束, 可以开始下一次识别过程 - LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); - - addOneTryCount(); // 判断是否超过次数, 重置识别状态 - this->msleep(200); // 200ms后再判断 - continue; - } - - // 设置识别状态值=通过活体检测 - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; - - // 调用算法提取特征值, 1024个字节的float数组 - faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); - - // 设置识别状态值=特征值提取 - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; - CasicFaceRecState::getInstance().faceInfo = &faceInfo; - - LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); - - // 特征值提取成功的人脸 与人脸库中的人脸进行比较 - compareFaceInCollection(); - } -} - -void FaceDetectRecogProcess::compareFaceInCollection() -{ - ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 - QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); - for (int i = 0; i < faceFeatures.size(); i++) - { - QVariantMap ffMap = faceFeatures.at(i); - - QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); - float ffArr[1024]; - for (int i = 0; i < 1024; i++) - { - QByteArray tempBa; - tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); - ffArr[i] = ByteUtil::binToFloat(tempBa); - } - - float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); - - LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); - if (sim > 0.62) - { - CasicFaceRecState::getInstance().faceInfo->sim = sim; - CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); - CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; - - // 找到匹配的人脸图像 - this->afterRecogAction(ffMap.value("person_id").toString()); - this->setWorking(false); // 找到匹配的人脸之后停止识别线程工作 - return ; - } - } - - this->addOneTryCount(); -} - -void FaceDetectRecogProcess::afterRecogAction(QString personId) -{ - ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 - - LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); - - // 识别记录存入数据库 - RecognitionRecordDao recDao; - QVariantMap record; - record.insert("person_id", personId); - record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); - record.insert("type", "1"); - record.insert("debug_info", CasicFaceRecState::getInstance().toString()); - recDao.save(record); - - // 发送信号, 在主界面上显示 - emit matchSuccess(personId); -} - diff --git a/device/face/FaceDetectRecogProcess.h b/device/face/FaceDetectRecogProcess.h deleted file mode 100644 index 4ca4e94..0000000 --- a/device/face/FaceDetectRecogProcess.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef FACEDETECTRECOGPROCESS_H -#define FACEDETECTRECOGPROCESS_H - -#include -#include -#include "opencv2/opencv.hpp" - -#include "dao/RecognitionRecordDao.h" - -#include "CasicFaceRecState.h" -#include "casic/ProMemory.h" -#include "casic/face/CasicFaceInterface.h" -#include "utils/UtilInclude.h" - -class FaceDetectRecogProcess : public QThread -{ - Q_OBJECT -public: - explicit FaceDetectRecogProcess(QObject *parent = nullptr); - ~FaceDetectRecogProcess(); - - void setWorking(bool working); - void exitThread(); - void startThread(); - - void addOneTryCount(); - void addOneNoFaceCount(); - -protected: - //QThread的虚函数 - //线程处理函数 - //不能直接调用, 通过start()间接调用 - void run(); - void compareFaceInCollection(); - void afterRecogAction(QString personId); - - volatile bool working; - volatile bool exit; - -signals: - void matchSuccess(QString personId); // 匹配成功 - void matchFailure(); // 匹配失败 - -}; - -#endif // FACEDETECTRECOGPROCESS_H diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index d14fd54..05fe5f1 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -258,8 +258,8 @@ // 情况3 编辑时非本人 人脸重复 // 语音提示 - SpeakerUtil::getInstance().speak(QString("人脸重复注册,请重试")); - LOG(DEBUG) << "人脸已经注册" << ui->inputName->text().toStdString(); + SpeakerUtil::getInstance().speak(QString("人脸已注册其他人,请重试")); + LOG(DEBUG) << "人脸已注册其他人" << ui->inputName->text().toStdString(); } } } @@ -288,19 +288,20 @@ // 停止拍图 ProMemory::getInstance().irisCam->stopCapture(); - ProMemory::getInstance().irisRegistPro->setWorking(false); - // 语音提示 - SpeakerUtil::getInstance().speak(QString("虹膜重复注册,请重试")); - if (this->personId.isEmpty() == true) { // 情况1 新注册 重复注册 loadPersonInfo(personIdByIris); + + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已经注册,请重试")); LOG(DEBUG) << "虹膜已经注册" << ui->inputName->text().toStdString(); } else { - LOG(DEBUG) << "虹膜已经注册" << personIdByIris.toStdString(); + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已注册其他人,请重试")); + LOG(DEBUG) << "虹膜已注册其他人" << personIdByIris.toStdString(); } } diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index 45fe761..f202cfe 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -30,6 +30,7 @@ initFaceRegistThread(); // 人脸注册线程 initFaceRecogThread(); // 人脸识别线程 initIrisRegistThread(); // 虹膜注册线程 + initIrisRecogThread(); // 虹膜识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); @@ -67,6 +68,10 @@ ProMemory::getInstance().irisRegistPro->deleteLater(); ProMemory::getInstance().irisRegistPro->wait(); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + // 关闭自动启动的外部程序 // outExe->close(); // delete outExe; @@ -75,6 +80,7 @@ delete ProMemory::getInstance().faceRegistPro; delete ProMemory::getInstance().faceRecogPro; delete ProMemory::getInstance().irisRegistPro; + delete ProMemory::getInstance().irisRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -194,15 +200,17 @@ void CasicBioRecWin::initFaceRecogThread() { // 人脸识别处理过程 - ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + ProMemory::getInstance().faceRecogPro = new FaceRecogProcess(this); // 绑定信号与槽函数 // 识别成功 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, - recogResultForm, &RecognizeResultForm::showRecognizeResult); +// connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); // 识别失败 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchFailure, recogResultForm, &RecognizeResultForm::showRecogFailure); ProMemory::getInstance().faceRecogPro->start(); @@ -222,9 +230,28 @@ connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::captureIrisFailure, addPersonForm, &AddPersonForm::onFailedCaptureIris); - // 采集虹膜图像成功 有匹配到红魔库 + // 采集虹膜图像成功 有匹配到虹膜库 connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::findMatchedIris, addPersonForm, &AddPersonForm::onMatchedIris); ProMemory::getInstance().irisRegistPro->start(); } + +void CasicBioRecWin::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 +// connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index ff2ed35..b70245a 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -53,6 +53,7 @@ void initFaceRegistThread(); void initFaceRecogThread(); void initIrisRegistThread(); + void initIrisRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp index b61cb09..e45a191 100644 --- a/RecognizeResultForm.cpp +++ b/RecognizeResultForm.cpp @@ -26,10 +26,28 @@ void RecognizeResultForm::startWorkingRecognize() { // 开始人脸识别 - ProMemory::getInstance().faceRecogPro->setWorking(true); + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + // 人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + break; + case 2: + // 虹膜识别 + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + case 3: + case 4: + // 人脸和虹膜都需要打开 + ProMemory::getInstance().faceRecogPro->setWorking(true); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + } // 将界面切换到识别界面 RecognizeResultForm ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + ui->labBackground->raise(); // 1人脸图像显示的容器 ui->labVideo->resize(1280, 720); @@ -63,13 +81,17 @@ ui->widgetFail->show(); QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ - emit backToHomeAndWait(); - CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; + + emit backToHomeAndWait(); }); } void RecognizeResultForm::showRecognizeResult(QString personId) { + personIdByFace = ""; + personIdByIris = ""; + SpeakerUtil::getInstance().speak("识别成功"); ui->labVideo->hide(); ui->labTitle->hide(); @@ -102,8 +124,131 @@ ui->widgetSucc->show(); QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ - emit backToHomeAndWait(); CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + + emit backToHomeAndWait(); }); } + +void RecognizeResultForm::checkRecognizeResult(QString personId, int faceOrIris) +{ + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + { + // 仅人脸识别 + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 人脸识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 2: + { + // 仅虹膜识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜识别成功 [%1]").arg(CasicIrisRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "2"); + record.insert("debug_info", CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 4: + { + // 任意识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + QString logStr = QString("[RecognizeResultForm]%1识别成功[%2]"); + if (faceOrIris == 1) + { + logStr.arg("人脸").arg(CasicFaceRecState::getInstance().toString()); + } else if (faceOrIris == 2) + { + logStr.arg("虹膜").arg(CasicIrisRecState::getInstance().toString()); + } + LOG(DEBUG) << logStr.toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", QString::number(faceOrIris)); + record.insert("debug_info", faceOrIris == 1 ? CasicFaceRecState::getInstance().toString() : CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 3: + if (faceOrIris == 1) + { + this->personIdByFace = personId; + } else if (faceOrIris == 2) + { + this->personIdByIris = personId; + } + + if (personIdByFace.isEmpty() || personIdByIris.isEmpty()) + { + // 只有一个成功的结果 需要等待下次 + return; + } else if (personIdByFace != personIdByIris) + { + // 人脸和虹膜识别的不是同一人 识别失败 + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜与人脸识别结果不一致,识别失败 [face: %1][iris: %2]").arg(personIdByFace).arg(personIdByIris).toStdString(); + SpeakerUtil::getInstance().speak("虹膜与人脸识别结果不一致,识别失败,请重试"); + showRecogFailure(); + } else + { + LOG(DEBUG) << QString("[RecognizeResultForm]人脸虹膜识别成功").toStdString(); + showRecognizeResult(personId); + } + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "4"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString() + " " + CasicIrisRecState::getInstance().toString()); + recDao.save(record); + } +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h index f5ef019..2c51865 100644 --- a/RecognizeResultForm.h +++ b/RecognizeResultForm.h @@ -25,7 +25,8 @@ public slots: void showRecogFailure(); - void showRecognizeResult(QString personId); + + void checkRecognizeResult(QString personId, int faceOrIris); void startWorkingRecognize(); // 开始工作 void drawImageOnHomeForm(QImage imageDisp); @@ -33,6 +34,11 @@ private: Ui::RecognizeResultForm *ui; + QString personIdByFace; + QString personIdByIris; + + void showRecognizeResult(QString personId); + signals: void backToHomeAndWait(); // 识别结束 返回主界面并待机 diff --git a/StartupForm.cpp b/StartupForm.cpp index 3d3dfad..16c4dfc 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -29,8 +29,8 @@ // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); -// connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, -// this, &StartupForm::takeOneFrameForCheckStatus); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); TimeCounterUtil::getInstance().clockCounter->start(1000); } @@ -54,6 +54,12 @@ return; } + if (this->isVisible() == false) + { + // 没有在这个页面直接返回 + return; + } + // 不在这个页面 则直接返回 不做后续判断 if (ProMemory::getInstance().widgeFrame != CasicBioRecConst::WidgeFrameName::MAIN_PAGE) { @@ -61,10 +67,25 @@ } cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); - bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + + // 判断是否开始工作时使用严格标准 人脸大小需要符合注册图像的尺寸 + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(rawFrame, SettingConfig::getInstance().MIN_WORK_FACE_SIZE); + if (faceRect.width == 0) + { + return ; + } + + bool hasFace = faceRect.width == 0 ? false : true; + if (faceRect.x < SettingConfig::getInstance().MIN_WORK_FACE_POSX || faceRect.x > SettingConfig::getInstance().MAX_WORK_FACE_POSX || + faceRect.y < SettingConfig::getInstance().MIN_WORK_FACE_POSY || faceRect.y > SettingConfig::getInstance().MAX_WORK_FACE_POSY) + { + // 检测到的人脸不在核心区则返回 + hasFace = false; + } + if (hasFace == true) { - LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + LOG(INFO) << QString("检测到人脸,START RECOGNIZE 线程").toStdString(); ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; // 启动识别线程 diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 1bc7d3a..3e9fbd4 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -13,14 +13,16 @@ #include "device/FaceCameraController.h" #include "device/IrisCameraController.h" #include "device/face/FaceRegistProcess.h" -#include "device/face/FaceDetectRecogProcess.h" +#include "device/face/FaceRecogProcess.h" #include "device/iris/IrisRegistProcess.h" +#include "device/iris/IrisRecogProcess.h" class FaceCameraController; class IrisCameraController; class FaceRegistProcess; -class FaceDetectRecogProcess; +class FaceRecogProcess; class IrisRegistProcess; +class IrisRecogProcess; class ProMemory { @@ -58,18 +60,17 @@ FaceCameraController * faceCam; FaceRegistProcess * faceRegistPro; - FaceDetectRecogProcess * faceRecogPro; + FaceRecogProcess * faceRecogPro; IrisCameraController * irisCam; IrisRegistProcess * irisRegistPro; + IrisRecogProcess * irisRecogPro; private: ProMemory(); QStack faceQueue; // 人脸信息队列 QStack irisQueue; // 虹膜信息队列 -// QStack irisLeftQueue; // 左眼信息队列 -// QStack irisRightQueue; // 右眼信息队列 QVector faceFeatures; // 人脸特征值集合 QVector irisFeatures; // 虹膜特征值集合 diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index cb4d3bd..f530212 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -372,6 +372,28 @@ return rect.at(0); } +cv::Rect casic::face::CasicFaceInterface::faceDetectByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + if (rect.size() == 0) + { + return cv::Rect(0, 0, 0, 0); + } + return rect.at(0); +} + cv::Rect casic::face::CasicFaceInterface::eyeDetectByCVCascade(cv::Mat frame) { // 构建openCV自带的眼睛分类器 @@ -402,23 +424,6 @@ return rect.at(0); } -bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) -{ - // 构建OpenCV自带的人脸分类器 - if (this->cascade == nullptr) { - this->cascade = new cv::CascadeClassifier(); - this->cascade->load(cvFaceCascadeName); - } - - std::vector rect; - cv::Size minRectSize(minFaceSize, minFaceSize); - cv::Size maxRectSize(maxFaceSize, maxFaceSize); - - // ★分类器对象调用 - cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); - - return rect.size() == 0 ? false : true; -} bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) { // 构建openCV自带的眼睛分类器 diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index 8a1c564..9d8b8ea 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -1,4 +1,4 @@ -#ifndef CASICFACEINTERFACE_H +#ifndef CASICFACEINTERFACE_H #define CASICFACEINTERFACE_H #include "opencv2/opencv.hpp" @@ -49,8 +49,9 @@ float faceSimCalculate(float* feature, float* otherFeature); cv::Rect faceDetectByCVCascade(cv::Mat frame); + cv::Rect faceDetectByCVCascade(cv::Mat frame, int minFaceSize); + cv::Rect eyeDetectByCVCascade(cv::Mat frame); - bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); @@ -68,7 +69,7 @@ int minFaceSize = 320; int maxFaceSize = 720; int minEyeSize = 100; - int maxEyeSize = 600; + int maxEyeSize = 300; std::string detectorModelPath = "./model/face_detector.csta"; std::string markPts5ModelPath = "./model/face_landmarker_pts5.csta"; diff --git a/conf/config.ini b/conf/config.ini index 84e31c9..79045a6 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -1,4 +1,4 @@ -[com] +[com] #电机控制的串口名 motoPortName=COM3 @@ -17,6 +17,10 @@ maxFaceTryCount=20 #持续没找到人脸的最大次数 maxFaceNotFoundCount=500 +#注册时最小人脸 +minFaceRegist=240 +#识别时最小人脸 +minFaceRecog=100 #虹膜识别最大尝试次数 maxIrisTryCount=10 @@ -34,6 +38,18 @@ #统一背景色 backgroundColor="#FFFFFF" +[work] +#工作状态检测时最小人脸范围 +minFaceSize=160 +#人脸范围最小横坐标 +minFacePosX=320 +#人脸范围最大横坐标 +maxFacePosX=960 +#人脸范围最小纵坐标 +minFacePosY=180 +#人脸范围最大纵坐标 +maxFacePosY=540 + [camera] #人脸摄像头的编号 faceIndex=1 @@ -53,11 +69,3 @@ irisWidth=640 #虹膜图像高度 irisHeight=480 - -[stack] -#拍摄图像栈最大值 -capture=50 -#找到的眼睛图像栈最大值 -found=30 -#质量合格图像栈最大值 -qualified=30 diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 25854c3..0fe4b4c 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -63,7 +63,7 @@ cv::Mat faceMatDisp = imageMatMiir.clone(); // 利用人脸分类器进行初步的检测 - cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp); + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp, SettingConfig::getInstance().MIN_FACE_REGIST_SIZE); if (faceRect.width > 0) { // 初筛检测到人脸时将图像入栈 diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index da744f5..151de09 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -34,7 +34,7 @@ irisInfo.leftOrRight = "right"; } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::MAIN_PAGE) + if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) { // 相机拍摄下的图像1280*960, 直接用于算法判断 QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); @@ -43,7 +43,6 @@ irisInfo.data = imgDisp; irisInfo.matData = irisMat; - // 识别过程任意一个眼睛都行, 全部存入左眼队列 ProMemory::getInstance().pushCasicIris(irisInfo); } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) { diff --git a/device/device.pri b/device/device.pri index 6dc2f3c..64e6e17 100644 --- a/device/device.pri +++ b/device/device.pri @@ -1,24 +1,24 @@ -HEADERS += $$PWD/FaceCameraController.h \ - $$PWD/face/FaceRegistProcess.h -HEADERS += -HEADERS += $$PWD/face/FaceDetectRecogProcess.h +HEADERS += $$PWD/FaceCameraController.h +HEADERS += $$PWD/face/FaceRecogProcess.h +HEADERS += $$PWD/face/FaceRegistProcess.h HEADERS += $$PWD/face/CasicFaceRecState.h -SOURCES += $$PWD/FaceCameraController.cpp \ - $$PWD/face/FaceRegistProcess.cpp -SOURCES += -SOURCES += $$PWD/face/FaceDetectRecogProcess.cpp +SOURCES += $$PWD/FaceCameraController.cpp +SOURCES += $$PWD/face/FaceRecogProcess.cpp +SOURCES += $$PWD/face/FaceRegistProcess.cpp SOURCES += $$PWD/face/CasicFaceRecState.cpp 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/MotoController.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/MotoController.cpp diff --git a/device/face/FaceDetectRecogProcess.cpp b/device/face/FaceDetectRecogProcess.cpp deleted file mode 100644 index d8d6d01..0000000 --- a/device/face/FaceDetectRecogProcess.cpp +++ /dev/null @@ -1,197 +0,0 @@ -#include "FaceDetectRecogProcess.h" - -FaceDetectRecogProcess::FaceDetectRecogProcess(QObject *parent) : QThread(parent) -{ - this->working = false; - this->exit = false; -} - -FaceDetectRecogProcess::~FaceDetectRecogProcess() -{ - this->setWorking(false); -} - -void FaceDetectRecogProcess::setWorking(bool working) -{ - this->working = working; -} -void FaceDetectRecogProcess::exitThread() -{ - this->exit = true; -} -void FaceDetectRecogProcess::startThread() -{ - this->exit = false; - this->start(); -} - -void FaceDetectRecogProcess::addOneTryCount() -{ - LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); - if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) - { - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; - } else - { - CasicFaceRecState::getInstance().tryCount = 0; - CasicFaceRecState::getInstance().noFaceCount = 0; - emit matchFailure(); - - this->setWorking(false); // 返回后则线程暂停工作 - } -} - -void FaceDetectRecogProcess::addOneNoFaceCount() -{ - CasicFaceRecState::getInstance().noFaceCount++; - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; - if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) - { - CasicFaceRecState::getInstance().noFaceCount = 0; - emit matchFailure(); - - this->setWorking(false); // 返回后则暂停工作 - } -} - -void FaceDetectRecogProcess::run() -{ - while (exit == false) - { - if (this->working == false) - { - this->msleep(100); // 100ms后再判断 - continue; - } - - // 图像栈中没有图像则直接返回 - if (ProMemory::getInstance().isFaceQueueEmpty() == true) - { - addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 - LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); - - this->msleep(200); // 200ms后再判断 - continue; - } - - // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 - if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) - { - LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); - this->msleep(200); // 200ms后再判断 - continue; - } - - // 取出人脸图像栈中的一条数据 - CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); - - // 调用人脸检测算法 - faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); - - // 没有找到人脸则返回 - if (faceInfo.hasFace == false) - { - // 表示本次识别结束, 可以开始下一次识别过程 - addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 - LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); - this->msleep(200); // 200ms后再判断 - continue; - } - - // 找到人脸则开始一次识别 - if (CasicFaceRecState::getInstance().recoginzeId == "0") - { - CasicFaceRecState::getInstance().initRecognize(); - } - CasicFaceRecState::getInstance().faceInfo = &faceInfo; - CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 - CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 - - // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 - casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); - faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); - - // 活体检测判断为假脸 - if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) - { - // 表示本次识别结束, 可以开始下一次识别过程 - LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); - - addOneTryCount(); // 判断是否超过次数, 重置识别状态 - this->msleep(200); // 200ms后再判断 - continue; - } - - // 设置识别状态值=通过活体检测 - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; - - // 调用算法提取特征值, 1024个字节的float数组 - faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); - - // 设置识别状态值=特征值提取 - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; - CasicFaceRecState::getInstance().faceInfo = &faceInfo; - - LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); - - // 特征值提取成功的人脸 与人脸库中的人脸进行比较 - compareFaceInCollection(); - } -} - -void FaceDetectRecogProcess::compareFaceInCollection() -{ - ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 - QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); - for (int i = 0; i < faceFeatures.size(); i++) - { - QVariantMap ffMap = faceFeatures.at(i); - - QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); - float ffArr[1024]; - for (int i = 0; i < 1024; i++) - { - QByteArray tempBa; - tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); - ffArr[i] = ByteUtil::binToFloat(tempBa); - } - - float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); - - LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); - if (sim > 0.62) - { - CasicFaceRecState::getInstance().faceInfo->sim = sim; - CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); - CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; - - // 找到匹配的人脸图像 - this->afterRecogAction(ffMap.value("person_id").toString()); - this->setWorking(false); // 找到匹配的人脸之后停止识别线程工作 - return ; - } - } - - this->addOneTryCount(); -} - -void FaceDetectRecogProcess::afterRecogAction(QString personId) -{ - ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 - - LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); - - // 识别记录存入数据库 - RecognitionRecordDao recDao; - QVariantMap record; - record.insert("person_id", personId); - record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); - record.insert("type", "1"); - record.insert("debug_info", CasicFaceRecState::getInstance().toString()); - recDao.save(record); - - // 发送信号, 在主界面上显示 - emit matchSuccess(personId); -} - diff --git a/device/face/FaceDetectRecogProcess.h b/device/face/FaceDetectRecogProcess.h deleted file mode 100644 index 4ca4e94..0000000 --- a/device/face/FaceDetectRecogProcess.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef FACEDETECTRECOGPROCESS_H -#define FACEDETECTRECOGPROCESS_H - -#include -#include -#include "opencv2/opencv.hpp" - -#include "dao/RecognitionRecordDao.h" - -#include "CasicFaceRecState.h" -#include "casic/ProMemory.h" -#include "casic/face/CasicFaceInterface.h" -#include "utils/UtilInclude.h" - -class FaceDetectRecogProcess : public QThread -{ - Q_OBJECT -public: - explicit FaceDetectRecogProcess(QObject *parent = nullptr); - ~FaceDetectRecogProcess(); - - void setWorking(bool working); - void exitThread(); - void startThread(); - - void addOneTryCount(); - void addOneNoFaceCount(); - -protected: - //QThread的虚函数 - //线程处理函数 - //不能直接调用, 通过start()间接调用 - void run(); - void compareFaceInCollection(); - void afterRecogAction(QString personId); - - volatile bool working; - volatile bool exit; - -signals: - void matchSuccess(QString personId); // 匹配成功 - void matchFailure(); // 匹配失败 - -}; - -#endif // FACEDETECTRECOGPROCESS_H diff --git a/device/face/FaceRecogProcess.cpp b/device/face/FaceRecogProcess.cpp new file mode 100644 index 0000000..0fcd9d9 --- /dev/null +++ b/device/face/FaceRecogProcess.cpp @@ -0,0 +1,201 @@ +#include "FaceRecogProcess.h" + +FaceRecogProcess::FaceRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; +} + +FaceRecogProcess::~FaceRecogProcess() +{ + this->setWorking(false); +} + +void FaceRecogProcess::setWorking(bool working) +{ + this->working = working; +} +void FaceRecogProcess::exitThread() +{ + this->exit = true; +} +void FaceRecogProcess::startThread() +{ + this->exit = false; + this->start(); +} + +void FaceRecogProcess::addOneTryCount() +{ + LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); + if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) + { + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + } else + { + CasicFaceRecState::getInstance().tryCount = 0; + CasicFaceRecState::getInstance().noFaceCount = 0; + ProMemory::getInstance().clearFaceQueue(); + emit matchFailure(); + + this->setWorking(false); // 返回后则线程暂停工作 + } +} + +void FaceRecogProcess::addOneNoFaceCount() +{ + CasicFaceRecState::getInstance().noFaceCount++; + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) + { + CasicFaceRecState::getInstance().noFaceCount = 0; + ProMemory::getInstance().clearFaceQueue(); + emit matchFailure(); + + this->setWorking(false); // 返回后则暂停工作 + } +} + +void FaceRecogProcess::run() +{ + while (exit == false) + { + if (this->working == false) + { + this->msleep(100); // 100ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isFaceQueueEmpty() == true) + { + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) + { + LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 取出人脸图像栈中的一条数据 + CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); + + // 调用人脸检测算法 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); + + // 没有找到人脸则返回 + if (faceInfo.hasFace == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 找到人脸则开始一次识别 + if (CasicFaceRecState::getInstance().recoginzeId == "0") + { + CasicFaceRecState::getInstance().initRecognize(); + } + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 + CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 + + // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 + casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); + faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); + + // 活体检测判断为假脸 + if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) + { + // 表示本次识别结束, 可以开始下一次识别过程 + LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); + + addOneTryCount(); // 判断是否超过次数, 重置识别状态 + this->msleep(200); // 200ms后再判断 + continue; + } + + // 设置识别状态值=通过活体检测 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; + + // 调用算法提取特征值, 1024个字节的float数组 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); + + // 设置识别状态值=特征值提取 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + + LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 特征值提取成功的人脸 与人脸库中的人脸进行比较 + compareFaceInCollection(); + } +} + +void FaceRecogProcess::compareFaceInCollection() +{ + ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 + QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); + for (int i = 0; i < faceFeatures.size(); i++) + { + QVariantMap ffMap = faceFeatures.at(i); + + QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); + float ffArr[1024]; + for (int i = 0; i < 1024; i++) + { + QByteArray tempBa; + tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); + ffArr[i] = ByteUtil::binToFloat(tempBa); + } + + float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); + + LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); + if (sim > 0.62) + { + CasicFaceRecState::getInstance().faceInfo->sim = sim; + CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); + CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; + + // 找到匹配的人脸图像 + // 发送信号, 在主界面上显示 + emit matchSuccess(ffMap.value("person_id").toString(), 1); + +// this->afterRecogAction(ffMap.value("person_id").toString()); + this->setWorking(false); // 找到匹配的人脸之后停止识别线程工作 + return ; + } + } + + this->addOneTryCount(); +} + +void FaceRecogProcess::afterRecogAction(QString personId) +{ + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + + LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + +} + diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index d14fd54..05fe5f1 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -258,8 +258,8 @@ // 情况3 编辑时非本人 人脸重复 // 语音提示 - SpeakerUtil::getInstance().speak(QString("人脸重复注册,请重试")); - LOG(DEBUG) << "人脸已经注册" << ui->inputName->text().toStdString(); + SpeakerUtil::getInstance().speak(QString("人脸已注册其他人,请重试")); + LOG(DEBUG) << "人脸已注册其他人" << ui->inputName->text().toStdString(); } } } @@ -288,19 +288,20 @@ // 停止拍图 ProMemory::getInstance().irisCam->stopCapture(); - ProMemory::getInstance().irisRegistPro->setWorking(false); - // 语音提示 - SpeakerUtil::getInstance().speak(QString("虹膜重复注册,请重试")); - if (this->personId.isEmpty() == true) { // 情况1 新注册 重复注册 loadPersonInfo(personIdByIris); + + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已经注册,请重试")); LOG(DEBUG) << "虹膜已经注册" << ui->inputName->text().toStdString(); } else { - LOG(DEBUG) << "虹膜已经注册" << personIdByIris.toStdString(); + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已注册其他人,请重试")); + LOG(DEBUG) << "虹膜已注册其他人" << personIdByIris.toStdString(); } } diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index 45fe761..f202cfe 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -30,6 +30,7 @@ initFaceRegistThread(); // 人脸注册线程 initFaceRecogThread(); // 人脸识别线程 initIrisRegistThread(); // 虹膜注册线程 + initIrisRecogThread(); // 虹膜识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); @@ -67,6 +68,10 @@ ProMemory::getInstance().irisRegistPro->deleteLater(); ProMemory::getInstance().irisRegistPro->wait(); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + // 关闭自动启动的外部程序 // outExe->close(); // delete outExe; @@ -75,6 +80,7 @@ delete ProMemory::getInstance().faceRegistPro; delete ProMemory::getInstance().faceRecogPro; delete ProMemory::getInstance().irisRegistPro; + delete ProMemory::getInstance().irisRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -194,15 +200,17 @@ void CasicBioRecWin::initFaceRecogThread() { // 人脸识别处理过程 - ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + ProMemory::getInstance().faceRecogPro = new FaceRecogProcess(this); // 绑定信号与槽函数 // 识别成功 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, - recogResultForm, &RecognizeResultForm::showRecognizeResult); +// connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); // 识别失败 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchFailure, recogResultForm, &RecognizeResultForm::showRecogFailure); ProMemory::getInstance().faceRecogPro->start(); @@ -222,9 +230,28 @@ connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::captureIrisFailure, addPersonForm, &AddPersonForm::onFailedCaptureIris); - // 采集虹膜图像成功 有匹配到红魔库 + // 采集虹膜图像成功 有匹配到虹膜库 connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::findMatchedIris, addPersonForm, &AddPersonForm::onMatchedIris); ProMemory::getInstance().irisRegistPro->start(); } + +void CasicBioRecWin::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 +// connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index ff2ed35..b70245a 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -53,6 +53,7 @@ void initFaceRegistThread(); void initFaceRecogThread(); void initIrisRegistThread(); + void initIrisRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp index b61cb09..e45a191 100644 --- a/RecognizeResultForm.cpp +++ b/RecognizeResultForm.cpp @@ -26,10 +26,28 @@ void RecognizeResultForm::startWorkingRecognize() { // 开始人脸识别 - ProMemory::getInstance().faceRecogPro->setWorking(true); + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + // 人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + break; + case 2: + // 虹膜识别 + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + case 3: + case 4: + // 人脸和虹膜都需要打开 + ProMemory::getInstance().faceRecogPro->setWorking(true); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + } // 将界面切换到识别界面 RecognizeResultForm ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + ui->labBackground->raise(); // 1人脸图像显示的容器 ui->labVideo->resize(1280, 720); @@ -63,13 +81,17 @@ ui->widgetFail->show(); QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ - emit backToHomeAndWait(); - CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; + + emit backToHomeAndWait(); }); } void RecognizeResultForm::showRecognizeResult(QString personId) { + personIdByFace = ""; + personIdByIris = ""; + SpeakerUtil::getInstance().speak("识别成功"); ui->labVideo->hide(); ui->labTitle->hide(); @@ -102,8 +124,131 @@ ui->widgetSucc->show(); QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ - emit backToHomeAndWait(); CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + + emit backToHomeAndWait(); }); } + +void RecognizeResultForm::checkRecognizeResult(QString personId, int faceOrIris) +{ + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + { + // 仅人脸识别 + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 人脸识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 2: + { + // 仅虹膜识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜识别成功 [%1]").arg(CasicIrisRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "2"); + record.insert("debug_info", CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 4: + { + // 任意识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + QString logStr = QString("[RecognizeResultForm]%1识别成功[%2]"); + if (faceOrIris == 1) + { + logStr.arg("人脸").arg(CasicFaceRecState::getInstance().toString()); + } else if (faceOrIris == 2) + { + logStr.arg("虹膜").arg(CasicIrisRecState::getInstance().toString()); + } + LOG(DEBUG) << logStr.toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", QString::number(faceOrIris)); + record.insert("debug_info", faceOrIris == 1 ? CasicFaceRecState::getInstance().toString() : CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 3: + if (faceOrIris == 1) + { + this->personIdByFace = personId; + } else if (faceOrIris == 2) + { + this->personIdByIris = personId; + } + + if (personIdByFace.isEmpty() || personIdByIris.isEmpty()) + { + // 只有一个成功的结果 需要等待下次 + return; + } else if (personIdByFace != personIdByIris) + { + // 人脸和虹膜识别的不是同一人 识别失败 + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜与人脸识别结果不一致,识别失败 [face: %1][iris: %2]").arg(personIdByFace).arg(personIdByIris).toStdString(); + SpeakerUtil::getInstance().speak("虹膜与人脸识别结果不一致,识别失败,请重试"); + showRecogFailure(); + } else + { + LOG(DEBUG) << QString("[RecognizeResultForm]人脸虹膜识别成功").toStdString(); + showRecognizeResult(personId); + } + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "4"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString() + " " + CasicIrisRecState::getInstance().toString()); + recDao.save(record); + } +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h index f5ef019..2c51865 100644 --- a/RecognizeResultForm.h +++ b/RecognizeResultForm.h @@ -25,7 +25,8 @@ public slots: void showRecogFailure(); - void showRecognizeResult(QString personId); + + void checkRecognizeResult(QString personId, int faceOrIris); void startWorkingRecognize(); // 开始工作 void drawImageOnHomeForm(QImage imageDisp); @@ -33,6 +34,11 @@ private: Ui::RecognizeResultForm *ui; + QString personIdByFace; + QString personIdByIris; + + void showRecognizeResult(QString personId); + signals: void backToHomeAndWait(); // 识别结束 返回主界面并待机 diff --git a/StartupForm.cpp b/StartupForm.cpp index 3d3dfad..16c4dfc 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -29,8 +29,8 @@ // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); -// connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, -// this, &StartupForm::takeOneFrameForCheckStatus); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); TimeCounterUtil::getInstance().clockCounter->start(1000); } @@ -54,6 +54,12 @@ return; } + if (this->isVisible() == false) + { + // 没有在这个页面直接返回 + return; + } + // 不在这个页面 则直接返回 不做后续判断 if (ProMemory::getInstance().widgeFrame != CasicBioRecConst::WidgeFrameName::MAIN_PAGE) { @@ -61,10 +67,25 @@ } cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); - bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + + // 判断是否开始工作时使用严格标准 人脸大小需要符合注册图像的尺寸 + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(rawFrame, SettingConfig::getInstance().MIN_WORK_FACE_SIZE); + if (faceRect.width == 0) + { + return ; + } + + bool hasFace = faceRect.width == 0 ? false : true; + if (faceRect.x < SettingConfig::getInstance().MIN_WORK_FACE_POSX || faceRect.x > SettingConfig::getInstance().MAX_WORK_FACE_POSX || + faceRect.y < SettingConfig::getInstance().MIN_WORK_FACE_POSY || faceRect.y > SettingConfig::getInstance().MAX_WORK_FACE_POSY) + { + // 检测到的人脸不在核心区则返回 + hasFace = false; + } + if (hasFace == true) { - LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + LOG(INFO) << QString("检测到人脸,START RECOGNIZE 线程").toStdString(); ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; // 启动识别线程 diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 1bc7d3a..3e9fbd4 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -13,14 +13,16 @@ #include "device/FaceCameraController.h" #include "device/IrisCameraController.h" #include "device/face/FaceRegistProcess.h" -#include "device/face/FaceDetectRecogProcess.h" +#include "device/face/FaceRecogProcess.h" #include "device/iris/IrisRegistProcess.h" +#include "device/iris/IrisRecogProcess.h" class FaceCameraController; class IrisCameraController; class FaceRegistProcess; -class FaceDetectRecogProcess; +class FaceRecogProcess; class IrisRegistProcess; +class IrisRecogProcess; class ProMemory { @@ -58,18 +60,17 @@ FaceCameraController * faceCam; FaceRegistProcess * faceRegistPro; - FaceDetectRecogProcess * faceRecogPro; + FaceRecogProcess * faceRecogPro; IrisCameraController * irisCam; IrisRegistProcess * irisRegistPro; + IrisRecogProcess * irisRecogPro; private: ProMemory(); QStack faceQueue; // 人脸信息队列 QStack irisQueue; // 虹膜信息队列 -// QStack irisLeftQueue; // 左眼信息队列 -// QStack irisRightQueue; // 右眼信息队列 QVector faceFeatures; // 人脸特征值集合 QVector irisFeatures; // 虹膜特征值集合 diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index cb4d3bd..f530212 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -372,6 +372,28 @@ return rect.at(0); } +cv::Rect casic::face::CasicFaceInterface::faceDetectByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + if (rect.size() == 0) + { + return cv::Rect(0, 0, 0, 0); + } + return rect.at(0); +} + cv::Rect casic::face::CasicFaceInterface::eyeDetectByCVCascade(cv::Mat frame) { // 构建openCV自带的眼睛分类器 @@ -402,23 +424,6 @@ return rect.at(0); } -bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) -{ - // 构建OpenCV自带的人脸分类器 - if (this->cascade == nullptr) { - this->cascade = new cv::CascadeClassifier(); - this->cascade->load(cvFaceCascadeName); - } - - std::vector rect; - cv::Size minRectSize(minFaceSize, minFaceSize); - cv::Size maxRectSize(maxFaceSize, maxFaceSize); - - // ★分类器对象调用 - cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); - - return rect.size() == 0 ? false : true; -} bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) { // 构建openCV自带的眼睛分类器 diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index 8a1c564..9d8b8ea 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -1,4 +1,4 @@ -#ifndef CASICFACEINTERFACE_H +#ifndef CASICFACEINTERFACE_H #define CASICFACEINTERFACE_H #include "opencv2/opencv.hpp" @@ -49,8 +49,9 @@ float faceSimCalculate(float* feature, float* otherFeature); cv::Rect faceDetectByCVCascade(cv::Mat frame); + cv::Rect faceDetectByCVCascade(cv::Mat frame, int minFaceSize); + cv::Rect eyeDetectByCVCascade(cv::Mat frame); - bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); @@ -68,7 +69,7 @@ int minFaceSize = 320; int maxFaceSize = 720; int minEyeSize = 100; - int maxEyeSize = 600; + int maxEyeSize = 300; std::string detectorModelPath = "./model/face_detector.csta"; std::string markPts5ModelPath = "./model/face_landmarker_pts5.csta"; diff --git a/conf/config.ini b/conf/config.ini index 84e31c9..79045a6 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -1,4 +1,4 @@ -[com] +[com] #电机控制的串口名 motoPortName=COM3 @@ -17,6 +17,10 @@ maxFaceTryCount=20 #持续没找到人脸的最大次数 maxFaceNotFoundCount=500 +#注册时最小人脸 +minFaceRegist=240 +#识别时最小人脸 +minFaceRecog=100 #虹膜识别最大尝试次数 maxIrisTryCount=10 @@ -34,6 +38,18 @@ #统一背景色 backgroundColor="#FFFFFF" +[work] +#工作状态检测时最小人脸范围 +minFaceSize=160 +#人脸范围最小横坐标 +minFacePosX=320 +#人脸范围最大横坐标 +maxFacePosX=960 +#人脸范围最小纵坐标 +minFacePosY=180 +#人脸范围最大纵坐标 +maxFacePosY=540 + [camera] #人脸摄像头的编号 faceIndex=1 @@ -53,11 +69,3 @@ irisWidth=640 #虹膜图像高度 irisHeight=480 - -[stack] -#拍摄图像栈最大值 -capture=50 -#找到的眼睛图像栈最大值 -found=30 -#质量合格图像栈最大值 -qualified=30 diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 25854c3..0fe4b4c 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -63,7 +63,7 @@ cv::Mat faceMatDisp = imageMatMiir.clone(); // 利用人脸分类器进行初步的检测 - cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp); + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp, SettingConfig::getInstance().MIN_FACE_REGIST_SIZE); if (faceRect.width > 0) { // 初筛检测到人脸时将图像入栈 diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index da744f5..151de09 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -34,7 +34,7 @@ irisInfo.leftOrRight = "right"; } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::MAIN_PAGE) + if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) { // 相机拍摄下的图像1280*960, 直接用于算法判断 QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); @@ -43,7 +43,6 @@ irisInfo.data = imgDisp; irisInfo.matData = irisMat; - // 识别过程任意一个眼睛都行, 全部存入左眼队列 ProMemory::getInstance().pushCasicIris(irisInfo); } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) { diff --git a/device/device.pri b/device/device.pri index 6dc2f3c..64e6e17 100644 --- a/device/device.pri +++ b/device/device.pri @@ -1,24 +1,24 @@ -HEADERS += $$PWD/FaceCameraController.h \ - $$PWD/face/FaceRegistProcess.h -HEADERS += -HEADERS += $$PWD/face/FaceDetectRecogProcess.h +HEADERS += $$PWD/FaceCameraController.h +HEADERS += $$PWD/face/FaceRecogProcess.h +HEADERS += $$PWD/face/FaceRegistProcess.h HEADERS += $$PWD/face/CasicFaceRecState.h -SOURCES += $$PWD/FaceCameraController.cpp \ - $$PWD/face/FaceRegistProcess.cpp -SOURCES += -SOURCES += $$PWD/face/FaceDetectRecogProcess.cpp +SOURCES += $$PWD/FaceCameraController.cpp +SOURCES += $$PWD/face/FaceRecogProcess.cpp +SOURCES += $$PWD/face/FaceRegistProcess.cpp SOURCES += $$PWD/face/CasicFaceRecState.cpp 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/MotoController.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/MotoController.cpp diff --git a/device/face/FaceDetectRecogProcess.cpp b/device/face/FaceDetectRecogProcess.cpp deleted file mode 100644 index d8d6d01..0000000 --- a/device/face/FaceDetectRecogProcess.cpp +++ /dev/null @@ -1,197 +0,0 @@ -#include "FaceDetectRecogProcess.h" - -FaceDetectRecogProcess::FaceDetectRecogProcess(QObject *parent) : QThread(parent) -{ - this->working = false; - this->exit = false; -} - -FaceDetectRecogProcess::~FaceDetectRecogProcess() -{ - this->setWorking(false); -} - -void FaceDetectRecogProcess::setWorking(bool working) -{ - this->working = working; -} -void FaceDetectRecogProcess::exitThread() -{ - this->exit = true; -} -void FaceDetectRecogProcess::startThread() -{ - this->exit = false; - this->start(); -} - -void FaceDetectRecogProcess::addOneTryCount() -{ - LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); - if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) - { - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; - } else - { - CasicFaceRecState::getInstance().tryCount = 0; - CasicFaceRecState::getInstance().noFaceCount = 0; - emit matchFailure(); - - this->setWorking(false); // 返回后则线程暂停工作 - } -} - -void FaceDetectRecogProcess::addOneNoFaceCount() -{ - CasicFaceRecState::getInstance().noFaceCount++; - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; - if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) - { - CasicFaceRecState::getInstance().noFaceCount = 0; - emit matchFailure(); - - this->setWorking(false); // 返回后则暂停工作 - } -} - -void FaceDetectRecogProcess::run() -{ - while (exit == false) - { - if (this->working == false) - { - this->msleep(100); // 100ms后再判断 - continue; - } - - // 图像栈中没有图像则直接返回 - if (ProMemory::getInstance().isFaceQueueEmpty() == true) - { - addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 - LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); - - this->msleep(200); // 200ms后再判断 - continue; - } - - // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 - if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) - { - LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); - this->msleep(200); // 200ms后再判断 - continue; - } - - // 取出人脸图像栈中的一条数据 - CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); - - // 调用人脸检测算法 - faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); - - // 没有找到人脸则返回 - if (faceInfo.hasFace == false) - { - // 表示本次识别结束, 可以开始下一次识别过程 - addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 - LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); - this->msleep(200); // 200ms后再判断 - continue; - } - - // 找到人脸则开始一次识别 - if (CasicFaceRecState::getInstance().recoginzeId == "0") - { - CasicFaceRecState::getInstance().initRecognize(); - } - CasicFaceRecState::getInstance().faceInfo = &faceInfo; - CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 - CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 - - // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 - casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); - faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); - - // 活体检测判断为假脸 - if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) - { - // 表示本次识别结束, 可以开始下一次识别过程 - LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); - - addOneTryCount(); // 判断是否超过次数, 重置识别状态 - this->msleep(200); // 200ms后再判断 - continue; - } - - // 设置识别状态值=通过活体检测 - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; - - // 调用算法提取特征值, 1024个字节的float数组 - faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); - - // 设置识别状态值=特征值提取 - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; - CasicFaceRecState::getInstance().faceInfo = &faceInfo; - - LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); - - // 特征值提取成功的人脸 与人脸库中的人脸进行比较 - compareFaceInCollection(); - } -} - -void FaceDetectRecogProcess::compareFaceInCollection() -{ - ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 - QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); - for (int i = 0; i < faceFeatures.size(); i++) - { - QVariantMap ffMap = faceFeatures.at(i); - - QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); - float ffArr[1024]; - for (int i = 0; i < 1024; i++) - { - QByteArray tempBa; - tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); - ffArr[i] = ByteUtil::binToFloat(tempBa); - } - - float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); - - LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); - if (sim > 0.62) - { - CasicFaceRecState::getInstance().faceInfo->sim = sim; - CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); - CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; - - // 找到匹配的人脸图像 - this->afterRecogAction(ffMap.value("person_id").toString()); - this->setWorking(false); // 找到匹配的人脸之后停止识别线程工作 - return ; - } - } - - this->addOneTryCount(); -} - -void FaceDetectRecogProcess::afterRecogAction(QString personId) -{ - ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 - - LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); - - // 识别记录存入数据库 - RecognitionRecordDao recDao; - QVariantMap record; - record.insert("person_id", personId); - record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); - record.insert("type", "1"); - record.insert("debug_info", CasicFaceRecState::getInstance().toString()); - recDao.save(record); - - // 发送信号, 在主界面上显示 - emit matchSuccess(personId); -} - diff --git a/device/face/FaceDetectRecogProcess.h b/device/face/FaceDetectRecogProcess.h deleted file mode 100644 index 4ca4e94..0000000 --- a/device/face/FaceDetectRecogProcess.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef FACEDETECTRECOGPROCESS_H -#define FACEDETECTRECOGPROCESS_H - -#include -#include -#include "opencv2/opencv.hpp" - -#include "dao/RecognitionRecordDao.h" - -#include "CasicFaceRecState.h" -#include "casic/ProMemory.h" -#include "casic/face/CasicFaceInterface.h" -#include "utils/UtilInclude.h" - -class FaceDetectRecogProcess : public QThread -{ - Q_OBJECT -public: - explicit FaceDetectRecogProcess(QObject *parent = nullptr); - ~FaceDetectRecogProcess(); - - void setWorking(bool working); - void exitThread(); - void startThread(); - - void addOneTryCount(); - void addOneNoFaceCount(); - -protected: - //QThread的虚函数 - //线程处理函数 - //不能直接调用, 通过start()间接调用 - void run(); - void compareFaceInCollection(); - void afterRecogAction(QString personId); - - volatile bool working; - volatile bool exit; - -signals: - void matchSuccess(QString personId); // 匹配成功 - void matchFailure(); // 匹配失败 - -}; - -#endif // FACEDETECTRECOGPROCESS_H diff --git a/device/face/FaceRecogProcess.cpp b/device/face/FaceRecogProcess.cpp new file mode 100644 index 0000000..0fcd9d9 --- /dev/null +++ b/device/face/FaceRecogProcess.cpp @@ -0,0 +1,201 @@ +#include "FaceRecogProcess.h" + +FaceRecogProcess::FaceRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; +} + +FaceRecogProcess::~FaceRecogProcess() +{ + this->setWorking(false); +} + +void FaceRecogProcess::setWorking(bool working) +{ + this->working = working; +} +void FaceRecogProcess::exitThread() +{ + this->exit = true; +} +void FaceRecogProcess::startThread() +{ + this->exit = false; + this->start(); +} + +void FaceRecogProcess::addOneTryCount() +{ + LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); + if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) + { + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + } else + { + CasicFaceRecState::getInstance().tryCount = 0; + CasicFaceRecState::getInstance().noFaceCount = 0; + ProMemory::getInstance().clearFaceQueue(); + emit matchFailure(); + + this->setWorking(false); // 返回后则线程暂停工作 + } +} + +void FaceRecogProcess::addOneNoFaceCount() +{ + CasicFaceRecState::getInstance().noFaceCount++; + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) + { + CasicFaceRecState::getInstance().noFaceCount = 0; + ProMemory::getInstance().clearFaceQueue(); + emit matchFailure(); + + this->setWorking(false); // 返回后则暂停工作 + } +} + +void FaceRecogProcess::run() +{ + while (exit == false) + { + if (this->working == false) + { + this->msleep(100); // 100ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isFaceQueueEmpty() == true) + { + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) + { + LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 取出人脸图像栈中的一条数据 + CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); + + // 调用人脸检测算法 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); + + // 没有找到人脸则返回 + if (faceInfo.hasFace == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 找到人脸则开始一次识别 + if (CasicFaceRecState::getInstance().recoginzeId == "0") + { + CasicFaceRecState::getInstance().initRecognize(); + } + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 + CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 + + // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 + casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); + faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); + + // 活体检测判断为假脸 + if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) + { + // 表示本次识别结束, 可以开始下一次识别过程 + LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); + + addOneTryCount(); // 判断是否超过次数, 重置识别状态 + this->msleep(200); // 200ms后再判断 + continue; + } + + // 设置识别状态值=通过活体检测 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; + + // 调用算法提取特征值, 1024个字节的float数组 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); + + // 设置识别状态值=特征值提取 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + + LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 特征值提取成功的人脸 与人脸库中的人脸进行比较 + compareFaceInCollection(); + } +} + +void FaceRecogProcess::compareFaceInCollection() +{ + ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 + QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); + for (int i = 0; i < faceFeatures.size(); i++) + { + QVariantMap ffMap = faceFeatures.at(i); + + QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); + float ffArr[1024]; + for (int i = 0; i < 1024; i++) + { + QByteArray tempBa; + tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); + ffArr[i] = ByteUtil::binToFloat(tempBa); + } + + float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); + + LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); + if (sim > 0.62) + { + CasicFaceRecState::getInstance().faceInfo->sim = sim; + CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); + CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; + + // 找到匹配的人脸图像 + // 发送信号, 在主界面上显示 + emit matchSuccess(ffMap.value("person_id").toString(), 1); + +// this->afterRecogAction(ffMap.value("person_id").toString()); + this->setWorking(false); // 找到匹配的人脸之后停止识别线程工作 + return ; + } + } + + this->addOneTryCount(); +} + +void FaceRecogProcess::afterRecogAction(QString personId) +{ + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + + LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + +} + diff --git a/device/face/FaceRecogProcess.h b/device/face/FaceRecogProcess.h new file mode 100644 index 0000000..c551e23 --- /dev/null +++ b/device/face/FaceRecogProcess.h @@ -0,0 +1,46 @@ +#ifndef FACERECOGPROCESS_H +#define FACERECOGPROCESS_H + +#include +#include +#include "opencv2/opencv.hpp" + +#include "dao/RecognitionRecordDao.h" + +#include "CasicFaceRecState.h" +#include "casic/ProMemory.h" +#include "casic/face/CasicFaceInterface.h" +#include "utils/UtilInclude.h" + +class FaceRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit FaceRecogProcess(QObject *parent = nullptr); + ~FaceRecogProcess(); + + void setWorking(bool working); + void exitThread(); + void startThread(); + + void addOneTryCount(); + void addOneNoFaceCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + void compareFaceInCollection(); + void afterRecogAction(QString personId); + + volatile bool working; + volatile bool exit; + +signals: + void matchSuccess(QString personId, int faceOrIris); // 匹配成功 + void matchFailure(); // 匹配失败 + +}; + +#endif // FACERECOGPROCESS_H diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index d14fd54..05fe5f1 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -258,8 +258,8 @@ // 情况3 编辑时非本人 人脸重复 // 语音提示 - SpeakerUtil::getInstance().speak(QString("人脸重复注册,请重试")); - LOG(DEBUG) << "人脸已经注册" << ui->inputName->text().toStdString(); + SpeakerUtil::getInstance().speak(QString("人脸已注册其他人,请重试")); + LOG(DEBUG) << "人脸已注册其他人" << ui->inputName->text().toStdString(); } } } @@ -288,19 +288,20 @@ // 停止拍图 ProMemory::getInstance().irisCam->stopCapture(); - ProMemory::getInstance().irisRegistPro->setWorking(false); - // 语音提示 - SpeakerUtil::getInstance().speak(QString("虹膜重复注册,请重试")); - if (this->personId.isEmpty() == true) { // 情况1 新注册 重复注册 loadPersonInfo(personIdByIris); + + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已经注册,请重试")); LOG(DEBUG) << "虹膜已经注册" << ui->inputName->text().toStdString(); } else { - LOG(DEBUG) << "虹膜已经注册" << personIdByIris.toStdString(); + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已注册其他人,请重试")); + LOG(DEBUG) << "虹膜已注册其他人" << personIdByIris.toStdString(); } } diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index 45fe761..f202cfe 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -30,6 +30,7 @@ initFaceRegistThread(); // 人脸注册线程 initFaceRecogThread(); // 人脸识别线程 initIrisRegistThread(); // 虹膜注册线程 + initIrisRecogThread(); // 虹膜识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); @@ -67,6 +68,10 @@ ProMemory::getInstance().irisRegistPro->deleteLater(); ProMemory::getInstance().irisRegistPro->wait(); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + // 关闭自动启动的外部程序 // outExe->close(); // delete outExe; @@ -75,6 +80,7 @@ delete ProMemory::getInstance().faceRegistPro; delete ProMemory::getInstance().faceRecogPro; delete ProMemory::getInstance().irisRegistPro; + delete ProMemory::getInstance().irisRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -194,15 +200,17 @@ void CasicBioRecWin::initFaceRecogThread() { // 人脸识别处理过程 - ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + ProMemory::getInstance().faceRecogPro = new FaceRecogProcess(this); // 绑定信号与槽函数 // 识别成功 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, - recogResultForm, &RecognizeResultForm::showRecognizeResult); +// connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); // 识别失败 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchFailure, recogResultForm, &RecognizeResultForm::showRecogFailure); ProMemory::getInstance().faceRecogPro->start(); @@ -222,9 +230,28 @@ connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::captureIrisFailure, addPersonForm, &AddPersonForm::onFailedCaptureIris); - // 采集虹膜图像成功 有匹配到红魔库 + // 采集虹膜图像成功 有匹配到虹膜库 connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::findMatchedIris, addPersonForm, &AddPersonForm::onMatchedIris); ProMemory::getInstance().irisRegistPro->start(); } + +void CasicBioRecWin::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 +// connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index ff2ed35..b70245a 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -53,6 +53,7 @@ void initFaceRegistThread(); void initFaceRecogThread(); void initIrisRegistThread(); + void initIrisRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp index b61cb09..e45a191 100644 --- a/RecognizeResultForm.cpp +++ b/RecognizeResultForm.cpp @@ -26,10 +26,28 @@ void RecognizeResultForm::startWorkingRecognize() { // 开始人脸识别 - ProMemory::getInstance().faceRecogPro->setWorking(true); + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + // 人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + break; + case 2: + // 虹膜识别 + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + case 3: + case 4: + // 人脸和虹膜都需要打开 + ProMemory::getInstance().faceRecogPro->setWorking(true); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + } // 将界面切换到识别界面 RecognizeResultForm ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + ui->labBackground->raise(); // 1人脸图像显示的容器 ui->labVideo->resize(1280, 720); @@ -63,13 +81,17 @@ ui->widgetFail->show(); QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ - emit backToHomeAndWait(); - CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; + + emit backToHomeAndWait(); }); } void RecognizeResultForm::showRecognizeResult(QString personId) { + personIdByFace = ""; + personIdByIris = ""; + SpeakerUtil::getInstance().speak("识别成功"); ui->labVideo->hide(); ui->labTitle->hide(); @@ -102,8 +124,131 @@ ui->widgetSucc->show(); QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ - emit backToHomeAndWait(); CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + + emit backToHomeAndWait(); }); } + +void RecognizeResultForm::checkRecognizeResult(QString personId, int faceOrIris) +{ + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + { + // 仅人脸识别 + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 人脸识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 2: + { + // 仅虹膜识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜识别成功 [%1]").arg(CasicIrisRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "2"); + record.insert("debug_info", CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 4: + { + // 任意识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + QString logStr = QString("[RecognizeResultForm]%1识别成功[%2]"); + if (faceOrIris == 1) + { + logStr.arg("人脸").arg(CasicFaceRecState::getInstance().toString()); + } else if (faceOrIris == 2) + { + logStr.arg("虹膜").arg(CasicIrisRecState::getInstance().toString()); + } + LOG(DEBUG) << logStr.toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", QString::number(faceOrIris)); + record.insert("debug_info", faceOrIris == 1 ? CasicFaceRecState::getInstance().toString() : CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 3: + if (faceOrIris == 1) + { + this->personIdByFace = personId; + } else if (faceOrIris == 2) + { + this->personIdByIris = personId; + } + + if (personIdByFace.isEmpty() || personIdByIris.isEmpty()) + { + // 只有一个成功的结果 需要等待下次 + return; + } else if (personIdByFace != personIdByIris) + { + // 人脸和虹膜识别的不是同一人 识别失败 + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜与人脸识别结果不一致,识别失败 [face: %1][iris: %2]").arg(personIdByFace).arg(personIdByIris).toStdString(); + SpeakerUtil::getInstance().speak("虹膜与人脸识别结果不一致,识别失败,请重试"); + showRecogFailure(); + } else + { + LOG(DEBUG) << QString("[RecognizeResultForm]人脸虹膜识别成功").toStdString(); + showRecognizeResult(personId); + } + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "4"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString() + " " + CasicIrisRecState::getInstance().toString()); + recDao.save(record); + } +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h index f5ef019..2c51865 100644 --- a/RecognizeResultForm.h +++ b/RecognizeResultForm.h @@ -25,7 +25,8 @@ public slots: void showRecogFailure(); - void showRecognizeResult(QString personId); + + void checkRecognizeResult(QString personId, int faceOrIris); void startWorkingRecognize(); // 开始工作 void drawImageOnHomeForm(QImage imageDisp); @@ -33,6 +34,11 @@ private: Ui::RecognizeResultForm *ui; + QString personIdByFace; + QString personIdByIris; + + void showRecognizeResult(QString personId); + signals: void backToHomeAndWait(); // 识别结束 返回主界面并待机 diff --git a/StartupForm.cpp b/StartupForm.cpp index 3d3dfad..16c4dfc 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -29,8 +29,8 @@ // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); -// connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, -// this, &StartupForm::takeOneFrameForCheckStatus); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); TimeCounterUtil::getInstance().clockCounter->start(1000); } @@ -54,6 +54,12 @@ return; } + if (this->isVisible() == false) + { + // 没有在这个页面直接返回 + return; + } + // 不在这个页面 则直接返回 不做后续判断 if (ProMemory::getInstance().widgeFrame != CasicBioRecConst::WidgeFrameName::MAIN_PAGE) { @@ -61,10 +67,25 @@ } cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); - bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + + // 判断是否开始工作时使用严格标准 人脸大小需要符合注册图像的尺寸 + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(rawFrame, SettingConfig::getInstance().MIN_WORK_FACE_SIZE); + if (faceRect.width == 0) + { + return ; + } + + bool hasFace = faceRect.width == 0 ? false : true; + if (faceRect.x < SettingConfig::getInstance().MIN_WORK_FACE_POSX || faceRect.x > SettingConfig::getInstance().MAX_WORK_FACE_POSX || + faceRect.y < SettingConfig::getInstance().MIN_WORK_FACE_POSY || faceRect.y > SettingConfig::getInstance().MAX_WORK_FACE_POSY) + { + // 检测到的人脸不在核心区则返回 + hasFace = false; + } + if (hasFace == true) { - LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + LOG(INFO) << QString("检测到人脸,START RECOGNIZE 线程").toStdString(); ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; // 启动识别线程 diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 1bc7d3a..3e9fbd4 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -13,14 +13,16 @@ #include "device/FaceCameraController.h" #include "device/IrisCameraController.h" #include "device/face/FaceRegistProcess.h" -#include "device/face/FaceDetectRecogProcess.h" +#include "device/face/FaceRecogProcess.h" #include "device/iris/IrisRegistProcess.h" +#include "device/iris/IrisRecogProcess.h" class FaceCameraController; class IrisCameraController; class FaceRegistProcess; -class FaceDetectRecogProcess; +class FaceRecogProcess; class IrisRegistProcess; +class IrisRecogProcess; class ProMemory { @@ -58,18 +60,17 @@ FaceCameraController * faceCam; FaceRegistProcess * faceRegistPro; - FaceDetectRecogProcess * faceRecogPro; + FaceRecogProcess * faceRecogPro; IrisCameraController * irisCam; IrisRegistProcess * irisRegistPro; + IrisRecogProcess * irisRecogPro; private: ProMemory(); QStack faceQueue; // 人脸信息队列 QStack irisQueue; // 虹膜信息队列 -// QStack irisLeftQueue; // 左眼信息队列 -// QStack irisRightQueue; // 右眼信息队列 QVector faceFeatures; // 人脸特征值集合 QVector irisFeatures; // 虹膜特征值集合 diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index cb4d3bd..f530212 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -372,6 +372,28 @@ return rect.at(0); } +cv::Rect casic::face::CasicFaceInterface::faceDetectByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + if (rect.size() == 0) + { + return cv::Rect(0, 0, 0, 0); + } + return rect.at(0); +} + cv::Rect casic::face::CasicFaceInterface::eyeDetectByCVCascade(cv::Mat frame) { // 构建openCV自带的眼睛分类器 @@ -402,23 +424,6 @@ return rect.at(0); } -bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) -{ - // 构建OpenCV自带的人脸分类器 - if (this->cascade == nullptr) { - this->cascade = new cv::CascadeClassifier(); - this->cascade->load(cvFaceCascadeName); - } - - std::vector rect; - cv::Size minRectSize(minFaceSize, minFaceSize); - cv::Size maxRectSize(maxFaceSize, maxFaceSize); - - // ★分类器对象调用 - cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); - - return rect.size() == 0 ? false : true; -} bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) { // 构建openCV自带的眼睛分类器 diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index 8a1c564..9d8b8ea 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -1,4 +1,4 @@ -#ifndef CASICFACEINTERFACE_H +#ifndef CASICFACEINTERFACE_H #define CASICFACEINTERFACE_H #include "opencv2/opencv.hpp" @@ -49,8 +49,9 @@ float faceSimCalculate(float* feature, float* otherFeature); cv::Rect faceDetectByCVCascade(cv::Mat frame); + cv::Rect faceDetectByCVCascade(cv::Mat frame, int minFaceSize); + cv::Rect eyeDetectByCVCascade(cv::Mat frame); - bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); @@ -68,7 +69,7 @@ int minFaceSize = 320; int maxFaceSize = 720; int minEyeSize = 100; - int maxEyeSize = 600; + int maxEyeSize = 300; std::string detectorModelPath = "./model/face_detector.csta"; std::string markPts5ModelPath = "./model/face_landmarker_pts5.csta"; diff --git a/conf/config.ini b/conf/config.ini index 84e31c9..79045a6 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -1,4 +1,4 @@ -[com] +[com] #电机控制的串口名 motoPortName=COM3 @@ -17,6 +17,10 @@ maxFaceTryCount=20 #持续没找到人脸的最大次数 maxFaceNotFoundCount=500 +#注册时最小人脸 +minFaceRegist=240 +#识别时最小人脸 +minFaceRecog=100 #虹膜识别最大尝试次数 maxIrisTryCount=10 @@ -34,6 +38,18 @@ #统一背景色 backgroundColor="#FFFFFF" +[work] +#工作状态检测时最小人脸范围 +minFaceSize=160 +#人脸范围最小横坐标 +minFacePosX=320 +#人脸范围最大横坐标 +maxFacePosX=960 +#人脸范围最小纵坐标 +minFacePosY=180 +#人脸范围最大纵坐标 +maxFacePosY=540 + [camera] #人脸摄像头的编号 faceIndex=1 @@ -53,11 +69,3 @@ irisWidth=640 #虹膜图像高度 irisHeight=480 - -[stack] -#拍摄图像栈最大值 -capture=50 -#找到的眼睛图像栈最大值 -found=30 -#质量合格图像栈最大值 -qualified=30 diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 25854c3..0fe4b4c 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -63,7 +63,7 @@ cv::Mat faceMatDisp = imageMatMiir.clone(); // 利用人脸分类器进行初步的检测 - cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp); + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp, SettingConfig::getInstance().MIN_FACE_REGIST_SIZE); if (faceRect.width > 0) { // 初筛检测到人脸时将图像入栈 diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index da744f5..151de09 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -34,7 +34,7 @@ irisInfo.leftOrRight = "right"; } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::MAIN_PAGE) + if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) { // 相机拍摄下的图像1280*960, 直接用于算法判断 QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); @@ -43,7 +43,6 @@ irisInfo.data = imgDisp; irisInfo.matData = irisMat; - // 识别过程任意一个眼睛都行, 全部存入左眼队列 ProMemory::getInstance().pushCasicIris(irisInfo); } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) { diff --git a/device/device.pri b/device/device.pri index 6dc2f3c..64e6e17 100644 --- a/device/device.pri +++ b/device/device.pri @@ -1,24 +1,24 @@ -HEADERS += $$PWD/FaceCameraController.h \ - $$PWD/face/FaceRegistProcess.h -HEADERS += -HEADERS += $$PWD/face/FaceDetectRecogProcess.h +HEADERS += $$PWD/FaceCameraController.h +HEADERS += $$PWD/face/FaceRecogProcess.h +HEADERS += $$PWD/face/FaceRegistProcess.h HEADERS += $$PWD/face/CasicFaceRecState.h -SOURCES += $$PWD/FaceCameraController.cpp \ - $$PWD/face/FaceRegistProcess.cpp -SOURCES += -SOURCES += $$PWD/face/FaceDetectRecogProcess.cpp +SOURCES += $$PWD/FaceCameraController.cpp +SOURCES += $$PWD/face/FaceRecogProcess.cpp +SOURCES += $$PWD/face/FaceRegistProcess.cpp SOURCES += $$PWD/face/CasicFaceRecState.cpp 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/MotoController.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/MotoController.cpp diff --git a/device/face/FaceDetectRecogProcess.cpp b/device/face/FaceDetectRecogProcess.cpp deleted file mode 100644 index d8d6d01..0000000 --- a/device/face/FaceDetectRecogProcess.cpp +++ /dev/null @@ -1,197 +0,0 @@ -#include "FaceDetectRecogProcess.h" - -FaceDetectRecogProcess::FaceDetectRecogProcess(QObject *parent) : QThread(parent) -{ - this->working = false; - this->exit = false; -} - -FaceDetectRecogProcess::~FaceDetectRecogProcess() -{ - this->setWorking(false); -} - -void FaceDetectRecogProcess::setWorking(bool working) -{ - this->working = working; -} -void FaceDetectRecogProcess::exitThread() -{ - this->exit = true; -} -void FaceDetectRecogProcess::startThread() -{ - this->exit = false; - this->start(); -} - -void FaceDetectRecogProcess::addOneTryCount() -{ - LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); - if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) - { - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; - } else - { - CasicFaceRecState::getInstance().tryCount = 0; - CasicFaceRecState::getInstance().noFaceCount = 0; - emit matchFailure(); - - this->setWorking(false); // 返回后则线程暂停工作 - } -} - -void FaceDetectRecogProcess::addOneNoFaceCount() -{ - CasicFaceRecState::getInstance().noFaceCount++; - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; - if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) - { - CasicFaceRecState::getInstance().noFaceCount = 0; - emit matchFailure(); - - this->setWorking(false); // 返回后则暂停工作 - } -} - -void FaceDetectRecogProcess::run() -{ - while (exit == false) - { - if (this->working == false) - { - this->msleep(100); // 100ms后再判断 - continue; - } - - // 图像栈中没有图像则直接返回 - if (ProMemory::getInstance().isFaceQueueEmpty() == true) - { - addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 - LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); - - this->msleep(200); // 200ms后再判断 - continue; - } - - // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 - if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) - { - LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); - this->msleep(200); // 200ms后再判断 - continue; - } - - // 取出人脸图像栈中的一条数据 - CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); - - // 调用人脸检测算法 - faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); - - // 没有找到人脸则返回 - if (faceInfo.hasFace == false) - { - // 表示本次识别结束, 可以开始下一次识别过程 - addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 - LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); - this->msleep(200); // 200ms后再判断 - continue; - } - - // 找到人脸则开始一次识别 - if (CasicFaceRecState::getInstance().recoginzeId == "0") - { - CasicFaceRecState::getInstance().initRecognize(); - } - CasicFaceRecState::getInstance().faceInfo = &faceInfo; - CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 - CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 - - // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 - casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); - faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); - - // 活体检测判断为假脸 - if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) - { - // 表示本次识别结束, 可以开始下一次识别过程 - LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); - - addOneTryCount(); // 判断是否超过次数, 重置识别状态 - this->msleep(200); // 200ms后再判断 - continue; - } - - // 设置识别状态值=通过活体检测 - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; - - // 调用算法提取特征值, 1024个字节的float数组 - faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); - - // 设置识别状态值=特征值提取 - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; - CasicFaceRecState::getInstance().faceInfo = &faceInfo; - - LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); - - // 特征值提取成功的人脸 与人脸库中的人脸进行比较 - compareFaceInCollection(); - } -} - -void FaceDetectRecogProcess::compareFaceInCollection() -{ - ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 - QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); - for (int i = 0; i < faceFeatures.size(); i++) - { - QVariantMap ffMap = faceFeatures.at(i); - - QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); - float ffArr[1024]; - for (int i = 0; i < 1024; i++) - { - QByteArray tempBa; - tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); - ffArr[i] = ByteUtil::binToFloat(tempBa); - } - - float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); - - LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); - if (sim > 0.62) - { - CasicFaceRecState::getInstance().faceInfo->sim = sim; - CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); - CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; - - // 找到匹配的人脸图像 - this->afterRecogAction(ffMap.value("person_id").toString()); - this->setWorking(false); // 找到匹配的人脸之后停止识别线程工作 - return ; - } - } - - this->addOneTryCount(); -} - -void FaceDetectRecogProcess::afterRecogAction(QString personId) -{ - ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 - - LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); - - // 识别记录存入数据库 - RecognitionRecordDao recDao; - QVariantMap record; - record.insert("person_id", personId); - record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); - record.insert("type", "1"); - record.insert("debug_info", CasicFaceRecState::getInstance().toString()); - recDao.save(record); - - // 发送信号, 在主界面上显示 - emit matchSuccess(personId); -} - diff --git a/device/face/FaceDetectRecogProcess.h b/device/face/FaceDetectRecogProcess.h deleted file mode 100644 index 4ca4e94..0000000 --- a/device/face/FaceDetectRecogProcess.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef FACEDETECTRECOGPROCESS_H -#define FACEDETECTRECOGPROCESS_H - -#include -#include -#include "opencv2/opencv.hpp" - -#include "dao/RecognitionRecordDao.h" - -#include "CasicFaceRecState.h" -#include "casic/ProMemory.h" -#include "casic/face/CasicFaceInterface.h" -#include "utils/UtilInclude.h" - -class FaceDetectRecogProcess : public QThread -{ - Q_OBJECT -public: - explicit FaceDetectRecogProcess(QObject *parent = nullptr); - ~FaceDetectRecogProcess(); - - void setWorking(bool working); - void exitThread(); - void startThread(); - - void addOneTryCount(); - void addOneNoFaceCount(); - -protected: - //QThread的虚函数 - //线程处理函数 - //不能直接调用, 通过start()间接调用 - void run(); - void compareFaceInCollection(); - void afterRecogAction(QString personId); - - volatile bool working; - volatile bool exit; - -signals: - void matchSuccess(QString personId); // 匹配成功 - void matchFailure(); // 匹配失败 - -}; - -#endif // FACEDETECTRECOGPROCESS_H diff --git a/device/face/FaceRecogProcess.cpp b/device/face/FaceRecogProcess.cpp new file mode 100644 index 0000000..0fcd9d9 --- /dev/null +++ b/device/face/FaceRecogProcess.cpp @@ -0,0 +1,201 @@ +#include "FaceRecogProcess.h" + +FaceRecogProcess::FaceRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; +} + +FaceRecogProcess::~FaceRecogProcess() +{ + this->setWorking(false); +} + +void FaceRecogProcess::setWorking(bool working) +{ + this->working = working; +} +void FaceRecogProcess::exitThread() +{ + this->exit = true; +} +void FaceRecogProcess::startThread() +{ + this->exit = false; + this->start(); +} + +void FaceRecogProcess::addOneTryCount() +{ + LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); + if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) + { + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + } else + { + CasicFaceRecState::getInstance().tryCount = 0; + CasicFaceRecState::getInstance().noFaceCount = 0; + ProMemory::getInstance().clearFaceQueue(); + emit matchFailure(); + + this->setWorking(false); // 返回后则线程暂停工作 + } +} + +void FaceRecogProcess::addOneNoFaceCount() +{ + CasicFaceRecState::getInstance().noFaceCount++; + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) + { + CasicFaceRecState::getInstance().noFaceCount = 0; + ProMemory::getInstance().clearFaceQueue(); + emit matchFailure(); + + this->setWorking(false); // 返回后则暂停工作 + } +} + +void FaceRecogProcess::run() +{ + while (exit == false) + { + if (this->working == false) + { + this->msleep(100); // 100ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isFaceQueueEmpty() == true) + { + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) + { + LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 取出人脸图像栈中的一条数据 + CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); + + // 调用人脸检测算法 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); + + // 没有找到人脸则返回 + if (faceInfo.hasFace == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 找到人脸则开始一次识别 + if (CasicFaceRecState::getInstance().recoginzeId == "0") + { + CasicFaceRecState::getInstance().initRecognize(); + } + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 + CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 + + // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 + casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); + faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); + + // 活体检测判断为假脸 + if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) + { + // 表示本次识别结束, 可以开始下一次识别过程 + LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); + + addOneTryCount(); // 判断是否超过次数, 重置识别状态 + this->msleep(200); // 200ms后再判断 + continue; + } + + // 设置识别状态值=通过活体检测 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; + + // 调用算法提取特征值, 1024个字节的float数组 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); + + // 设置识别状态值=特征值提取 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + + LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 特征值提取成功的人脸 与人脸库中的人脸进行比较 + compareFaceInCollection(); + } +} + +void FaceRecogProcess::compareFaceInCollection() +{ + ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 + QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); + for (int i = 0; i < faceFeatures.size(); i++) + { + QVariantMap ffMap = faceFeatures.at(i); + + QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); + float ffArr[1024]; + for (int i = 0; i < 1024; i++) + { + QByteArray tempBa; + tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); + ffArr[i] = ByteUtil::binToFloat(tempBa); + } + + float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); + + LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); + if (sim > 0.62) + { + CasicFaceRecState::getInstance().faceInfo->sim = sim; + CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); + CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; + + // 找到匹配的人脸图像 + // 发送信号, 在主界面上显示 + emit matchSuccess(ffMap.value("person_id").toString(), 1); + +// this->afterRecogAction(ffMap.value("person_id").toString()); + this->setWorking(false); // 找到匹配的人脸之后停止识别线程工作 + return ; + } + } + + this->addOneTryCount(); +} + +void FaceRecogProcess::afterRecogAction(QString personId) +{ + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + + LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + +} + diff --git a/device/face/FaceRecogProcess.h b/device/face/FaceRecogProcess.h new file mode 100644 index 0000000..c551e23 --- /dev/null +++ b/device/face/FaceRecogProcess.h @@ -0,0 +1,46 @@ +#ifndef FACERECOGPROCESS_H +#define FACERECOGPROCESS_H + +#include +#include +#include "opencv2/opencv.hpp" + +#include "dao/RecognitionRecordDao.h" + +#include "CasicFaceRecState.h" +#include "casic/ProMemory.h" +#include "casic/face/CasicFaceInterface.h" +#include "utils/UtilInclude.h" + +class FaceRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit FaceRecogProcess(QObject *parent = nullptr); + ~FaceRecogProcess(); + + void setWorking(bool working); + void exitThread(); + void startThread(); + + void addOneTryCount(); + void addOneNoFaceCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + void compareFaceInCollection(); + void afterRecogAction(QString personId); + + volatile bool working; + volatile bool exit; + +signals: + void matchSuccess(QString personId, int faceOrIris); // 匹配成功 + void matchFailure(); // 匹配失败 + +}; + +#endif // FACERECOGPROCESS_H diff --git a/device/iris/CasicIrisRecState.cpp b/device/iris/CasicIrisRecState.cpp index 28625a1..d6d01e1 100644 --- a/device/iris/CasicIrisRecState.cpp +++ b/device/iris/CasicIrisRecState.cpp @@ -19,7 +19,7 @@ void CasicIrisRecState::initRecognize() { QDateTime now = QDateTime::currentDateTime(); - this->recoginzeId = now.toString("yyyyMMddHHmmsszzz").toStdString(); + this->recoginzeId = now.toString("yyyyMMddHHmmsszzz"); this->timeStamp = now.toMSecsSinceEpoch(); this->tryCount = 0; this->noEyeCount = 0; @@ -27,9 +27,9 @@ LOG(DEBUG) << QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString(); } -std::string CasicIrisRecState::toString() +QString CasicIrisRecState::toString() { - return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)).toStdString(); + return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)); } @@ -37,7 +37,7 @@ { QJsonObject obj; - obj.insert("recoginzeId", QString::fromStdString(recoginzeId)); + obj.insert("recoginzeId", recoginzeId); obj.insert("timestamp", timeStamp); obj.insert("timestampSucc", timeStampSucc); obj.insert("state", state); diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index d14fd54..05fe5f1 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -258,8 +258,8 @@ // 情况3 编辑时非本人 人脸重复 // 语音提示 - SpeakerUtil::getInstance().speak(QString("人脸重复注册,请重试")); - LOG(DEBUG) << "人脸已经注册" << ui->inputName->text().toStdString(); + SpeakerUtil::getInstance().speak(QString("人脸已注册其他人,请重试")); + LOG(DEBUG) << "人脸已注册其他人" << ui->inputName->text().toStdString(); } } } @@ -288,19 +288,20 @@ // 停止拍图 ProMemory::getInstance().irisCam->stopCapture(); - ProMemory::getInstance().irisRegistPro->setWorking(false); - // 语音提示 - SpeakerUtil::getInstance().speak(QString("虹膜重复注册,请重试")); - if (this->personId.isEmpty() == true) { // 情况1 新注册 重复注册 loadPersonInfo(personIdByIris); + + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已经注册,请重试")); LOG(DEBUG) << "虹膜已经注册" << ui->inputName->text().toStdString(); } else { - LOG(DEBUG) << "虹膜已经注册" << personIdByIris.toStdString(); + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已注册其他人,请重试")); + LOG(DEBUG) << "虹膜已注册其他人" << personIdByIris.toStdString(); } } diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index 45fe761..f202cfe 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -30,6 +30,7 @@ initFaceRegistThread(); // 人脸注册线程 initFaceRecogThread(); // 人脸识别线程 initIrisRegistThread(); // 虹膜注册线程 + initIrisRecogThread(); // 虹膜识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); @@ -67,6 +68,10 @@ ProMemory::getInstance().irisRegistPro->deleteLater(); ProMemory::getInstance().irisRegistPro->wait(); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + // 关闭自动启动的外部程序 // outExe->close(); // delete outExe; @@ -75,6 +80,7 @@ delete ProMemory::getInstance().faceRegistPro; delete ProMemory::getInstance().faceRecogPro; delete ProMemory::getInstance().irisRegistPro; + delete ProMemory::getInstance().irisRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -194,15 +200,17 @@ void CasicBioRecWin::initFaceRecogThread() { // 人脸识别处理过程 - ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + ProMemory::getInstance().faceRecogPro = new FaceRecogProcess(this); // 绑定信号与槽函数 // 识别成功 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, - recogResultForm, &RecognizeResultForm::showRecognizeResult); +// connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); // 识别失败 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchFailure, recogResultForm, &RecognizeResultForm::showRecogFailure); ProMemory::getInstance().faceRecogPro->start(); @@ -222,9 +230,28 @@ connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::captureIrisFailure, addPersonForm, &AddPersonForm::onFailedCaptureIris); - // 采集虹膜图像成功 有匹配到红魔库 + // 采集虹膜图像成功 有匹配到虹膜库 connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::findMatchedIris, addPersonForm, &AddPersonForm::onMatchedIris); ProMemory::getInstance().irisRegistPro->start(); } + +void CasicBioRecWin::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 +// connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index ff2ed35..b70245a 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -53,6 +53,7 @@ void initFaceRegistThread(); void initFaceRecogThread(); void initIrisRegistThread(); + void initIrisRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp index b61cb09..e45a191 100644 --- a/RecognizeResultForm.cpp +++ b/RecognizeResultForm.cpp @@ -26,10 +26,28 @@ void RecognizeResultForm::startWorkingRecognize() { // 开始人脸识别 - ProMemory::getInstance().faceRecogPro->setWorking(true); + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + // 人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + break; + case 2: + // 虹膜识别 + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + case 3: + case 4: + // 人脸和虹膜都需要打开 + ProMemory::getInstance().faceRecogPro->setWorking(true); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + } // 将界面切换到识别界面 RecognizeResultForm ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + ui->labBackground->raise(); // 1人脸图像显示的容器 ui->labVideo->resize(1280, 720); @@ -63,13 +81,17 @@ ui->widgetFail->show(); QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ - emit backToHomeAndWait(); - CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; + + emit backToHomeAndWait(); }); } void RecognizeResultForm::showRecognizeResult(QString personId) { + personIdByFace = ""; + personIdByIris = ""; + SpeakerUtil::getInstance().speak("识别成功"); ui->labVideo->hide(); ui->labTitle->hide(); @@ -102,8 +124,131 @@ ui->widgetSucc->show(); QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ - emit backToHomeAndWait(); CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + + emit backToHomeAndWait(); }); } + +void RecognizeResultForm::checkRecognizeResult(QString personId, int faceOrIris) +{ + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + { + // 仅人脸识别 + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 人脸识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 2: + { + // 仅虹膜识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜识别成功 [%1]").arg(CasicIrisRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "2"); + record.insert("debug_info", CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 4: + { + // 任意识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + QString logStr = QString("[RecognizeResultForm]%1识别成功[%2]"); + if (faceOrIris == 1) + { + logStr.arg("人脸").arg(CasicFaceRecState::getInstance().toString()); + } else if (faceOrIris == 2) + { + logStr.arg("虹膜").arg(CasicIrisRecState::getInstance().toString()); + } + LOG(DEBUG) << logStr.toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", QString::number(faceOrIris)); + record.insert("debug_info", faceOrIris == 1 ? CasicFaceRecState::getInstance().toString() : CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 3: + if (faceOrIris == 1) + { + this->personIdByFace = personId; + } else if (faceOrIris == 2) + { + this->personIdByIris = personId; + } + + if (personIdByFace.isEmpty() || personIdByIris.isEmpty()) + { + // 只有一个成功的结果 需要等待下次 + return; + } else if (personIdByFace != personIdByIris) + { + // 人脸和虹膜识别的不是同一人 识别失败 + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜与人脸识别结果不一致,识别失败 [face: %1][iris: %2]").arg(personIdByFace).arg(personIdByIris).toStdString(); + SpeakerUtil::getInstance().speak("虹膜与人脸识别结果不一致,识别失败,请重试"); + showRecogFailure(); + } else + { + LOG(DEBUG) << QString("[RecognizeResultForm]人脸虹膜识别成功").toStdString(); + showRecognizeResult(personId); + } + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "4"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString() + " " + CasicIrisRecState::getInstance().toString()); + recDao.save(record); + } +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h index f5ef019..2c51865 100644 --- a/RecognizeResultForm.h +++ b/RecognizeResultForm.h @@ -25,7 +25,8 @@ public slots: void showRecogFailure(); - void showRecognizeResult(QString personId); + + void checkRecognizeResult(QString personId, int faceOrIris); void startWorkingRecognize(); // 开始工作 void drawImageOnHomeForm(QImage imageDisp); @@ -33,6 +34,11 @@ private: Ui::RecognizeResultForm *ui; + QString personIdByFace; + QString personIdByIris; + + void showRecognizeResult(QString personId); + signals: void backToHomeAndWait(); // 识别结束 返回主界面并待机 diff --git a/StartupForm.cpp b/StartupForm.cpp index 3d3dfad..16c4dfc 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -29,8 +29,8 @@ // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); -// connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, -// this, &StartupForm::takeOneFrameForCheckStatus); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); TimeCounterUtil::getInstance().clockCounter->start(1000); } @@ -54,6 +54,12 @@ return; } + if (this->isVisible() == false) + { + // 没有在这个页面直接返回 + return; + } + // 不在这个页面 则直接返回 不做后续判断 if (ProMemory::getInstance().widgeFrame != CasicBioRecConst::WidgeFrameName::MAIN_PAGE) { @@ -61,10 +67,25 @@ } cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); - bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + + // 判断是否开始工作时使用严格标准 人脸大小需要符合注册图像的尺寸 + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(rawFrame, SettingConfig::getInstance().MIN_WORK_FACE_SIZE); + if (faceRect.width == 0) + { + return ; + } + + bool hasFace = faceRect.width == 0 ? false : true; + if (faceRect.x < SettingConfig::getInstance().MIN_WORK_FACE_POSX || faceRect.x > SettingConfig::getInstance().MAX_WORK_FACE_POSX || + faceRect.y < SettingConfig::getInstance().MIN_WORK_FACE_POSY || faceRect.y > SettingConfig::getInstance().MAX_WORK_FACE_POSY) + { + // 检测到的人脸不在核心区则返回 + hasFace = false; + } + if (hasFace == true) { - LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + LOG(INFO) << QString("检测到人脸,START RECOGNIZE 线程").toStdString(); ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; // 启动识别线程 diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 1bc7d3a..3e9fbd4 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -13,14 +13,16 @@ #include "device/FaceCameraController.h" #include "device/IrisCameraController.h" #include "device/face/FaceRegistProcess.h" -#include "device/face/FaceDetectRecogProcess.h" +#include "device/face/FaceRecogProcess.h" #include "device/iris/IrisRegistProcess.h" +#include "device/iris/IrisRecogProcess.h" class FaceCameraController; class IrisCameraController; class FaceRegistProcess; -class FaceDetectRecogProcess; +class FaceRecogProcess; class IrisRegistProcess; +class IrisRecogProcess; class ProMemory { @@ -58,18 +60,17 @@ FaceCameraController * faceCam; FaceRegistProcess * faceRegistPro; - FaceDetectRecogProcess * faceRecogPro; + FaceRecogProcess * faceRecogPro; IrisCameraController * irisCam; IrisRegistProcess * irisRegistPro; + IrisRecogProcess * irisRecogPro; private: ProMemory(); QStack faceQueue; // 人脸信息队列 QStack irisQueue; // 虹膜信息队列 -// QStack irisLeftQueue; // 左眼信息队列 -// QStack irisRightQueue; // 右眼信息队列 QVector faceFeatures; // 人脸特征值集合 QVector irisFeatures; // 虹膜特征值集合 diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index cb4d3bd..f530212 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -372,6 +372,28 @@ return rect.at(0); } +cv::Rect casic::face::CasicFaceInterface::faceDetectByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + if (rect.size() == 0) + { + return cv::Rect(0, 0, 0, 0); + } + return rect.at(0); +} + cv::Rect casic::face::CasicFaceInterface::eyeDetectByCVCascade(cv::Mat frame) { // 构建openCV自带的眼睛分类器 @@ -402,23 +424,6 @@ return rect.at(0); } -bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) -{ - // 构建OpenCV自带的人脸分类器 - if (this->cascade == nullptr) { - this->cascade = new cv::CascadeClassifier(); - this->cascade->load(cvFaceCascadeName); - } - - std::vector rect; - cv::Size minRectSize(minFaceSize, minFaceSize); - cv::Size maxRectSize(maxFaceSize, maxFaceSize); - - // ★分类器对象调用 - cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); - - return rect.size() == 0 ? false : true; -} bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) { // 构建openCV自带的眼睛分类器 diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index 8a1c564..9d8b8ea 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -1,4 +1,4 @@ -#ifndef CASICFACEINTERFACE_H +#ifndef CASICFACEINTERFACE_H #define CASICFACEINTERFACE_H #include "opencv2/opencv.hpp" @@ -49,8 +49,9 @@ float faceSimCalculate(float* feature, float* otherFeature); cv::Rect faceDetectByCVCascade(cv::Mat frame); + cv::Rect faceDetectByCVCascade(cv::Mat frame, int minFaceSize); + cv::Rect eyeDetectByCVCascade(cv::Mat frame); - bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); @@ -68,7 +69,7 @@ int minFaceSize = 320; int maxFaceSize = 720; int minEyeSize = 100; - int maxEyeSize = 600; + int maxEyeSize = 300; std::string detectorModelPath = "./model/face_detector.csta"; std::string markPts5ModelPath = "./model/face_landmarker_pts5.csta"; diff --git a/conf/config.ini b/conf/config.ini index 84e31c9..79045a6 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -1,4 +1,4 @@ -[com] +[com] #电机控制的串口名 motoPortName=COM3 @@ -17,6 +17,10 @@ maxFaceTryCount=20 #持续没找到人脸的最大次数 maxFaceNotFoundCount=500 +#注册时最小人脸 +minFaceRegist=240 +#识别时最小人脸 +minFaceRecog=100 #虹膜识别最大尝试次数 maxIrisTryCount=10 @@ -34,6 +38,18 @@ #统一背景色 backgroundColor="#FFFFFF" +[work] +#工作状态检测时最小人脸范围 +minFaceSize=160 +#人脸范围最小横坐标 +minFacePosX=320 +#人脸范围最大横坐标 +maxFacePosX=960 +#人脸范围最小纵坐标 +minFacePosY=180 +#人脸范围最大纵坐标 +maxFacePosY=540 + [camera] #人脸摄像头的编号 faceIndex=1 @@ -53,11 +69,3 @@ irisWidth=640 #虹膜图像高度 irisHeight=480 - -[stack] -#拍摄图像栈最大值 -capture=50 -#找到的眼睛图像栈最大值 -found=30 -#质量合格图像栈最大值 -qualified=30 diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 25854c3..0fe4b4c 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -63,7 +63,7 @@ cv::Mat faceMatDisp = imageMatMiir.clone(); // 利用人脸分类器进行初步的检测 - cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp); + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp, SettingConfig::getInstance().MIN_FACE_REGIST_SIZE); if (faceRect.width > 0) { // 初筛检测到人脸时将图像入栈 diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index da744f5..151de09 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -34,7 +34,7 @@ irisInfo.leftOrRight = "right"; } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::MAIN_PAGE) + if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) { // 相机拍摄下的图像1280*960, 直接用于算法判断 QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); @@ -43,7 +43,6 @@ irisInfo.data = imgDisp; irisInfo.matData = irisMat; - // 识别过程任意一个眼睛都行, 全部存入左眼队列 ProMemory::getInstance().pushCasicIris(irisInfo); } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) { diff --git a/device/device.pri b/device/device.pri index 6dc2f3c..64e6e17 100644 --- a/device/device.pri +++ b/device/device.pri @@ -1,24 +1,24 @@ -HEADERS += $$PWD/FaceCameraController.h \ - $$PWD/face/FaceRegistProcess.h -HEADERS += -HEADERS += $$PWD/face/FaceDetectRecogProcess.h +HEADERS += $$PWD/FaceCameraController.h +HEADERS += $$PWD/face/FaceRecogProcess.h +HEADERS += $$PWD/face/FaceRegistProcess.h HEADERS += $$PWD/face/CasicFaceRecState.h -SOURCES += $$PWD/FaceCameraController.cpp \ - $$PWD/face/FaceRegistProcess.cpp -SOURCES += -SOURCES += $$PWD/face/FaceDetectRecogProcess.cpp +SOURCES += $$PWD/FaceCameraController.cpp +SOURCES += $$PWD/face/FaceRecogProcess.cpp +SOURCES += $$PWD/face/FaceRegistProcess.cpp SOURCES += $$PWD/face/CasicFaceRecState.cpp 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/MotoController.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/MotoController.cpp diff --git a/device/face/FaceDetectRecogProcess.cpp b/device/face/FaceDetectRecogProcess.cpp deleted file mode 100644 index d8d6d01..0000000 --- a/device/face/FaceDetectRecogProcess.cpp +++ /dev/null @@ -1,197 +0,0 @@ -#include "FaceDetectRecogProcess.h" - -FaceDetectRecogProcess::FaceDetectRecogProcess(QObject *parent) : QThread(parent) -{ - this->working = false; - this->exit = false; -} - -FaceDetectRecogProcess::~FaceDetectRecogProcess() -{ - this->setWorking(false); -} - -void FaceDetectRecogProcess::setWorking(bool working) -{ - this->working = working; -} -void FaceDetectRecogProcess::exitThread() -{ - this->exit = true; -} -void FaceDetectRecogProcess::startThread() -{ - this->exit = false; - this->start(); -} - -void FaceDetectRecogProcess::addOneTryCount() -{ - LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); - if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) - { - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; - } else - { - CasicFaceRecState::getInstance().tryCount = 0; - CasicFaceRecState::getInstance().noFaceCount = 0; - emit matchFailure(); - - this->setWorking(false); // 返回后则线程暂停工作 - } -} - -void FaceDetectRecogProcess::addOneNoFaceCount() -{ - CasicFaceRecState::getInstance().noFaceCount++; - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; - if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) - { - CasicFaceRecState::getInstance().noFaceCount = 0; - emit matchFailure(); - - this->setWorking(false); // 返回后则暂停工作 - } -} - -void FaceDetectRecogProcess::run() -{ - while (exit == false) - { - if (this->working == false) - { - this->msleep(100); // 100ms后再判断 - continue; - } - - // 图像栈中没有图像则直接返回 - if (ProMemory::getInstance().isFaceQueueEmpty() == true) - { - addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 - LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); - - this->msleep(200); // 200ms后再判断 - continue; - } - - // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 - if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) - { - LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); - this->msleep(200); // 200ms后再判断 - continue; - } - - // 取出人脸图像栈中的一条数据 - CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); - - // 调用人脸检测算法 - faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); - - // 没有找到人脸则返回 - if (faceInfo.hasFace == false) - { - // 表示本次识别结束, 可以开始下一次识别过程 - addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 - LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); - this->msleep(200); // 200ms后再判断 - continue; - } - - // 找到人脸则开始一次识别 - if (CasicFaceRecState::getInstance().recoginzeId == "0") - { - CasicFaceRecState::getInstance().initRecognize(); - } - CasicFaceRecState::getInstance().faceInfo = &faceInfo; - CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 - CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 - - // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 - casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); - faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); - - // 活体检测判断为假脸 - if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) - { - // 表示本次识别结束, 可以开始下一次识别过程 - LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); - - addOneTryCount(); // 判断是否超过次数, 重置识别状态 - this->msleep(200); // 200ms后再判断 - continue; - } - - // 设置识别状态值=通过活体检测 - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; - - // 调用算法提取特征值, 1024个字节的float数组 - faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); - - // 设置识别状态值=特征值提取 - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; - CasicFaceRecState::getInstance().faceInfo = &faceInfo; - - LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); - - // 特征值提取成功的人脸 与人脸库中的人脸进行比较 - compareFaceInCollection(); - } -} - -void FaceDetectRecogProcess::compareFaceInCollection() -{ - ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 - QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); - for (int i = 0; i < faceFeatures.size(); i++) - { - QVariantMap ffMap = faceFeatures.at(i); - - QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); - float ffArr[1024]; - for (int i = 0; i < 1024; i++) - { - QByteArray tempBa; - tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); - ffArr[i] = ByteUtil::binToFloat(tempBa); - } - - float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); - - LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); - if (sim > 0.62) - { - CasicFaceRecState::getInstance().faceInfo->sim = sim; - CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); - CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; - - // 找到匹配的人脸图像 - this->afterRecogAction(ffMap.value("person_id").toString()); - this->setWorking(false); // 找到匹配的人脸之后停止识别线程工作 - return ; - } - } - - this->addOneTryCount(); -} - -void FaceDetectRecogProcess::afterRecogAction(QString personId) -{ - ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 - - LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); - - // 识别记录存入数据库 - RecognitionRecordDao recDao; - QVariantMap record; - record.insert("person_id", personId); - record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); - record.insert("type", "1"); - record.insert("debug_info", CasicFaceRecState::getInstance().toString()); - recDao.save(record); - - // 发送信号, 在主界面上显示 - emit matchSuccess(personId); -} - diff --git a/device/face/FaceDetectRecogProcess.h b/device/face/FaceDetectRecogProcess.h deleted file mode 100644 index 4ca4e94..0000000 --- a/device/face/FaceDetectRecogProcess.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef FACEDETECTRECOGPROCESS_H -#define FACEDETECTRECOGPROCESS_H - -#include -#include -#include "opencv2/opencv.hpp" - -#include "dao/RecognitionRecordDao.h" - -#include "CasicFaceRecState.h" -#include "casic/ProMemory.h" -#include "casic/face/CasicFaceInterface.h" -#include "utils/UtilInclude.h" - -class FaceDetectRecogProcess : public QThread -{ - Q_OBJECT -public: - explicit FaceDetectRecogProcess(QObject *parent = nullptr); - ~FaceDetectRecogProcess(); - - void setWorking(bool working); - void exitThread(); - void startThread(); - - void addOneTryCount(); - void addOneNoFaceCount(); - -protected: - //QThread的虚函数 - //线程处理函数 - //不能直接调用, 通过start()间接调用 - void run(); - void compareFaceInCollection(); - void afterRecogAction(QString personId); - - volatile bool working; - volatile bool exit; - -signals: - void matchSuccess(QString personId); // 匹配成功 - void matchFailure(); // 匹配失败 - -}; - -#endif // FACEDETECTRECOGPROCESS_H diff --git a/device/face/FaceRecogProcess.cpp b/device/face/FaceRecogProcess.cpp new file mode 100644 index 0000000..0fcd9d9 --- /dev/null +++ b/device/face/FaceRecogProcess.cpp @@ -0,0 +1,201 @@ +#include "FaceRecogProcess.h" + +FaceRecogProcess::FaceRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; +} + +FaceRecogProcess::~FaceRecogProcess() +{ + this->setWorking(false); +} + +void FaceRecogProcess::setWorking(bool working) +{ + this->working = working; +} +void FaceRecogProcess::exitThread() +{ + this->exit = true; +} +void FaceRecogProcess::startThread() +{ + this->exit = false; + this->start(); +} + +void FaceRecogProcess::addOneTryCount() +{ + LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); + if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) + { + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + } else + { + CasicFaceRecState::getInstance().tryCount = 0; + CasicFaceRecState::getInstance().noFaceCount = 0; + ProMemory::getInstance().clearFaceQueue(); + emit matchFailure(); + + this->setWorking(false); // 返回后则线程暂停工作 + } +} + +void FaceRecogProcess::addOneNoFaceCount() +{ + CasicFaceRecState::getInstance().noFaceCount++; + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) + { + CasicFaceRecState::getInstance().noFaceCount = 0; + ProMemory::getInstance().clearFaceQueue(); + emit matchFailure(); + + this->setWorking(false); // 返回后则暂停工作 + } +} + +void FaceRecogProcess::run() +{ + while (exit == false) + { + if (this->working == false) + { + this->msleep(100); // 100ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isFaceQueueEmpty() == true) + { + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) + { + LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 取出人脸图像栈中的一条数据 + CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); + + // 调用人脸检测算法 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); + + // 没有找到人脸则返回 + if (faceInfo.hasFace == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 找到人脸则开始一次识别 + if (CasicFaceRecState::getInstance().recoginzeId == "0") + { + CasicFaceRecState::getInstance().initRecognize(); + } + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 + CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 + + // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 + casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); + faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); + + // 活体检测判断为假脸 + if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) + { + // 表示本次识别结束, 可以开始下一次识别过程 + LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); + + addOneTryCount(); // 判断是否超过次数, 重置识别状态 + this->msleep(200); // 200ms后再判断 + continue; + } + + // 设置识别状态值=通过活体检测 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; + + // 调用算法提取特征值, 1024个字节的float数组 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); + + // 设置识别状态值=特征值提取 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + + LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 特征值提取成功的人脸 与人脸库中的人脸进行比较 + compareFaceInCollection(); + } +} + +void FaceRecogProcess::compareFaceInCollection() +{ + ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 + QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); + for (int i = 0; i < faceFeatures.size(); i++) + { + QVariantMap ffMap = faceFeatures.at(i); + + QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); + float ffArr[1024]; + for (int i = 0; i < 1024; i++) + { + QByteArray tempBa; + tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); + ffArr[i] = ByteUtil::binToFloat(tempBa); + } + + float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); + + LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); + if (sim > 0.62) + { + CasicFaceRecState::getInstance().faceInfo->sim = sim; + CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); + CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; + + // 找到匹配的人脸图像 + // 发送信号, 在主界面上显示 + emit matchSuccess(ffMap.value("person_id").toString(), 1); + +// this->afterRecogAction(ffMap.value("person_id").toString()); + this->setWorking(false); // 找到匹配的人脸之后停止识别线程工作 + return ; + } + } + + this->addOneTryCount(); +} + +void FaceRecogProcess::afterRecogAction(QString personId) +{ + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + + LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + +} + diff --git a/device/face/FaceRecogProcess.h b/device/face/FaceRecogProcess.h new file mode 100644 index 0000000..c551e23 --- /dev/null +++ b/device/face/FaceRecogProcess.h @@ -0,0 +1,46 @@ +#ifndef FACERECOGPROCESS_H +#define FACERECOGPROCESS_H + +#include +#include +#include "opencv2/opencv.hpp" + +#include "dao/RecognitionRecordDao.h" + +#include "CasicFaceRecState.h" +#include "casic/ProMemory.h" +#include "casic/face/CasicFaceInterface.h" +#include "utils/UtilInclude.h" + +class FaceRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit FaceRecogProcess(QObject *parent = nullptr); + ~FaceRecogProcess(); + + void setWorking(bool working); + void exitThread(); + void startThread(); + + void addOneTryCount(); + void addOneNoFaceCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + void compareFaceInCollection(); + void afterRecogAction(QString personId); + + volatile bool working; + volatile bool exit; + +signals: + void matchSuccess(QString personId, int faceOrIris); // 匹配成功 + void matchFailure(); // 匹配失败 + +}; + +#endif // FACERECOGPROCESS_H diff --git a/device/iris/CasicIrisRecState.cpp b/device/iris/CasicIrisRecState.cpp index 28625a1..d6d01e1 100644 --- a/device/iris/CasicIrisRecState.cpp +++ b/device/iris/CasicIrisRecState.cpp @@ -19,7 +19,7 @@ void CasicIrisRecState::initRecognize() { QDateTime now = QDateTime::currentDateTime(); - this->recoginzeId = now.toString("yyyyMMddHHmmsszzz").toStdString(); + this->recoginzeId = now.toString("yyyyMMddHHmmsszzz"); this->timeStamp = now.toMSecsSinceEpoch(); this->tryCount = 0; this->noEyeCount = 0; @@ -27,9 +27,9 @@ LOG(DEBUG) << QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString(); } -std::string CasicIrisRecState::toString() +QString CasicIrisRecState::toString() { - return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)).toStdString(); + return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)); } @@ -37,7 +37,7 @@ { QJsonObject obj; - obj.insert("recoginzeId", QString::fromStdString(recoginzeId)); + obj.insert("recoginzeId", recoginzeId); obj.insert("timestamp", timeStamp); obj.insert("timestampSucc", timeStampSucc); obj.insert("state", state); diff --git a/device/iris/CasicIrisRecState.h b/device/iris/CasicIrisRecState.h index 43bf234..d04b9e4 100644 --- a/device/iris/CasicIrisRecState.h +++ b/device/iris/CasicIrisRecState.h @@ -22,10 +22,10 @@ } void initRecognize(); - std::string toString(); + QString toString(); QJsonObject toJSON(); - std::string recoginzeId; // 识别过程id + QString recoginzeId; // 识别过程id qint64 timeStamp = 0; // 识别开始时间戳 qint64 timeStampSucc = 0; // 识别成功时的时间戳 qint64 findEyeTmLast = 0; // 找眼操作耗时 diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index d14fd54..05fe5f1 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -258,8 +258,8 @@ // 情况3 编辑时非本人 人脸重复 // 语音提示 - SpeakerUtil::getInstance().speak(QString("人脸重复注册,请重试")); - LOG(DEBUG) << "人脸已经注册" << ui->inputName->text().toStdString(); + SpeakerUtil::getInstance().speak(QString("人脸已注册其他人,请重试")); + LOG(DEBUG) << "人脸已注册其他人" << ui->inputName->text().toStdString(); } } } @@ -288,19 +288,20 @@ // 停止拍图 ProMemory::getInstance().irisCam->stopCapture(); - ProMemory::getInstance().irisRegistPro->setWorking(false); - // 语音提示 - SpeakerUtil::getInstance().speak(QString("虹膜重复注册,请重试")); - if (this->personId.isEmpty() == true) { // 情况1 新注册 重复注册 loadPersonInfo(personIdByIris); + + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已经注册,请重试")); LOG(DEBUG) << "虹膜已经注册" << ui->inputName->text().toStdString(); } else { - LOG(DEBUG) << "虹膜已经注册" << personIdByIris.toStdString(); + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已注册其他人,请重试")); + LOG(DEBUG) << "虹膜已注册其他人" << personIdByIris.toStdString(); } } diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index 45fe761..f202cfe 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -30,6 +30,7 @@ initFaceRegistThread(); // 人脸注册线程 initFaceRecogThread(); // 人脸识别线程 initIrisRegistThread(); // 虹膜注册线程 + initIrisRecogThread(); // 虹膜识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); @@ -67,6 +68,10 @@ ProMemory::getInstance().irisRegistPro->deleteLater(); ProMemory::getInstance().irisRegistPro->wait(); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + // 关闭自动启动的外部程序 // outExe->close(); // delete outExe; @@ -75,6 +80,7 @@ delete ProMemory::getInstance().faceRegistPro; delete ProMemory::getInstance().faceRecogPro; delete ProMemory::getInstance().irisRegistPro; + delete ProMemory::getInstance().irisRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -194,15 +200,17 @@ void CasicBioRecWin::initFaceRecogThread() { // 人脸识别处理过程 - ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + ProMemory::getInstance().faceRecogPro = new FaceRecogProcess(this); // 绑定信号与槽函数 // 识别成功 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, - recogResultForm, &RecognizeResultForm::showRecognizeResult); +// connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); // 识别失败 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchFailure, recogResultForm, &RecognizeResultForm::showRecogFailure); ProMemory::getInstance().faceRecogPro->start(); @@ -222,9 +230,28 @@ connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::captureIrisFailure, addPersonForm, &AddPersonForm::onFailedCaptureIris); - // 采集虹膜图像成功 有匹配到红魔库 + // 采集虹膜图像成功 有匹配到虹膜库 connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::findMatchedIris, addPersonForm, &AddPersonForm::onMatchedIris); ProMemory::getInstance().irisRegistPro->start(); } + +void CasicBioRecWin::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 +// connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index ff2ed35..b70245a 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -53,6 +53,7 @@ void initFaceRegistThread(); void initFaceRecogThread(); void initIrisRegistThread(); + void initIrisRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp index b61cb09..e45a191 100644 --- a/RecognizeResultForm.cpp +++ b/RecognizeResultForm.cpp @@ -26,10 +26,28 @@ void RecognizeResultForm::startWorkingRecognize() { // 开始人脸识别 - ProMemory::getInstance().faceRecogPro->setWorking(true); + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + // 人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + break; + case 2: + // 虹膜识别 + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + case 3: + case 4: + // 人脸和虹膜都需要打开 + ProMemory::getInstance().faceRecogPro->setWorking(true); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + } // 将界面切换到识别界面 RecognizeResultForm ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + ui->labBackground->raise(); // 1人脸图像显示的容器 ui->labVideo->resize(1280, 720); @@ -63,13 +81,17 @@ ui->widgetFail->show(); QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ - emit backToHomeAndWait(); - CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; + + emit backToHomeAndWait(); }); } void RecognizeResultForm::showRecognizeResult(QString personId) { + personIdByFace = ""; + personIdByIris = ""; + SpeakerUtil::getInstance().speak("识别成功"); ui->labVideo->hide(); ui->labTitle->hide(); @@ -102,8 +124,131 @@ ui->widgetSucc->show(); QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ - emit backToHomeAndWait(); CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + + emit backToHomeAndWait(); }); } + +void RecognizeResultForm::checkRecognizeResult(QString personId, int faceOrIris) +{ + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + { + // 仅人脸识别 + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 人脸识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 2: + { + // 仅虹膜识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜识别成功 [%1]").arg(CasicIrisRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "2"); + record.insert("debug_info", CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 4: + { + // 任意识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + QString logStr = QString("[RecognizeResultForm]%1识别成功[%2]"); + if (faceOrIris == 1) + { + logStr.arg("人脸").arg(CasicFaceRecState::getInstance().toString()); + } else if (faceOrIris == 2) + { + logStr.arg("虹膜").arg(CasicIrisRecState::getInstance().toString()); + } + LOG(DEBUG) << logStr.toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", QString::number(faceOrIris)); + record.insert("debug_info", faceOrIris == 1 ? CasicFaceRecState::getInstance().toString() : CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 3: + if (faceOrIris == 1) + { + this->personIdByFace = personId; + } else if (faceOrIris == 2) + { + this->personIdByIris = personId; + } + + if (personIdByFace.isEmpty() || personIdByIris.isEmpty()) + { + // 只有一个成功的结果 需要等待下次 + return; + } else if (personIdByFace != personIdByIris) + { + // 人脸和虹膜识别的不是同一人 识别失败 + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜与人脸识别结果不一致,识别失败 [face: %1][iris: %2]").arg(personIdByFace).arg(personIdByIris).toStdString(); + SpeakerUtil::getInstance().speak("虹膜与人脸识别结果不一致,识别失败,请重试"); + showRecogFailure(); + } else + { + LOG(DEBUG) << QString("[RecognizeResultForm]人脸虹膜识别成功").toStdString(); + showRecognizeResult(personId); + } + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "4"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString() + " " + CasicIrisRecState::getInstance().toString()); + recDao.save(record); + } +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h index f5ef019..2c51865 100644 --- a/RecognizeResultForm.h +++ b/RecognizeResultForm.h @@ -25,7 +25,8 @@ public slots: void showRecogFailure(); - void showRecognizeResult(QString personId); + + void checkRecognizeResult(QString personId, int faceOrIris); void startWorkingRecognize(); // 开始工作 void drawImageOnHomeForm(QImage imageDisp); @@ -33,6 +34,11 @@ private: Ui::RecognizeResultForm *ui; + QString personIdByFace; + QString personIdByIris; + + void showRecognizeResult(QString personId); + signals: void backToHomeAndWait(); // 识别结束 返回主界面并待机 diff --git a/StartupForm.cpp b/StartupForm.cpp index 3d3dfad..16c4dfc 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -29,8 +29,8 @@ // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); -// connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, -// this, &StartupForm::takeOneFrameForCheckStatus); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); TimeCounterUtil::getInstance().clockCounter->start(1000); } @@ -54,6 +54,12 @@ return; } + if (this->isVisible() == false) + { + // 没有在这个页面直接返回 + return; + } + // 不在这个页面 则直接返回 不做后续判断 if (ProMemory::getInstance().widgeFrame != CasicBioRecConst::WidgeFrameName::MAIN_PAGE) { @@ -61,10 +67,25 @@ } cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); - bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + + // 判断是否开始工作时使用严格标准 人脸大小需要符合注册图像的尺寸 + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(rawFrame, SettingConfig::getInstance().MIN_WORK_FACE_SIZE); + if (faceRect.width == 0) + { + return ; + } + + bool hasFace = faceRect.width == 0 ? false : true; + if (faceRect.x < SettingConfig::getInstance().MIN_WORK_FACE_POSX || faceRect.x > SettingConfig::getInstance().MAX_WORK_FACE_POSX || + faceRect.y < SettingConfig::getInstance().MIN_WORK_FACE_POSY || faceRect.y > SettingConfig::getInstance().MAX_WORK_FACE_POSY) + { + // 检测到的人脸不在核心区则返回 + hasFace = false; + } + if (hasFace == true) { - LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + LOG(INFO) << QString("检测到人脸,START RECOGNIZE 线程").toStdString(); ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; // 启动识别线程 diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 1bc7d3a..3e9fbd4 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -13,14 +13,16 @@ #include "device/FaceCameraController.h" #include "device/IrisCameraController.h" #include "device/face/FaceRegistProcess.h" -#include "device/face/FaceDetectRecogProcess.h" +#include "device/face/FaceRecogProcess.h" #include "device/iris/IrisRegistProcess.h" +#include "device/iris/IrisRecogProcess.h" class FaceCameraController; class IrisCameraController; class FaceRegistProcess; -class FaceDetectRecogProcess; +class FaceRecogProcess; class IrisRegistProcess; +class IrisRecogProcess; class ProMemory { @@ -58,18 +60,17 @@ FaceCameraController * faceCam; FaceRegistProcess * faceRegistPro; - FaceDetectRecogProcess * faceRecogPro; + FaceRecogProcess * faceRecogPro; IrisCameraController * irisCam; IrisRegistProcess * irisRegistPro; + IrisRecogProcess * irisRecogPro; private: ProMemory(); QStack faceQueue; // 人脸信息队列 QStack irisQueue; // 虹膜信息队列 -// QStack irisLeftQueue; // 左眼信息队列 -// QStack irisRightQueue; // 右眼信息队列 QVector faceFeatures; // 人脸特征值集合 QVector irisFeatures; // 虹膜特征值集合 diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index cb4d3bd..f530212 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -372,6 +372,28 @@ return rect.at(0); } +cv::Rect casic::face::CasicFaceInterface::faceDetectByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + if (rect.size() == 0) + { + return cv::Rect(0, 0, 0, 0); + } + return rect.at(0); +} + cv::Rect casic::face::CasicFaceInterface::eyeDetectByCVCascade(cv::Mat frame) { // 构建openCV自带的眼睛分类器 @@ -402,23 +424,6 @@ return rect.at(0); } -bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) -{ - // 构建OpenCV自带的人脸分类器 - if (this->cascade == nullptr) { - this->cascade = new cv::CascadeClassifier(); - this->cascade->load(cvFaceCascadeName); - } - - std::vector rect; - cv::Size minRectSize(minFaceSize, minFaceSize); - cv::Size maxRectSize(maxFaceSize, maxFaceSize); - - // ★分类器对象调用 - cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); - - return rect.size() == 0 ? false : true; -} bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) { // 构建openCV自带的眼睛分类器 diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index 8a1c564..9d8b8ea 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -1,4 +1,4 @@ -#ifndef CASICFACEINTERFACE_H +#ifndef CASICFACEINTERFACE_H #define CASICFACEINTERFACE_H #include "opencv2/opencv.hpp" @@ -49,8 +49,9 @@ float faceSimCalculate(float* feature, float* otherFeature); cv::Rect faceDetectByCVCascade(cv::Mat frame); + cv::Rect faceDetectByCVCascade(cv::Mat frame, int minFaceSize); + cv::Rect eyeDetectByCVCascade(cv::Mat frame); - bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); @@ -68,7 +69,7 @@ int minFaceSize = 320; int maxFaceSize = 720; int minEyeSize = 100; - int maxEyeSize = 600; + int maxEyeSize = 300; std::string detectorModelPath = "./model/face_detector.csta"; std::string markPts5ModelPath = "./model/face_landmarker_pts5.csta"; diff --git a/conf/config.ini b/conf/config.ini index 84e31c9..79045a6 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -1,4 +1,4 @@ -[com] +[com] #电机控制的串口名 motoPortName=COM3 @@ -17,6 +17,10 @@ maxFaceTryCount=20 #持续没找到人脸的最大次数 maxFaceNotFoundCount=500 +#注册时最小人脸 +minFaceRegist=240 +#识别时最小人脸 +minFaceRecog=100 #虹膜识别最大尝试次数 maxIrisTryCount=10 @@ -34,6 +38,18 @@ #统一背景色 backgroundColor="#FFFFFF" +[work] +#工作状态检测时最小人脸范围 +minFaceSize=160 +#人脸范围最小横坐标 +minFacePosX=320 +#人脸范围最大横坐标 +maxFacePosX=960 +#人脸范围最小纵坐标 +minFacePosY=180 +#人脸范围最大纵坐标 +maxFacePosY=540 + [camera] #人脸摄像头的编号 faceIndex=1 @@ -53,11 +69,3 @@ irisWidth=640 #虹膜图像高度 irisHeight=480 - -[stack] -#拍摄图像栈最大值 -capture=50 -#找到的眼睛图像栈最大值 -found=30 -#质量合格图像栈最大值 -qualified=30 diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 25854c3..0fe4b4c 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -63,7 +63,7 @@ cv::Mat faceMatDisp = imageMatMiir.clone(); // 利用人脸分类器进行初步的检测 - cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp); + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp, SettingConfig::getInstance().MIN_FACE_REGIST_SIZE); if (faceRect.width > 0) { // 初筛检测到人脸时将图像入栈 diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index da744f5..151de09 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -34,7 +34,7 @@ irisInfo.leftOrRight = "right"; } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::MAIN_PAGE) + if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) { // 相机拍摄下的图像1280*960, 直接用于算法判断 QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); @@ -43,7 +43,6 @@ irisInfo.data = imgDisp; irisInfo.matData = irisMat; - // 识别过程任意一个眼睛都行, 全部存入左眼队列 ProMemory::getInstance().pushCasicIris(irisInfo); } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) { diff --git a/device/device.pri b/device/device.pri index 6dc2f3c..64e6e17 100644 --- a/device/device.pri +++ b/device/device.pri @@ -1,24 +1,24 @@ -HEADERS += $$PWD/FaceCameraController.h \ - $$PWD/face/FaceRegistProcess.h -HEADERS += -HEADERS += $$PWD/face/FaceDetectRecogProcess.h +HEADERS += $$PWD/FaceCameraController.h +HEADERS += $$PWD/face/FaceRecogProcess.h +HEADERS += $$PWD/face/FaceRegistProcess.h HEADERS += $$PWD/face/CasicFaceRecState.h -SOURCES += $$PWD/FaceCameraController.cpp \ - $$PWD/face/FaceRegistProcess.cpp -SOURCES += -SOURCES += $$PWD/face/FaceDetectRecogProcess.cpp +SOURCES += $$PWD/FaceCameraController.cpp +SOURCES += $$PWD/face/FaceRecogProcess.cpp +SOURCES += $$PWD/face/FaceRegistProcess.cpp SOURCES += $$PWD/face/CasicFaceRecState.cpp 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/MotoController.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/MotoController.cpp diff --git a/device/face/FaceDetectRecogProcess.cpp b/device/face/FaceDetectRecogProcess.cpp deleted file mode 100644 index d8d6d01..0000000 --- a/device/face/FaceDetectRecogProcess.cpp +++ /dev/null @@ -1,197 +0,0 @@ -#include "FaceDetectRecogProcess.h" - -FaceDetectRecogProcess::FaceDetectRecogProcess(QObject *parent) : QThread(parent) -{ - this->working = false; - this->exit = false; -} - -FaceDetectRecogProcess::~FaceDetectRecogProcess() -{ - this->setWorking(false); -} - -void FaceDetectRecogProcess::setWorking(bool working) -{ - this->working = working; -} -void FaceDetectRecogProcess::exitThread() -{ - this->exit = true; -} -void FaceDetectRecogProcess::startThread() -{ - this->exit = false; - this->start(); -} - -void FaceDetectRecogProcess::addOneTryCount() -{ - LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); - if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) - { - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; - } else - { - CasicFaceRecState::getInstance().tryCount = 0; - CasicFaceRecState::getInstance().noFaceCount = 0; - emit matchFailure(); - - this->setWorking(false); // 返回后则线程暂停工作 - } -} - -void FaceDetectRecogProcess::addOneNoFaceCount() -{ - CasicFaceRecState::getInstance().noFaceCount++; - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; - if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) - { - CasicFaceRecState::getInstance().noFaceCount = 0; - emit matchFailure(); - - this->setWorking(false); // 返回后则暂停工作 - } -} - -void FaceDetectRecogProcess::run() -{ - while (exit == false) - { - if (this->working == false) - { - this->msleep(100); // 100ms后再判断 - continue; - } - - // 图像栈中没有图像则直接返回 - if (ProMemory::getInstance().isFaceQueueEmpty() == true) - { - addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 - LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); - - this->msleep(200); // 200ms后再判断 - continue; - } - - // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 - if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) - { - LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); - this->msleep(200); // 200ms后再判断 - continue; - } - - // 取出人脸图像栈中的一条数据 - CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); - - // 调用人脸检测算法 - faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); - - // 没有找到人脸则返回 - if (faceInfo.hasFace == false) - { - // 表示本次识别结束, 可以开始下一次识别过程 - addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 - LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); - this->msleep(200); // 200ms后再判断 - continue; - } - - // 找到人脸则开始一次识别 - if (CasicFaceRecState::getInstance().recoginzeId == "0") - { - CasicFaceRecState::getInstance().initRecognize(); - } - CasicFaceRecState::getInstance().faceInfo = &faceInfo; - CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 - CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 - - // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 - casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); - faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); - - // 活体检测判断为假脸 - if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) - { - // 表示本次识别结束, 可以开始下一次识别过程 - LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); - - addOneTryCount(); // 判断是否超过次数, 重置识别状态 - this->msleep(200); // 200ms后再判断 - continue; - } - - // 设置识别状态值=通过活体检测 - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; - - // 调用算法提取特征值, 1024个字节的float数组 - faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); - - // 设置识别状态值=特征值提取 - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; - CasicFaceRecState::getInstance().faceInfo = &faceInfo; - - LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); - - // 特征值提取成功的人脸 与人脸库中的人脸进行比较 - compareFaceInCollection(); - } -} - -void FaceDetectRecogProcess::compareFaceInCollection() -{ - ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 - QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); - for (int i = 0; i < faceFeatures.size(); i++) - { - QVariantMap ffMap = faceFeatures.at(i); - - QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); - float ffArr[1024]; - for (int i = 0; i < 1024; i++) - { - QByteArray tempBa; - tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); - ffArr[i] = ByteUtil::binToFloat(tempBa); - } - - float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); - - LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); - if (sim > 0.62) - { - CasicFaceRecState::getInstance().faceInfo->sim = sim; - CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); - CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; - - // 找到匹配的人脸图像 - this->afterRecogAction(ffMap.value("person_id").toString()); - this->setWorking(false); // 找到匹配的人脸之后停止识别线程工作 - return ; - } - } - - this->addOneTryCount(); -} - -void FaceDetectRecogProcess::afterRecogAction(QString personId) -{ - ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 - - LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); - - // 识别记录存入数据库 - RecognitionRecordDao recDao; - QVariantMap record; - record.insert("person_id", personId); - record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); - record.insert("type", "1"); - record.insert("debug_info", CasicFaceRecState::getInstance().toString()); - recDao.save(record); - - // 发送信号, 在主界面上显示 - emit matchSuccess(personId); -} - diff --git a/device/face/FaceDetectRecogProcess.h b/device/face/FaceDetectRecogProcess.h deleted file mode 100644 index 4ca4e94..0000000 --- a/device/face/FaceDetectRecogProcess.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef FACEDETECTRECOGPROCESS_H -#define FACEDETECTRECOGPROCESS_H - -#include -#include -#include "opencv2/opencv.hpp" - -#include "dao/RecognitionRecordDao.h" - -#include "CasicFaceRecState.h" -#include "casic/ProMemory.h" -#include "casic/face/CasicFaceInterface.h" -#include "utils/UtilInclude.h" - -class FaceDetectRecogProcess : public QThread -{ - Q_OBJECT -public: - explicit FaceDetectRecogProcess(QObject *parent = nullptr); - ~FaceDetectRecogProcess(); - - void setWorking(bool working); - void exitThread(); - void startThread(); - - void addOneTryCount(); - void addOneNoFaceCount(); - -protected: - //QThread的虚函数 - //线程处理函数 - //不能直接调用, 通过start()间接调用 - void run(); - void compareFaceInCollection(); - void afterRecogAction(QString personId); - - volatile bool working; - volatile bool exit; - -signals: - void matchSuccess(QString personId); // 匹配成功 - void matchFailure(); // 匹配失败 - -}; - -#endif // FACEDETECTRECOGPROCESS_H diff --git a/device/face/FaceRecogProcess.cpp b/device/face/FaceRecogProcess.cpp new file mode 100644 index 0000000..0fcd9d9 --- /dev/null +++ b/device/face/FaceRecogProcess.cpp @@ -0,0 +1,201 @@ +#include "FaceRecogProcess.h" + +FaceRecogProcess::FaceRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; +} + +FaceRecogProcess::~FaceRecogProcess() +{ + this->setWorking(false); +} + +void FaceRecogProcess::setWorking(bool working) +{ + this->working = working; +} +void FaceRecogProcess::exitThread() +{ + this->exit = true; +} +void FaceRecogProcess::startThread() +{ + this->exit = false; + this->start(); +} + +void FaceRecogProcess::addOneTryCount() +{ + LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); + if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) + { + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + } else + { + CasicFaceRecState::getInstance().tryCount = 0; + CasicFaceRecState::getInstance().noFaceCount = 0; + ProMemory::getInstance().clearFaceQueue(); + emit matchFailure(); + + this->setWorking(false); // 返回后则线程暂停工作 + } +} + +void FaceRecogProcess::addOneNoFaceCount() +{ + CasicFaceRecState::getInstance().noFaceCount++; + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) + { + CasicFaceRecState::getInstance().noFaceCount = 0; + ProMemory::getInstance().clearFaceQueue(); + emit matchFailure(); + + this->setWorking(false); // 返回后则暂停工作 + } +} + +void FaceRecogProcess::run() +{ + while (exit == false) + { + if (this->working == false) + { + this->msleep(100); // 100ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isFaceQueueEmpty() == true) + { + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) + { + LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 取出人脸图像栈中的一条数据 + CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); + + // 调用人脸检测算法 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); + + // 没有找到人脸则返回 + if (faceInfo.hasFace == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 找到人脸则开始一次识别 + if (CasicFaceRecState::getInstance().recoginzeId == "0") + { + CasicFaceRecState::getInstance().initRecognize(); + } + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 + CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 + + // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 + casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); + faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); + + // 活体检测判断为假脸 + if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) + { + // 表示本次识别结束, 可以开始下一次识别过程 + LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); + + addOneTryCount(); // 判断是否超过次数, 重置识别状态 + this->msleep(200); // 200ms后再判断 + continue; + } + + // 设置识别状态值=通过活体检测 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; + + // 调用算法提取特征值, 1024个字节的float数组 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); + + // 设置识别状态值=特征值提取 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + + LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 特征值提取成功的人脸 与人脸库中的人脸进行比较 + compareFaceInCollection(); + } +} + +void FaceRecogProcess::compareFaceInCollection() +{ + ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 + QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); + for (int i = 0; i < faceFeatures.size(); i++) + { + QVariantMap ffMap = faceFeatures.at(i); + + QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); + float ffArr[1024]; + for (int i = 0; i < 1024; i++) + { + QByteArray tempBa; + tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); + ffArr[i] = ByteUtil::binToFloat(tempBa); + } + + float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); + + LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); + if (sim > 0.62) + { + CasicFaceRecState::getInstance().faceInfo->sim = sim; + CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); + CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; + + // 找到匹配的人脸图像 + // 发送信号, 在主界面上显示 + emit matchSuccess(ffMap.value("person_id").toString(), 1); + +// this->afterRecogAction(ffMap.value("person_id").toString()); + this->setWorking(false); // 找到匹配的人脸之后停止识别线程工作 + return ; + } + } + + this->addOneTryCount(); +} + +void FaceRecogProcess::afterRecogAction(QString personId) +{ + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + + LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + +} + diff --git a/device/face/FaceRecogProcess.h b/device/face/FaceRecogProcess.h new file mode 100644 index 0000000..c551e23 --- /dev/null +++ b/device/face/FaceRecogProcess.h @@ -0,0 +1,46 @@ +#ifndef FACERECOGPROCESS_H +#define FACERECOGPROCESS_H + +#include +#include +#include "opencv2/opencv.hpp" + +#include "dao/RecognitionRecordDao.h" + +#include "CasicFaceRecState.h" +#include "casic/ProMemory.h" +#include "casic/face/CasicFaceInterface.h" +#include "utils/UtilInclude.h" + +class FaceRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit FaceRecogProcess(QObject *parent = nullptr); + ~FaceRecogProcess(); + + void setWorking(bool working); + void exitThread(); + void startThread(); + + void addOneTryCount(); + void addOneNoFaceCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + void compareFaceInCollection(); + void afterRecogAction(QString personId); + + volatile bool working; + volatile bool exit; + +signals: + void matchSuccess(QString personId, int faceOrIris); // 匹配成功 + void matchFailure(); // 匹配失败 + +}; + +#endif // FACERECOGPROCESS_H diff --git a/device/iris/CasicIrisRecState.cpp b/device/iris/CasicIrisRecState.cpp index 28625a1..d6d01e1 100644 --- a/device/iris/CasicIrisRecState.cpp +++ b/device/iris/CasicIrisRecState.cpp @@ -19,7 +19,7 @@ void CasicIrisRecState::initRecognize() { QDateTime now = QDateTime::currentDateTime(); - this->recoginzeId = now.toString("yyyyMMddHHmmsszzz").toStdString(); + this->recoginzeId = now.toString("yyyyMMddHHmmsszzz"); this->timeStamp = now.toMSecsSinceEpoch(); this->tryCount = 0; this->noEyeCount = 0; @@ -27,9 +27,9 @@ LOG(DEBUG) << QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString(); } -std::string CasicIrisRecState::toString() +QString CasicIrisRecState::toString() { - return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)).toStdString(); + return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)); } @@ -37,7 +37,7 @@ { QJsonObject obj; - obj.insert("recoginzeId", QString::fromStdString(recoginzeId)); + obj.insert("recoginzeId", recoginzeId); obj.insert("timestamp", timeStamp); obj.insert("timestampSucc", timeStampSucc); obj.insert("state", state); diff --git a/device/iris/CasicIrisRecState.h b/device/iris/CasicIrisRecState.h index 43bf234..d04b9e4 100644 --- a/device/iris/CasicIrisRecState.h +++ b/device/iris/CasicIrisRecState.h @@ -22,10 +22,10 @@ } void initRecognize(); - std::string toString(); + QString toString(); QJsonObject toJSON(); - std::string recoginzeId; // 识别过程id + QString recoginzeId; // 识别过程id qint64 timeStamp = 0; // 识别开始时间戳 qint64 timeStampSucc = 0; // 识别成功时的时间戳 qint64 findEyeTmLast = 0; // 找眼操作耗时 diff --git a/device/iris/IrisRecogProcess.cpp b/device/iris/IrisRecogProcess.cpp new file mode 100644 index 0000000..52c3826 --- /dev/null +++ b/device/iris/IrisRecogProcess.cpp @@ -0,0 +1,215 @@ +#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; + } + + LOG(DEBUG) << QString("[IrisRecogProcess]虹膜识别线程").toStdString(); + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isIrisQueueEmpty() == true) + { + LOG(DEBUG) << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString(); + 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(); + + this->msleep(200); // 200ms后再判断 + continue; + } + + // 取出虹膜图像栈中的一条数据 + CasicIrisInfo irisInfo = ProMemory::getInstance().popCasicIris(); + + LOG(DEBUG) << QString("[IrisRecogProcess]取出虹膜图像").toStdString(); + + // 调用找眼分类器算法 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + + // 没有找到眼睛则返回 + if (irisInfo.hasEye == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 + LOG(DEBUG) << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString(); + + addOneNoEyeCount(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 找到眼睛则开始质量评估和编码 + // 调用远程算法进行编码 + 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->leftOrRight = irisInfo.leftOrRight; + 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(); + + LOG(INFO) << QString("算法匹配结果").toStdString() << 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(); + + // 保存图像文件 + 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, 2); +// this->afterRecogAction(personId); + } else if (code.toInt() == -200) + { + // 匹配失败 + LOG(INFO) << QString("匹配失败: ").toStdString() << matchResponse.toStdString(); + + // 匹配失败则尝试次数+1 + addOneTryCount(); + } else if (code.toInt() == -100) + { + // 编码失败 + LOG(INFO) << QString("编码失败: ").toStdString() << matchResponse.toStdString(); + + // 编码失败则尝试次数+1 + addOneTryCount(); + } + } else + { + // 超时返回则尝试次数+1 + addOneTryCount(); + } + } +} + +void IrisRecogProcess::afterRecogAction(QString personId) +{ + ProMemory::getInstance().clearIrisQueue(); // 清理虹膜数据栈 + + this->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + LOG(DEBUG) << QString("[IrisRecogProcess] 识别成功 [%1]").arg(CasicIrisRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "2"); + record.insert("debug_info", CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + + // 发送信号, 在主界面上显示 + emit findMatchedIris(personId, 2); +} + +void IrisRecogProcess::addOneTryCount() +{ + CasicIrisRecState::getInstance().tryCount++; + 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(); + emit failedMatchedIris(); + } +} diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index d14fd54..05fe5f1 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -258,8 +258,8 @@ // 情况3 编辑时非本人 人脸重复 // 语音提示 - SpeakerUtil::getInstance().speak(QString("人脸重复注册,请重试")); - LOG(DEBUG) << "人脸已经注册" << ui->inputName->text().toStdString(); + SpeakerUtil::getInstance().speak(QString("人脸已注册其他人,请重试")); + LOG(DEBUG) << "人脸已注册其他人" << ui->inputName->text().toStdString(); } } } @@ -288,19 +288,20 @@ // 停止拍图 ProMemory::getInstance().irisCam->stopCapture(); - ProMemory::getInstance().irisRegistPro->setWorking(false); - // 语音提示 - SpeakerUtil::getInstance().speak(QString("虹膜重复注册,请重试")); - if (this->personId.isEmpty() == true) { // 情况1 新注册 重复注册 loadPersonInfo(personIdByIris); + + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已经注册,请重试")); LOG(DEBUG) << "虹膜已经注册" << ui->inputName->text().toStdString(); } else { - LOG(DEBUG) << "虹膜已经注册" << personIdByIris.toStdString(); + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已注册其他人,请重试")); + LOG(DEBUG) << "虹膜已注册其他人" << personIdByIris.toStdString(); } } diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index 45fe761..f202cfe 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -30,6 +30,7 @@ initFaceRegistThread(); // 人脸注册线程 initFaceRecogThread(); // 人脸识别线程 initIrisRegistThread(); // 虹膜注册线程 + initIrisRecogThread(); // 虹膜识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); @@ -67,6 +68,10 @@ ProMemory::getInstance().irisRegistPro->deleteLater(); ProMemory::getInstance().irisRegistPro->wait(); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + // 关闭自动启动的外部程序 // outExe->close(); // delete outExe; @@ -75,6 +80,7 @@ delete ProMemory::getInstance().faceRegistPro; delete ProMemory::getInstance().faceRecogPro; delete ProMemory::getInstance().irisRegistPro; + delete ProMemory::getInstance().irisRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -194,15 +200,17 @@ void CasicBioRecWin::initFaceRecogThread() { // 人脸识别处理过程 - ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + ProMemory::getInstance().faceRecogPro = new FaceRecogProcess(this); // 绑定信号与槽函数 // 识别成功 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, - recogResultForm, &RecognizeResultForm::showRecognizeResult); +// connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); // 识别失败 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchFailure, recogResultForm, &RecognizeResultForm::showRecogFailure); ProMemory::getInstance().faceRecogPro->start(); @@ -222,9 +230,28 @@ connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::captureIrisFailure, addPersonForm, &AddPersonForm::onFailedCaptureIris); - // 采集虹膜图像成功 有匹配到红魔库 + // 采集虹膜图像成功 有匹配到虹膜库 connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::findMatchedIris, addPersonForm, &AddPersonForm::onMatchedIris); ProMemory::getInstance().irisRegistPro->start(); } + +void CasicBioRecWin::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 +// connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index ff2ed35..b70245a 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -53,6 +53,7 @@ void initFaceRegistThread(); void initFaceRecogThread(); void initIrisRegistThread(); + void initIrisRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp index b61cb09..e45a191 100644 --- a/RecognizeResultForm.cpp +++ b/RecognizeResultForm.cpp @@ -26,10 +26,28 @@ void RecognizeResultForm::startWorkingRecognize() { // 开始人脸识别 - ProMemory::getInstance().faceRecogPro->setWorking(true); + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + // 人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + break; + case 2: + // 虹膜识别 + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + case 3: + case 4: + // 人脸和虹膜都需要打开 + ProMemory::getInstance().faceRecogPro->setWorking(true); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + } // 将界面切换到识别界面 RecognizeResultForm ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + ui->labBackground->raise(); // 1人脸图像显示的容器 ui->labVideo->resize(1280, 720); @@ -63,13 +81,17 @@ ui->widgetFail->show(); QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ - emit backToHomeAndWait(); - CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; + + emit backToHomeAndWait(); }); } void RecognizeResultForm::showRecognizeResult(QString personId) { + personIdByFace = ""; + personIdByIris = ""; + SpeakerUtil::getInstance().speak("识别成功"); ui->labVideo->hide(); ui->labTitle->hide(); @@ -102,8 +124,131 @@ ui->widgetSucc->show(); QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ - emit backToHomeAndWait(); CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + + emit backToHomeAndWait(); }); } + +void RecognizeResultForm::checkRecognizeResult(QString personId, int faceOrIris) +{ + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + { + // 仅人脸识别 + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 人脸识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 2: + { + // 仅虹膜识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜识别成功 [%1]").arg(CasicIrisRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "2"); + record.insert("debug_info", CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 4: + { + // 任意识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + QString logStr = QString("[RecognizeResultForm]%1识别成功[%2]"); + if (faceOrIris == 1) + { + logStr.arg("人脸").arg(CasicFaceRecState::getInstance().toString()); + } else if (faceOrIris == 2) + { + logStr.arg("虹膜").arg(CasicIrisRecState::getInstance().toString()); + } + LOG(DEBUG) << logStr.toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", QString::number(faceOrIris)); + record.insert("debug_info", faceOrIris == 1 ? CasicFaceRecState::getInstance().toString() : CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 3: + if (faceOrIris == 1) + { + this->personIdByFace = personId; + } else if (faceOrIris == 2) + { + this->personIdByIris = personId; + } + + if (personIdByFace.isEmpty() || personIdByIris.isEmpty()) + { + // 只有一个成功的结果 需要等待下次 + return; + } else if (personIdByFace != personIdByIris) + { + // 人脸和虹膜识别的不是同一人 识别失败 + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜与人脸识别结果不一致,识别失败 [face: %1][iris: %2]").arg(personIdByFace).arg(personIdByIris).toStdString(); + SpeakerUtil::getInstance().speak("虹膜与人脸识别结果不一致,识别失败,请重试"); + showRecogFailure(); + } else + { + LOG(DEBUG) << QString("[RecognizeResultForm]人脸虹膜识别成功").toStdString(); + showRecognizeResult(personId); + } + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "4"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString() + " " + CasicIrisRecState::getInstance().toString()); + recDao.save(record); + } +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h index f5ef019..2c51865 100644 --- a/RecognizeResultForm.h +++ b/RecognizeResultForm.h @@ -25,7 +25,8 @@ public slots: void showRecogFailure(); - void showRecognizeResult(QString personId); + + void checkRecognizeResult(QString personId, int faceOrIris); void startWorkingRecognize(); // 开始工作 void drawImageOnHomeForm(QImage imageDisp); @@ -33,6 +34,11 @@ private: Ui::RecognizeResultForm *ui; + QString personIdByFace; + QString personIdByIris; + + void showRecognizeResult(QString personId); + signals: void backToHomeAndWait(); // 识别结束 返回主界面并待机 diff --git a/StartupForm.cpp b/StartupForm.cpp index 3d3dfad..16c4dfc 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -29,8 +29,8 @@ // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); -// connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, -// this, &StartupForm::takeOneFrameForCheckStatus); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); TimeCounterUtil::getInstance().clockCounter->start(1000); } @@ -54,6 +54,12 @@ return; } + if (this->isVisible() == false) + { + // 没有在这个页面直接返回 + return; + } + // 不在这个页面 则直接返回 不做后续判断 if (ProMemory::getInstance().widgeFrame != CasicBioRecConst::WidgeFrameName::MAIN_PAGE) { @@ -61,10 +67,25 @@ } cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); - bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + + // 判断是否开始工作时使用严格标准 人脸大小需要符合注册图像的尺寸 + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(rawFrame, SettingConfig::getInstance().MIN_WORK_FACE_SIZE); + if (faceRect.width == 0) + { + return ; + } + + bool hasFace = faceRect.width == 0 ? false : true; + if (faceRect.x < SettingConfig::getInstance().MIN_WORK_FACE_POSX || faceRect.x > SettingConfig::getInstance().MAX_WORK_FACE_POSX || + faceRect.y < SettingConfig::getInstance().MIN_WORK_FACE_POSY || faceRect.y > SettingConfig::getInstance().MAX_WORK_FACE_POSY) + { + // 检测到的人脸不在核心区则返回 + hasFace = false; + } + if (hasFace == true) { - LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + LOG(INFO) << QString("检测到人脸,START RECOGNIZE 线程").toStdString(); ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; // 启动识别线程 diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 1bc7d3a..3e9fbd4 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -13,14 +13,16 @@ #include "device/FaceCameraController.h" #include "device/IrisCameraController.h" #include "device/face/FaceRegistProcess.h" -#include "device/face/FaceDetectRecogProcess.h" +#include "device/face/FaceRecogProcess.h" #include "device/iris/IrisRegistProcess.h" +#include "device/iris/IrisRecogProcess.h" class FaceCameraController; class IrisCameraController; class FaceRegistProcess; -class FaceDetectRecogProcess; +class FaceRecogProcess; class IrisRegistProcess; +class IrisRecogProcess; class ProMemory { @@ -58,18 +60,17 @@ FaceCameraController * faceCam; FaceRegistProcess * faceRegistPro; - FaceDetectRecogProcess * faceRecogPro; + FaceRecogProcess * faceRecogPro; IrisCameraController * irisCam; IrisRegistProcess * irisRegistPro; + IrisRecogProcess * irisRecogPro; private: ProMemory(); QStack faceQueue; // 人脸信息队列 QStack irisQueue; // 虹膜信息队列 -// QStack irisLeftQueue; // 左眼信息队列 -// QStack irisRightQueue; // 右眼信息队列 QVector faceFeatures; // 人脸特征值集合 QVector irisFeatures; // 虹膜特征值集合 diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index cb4d3bd..f530212 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -372,6 +372,28 @@ return rect.at(0); } +cv::Rect casic::face::CasicFaceInterface::faceDetectByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + if (rect.size() == 0) + { + return cv::Rect(0, 0, 0, 0); + } + return rect.at(0); +} + cv::Rect casic::face::CasicFaceInterface::eyeDetectByCVCascade(cv::Mat frame) { // 构建openCV自带的眼睛分类器 @@ -402,23 +424,6 @@ return rect.at(0); } -bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) -{ - // 构建OpenCV自带的人脸分类器 - if (this->cascade == nullptr) { - this->cascade = new cv::CascadeClassifier(); - this->cascade->load(cvFaceCascadeName); - } - - std::vector rect; - cv::Size minRectSize(minFaceSize, minFaceSize); - cv::Size maxRectSize(maxFaceSize, maxFaceSize); - - // ★分类器对象调用 - cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); - - return rect.size() == 0 ? false : true; -} bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) { // 构建openCV自带的眼睛分类器 diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index 8a1c564..9d8b8ea 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -1,4 +1,4 @@ -#ifndef CASICFACEINTERFACE_H +#ifndef CASICFACEINTERFACE_H #define CASICFACEINTERFACE_H #include "opencv2/opencv.hpp" @@ -49,8 +49,9 @@ float faceSimCalculate(float* feature, float* otherFeature); cv::Rect faceDetectByCVCascade(cv::Mat frame); + cv::Rect faceDetectByCVCascade(cv::Mat frame, int minFaceSize); + cv::Rect eyeDetectByCVCascade(cv::Mat frame); - bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); @@ -68,7 +69,7 @@ int minFaceSize = 320; int maxFaceSize = 720; int minEyeSize = 100; - int maxEyeSize = 600; + int maxEyeSize = 300; std::string detectorModelPath = "./model/face_detector.csta"; std::string markPts5ModelPath = "./model/face_landmarker_pts5.csta"; diff --git a/conf/config.ini b/conf/config.ini index 84e31c9..79045a6 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -1,4 +1,4 @@ -[com] +[com] #电机控制的串口名 motoPortName=COM3 @@ -17,6 +17,10 @@ maxFaceTryCount=20 #持续没找到人脸的最大次数 maxFaceNotFoundCount=500 +#注册时最小人脸 +minFaceRegist=240 +#识别时最小人脸 +minFaceRecog=100 #虹膜识别最大尝试次数 maxIrisTryCount=10 @@ -34,6 +38,18 @@ #统一背景色 backgroundColor="#FFFFFF" +[work] +#工作状态检测时最小人脸范围 +minFaceSize=160 +#人脸范围最小横坐标 +minFacePosX=320 +#人脸范围最大横坐标 +maxFacePosX=960 +#人脸范围最小纵坐标 +minFacePosY=180 +#人脸范围最大纵坐标 +maxFacePosY=540 + [camera] #人脸摄像头的编号 faceIndex=1 @@ -53,11 +69,3 @@ irisWidth=640 #虹膜图像高度 irisHeight=480 - -[stack] -#拍摄图像栈最大值 -capture=50 -#找到的眼睛图像栈最大值 -found=30 -#质量合格图像栈最大值 -qualified=30 diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 25854c3..0fe4b4c 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -63,7 +63,7 @@ cv::Mat faceMatDisp = imageMatMiir.clone(); // 利用人脸分类器进行初步的检测 - cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp); + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp, SettingConfig::getInstance().MIN_FACE_REGIST_SIZE); if (faceRect.width > 0) { // 初筛检测到人脸时将图像入栈 diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index da744f5..151de09 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -34,7 +34,7 @@ irisInfo.leftOrRight = "right"; } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::MAIN_PAGE) + if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) { // 相机拍摄下的图像1280*960, 直接用于算法判断 QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); @@ -43,7 +43,6 @@ irisInfo.data = imgDisp; irisInfo.matData = irisMat; - // 识别过程任意一个眼睛都行, 全部存入左眼队列 ProMemory::getInstance().pushCasicIris(irisInfo); } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) { diff --git a/device/device.pri b/device/device.pri index 6dc2f3c..64e6e17 100644 --- a/device/device.pri +++ b/device/device.pri @@ -1,24 +1,24 @@ -HEADERS += $$PWD/FaceCameraController.h \ - $$PWD/face/FaceRegistProcess.h -HEADERS += -HEADERS += $$PWD/face/FaceDetectRecogProcess.h +HEADERS += $$PWD/FaceCameraController.h +HEADERS += $$PWD/face/FaceRecogProcess.h +HEADERS += $$PWD/face/FaceRegistProcess.h HEADERS += $$PWD/face/CasicFaceRecState.h -SOURCES += $$PWD/FaceCameraController.cpp \ - $$PWD/face/FaceRegistProcess.cpp -SOURCES += -SOURCES += $$PWD/face/FaceDetectRecogProcess.cpp +SOURCES += $$PWD/FaceCameraController.cpp +SOURCES += $$PWD/face/FaceRecogProcess.cpp +SOURCES += $$PWD/face/FaceRegistProcess.cpp SOURCES += $$PWD/face/CasicFaceRecState.cpp 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/MotoController.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/MotoController.cpp diff --git a/device/face/FaceDetectRecogProcess.cpp b/device/face/FaceDetectRecogProcess.cpp deleted file mode 100644 index d8d6d01..0000000 --- a/device/face/FaceDetectRecogProcess.cpp +++ /dev/null @@ -1,197 +0,0 @@ -#include "FaceDetectRecogProcess.h" - -FaceDetectRecogProcess::FaceDetectRecogProcess(QObject *parent) : QThread(parent) -{ - this->working = false; - this->exit = false; -} - -FaceDetectRecogProcess::~FaceDetectRecogProcess() -{ - this->setWorking(false); -} - -void FaceDetectRecogProcess::setWorking(bool working) -{ - this->working = working; -} -void FaceDetectRecogProcess::exitThread() -{ - this->exit = true; -} -void FaceDetectRecogProcess::startThread() -{ - this->exit = false; - this->start(); -} - -void FaceDetectRecogProcess::addOneTryCount() -{ - LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); - if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) - { - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; - } else - { - CasicFaceRecState::getInstance().tryCount = 0; - CasicFaceRecState::getInstance().noFaceCount = 0; - emit matchFailure(); - - this->setWorking(false); // 返回后则线程暂停工作 - } -} - -void FaceDetectRecogProcess::addOneNoFaceCount() -{ - CasicFaceRecState::getInstance().noFaceCount++; - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; - if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) - { - CasicFaceRecState::getInstance().noFaceCount = 0; - emit matchFailure(); - - this->setWorking(false); // 返回后则暂停工作 - } -} - -void FaceDetectRecogProcess::run() -{ - while (exit == false) - { - if (this->working == false) - { - this->msleep(100); // 100ms后再判断 - continue; - } - - // 图像栈中没有图像则直接返回 - if (ProMemory::getInstance().isFaceQueueEmpty() == true) - { - addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 - LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); - - this->msleep(200); // 200ms后再判断 - continue; - } - - // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 - if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) - { - LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); - this->msleep(200); // 200ms后再判断 - continue; - } - - // 取出人脸图像栈中的一条数据 - CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); - - // 调用人脸检测算法 - faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); - - // 没有找到人脸则返回 - if (faceInfo.hasFace == false) - { - // 表示本次识别结束, 可以开始下一次识别过程 - addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 - LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); - this->msleep(200); // 200ms后再判断 - continue; - } - - // 找到人脸则开始一次识别 - if (CasicFaceRecState::getInstance().recoginzeId == "0") - { - CasicFaceRecState::getInstance().initRecognize(); - } - CasicFaceRecState::getInstance().faceInfo = &faceInfo; - CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 - CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 - - // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 - casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); - faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); - - // 活体检测判断为假脸 - if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) - { - // 表示本次识别结束, 可以开始下一次识别过程 - LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); - - addOneTryCount(); // 判断是否超过次数, 重置识别状态 - this->msleep(200); // 200ms后再判断 - continue; - } - - // 设置识别状态值=通过活体检测 - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; - - // 调用算法提取特征值, 1024个字节的float数组 - faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); - - // 设置识别状态值=特征值提取 - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; - CasicFaceRecState::getInstance().faceInfo = &faceInfo; - - LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); - - // 特征值提取成功的人脸 与人脸库中的人脸进行比较 - compareFaceInCollection(); - } -} - -void FaceDetectRecogProcess::compareFaceInCollection() -{ - ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 - QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); - for (int i = 0; i < faceFeatures.size(); i++) - { - QVariantMap ffMap = faceFeatures.at(i); - - QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); - float ffArr[1024]; - for (int i = 0; i < 1024; i++) - { - QByteArray tempBa; - tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); - ffArr[i] = ByteUtil::binToFloat(tempBa); - } - - float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); - - LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); - if (sim > 0.62) - { - CasicFaceRecState::getInstance().faceInfo->sim = sim; - CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); - CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; - - // 找到匹配的人脸图像 - this->afterRecogAction(ffMap.value("person_id").toString()); - this->setWorking(false); // 找到匹配的人脸之后停止识别线程工作 - return ; - } - } - - this->addOneTryCount(); -} - -void FaceDetectRecogProcess::afterRecogAction(QString personId) -{ - ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 - - LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); - - // 识别记录存入数据库 - RecognitionRecordDao recDao; - QVariantMap record; - record.insert("person_id", personId); - record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); - record.insert("type", "1"); - record.insert("debug_info", CasicFaceRecState::getInstance().toString()); - recDao.save(record); - - // 发送信号, 在主界面上显示 - emit matchSuccess(personId); -} - diff --git a/device/face/FaceDetectRecogProcess.h b/device/face/FaceDetectRecogProcess.h deleted file mode 100644 index 4ca4e94..0000000 --- a/device/face/FaceDetectRecogProcess.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef FACEDETECTRECOGPROCESS_H -#define FACEDETECTRECOGPROCESS_H - -#include -#include -#include "opencv2/opencv.hpp" - -#include "dao/RecognitionRecordDao.h" - -#include "CasicFaceRecState.h" -#include "casic/ProMemory.h" -#include "casic/face/CasicFaceInterface.h" -#include "utils/UtilInclude.h" - -class FaceDetectRecogProcess : public QThread -{ - Q_OBJECT -public: - explicit FaceDetectRecogProcess(QObject *parent = nullptr); - ~FaceDetectRecogProcess(); - - void setWorking(bool working); - void exitThread(); - void startThread(); - - void addOneTryCount(); - void addOneNoFaceCount(); - -protected: - //QThread的虚函数 - //线程处理函数 - //不能直接调用, 通过start()间接调用 - void run(); - void compareFaceInCollection(); - void afterRecogAction(QString personId); - - volatile bool working; - volatile bool exit; - -signals: - void matchSuccess(QString personId); // 匹配成功 - void matchFailure(); // 匹配失败 - -}; - -#endif // FACEDETECTRECOGPROCESS_H diff --git a/device/face/FaceRecogProcess.cpp b/device/face/FaceRecogProcess.cpp new file mode 100644 index 0000000..0fcd9d9 --- /dev/null +++ b/device/face/FaceRecogProcess.cpp @@ -0,0 +1,201 @@ +#include "FaceRecogProcess.h" + +FaceRecogProcess::FaceRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; +} + +FaceRecogProcess::~FaceRecogProcess() +{ + this->setWorking(false); +} + +void FaceRecogProcess::setWorking(bool working) +{ + this->working = working; +} +void FaceRecogProcess::exitThread() +{ + this->exit = true; +} +void FaceRecogProcess::startThread() +{ + this->exit = false; + this->start(); +} + +void FaceRecogProcess::addOneTryCount() +{ + LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); + if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) + { + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + } else + { + CasicFaceRecState::getInstance().tryCount = 0; + CasicFaceRecState::getInstance().noFaceCount = 0; + ProMemory::getInstance().clearFaceQueue(); + emit matchFailure(); + + this->setWorking(false); // 返回后则线程暂停工作 + } +} + +void FaceRecogProcess::addOneNoFaceCount() +{ + CasicFaceRecState::getInstance().noFaceCount++; + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) + { + CasicFaceRecState::getInstance().noFaceCount = 0; + ProMemory::getInstance().clearFaceQueue(); + emit matchFailure(); + + this->setWorking(false); // 返回后则暂停工作 + } +} + +void FaceRecogProcess::run() +{ + while (exit == false) + { + if (this->working == false) + { + this->msleep(100); // 100ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isFaceQueueEmpty() == true) + { + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) + { + LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 取出人脸图像栈中的一条数据 + CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); + + // 调用人脸检测算法 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); + + // 没有找到人脸则返回 + if (faceInfo.hasFace == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 找到人脸则开始一次识别 + if (CasicFaceRecState::getInstance().recoginzeId == "0") + { + CasicFaceRecState::getInstance().initRecognize(); + } + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 + CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 + + // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 + casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); + faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); + + // 活体检测判断为假脸 + if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) + { + // 表示本次识别结束, 可以开始下一次识别过程 + LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); + + addOneTryCount(); // 判断是否超过次数, 重置识别状态 + this->msleep(200); // 200ms后再判断 + continue; + } + + // 设置识别状态值=通过活体检测 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; + + // 调用算法提取特征值, 1024个字节的float数组 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); + + // 设置识别状态值=特征值提取 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + + LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 特征值提取成功的人脸 与人脸库中的人脸进行比较 + compareFaceInCollection(); + } +} + +void FaceRecogProcess::compareFaceInCollection() +{ + ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 + QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); + for (int i = 0; i < faceFeatures.size(); i++) + { + QVariantMap ffMap = faceFeatures.at(i); + + QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); + float ffArr[1024]; + for (int i = 0; i < 1024; i++) + { + QByteArray tempBa; + tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); + ffArr[i] = ByteUtil::binToFloat(tempBa); + } + + float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); + + LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); + if (sim > 0.62) + { + CasicFaceRecState::getInstance().faceInfo->sim = sim; + CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); + CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; + + // 找到匹配的人脸图像 + // 发送信号, 在主界面上显示 + emit matchSuccess(ffMap.value("person_id").toString(), 1); + +// this->afterRecogAction(ffMap.value("person_id").toString()); + this->setWorking(false); // 找到匹配的人脸之后停止识别线程工作 + return ; + } + } + + this->addOneTryCount(); +} + +void FaceRecogProcess::afterRecogAction(QString personId) +{ + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + + LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + +} + diff --git a/device/face/FaceRecogProcess.h b/device/face/FaceRecogProcess.h new file mode 100644 index 0000000..c551e23 --- /dev/null +++ b/device/face/FaceRecogProcess.h @@ -0,0 +1,46 @@ +#ifndef FACERECOGPROCESS_H +#define FACERECOGPROCESS_H + +#include +#include +#include "opencv2/opencv.hpp" + +#include "dao/RecognitionRecordDao.h" + +#include "CasicFaceRecState.h" +#include "casic/ProMemory.h" +#include "casic/face/CasicFaceInterface.h" +#include "utils/UtilInclude.h" + +class FaceRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit FaceRecogProcess(QObject *parent = nullptr); + ~FaceRecogProcess(); + + void setWorking(bool working); + void exitThread(); + void startThread(); + + void addOneTryCount(); + void addOneNoFaceCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + void compareFaceInCollection(); + void afterRecogAction(QString personId); + + volatile bool working; + volatile bool exit; + +signals: + void matchSuccess(QString personId, int faceOrIris); // 匹配成功 + void matchFailure(); // 匹配失败 + +}; + +#endif // FACERECOGPROCESS_H diff --git a/device/iris/CasicIrisRecState.cpp b/device/iris/CasicIrisRecState.cpp index 28625a1..d6d01e1 100644 --- a/device/iris/CasicIrisRecState.cpp +++ b/device/iris/CasicIrisRecState.cpp @@ -19,7 +19,7 @@ void CasicIrisRecState::initRecognize() { QDateTime now = QDateTime::currentDateTime(); - this->recoginzeId = now.toString("yyyyMMddHHmmsszzz").toStdString(); + this->recoginzeId = now.toString("yyyyMMddHHmmsszzz"); this->timeStamp = now.toMSecsSinceEpoch(); this->tryCount = 0; this->noEyeCount = 0; @@ -27,9 +27,9 @@ LOG(DEBUG) << QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString(); } -std::string CasicIrisRecState::toString() +QString CasicIrisRecState::toString() { - return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)).toStdString(); + return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)); } @@ -37,7 +37,7 @@ { QJsonObject obj; - obj.insert("recoginzeId", QString::fromStdString(recoginzeId)); + obj.insert("recoginzeId", recoginzeId); obj.insert("timestamp", timeStamp); obj.insert("timestampSucc", timeStampSucc); obj.insert("state", state); diff --git a/device/iris/CasicIrisRecState.h b/device/iris/CasicIrisRecState.h index 43bf234..d04b9e4 100644 --- a/device/iris/CasicIrisRecState.h +++ b/device/iris/CasicIrisRecState.h @@ -22,10 +22,10 @@ } void initRecognize(); - std::string toString(); + QString toString(); QJsonObject toJSON(); - std::string recoginzeId; // 识别过程id + QString recoginzeId; // 识别过程id qint64 timeStamp = 0; // 识别开始时间戳 qint64 timeStampSucc = 0; // 识别成功时的时间戳 qint64 findEyeTmLast = 0; // 找眼操作耗时 diff --git a/device/iris/IrisRecogProcess.cpp b/device/iris/IrisRecogProcess.cpp new file mode 100644 index 0000000..52c3826 --- /dev/null +++ b/device/iris/IrisRecogProcess.cpp @@ -0,0 +1,215 @@ +#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; + } + + LOG(DEBUG) << QString("[IrisRecogProcess]虹膜识别线程").toStdString(); + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isIrisQueueEmpty() == true) + { + LOG(DEBUG) << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString(); + 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(); + + this->msleep(200); // 200ms后再判断 + continue; + } + + // 取出虹膜图像栈中的一条数据 + CasicIrisInfo irisInfo = ProMemory::getInstance().popCasicIris(); + + LOG(DEBUG) << QString("[IrisRecogProcess]取出虹膜图像").toStdString(); + + // 调用找眼分类器算法 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + + // 没有找到眼睛则返回 + if (irisInfo.hasEye == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 + LOG(DEBUG) << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString(); + + addOneNoEyeCount(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 找到眼睛则开始质量评估和编码 + // 调用远程算法进行编码 + 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->leftOrRight = irisInfo.leftOrRight; + 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(); + + LOG(INFO) << QString("算法匹配结果").toStdString() << 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(); + + // 保存图像文件 + 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, 2); +// this->afterRecogAction(personId); + } else if (code.toInt() == -200) + { + // 匹配失败 + LOG(INFO) << QString("匹配失败: ").toStdString() << matchResponse.toStdString(); + + // 匹配失败则尝试次数+1 + addOneTryCount(); + } else if (code.toInt() == -100) + { + // 编码失败 + LOG(INFO) << QString("编码失败: ").toStdString() << matchResponse.toStdString(); + + // 编码失败则尝试次数+1 + addOneTryCount(); + } + } else + { + // 超时返回则尝试次数+1 + addOneTryCount(); + } + } +} + +void IrisRecogProcess::afterRecogAction(QString personId) +{ + ProMemory::getInstance().clearIrisQueue(); // 清理虹膜数据栈 + + this->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + LOG(DEBUG) << QString("[IrisRecogProcess] 识别成功 [%1]").arg(CasicIrisRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "2"); + record.insert("debug_info", CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + + // 发送信号, 在主界面上显示 + emit findMatchedIris(personId, 2); +} + +void IrisRecogProcess::addOneTryCount() +{ + CasicIrisRecState::getInstance().tryCount++; + 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(); + emit failedMatchedIris(); + } +} diff --git a/device/iris/IrisRecogProcess.h b/device/iris/IrisRecogProcess.h new file mode 100644 index 0000000..e256614 --- /dev/null +++ b/device/iris/IrisRecogProcess.h @@ -0,0 +1,47 @@ +#ifndef IRISRECOGPROCESS_H +#define IRISRECOGPROCESS_H + +#include +#include +#include +#include + +#include "casic/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(QString personId); + +signals: + void sendDataToExract(QByteArray data); + + void failedMatchedIris(); + void findMatchedIris(QString personId, int faceOrIris); + +}; + +#endif // IRISRECOGPROCESS_H diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index d14fd54..05fe5f1 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -258,8 +258,8 @@ // 情况3 编辑时非本人 人脸重复 // 语音提示 - SpeakerUtil::getInstance().speak(QString("人脸重复注册,请重试")); - LOG(DEBUG) << "人脸已经注册" << ui->inputName->text().toStdString(); + SpeakerUtil::getInstance().speak(QString("人脸已注册其他人,请重试")); + LOG(DEBUG) << "人脸已注册其他人" << ui->inputName->text().toStdString(); } } } @@ -288,19 +288,20 @@ // 停止拍图 ProMemory::getInstance().irisCam->stopCapture(); - ProMemory::getInstance().irisRegistPro->setWorking(false); - // 语音提示 - SpeakerUtil::getInstance().speak(QString("虹膜重复注册,请重试")); - if (this->personId.isEmpty() == true) { // 情况1 新注册 重复注册 loadPersonInfo(personIdByIris); + + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已经注册,请重试")); LOG(DEBUG) << "虹膜已经注册" << ui->inputName->text().toStdString(); } else { - LOG(DEBUG) << "虹膜已经注册" << personIdByIris.toStdString(); + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已注册其他人,请重试")); + LOG(DEBUG) << "虹膜已注册其他人" << personIdByIris.toStdString(); } } diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index 45fe761..f202cfe 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -30,6 +30,7 @@ initFaceRegistThread(); // 人脸注册线程 initFaceRecogThread(); // 人脸识别线程 initIrisRegistThread(); // 虹膜注册线程 + initIrisRecogThread(); // 虹膜识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); @@ -67,6 +68,10 @@ ProMemory::getInstance().irisRegistPro->deleteLater(); ProMemory::getInstance().irisRegistPro->wait(); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + // 关闭自动启动的外部程序 // outExe->close(); // delete outExe; @@ -75,6 +80,7 @@ delete ProMemory::getInstance().faceRegistPro; delete ProMemory::getInstance().faceRecogPro; delete ProMemory::getInstance().irisRegistPro; + delete ProMemory::getInstance().irisRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -194,15 +200,17 @@ void CasicBioRecWin::initFaceRecogThread() { // 人脸识别处理过程 - ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + ProMemory::getInstance().faceRecogPro = new FaceRecogProcess(this); // 绑定信号与槽函数 // 识别成功 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, - recogResultForm, &RecognizeResultForm::showRecognizeResult); +// connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); // 识别失败 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchFailure, recogResultForm, &RecognizeResultForm::showRecogFailure); ProMemory::getInstance().faceRecogPro->start(); @@ -222,9 +230,28 @@ connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::captureIrisFailure, addPersonForm, &AddPersonForm::onFailedCaptureIris); - // 采集虹膜图像成功 有匹配到红魔库 + // 采集虹膜图像成功 有匹配到虹膜库 connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::findMatchedIris, addPersonForm, &AddPersonForm::onMatchedIris); ProMemory::getInstance().irisRegistPro->start(); } + +void CasicBioRecWin::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 +// connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index ff2ed35..b70245a 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -53,6 +53,7 @@ void initFaceRegistThread(); void initFaceRecogThread(); void initIrisRegistThread(); + void initIrisRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp index b61cb09..e45a191 100644 --- a/RecognizeResultForm.cpp +++ b/RecognizeResultForm.cpp @@ -26,10 +26,28 @@ void RecognizeResultForm::startWorkingRecognize() { // 开始人脸识别 - ProMemory::getInstance().faceRecogPro->setWorking(true); + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + // 人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + break; + case 2: + // 虹膜识别 + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + case 3: + case 4: + // 人脸和虹膜都需要打开 + ProMemory::getInstance().faceRecogPro->setWorking(true); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + } // 将界面切换到识别界面 RecognizeResultForm ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + ui->labBackground->raise(); // 1人脸图像显示的容器 ui->labVideo->resize(1280, 720); @@ -63,13 +81,17 @@ ui->widgetFail->show(); QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ - emit backToHomeAndWait(); - CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; + + emit backToHomeAndWait(); }); } void RecognizeResultForm::showRecognizeResult(QString personId) { + personIdByFace = ""; + personIdByIris = ""; + SpeakerUtil::getInstance().speak("识别成功"); ui->labVideo->hide(); ui->labTitle->hide(); @@ -102,8 +124,131 @@ ui->widgetSucc->show(); QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ - emit backToHomeAndWait(); CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + + emit backToHomeAndWait(); }); } + +void RecognizeResultForm::checkRecognizeResult(QString personId, int faceOrIris) +{ + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + { + // 仅人脸识别 + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 人脸识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 2: + { + // 仅虹膜识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜识别成功 [%1]").arg(CasicIrisRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "2"); + record.insert("debug_info", CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 4: + { + // 任意识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + QString logStr = QString("[RecognizeResultForm]%1识别成功[%2]"); + if (faceOrIris == 1) + { + logStr.arg("人脸").arg(CasicFaceRecState::getInstance().toString()); + } else if (faceOrIris == 2) + { + logStr.arg("虹膜").arg(CasicIrisRecState::getInstance().toString()); + } + LOG(DEBUG) << logStr.toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", QString::number(faceOrIris)); + record.insert("debug_info", faceOrIris == 1 ? CasicFaceRecState::getInstance().toString() : CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 3: + if (faceOrIris == 1) + { + this->personIdByFace = personId; + } else if (faceOrIris == 2) + { + this->personIdByIris = personId; + } + + if (personIdByFace.isEmpty() || personIdByIris.isEmpty()) + { + // 只有一个成功的结果 需要等待下次 + return; + } else if (personIdByFace != personIdByIris) + { + // 人脸和虹膜识别的不是同一人 识别失败 + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜与人脸识别结果不一致,识别失败 [face: %1][iris: %2]").arg(personIdByFace).arg(personIdByIris).toStdString(); + SpeakerUtil::getInstance().speak("虹膜与人脸识别结果不一致,识别失败,请重试"); + showRecogFailure(); + } else + { + LOG(DEBUG) << QString("[RecognizeResultForm]人脸虹膜识别成功").toStdString(); + showRecognizeResult(personId); + } + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "4"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString() + " " + CasicIrisRecState::getInstance().toString()); + recDao.save(record); + } +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h index f5ef019..2c51865 100644 --- a/RecognizeResultForm.h +++ b/RecognizeResultForm.h @@ -25,7 +25,8 @@ public slots: void showRecogFailure(); - void showRecognizeResult(QString personId); + + void checkRecognizeResult(QString personId, int faceOrIris); void startWorkingRecognize(); // 开始工作 void drawImageOnHomeForm(QImage imageDisp); @@ -33,6 +34,11 @@ private: Ui::RecognizeResultForm *ui; + QString personIdByFace; + QString personIdByIris; + + void showRecognizeResult(QString personId); + signals: void backToHomeAndWait(); // 识别结束 返回主界面并待机 diff --git a/StartupForm.cpp b/StartupForm.cpp index 3d3dfad..16c4dfc 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -29,8 +29,8 @@ // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); -// connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, -// this, &StartupForm::takeOneFrameForCheckStatus); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); TimeCounterUtil::getInstance().clockCounter->start(1000); } @@ -54,6 +54,12 @@ return; } + if (this->isVisible() == false) + { + // 没有在这个页面直接返回 + return; + } + // 不在这个页面 则直接返回 不做后续判断 if (ProMemory::getInstance().widgeFrame != CasicBioRecConst::WidgeFrameName::MAIN_PAGE) { @@ -61,10 +67,25 @@ } cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); - bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + + // 判断是否开始工作时使用严格标准 人脸大小需要符合注册图像的尺寸 + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(rawFrame, SettingConfig::getInstance().MIN_WORK_FACE_SIZE); + if (faceRect.width == 0) + { + return ; + } + + bool hasFace = faceRect.width == 0 ? false : true; + if (faceRect.x < SettingConfig::getInstance().MIN_WORK_FACE_POSX || faceRect.x > SettingConfig::getInstance().MAX_WORK_FACE_POSX || + faceRect.y < SettingConfig::getInstance().MIN_WORK_FACE_POSY || faceRect.y > SettingConfig::getInstance().MAX_WORK_FACE_POSY) + { + // 检测到的人脸不在核心区则返回 + hasFace = false; + } + if (hasFace == true) { - LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + LOG(INFO) << QString("检测到人脸,START RECOGNIZE 线程").toStdString(); ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; // 启动识别线程 diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 1bc7d3a..3e9fbd4 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -13,14 +13,16 @@ #include "device/FaceCameraController.h" #include "device/IrisCameraController.h" #include "device/face/FaceRegistProcess.h" -#include "device/face/FaceDetectRecogProcess.h" +#include "device/face/FaceRecogProcess.h" #include "device/iris/IrisRegistProcess.h" +#include "device/iris/IrisRecogProcess.h" class FaceCameraController; class IrisCameraController; class FaceRegistProcess; -class FaceDetectRecogProcess; +class FaceRecogProcess; class IrisRegistProcess; +class IrisRecogProcess; class ProMemory { @@ -58,18 +60,17 @@ FaceCameraController * faceCam; FaceRegistProcess * faceRegistPro; - FaceDetectRecogProcess * faceRecogPro; + FaceRecogProcess * faceRecogPro; IrisCameraController * irisCam; IrisRegistProcess * irisRegistPro; + IrisRecogProcess * irisRecogPro; private: ProMemory(); QStack faceQueue; // 人脸信息队列 QStack irisQueue; // 虹膜信息队列 -// QStack irisLeftQueue; // 左眼信息队列 -// QStack irisRightQueue; // 右眼信息队列 QVector faceFeatures; // 人脸特征值集合 QVector irisFeatures; // 虹膜特征值集合 diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index cb4d3bd..f530212 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -372,6 +372,28 @@ return rect.at(0); } +cv::Rect casic::face::CasicFaceInterface::faceDetectByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + if (rect.size() == 0) + { + return cv::Rect(0, 0, 0, 0); + } + return rect.at(0); +} + cv::Rect casic::face::CasicFaceInterface::eyeDetectByCVCascade(cv::Mat frame) { // 构建openCV自带的眼睛分类器 @@ -402,23 +424,6 @@ return rect.at(0); } -bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) -{ - // 构建OpenCV自带的人脸分类器 - if (this->cascade == nullptr) { - this->cascade = new cv::CascadeClassifier(); - this->cascade->load(cvFaceCascadeName); - } - - std::vector rect; - cv::Size minRectSize(minFaceSize, minFaceSize); - cv::Size maxRectSize(maxFaceSize, maxFaceSize); - - // ★分类器对象调用 - cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); - - return rect.size() == 0 ? false : true; -} bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) { // 构建openCV自带的眼睛分类器 diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index 8a1c564..9d8b8ea 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -1,4 +1,4 @@ -#ifndef CASICFACEINTERFACE_H +#ifndef CASICFACEINTERFACE_H #define CASICFACEINTERFACE_H #include "opencv2/opencv.hpp" @@ -49,8 +49,9 @@ float faceSimCalculate(float* feature, float* otherFeature); cv::Rect faceDetectByCVCascade(cv::Mat frame); + cv::Rect faceDetectByCVCascade(cv::Mat frame, int minFaceSize); + cv::Rect eyeDetectByCVCascade(cv::Mat frame); - bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); @@ -68,7 +69,7 @@ int minFaceSize = 320; int maxFaceSize = 720; int minEyeSize = 100; - int maxEyeSize = 600; + int maxEyeSize = 300; std::string detectorModelPath = "./model/face_detector.csta"; std::string markPts5ModelPath = "./model/face_landmarker_pts5.csta"; diff --git a/conf/config.ini b/conf/config.ini index 84e31c9..79045a6 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -1,4 +1,4 @@ -[com] +[com] #电机控制的串口名 motoPortName=COM3 @@ -17,6 +17,10 @@ maxFaceTryCount=20 #持续没找到人脸的最大次数 maxFaceNotFoundCount=500 +#注册时最小人脸 +minFaceRegist=240 +#识别时最小人脸 +minFaceRecog=100 #虹膜识别最大尝试次数 maxIrisTryCount=10 @@ -34,6 +38,18 @@ #统一背景色 backgroundColor="#FFFFFF" +[work] +#工作状态检测时最小人脸范围 +minFaceSize=160 +#人脸范围最小横坐标 +minFacePosX=320 +#人脸范围最大横坐标 +maxFacePosX=960 +#人脸范围最小纵坐标 +minFacePosY=180 +#人脸范围最大纵坐标 +maxFacePosY=540 + [camera] #人脸摄像头的编号 faceIndex=1 @@ -53,11 +69,3 @@ irisWidth=640 #虹膜图像高度 irisHeight=480 - -[stack] -#拍摄图像栈最大值 -capture=50 -#找到的眼睛图像栈最大值 -found=30 -#质量合格图像栈最大值 -qualified=30 diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 25854c3..0fe4b4c 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -63,7 +63,7 @@ cv::Mat faceMatDisp = imageMatMiir.clone(); // 利用人脸分类器进行初步的检测 - cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp); + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp, SettingConfig::getInstance().MIN_FACE_REGIST_SIZE); if (faceRect.width > 0) { // 初筛检测到人脸时将图像入栈 diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index da744f5..151de09 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -34,7 +34,7 @@ irisInfo.leftOrRight = "right"; } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::MAIN_PAGE) + if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) { // 相机拍摄下的图像1280*960, 直接用于算法判断 QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); @@ -43,7 +43,6 @@ irisInfo.data = imgDisp; irisInfo.matData = irisMat; - // 识别过程任意一个眼睛都行, 全部存入左眼队列 ProMemory::getInstance().pushCasicIris(irisInfo); } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) { diff --git a/device/device.pri b/device/device.pri index 6dc2f3c..64e6e17 100644 --- a/device/device.pri +++ b/device/device.pri @@ -1,24 +1,24 @@ -HEADERS += $$PWD/FaceCameraController.h \ - $$PWD/face/FaceRegistProcess.h -HEADERS += -HEADERS += $$PWD/face/FaceDetectRecogProcess.h +HEADERS += $$PWD/FaceCameraController.h +HEADERS += $$PWD/face/FaceRecogProcess.h +HEADERS += $$PWD/face/FaceRegistProcess.h HEADERS += $$PWD/face/CasicFaceRecState.h -SOURCES += $$PWD/FaceCameraController.cpp \ - $$PWD/face/FaceRegistProcess.cpp -SOURCES += -SOURCES += $$PWD/face/FaceDetectRecogProcess.cpp +SOURCES += $$PWD/FaceCameraController.cpp +SOURCES += $$PWD/face/FaceRecogProcess.cpp +SOURCES += $$PWD/face/FaceRegistProcess.cpp SOURCES += $$PWD/face/CasicFaceRecState.cpp 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/MotoController.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/MotoController.cpp diff --git a/device/face/FaceDetectRecogProcess.cpp b/device/face/FaceDetectRecogProcess.cpp deleted file mode 100644 index d8d6d01..0000000 --- a/device/face/FaceDetectRecogProcess.cpp +++ /dev/null @@ -1,197 +0,0 @@ -#include "FaceDetectRecogProcess.h" - -FaceDetectRecogProcess::FaceDetectRecogProcess(QObject *parent) : QThread(parent) -{ - this->working = false; - this->exit = false; -} - -FaceDetectRecogProcess::~FaceDetectRecogProcess() -{ - this->setWorking(false); -} - -void FaceDetectRecogProcess::setWorking(bool working) -{ - this->working = working; -} -void FaceDetectRecogProcess::exitThread() -{ - this->exit = true; -} -void FaceDetectRecogProcess::startThread() -{ - this->exit = false; - this->start(); -} - -void FaceDetectRecogProcess::addOneTryCount() -{ - LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); - if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) - { - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; - } else - { - CasicFaceRecState::getInstance().tryCount = 0; - CasicFaceRecState::getInstance().noFaceCount = 0; - emit matchFailure(); - - this->setWorking(false); // 返回后则线程暂停工作 - } -} - -void FaceDetectRecogProcess::addOneNoFaceCount() -{ - CasicFaceRecState::getInstance().noFaceCount++; - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; - if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) - { - CasicFaceRecState::getInstance().noFaceCount = 0; - emit matchFailure(); - - this->setWorking(false); // 返回后则暂停工作 - } -} - -void FaceDetectRecogProcess::run() -{ - while (exit == false) - { - if (this->working == false) - { - this->msleep(100); // 100ms后再判断 - continue; - } - - // 图像栈中没有图像则直接返回 - if (ProMemory::getInstance().isFaceQueueEmpty() == true) - { - addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 - LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); - - this->msleep(200); // 200ms后再判断 - continue; - } - - // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 - if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) - { - LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); - this->msleep(200); // 200ms后再判断 - continue; - } - - // 取出人脸图像栈中的一条数据 - CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); - - // 调用人脸检测算法 - faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); - - // 没有找到人脸则返回 - if (faceInfo.hasFace == false) - { - // 表示本次识别结束, 可以开始下一次识别过程 - addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 - LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); - this->msleep(200); // 200ms后再判断 - continue; - } - - // 找到人脸则开始一次识别 - if (CasicFaceRecState::getInstance().recoginzeId == "0") - { - CasicFaceRecState::getInstance().initRecognize(); - } - CasicFaceRecState::getInstance().faceInfo = &faceInfo; - CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 - CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 - - // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 - casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); - faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); - - // 活体检测判断为假脸 - if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) - { - // 表示本次识别结束, 可以开始下一次识别过程 - LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); - - addOneTryCount(); // 判断是否超过次数, 重置识别状态 - this->msleep(200); // 200ms后再判断 - continue; - } - - // 设置识别状态值=通过活体检测 - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; - - // 调用算法提取特征值, 1024个字节的float数组 - faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); - - // 设置识别状态值=特征值提取 - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; - CasicFaceRecState::getInstance().faceInfo = &faceInfo; - - LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); - - // 特征值提取成功的人脸 与人脸库中的人脸进行比较 - compareFaceInCollection(); - } -} - -void FaceDetectRecogProcess::compareFaceInCollection() -{ - ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 - QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); - for (int i = 0; i < faceFeatures.size(); i++) - { - QVariantMap ffMap = faceFeatures.at(i); - - QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); - float ffArr[1024]; - for (int i = 0; i < 1024; i++) - { - QByteArray tempBa; - tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); - ffArr[i] = ByteUtil::binToFloat(tempBa); - } - - float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); - - LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); - if (sim > 0.62) - { - CasicFaceRecState::getInstance().faceInfo->sim = sim; - CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); - CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; - - // 找到匹配的人脸图像 - this->afterRecogAction(ffMap.value("person_id").toString()); - this->setWorking(false); // 找到匹配的人脸之后停止识别线程工作 - return ; - } - } - - this->addOneTryCount(); -} - -void FaceDetectRecogProcess::afterRecogAction(QString personId) -{ - ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 - - LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); - - // 识别记录存入数据库 - RecognitionRecordDao recDao; - QVariantMap record; - record.insert("person_id", personId); - record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); - record.insert("type", "1"); - record.insert("debug_info", CasicFaceRecState::getInstance().toString()); - recDao.save(record); - - // 发送信号, 在主界面上显示 - emit matchSuccess(personId); -} - diff --git a/device/face/FaceDetectRecogProcess.h b/device/face/FaceDetectRecogProcess.h deleted file mode 100644 index 4ca4e94..0000000 --- a/device/face/FaceDetectRecogProcess.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef FACEDETECTRECOGPROCESS_H -#define FACEDETECTRECOGPROCESS_H - -#include -#include -#include "opencv2/opencv.hpp" - -#include "dao/RecognitionRecordDao.h" - -#include "CasicFaceRecState.h" -#include "casic/ProMemory.h" -#include "casic/face/CasicFaceInterface.h" -#include "utils/UtilInclude.h" - -class FaceDetectRecogProcess : public QThread -{ - Q_OBJECT -public: - explicit FaceDetectRecogProcess(QObject *parent = nullptr); - ~FaceDetectRecogProcess(); - - void setWorking(bool working); - void exitThread(); - void startThread(); - - void addOneTryCount(); - void addOneNoFaceCount(); - -protected: - //QThread的虚函数 - //线程处理函数 - //不能直接调用, 通过start()间接调用 - void run(); - void compareFaceInCollection(); - void afterRecogAction(QString personId); - - volatile bool working; - volatile bool exit; - -signals: - void matchSuccess(QString personId); // 匹配成功 - void matchFailure(); // 匹配失败 - -}; - -#endif // FACEDETECTRECOGPROCESS_H diff --git a/device/face/FaceRecogProcess.cpp b/device/face/FaceRecogProcess.cpp new file mode 100644 index 0000000..0fcd9d9 --- /dev/null +++ b/device/face/FaceRecogProcess.cpp @@ -0,0 +1,201 @@ +#include "FaceRecogProcess.h" + +FaceRecogProcess::FaceRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; +} + +FaceRecogProcess::~FaceRecogProcess() +{ + this->setWorking(false); +} + +void FaceRecogProcess::setWorking(bool working) +{ + this->working = working; +} +void FaceRecogProcess::exitThread() +{ + this->exit = true; +} +void FaceRecogProcess::startThread() +{ + this->exit = false; + this->start(); +} + +void FaceRecogProcess::addOneTryCount() +{ + LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); + if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) + { + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + } else + { + CasicFaceRecState::getInstance().tryCount = 0; + CasicFaceRecState::getInstance().noFaceCount = 0; + ProMemory::getInstance().clearFaceQueue(); + emit matchFailure(); + + this->setWorking(false); // 返回后则线程暂停工作 + } +} + +void FaceRecogProcess::addOneNoFaceCount() +{ + CasicFaceRecState::getInstance().noFaceCount++; + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) + { + CasicFaceRecState::getInstance().noFaceCount = 0; + ProMemory::getInstance().clearFaceQueue(); + emit matchFailure(); + + this->setWorking(false); // 返回后则暂停工作 + } +} + +void FaceRecogProcess::run() +{ + while (exit == false) + { + if (this->working == false) + { + this->msleep(100); // 100ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isFaceQueueEmpty() == true) + { + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) + { + LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 取出人脸图像栈中的一条数据 + CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); + + // 调用人脸检测算法 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); + + // 没有找到人脸则返回 + if (faceInfo.hasFace == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 找到人脸则开始一次识别 + if (CasicFaceRecState::getInstance().recoginzeId == "0") + { + CasicFaceRecState::getInstance().initRecognize(); + } + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 + CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 + + // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 + casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); + faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); + + // 活体检测判断为假脸 + if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) + { + // 表示本次识别结束, 可以开始下一次识别过程 + LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); + + addOneTryCount(); // 判断是否超过次数, 重置识别状态 + this->msleep(200); // 200ms后再判断 + continue; + } + + // 设置识别状态值=通过活体检测 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; + + // 调用算法提取特征值, 1024个字节的float数组 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); + + // 设置识别状态值=特征值提取 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + + LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 特征值提取成功的人脸 与人脸库中的人脸进行比较 + compareFaceInCollection(); + } +} + +void FaceRecogProcess::compareFaceInCollection() +{ + ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 + QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); + for (int i = 0; i < faceFeatures.size(); i++) + { + QVariantMap ffMap = faceFeatures.at(i); + + QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); + float ffArr[1024]; + for (int i = 0; i < 1024; i++) + { + QByteArray tempBa; + tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); + ffArr[i] = ByteUtil::binToFloat(tempBa); + } + + float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); + + LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); + if (sim > 0.62) + { + CasicFaceRecState::getInstance().faceInfo->sim = sim; + CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); + CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; + + // 找到匹配的人脸图像 + // 发送信号, 在主界面上显示 + emit matchSuccess(ffMap.value("person_id").toString(), 1); + +// this->afterRecogAction(ffMap.value("person_id").toString()); + this->setWorking(false); // 找到匹配的人脸之后停止识别线程工作 + return ; + } + } + + this->addOneTryCount(); +} + +void FaceRecogProcess::afterRecogAction(QString personId) +{ + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + + LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + +} + diff --git a/device/face/FaceRecogProcess.h b/device/face/FaceRecogProcess.h new file mode 100644 index 0000000..c551e23 --- /dev/null +++ b/device/face/FaceRecogProcess.h @@ -0,0 +1,46 @@ +#ifndef FACERECOGPROCESS_H +#define FACERECOGPROCESS_H + +#include +#include +#include "opencv2/opencv.hpp" + +#include "dao/RecognitionRecordDao.h" + +#include "CasicFaceRecState.h" +#include "casic/ProMemory.h" +#include "casic/face/CasicFaceInterface.h" +#include "utils/UtilInclude.h" + +class FaceRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit FaceRecogProcess(QObject *parent = nullptr); + ~FaceRecogProcess(); + + void setWorking(bool working); + void exitThread(); + void startThread(); + + void addOneTryCount(); + void addOneNoFaceCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + void compareFaceInCollection(); + void afterRecogAction(QString personId); + + volatile bool working; + volatile bool exit; + +signals: + void matchSuccess(QString personId, int faceOrIris); // 匹配成功 + void matchFailure(); // 匹配失败 + +}; + +#endif // FACERECOGPROCESS_H diff --git a/device/iris/CasicIrisRecState.cpp b/device/iris/CasicIrisRecState.cpp index 28625a1..d6d01e1 100644 --- a/device/iris/CasicIrisRecState.cpp +++ b/device/iris/CasicIrisRecState.cpp @@ -19,7 +19,7 @@ void CasicIrisRecState::initRecognize() { QDateTime now = QDateTime::currentDateTime(); - this->recoginzeId = now.toString("yyyyMMddHHmmsszzz").toStdString(); + this->recoginzeId = now.toString("yyyyMMddHHmmsszzz"); this->timeStamp = now.toMSecsSinceEpoch(); this->tryCount = 0; this->noEyeCount = 0; @@ -27,9 +27,9 @@ LOG(DEBUG) << QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString(); } -std::string CasicIrisRecState::toString() +QString CasicIrisRecState::toString() { - return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)).toStdString(); + return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)); } @@ -37,7 +37,7 @@ { QJsonObject obj; - obj.insert("recoginzeId", QString::fromStdString(recoginzeId)); + obj.insert("recoginzeId", recoginzeId); obj.insert("timestamp", timeStamp); obj.insert("timestampSucc", timeStampSucc); obj.insert("state", state); diff --git a/device/iris/CasicIrisRecState.h b/device/iris/CasicIrisRecState.h index 43bf234..d04b9e4 100644 --- a/device/iris/CasicIrisRecState.h +++ b/device/iris/CasicIrisRecState.h @@ -22,10 +22,10 @@ } void initRecognize(); - std::string toString(); + QString toString(); QJsonObject toJSON(); - std::string recoginzeId; // 识别过程id + QString recoginzeId; // 识别过程id qint64 timeStamp = 0; // 识别开始时间戳 qint64 timeStampSucc = 0; // 识别成功时的时间戳 qint64 findEyeTmLast = 0; // 找眼操作耗时 diff --git a/device/iris/IrisRecogProcess.cpp b/device/iris/IrisRecogProcess.cpp new file mode 100644 index 0000000..52c3826 --- /dev/null +++ b/device/iris/IrisRecogProcess.cpp @@ -0,0 +1,215 @@ +#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; + } + + LOG(DEBUG) << QString("[IrisRecogProcess]虹膜识别线程").toStdString(); + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isIrisQueueEmpty() == true) + { + LOG(DEBUG) << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString(); + 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(); + + this->msleep(200); // 200ms后再判断 + continue; + } + + // 取出虹膜图像栈中的一条数据 + CasicIrisInfo irisInfo = ProMemory::getInstance().popCasicIris(); + + LOG(DEBUG) << QString("[IrisRecogProcess]取出虹膜图像").toStdString(); + + // 调用找眼分类器算法 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + + // 没有找到眼睛则返回 + if (irisInfo.hasEye == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 + LOG(DEBUG) << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString(); + + addOneNoEyeCount(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 找到眼睛则开始质量评估和编码 + // 调用远程算法进行编码 + 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->leftOrRight = irisInfo.leftOrRight; + 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(); + + LOG(INFO) << QString("算法匹配结果").toStdString() << 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(); + + // 保存图像文件 + 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, 2); +// this->afterRecogAction(personId); + } else if (code.toInt() == -200) + { + // 匹配失败 + LOG(INFO) << QString("匹配失败: ").toStdString() << matchResponse.toStdString(); + + // 匹配失败则尝试次数+1 + addOneTryCount(); + } else if (code.toInt() == -100) + { + // 编码失败 + LOG(INFO) << QString("编码失败: ").toStdString() << matchResponse.toStdString(); + + // 编码失败则尝试次数+1 + addOneTryCount(); + } + } else + { + // 超时返回则尝试次数+1 + addOneTryCount(); + } + } +} + +void IrisRecogProcess::afterRecogAction(QString personId) +{ + ProMemory::getInstance().clearIrisQueue(); // 清理虹膜数据栈 + + this->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + LOG(DEBUG) << QString("[IrisRecogProcess] 识别成功 [%1]").arg(CasicIrisRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "2"); + record.insert("debug_info", CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + + // 发送信号, 在主界面上显示 + emit findMatchedIris(personId, 2); +} + +void IrisRecogProcess::addOneTryCount() +{ + CasicIrisRecState::getInstance().tryCount++; + 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(); + emit failedMatchedIris(); + } +} diff --git a/device/iris/IrisRecogProcess.h b/device/iris/IrisRecogProcess.h new file mode 100644 index 0000000..e256614 --- /dev/null +++ b/device/iris/IrisRecogProcess.h @@ -0,0 +1,47 @@ +#ifndef IRISRECOGPROCESS_H +#define IRISRECOGPROCESS_H + +#include +#include +#include +#include + +#include "casic/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(QString personId); + +signals: + void sendDataToExract(QByteArray data); + + void failedMatchedIris(); + void findMatchedIris(QString personId, int faceOrIris); + +}; + +#endif // IRISRECOGPROCESS_H diff --git a/utils/SettingConfig.cpp b/utils/SettingConfig.cpp index 13976d3..ce43d9f 100644 --- a/utils/SettingConfig.cpp +++ b/utils/SettingConfig.cpp @@ -1,4 +1,4 @@ -#include "SettingConfig.h" +#include "SettingConfig.h" #include SettingConfig::SettingConfig() @@ -29,10 +29,14 @@ MAX_FACE_NOT_FOUND_COUNT = getProperty("recognize", "maxFaceNotFoundCount").toInt(); MAX_IRIS_TRY_COUNT = getProperty("recognize", "maxIrisTryCount").toInt(); MAX_EYE_NOT_FOUND_COUNT = getProperty("recognize", "maxEyeNotFoundCount").toInt(); + MIN_FACE_REGIST_SIZE = getProperty("recognize", "minFaceRegist").toInt(); + MIN_FACE_RECOG_SIZE = getProperty("recognize", "minFaceRecog").toInt(); - MAX_CAPTURE_STACK_SIZE = getProperty("stack", "capture").toInt(); - MAX_FOUND_STACK_SIZE = getProperty("stack", "found").toInt(); - MAX_QUALIFIED_STACK_SIZE = getProperty("stack", "qualified").toInt(); + MIN_WORK_FACE_SIZE = getProperty("work", "minFaceSize").toInt(); + MIN_WORK_FACE_POSX = getProperty("work", "minFacePosX").toInt(); + MAX_WORK_FACE_POSX = getProperty("work", "maxFacePosX").toInt(); + MIN_WORK_FACE_POSY = getProperty("work", "minFacePosY").toInt(); + MAX_WORK_FACE_POSY = getProperty("work", "maxFacePosY").toInt(); PORT_NAME = getProperty("com", "motoPortName").toString(); diff --git a/AddPersonForm.cpp b/AddPersonForm.cpp index d14fd54..05fe5f1 100644 --- a/AddPersonForm.cpp +++ b/AddPersonForm.cpp @@ -258,8 +258,8 @@ // 情况3 编辑时非本人 人脸重复 // 语音提示 - SpeakerUtil::getInstance().speak(QString("人脸重复注册,请重试")); - LOG(DEBUG) << "人脸已经注册" << ui->inputName->text().toStdString(); + SpeakerUtil::getInstance().speak(QString("人脸已注册其他人,请重试")); + LOG(DEBUG) << "人脸已注册其他人" << ui->inputName->text().toStdString(); } } } @@ -288,19 +288,20 @@ // 停止拍图 ProMemory::getInstance().irisCam->stopCapture(); - ProMemory::getInstance().irisRegistPro->setWorking(false); - // 语音提示 - SpeakerUtil::getInstance().speak(QString("虹膜重复注册,请重试")); - if (this->personId.isEmpty() == true) { // 情况1 新注册 重复注册 loadPersonInfo(personIdByIris); + + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已经注册,请重试")); LOG(DEBUG) << "虹膜已经注册" << ui->inputName->text().toStdString(); } else { - LOG(DEBUG) << "虹膜已经注册" << personIdByIris.toStdString(); + // 语音提示 + SpeakerUtil::getInstance().speak(QString("虹膜已注册其他人,请重试")); + LOG(DEBUG) << "虹膜已注册其他人" << personIdByIris.toStdString(); } } diff --git a/CasicBioRecWin.cpp b/CasicBioRecWin.cpp index 45fe761..f202cfe 100644 --- a/CasicBioRecWin.cpp +++ b/CasicBioRecWin.cpp @@ -30,6 +30,7 @@ initFaceRegistThread(); // 人脸注册线程 initFaceRecogThread(); // 人脸识别线程 initIrisRegistThread(); // 虹膜注册线程 + initIrisRecogThread(); // 虹膜识别线程 // 初始化人脸相机控制 ProMemory::getInstance().faceCam = new FaceCameraController(this); @@ -67,6 +68,10 @@ ProMemory::getInstance().irisRegistPro->deleteLater(); ProMemory::getInstance().irisRegistPro->wait(); + ProMemory::getInstance().irisRecogPro->exitThread(); + ProMemory::getInstance().irisRecogPro->deleteLater(); + ProMemory::getInstance().irisRecogPro->wait(); + // 关闭自动启动的外部程序 // outExe->close(); // delete outExe; @@ -75,6 +80,7 @@ delete ProMemory::getInstance().faceRegistPro; delete ProMemory::getInstance().faceRecogPro; delete ProMemory::getInstance().irisRegistPro; + delete ProMemory::getInstance().irisRecogPro; } void CasicBioRecWin::keyPressEvent(QKeyEvent *event) @@ -194,15 +200,17 @@ void CasicBioRecWin::initFaceRecogThread() { // 人脸识别处理过程 - ProMemory::getInstance().faceRecogPro = new FaceDetectRecogProcess(this); + ProMemory::getInstance().faceRecogPro = new FaceRecogProcess(this); // 绑定信号与槽函数 // 识别成功 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchSuccess, - recogResultForm, &RecognizeResultForm::showRecognizeResult); +// connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchSuccess, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); // 识别失败 - connect(ProMemory::getInstance().faceRecogPro, &FaceDetectRecogProcess::matchFailure, + connect(ProMemory::getInstance().faceRecogPro, &FaceRecogProcess::matchFailure, recogResultForm, &RecognizeResultForm::showRecogFailure); ProMemory::getInstance().faceRecogPro->start(); @@ -222,9 +230,28 @@ connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::captureIrisFailure, addPersonForm, &AddPersonForm::onFailedCaptureIris); - // 采集虹膜图像成功 有匹配到红魔库 + // 采集虹膜图像成功 有匹配到虹膜库 connect(ProMemory::getInstance().irisRegistPro, &IrisRegistProcess::findMatchedIris, addPersonForm, &AddPersonForm::onMatchedIris); ProMemory::getInstance().irisRegistPro->start(); } + +void CasicBioRecWin::initIrisRecogThread() +{ + // 虹膜识别处理过程 + ProMemory::getInstance().irisRecogPro = new IrisRecogProcess(this); + + // 绑定信号与槽函数 + // 识别成功 +// connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, +// recogResultForm, &RecognizeResultForm::showRecognizeResult); + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::findMatchedIris, + recogResultForm, &RecognizeResultForm::checkRecognizeResult); + + // 识别失败 + connect(ProMemory::getInstance().irisRecogPro, &IrisRecogProcess::failedMatchedIris, + recogResultForm, &RecognizeResultForm::showRecogFailure); + + ProMemory::getInstance().irisRecogPro->start(); +} diff --git a/CasicBioRecWin.h b/CasicBioRecWin.h index ff2ed35..b70245a 100644 --- a/CasicBioRecWin.h +++ b/CasicBioRecWin.h @@ -53,6 +53,7 @@ void initFaceRegistThread(); void initFaceRecogThread(); void initIrisRegistThread(); + void initIrisRecogThread(); }; #endif // CASICBIORECWIN_H diff --git a/RecognizeResultForm.cpp b/RecognizeResultForm.cpp index b61cb09..e45a191 100644 --- a/RecognizeResultForm.cpp +++ b/RecognizeResultForm.cpp @@ -26,10 +26,28 @@ void RecognizeResultForm::startWorkingRecognize() { // 开始人脸识别 - ProMemory::getInstance().faceRecogPro->setWorking(true); + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + // 人脸识别 + ProMemory::getInstance().faceRecogPro->setWorking(true); + break; + case 2: + // 虹膜识别 + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + case 3: + case 4: + // 人脸和虹膜都需要打开 + ProMemory::getInstance().faceRecogPro->setWorking(true); + ProMemory::getInstance().irisRecogPro->setWorking(true); + ProMemory::getInstance().irisCam->startCapture(); + break; + } // 将界面切换到识别界面 RecognizeResultForm ProMemory::getInstance().faceCam->openFaceCamera(SettingConfig::getInstance().FACE_FRAME_INTERVAL); + ui->labBackground->raise(); // 1人脸图像显示的容器 ui->labVideo->resize(1280, 720); @@ -63,13 +81,17 @@ ui->widgetFail->show(); QTimer::singleShot(SettingConfig::getInstance().FAILURE_TIPS_LAST, [=](){ - emit backToHomeAndWait(); - CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; + + emit backToHomeAndWait(); }); } void RecognizeResultForm::showRecognizeResult(QString personId) { + personIdByFace = ""; + personIdByIris = ""; + SpeakerUtil::getInstance().speak("识别成功"); ui->labVideo->hide(); ui->labTitle->hide(); @@ -102,8 +124,131 @@ ui->widgetSucc->show(); QTimer::singleShot(SettingConfig::getInstance().SUCCESS_TIPS_LAST, [=](){ - emit backToHomeAndWait(); CasicFaceRecState::getInstance().state = CasicFaceRecState::REC_NOT_START; ui->labBackground->raise(); + + emit backToHomeAndWait(); }); } + +void RecognizeResultForm::checkRecognizeResult(QString personId, int faceOrIris) +{ + switch (SettingConfig::getInstance().RECOG_TYPE) { + case 1: + { + // 仅人脸识别 + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 人脸识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 2: + { + // 仅虹膜识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜识别成功 [%1]").arg(CasicIrisRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "2"); + record.insert("debug_info", CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 4: + { + // 任意识别 + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + QString logStr = QString("[RecognizeResultForm]%1识别成功[%2]"); + if (faceOrIris == 1) + { + logStr.arg("人脸").arg(CasicFaceRecState::getInstance().toString()); + } else if (faceOrIris == 2) + { + logStr.arg("虹膜").arg(CasicIrisRecState::getInstance().toString()); + } + LOG(DEBUG) << logStr.toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", QString::number(faceOrIris)); + record.insert("debug_info", faceOrIris == 1 ? CasicFaceRecState::getInstance().toString() : CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + showRecognizeResult(personId); + break; + } + case 3: + if (faceOrIris == 1) + { + this->personIdByFace = personId; + } else if (faceOrIris == 2) + { + this->personIdByIris = personId; + } + + if (personIdByFace.isEmpty() || personIdByIris.isEmpty()) + { + // 只有一个成功的结果 需要等待下次 + return; + } else if (personIdByFace != personIdByIris) + { + // 人脸和虹膜识别的不是同一人 识别失败 + LOG(DEBUG) << QString("[RecognizeResultForm] 虹膜与人脸识别结果不一致,识别失败 [face: %1][iris: %2]").arg(personIdByFace).arg(personIdByIris).toStdString(); + SpeakerUtil::getInstance().speak("虹膜与人脸识别结果不一致,识别失败,请重试"); + showRecogFailure(); + } else + { + LOG(DEBUG) << QString("[RecognizeResultForm]人脸虹膜识别成功").toStdString(); + showRecognizeResult(personId); + } + + ProMemory::getInstance().clearIrisQueue(); + ProMemory::getInstance().irisRecogPro->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + ProMemory::getInstance().clearFaceQueue(); + ProMemory::getInstance().faceRecogPro->setWorking(false); + ProMemory::getInstance().faceCam->stopTakingPhoto(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "4"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString() + " " + CasicIrisRecState::getInstance().toString()); + recDao.save(record); + } +} diff --git a/RecognizeResultForm.h b/RecognizeResultForm.h index f5ef019..2c51865 100644 --- a/RecognizeResultForm.h +++ b/RecognizeResultForm.h @@ -25,7 +25,8 @@ public slots: void showRecogFailure(); - void showRecognizeResult(QString personId); + + void checkRecognizeResult(QString personId, int faceOrIris); void startWorkingRecognize(); // 开始工作 void drawImageOnHomeForm(QImage imageDisp); @@ -33,6 +34,11 @@ private: Ui::RecognizeResultForm *ui; + QString personIdByFace; + QString personIdByIris; + + void showRecognizeResult(QString personId); + signals: void backToHomeAndWait(); // 识别结束 返回主界面并待机 diff --git a/StartupForm.cpp b/StartupForm.cpp index 3d3dfad..16c4dfc 100644 --- a/StartupForm.cpp +++ b/StartupForm.cpp @@ -29,8 +29,8 @@ // 每秒执行一次 connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, this, &StartupForm::updateDateAndTime); -// connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, -// this, &StartupForm::takeOneFrameForCheckStatus); + connect(TimeCounterUtil::getInstance().clockCounter, &QTimer::timeout, + this, &StartupForm::takeOneFrameForCheckStatus); TimeCounterUtil::getInstance().clockCounter->start(1000); } @@ -54,6 +54,12 @@ return; } + if (this->isVisible() == false) + { + // 没有在这个页面直接返回 + return; + } + // 不在这个页面 则直接返回 不做后续判断 if (ProMemory::getInstance().widgeFrame != CasicBioRecConst::WidgeFrameName::MAIN_PAGE) { @@ -61,10 +67,25 @@ } cv::Mat rawFrame = ProMemory::getInstance().faceCam->takeOneRawFrame(); - bool hasFace = casic::face::CasicFaceInterface::getInstance().hasFaceDetectedByCVCascade(rawFrame, 100); + + // 判断是否开始工作时使用严格标准 人脸大小需要符合注册图像的尺寸 + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(rawFrame, SettingConfig::getInstance().MIN_WORK_FACE_SIZE); + if (faceRect.width == 0) + { + return ; + } + + bool hasFace = faceRect.width == 0 ? false : true; + if (faceRect.x < SettingConfig::getInstance().MIN_WORK_FACE_POSX || faceRect.x > SettingConfig::getInstance().MAX_WORK_FACE_POSX || + faceRect.y < SettingConfig::getInstance().MIN_WORK_FACE_POSY || faceRect.y > SettingConfig::getInstance().MAX_WORK_FACE_POSY) + { + // 检测到的人脸不在核心区则返回 + hasFace = false; + } + if (hasFace == true) { - LOG(INFO) << QString("FACE DETECTED START WORKING").toStdString(); + LOG(INFO) << QString("检测到人脸,START RECOGNIZE 线程").toStdString(); ProMemory::getInstance().appState = CasicBioRecConst::ApplicationState::STATE_WORKING; // 启动识别线程 diff --git a/casic/ProMemory.h b/casic/ProMemory.h index 1bc7d3a..3e9fbd4 100644 --- a/casic/ProMemory.h +++ b/casic/ProMemory.h @@ -13,14 +13,16 @@ #include "device/FaceCameraController.h" #include "device/IrisCameraController.h" #include "device/face/FaceRegistProcess.h" -#include "device/face/FaceDetectRecogProcess.h" +#include "device/face/FaceRecogProcess.h" #include "device/iris/IrisRegistProcess.h" +#include "device/iris/IrisRecogProcess.h" class FaceCameraController; class IrisCameraController; class FaceRegistProcess; -class FaceDetectRecogProcess; +class FaceRecogProcess; class IrisRegistProcess; +class IrisRecogProcess; class ProMemory { @@ -58,18 +60,17 @@ FaceCameraController * faceCam; FaceRegistProcess * faceRegistPro; - FaceDetectRecogProcess * faceRecogPro; + FaceRecogProcess * faceRecogPro; IrisCameraController * irisCam; IrisRegistProcess * irisRegistPro; + IrisRecogProcess * irisRecogPro; private: ProMemory(); QStack faceQueue; // 人脸信息队列 QStack irisQueue; // 虹膜信息队列 -// QStack irisLeftQueue; // 左眼信息队列 -// QStack irisRightQueue; // 右眼信息队列 QVector faceFeatures; // 人脸特征值集合 QVector irisFeatures; // 虹膜特征值集合 diff --git a/casic/face/CasicFaceInterface.cpp b/casic/face/CasicFaceInterface.cpp index cb4d3bd..f530212 100644 --- a/casic/face/CasicFaceInterface.cpp +++ b/casic/face/CasicFaceInterface.cpp @@ -372,6 +372,28 @@ return rect.at(0); } +cv::Rect casic::face::CasicFaceInterface::faceDetectByCVCascade(cv::Mat frame, int minFaceSize) +{ + // 构建OpenCV自带的人脸分类器 + if (this->cascade == nullptr) { + this->cascade = new cv::CascadeClassifier(); + this->cascade->load(cvFaceCascadeName); + } + + std::vector rect; + cv::Size minRectSize(minFaceSize, minFaceSize); + cv::Size maxRectSize(maxFaceSize, maxFaceSize); + + // ★分类器对象调用 + cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); + + if (rect.size() == 0) + { + return cv::Rect(0, 0, 0, 0); + } + return rect.at(0); +} + cv::Rect casic::face::CasicFaceInterface::eyeDetectByCVCascade(cv::Mat frame) { // 构建openCV自带的眼睛分类器 @@ -402,23 +424,6 @@ return rect.at(0); } -bool casic::face::CasicFaceInterface::hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize) -{ - // 构建OpenCV自带的人脸分类器 - if (this->cascade == nullptr) { - this->cascade = new cv::CascadeClassifier(); - this->cascade->load(cvFaceCascadeName); - } - - std::vector rect; - cv::Size minRectSize(minFaceSize, minFaceSize); - cv::Size maxRectSize(maxFaceSize, maxFaceSize); - - // ★分类器对象调用 - cascade->detectMultiScale(frame, rect, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT, minRectSize, maxRectSize); - - return rect.size() == 0 ? false : true; -} bool casic::face::CasicFaceInterface::hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize) { // 构建openCV自带的眼睛分类器 diff --git a/casic/face/CasicFaceInterface.h b/casic/face/CasicFaceInterface.h index 8a1c564..9d8b8ea 100644 --- a/casic/face/CasicFaceInterface.h +++ b/casic/face/CasicFaceInterface.h @@ -1,4 +1,4 @@ -#ifndef CASICFACEINTERFACE_H +#ifndef CASICFACEINTERFACE_H #define CASICFACEINTERFACE_H #include "opencv2/opencv.hpp" @@ -49,8 +49,9 @@ float faceSimCalculate(float* feature, float* otherFeature); cv::Rect faceDetectByCVCascade(cv::Mat frame); + cv::Rect faceDetectByCVCascade(cv::Mat frame, int minFaceSize); + cv::Rect eyeDetectByCVCascade(cv::Mat frame); - bool hasFaceDetectedByCVCascade(cv::Mat frame, int minFaceSize); bool hasEyeDetectedByCVCascade(cv::Mat frame, int minEyeSize); void setMinFaceSize(int minFaceSize); void setMinEyeSize(int minEyeSize); @@ -68,7 +69,7 @@ int minFaceSize = 320; int maxFaceSize = 720; int minEyeSize = 100; - int maxEyeSize = 600; + int maxEyeSize = 300; std::string detectorModelPath = "./model/face_detector.csta"; std::string markPts5ModelPath = "./model/face_landmarker_pts5.csta"; diff --git a/conf/config.ini b/conf/config.ini index 84e31c9..79045a6 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -1,4 +1,4 @@ -[com] +[com] #电机控制的串口名 motoPortName=COM3 @@ -17,6 +17,10 @@ maxFaceTryCount=20 #持续没找到人脸的最大次数 maxFaceNotFoundCount=500 +#注册时最小人脸 +minFaceRegist=240 +#识别时最小人脸 +minFaceRecog=100 #虹膜识别最大尝试次数 maxIrisTryCount=10 @@ -34,6 +38,18 @@ #统一背景色 backgroundColor="#FFFFFF" +[work] +#工作状态检测时最小人脸范围 +minFaceSize=160 +#人脸范围最小横坐标 +minFacePosX=320 +#人脸范围最大横坐标 +maxFacePosX=960 +#人脸范围最小纵坐标 +minFacePosY=180 +#人脸范围最大纵坐标 +maxFacePosY=540 + [camera] #人脸摄像头的编号 faceIndex=1 @@ -53,11 +69,3 @@ irisWidth=640 #虹膜图像高度 irisHeight=480 - -[stack] -#拍摄图像栈最大值 -capture=50 -#找到的眼睛图像栈最大值 -found=30 -#质量合格图像栈最大值 -qualified=30 diff --git a/device/FaceCameraController.cpp b/device/FaceCameraController.cpp index 25854c3..0fe4b4c 100644 --- a/device/FaceCameraController.cpp +++ b/device/FaceCameraController.cpp @@ -63,7 +63,7 @@ cv::Mat faceMatDisp = imageMatMiir.clone(); // 利用人脸分类器进行初步的检测 - cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp); + cv::Rect faceRect = casic::face::CasicFaceInterface::getInstance().faceDetectByCVCascade(faceMatDisp, SettingConfig::getInstance().MIN_FACE_REGIST_SIZE); if (faceRect.width > 0) { // 初筛检测到人脸时将图像入栈 diff --git a/device/IrisCameraCapEventHandler.cpp b/device/IrisCameraCapEventHandler.cpp index da744f5..151de09 100644 --- a/device/IrisCameraCapEventHandler.cpp +++ b/device/IrisCameraCapEventHandler.cpp @@ -34,7 +34,7 @@ irisInfo.leftOrRight = "right"; } - if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::MAIN_PAGE) + if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::RECOGNIZE_RESULT_FORM) { // 相机拍摄下的图像1280*960, 直接用于算法判断 QImage imgDisp = QImage(pBuffer, width, height, QImage::Format_Grayscale8); @@ -43,7 +43,6 @@ irisInfo.data = imgDisp; irisInfo.matData = irisMat; - // 识别过程任意一个眼睛都行, 全部存入左眼队列 ProMemory::getInstance().pushCasicIris(irisInfo); } else if (ProMemory::getInstance().widgeFrame == CasicBioRecConst::ADD_PERSON_CAPTURE_IRIS) { diff --git a/device/device.pri b/device/device.pri index 6dc2f3c..64e6e17 100644 --- a/device/device.pri +++ b/device/device.pri @@ -1,24 +1,24 @@ -HEADERS += $$PWD/FaceCameraController.h \ - $$PWD/face/FaceRegistProcess.h -HEADERS += -HEADERS += $$PWD/face/FaceDetectRecogProcess.h +HEADERS += $$PWD/FaceCameraController.h +HEADERS += $$PWD/face/FaceRecogProcess.h +HEADERS += $$PWD/face/FaceRegistProcess.h HEADERS += $$PWD/face/CasicFaceRecState.h -SOURCES += $$PWD/FaceCameraController.cpp \ - $$PWD/face/FaceRegistProcess.cpp -SOURCES += -SOURCES += $$PWD/face/FaceDetectRecogProcess.cpp +SOURCES += $$PWD/FaceCameraController.cpp +SOURCES += $$PWD/face/FaceRecogProcess.cpp +SOURCES += $$PWD/face/FaceRegistProcess.cpp SOURCES += $$PWD/face/CasicFaceRecState.cpp 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/MotoController.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/MotoController.cpp diff --git a/device/face/FaceDetectRecogProcess.cpp b/device/face/FaceDetectRecogProcess.cpp deleted file mode 100644 index d8d6d01..0000000 --- a/device/face/FaceDetectRecogProcess.cpp +++ /dev/null @@ -1,197 +0,0 @@ -#include "FaceDetectRecogProcess.h" - -FaceDetectRecogProcess::FaceDetectRecogProcess(QObject *parent) : QThread(parent) -{ - this->working = false; - this->exit = false; -} - -FaceDetectRecogProcess::~FaceDetectRecogProcess() -{ - this->setWorking(false); -} - -void FaceDetectRecogProcess::setWorking(bool working) -{ - this->working = working; -} -void FaceDetectRecogProcess::exitThread() -{ - this->exit = true; -} -void FaceDetectRecogProcess::startThread() -{ - this->exit = false; - this->start(); -} - -void FaceDetectRecogProcess::addOneTryCount() -{ - LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); - if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) - { - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; - } else - { - CasicFaceRecState::getInstance().tryCount = 0; - CasicFaceRecState::getInstance().noFaceCount = 0; - emit matchFailure(); - - this->setWorking(false); // 返回后则线程暂停工作 - } -} - -void FaceDetectRecogProcess::addOneNoFaceCount() -{ - CasicFaceRecState::getInstance().noFaceCount++; - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; - if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) - { - CasicFaceRecState::getInstance().noFaceCount = 0; - emit matchFailure(); - - this->setWorking(false); // 返回后则暂停工作 - } -} - -void FaceDetectRecogProcess::run() -{ - while (exit == false) - { - if (this->working == false) - { - this->msleep(100); // 100ms后再判断 - continue; - } - - // 图像栈中没有图像则直接返回 - if (ProMemory::getInstance().isFaceQueueEmpty() == true) - { - addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 - LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); - - this->msleep(200); // 200ms后再判断 - continue; - } - - // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 - if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) - { - LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); - this->msleep(200); // 200ms后再判断 - continue; - } - - // 取出人脸图像栈中的一条数据 - CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); - - // 调用人脸检测算法 - faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); - - // 没有找到人脸则返回 - if (faceInfo.hasFace == false) - { - // 表示本次识别结束, 可以开始下一次识别过程 - addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 - LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); - this->msleep(200); // 200ms后再判断 - continue; - } - - // 找到人脸则开始一次识别 - if (CasicFaceRecState::getInstance().recoginzeId == "0") - { - CasicFaceRecState::getInstance().initRecognize(); - } - CasicFaceRecState::getInstance().faceInfo = &faceInfo; - CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 - CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 - - // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 - casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); - faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); - - // 活体检测判断为假脸 - if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) - { - // 表示本次识别结束, 可以开始下一次识别过程 - LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); - - addOneTryCount(); // 判断是否超过次数, 重置识别状态 - this->msleep(200); // 200ms后再判断 - continue; - } - - // 设置识别状态值=通过活体检测 - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; - - // 调用算法提取特征值, 1024个字节的float数组 - faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); - - // 设置识别状态值=特征值提取 - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; - CasicFaceRecState::getInstance().faceInfo = &faceInfo; - - LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); - - // 特征值提取成功的人脸 与人脸库中的人脸进行比较 - compareFaceInCollection(); - } -} - -void FaceDetectRecogProcess::compareFaceInCollection() -{ - ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 - QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); - for (int i = 0; i < faceFeatures.size(); i++) - { - QVariantMap ffMap = faceFeatures.at(i); - - QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); - float ffArr[1024]; - for (int i = 0; i < 1024; i++) - { - QByteArray tempBa; - tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); - ffArr[i] = ByteUtil::binToFloat(tempBa); - } - - float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); - - LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); - if (sim > 0.62) - { - CasicFaceRecState::getInstance().faceInfo->sim = sim; - CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); - CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); - CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; - - // 找到匹配的人脸图像 - this->afterRecogAction(ffMap.value("person_id").toString()); - this->setWorking(false); // 找到匹配的人脸之后停止识别线程工作 - return ; - } - } - - this->addOneTryCount(); -} - -void FaceDetectRecogProcess::afterRecogAction(QString personId) -{ - ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 - - LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); - - // 识别记录存入数据库 - RecognitionRecordDao recDao; - QVariantMap record; - record.insert("person_id", personId); - record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); - record.insert("type", "1"); - record.insert("debug_info", CasicFaceRecState::getInstance().toString()); - recDao.save(record); - - // 发送信号, 在主界面上显示 - emit matchSuccess(personId); -} - diff --git a/device/face/FaceDetectRecogProcess.h b/device/face/FaceDetectRecogProcess.h deleted file mode 100644 index 4ca4e94..0000000 --- a/device/face/FaceDetectRecogProcess.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef FACEDETECTRECOGPROCESS_H -#define FACEDETECTRECOGPROCESS_H - -#include -#include -#include "opencv2/opencv.hpp" - -#include "dao/RecognitionRecordDao.h" - -#include "CasicFaceRecState.h" -#include "casic/ProMemory.h" -#include "casic/face/CasicFaceInterface.h" -#include "utils/UtilInclude.h" - -class FaceDetectRecogProcess : public QThread -{ - Q_OBJECT -public: - explicit FaceDetectRecogProcess(QObject *parent = nullptr); - ~FaceDetectRecogProcess(); - - void setWorking(bool working); - void exitThread(); - void startThread(); - - void addOneTryCount(); - void addOneNoFaceCount(); - -protected: - //QThread的虚函数 - //线程处理函数 - //不能直接调用, 通过start()间接调用 - void run(); - void compareFaceInCollection(); - void afterRecogAction(QString personId); - - volatile bool working; - volatile bool exit; - -signals: - void matchSuccess(QString personId); // 匹配成功 - void matchFailure(); // 匹配失败 - -}; - -#endif // FACEDETECTRECOGPROCESS_H diff --git a/device/face/FaceRecogProcess.cpp b/device/face/FaceRecogProcess.cpp new file mode 100644 index 0000000..0fcd9d9 --- /dev/null +++ b/device/face/FaceRecogProcess.cpp @@ -0,0 +1,201 @@ +#include "FaceRecogProcess.h" + +FaceRecogProcess::FaceRecogProcess(QObject *parent) : QThread(parent) +{ + this->working = false; + this->exit = false; +} + +FaceRecogProcess::~FaceRecogProcess() +{ + this->setWorking(false); +} + +void FaceRecogProcess::setWorking(bool working) +{ + this->working = working; +} +void FaceRecogProcess::exitThread() +{ + this->exit = true; +} +void FaceRecogProcess::startThread() +{ + this->exit = false; + this->start(); +} + +void FaceRecogProcess::addOneTryCount() +{ + LOG(DEBUG) << QString("[addOneTryCount]已尝试次数[%1]").arg(CasicFaceRecState::getInstance().tryCount).toStdString(); + if (CasicFaceRecState::getInstance().tryCount < SettingConfig::getInstance().MAX_FACE_TRY_COUNT) + { + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + } else + { + CasicFaceRecState::getInstance().tryCount = 0; + CasicFaceRecState::getInstance().noFaceCount = 0; + ProMemory::getInstance().clearFaceQueue(); + emit matchFailure(); + + this->setWorking(false); // 返回后则线程暂停工作 + } +} + +void FaceRecogProcess::addOneNoFaceCount() +{ + CasicFaceRecState::getInstance().noFaceCount++; + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_NOT_START; + if (CasicFaceRecState::getInstance().noFaceCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT) + { + CasicFaceRecState::getInstance().noFaceCount = 0; + ProMemory::getInstance().clearFaceQueue(); + emit matchFailure(); + + this->setWorking(false); // 返回后则暂停工作 + } +} + +void FaceRecogProcess::run() +{ + while (exit == false) + { + if (this->working == false) + { + this->msleep(100); // 100ms后再判断 + continue; + } + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isFaceQueueEmpty() == true) + { + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(TRACE) << QString("[CasicFaceRecognize][%1] 人脸图像栈空, 暂停200ms").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + + this->msleep(200); // 200ms后再判断 + continue; + } + + // 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束 + if (CasicFaceRecState::getInstance().state != CasicFaceRecState::FaceRecStateName::REC_NOT_START) + { + LOG(DEBUG) << QString("[CasicFaceRecognize] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicFaceRecState::getInstance().state).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 取出人脸图像栈中的一条数据 + CasicFaceInfo faceInfo = ProMemory::getInstance().popCasicFace(); + + // 调用人脸检测算法 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceDetect(faceInfo.matData); + + // 没有找到人脸则返回 + if (faceInfo.hasFace == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 + addOneNoFaceCount(); // 连续没找到脸的次数+1;注册过程有多调用opencv的分类器, 没有符合要求脸的图像不入栈 + LOG(DEBUG) << QString("[CasicFaceRecognize] 没有找到人脸, 暂停200ms。重置识别状态为REC_NOT_START[%1]").arg(CasicFaceRecState::getInstance().noFaceCount).toStdString(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 找到人脸则开始一次识别 + if (CasicFaceRecState::getInstance().recoginzeId == "0") + { + CasicFaceRecState::getInstance().initRecognize(); + } + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + CasicFaceRecState::getInstance().tryCount++; // 尝试识别次数+1 + CasicFaceRecState::getInstance().noFaceCount = 0; // 找到脸 则将连续没找到脸的次数清零 + + // 开始人脸活体检测, 提高活体检测的阈值到0.3/0.6 + casic::face::CasicFaceInterface::getInstance().setAntiThreshold(0.3, 0.3); + faceInfo = casic::face::CasicFaceInterface::getInstance().faceAntiSpoofing(faceInfo); + + // 活体检测判断为假脸 + if (faceInfo.antiStatus != seeta::FaceAntiSpoofing::Status::REAL) + { + // 表示本次识别结束, 可以开始下一次识别过程 + LOG(DEBUG) << QString("[CasicFaceRecognize] 人脸活体检测未通过, 暂停200ms。[%1]").arg("CasicFaceRecState::getInstance().toString()").toStdString(); + + addOneTryCount(); // 判断是否超过次数, 重置识别状态 + this->msleep(200); // 200ms后再判断 + continue; + } + + // 设置识别状态值=通过活体检测 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_ANTI_SPOOFING; + + // 调用算法提取特征值, 1024个字节的float数组 + faceInfo = casic::face::CasicFaceInterface::getInstance().faceFeatureExtract(faceInfo); + + // 设置识别状态值=特征值提取 + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_FEATURE_EXTRACT; + CasicFaceRecState::getInstance().faceInfo = &faceInfo; + + LOG(DEBUG) << QString("[CasicFaceRecognize] 特征提取成功[%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 特征值提取成功的人脸 与人脸库中的人脸进行比较 + compareFaceInCollection(); + } +} + +void FaceRecogProcess::compareFaceInCollection() +{ + ProMemory::getInstance().clearFaceQueue(); // 特征值提取成功, 开始在库中匹配, 清除人脸图像栈 + QVector faceFeatures = ProMemory::getInstance().getFaceFeatures(); + for (int i = 0; i < faceFeatures.size(); i++) + { + QVariantMap ffMap = faceFeatures.at(i); + + QByteArray ffByteArr = ffMap.value("face_code").toByteArray(); + float ffArr[1024]; + for (int i = 0; i < 1024; i++) + { + QByteArray tempBa; + tempBa.append(ffByteArr.at(i*4)).append(ffByteArr.at(i*4 + 1)).append(ffByteArr.at(i*4 + 2)).append(ffByteArr.at(i*4 + 3)); + ffArr[i] = ByteUtil::binToFloat(tempBa); + } + + float sim = casic::face::CasicFaceInterface::getInstance().faceSimCalculate(CasicFaceRecState::getInstance().faceInfo->feature, ffArr); + + LOG(DEBUG) << QString("[compareFaceInCollection] 特征值比对结果[%1]").arg(sim).toStdString(); + if (sim > 0.62) + { + CasicFaceRecState::getInstance().faceInfo->sim = sim; + CasicFaceRecState::getInstance().timeStampSucc = QDateTime::currentMSecsSinceEpoch(); + CasicFaceRecState::getInstance().recogTimeLast = (float) ((CasicFaceRecState::getInstance().timeStampSucc - CasicFaceRecState::getInstance().timeStamp) / 1000.0); + CasicFaceRecState::getInstance().state = CasicFaceRecState::FaceRecStateName::REC_SEARCH_SUCC; + + // 找到匹配的人脸图像 + // 发送信号, 在主界面上显示 + emit matchSuccess(ffMap.value("person_id").toString(), 1); + +// this->afterRecogAction(ffMap.value("person_id").toString()); + this->setWorking(false); // 找到匹配的人脸之后停止识别线程工作 + return ; + } + } + + this->addOneTryCount(); +} + +void FaceRecogProcess::afterRecogAction(QString personId) +{ + ProMemory::getInstance().clearFaceQueue(); // 清理人脸数据栈 + + LOG(DEBUG) << QString("[FaceDetectRecogProcess] 识别成功 [%1]").arg(CasicFaceRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "1"); + record.insert("debug_info", CasicFaceRecState::getInstance().toString()); + recDao.save(record); + + +} + diff --git a/device/face/FaceRecogProcess.h b/device/face/FaceRecogProcess.h new file mode 100644 index 0000000..c551e23 --- /dev/null +++ b/device/face/FaceRecogProcess.h @@ -0,0 +1,46 @@ +#ifndef FACERECOGPROCESS_H +#define FACERECOGPROCESS_H + +#include +#include +#include "opencv2/opencv.hpp" + +#include "dao/RecognitionRecordDao.h" + +#include "CasicFaceRecState.h" +#include "casic/ProMemory.h" +#include "casic/face/CasicFaceInterface.h" +#include "utils/UtilInclude.h" + +class FaceRecogProcess : public QThread +{ + Q_OBJECT +public: + explicit FaceRecogProcess(QObject *parent = nullptr); + ~FaceRecogProcess(); + + void setWorking(bool working); + void exitThread(); + void startThread(); + + void addOneTryCount(); + void addOneNoFaceCount(); + +protected: + //QThread的虚函数 + //线程处理函数 + //不能直接调用, 通过start()间接调用 + void run(); + void compareFaceInCollection(); + void afterRecogAction(QString personId); + + volatile bool working; + volatile bool exit; + +signals: + void matchSuccess(QString personId, int faceOrIris); // 匹配成功 + void matchFailure(); // 匹配失败 + +}; + +#endif // FACERECOGPROCESS_H diff --git a/device/iris/CasicIrisRecState.cpp b/device/iris/CasicIrisRecState.cpp index 28625a1..d6d01e1 100644 --- a/device/iris/CasicIrisRecState.cpp +++ b/device/iris/CasicIrisRecState.cpp @@ -19,7 +19,7 @@ void CasicIrisRecState::initRecognize() { QDateTime now = QDateTime::currentDateTime(); - this->recoginzeId = now.toString("yyyyMMddHHmmsszzz").toStdString(); + this->recoginzeId = now.toString("yyyyMMddHHmmsszzz"); this->timeStamp = now.toMSecsSinceEpoch(); this->tryCount = 0; this->noEyeCount = 0; @@ -27,9 +27,9 @@ LOG(DEBUG) << QString("[CasicIrisRecState][initRecognize] 虹膜识别状态初始化").toStdString(); } -std::string CasicIrisRecState::toString() +QString CasicIrisRecState::toString() { - return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)).toStdString(); + return QString(QJsonDocument(toJSON()).toJson(QJsonDocument::Compact)); } @@ -37,7 +37,7 @@ { QJsonObject obj; - obj.insert("recoginzeId", QString::fromStdString(recoginzeId)); + obj.insert("recoginzeId", recoginzeId); obj.insert("timestamp", timeStamp); obj.insert("timestampSucc", timeStampSucc); obj.insert("state", state); diff --git a/device/iris/CasicIrisRecState.h b/device/iris/CasicIrisRecState.h index 43bf234..d04b9e4 100644 --- a/device/iris/CasicIrisRecState.h +++ b/device/iris/CasicIrisRecState.h @@ -22,10 +22,10 @@ } void initRecognize(); - std::string toString(); + QString toString(); QJsonObject toJSON(); - std::string recoginzeId; // 识别过程id + QString recoginzeId; // 识别过程id qint64 timeStamp = 0; // 识别开始时间戳 qint64 timeStampSucc = 0; // 识别成功时的时间戳 qint64 findEyeTmLast = 0; // 找眼操作耗时 diff --git a/device/iris/IrisRecogProcess.cpp b/device/iris/IrisRecogProcess.cpp new file mode 100644 index 0000000..52c3826 --- /dev/null +++ b/device/iris/IrisRecogProcess.cpp @@ -0,0 +1,215 @@ +#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; + } + + LOG(DEBUG) << QString("[IrisRecogProcess]虹膜识别线程").toStdString(); + + // 图像栈中没有图像则直接返回 + if (ProMemory::getInstance().isIrisQueueEmpty() == true) + { + LOG(DEBUG) << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms").toStdString(); + 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(); + + this->msleep(200); // 200ms后再判断 + continue; + } + + // 取出虹膜图像栈中的一条数据 + CasicIrisInfo irisInfo = ProMemory::getInstance().popCasicIris(); + + LOG(DEBUG) << QString("[IrisRecogProcess]取出虹膜图像").toStdString(); + + // 调用找眼分类器算法 + casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(360); + irisInfo = casic::iris::CasicIrisInterface::getInstance().findEye(irisInfo); + + // 没有找到眼睛则返回 + if (irisInfo.hasEye == false) + { + // 表示本次识别结束, 可以开始下一次识别过程 + LOG(DEBUG) << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount).toStdString(); + + addOneNoEyeCount(); + this->msleep(200); // 200ms后再判断 + continue; + } + + // 找到眼睛则开始质量评估和编码 + // 调用远程算法进行编码 + 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->leftOrRight = irisInfo.leftOrRight; + 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(); + + LOG(INFO) << QString("算法匹配结果").toStdString() << 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(); + + // 保存图像文件 + 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, 2); +// this->afterRecogAction(personId); + } else if (code.toInt() == -200) + { + // 匹配失败 + LOG(INFO) << QString("匹配失败: ").toStdString() << matchResponse.toStdString(); + + // 匹配失败则尝试次数+1 + addOneTryCount(); + } else if (code.toInt() == -100) + { + // 编码失败 + LOG(INFO) << QString("编码失败: ").toStdString() << matchResponse.toStdString(); + + // 编码失败则尝试次数+1 + addOneTryCount(); + } + } else + { + // 超时返回则尝试次数+1 + addOneTryCount(); + } + } +} + +void IrisRecogProcess::afterRecogAction(QString personId) +{ + ProMemory::getInstance().clearIrisQueue(); // 清理虹膜数据栈 + + this->setWorking(false); + ProMemory::getInstance().irisCam->stopCapture(); + + LOG(DEBUG) << QString("[IrisRecogProcess] 识别成功 [%1]").arg(CasicIrisRecState::getInstance().toString()).toStdString(); + + // 识别记录存入数据库 + RecognitionRecordDao recDao; + QVariantMap record; + record.insert("person_id", personId); + record.insert("date_time", QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")); + record.insert("type", "2"); + record.insert("debug_info", CasicIrisRecState::getInstance().toString()); + recDao.save(record); + + CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START; + + // 发送信号, 在主界面上显示 + emit findMatchedIris(personId, 2); +} + +void IrisRecogProcess::addOneTryCount() +{ + CasicIrisRecState::getInstance().tryCount++; + 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(); + emit failedMatchedIris(); + } +} diff --git a/device/iris/IrisRecogProcess.h b/device/iris/IrisRecogProcess.h new file mode 100644 index 0000000..e256614 --- /dev/null +++ b/device/iris/IrisRecogProcess.h @@ -0,0 +1,47 @@ +#ifndef IRISRECOGPROCESS_H +#define IRISRECOGPROCESS_H + +#include +#include +#include +#include + +#include "casic/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(QString personId); + +signals: + void sendDataToExract(QByteArray data); + + void failedMatchedIris(); + void findMatchedIris(QString personId, int faceOrIris); + +}; + +#endif // IRISRECOGPROCESS_H diff --git a/utils/SettingConfig.cpp b/utils/SettingConfig.cpp index 13976d3..ce43d9f 100644 --- a/utils/SettingConfig.cpp +++ b/utils/SettingConfig.cpp @@ -1,4 +1,4 @@ -#include "SettingConfig.h" +#include "SettingConfig.h" #include SettingConfig::SettingConfig() @@ -29,10 +29,14 @@ MAX_FACE_NOT_FOUND_COUNT = getProperty("recognize", "maxFaceNotFoundCount").toInt(); MAX_IRIS_TRY_COUNT = getProperty("recognize", "maxIrisTryCount").toInt(); MAX_EYE_NOT_FOUND_COUNT = getProperty("recognize", "maxEyeNotFoundCount").toInt(); + MIN_FACE_REGIST_SIZE = getProperty("recognize", "minFaceRegist").toInt(); + MIN_FACE_RECOG_SIZE = getProperty("recognize", "minFaceRecog").toInt(); - MAX_CAPTURE_STACK_SIZE = getProperty("stack", "capture").toInt(); - MAX_FOUND_STACK_SIZE = getProperty("stack", "found").toInt(); - MAX_QUALIFIED_STACK_SIZE = getProperty("stack", "qualified").toInt(); + MIN_WORK_FACE_SIZE = getProperty("work", "minFaceSize").toInt(); + MIN_WORK_FACE_POSX = getProperty("work", "minFacePosX").toInt(); + MAX_WORK_FACE_POSX = getProperty("work", "maxFacePosX").toInt(); + MIN_WORK_FACE_POSY = getProperty("work", "minFacePosY").toInt(); + MAX_WORK_FACE_POSY = getProperty("work", "maxFacePosY").toInt(); PORT_NAME = getProperty("com", "motoPortName").toString(); diff --git a/utils/SettingConfig.h b/utils/SettingConfig.h index f2f8e98..c05b2ec 100644 --- a/utils/SettingConfig.h +++ b/utils/SettingConfig.h @@ -1,4 +1,4 @@ -#ifndef SETTINGCONFIG_H +#ifndef SETTINGCONFIG_H #define SETTINGCONFIG_H #include @@ -49,10 +49,14 @@ int MAX_FACE_NOT_FOUND_COUNT; int MAX_IRIS_TRY_COUNT; int MAX_EYE_NOT_FOUND_COUNT; + int MIN_FACE_REGIST_SIZE; + int MIN_FACE_RECOG_SIZE; - int MAX_CAPTURE_STACK_SIZE; - int MAX_FOUND_STACK_SIZE; - int MAX_QUALIFIED_STACK_SIZE; + int MIN_WORK_FACE_SIZE; + int MIN_WORK_FACE_POSX; + int MAX_WORK_FACE_POSX; + int MIN_WORK_FACE_POSY; + int MAX_WORK_FACE_POSY; QString PORT_NAME;