diff --git a/AlgorithmModule/include/ImageAllResult.h b/AlgorithmModule/include/ImageAllResult.h index d9976de..8e89f97 100644 --- a/AlgorithmModule/include/ImageAllResult.h +++ b/AlgorithmModule/include/ImageAllResult.h @@ -173,6 +173,7 @@ public: std::shared_ptr qx_DetAIResult; // BLob 检测要用到的一些 参数 。 std::shared_ptr cell127_DetAIResult; // 127 cell 检测要用到的一些 参数 。 + std::shared_ptr bq_DetAIResult; // BQ标签检测要用到的一些 参数 。 // 结果图片 cv::Mat resultImg; diff --git a/AlgorithmModule/include/ImageDetConfig.h b/AlgorithmModule/include/ImageDetConfig.h index 9859ef6..a332917 100644 --- a/AlgorithmModule/include/ImageDetConfig.h +++ b/AlgorithmModule/include/ImageDetConfig.h @@ -345,7 +345,10 @@ struct BQ_Result { int nresult = 1; bool bShield_BQ = true; // 是否屏蔽标签 - std::vector pBQ_roiList; // 标签的区域 + bool bBQ_AI_Det = false; // 是否启用标签独立AI检测 + std::vector pBQ_roiList; // 标签的原始区域 + std::vector pBQ_expandedRoiList; // 标签的扩展后区域(用于AI检测) + std::vector pBQ_cropImages; // 标签扩展区域图像 std::vector BQ_centerPoint; // 标签的中心点位置 }; struct CameraBaseResult diff --git a/AlgorithmModule/include/ImgCheckAnalysisy.hpp b/AlgorithmModule/include/ImgCheckAnalysisy.hpp index a8e22bf..fc4ff95 100644 --- a/AlgorithmModule/include/ImgCheckAnalysisy.hpp +++ b/AlgorithmModule/include/ImgCheckAnalysisy.hpp @@ -194,6 +194,12 @@ private: // 获得 127cell blob int GetBlob_127cell(); + // 获得 BQ标签 blob + int GetBlob_BQ(); + + // BQ标签 AI 检测 + int AI_Detect_BQ(); + // 对AI mask图片进行 结果处理 int AIMaskDet(); diff --git a/AlgorithmModule/src/CameraCheckAnalysisy.cpp b/AlgorithmModule/src/CameraCheckAnalysisy.cpp index 7adb551..00ddbf2 100644 --- a/AlgorithmModule/src/CameraCheckAnalysisy.cpp +++ b/AlgorithmModule/src/CameraCheckAnalysisy.cpp @@ -697,6 +697,7 @@ int CameraCheckAnalysisy::preDet_BQ(const cv::Mat &L255CutImg, std::shared_ptrcameraBaseResult->pBQ_Result = std::make_shared(); m_pCheck_Result->cameraBaseResult->pBQ_Result->bShield_BQ = m_AnalysisyConfig.commonCheckConfig.baseConfig.bShield_BQ; + m_pCheck_Result->cameraBaseResult->pBQ_Result->bBQ_AI_Det = m_pbaseCheckFunction->Det_BQ.bBQ_AI_Det; cv::Rect Det_CropRoi = m_pCheck_Result->cameraBaseResult->pEdgeDetResult->cutRoi; @@ -718,7 +719,7 @@ int CameraCheckAnalysisy::preDet_BQ(const cv::Mat &L255CutImg, std::shared_ptrcameraBaseResult->pBQ_Result->bShield_BQ && m_pbaseCheckFunction->Det_BQ.bOpen) + if (m_pCheck_Result->cameraBaseResult->pBQ_Result->bShield_BQ) { m_pdetlog->AddCheckstr(PrintLevel_2, "preDet_BQ", "shieldBQ is Open"); cv::Mat detImg_mask = m_pCheck_Result->cameraBaseResult->pEdgeDetResult->shieldMask; @@ -733,7 +734,16 @@ int CameraCheckAnalysisy::preDet_BQ(const cv::Mat &L255CutImg, std::shared_ptr 0 && boundingRect.height > 0) { + // 同时屏蔽主AI,避免重复检测 detImg_mask(boundingRect).setTo(255); + + // 保存裁剪图像供独立BQ AI检测 + if (m_pbaseCheckFunction->Det_BQ.bBQ_AI_Det) + { + m_pCheck_Result->cameraBaseResult->pBQ_Result->pBQ_expandedRoiList.push_back(boundingRect); + cv::Mat bqCrop = L255CutImg(boundingRect).clone(); + m_pCheck_Result->cameraBaseResult->pBQ_Result->pBQ_cropImages.push_back(bqCrop); + } } } if (L255->result->in_shareImage->bDebugsaveImg) diff --git a/AlgorithmModule/src/ImgCheckAnalysisy.cpp b/AlgorithmModule/src/ImgCheckAnalysisy.cpp index 275e633..543cf1d 100644 --- a/AlgorithmModule/src/ImgCheckAnalysisy.cpp +++ b/AlgorithmModule/src/ImgCheckAnalysisy.cpp @@ -518,6 +518,14 @@ int ImgCheckAnalysisy::CheckRun() Edge_Det(); + // BQ标签AI检测 + { + long t_BQ_s = CheckUtil::getcurTime(); + int recBQ = AI_Detect_BQ(); + long t_BQ_e = CheckUtil::getcurTime(); + m_pdetlog->AddCheckstr(PrintLevel_0, "4、BQ Detect", "-------------------------BQ AI Detect--------%ld ms-------\n", t_BQ_e - t_BQ_s); + } + m_CheckResult_shareP->resultMaskImg = m_pImageAllResult->qx_DetAIResult->AI_MaskImg; // cv::imwrite("dddddddd.png", m_pImageAllResult->qx_DetAIResult->AI_MaskImg); @@ -1695,6 +1703,8 @@ int ImgCheckAnalysisy::GetALLBlob() re = GetBlob_QX(); long t4 = CheckUtil::getcurTime(); re = GetBlob_127cell(); + long t5 = CheckUtil::getcurTime(); + re = GetBlob_BQ(); if (blobs.blobCount > 100) { @@ -1704,8 +1714,8 @@ int ImgCheckAnalysisy::GetALLBlob() long te = CheckUtil::getcurTime(); m_pdetlog->AddCheckstr(PrintLevel_0, strBaseLog, - "---GetALLBlob End ;use time %ld ms yx %ld ms lack %ld ms qx %ld ms 127 %ld ms", - te - t1, t2 - t1, t3 - t2, t4 - t3, te - t4); + "---GetALLBlob End ;use time %ld ms yx %ld ms lack %ld ms qx %ld ms 127 %ld ms bq %ld ms", + te - t1, t2 - t1, t3 - t2, t4 - t3, t5 - t4, te - t5); // getchar(); return 0; @@ -2143,6 +2153,199 @@ int ImgCheckAnalysisy::GetBlob_127cell() return 0; } +// BQAI检测 +int ImgCheckAnalysisy::AI_Detect_BQ() +{ + std::string strBaseLog = "AI_Detect_BQ"; + + // 检查BQ标签AI检测是否启用 + if (!m_pImageAllResult->cameraBaseResult->pBQ_Result) + { + return 0; + } + if (!m_pImageAllResult->cameraBaseResult->pBQ_Result->bBQ_AI_Det) + { + return 0; + } + + int bqNum = static_cast(m_pImageAllResult->cameraBaseResult->pBQ_Result->pBQ_cropImages.size()); + if (bqNum <= 0) + { + return 0; + } + + m_pdetlog->AddCheckstr(PrintLevel_1, strBaseLog, "============= Start, BQ num = %d", bqNum); + long ts = CheckUtil::getcurTime(); + + // 初始化BQ AI检测结果 + m_pImageAllResult->bq_DetAIResult = std::make_shared(); + std::shared_ptr pDetAIResult = m_pImageAllResult->bq_DetAIResult; + + // 使用与主检测相同的AI模型(后续更改为BQ AI模型) + std::shared_ptr pAI_Model = AI_Factory->AI_defect_NF; + + int AIInputImg_width = pAI_Model->input_0.width; + int AIInputImg_height = pAI_Model->input_0.height; + cv::Size modelInputSize(AIInputImg_width, AIInputImg_height); + + // 创建全图大小的AI mask(与主检测detImg同尺寸) + cv::Mat AI_detImage = m_pImageAllResult->AI_detImg; + pDetAIResult->AI_MaskImg = cv::Mat::zeros(AI_detImage.size(), CV_8UC1); + + // 先提交所有BQ AI推理任务(仿照AI_Detect_QX的提交-收集模式) + int submitted = 0; + int completed = 0; + while (completed < bqNum) + { + // 提交任务(限制并发数不超过2,避免占用过多资源) + if (submitted < bqNum && runner->GetProcessingCount() < 2) + { + cv::Mat bqCrop = m_pImageAllResult->cameraBaseResult->pBQ_Result->pBQ_cropImages.at(submitted); + if (!bqCrop.empty()) + { + cv::Mat resizedCrop; + cv::resize(bqCrop, resizedCrop, modelInputSize); + + std::shared_ptr task = std::make_shared(); + task->id = submitted; + task->roi = cv::Rect(0, 0, modelInputSize.width, modelInputSize.height); + task->input = resizedCrop; + task->output = std::make_shared(); + task->engine = pAI_Model; + + runner->SubmitTask(task); + } + submitted++; + } + + // 收集已完成的结果 + std::shared_ptr result; + if (runner->PopResult(result)) + { + int idx = result->id; + if (idx >= 0 && idx < bqNum) + { + cv::Rect bqRoi = m_pImageAllResult->cameraBaseResult->pBQ_Result->pBQ_expandedRoiList.at(idx); + cv::Rect validRoi = bqRoi & cv::Rect(0, 0, AI_detImage.cols, AI_detImage.rows); + + if (validRoi.width > 0 && validRoi.height > 0) + { + cv::Mat &outMask = *(result->output); + if (!outMask.empty()) + { + // 将AI输出mask resize回BQ裁剪图原始尺寸 + cv::Mat resizedMask; + cv::resize(outMask, resizedMask, cv::Size(bqRoi.width, bqRoi.height)); + + // 将BQ的mask结果放到全图mask的对应位置 + resizedMask.copyTo(pDetAIResult->AI_MaskImg(validRoi), resizedMask); + + m_pdetlog->AddCheckstr(PrintLevel_2, strBaseLog, "BQ[%d] AI done, roi=[%d,%d,%d,%d]", + idx, validRoi.x, validRoi.y, validRoi.width, validRoi.height); + } + else + { + m_pdetlog->AddCheckstr(PrintLevel_2, strBaseLog, "BQ[%d] AI output empty", idx); + } + } + } + completed++; + } + else + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + } + + long te = CheckUtil::getcurTime(); + m_pdetlog->AddCheckstr(PrintLevel_1, strBaseLog, "============= End, time=%ld ms", te - ts); + + // 调试存图 + if (DetImgInfo_shareP->bDebugsaveImg) + { + cv::imwrite(m_strCurDetCamChannel + "_AI_BQ_mask.png", pDetAIResult->AI_MaskImg); + } + + return 0; +} + +int ImgCheckAnalysisy::GetBlob_BQ() +{ + std::string strBaseLog = "GetBlob_BQ"; + + // 检查BQ标签AI检测是否启用 + if (!m_pImageAllResult->cameraBaseResult->pBQ_Result) + { + return 0; + } + if (!m_pImageAllResult->cameraBaseResult->pBQ_Result->bBQ_AI_Det) + { + return 0; + } + if (!m_pImageAllResult->bq_DetAIResult) + { + m_pdetlog->AddCheckstr(PrintLevel_2, strBaseLog, "bq_DetAIResult is null, skip"); + return 0; + } + + std::shared_ptr pDetAIResult = m_pImageAllResult->bq_DetAIResult; + cv::Mat maskimg = pDetAIResult->AI_MaskImg; + if (maskimg.empty()) + { + m_pdetlog->AddCheckstr(PrintLevel_2, strBaseLog, "AI_MaskImg is empty, skip"); + return 0; + } + + long t1 = CheckUtil::getcurTime(); + + // 使用与主流程相同的blob提取方式:GetBlobs_V3 + // BQ检测的mask中,缺陷像素值为非零值 + ERROR_DOTS_BLOBS blobs_bq; + memset(&blobs_bq, 0x00, sizeof(ERROR_DOTS_BLOBS)); + + unsigned char *pGrayErrordata = (unsigned char *)maskimg.data; + int width = maskimg.cols; + int height = maskimg.rows; + int minArea = 10; // BQ标签区域最小缺陷面积阈值 + + // 使用逐像素扫描方式提取blob(GetBlobs_V3对mask中的非零值进行blob提取) + GetBlobs_V3(&blobs_bq, pGrayErrordata, width, height, minArea); + + // 设置BQ blob的默认缺陷类型(后续分类会重新确定类型) + // 使用非cell类型,确保进入AI_Classify_New分类流程 + for (int i = 0; i < blobs_bq.blobCount; i++) + { + blobs_bq.blobTab[i].ErrType = CONFIG_QX_NAME_LD; // 以亮点作为初始类型,后续分类修正 + } + + // 将BQ的blob汇入主blob列表 + PushBlob(&blobs, &blobs_bq); + + long te = CheckUtil::getcurTime(); + m_pdetlog->AddCheckstr(PrintLevel_1, strBaseLog, + "BQ blob num = %d, merged to main blobs (total=%d), time=%ld ms", + blobs_bq.blobCount, blobs.blobCount, te - t1); + + // 调试存图 + if (DetImgInfo_shareP->bDebugsaveImg && blobs_bq.blobCount > 0) + { + cv::Mat tm; + cv::cvtColor(maskimg, tm, cv::COLOR_GRAY2RGB); + for (int i = 0; i < blobs_bq.blobCount; i++) + { + cv::Rect roi; + roi.x = blobs_bq.blobTab[i].minx; + roi.y = blobs_bq.blobTab[i].miny; + roi.width = blobs_bq.blobTab[i].maxx - blobs_bq.blobTab[i].minx + 1; + roi.height = blobs_bq.blobTab[i].maxy - blobs_bq.blobTab[i].miny + 1; + cv::rectangle(tm, roi, cv::Scalar(0, 0, 255), 2); + } + cv::imwrite(m_strCurDetCamChannel + "_BQ_blob.png", tm); + } + + return 0; +} + int ImgCheckAnalysisy::AIMaskDet() { m_pdetlog->AddCheckstr(PrintLevel_0, "AIMaskDet", "=======start"); diff --git a/ConfigModule/include/CheckConfigDefine.h b/ConfigModule/include/CheckConfigDefine.h index f09dadf..9d031bc 100644 --- a/ConfigModule/include/CheckConfigDefine.h +++ b/ConfigModule/include/CheckConfigDefine.h @@ -2263,8 +2263,8 @@ struct Base_Function_AD_Check struct Base_Function_Det_BQ { - bool bOpen; int BQ_expand; + bool bBQ_AI_Det; // 是否启用标签独立AI检测,汇入主流程分类 Base_Function_Det_BQ() { @@ -2272,24 +2272,24 @@ struct Base_Function_Det_BQ } void Init() { - bOpen = false; BQ_expand = 0; + bBQ_AI_Det = false; } void copy(Base_Function_Det_BQ tem) { - this->bOpen = tem.bOpen; this->BQ_expand = tem.BQ_expand; + this->bBQ_AI_Det = tem.bBQ_AI_Det; } void print(std::string str) { - printf("%s>>bOpen %d BQ_expand %d\n", str.c_str(), - bOpen, BQ_expand); + printf("%d BQ_expand %d bBQ_AI_Det %d\n", str.c_str(), + BQ_expand, bBQ_AI_Det); } std::string GetInfo(std::string str) { char buffer[256]; - sprintf(buffer, "%s>>bOpen %d BQ_expand %d\n", str.c_str(), - bOpen, BQ_expand); + sprintf(buffer, "%d BQ_expand %d bBQ_AI_Det %d\n", str.c_str(), + BQ_expand, bBQ_AI_Det); std::string str123 = buffer; return str123; } diff --git a/ConfigModule/src/JsonConfig.cpp b/ConfigModule/src/JsonConfig.cpp index 423a8ad..ba11b73 100644 --- a/ConfigModule/src/JsonConfig.cpp +++ b/ConfigModule/src/JsonConfig.cpp @@ -1477,18 +1477,13 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value) auto value_f = value; // std::cout << value_f << std::endl; // getchar(); - _config.Det_BQ.bOpen = value_f["isOpen"].asBool(); - if (_config.Det_BQ.bOpen) + _config.Det_BQ.bBQ_AI_Det = value_f["isOpen"].asBool(); { if (value_f["form"]["bShield_BQ"]["BQ_expand"]) { _config.Det_BQ.BQ_expand = value_f["form"]["bShield_BQ"]["BQ_expand"].asInt(); } } - else - { - _config.Det_BQ.Init(); - } // _config.edgeDet.print("edgeDet"); // getchar(); }