Переглянути джерело

【功能修改】(黄根)修改预识别流程 & 优化预识别速度及二维码识别速度
【工作量】12h
【评审人】叶长城

huanggen 5 місяців тому
батько
коміт
462bedd201

+ 199 - 8
app/src/main/cpp/paperPreIdentify.cpp

@@ -7,6 +7,8 @@
 #include "jsoncpp/json.h"
 #include "curl/curl.h"
 #include "zbar.h"
+#include <thread>
+#include <future>
 
 extern "C" {
 using namespace std;
@@ -74,6 +76,63 @@ string ZbarDecoder(Mat img, int & nAnchorsToQrCode)
     return result;
 }
 
+bool cpmpareFileName(string & a, string & b)
+{
+    if(a.length() != b.length())
+        return a.length() < b.length();
+    int nRet = strcmp(a.c_str(), b.c_str());
+    return nRet < 0;
+}
+
+string getQrcode(Mat tImg, int nX, int nY)
+{
+    string strRet = "";
+    if(tImg.empty())
+        return strRet;
+    Mat roiMat = tImg(Rect(nX, nY, tImg.cols / 4, tImg.rows / 5));
+    Mat imgGray;
+    cvtColor(roiMat, imgGray, CV_BGR2GRAY);  // 灰度化
+    erode(imgGray, imgGray, Mat());     //图片腐蚀,缩小高亮(白色)区域
+    int nAnchorsToQrCode = 0;
+    strRet = ZbarDecoder(imgGray, nAnchorsToQrCode);
+    return strRet;
+}
+
+void findQrcode(string & strPath, string & strRet)
+{
+//    // 开始时间点
+//    auto start = std::chrono::high_resolution_clock::now();
+    Mat tImg = imread(strPath);
+    vector<shared_future<string>> tFutures;
+    shared_future<string> tFut1 = std::async(launch::async, getQrcode, tImg, 0, 0);
+    shared_future<string> tFut2 = std::async(launch::async, getQrcode, tImg, tImg.cols * 3 / 4, 0);
+    shared_future<string> tFut3 = std::async(launch::async, getQrcode, tImg, tImg.cols * 3 / 4, tImg.rows * 4 / 5);
+    shared_future<string> tFut4 = std::async(launch::async, getQrcode, tImg, 0, tImg.rows * 4 / 5);
+    tFutures.emplace_back(tFut1);
+    tFutures.emplace_back(tFut2);
+    tFutures.emplace_back(tFut3);
+    tFutures.emplace_back(tFut4);
+//    int nFinishedCount = 0;
+//    while(nFinishedCount < 4)
+//    {
+//        nFinishedCount = 0;
+//        for(int i = 0; i < tFutures.size(); i++)
+//            if(tFutures[i].wait_for(chrono::microseconds(100)) == future_status::ready)
+//                nFinishedCount++;
+//    }
+    for(int i = 0; i < tFutures.size(); i++)
+    {
+        tFutures[i].wait();
+        strRet += tFutures[i].get();
+        if(!strRet.empty())
+            break;
+    }
+//    auto finish = std::chrono::high_resolution_clock::now();
+//    // 计算时间差,即执行时间
+//    chrono::duration<double> elapsed = finish - start;
+//    auto deltaTime = elapsed.count();
+}
+
 paperPreIdentify::paperPreIdentify(int nSchoolId)
 {
     m_nSchoolId = nSchoolId;
@@ -91,13 +150,13 @@ PAPERIDENTIFYSTATUS paperPreIdentify::scanPaper(string strImgDir, string strIp)
     m_vPaperPath.clear();
     m_abnPaperMap.clear();
     traverseDir(strImgDir);
-    sort(m_vPaperPath.begin(), m_vPaperPath.end());
+    sort(m_vPaperPath.begin(), m_vPaperPath.end(), cpmpareFileName);
     return preIdentify(m_vPaperPath, strIp);
 }
 
 PAPERIDENTIFYSTATUS paperPreIdentify::scanPaper(std::vector<std::string> papersVec, string strIp)
 {
-    sort(papersVec.begin(), papersVec.end());
+    sort(papersVec.begin(), papersVec.end(), cpmpareFileName);
     return preIdentify(papersVec, strIp);
 }
 
@@ -117,6 +176,23 @@ bool paperPreIdentify::findAnchors(PaperPage sPage)
 
 string paperPreIdentify::readQrCode(PaperPage sPage)
 {
+    string strPath = "";
+    string strRet = "";
+//    auto start = std::chrono::high_resolution_clock::now();
+
+    for(int i = 0; i < 2; i++)
+    {
+        strPath = i == 0 ? sPage.firstPage : sPage.secondPage;
+        findQrcode(strPath, strRet);
+        if(!strRet.empty())
+            break;
+    }
+//    auto finish = std::chrono::high_resolution_clock::now();
+//    // 计算时间差,即执行时间
+//    chrono::duration<double> elapsed = finish - start;
+//    auto deltaTime = elapsed.count();
+    return strRet;
+#if 0
     string strRet;
     for (int i = 0; i < 2; i++)
     {
@@ -154,6 +230,7 @@ string paperPreIdentify::readQrCode(PaperPage sPage)
             break;
     }
     return strRet;
+#endif
 }
 
 void paperPreIdentify::traverseDir(string strImgDir)
@@ -557,16 +634,53 @@ int paperPreIdentify::getBalckAreaCount(Mat& tMat)
 }
 
 PAPERIDENTIFYSTATUS paperPreIdentify::preIdentify(vector<string>& papersVec, string strIp) {
-    vector<PaperPage> tAllPaperList;
     int nPaperSize = papersVec.size();
     if(0 == nPaperSize || nPaperSize % 2 != 0)
         return PAPERNUMODD;
 
-    int nGetTmpFailCount = 0;
-    int nGetQrcodeFailCount = 0;
+    nGetTmpFailCount = 0;
+    nGetQrcodeFailCount = 0;
+    qrCodeCountMap.clear();
+    qrCodeContentMap.clear();
+    tAllPaperList.clear();
+    int nMid = nPaperSize / 2;
+    if(nPaperSize > 10)
+    {
+        nMid = nPaperSize > 20 ? nMid : 10;
+        auto func1 = bind(&paperPreIdentify::identifyPaper, this, 0, nMid, strIp, papersVec);
+        auto func2 = bind(&paperPreIdentify::identifyPaper, this, nMid, nPaperSize, strIp, papersVec);
+        shared_future<int> tFut1 = async(launch::async, func1);
+        shared_future<int> tFut2 = async(launch::async, func2);
+        vector<shared_future<int>> tFutures;
+        tFutures.emplace_back(tFut1);
+        tFutures.emplace_back(tFut2);
+        for(int i = 0; i < 2; i++)
+            tFutures[i].wait();
+        int nRet1 = 3, nRet2 = 3;
+        try{
+            nRet1 = tFut1.get();
+            nRet2 = tFut2.get();
+        }
+        catch (const exception & e) {
+            string strErr = e.what();
+            int i = 0;
+        }
+        if(nRet1 != FINISHPREIDENTIFY)
+            return (PAPERIDENTIFYSTATUS)nRet1;
+        if(nRet2 != FINISHPREIDENTIFY)
+            return (PAPERIDENTIFYSTATUS)nRet2;
+    }
+    else
+    {
+        auto func1 = bind(&paperPreIdentify::identifyPaper, this, 0, nPaperSize, strIp, papersVec);
+        shared_future<int> tFut1 = async(launch::async, func1);
+        tFut1.wait();
+        int nRet = tFut1.get();
+        if(nRet != FINISHPREIDENTIFY)
+            return (PAPERIDENTIFYSTATUS)nRet;
+    }
+#if 0
     string strFirPagePath;
-    map<string, int> qrCodeCountMap;
-    map<string, int> qrCodeContentMap;
     for(int i = 0; i < nPaperSize; i++)
     {
         if(i % 2 == 0)
@@ -622,7 +736,8 @@ PAPERIDENTIFYSTATUS paperPreIdentify::preIdentify(vector<string>& papersVec, str
                     //仅记录能够成功获取模板信息的QrCode
                     if(qrCodeCountMap.size() == 0)
                         qrCodeCountMap[strQRCode] = 2;
-                    qrCodeCountMap[strQRCode] = 1;
+                    else
+                        qrCodeCountMap[strQRCode] = 1;
                 }
             }
             else
@@ -641,6 +756,7 @@ PAPERIDENTIFYSTATUS paperPreIdentify::preIdentify(vector<string>& papersVec, str
             tAllPaperList.push_back(tPage);
         }
     }
+#endif
     auto iter = qrCodeCountMap.begin();
     int nMaxCount;
     string strMaxCountQr = "";
@@ -682,6 +798,81 @@ PAPERIDENTIFYSTATUS paperPreIdentify::preIdentify(vector<string>& papersVec, str
     return FINISHPREIDENTIFY;
 }
 
+int paperPreIdentify::identifyPaper(int nBegin, int nEnd, string strIp, vector<string>& papersVec)
+{
+    string strFirPagePath;
+    for(int i = nBegin; i < nEnd; i++)
+    {
+        if(i % 2 == 0)
+        {
+            strFirPagePath = papersVec.at(i);
+        }
+        else
+        {
+            PaperPage tPage;
+            tPage.firstPage = strFirPagePath;
+            tPage.secondPage = papersVec.at(i);
+            string strQRCode = readQrCode(tPage);
+            if(strQRCode.empty())
+            {
+                //获取模板失败答题卡计数
+                if(i + 1 <= 10)
+                    nGetQrcodeFailCount++;
+                if(nGetQrcodeFailCount == 5 && nEnd >= 10 || nGetQrcodeFailCount == nEnd / 2)
+                    return GETQRCODEFAILED;
+                //当扫描的这一批答题卡同时存在二维码无法识别和二维码无法找到模板信息时,弹窗提示二维码找不到模板信息
+                if(nGetTmpFailCount + nGetQrcodeFailCount == 5 && nEnd >= 10 || nGetTmpFailCount + nGetQrcodeFailCount == nEnd / 2)
+                    return GETTEMPLATEFAILED;
+                tPage.ePaperStatus = PAPER_CANNOTREADQRCODE;
+                tAllPaperList.push_back(tPage);
+                continue;
+            }
+            else if(i + 1 <= 10)
+                qrCodeContentMap[strQRCode] = 1;
+            tPage.qrCode = strQRCode;
 
+            //前五份之内存在如果存在试卷夹带,中止扫描
+            if(i + 1 <= 10 && qrCodeContentMap.size() > 1)
+                return PAPERDOPING;
+
+            if(qrCodeCountMap.count(strQRCode) == 0)
+            {
+                //二维码能正确识别则根据识别出的答题卡ID获取模板信息
+                bool bGetTempSucceful = getCardTemplate(strQRCode, strIp);
+                if(!bGetTempSucceful)
+                {
+                    //获取模板失败答题卡计数
+                    if(i + 1 <= 10)
+                        nGetTmpFailCount++;
+                    //当扫描的这一批答题卡同时存在二维码无法识别和二维码无法找到模板信息时,弹窗提示二维码找不到模板信息
+                    if(nGetTmpFailCount + nGetQrcodeFailCount == 5 && nEnd >= 10 || nGetTmpFailCount + nGetQrcodeFailCount == nEnd / 2)
+                        return GETTEMPLATEFAILED;
+                    tPage.ePaperStatus = PAPER_INVALIDQRCODE;
+                    tAllPaperList.push_back(tPage);
+                    continue;
+                }
+                else
+                {
+                    if(nBegin == 0)
+                    {
+                        //仅记录能够成功获取模板信息的QrCode
+                        if(qrCodeCountMap.size() == 0)
+                            qrCodeCountMap[strQRCode] = 2;
+                        else
+                            qrCodeCountMap[strQRCode] = 1;
+                    }
+                }
+            }
+            else
+            {
+                //计数加1
+                if(nBegin == 0 && qrCodeCountMap.size() == 1)
+                    qrCodeCountMap[strQRCode]++;
+            }
+            tAllPaperList.push_back(tPage);
+        }
+    }
+    return FINISHPREIDENTIFY;
+}
 
 

+ 6 - 0
app/src/main/cpp/paperPreIdentify.h

@@ -112,15 +112,21 @@ private:
     void scaleSchemeParam(const SchemeParam& default_schema_const_param,
                           SchemeParam& schema_param, double scale);                                 //调整图像系数
     int getBalckAreaCount(Mat& tMat);                                                               //统计图像区域黑色点数量
+    int identifyPaper(int nBegin, int nEnd, std::string strIp, std::vector<std::string>& papersVec);
 
 private:
     int m_nAnchorsToQrCode;                                                                         //定位点离二维码左上角点的像素距离(y轴方向)
     int m_nSchoolId;                                                                                //学校ID
+    std::atomic<int> nGetTmpFailCount;
+    std::atomic<int> nGetQrcodeFailCount;
     std::string m_sCardId;                                                                          //答题卡ID
     SchemeParam m_SchemeParam;
     SchemeParam m_DefaultSchemeParam;
     std::vector<std::string> m_vPaperPath;                                                          //图片路径
     std::map<PaperAbnormalType, std::vector<PaperPage>> m_abnPaperMap;                              //记录所有异常类型答题卡
+    std::map<std::string, int> qrCodeCountMap;
+    std::map<std::string, int> qrCodeContentMap;
+    std::vector<PaperPage> tAllPaperList;
 };