Newer
Older
CasicIrisIdentify / device / iris / IrisRecogProcess.cpp
TAN YUE on 15 Nov 2023 12 KB 20231115 识别调试
#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(200); // 200ms后再判断
            continue;
        }

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

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

            qDebug() << QString("[IrisRecogProcess] 已在一次识别过程中, 暂停200ms。当前状态为: %1").arg(CasicIrisRecState::getInstance().state);
            this->msleep(200); // 200ms后再判断
            continue;
        }

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

//        LOG(DEBUG) << QString("[IrisRecogProcess] 取出虹膜图像").toStdString();
//        LOG_DEBUG(QString("[IrisRecogProcess] 取出虹膜图像").toStdString());
        qDebug() << QString("[IrisRecogProcess] 取出虹膜图像");

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

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

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

//        LOG(DEBUG) << QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString();
//        LOG_DEBUG(QString("[IrisRecogProcess] 找到眼睛调用远程算法进行识别").toStdString());

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

        CasicIrisRecState::getInstance().noEyeCount = 0; // 持续未找到眼的次数清零
        CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_FIND_EYE;
//        CasicIrisRecState::getInstance().irisInfo->hasEye = irisInfo.hasEye;
//        CasicIrisRecState::getInstance().irisInfo->eyeRect = irisInfo.eyeRect;
//        CasicIrisRecState::getInstance().irisInfo->matData = irisInfo.matData;
//        CasicIrisRecState::getInstance().irisInfo->data = ImageUtil::MatImageToQImage(irisInfo.matData);

//        irisInfo.matData = cv::imread("d:\\irisLogs\\photo\\left.bmp", 0);

        QElapsedTimer timer;
        timer.start();

        // 进行预处理 如图像
        irisInfo = casic::iris::CasicIrisInterface::getInstance().irisPreProcess(irisInfo);

        QByteArray data((char*)irisInfo.matData.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();

        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);
        }

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

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

        timer.restart();
        qDebug() << "开始提取特征";
        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);
            qDebug() << score;
            if (score <= 0.32) {
                // 找到匹配结果
                emit findMatchedIris(feature.personId);

                break;
            }
        }

        // 没有匹配上
        addOneTryCount();

//        QByteArray matchResponse;
//        LOG(INFO) << QString("算法匹配结果").toStdString() << matchResponse.toStdString();
//        LOG_INFO("算法匹配结果 {}",matchResponse.toStdString());
/*
        // 算法调用返回成功
        if (matchResponse.size() > 0)
        {
            QString response = matchResponse.mid(5, matchResponse.size() - 6);
            QStringList messList = response.split(";");
            QString code = messList.at(0);
            if (code.toInt() == 0)
            {
                QString personId = messList.at(1);
                CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_SEARCH_SUCC;

//                LOG(INFO) << QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString();
//                LOG_INFO(QString("匹配成功[tm: %1 ms][id: %2]").arg(timer.elapsed()).arg(personId).toStdString());

                // 保存图像文件
//                cv::imwrite(QString("D:\\irisLogs\\%1-%2.bmp").arg(QDateTime::currentDateTime().toString("HHmmsszzz")).arg(irisInfo.leftOrRight).toStdString(), irisInfo.matData);

                CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START;
                emit findMatchedIris(personId);
                this->afterRecogAction();
            } else if (code.toInt() == -200)
            {
                // 匹配失败
//                LOG(INFO) << QString("匹配失败: ").toStdString() << matchResponse.toStdString();
//                LOG_INFO("匹配失败: {}", matchResponse.toStdString());

                // 匹配失败则尝试次数+1
                addOneTryCount();
            } else if (code.toInt() == -100)
            {
                // 编码失败
//                LOG(INFO) << QString("编码失败: ").toStdString() << matchResponse.toStdString();
//                LOG_INFO("编码失败: {}", matchResponse.toStdString());
                // 编码失败则尝试次数+1
                addOneTryCount();
            }
        } else
        {
            // 超时返回则尝试次数+1
            addOneTryCount();
        }*/
    }
}

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

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

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

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

        this->setWorking(false);
//        ProMemory::getInstance().irisCam->stopCapture();
        ProMemory::getInstance().clearIrisQueue();
        emit failedMatchedIris();
    }
}
void IrisRecogProcess::addOneNoEyeCount()
{
    CasicIrisRecState::getInstance().noEyeCount++;
    CasicIrisRecState::getInstance().state = CasicIrisRecState::IrisRecStateName::REC_NOT_START;
    if (CasicIrisRecState::getInstance().noEyeCount >= SettingConfig::getInstance().MAX_EYE_NOT_FOUND_COUNT)
    {
        CasicIrisRecState::getInstance().noEyeCount = 0;

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

//        if (qrand() % 10 < 5) {
            emit failedMatchedIris();
//        }
//        else {
//            emit findMatchedIris("1");
//        }
    }
}