From 6da5477823a35f37dac1662a39858dc601b66a27 Mon Sep 17 00:00:00 2001 From: liusiyang Date: Mon, 22 Jun 2026 16:00:37 +0800 Subject: [PATCH] =?UTF-8?q?feat=20=E5=88=9D=E6=AD=A5=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E4=BC=A0=E7=BB=9F=E6=A3=80=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AlgorithmModule/include/ImgCheckAnalysisy.hpp | 4 + AlgorithmModule/src/ImgCheckAnalysisy.cpp | 108 +++++++++++++++++- ConfigModule/include/CheckConfigDefine.h | 4 + ConfigModule/src/JsonConfig.cpp | 1 + 4 files changed, 112 insertions(+), 5 deletions(-) diff --git a/AlgorithmModule/include/ImgCheckAnalysisy.hpp b/AlgorithmModule/include/ImgCheckAnalysisy.hpp index c501e6b..a4f754d 100644 --- a/AlgorithmModule/include/ImgCheckAnalysisy.hpp +++ b/AlgorithmModule/include/ImgCheckAnalysisy.hpp @@ -163,8 +163,12 @@ private: int ConfigCheck(cv::Mat img); // 多线程方式处理 int AI_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg); + // 传统检测 + int Traditional_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg); // 缺陷分类 int AI_QX_Class_Thread(); + // 传统分类 + int Traditional_QX_Class_Thread(); // 多线程 任务运行管理器 int ThreadTask(int nId); // 运行; diff --git a/AlgorithmModule/src/ImgCheckAnalysisy.cpp b/AlgorithmModule/src/ImgCheckAnalysisy.cpp index 52eecbf..5d41fb7 100644 --- a/AlgorithmModule/src/ImgCheckAnalysisy.cpp +++ b/AlgorithmModule/src/ImgCheckAnalysisy.cpp @@ -678,7 +678,7 @@ int ImgCheckAnalysisy::CheckRun() { m_pImageAllResult->detImg = image(m_CutRoi).clone(); } - // 多线程开启 AI 推理检测 + // 多线程开启 传统/AI 推理检测 long time_AI_s = CheckUtil::getcurTime(); m_AItask = std::make_shared(); m_AItask->taskname = Task_AI; @@ -1294,6 +1294,40 @@ int ImgCheckAnalysisy::AIMaskDet() m_ImgBlobHFlagData = new unsigned char[m_pImageAllResult->detImg.rows]; memset(m_ImgBlobHFlagData, 0, sizeof(unsigned char) * m_pImageAllResult->detImg.rows); + // 传统检测路径:等待异步任务完成后,计算HFlag + if(m_pBasicConfig->bTraditionalDetect) + { + m_AItask->waitComplate(); + int rec = m_AItask->nresult; + if (rec != CHECK_OK) + { + return rec; + } + if (!m_pImageAllResult->AIMaskImg.empty()) + { + unsigned char *pGrayErrordata = (unsigned char *)m_pImageAllResult->AIMaskImg.data; + int width = m_pImageAllResult->AIMaskImg.cols; + int height = m_pImageAllResult->AIMaskImg.rows; + for (int y = 0; y < height; y++) + { + if (m_ImgBlobHFlagData[y] == 0) + { + unsigned char *p = pGrayErrordata + y * width; + for (int x = 0; x < width; x++) + { + if (p[x] != 0) + { + m_ImgBlobHFlagData[y] = 1; + break; + } + } + } + } + } + m_CheckResult_shareP->resultMaskImg = m_pImageAllResult->AIMaskImg; + return 0; + } + while (true) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); @@ -1577,6 +1611,25 @@ int ImgCheckAnalysisy::AI_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg) return 0; } +// ======================== 传统检测 ======================== +int ImgCheckAnalysisy::Traditional_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg) +{ + std::string strBaseLog = "Traditional_Detect"; + m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "Traditional_Detect Start (placeholder)"); + + // 输出与AI推理相同格式的二值mask图 (CV_8UC1) + ResultImg = cv::Mat::zeros(img.size(), CV_8UC1); + + // ===== TODO: 在此处调用传统检测算法库 ===== + // 示例:cv::threshold(img, ResultImg, 128, 255, cv::THRESH_BINARY); + // 输入: img (单通道灰度图, CV_8UC1) + // 输出: ResultImg (二值mask, CV_8UC1, 0/255) + // ========================================== + + m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "Traditional_Detect End (placeholder)"); + return 0; +} + int ImgCheckAnalysisy::AI_QX_Class_Thread() { @@ -1742,6 +1795,35 @@ int ImgCheckAnalysisy::AI_QX_Class_Thread() return 0; } +// ======================== 传统分类 ======================== +int ImgCheckAnalysisy::Traditional_QX_Class_Thread() +{ + m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Traditional_Class", " Start (placeholder)"); + + int totalTasks = blobs.blobCount; + for (int i = 0; i < totalTasks; i++) + { + ERROR_DOTS_BLOB_DATA *pblob = &blobs.blobTab[i]; + + if (pblob->ErrType == ERR_TYPE_2) + { + pblob->AIclasstype = CONFIG_QX_NAME_cell_ymhs; + } + else + { + // ===== TODO: 在此处调用传统分类算法库 ===== + // 输入: pblob->minx/maxy/miny/maxy 定位的blob区域 + // m_pImageAllResult->detImg 原始检测图 + // 输出: pblob->AIclasstype (CONFIG_QX_NAME_cell_xxx) + // ========================================== + pblob->AIclasstype = CONFIG_QX_NAME_cell_other; + } + } + + m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Traditional_Class", " End (placeholder), classified %d blobs", totalTasks); + return 0; +} + int ImgCheckAnalysisy::ThreadTask(int nId) { @@ -1791,11 +1873,19 @@ void ImgCheckAnalysisy::TaskFun_AIDet(std::shared_ptr task) { task->SetStatus(TaskStep_run); long t1, t2; - // AI 推理生成 + // 检测:传统检测 / AI推理 { t1 = CheckUtil::getcurTime(); - int rec = AI_Detect_Thread(m_pImageAllResult->detImg, m_pImageAllResult->AIMaskImg); + int rec; + if(m_pBasicConfig->bTraditionalDetect) + { + rec = Traditional_Detect_Thread(m_pImageAllResult->detImg, m_pImageAllResult->AIMaskImg); + } + else + { + rec = AI_Detect_Thread(m_pImageAllResult->detImg, m_pImageAllResult->AIMaskImg); + } t2 = CheckUtil::getcurTime(); task->nresult = rec; @@ -1807,11 +1897,19 @@ void ImgCheckAnalysisy::TaskFun_QxClass(std::shared_ptr task) { task->SetStatus(TaskStep_run); long t1, t2; - // AI 推理生成 + // 缺陷分类:传统检测 / AI推理 { t1 = CheckUtil::getcurTime(); - int rec = AI_QX_Class_Thread(); + int rec; + if(m_pBasicConfig->bTraditionalDetect) + { + rec = Traditional_QX_Class_Thread(); + } + else + { + rec = AI_QX_Class_Thread(); + } t2 = CheckUtil::getcurTime(); task->nresult = rec; diff --git a/ConfigModule/include/CheckConfigDefine.h b/ConfigModule/include/CheckConfigDefine.h index 101e428..f14b459 100644 --- a/ConfigModule/include/CheckConfigDefine.h +++ b/ConfigModule/include/CheckConfigDefine.h @@ -407,6 +407,7 @@ struct BasicConfig float Product_Size_Height_mm; // 产品尺寸 高度 mm float fImage_Scale_x; // 成像精度 float fImage_Scale_y; // 成像精度 + bool bTraditionalDetect; // 使用传统算法检测 std::string strCamName; // float density_R_mm; // 密度计算半径 像素 @@ -427,6 +428,7 @@ struct BasicConfig Product_Size_Height_mm = 1000; fImage_Scale_x = 0.03; fImage_Scale_y = 0.03; + bTraditionalDetect = false; density_R_mm = 5; strCamName = ""; strCamearName = EMPTY_CONFIG_NAME; @@ -450,6 +452,7 @@ struct BasicConfig this->Product_Size_Height_mm = tem.Product_Size_Height_mm; this->fImage_Scale_x = tem.fImage_Scale_x; this->fImage_Scale_y = tem.fImage_Scale_y; + this->bTraditionalDetect = tem.bTraditionalDetect; this->density_R_mm = tem.density_R_mm; this->strCamearName = tem.strCamearName; } @@ -458,6 +461,7 @@ struct BasicConfig printf("============================↓↓↓↓↓↓%s↓↓ %s ↓↓↓↓↓=========================\n", str.c_str(), strCamearName.c_str()); printf("bCal_ImageScale %d Product_Size_Width =%f Product_Size_Height =%f \n", bCal_ImageScale, Product_Size_Width_mm, Product_Size_Height_mm); printf("fImage_Scale_x =%f fImage_Scale_y=%f \n", fImage_Scale_x, fImage_Scale_y); + printf("bTraditionalDetect %d density_R_mm=%f \n", bTraditionalDetect, density_R_mm); // printf("height_min =%d height_max=%d \n", height_min, height_max); printf("bDrawShieldRoi %d bShield_ZF %d DrawPreRoi %d fUP_IOU %f density_R_mm %f\n", bDrawShieldRoi, bShield_ZF, bDrawPreRoi, fUP_IOU, density_R_mm); printf("============================↑↑↑↑↑↑%s↑↑↑↑↑↑=========================\n", str.c_str()); diff --git a/ConfigModule/src/JsonConfig.cpp b/ConfigModule/src/JsonConfig.cpp index c296c79..8c7ccd3 100644 --- a/ConfigModule/src/JsonConfig.cpp +++ b/ConfigModule/src/JsonConfig.cpp @@ -57,6 +57,7 @@ void CommonParamToCheckConfigJson::toObjectFromValue(Json::Value root) _config.baseConfig.Product_Size_Height_mm = value["Product_Size_H"].asFloat(); _config.baseConfig.fImage_Scale_x = value["Image_Scale_X"].asFloat(); _config.baseConfig.fImage_Scale_y = value["Image_Scale_Y"].asFloat(); + _config.baseConfig.bTraditionalDetect = value["bTraditionalDetect"].asFloat(); if (value["Density_R"]) { _config.baseConfig.density_R_mm = value["Density_R"].asFloat();