Newer
Older
CasicIrisIdentify / device / iris / IrisRecogProcess.cpp
#ifdef _MSC_VER
#pragma execution_character_set("utf-8")    // Qt VS 中文兼容(UTF-8)
#endif

#include "IrisRecogProcess.h"

IrisRecogProcess::IrisRecogProcess(QObject *parent) : QThread(parent)
{
    this->working = false;
    this->exit = false;

    // 连接算法服务
    clientUtil = new SocketClientUtil(this);
    clientUtil->connect("192.168.83.223", 50007);

    // 调用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(THREAD_MSLEEP); // 200ms后再判断
            continue;
        }

        // 1. 图像栈中没有图像则直接返回
        if (ProMemory::getInstance().isIrisQueueEmpty() == true)
        {
            qDebug() << QString("[IrisRecogProcess] 虹膜图像栈空, 暂停200ms");
            this->msleep(THREAD_MSLEEP); // 200ms后再判断
            continue;
        }

        // 2. 识别状态不等于未开始, 表示已经进入识别程序了, 后续不再执行, 等待本次识别过程结束
        if (CasicIrisRecState::getInstance().state != CasicIrisRecState::IrisRecStateName::REC_NOT_START)
        {
            qDebug() << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state);
            this->msleep(THREAD_MSLEEP); // 200ms后再判断
            continue;
        }

        // 3. 取出虹膜图像栈中的一条数据
        CasicIrisInfo irisInfo = ProMemory::getInstance().popCasicIris();

        // 4. 调用找眼分类器算法
        casic::iris::CasicIrisInterface::getInstance().setMinEyeSize(SettingConfig::getInstance().MIN_EYE_SIZE);
        irisInfo = casic::iris::CasicIrisInterface::getInstance().findAndCutEye(irisInfo);

        // 4.1 没有找到眼睛则返回
        if (irisInfo.hasEye == false)
        {
            // 表示本次识别结束, 可以开始下一次识别过程
            qDebug() << QString("[IrisRecogProcess] 分类器没有找到眼睛,暂停200ms[%1]").arg(CasicIrisRecState::getInstance().noEyeCount);

            addOneNoEyeCount();
            this->msleep(THREAD_MSLEEP); // 200ms后再判断
            continue;
        }

        // 4.2 找到眼睛则开始识别

        // 发送信号更新界面
        emit startIdentifyIris();

        // 调用远程算法进行编码
        if (CasicIrisRecState::getInstance().recoginzeId == "0")
        {
            // 第一次找到眼则 虹膜识别状态初始化
            CasicIrisRecState::getInstance().initRecognize();
        }

        CasicIrisRecState::getInstance().noEyeCount = 0; // 持续未找到眼的次数清零
        CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FIND_EYE;

        QElapsedTimer timer;
        timer.start();

        // 进行预处理 转换成 320 * 240 的三通道图像 送去压缩
        cv::Mat segMat;

        // 图像转换为RGB的彩色图像
        cv::cvtColor(irisInfo.matData, segMat, cv::COLOR_GRAY2RGB);

        // 缩放到320 * 240
        cv::resize(segMat, segMat, cv::Size(SettingConfig::getInstance().IRIS_WIDTH * 0.5, SettingConfig::getInstance().IRIS_HEIGHT * 0.5));

        //        std::string filename = QString("%1\\%2\\%3-seg.bmp").arg("d:\\irisLogs").arg(QDate::currentDate().toString("yyyyMMdd")).arg(QTime::currentTime().toString("HHmmss")).toStdString();
        //        cv::imwrite(filename, segMat);
        //        irisInfo = casic::iris::CasicIrisInterface::getInstance().irisPreProcess(irisInfo);

        QByteArray data((char*)segMat.data, SettingConfig::getInstance().IRIS_WIDTH * 0.5 * SettingConfig::getInstance().IRIS_HEIGHT * 0.5 * 3);

        // 发送TCP消息去匹配
        emit sendDataToExract(data);

        // 等待接收算法返回的结果
        QTimer toTimer;
        QEventLoop loop;
        toTimer.singleShot(3000, &loop, &QEventLoop::quit); // 等待3秒后退出等待
        connect(clientUtil, &SocketClientUtil::responseReaded, &loop, &QEventLoop::quit);
        loop.exec();

        if (clientUtil->getResponse().size() < SettingConfig::getInstance().IRIS_WIDTH * 0.5 * SettingConfig::getInstance().IRIS_HEIGHT * 0.5 * 3) {
            addOneTryCount();
            qDebug() << QString("算法分割图像失败,暂停200ms[%1 ms]").arg(timer.elapsed());
            this->msleep(THREAD_MSLEEP); // 200ms后再判断
            continue;
        }

        char recvPupil[320 * 240 * 1];
        char recvMask[320 * 240 * 1];
        char recvIris[320 * 240 * 1];
        memset(recvPupil, 0, sizeof(recvPupil));
        memset(recvMask, 0, sizeof(recvMask));
        memset(recvIris, 0, sizeof(recvIris));
        for (int i = 0; i < clientUtil->getResponse().size(); i++) {
            if (i < 320 * 240)
                recvPupil[i] = clientUtil->getResponse().at(i);
            else if (i >= 320 * 240 && i < 2 * 320 * 240)
                recvMask[i - 320 * 240] = clientUtil->getResponse().at(i);
            else
                recvIris[i - 2 * 320 * 240] = clientUtil->getResponse().at(i);
        }

        // 成功接收后清除缓存区
        clientUtil->resetRecvBuffer();

        cv::Mat pupil(240, 320, CV_8UC1, recvPupil);
        cv::Mat mask(240, 320, CV_8UC1, recvMask);
        cv::Mat iris(240, 320, CV_8UC1, recvIris);
        irisInfo.segResult.innerMask = pupil;
        irisInfo.segResult.irisMask = mask;
        irisInfo.segResult.outerCircle = iris;
        /*
        std::string pupilSeg = QString("%1\\%2\\%3-pupil-seg.bmp").arg("d:\\irisLogs").arg(QDate::currentDate().toString("yyyyMMdd")).arg(QTime::currentTime().toString("HHmmss")).toStdString();
        std::string maskSeg = QString("%1\\%2\\%3-mask-seg.bmp").arg("d:\\irisLogs").arg(QDate::currentDate().toString("yyyyMMdd")).arg(QTime::currentTime().toString("HHmmss")).toStdString();
        std::string irisSeg = QString("%1\\%2\\%3-iris-seg.bmp").arg("d:\\irisLogs").arg(QDate::currentDate().toString("yyyyMMdd")).arg(QTime::currentTime().toString("HHmmss")).toStdString();
        cv::imwrite(pupilSeg, pupil);
        cv::imwrite(maskSeg, mask);
        cv::imwrite(irisSeg, iris);
*/
        qDebug() << QString("算法分割图像成功[%1 ms]").arg(timer.elapsed());

        // 分割后的后处理
        if (cv::countNonZero(mask) == 0  ||  cv::countNonZero(pupil) == 0|| cv::countNonZero(iris) == 0)
        {
            qDebug() << "算法分割图像失败,暂停200ms";

            addOneTryCount();
            this->msleep(THREAD_MSLEEP); // 200ms后再判断
            continue;
        }

        // 状态修改为特征提取
        CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FEATURE_EXTRACT;

        timer.restart();
        irisInfo = casic::iris::CasicIrisInterface::getInstance().irisEncode(irisInfo);

        std::string codeFilename = QString("%1\\%2\\%3-code.bmp").arg("d:\\irisLogs").arg(QDate::currentDate().toString("yyyyMMdd")).arg(QTime::currentTime().toString("HHmmss")).toStdString();
        std::string maskFilename = QString("%1\\%2\\%3-mask.bmp").arg("d:\\irisLogs").arg(QDate::currentDate().toString("yyyyMMdd")).arg(QTime::currentTime().toString("HHmmss")).toStdString();
        cv::imwrite(codeFilename, irisInfo.irisCode);
        cv::imwrite(maskFilename, irisInfo.maskNorm);

        qDebug() << QString("虹膜图像编码成功[%1 ms]").arg(timer.elapsed());

        // 开始匹配
        for (int i = 0; i < ProMemory::getInstance().getIrisFeatures().size(); i++)
        {
            CasicIrisFeature feature = ProMemory::getInstance().getIrisFeatures().at(i);
            float score = casic::iris::CasicIrisInterface::getInstance().calculateMatchScore(feature, irisInfo);
            //            SpeakerUtil::getInstance().speak(QString::number(score));
            cv::imwrite(QString("%1\\%2\\%3-%4.bmp").arg("d:\\irisLogs").arg(QDate::currentDate().toString("yyyyMMdd")).arg(QTime::currentTime().toString("HHmmss")).arg(score).toStdString(), irisInfo.matData);
            if (score <= 0.32) {
                CasicIrisRecState::getInstance().state = CasicIrisRecState::REC_SEARCH_SUCC;
                CasicIrisRecState::getInstance().matchedId = feature.personId;
                break ;
            }
        }

        if (CasicIrisRecState::getInstance().state == CasicIrisRecState::REC_SEARCH_SUCC) {
            // 找到匹配结果
            emit findMatchedIris(CasicIrisRecState::getInstance().matchedId);

            ProMemory::getInstance().irisCam->stopCapture();
            ProMemory::getInstance().clearIrisQueue();
            this->setWorking(false);
        } else {
            // 没有匹配上
            addOneTryCount();
        }
    }
}

void IrisRecogProcess::afterRecogAction()
{
    this->setWorking(false);

    ProMemory::getInstance().clearIrisQueue(); // 清理虹膜数据栈
}

void IrisRecogProcess::addOneTryCount()
{
    CasicIrisRecState::getInstance().tryCount++;
//    LOG(DEBUG) << QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString();
//    LOG_DEBUG(QString("[CasicIrisRecogProcess]已尝试次数[%1]").arg(CasicIrisRecState::getInstance().tryCount).toStdString());

    CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START;
    if (CasicIrisRecState::getInstance().tryCount >= SettingConfig::getInstance().MAX_IRIS_TRY_COUNT)
    {
        CasicIrisRecState::getInstance().noEyeCount = 0;
        CasicIrisRecState::getInstance().tryCount = 0;

        this->setWorking(false);
        ProMemory::getInstance().irisCam->stopCapture();
        ProMemory::getInstance().clearIrisQueue();

        emit failedMatchedIris();
    }
}
void IrisRecogProcess::addOneNoEyeCount()
{
    if (ProMemory::getInstance().appState == AppConstants::ApplicationState::STATE_IDENTIFYING)
    {
        CasicIrisRecState::getInstance().noEyeCount++;

        // 如果在识别中 则超过一定次数后返回识别失败
        if (CasicIrisRecState::getInstance().noEyeCount >= SettingConfig::getInstance().MAX_EYE_NOT_FOUND_COUNT)
        {
            // 发送信号识别失败
            emit failedMatchedIris();

            CasicIrisRecState::getInstance().noEyeCount = 0;

            // 识别失败时暂停工作 待返回识别界面时再开始工作和拍图
            this->setWorking(false);
            ProMemory::getInstance().irisCam->stopCapture();
            ProMemory::getInstance().clearIrisQueue();
        }
    } else if (ProMemory::getInstance().appState == AppConstants::ApplicationState::STATE_WORKING)
    {
        CasicIrisRecState::getInstance().noEyeCount++;

        // 如果在工作状态 则超过一定次数后返回待机
        if (CasicIrisRecState::getInstance().noEyeCount >= SettingConfig::getInstance().MAX_FACE_NOT_FOUND_COUNT)
        {
            // 发送信号待机
            emit backToLockScreen();

            CasicIrisRecState::getInstance().noEyeCount = 0;

            // 待机界面还在拍图和工作
            ProMemory::getInstance().clearIrisQueue();
        }
    } else {
        // 待机界面 不做处理 等待找到眼
    }
}