From 5b7d9f11e87a7156f870823c10fb3ca9a947edf9 Mon Sep 17 00:00:00 2001 From: liusiyang Date: Thu, 27 Aug 2026 15:39:29 +0800 Subject: [PATCH] =?UTF-8?q?feat=20=E5=88=9D=E6=AD=A5=E6=B7=BB=E5=8A=A0AD?= =?UTF-8?q?=E7=BB=91=E5=AE=9A=E5=88=86=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AlgorithmModule/include/QX_Merge_Analysis.h | 2 + AlgorithmModule/src/QX_Merge_Analysis.cpp | 404 +++++++++++++++++++- ConfigModule/include/CheckConfigDefine.h | 40 ++ ConfigModule/src/JsonConfig.cpp | 59 +++ 4 files changed, 504 insertions(+), 1 deletion(-) diff --git a/AlgorithmModule/include/QX_Merge_Analysis.h b/AlgorithmModule/include/QX_Merge_Analysis.h index 0730b24..bb17d37 100644 --- a/AlgorithmModule/include/QX_Merge_Analysis.h +++ b/AlgorithmModule/include/QX_Merge_Analysis.h @@ -116,6 +116,8 @@ private: int Judge_NG_Config(); int Analysis_AD(ALL_Qx_DataList *pALLTypeqxList, int qx_idx); + int Analysis_AD_Bind(ALL_Qx_DataList *pALLTypeqxList, int qx_idx); + ChannelCheckFunction *GetChannelFuntion(std::string strChannelName); diff --git a/AlgorithmModule/src/QX_Merge_Analysis.cpp b/AlgorithmModule/src/QX_Merge_Analysis.cpp index 3702942..8079a85 100644 --- a/AlgorithmModule/src/QX_Merge_Analysis.cpp +++ b/AlgorithmModule/src/QX_Merge_Analysis.cpp @@ -696,7 +696,15 @@ int QX_Merge_Analysis::Analysis_QXtype(ALL_Qx_DataList *pALLTypeqxList, int qx_i // AD 要进行额外的分析 if (qx_idx == QX_ANALYSIS_AD) { - Analysis_AD(pALLTypeqxList, qx_idx); + if(m_pbaseCheckFunction->ad_check.analysis_bind.bUse) + { + Analysis_AD_Bind(pALLTypeqxList, qx_idx); + } + else + { + Analysis_AD(pALLTypeqxList, qx_idx); + } + } return 0; @@ -986,7 +994,399 @@ int QX_Merge_Analysis::Analysis_AD(ALL_Qx_DataList *pALLTypeqxList, int qx_idx) } A_2S_num += AD_list.at(ad_i).num_2s; A_3S_num += AD_list.at(ad_i).num_3s; + + + if(AD_list.at(ad_i).num_1s >= 3) A_3S_num++; + + m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "AD_list %d %s", + ad_i, AD_list.at(ad_i).GetInfo().c_str()); + } + m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "product_AD_num %d 2S_num = %d 3S_num s = %d min_dis %0.2f", + product_AD_num, A_2S_num, A_3S_num, min_dis); + } + + for (int i = 0; i < pALLTypeqxList->channelqxList.size(); i++) + { + QX_channel_List *pQXChannelList = &pALLTypeqxList->channelqxList[i]; + + if (!pAd_checkParma->bOpen) + { + + continue; + } + bool bNG = false; + + bool NG_num = false; + bool NG_3S = false; + bool NG_2S = false; + bool NG_dis = false; + + if (pAd_checkParma->analysis_num.bOpen) + { + // 数量分析 + if (product_AD_num >= pAd_checkParma->analysis_num.numT) + { + m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "Num Analysis --> %s result NG ,product_AD_num %d >= parm num %d", + pQXChannelList->channel_name.c_str(), product_AD_num, pAd_checkParma->analysis_num.numT); + bNG = true; + NG_num = true; + } + else + { + m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "Num Analysis--> %s result OK ,product_AD_num %d < parm num %d", + pQXChannelList->channel_name.c_str(), product_AD_num, pAd_checkParma->analysis_num.numT); + } + } + // 不NG + if (!bNG) + { + // 3S直接 NG + if (pAd_checkParma->analysis_s.NG_3s) + { + // 数量分析 + if (A_3S_num >= 1) + { + m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "3S Analysis --> %s result NG 3S %d >= 1", + pQXChannelList->channel_name.c_str(), A_3S_num); + + bNG = true; + NG_3S = true; + } + else + { + m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "3S Analysis --> %s result OK 3S %d < 1", + pQXChannelList->channel_name.c_str(), A_3S_num); + } + } + } + // 不NG + if (!bNG) + { + // 距离判断 + if (pAd_checkParma->analysis_dis.bOpen) + { + // 数量分析 + if (min_dis <= pAd_checkParma->analysis_dis.disT) + { + m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "Dis Analysis--> %s Dis result NG ,min dis %f <= parm dis %f", + pQXChannelList->channel_name.c_str(), min_dis, pAd_checkParma->analysis_dis.disT); + + bNG = true; + NG_2S = true; + } + else + { + m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "Dis Analysis--> %s Dis result OK ,min dis %f > parm dis %f", + pQXChannelList->channel_name.c_str(), min_dis, pAd_checkParma->analysis_dis.disT); + } + } + } + // 不NG + if (!bNG) + { + // S标准判断 + if (pAd_checkParma->analysis_s.bOpen) + { + // 数量分析 + if (A_2S_num >= pAd_checkParma->analysis_s.Check_s_Num) + { + m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "S Analysis--> %s result NG , Check %ds Num %d >= parm S Num %d", + pQXChannelList->channel_name.c_str(), pAd_checkParma->analysis_s.Check_s_Value, A_2S_num, pAd_checkParma->analysis_s.Check_s_Num); + + bNG = true; + NG_2S = true; + } + else + { + m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "S Analysis--> %s result OK , Check %ds Num %d < parm S Num %d", + pQXChannelList->channel_name.c_str(), pAd_checkParma->analysis_s.Check_s_Value, A_2S_num, pAd_checkParma->analysis_s.Check_s_Num); + } + } + } + // 已经NG + if (bNG) + { + + QX_channel_List *pqxList = pQXChannelList; + for (int i = 0; i < (int)pqxList->qxList.size(); i++) + { + + if (pqxList->qxList.at(i).result == 0) + { + pqxList->qxList.at(i).result = 1; + + QX_RESULT tem; + tem.blobIdx = pqxList->qxList.at(i).blobIdx; + tem.mindis = pqxList->qxList.at(i).fmindis; + tem.flen = pqxList->qxList.at(i).length; + tem.error_Type = pqxList->qxList.at(i).nqx_type; + tem.camera_name = pqxList->qxList.at(i).camera_name; + tem.channel_name = pqxList->qxList.at(i).channel_name; + pqxList->pChannelDetlog->AddCheckstr(PrintLevel_4, 3, "result = NG", "Add New qx,Blob idx %d type %d num %d dis %f len %f ", tem.blobIdx, tem.error_Type, tem.qx_Num, tem.mindis, tem.flen); + m_pMergedetlog->AddCheckstr(PrintLevel_4, 3, "result = NG", "%s Add New qx,Blob idx %d type %d num %d dis %f len %f ", + tem.channel_name.c_str(), tem.blobIdx, tem.error_Type, tem.qx_Num, tem.mindis, tem.flen); + + m_reultList.resultList.push_back(tem); + } + } + } + } + + return 0; +} + +int QX_Merge_Analysis::Analysis_AD_Bind(ALL_Qx_DataList *pALLTypeqxList, int qx_idx) +{ + AD_list.clear(); + if (!m_pbaseCheckFunction) + { + return 1; + } + + Base_Function_AD_Check *pAd_checkParma = &m_pbaseCheckFunction->ad_check; + + int product_AD_num = 0; // 整个产品的 暗点数目。 + int check_s_Num = 0; + int s_param_value = -1; + int s_param_num = 0; + // 遍历每个通道,找到开启的 进行分析。 + for (int i = 0; i < pALLTypeqxList->channelqxList.size(); i++) + { + QX_channel_List *pQXChannelList = &pALLTypeqxList->channelqxList[i]; + + if (!pAd_checkParma) + { + continue; + } + if (pAd_checkParma && !pAd_checkParma->bOpen) + { + pQXChannelList->pChannelDetlog->AddCheckstr(PrintLevel_2, 3, "Analysis_AD ", + "channel %s AD Check is close", pQXChannelList->channel_name.c_str()); + continue; + } + bool bana_num = false; + bool bana_dis = false; + bool bana_S = false; + if (pAd_checkParma->analysis_num.bOpen) + { + bana_num = true; + } + if (pAd_checkParma->analysis_dis.bOpen) + { + bana_dis = true; + } + if (pAd_checkParma->analysis_s.bOpen) + { + bana_S = true; + } + { + pQXChannelList->pChannelDetlog->AddCheckstr(PrintLevel_2, 3, "Analysis_AD ", "NUM --> %s Param num check %d dis check %d S check %d", + pQXChannelList->channel_name.c_str(), bana_num, bana_dis, bana_S); + } + if (!bana_num && !bana_dis && !bana_S) + { + continue; + } + + for (int j = 0; j < pQXChannelList->qxList.size(); j++) + { + if (pQXChannelList->qxList[j].area >= pAd_checkParma->S_standard_1s.area && + pQXChannelList->qxList[j].length >= pAd_checkParma->S_standard_1s.len) + { + } + else + { + continue; + } + + tem_AD_QX_Info tem_AD_qx; // 暗点信息 + tem_AD_qx.channelidx = i; + tem_AD_qx.qxidx = j; + + int s_det_value = 0; + // 当前通道 要参与s标准分析 + if (pAd_checkParma->analysis_s.bOpen) + { + s_param_num = pAd_checkParma->analysis_s.Check_s_Num; + s_param_value = pAd_checkParma->analysis_s.Check_s_Value; + + if (pQXChannelList->qxList[j].area >= pAd_checkParma->S_standard_3s.area && + pQXChannelList->qxList[j].length >= pAd_checkParma->S_standard_3s.len) + { + s_det_value = 3; + pQXChannelList->pChannelDetlog->AddCheckstr(PrintLevel_3, 3, "add AD ", + "%d %s 3S: cur[A %0.2f L %0.2f] parm[A %0.2f L %0.2f]", + j, pQXChannelList->channel_name.c_str(), + pQXChannelList->qxList[j].area, pQXChannelList->qxList[j].length, + pAd_checkParma->S_standard_3s.area, pAd_checkParma->S_standard_3s.len); + } + else if (pQXChannelList->qxList[j].area >= pAd_checkParma->S_standard_2s.area && + pQXChannelList->qxList[j].length >= pAd_checkParma->S_standard_2s.len) + { + s_det_value = 2; + pQXChannelList->pChannelDetlog->AddCheckstr(PrintLevel_3, 3, " add AD ", + "%d %s 2S: cur[A %0.2f L %0.2f] parm[A %0.2f L %0.2f]", + j, pQXChannelList->channel_name.c_str(), + pQXChannelList->qxList[j].area, pQXChannelList->qxList[j].length, + pAd_checkParma->S_standard_2s.area, pAd_checkParma->S_standard_1s.len); + } + else + { + pQXChannelList->pChannelDetlog->AddCheckstr(PrintLevel_3, 3, "add AD ", + "%d %s 1S: cur[A %0.2f L %0.2f] parm[A %0.2f L %0.2f]", + j, pQXChannelList->channel_name.c_str(), + pQXChannelList->qxList[j].area, pQXChannelList->qxList[j].length, + pAd_checkParma->S_standard_2s.area, pAd_checkParma->S_standard_1s.len); + s_det_value = 1; + } + if (s_det_value >= s_param_value) + { + check_s_Num++; + } + } + + cv::Rect roi = pQXChannelList->qxList[j].product_roi; + + int list_idx = -1; + int channel_s = 0; + int roi_expand = (round)(pAd_checkParma->analysis_iou.AD_Expand); + bool bnew_add = true; + for (int idx = 0; idx < AD_list.size(); idx++) + { + cv::Rect tem_roi(AD_list.at(idx).roi.x-roi_expand, AD_list.at(idx).roi.y-roi_expand, AD_list.at(idx).roi.width+2*roi_expand, AD_list.at(idx).roi.height+2*roi_expand); + cv::Rect tem_roi2(roi.x-roi_expand, roi.y-roi_expand, roi.width+2*roi_expand, roi.height+2*roi_expand); + + float fiou = CheckUtil::CalIoU(AD_list.at(idx).roi, roi); + m_pMergedetlog->AddCheckstr(PrintLevel_3, 3, "CalIoU", + "roi1 %s roi2 %s expand %d iou %f", + CheckUtil::GetRectString(AD_list.at(idx).roi).c_str(), + CheckUtil::GetRectString(roi).c_str(), + roi_expand, fiou); + if (fiou > pAd_checkParma->analysis_iou.AD_IOU) + { + list_idx = idx; + } + } + // 在list已存在。 + if (list_idx >= 0) + { + AD_list.at(list_idx).num++; + AD_list.at(list_idx).numIdxList.push_back(tem_AD_qx); + + channel_s = AD_list.at(list_idx).num; + if (s_det_value == 1) + { + AD_list.at(list_idx).num_1s++; + } + else if (s_det_value == 2) + { + AD_list.at(list_idx).num_2s++; + AD_list.at(list_idx).num_2sIdxList.push_back(tem_AD_qx); + } + else + { + AD_list.at(list_idx).num_3s++; + AD_list.at(list_idx).num_3sIdxList.push_back(tem_AD_qx); + } + bnew_add = false; + } + else + { // 在list不存在。 + AD_Channel_Info_ tem; + tem.roi = roi; + tem.location_product_mm = pQXChannelList->qxList[j].pLocation_Product_mm; + tem.num = 1; + channel_s = 1; + tem.fdis = 99999999999; + + tem.numIdxList.push_back(tem_AD_qx); + + if (s_det_value == 1) + { + tem.num_1s++; + } + else if (s_det_value == 2) + { + tem.num_2s++; + tem.num_2sIdxList.push_back(tem_AD_qx); + } + else + { + tem.num_3s++; + tem.num_3sIdxList.push_back(tem_AD_qx); + } + AD_list.push_back(tem); + // 如果要参与数量统计 + if (bana_num) + { + product_AD_num++; + } + } + + m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "AD list size %ld; channel %s blob idx %d,new_add %d ,A %f len %f p %d %d", + AD_list.size(), pQXChannelList->channel_name.c_str(), j, bnew_add, pQXChannelList->qxList[j].area, + pQXChannelList->qxList[j].length, roi.x, roi.y); + + pQXChannelList->pChannelDetlog->AddCheckstr(PrintLevel_2, 3, "Analysis_AD ", + "%d %s AD list size %ld product_AD_num Num %d; cur channel num = %d;cur S = %ds; param :%ds num %d;->S check_s_Num = %d", + j, pQXChannelList->channel_name.c_str(), AD_list.size(), + product_AD_num, channel_s, s_det_value, s_param_value, s_param_num, check_s_Num); + } + } + + float min_dis = 9999999999; + // 求最小距离 + if (true) + { + for (int ad_i = 0; ad_i < AD_list.size(); ad_i++) + { + for (int ad_j = 0; ad_j < AD_list.size(); ad_j++) + { + if (ad_i == ad_j) + { + continue; + } + // double dis = DistanceBetweenRectCenters(AD_list.at(ad_i).roi, AD_list.at(ad_j).roi, + // 1, + // 1); + + float dis = CheckUtil::calDis(AD_list.at(ad_i).location_product_mm, AD_list.at(ad_j).location_product_mm); + if (dis < AD_list.at(ad_i).fdis) + { + AD_list.at(ad_i).fdis = dis; + AD_list.at(ad_i).dist_idx = ad_j; + if (dis < min_dis) + { + min_dis = dis; + } + } + } + } + } + int A_2S_num = 0; + int A_3S_num = 0; + // 统计 2s 总数 + if (s_param_value > 0) + { + int channels = 0; + int oneimgs = check_s_Num; + + for (int ad_i = 0; ad_i < AD_list.size(); ad_i++) + { + if (AD_list.at(ad_i).num > 1) + { + AD_list.at(ad_i).num_2s++; + for (int i = 0; i < AD_list.at(ad_i).numIdxList.size(); i++) + { + AD_list.at(ad_i).num_2sIdxList.push_back(AD_list.at(ad_i).numIdxList.at(i)); + } + } + A_2S_num += AD_list.at(ad_i).num_2s; + A_3S_num += AD_list.at(ad_i).num_3s; + + if(AD_list.at(ad_i).num_1s >= 3) A_3S_num++; + m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "AD RGBL255", "AD_list %d %s", ad_i, AD_list.at(ad_i).GetInfo().c_str()); } @@ -1123,6 +1523,8 @@ int QX_Merge_Analysis::Analysis_AD(ALL_Qx_DataList *pALLTypeqxList, int qx_idx) return 0; } + + ChannelCheckFunction *QX_Merge_Analysis::GetChannelFuntion(std::string strChannelName) { ChannelCheckFunction *p = NULL; diff --git a/ConfigModule/include/CheckConfigDefine.h b/ConfigModule/include/CheckConfigDefine.h index 4e0f4d1..5b098b6 100644 --- a/ConfigModule/include/CheckConfigDefine.h +++ b/ConfigModule/include/CheckConfigDefine.h @@ -1567,6 +1567,44 @@ struct AD_Analysisy_IOU return str123; } }; +struct AD_Analysisy_Bind +{ + bool bUse; + std::vector main_channel_2s; + std::vector second_channel_2s; + std::vector main_channel_3s; + std::vector second_channel_3s; + + AD_Analysisy_Bind() + { + Init(); + } + void Init() + { + bUse = false; + main_channel_2s.clear(); + second_channel_2s.clear(); + main_channel_3s.clear(); + second_channel_3s.clear(); + } + void copy (AD_Analysisy_Bind tem) + { + this->bUse = tem.bUse; + this->main_channel_2s = tem.main_channel_2s; + this->second_channel_2s = tem.second_channel_2s; + this->main_channel_3s = tem.main_channel_3s; + this->second_channel_3s = tem.second_channel_3s; + } + std::string GetInfo(std::string str) + { + char buffer[256]; + sprintf(buffer, "%s:bUse %d;", str.c_str(), + bUse); + std::string str123 = buffer; + return str123; + } +}; + // 暗点检测功能 struct Function_AD_Check { @@ -1579,6 +1617,7 @@ struct Function_AD_Check AD_Analysisy_Dis analysis_dis; // 距离分析 AD_Analysisy_S analysis_s; // s 标准分析 AD_Analysisy_IOU analysis_iou; // IOU 分析 + AD_Analysisy_Bind analysis_bind; // 绑定分析 Function_AD_Check() { @@ -2252,6 +2291,7 @@ struct Base_Function_AD_Check AD_Analysisy_Dis analysis_dis; // 距离分析 AD_Analysisy_S analysis_s; // s 标准分析 AD_Analysisy_IOU analysis_iou; // IOU 分析 + AD_Analysisy_Bind analysis_bind; // 绑定分析 Base_Function_AD_Check() { diff --git a/ConfigModule/src/JsonConfig.cpp b/ConfigModule/src/JsonConfig.cpp index 400de61..9209203 100644 --- a/ConfigModule/src/JsonConfig.cpp +++ b/ConfigModule/src/JsonConfig.cpp @@ -1435,6 +1435,7 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value) _config.ad_check.bOpen = value_f["isOpen"].asBool(); if (_config.ad_check.bOpen) { + // S标准 if (value_f["form"]["AD_S_Standard"]["AD_3S_Area"]) { _config.ad_check.S_standard_3s.area = value_f["form"]["AD_S_Standard"]["AD_3S_Area"].asFloat(); @@ -1462,6 +1463,7 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value) _config.ad_check.S_standard_1s.len = value_f["form"]["AD_S_Standard"]["AD_1S_Len"].asFloat(); } + // 数量分析 if (value_f["form"]["AD_Check_Num"]["Open"]) { _config.ad_check.analysis_num.bOpen = value_f["form"]["AD_Check_Num"]["Open"].asBool(); @@ -1471,6 +1473,7 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value) _config.ad_check.analysis_num.numT = value_f["form"]["AD_Check_Num"]["Num"].asInt(); } + // S数量分析 if (value_f["form"]["AD_Check_Dis"]["Open"]) { _config.ad_check.analysis_dis.bOpen = value_f["form"]["AD_Check_Dis"]["Open"].asBool(); @@ -1480,6 +1483,7 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value) _config.ad_check.analysis_dis.disT = value_f["form"]["AD_Check_Dis"]["Dis"].asFloat(); } + // 距离分析 if (value_f["form"]["AD_Check_S"]["Open"]) { _config.ad_check.analysis_s.bOpen = value_f["form"]["AD_Check_S"]["Open"].asBool(); @@ -1497,11 +1501,66 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value) { _config.ad_check.analysis_s.Check_s_Num = value_f["form"]["AD_Check_S"]["Num"].asInt(); } + + // IOU分析 + if (value_f["form"]["AD_Check_IOU"]["AD_IOU"]) + { + _config.ad_check.analysis_iou.AD_IOU = value_f["form"]["AD_Check_IOU"]["AD_IOU"].asFloat(); + } + if (value_f["form"]["AD_Check_IOU"]["AD_Expand"]) + { + _config.ad_check.analysis_iou.AD_Expand = value_f["form"]["AD_Check_IOU"]["AD_Expand"].asFloat(); + } + + // 通道绑定 + if (value_f["form"]["Bind_Channel"]["bUse_bind"]) + { + _config.ad_check.analysis_bind.bUse = value_f["form"]["Bind_Channel"]["bUse_bind"].asBool(); + } + auto value_qx = value_f["form"]["Bind_Channel"]["2s_main_channel"]; + if (value_qx.isArray()) + { + for (int idx = 0; idx < value_qx.size(); idx++) + { + std::string channel = value_qx[idx].asString(); + _config.ad_check.analysis_bind.main_channel_2s.push_back(channel); + } + } + value_qx = value_f["form"]["Bind_Channel"]["2s_second_channel"]; + if (value_qx.isArray()) + { + for (int idx = 0; idx < value_qx.size(); idx++) + { + std::string channel = value_qx[idx].asString(); + _config.ad_check.analysis_bind.second_channel_2s.push_back(channel); + } + } + + value_qx = value_f["form"]["Bind_Channel"]["3s_main_channel"]; + if (value_qx.isArray()) + { + for (int idx = 0; idx < value_qx.size(); idx++) + { + std::string channel = value_qx[idx].asString(); + _config.ad_check.analysis_bind.main_channel_3s.push_back(channel); + } + } + value_qx = value_f["form"]["Bind_Channel"]["3s_second_channel"]; + if (value_qx.isArray()) + { + for (int idx = 0; idx < value_qx.size(); idx++) + { + std::string channel = value_qx[idx].asString(); + _config.ad_check.analysis_bind.second_channel_3s.push_back(channel); + } + } + } else { _config.ad_check.Init(); } } + return 0; }