From 1a1edf84751f532e28f99397389d6ccaafea5426 Mon Sep 17 00:00:00 2001 From: liusiyang Date: Tue, 25 Aug 2026 15:10:18 +0800 Subject: [PATCH] =?UTF-8?q?feat=20=E4=BC=A0=E7=BB=9F=E6=A3=80=E6=B5=8B?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E6=B7=BB=E5=8A=A0AI=E7=BB=93=E6=9E=9C?= =?UTF-8?q?=E5=AD=98=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AlgorithmModule/include/ImageAllResult.h | 2 + AlgorithmModule/include/ImgCheckAnalysisy.hpp | 6 +- AlgorithmModule/src/CameraCheckAnalysisy.cpp | 2 +- AlgorithmModule/src/ImgCheckAnalysisy.cpp | 80 ++++++++++++++++++- ConfigModule/include/CheckConfigDefine.h | 11 ++- ConfigModule/src/JsonConfig.cpp | 4 + 6 files changed, 98 insertions(+), 7 deletions(-) diff --git a/AlgorithmModule/include/ImageAllResult.h b/AlgorithmModule/include/ImageAllResult.h index a6e59b2..638518f 100644 --- a/AlgorithmModule/include/ImageAllResult.h +++ b/AlgorithmModule/include/ImageAllResult.h @@ -64,6 +64,8 @@ public: cv::Mat detImg; // AI 推理的mask图片 cv::Mat AIMaskImg; + // AI 推理的mask图片(传统检测开启时,AI 与传统并行检测,AI 结果存于此,不参与最终 NG 判定) + cv::Mat AIDetMaskImg; // 结果图片 cv::Mat resultImg; diff --git a/AlgorithmModule/include/ImgCheckAnalysisy.hpp b/AlgorithmModule/include/ImgCheckAnalysisy.hpp index 834b9e9..bf923da 100644 --- a/AlgorithmModule/include/ImgCheckAnalysisy.hpp +++ b/AlgorithmModule/include/ImgCheckAnalysisy.hpp @@ -163,7 +163,7 @@ private: // 参数 核对 int ConfigCheck(cv::Mat img); // 多线程方式处理 - int AI_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg); + int AI_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg, bool bPushBlobQueue = true); // 传统检测 int Traditional_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg); // 缺陷分类 @@ -181,6 +181,9 @@ private: // 缺陷分类任务函数 void TaskFun_QxClass(std::shared_ptr task); + // 保存 AI 检测结果(并行模式下,用于模型优化) + int SaveAIDetResult(); + // 更新 检测区域 int Update_DetRoiList(); @@ -271,6 +274,7 @@ private: std::string m_strRootPath_TA_cls; std::string m_strRootPath_CA_cls; + std::string m_strRootPath_Det; // AI 检测结果存图根目录(根目录 + 产品ID + TA/CA + 日期) std::string m_strSavePath_cls; std::string m_strLastDate; diff --git a/AlgorithmModule/src/CameraCheckAnalysisy.cpp b/AlgorithmModule/src/CameraCheckAnalysisy.cpp index 0295a84..7daf496 100644 --- a/AlgorithmModule/src/CameraCheckAnalysisy.cpp +++ b/AlgorithmModule/src/CameraCheckAnalysisy.cpp @@ -168,7 +168,7 @@ int CameraCheckAnalysisy::Detect_Pre() if (pImageResult->result->in_shareImage->Det_Mode == DET_MODE_MergeImg) { - cv::imwrite(pImageResult->result->in_shareImage->strCameraName + "_MergeImg.png", pImageResult->result->in_shareImage->img); + cv::imwrite(pImageResult->result->in_shareImage->strCameraName + "_MergeImg.jpg", pImageResult->result->in_shareImage->img); return 2; } diff --git a/AlgorithmModule/src/ImgCheckAnalysisy.cpp b/AlgorithmModule/src/ImgCheckAnalysisy.cpp index 10c11dc..76d6390 100644 --- a/AlgorithmModule/src/ImgCheckAnalysisy.cpp +++ b/AlgorithmModule/src/ImgCheckAnalysisy.cpp @@ -39,6 +39,7 @@ ImgCheckAnalysisy::ImgCheckAnalysisy() m_strLastDate = ""; m_strRootPath_TA_cls = "/home/aidlux/BOE/Cls/TA/"; m_strRootPath_CA_cls = "/home/aidlux/BOE/Cls/CA/"; + m_strRootPath_Det = "/home/aidlux/BOE/CELL_AOI/AI_RESULT/"; creatsavedir(); m_pImageStorage = ImageStorage::getInstance(); m_nConfigIdx = -1; @@ -1650,7 +1651,7 @@ int ImgCheckAnalysisy::ConfigCheck(cv::Mat img) return re; } -int ImgCheckAnalysisy::AI_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg) +int ImgCheckAnalysisy::AI_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg, bool bPushBlobQueue) { std::shared_ptr pAIDet; // printf("=====>>>>AI_Detect_Thread m_strCurDetChannel %s \n", m_strCurDetChannel.c_str()); @@ -1741,6 +1742,7 @@ int ImgCheckAnalysisy::AI_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg) if (runner->PopResult(result)) { + if (bPushBlobQueue) { std::lock_guard lock(mtx_AIMaskImgBLobQueue); m_AIMaskImgBLobQueue.push(result); @@ -2129,7 +2131,28 @@ void ImgCheckAnalysisy::TaskFun_AIDet(std::shared_ptr task) int rec; if(m_pbaseCheckFunction->traditionDet.bOpen) { + // 传统检测与 AI 检测并行执行; + // 最终 NG 结果只由传统检测决定,AI 检测结果仅用于记录与展示。 + int recAI = 0; + std::thread aiThread([this, &recAI]() + { + recAI = AI_Detect_Thread(m_pImageAllResult->detImg, m_pImageAllResult->AIDetMaskImg, false); + }); + rec = Traditional_Detect_Thread(m_pImageAllResult->detImg, m_pImageAllResult->AIMaskImg); + + if (aiThread.joinable()) + { + aiThread.join(); + } + + m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, "TaskFun_AIDet", "traditional rec %d, AI rec %d", rec, recAI); + + // 保存 AI 检测结果,用于模型优化(需在配置 Det_Image_Save 下开启 Det_Save) + if (m_pbaseCheckFunction->saveImg.bSaveDetImg) + { + SaveAIDetResult(); + } } else { @@ -2142,6 +2165,61 @@ void ImgCheckAnalysisy::TaskFun_AIDet(std::shared_ptr task) task->SetStatus(TaskStep_compate); } +int ImgCheckAnalysisy::SaveAIDetResult() +{ + // 保存 AI 检测结果,用于模型优化 + std::string strProductID = DetImgInfo_shareP->strImgProductID; + if (strProductID.empty()) + { + strProductID = "Default"; + } + std::string strChannelDir; + if (m_strCurDetChannel.find("TA") != std::string::npos) + { + strChannelDir = "TA"; + } + else + { + strChannelDir = "CA"; + } + + // 目录结构:/home/aidlux/BOE/Det/<产品ID>//<日期>/ + std::string strRoot = m_strRootPath_Det + strProductID + "/" + strChannelDir + "/" + CheckUtil::getCurrentDate() + "/"; + CheckUtil::CreateDir(strRoot); + + std::string strBase = strRoot + m_strCurDetChannel + "_" + std::to_string(DetImgInfo_shareP->img_id) + "_" + std::to_string(CheckUtil::getcurTime()); + + // 1、保存整幅 AI mask 与 检测输入图 + if (!m_pImageAllResult->AIDetMaskImg.empty()) + { + m_pImageStorage->addImage(strBase + "_AI_mask.png", m_pImageAllResult->AIDetMaskImg); + } + if (!m_pImageAllResult->detImg.empty()) + { + m_pImageStorage->addImage(strBase + "_src.png", m_pImageAllResult->detImg); + } + + // 2、保存每个 AI 检出缺陷的小图(输入 + mask),只存有残点的 ROI + int nSaveIdx = 0; + for (auto &pAIMask : m_pImageAllResult->AI_Qx_MaskList) + { + if (!pAIMask || pAIMask->AI_mask.empty()) + { + continue; + } + if (cv::countNonZero(pAIMask->AI_mask) == 0) + { + continue; + } + m_pImageStorage->addImage(strBase + "_" + std::to_string(nSaveIdx) + "_in.png", pAIMask->AI_inImg); + m_pImageStorage->addImage(strBase + "_" + std::to_string(nSaveIdx) + "_mask.png", pAIMask->AI_mask); + nSaveIdx++; + } + + m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, "SaveAIDetResult", "save %d AI defect imgs to %s", nSaveIdx, strRoot.c_str()); + return 0; +} + void ImgCheckAnalysisy::TaskFun_QxClass(std::shared_ptr task) { task->SetStatus(TaskStep_run); diff --git a/ConfigModule/include/CheckConfigDefine.h b/ConfigModule/include/CheckConfigDefine.h index ed06031..b7df141 100644 --- a/ConfigModule/include/CheckConfigDefine.h +++ b/ConfigModule/include/CheckConfigDefine.h @@ -1747,6 +1747,7 @@ struct Base_Function_SaveImg bool bSaveMarkImg; // mark 存图 bool bSaveClsImg; // 分类 存图 bool bSaveAlginImg; // 分类 存图 + bool bSaveDetImg; // AI 检测存图(并行模式下保存 AI 检测结果,用于模型优化) Base_Function_SaveImg() { @@ -1758,6 +1759,7 @@ struct Base_Function_SaveImg bSaveMarkImg = false; bSaveClsImg = false; bSaveAlginImg = false; + bSaveDetImg = false; } void copy(Base_Function_SaveImg tem) @@ -1767,17 +1769,18 @@ struct Base_Function_SaveImg this->bSaveMarkImg = tem.bSaveMarkImg; this->bSaveClsImg = tem.bSaveClsImg; this->bSaveAlginImg = tem.bSaveAlginImg; + this->bSaveDetImg = tem.bSaveDetImg; } void print(std::string str) { - printf("%s>>bOpen %d bSaveMarkImg %d bSaveClsImg %d bSaveAlginImg %d \n", str.c_str(), - bOpen, bSaveMarkImg, bSaveClsImg, bSaveAlginImg); + printf("%s>>bOpen %d bSaveMarkImg %d bSaveClsImg %d bSaveAlginImg %d bSaveDetImg %d \n", str.c_str(), + bOpen, bSaveMarkImg, bSaveClsImg, bSaveAlginImg, bSaveDetImg); } std::string GetInfo(std::string str) { char buffer[256]; - sprintf(buffer, "%s>>bOpen %d bSaveMarkImg %d bSaveClsImg %d bSaveAlginImg %d \n", str.c_str(), - bOpen, bSaveMarkImg, bSaveClsImg, bSaveAlginImg); + sprintf(buffer, "%s>>bOpen %d bSaveMarkImg %d bSaveClsImg %d bSaveAlginImg %d bSaveDetImg %d \n", str.c_str(), + bOpen, bSaveMarkImg, bSaveClsImg, bSaveAlginImg, bSaveDetImg); std::string str123 = buffer; return str123; } diff --git a/ConfigModule/src/JsonConfig.cpp b/ConfigModule/src/JsonConfig.cpp index d406f64..c5cf631 100644 --- a/ConfigModule/src/JsonConfig.cpp +++ b/ConfigModule/src/JsonConfig.cpp @@ -1310,6 +1310,10 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value) { _config.saveImg.bSaveAlginImg = value_f["form"]["SaveImg_Config"]["Align_Big_Save"].asBool(); } + if (value_f["form"]["SaveImg_Config"]["Det_Save"]) + { + _config.saveImg.bSaveDetImg = value_f["form"]["SaveImg_Config"]["Det_Save"].asBool(); + } } else {