From cd8aa0f4929d095c38efab803bcabe8ace8062ba Mon Sep 17 00:00:00 2001 From: liusiyang Date: Tue, 22 Sep 2026 15:10:47 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E4=BF=AE=E6=94=B9=E8=84=8F=E6=B1=A1?= =?UTF-8?q?=E8=BF=87=E6=BB=A4=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AlgorithmModule/include/ImageResultJudge.h | 3 + AlgorithmModule/include/QX_Merge_Analysis.h | 9 ++ AlgorithmModule/src/ImageResultJudge.cpp | 115 +++++++++++++++++ AlgorithmModule/src/QX_Merge_Analysis.cpp | 135 +++++++++++++++----- 4 files changed, 233 insertions(+), 29 deletions(-) diff --git a/AlgorithmModule/include/ImageResultJudge.h b/AlgorithmModule/include/ImageResultJudge.h index 84c43cf..c574e1d 100644 --- a/AlgorithmModule/include/ImageResultJudge.h +++ b/AlgorithmModule/include/ImageResultJudge.h @@ -132,6 +132,9 @@ private: int AnalysisResult_Pre(QX_ERROR_INFO_ *QX_info); // 弱化处理 + // 关联通道脏污过滤:撤销与关联通道脏污重叠的暗点NG结果(含单图判定的单点NG) + int FilterCorrelatedDirtyNG(std::shared_ptr pImageResult); + ChannelCheckFunction *GetChannelFuntion(std::string strChannelName); // 获得 通道的检测功能 int ConfigTypeToQXAnalysis(int nconfigType); diff --git a/AlgorithmModule/include/QX_Merge_Analysis.h b/AlgorithmModule/include/QX_Merge_Analysis.h index 2614db9..41b15d4 100644 --- a/AlgorithmModule/include/QX_Merge_Analysis.h +++ b/AlgorithmModule/include/QX_Merge_Analysis.h @@ -177,6 +177,12 @@ public: // 登记关联通道(非主/次通道)的缺陷信息,如脏污(dirty),供 AD 绑定分析判断重叠缺陷 bool AddCorrelatedQxInfo(Correlated_Qx_Info_ qxinfo, std::shared_ptr plog); + // 关联通道脏污重叠判断(供外部调用):当前缺陷ROI是否与关联通道脏污缺陷重叠 + bool IsDirtyOverlapInCorrelatedChannel(const std::string &cur_channel_name, + const std::string &cur_camera_name, + const cv::Rect &qx_product_roi, + std::shared_ptr plog); + bool setSendStatus(std::string cameraName, RUN_STATUS_ status); bool waitComplete(int timeoutMs = 15000); @@ -207,6 +213,9 @@ private: int Analysis_AD(ALL_Qx_DataList *pALLTypeqxList, int qx_idx); int Analysis_AD_Bind(ALL_Qx_DataList *pALLTypeqxList, int qx_idx); + // 关联通道脏污过滤:移除与关联通道脏污重叠的缺陷,使其不参与后续数量/距离/S分析 + int FilterCorrelatedDirtyQx(ALL_Qx_DataList *pALLTypeqxList); + // 判断当前缺陷是否与关联通道(correlated_channels)中的脏污缺陷重叠 bool IsOverlapDirtyInCorrelatedChannel(const std::vector &correlated_channels, const std::string &cur_channel_name, diff --git a/AlgorithmModule/src/ImageResultJudge.cpp b/AlgorithmModule/src/ImageResultJudge.cpp index 018d247..21d2128 100644 --- a/AlgorithmModule/src/ImageResultJudge.cpp +++ b/AlgorithmModule/src/ImageResultJudge.cpp @@ -1,5 +1,6 @@ #include "ImageResultJudge.h" +#include ImageResultJudge::ImageResultJudge(/* args */) { @@ -807,6 +808,117 @@ int ImageResultJudge::UpdateMergedet(std::shared_ptr pCheck_Result return 0; } +/** + * @brief 关联通道脏污过滤:撤销与关联通道脏污缺陷重叠的暗点NG结果(含单图判定的单点NG) + * 被过滤的暗点不再计入NG + * @param pImageResult 当前检测图片结果 + * @return int 被过滤的缺陷个数 + */ +int ImageResultJudge::FilterCorrelatedDirtyNG(std::shared_ptr pImageResult) +{ + if (pImageResult == nullptr || pImageResult->cameraBaseResult == nullptr || + m_pbaseCheckFunction == nullptr || m_pQX_Merge_Analysis == nullptr || m_pAnalysisyConfig == nullptr) + { + return 0; + } + // 未配置关联通道(NONE/空)时不需要判断 + std::vector correlated_channels = m_pbaseCheckFunction->ad_check.analysis_bind.correlated_channels; + if (correlated_channels.empty()) + { + return 0; + } + std::shared_ptr pDetResult = pImageResult->pDetResult; // 检测结果 + std::shared_ptr m_CheckResult_shareP = pImageResult->result; // 返回结果 + if (pDetResult == nullptr || pDetResult->pQx_ErrorList == nullptr || m_CheckResult_shareP == nullptr) + { + return 0; + } + + std::shared_ptr pImageLog = pImageResult->detlog; + float fproduct_offx_mm = m_pAnalysisyConfig->commonCheckConfig.baseConfig.fProduct_Off_X_mm; + int fproduct_offx_piexl = int(fproduct_offx_mm / m_fImgage_Scale_X); + + int nFilterNum = 0; + for (int qxidx = 0; qxidx < (int)pDetResult->pQx_ErrorList->size(); qxidx++) + { + QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx); + // 只处理 暗点(AD) 的 NG 结果 + if (QX_info->nconfig_qx_type != CONFIG_QX_NAME_AD || QX_info->result != QX_RESULT_TYPE_NG) + { + continue; + } + + // 关联通道存在与当前缺陷重叠的脏污缺陷时,过滤该暗点NG + cv::Rect product_roi = QX_info->roi; + product_roi.x += fproduct_offx_piexl; + if (!m_pQX_Merge_Analysis->IsDirtyOverlapInCorrelatedChannel(pImageResult->strChannel, + pImageResult->cameraBaseResult->strCameraName, + product_roi, + pImageLog)) + { + continue; + } + + // 撤销NG结果 + QX_info->result = QX_RESULT_TYPE_OK; + QX_info->result_name = QX_RESULT_TYPE_Names[QX_info->result]; + int nqx_type = ConfigTypeToResultType(QX_info->nconfig_qx_type); + + // 移除该缺陷的NG小图 + int nEraseNum = 0; + for (auto it = m_CheckResult_shareP->qxImageResult.begin(); it != m_CheckResult_shareP->qxImageResult.end();) + { + if (it->idx == qxidx) + { + it = m_CheckResult_shareP->qxImageResult.erase(it); + nEraseNum++; + } + else + { + ++it; + } + } + + // 计数回退 + if (nqx_type >= 0 && nqx_type < ERROR_TYPE_COUNT) + { + m_CheckResult_shareP->defectResultList[nqx_type].num -= nEraseNum; + if (m_CheckResult_shareP->defectResultList[nqx_type].num < 0) + { + m_CheckResult_shareP->defectResultList[nqx_type].num = 0; + } + } + if (pImageResult->NG_num > 0) + { + pImageResult->NG_num--; + } + pImageResult->Ok_num++; + // 过滤后已无NG,则恢复图片结果 + if (m_CheckResult_shareP->qxImageResult.empty()) + { + m_CheckResult_shareP->nresult = ERROR_TYPE_OK; + } + + nFilterNum++; + if (pImageLog) + { + pImageLog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "DirtyCorrelatedFilter", + "img %s cam %s blob %d qx %s roi %s : 关联通道存在重叠脏污, 过滤该暗点NG", + pImageResult->strChannel.c_str(), pImageResult->cameraBaseResult->strCameraName.c_str(), + qxidx, QX_info->qx_name.c_str(), CheckUtil::GetRectString(product_roi).c_str()); + } + if (m_pQX_Merge_Analysis->m_pMergedetlog) + { + m_pQX_Merge_Analysis->m_pMergedetlog->AddCheckstr(PrintLevel_1, 3, "DirtyCorrelatedFilter", + "img %s cam %s blob %d qx %s roi %s : 关联通道存在重叠脏污, 过滤该暗点NG", + pImageResult->strChannel.c_str(), pImageResult->cameraBaseResult->strCameraName.c_str(), + qxidx, QX_info->qx_name.c_str(), CheckUtil::GetRectString(product_roi).c_str()); + } + } + + return nFilterNum; +} + int ImageResultJudge::MergeResult(std::shared_ptr pImageResult, QX_Analysis_Result_List *ptemre) { @@ -829,6 +941,9 @@ int ImageResultJudge::MergeResult(std::shared_ptr pImageResult, } int qxNum = pDetResult->pQx_ErrorList->size(); + // 关联通道脏污过滤:撤销与关联通道脏污重叠的暗点NG(含单图判定的单点NG) + FilterCorrelatedDirtyNG(pImageResult); + for (int iqx = 0; iqx < (int)ptemre->resultList.size(); iqx++) { if (ptemre->resultList.at(iqx).channel_name != pImageResult->strChannel || diff --git a/AlgorithmModule/src/QX_Merge_Analysis.cpp b/AlgorithmModule/src/QX_Merge_Analysis.cpp index 34ac7a4..c2689f4 100644 --- a/AlgorithmModule/src/QX_Merge_Analysis.cpp +++ b/AlgorithmModule/src/QX_Merge_Analysis.cpp @@ -424,6 +424,98 @@ bool QX_Merge_Analysis::IsOverlapDirtyInCorrelatedChannel(const std::vector plog) +{ + if (m_pbaseCheckFunction == nullptr) + { + return false; + } + Base_Function_AD_Check *pAd_checkParma = &m_pbaseCheckFunction->ad_check; + const std::vector &correlated_channels = pAd_checkParma->analysis_bind.correlated_channels; + const int roi_expand = (int)(round)(pAd_checkParma->analysis_iou.AD_Expand); + const float iou_threshold = pAd_checkParma->analysis_iou.AD_IOU; + + return IsOverlapDirtyInCorrelatedChannel(correlated_channels, cur_channel_name, cur_camera_name, + qx_product_roi, roi_expand, iou_threshold, plog); +} + +/** + * @brief 关联通道脏污过滤:将与该通道内关联通道脏污缺陷重叠的缺陷从列表中移除, + * 使其不参与后续数量/距离/S分析,也不会被判为NG + * @param pALLTypeqxList 当前缺陷类型的缺陷列表 + * @return int 被过滤的缺陷个数 + */ +int QX_Merge_Analysis::FilterCorrelatedDirtyQx(ALL_Qx_DataList *pALLTypeqxList) +{ + if (m_pbaseCheckFunction == nullptr || pALLTypeqxList == nullptr) + { + return 0; + } + Base_Function_AD_Check *pAd_checkParma = &m_pbaseCheckFunction->ad_check; + const std::vector correlated_channels = pAd_checkParma->analysis_bind.correlated_channels; + // 未配置关联通道(NONE/空)时不需要过滤 + if (correlated_channels.empty()) + { + return 0; + } + const int roi_expand = (int)(round)(pAd_checkParma->analysis_iou.AD_Expand); + const float iou_threshold = pAd_checkParma->analysis_iou.AD_IOU; + + int nFilterNum = 0; + for (int i = 0; i < (int)pALLTypeqxList->channelqxList.size(); i++) + { + QX_channel_List *pQXChannelList = &pALLTypeqxList->channelqxList[i]; + std::vector temQxList; + temQxList.reserve(pQXChannelList->qxList.size()); + for (int j = 0; j < (int)pQXChannelList->qxList.size(); j++) + { + if (IsOverlapDirtyInCorrelatedChannel(correlated_channels, + pQXChannelList->qxList.at(j).channel_name, + pQXChannelList->qxList.at(j).camera_name, + pQXChannelList->qxList.at(j).product_roi, + roi_expand, iou_threshold, + pQXChannelList->pChannelDetlog)) + { + nFilterNum++; + if (pQXChannelList->pChannelDetlog) + { + pQXChannelList->pChannelDetlog->AddCheckstr(PrintLevel_1, 3, "DirtyCorrelatedFilter", + "channel %s cam %s blob %d roi %s : 关联通道存在重叠脏污, 过滤该暗点(不参与数量/距离分析)", + pQXChannelList->qxList.at(j).channel_name.c_str(), + pQXChannelList->qxList.at(j).camera_name.c_str(), + pQXChannelList->qxList.at(j).blobIdx, + CheckUtil::GetRectString(pQXChannelList->qxList.at(j).product_roi).c_str()); + } + if (m_pMergedetlog) + { + m_pMergedetlog->AddCheckstr(PrintLevel_1, 3, "DirtyCorrelatedFilter", + "channel %s cam %s blob %d roi %s : 关联通道存在重叠脏污, 过滤该暗点(不参与数量/距离分析)", + pQXChannelList->qxList.at(j).channel_name.c_str(), + pQXChannelList->qxList.at(j).camera_name.c_str(), + pQXChannelList->qxList.at(j).blobIdx, + CheckUtil::GetRectString(pQXChannelList->qxList.at(j).product_roi).c_str()); + } + continue; + } + temQxList.push_back(pQXChannelList->qxList.at(j)); + } + pQXChannelList->qxList.swap(temQxList); + } + + return nFilterNum; +} + /** * @brief 等待所有任务完成 * @param timeoutMs 超时时间(毫秒) @@ -863,6 +955,16 @@ int QX_Merge_Analysis::Analysis_QXtype(ALL_Qx_DataList *pALLTypeqxList, int qx_i m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "Num And Dis Judge", "pALLTypeqxList->channelqxList.size() %ld", pALLTypeqxList->channelqxList.size()); + // 关联通道脏污过滤:AD 分析前先过滤与关联通道脏污重叠的缺陷,使其不参与数量/距离/S分析,也不会被判NG + if (qx_idx == QX_ANALYSIS_AD) + { + int nFilterNum = FilterCorrelatedDirtyQx(pALLTypeqxList); + if (nFilterNum > 0) + { + m_pMergedetlog->AddCheckstr(PrintLevel_1, 3, "DirtyCorrelatedFilter", "%s 关联通道脏污过滤 %d 个缺陷", + QX_ANALYSIS_NAME_Names[qx_idx].c_str(), nFilterNum); + } + } for (int i = 0; i < pALLTypeqxList->channelqxList.size(); i++) { QX_channel_List *pQXChannelList = &pALLTypeqxList->channelqxList[i]; @@ -1349,11 +1451,11 @@ int QX_Merge_Analysis::Analysis_AD_Bind(ALL_Qx_DataList *pALLTypeqxList, int qx_ vector second_channel_2s = pAd_checkParma->analysis_bind.second_channel_2s; vector main_channel_3s = pAd_checkParma->analysis_bind.main_channel_3s; vector second_channel_3s = pAd_checkParma->analysis_bind.second_channel_3s; - /* 获取关联通道 */ + /* 获取关联通道(已在 Analysis_QXtype 的过滤阶段使用, 此处仅打印) */ vector correlated_channels = pAd_checkParma->analysis_bind.correlated_channels; - m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "Analysis_AD_Bind", "bind main_2s %d second_2s %d main_3s %d second_3s %d", - (int)main_channel_2s.size(), (int)second_channel_2s.size(), (int)main_channel_3s.size(), (int)second_channel_3s.size()); + m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "Analysis_AD_Bind", "bind main_2s %d second_2s %d main_3s %d second_3s %d correlated %d", + (int)main_channel_2s.size(), (int)second_channel_2s.size(), (int)main_channel_3s.size(), (int)second_channel_3s.size(), (int)correlated_channels.size()); /* 获取主次通道的缺陷列表 */ vector main_channel_s_qxList; @@ -1674,9 +1776,7 @@ int QX_Merge_Analysis::Analysis_AD_Bind(ALL_Qx_DataList *pALLTypeqxList, int qx_ // 已经NG if (bNG) { - // 注意:按缺陷(blob)粒度逐条判断,避免把同一通道内与脏污无关的缺陷也一并放过 - const int roi_expand = (int)(round)(pAd_checkParma->analysis_iou.AD_Expand); - const float iou_threshold = pAd_checkParma->analysis_iou.AD_IOU; + // 注:与关联通道脏污重叠的缺陷已在 FilterCorrelatedDirtyQx(AD分析前) 中过滤,此处不会再被记录NG QX_channel_List *pqxList = pQXChannelList; for (int idx = 0; idx < (int)pqxList->qxList.size(); idx++) @@ -1686,29 +1786,6 @@ int QX_Merge_Analysis::Analysis_AD_Bind(ALL_Qx_DataList *pALLTypeqxList, int qx_ continue; } - // 关联通道存在与当前缺陷重叠的脏污缺陷时,该缺陷不记录NG结果 - if (IsOverlapDirtyInCorrelatedChannel(correlated_channels, - pqxList->qxList.at(idx).channel_name, - pqxList->qxList.at(idx).camera_name, - pqxList->qxList.at(idx).product_roi, - roi_expand, iou_threshold, - pqxList->pChannelDetlog)) - { - pqxList->pChannelDetlog->AddCheckstr(PrintLevel_1, 3, "result = NG skip", - "channel %s cam %s blob %d roi %s : 关联通道存在重叠, 不记录NG结果", - pqxList->qxList.at(idx).channel_name.c_str(), - pqxList->qxList.at(idx).camera_name.c_str(), - pqxList->qxList.at(idx).blobIdx, - CheckUtil::GetRectString(pqxList->qxList.at(idx).product_roi).c_str()); - m_pMergedetlog->AddCheckstr(PrintLevel_1, 3, "result = NG skip", - "channel %s cam %s blob %d roi %s : 关联通道存在重叠, 不记录NG结果", - pqxList->qxList.at(idx).channel_name.c_str(), - pqxList->qxList.at(idx).camera_name.c_str(), - pqxList->qxList.at(idx).blobIdx, - CheckUtil::GetRectString(pqxList->qxList.at(idx).product_roi).c_str()); - continue; - } - pqxList->qxList.at(idx).result = 1; QX_RESULT tem;