From ee98ece5ff052f81b92372a70eed1ec4c84e12f6 Mon Sep 17 00:00:00 2001 From: liusiyang Date: Mon, 28 Sep 2026 17:01:51 +0800 Subject: [PATCH] =?UTF-8?q?feat=20=E5=BC=80=E6=94=BE=E5=85=B3=E8=81=94?= =?UTF-8?q?=E9=80=9A=E9=81=93=E7=BC=BA=E9=99=B7=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AlgorithmModule/include/ImageResultJudge.h | 2 +- AlgorithmModule/include/QX_Merge_Analysis.h | 12 +- AlgorithmModule/src/ImageResultJudge.cpp | 17 ++- AlgorithmModule/src/QX_Merge_Analysis.cpp | 126 ++++++++++++++------ ConfigModule/include/CheckConfigDefine.h | 5 + ConfigModule/src/JsonConfig.cpp | 11 ++ 6 files changed, 121 insertions(+), 52 deletions(-) diff --git a/AlgorithmModule/include/ImageResultJudge.h b/AlgorithmModule/include/ImageResultJudge.h index c574e1d..a8a0956 100644 --- a/AlgorithmModule/include/ImageResultJudge.h +++ b/AlgorithmModule/include/ImageResultJudge.h @@ -132,7 +132,7 @@ private: int AnalysisResult_Pre(QX_ERROR_INFO_ *QX_info); // 弱化处理 - // 关联通道脏污过滤:撤销与关联通道脏污重叠的暗点NG结果(含单图判定的单点NG) + // 关联过滤源过滤:撤销与关联通道过滤源缺陷重叠的暗点NG结果(含单图判定的单点NG) int FilterCorrelatedDirtyNG(std::shared_ptr pImageResult); ChannelCheckFunction *GetChannelFuntion(std::string strChannelName); // 获得 通道的检测功能 diff --git a/AlgorithmModule/include/QX_Merge_Analysis.h b/AlgorithmModule/include/QX_Merge_Analysis.h index 41b15d4..acd038a 100644 --- a/AlgorithmModule/include/QX_Merge_Analysis.h +++ b/AlgorithmModule/include/QX_Merge_Analysis.h @@ -174,10 +174,14 @@ public: bool Idx(int qxidx); bool AddQxInfo(int qxidx, QX_Info qxinfo, std::shared_ptr plog, std::shared_ptr pchannelLog); - // 登记关联通道(非主/次通道)的缺陷信息,如脏污(dirty),供 AD 绑定分析判断重叠缺陷 + // 登记关联通道(非主/次通道)的过滤源缺陷信息(类型由 correlated_types 配置, 如脏污/暗点),供 AD 分析判断重叠缺陷 bool AddCorrelatedQxInfo(Correlated_Qx_Info_ qxinfo, std::shared_ptr plog); - // 关联通道脏污重叠判断(供外部调用):当前缺陷ROI是否与关联通道脏污缺陷重叠 + // 判断缺陷类型是否为配置的关联过滤源类型(analysis_bind.correlated_types, 如 "Dirty_L0"/"Dirty_L1"/"Dirty_L2"/"AD") + // 配置为空时默认三种脏污; 登记与过滤两处共用此判定 + bool IsCorrelatedSourceConfigType(int nconfigType); + + // 关联通道过滤源重叠判断(供外部调用):当前缺陷ROI是否与关联通道过滤源缺陷(脏污/暗点等)重叠 bool IsDirtyOverlapInCorrelatedChannel(const std::string &cur_channel_name, const std::string &cur_camera_name, const cv::Rect &qx_product_roi, @@ -213,10 +217,10 @@ private: int Analysis_AD(ALL_Qx_DataList *pALLTypeqxList, int qx_idx); int Analysis_AD_Bind(ALL_Qx_DataList *pALLTypeqxList, int qx_idx); - // 关联通道脏污过滤:移除与关联通道脏污重叠的缺陷,使其不参与后续数量/距离/S分析 + // 关联过滤源过滤:移除与关联通道过滤源缺陷重叠的缺陷,使其不参与后续数量/距离/S分析 int FilterCorrelatedDirtyQx(ALL_Qx_DataList *pALLTypeqxList); - // 判断当前缺陷是否与关联通道(correlated_channels)中的脏污缺陷重叠 + // 判断当前缺陷是否与关联通道(correlated_channels)中的过滤源缺陷(correlated_types)重叠 bool IsOverlapDirtyInCorrelatedChannel(const std::vector &correlated_channels, const std::string &cur_channel_name, const std::string &cur_camera_name, diff --git a/AlgorithmModule/src/ImageResultJudge.cpp b/AlgorithmModule/src/ImageResultJudge.cpp index 21d2128..cc3ae72 100644 --- a/AlgorithmModule/src/ImageResultJudge.cpp +++ b/AlgorithmModule/src/ImageResultJudge.cpp @@ -748,10 +748,9 @@ int ImageResultJudge::ResultJudge(std::shared_ptr pImageResult) } } - // 关联通道分析:登记脏污(dirty)缺陷位置,供 AD 绑定分析判断关联通道是否存在重叠脏污缺陷 - if (config_qx_type == CONFIG_QX_NAME_Dirty_L0 || - config_qx_type == CONFIG_QX_NAME_Dirty_L1 || - config_qx_type == CONFIG_QX_NAME_Dirty_L2) + // 关联通道分析:登记关联过滤源缺陷位置(类型由 analysis_bind.correlated_types 配置, 如脏污/暗点), + // 供 AD 分析判断关联通道是否存在重叠缺陷 + if (m_pQX_Merge_Analysis->IsCorrelatedSourceConfigType(config_qx_type)) { QX_Merge_Analysis::Correlated_Qx_Info_ corr_qx; corr_qx.channel_name = pImageResult->strChannel; @@ -809,7 +808,7 @@ int ImageResultJudge::UpdateMergedet(std::shared_ptr pCheck_Result } /** - * @brief 关联通道脏污过滤:撤销与关联通道脏污缺陷重叠的暗点NG结果(含单图判定的单点NG) + * @brief 关联过滤源过滤:撤销与关联通道过滤源缺陷重叠的暗点NG结果(含单图判定的单点NG) * 被过滤的暗点不再计入NG * @param pImageResult 当前检测图片结果 * @return int 被过滤的缺陷个数 @@ -848,7 +847,7 @@ int ImageResultJudge::FilterCorrelatedDirtyNG(std::shared_ptr pI continue; } - // 关联通道存在与当前缺陷重叠的脏污缺陷时,过滤该暗点NG + // 关联通道存在与当前缺陷重叠的过滤源缺陷时,过滤该暗点NG cv::Rect product_roi = QX_info->roi; product_roi.x += fproduct_offx_piexl; if (!m_pQX_Merge_Analysis->IsDirtyOverlapInCorrelatedChannel(pImageResult->strChannel, @@ -903,14 +902,14 @@ int ImageResultJudge::FilterCorrelatedDirtyNG(std::shared_ptr pI if (pImageLog) { pImageLog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "DirtyCorrelatedFilter", - "img %s cam %s blob %d qx %s roi %s : 关联通道存在重叠脏污, 过滤该暗点NG", + "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", + "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()); } @@ -941,7 +940,7 @@ int ImageResultJudge::MergeResult(std::shared_ptr pImageResult, } int qxNum = pDetResult->pQx_ErrorList->size(); - // 关联通道脏污过滤:撤销与关联通道脏污重叠的暗点NG(含单图判定的单点NG) + // 关联过滤源过滤:撤销与关联通道过滤源缺陷重叠的暗点NG(含单图判定的单点NG) FilterCorrelatedDirtyNG(pImageResult); for (int iqx = 0; iqx < (int)ptemre->resultList.size(); iqx++) diff --git a/AlgorithmModule/src/QX_Merge_Analysis.cpp b/AlgorithmModule/src/QX_Merge_Analysis.cpp index c2689f4..941fc0c 100644 --- a/AlgorithmModule/src/QX_Merge_Analysis.cpp +++ b/AlgorithmModule/src/QX_Merge_Analysis.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "CheckUtil.hpp" #include "CheckConfigDefine.h" @@ -268,35 +269,83 @@ bool QX_Merge_Analysis::setSendStatus(std::string cameraName, RUN_STATUS_ status } /** - * @brief 判断缺陷配置类型是否为脏污(dirty) - * @param nconfigType 缺陷配置类型 CONFIG_QX_NAME_ - * @return bool 是脏污返回true + * @brief 关联过滤源类型名称转配置类型(如 "Dirty_L0" -> CONFIG_QX_NAME_Dirty_L0), 大小写不敏感 + * @param strTypeName 缺陷类型名称(CONFIG_QX_NAME_Names 中的名称) + * @return int 匹配的配置类型, 未匹配返回 -1 */ -static bool IsDirtyConfigType(int nconfigType) +static int CorrelatedTypeNameToConfigType(const std::string &strTypeName) { - return nconfigType == CONFIG_QX_NAME_Dirty_L0 || - nconfigType == CONFIG_QX_NAME_Dirty_L1 || - nconfigType == CONFIG_QX_NAME_Dirty_L2; + for (int i = 0; i < (int)CONFIG_QX_NAME_Names.size(); i++) + { + if (CheckUtil::compareIgnoreCase(strTypeName, CONFIG_QX_NAME_Names.at(i))) + { + return i; + } + } + return -1; } /** - * @brief 判断关联通道名称是否需要参与判断(为空或NONE则不参与) - * @param strChannelName 关联通道名称 + * @brief 判断关联配置名称是否需要参与判断(为空或NONE则不参与) + * @param strName 关联通道/缺陷类型名称 * @return bool 需要判断返回true */ -static bool IsValidCorrelatedChannel(const std::string &strChannelName) +static bool IsValidCorrelatedName(const std::string &strName) { - if (strChannelName == "") + if (strName == "") { return false; } - if (CheckUtil::compareIgnoreCase(strChannelName, "NONE")) + if (CheckUtil::compareIgnoreCase(strName, "NONE")) { return false; } return true; } +/** + * @brief 判断缺陷类型是否为配置的关联过滤源类型(analysis_bind.correlated_types, + * 如 "Dirty_L0"/"Dirty_L1"/"Dirty_L2"/"AD"), 登记与过滤两处共用此判定 + * 配置为空时兼容旧行为, 默认三种脏污 + * @param nconfigType 缺陷配置类型 CONFIG_QX_NAME_ + * @return bool 是过滤源返回true + */ +bool QX_Merge_Analysis::IsCorrelatedSourceConfigType(int nconfigType) +{ + // 防御:非法类型直接返回 + if (nconfigType < 0 || nconfigType >= CONFIG_QX_NAME_count) + { + return false; + } + + // 从配置读取过滤源类型名称并转换 + std::vector configTypes; + if (m_pbaseCheckFunction != nullptr) + { + const std::vector &typeNames = m_pbaseCheckFunction->ad_check.analysis_bind.correlated_types; + for (int i = 0; i < (int)typeNames.size(); i++) + { + if (!IsValidCorrelatedName(typeNames.at(i))) + { + continue; + } + int type = CorrelatedTypeNameToConfigType(typeNames.at(i)); + if (type >= 0) + { + configTypes.push_back(type); + } + } + } + + if (!configTypes.empty()) + { + return std::find(configTypes.begin(), configTypes.end(), nconfigType) != configTypes.end(); + } + + // 缺省过滤源(兼容旧配置):三种脏污 + return false; +} + bool QX_Merge_Analysis::AddCorrelatedQxInfo(Correlated_Qx_Info_ qxinfo, std::shared_ptr plog) { // 防御:通道为空或ROI非法时不登记,避免无效数据参与后续判断 @@ -351,14 +400,14 @@ bool QX_Merge_Analysis::IsOverlapDirtyInCorrelatedChannel(const std::vector dirtyList; + // 拷贝出需要比较的过滤源缺陷列表,避免在锁内做IoU计算 + std::vector sourceList; { std::lock_guard lock(mtx_correlatedQx); for (int i = 0; i < (int)correlated_channels.size(); i++) { const std::string &channel_name = correlated_channels.at(i); - if (!IsValidCorrelatedChannel(channel_name)) + if (!IsValidCorrelatedName(channel_name)) { continue; } @@ -369,15 +418,15 @@ bool QX_Merge_Analysis::IsOverlapDirtyInCorrelatedChannel(const std::vectorsecond.size(); j++) { - if (IsDirtyConfigType(it->second.at(j).config_qx_type)) + if (IsCorrelatedSourceConfigType(it->second.at(j).config_qx_type)) { - dirtyList.push_back(it->second.at(j)); + sourceList.push_back(it->second.at(j)); } } } } - if (dirtyList.empty()) + if (sourceList.empty()) { return false; } @@ -386,22 +435,22 @@ bool QX_Merge_Analysis::IsOverlapDirtyInCorrelatedChannel(const std::vectorAddCheckstr(PrintLevel_3, 3, "CorrelatedDirty", - "cur %s cam %s roi %s <-> dirty %s roi %s expand %d iou %f", + "cur %s cam %s roi %s <-> source %s roi %s expand %d iou %f", cur_channel_name.c_str(), cur_camera_name.c_str(), CheckUtil::GetRectString(qx_product_roi).c_str(), - dirtyList.at(i).channel_name.c_str(), - CheckUtil::GetRectString(dirty_roi).c_str(), + sourceList.at(i).channel_name.c_str(), + CheckUtil::GetRectString(source_roi).c_str(), roi_expand, fiou); } // IOU 为 NaN(ROI 非法导致的除零)时比较结果为 false,不会误抑制 NG @@ -410,11 +459,11 @@ bool QX_Merge_Analysis::IsOverlapDirtyInCorrelatedChannel(const std::vectorAddCheckstr(PrintLevel_1, 3, "CorrelatedDirty", - "cur %s cam %s roi %s overlap dirty %s cam %s roi %s expand %d iou %f > %f", + "cur %s cam %s roi %s overlap source %s cam %s roi %s expand %d iou %f > %f", cur_channel_name.c_str(), cur_camera_name.c_str(), CheckUtil::GetRectString(qx_product_roi).c_str(), - dirtyList.at(i).channel_name.c_str(), dirtyList.at(i).camera_name.c_str(), - CheckUtil::GetRectString(dirty_roi).c_str(), + sourceList.at(i).channel_name.c_str(), sourceList.at(i).camera_name.c_str(), + CheckUtil::GetRectString(source_roi).c_str(), roi_expand, fiou, iou_threshold); } return true; @@ -425,7 +474,7 @@ bool QX_Merge_Analysis::IsOverlapDirtyInCorrelatedChannel(const std::vectorpChannelDetlog) { pQXChannelList->pChannelDetlog->AddCheckstr(PrintLevel_1, 3, "DirtyCorrelatedFilter", - "channel %s cam %s blob %d roi %s : 关联通道存在重叠脏污, 过滤该暗点(不参与数量/距离分析)", + "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, @@ -500,7 +549,7 @@ int QX_Merge_Analysis::FilterCorrelatedDirtyQx(ALL_Qx_DataList *pALLTypeqxList) if (m_pMergedetlog) { m_pMergedetlog->AddCheckstr(PrintLevel_1, 3, "DirtyCorrelatedFilter", - "channel %s cam %s blob %d roi %s : 关联通道存在重叠脏污, 过滤该暗点(不参与数量/距离分析)", + "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, @@ -955,13 +1004,13 @@ 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 + // 关联过滤源过滤: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 个缺陷", + m_pMergedetlog->AddCheckstr(PrintLevel_1, 3, "DirtyCorrelatedFilter", "%s 关联通道过滤源过滤 %d 个缺陷", QX_ANALYSIS_NAME_Names[qx_idx].c_str(), nFilterNum); } } @@ -1454,8 +1503,9 @@ int QX_Merge_Analysis::Analysis_AD_Bind(ALL_Qx_DataList *pALLTypeqxList, int qx_ /* 获取关联通道(已在 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 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()); + m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "Analysis_AD_Bind", "bind main_2s %d second_2s %d main_3s %d second_3s %d correlated_channels %d correlated_types %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(), (int)pAd_checkParma->analysis_bind.correlated_types.size()); /* 获取主次通道的缺陷列表 */ vector main_channel_s_qxList; @@ -1776,7 +1826,7 @@ int QX_Merge_Analysis::Analysis_AD_Bind(ALL_Qx_DataList *pALLTypeqxList, int qx_ // 已经NG if (bNG) { - // 注:与关联通道脏污重叠的缺陷已在 FilterCorrelatedDirtyQx(AD分析前) 中过滤,此处不会再被记录NG + // 注:与关联通道过滤源缺陷重叠的缺陷已在 FilterCorrelatedDirtyQx(AD分析前) 中过滤,此处不会再被记录NG QX_channel_List *pqxList = pQXChannelList; for (int idx = 0; idx < (int)pqxList->qxList.size(); idx++) diff --git a/ConfigModule/include/CheckConfigDefine.h b/ConfigModule/include/CheckConfigDefine.h index 42c6e7a..f9d50a4 100644 --- a/ConfigModule/include/CheckConfigDefine.h +++ b/ConfigModule/include/CheckConfigDefine.h @@ -1587,6 +1587,9 @@ struct AD_Analysisy_Bind std::vector main_channel_3s; std::vector second_channel_3s; std::vector correlated_channels; + // 关联过滤源缺陷类型名称(CONFIG_QX_NAME_Names 中的名称, 如 "Dirty_L0"/"Dirty_L1"/"Dirty_L2"/"AD") + // 仅这些类型的缺陷会被登记为过滤源(与 correlated_channels 配合使用); 为空时默认三种脏污(兼容旧配置) + std::vector correlated_types; AD_Analysisy_Bind() { @@ -1600,6 +1603,7 @@ struct AD_Analysisy_Bind main_channel_3s.clear(); second_channel_3s.clear(); correlated_channels.clear(); + correlated_types.clear(); } void copy (AD_Analysisy_Bind tem) { @@ -1609,6 +1613,7 @@ struct AD_Analysisy_Bind this->main_channel_3s = tem.main_channel_3s; this->second_channel_3s = tem.second_channel_3s; this->correlated_channels = tem.correlated_channels; + this->correlated_types = tem.correlated_types; } std::string GetInfo(std::string str) { diff --git a/ConfigModule/src/JsonConfig.cpp b/ConfigModule/src/JsonConfig.cpp index 6c8a069..d09f1b0 100644 --- a/ConfigModule/src/JsonConfig.cpp +++ b/ConfigModule/src/JsonConfig.cpp @@ -1482,6 +1482,17 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value) } } + // 关联过滤源缺陷类型(如 ["Dirty_L0","Dirty_L1","Dirty_L2","AD"]) + value_qx = value_f["form"]["Bind_Channel"]["correlated_types"]; + if (value_qx.isArray()) + { + for (int idx = 0; idx < value_qx.size(); idx++) + { + std::string qx_type = value_qx[idx].asString(); + _config.ad_check.analysis_bind.correlated_types.push_back(qx_type); + } + } + // 同画面分析 value_qx = value_f["form"]["Single_Channel"]["s_channel"]; if (value_qx.isArray())