|
|
|
@ -303,6 +303,29 @@ static bool IsValidCorrelatedName(const std::string &strName)
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @brief 判断通道名是否在通道列表中(忽略大小写)
|
|
|
|
|
|
|
|
* 通道配置由人工填写(如 "Blue" 与实际通道名 "BLUE"),大小写敏感匹配会漏掉应参与的通道
|
|
|
|
|
|
|
|
* @param channels 通道列表
|
|
|
|
|
|
|
|
* @param channelName 待判断的通道名
|
|
|
|
|
|
|
|
* @return bool 在列表中返回true
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
static bool IsChannelInList(const std::vector<std::string> &channels, const std::string &channelName)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (channelName.empty())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < (int)channels.size(); i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (CheckUtil::compareIgnoreCase(channels.at(i), channelName))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* @brief 判断缺陷类型是否为配置的关联过滤源类型(analysis_bind.correlated_types,
|
|
|
|
* @brief 判断缺陷类型是否为配置的关联过滤源类型(analysis_bind.correlated_types,
|
|
|
|
* 如 "Dirty_L0"/"Dirty_L1"/"Dirty_L2"/"AD"), 登记与过滤两处共用此判定
|
|
|
|
* 如 "Dirty_L0"/"Dirty_L1"/"Dirty_L2"/"AD"), 登记与过滤两处共用此判定
|
|
|
|
@ -712,7 +735,7 @@ int QX_Merge_Analysis::Analysis_single_Config(QXAnalysis_Config *pconfig, QX_cha
|
|
|
|
if (qx_type == QX_ANALYSIS_AD && m_pbaseCheckFunction)
|
|
|
|
if (qx_type == QX_ANALYSIS_AD && m_pbaseCheckFunction)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
std::vector<std::string> merge_analysy_region_sf = m_pbaseCheckFunction->ad_check.analysis_sf.region_sf;
|
|
|
|
std::vector<std::string> merge_analysy_region_sf = m_pbaseCheckFunction->ad_check.analysis_sf.region_sf;
|
|
|
|
if (std::find(merge_analysy_region_sf.begin(), merge_analysy_region_sf.end(), pqxList->channel_name) == merge_analysy_region_sf.end())
|
|
|
|
if (!IsChannelInList(merge_analysy_region_sf, pqxList->channel_name))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
pchannelLog->AddCheckstr(PrintLevel_1, 3, "Analysis_single_Config", "merge_analysy_region_sf not found %s --> skip", pqxList->channel_name.c_str());
|
|
|
|
pchannelLog->AddCheckstr(PrintLevel_1, 3, "Analysis_single_Config", "merge_analysy_region_sf not found %s --> skip", pqxList->channel_name.c_str());
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
@ -999,6 +1022,57 @@ int QX_Merge_Analysis::Analysis_single_Config(QXAnalysis_Config *pconfig, QX_cha
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @brief 绑定分析的主通道是否未配置(2s 或 3s 的主通道列表为空)
|
|
|
|
|
|
|
|
* 只按配置判断,与本次产品是否检出缺陷无关:良品主通道本来就没暗点,
|
|
|
|
|
|
|
|
* 若按“本次无匹配通道”判定回退,则每个良品都会回退,把次通道噪声直接判成 NG
|
|
|
|
|
|
|
|
* @return bool 需要回退用次通道走 Analysis_AD 老逻辑返回true
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool QX_Merge_Analysis::IsADBindMainChannelConfigEmpty()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (m_pbaseCheckFunction == nullptr)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
const AD_Analysisy_Bind &bind = m_pbaseCheckFunction->ad_check.analysis_bind;
|
|
|
|
|
|
|
|
// 2s/3s 任一主通道未配置,就无法完成对应的绑定判定,整体回退
|
|
|
|
|
|
|
|
return bind.main_channel_2s.empty() || bind.main_channel_3s.empty();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @brief 取绑定分析的次通道列表(second_channel_2s + second_channel_3s)
|
|
|
|
|
|
|
|
* 去重忽略大小写,并过滤空名
|
|
|
|
|
|
|
|
* @return std::vector<std::string> 次通道名列表
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
std::vector<std::string> QX_Merge_Analysis::GetADBindSecondChannels()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
std::vector<std::string> channels;
|
|
|
|
|
|
|
|
if (m_pbaseCheckFunction == nullptr)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return channels;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
const AD_Analysisy_Bind &bind = m_pbaseCheckFunction->ad_check.analysis_bind;
|
|
|
|
|
|
|
|
const std::vector<std::string> *pListArr[2] = {&bind.second_channel_2s, &bind.second_channel_3s};
|
|
|
|
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
const std::vector<std::string> &channelList = *pListArr[i];
|
|
|
|
|
|
|
|
for (int j = 0; j < (int)channelList.size(); j++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
const std::string &channelName = channelList.at(j);
|
|
|
|
|
|
|
|
if (channelName.empty())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// 2s/3s 重复配同一通道时只保留一份
|
|
|
|
|
|
|
|
if (!IsChannelInList(channels, channelName))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
channels.push_back(channelName);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return channels;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int QX_Merge_Analysis::Analysis_QXtype(ALL_Qx_DataList *pALLTypeqxList, int qx_idx)
|
|
|
|
int QX_Merge_Analysis::Analysis_QXtype(ALL_Qx_DataList *pALLTypeqxList, int qx_idx)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
@ -1021,17 +1095,41 @@ int QX_Merge_Analysis::Analysis_QXtype(ALL_Qx_DataList *pALLTypeqxList, int qx_i
|
|
|
|
Analysis_Channel(pQXChannelList, qx_idx);
|
|
|
|
Analysis_Channel(pQXChannelList, qx_idx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// AD 要进行额外的分析
|
|
|
|
// AD 要进行额外的分析
|
|
|
|
if (qx_idx == QX_ANALYSIS_AD)
|
|
|
|
if (qx_idx == QX_ANALYSIS_AD && m_pbaseCheckFunction != nullptr)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if(m_pbaseCheckFunction->ad_check.analysis_bind.bUse)
|
|
|
|
if (m_pbaseCheckFunction->ad_check.analysis_bind.bUse)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Analysis_AD_Bind(pALLTypeqxList, qx_idx);
|
|
|
|
if (IsADBindMainChannelConfigEmpty())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// 主通道未配置(2s 或 3s 的主通道列表为空):无法做绑定判定,
|
|
|
|
|
|
|
|
// 回退用次通道列表走 Analysis_AD 老逻辑(产品级数量/距离/S 分析)。
|
|
|
|
|
|
|
|
// 关联通道过滤(FilterCorrelatedDirtyQx)已在上面执行,回退路径同样受其保护。
|
|
|
|
|
|
|
|
std::vector<std::string> fallback_channels = GetADBindSecondChannels();
|
|
|
|
|
|
|
|
std::string strFallbackChannels;
|
|
|
|
|
|
|
|
for (int k = 0; k < (int)fallback_channels.size(); k++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (k > 0)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
strFallbackChannels += ",";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
strFallbackChannels += fallback_channels.at(k);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
m_pMergedetlog->AddCheckstr(PrintLevel_1, 3, "Analysis_AD_Bind",
|
|
|
|
|
|
|
|
"main channel config empty(main_2s %d main_3s %d) --> fallback Analysis_AD (only second channels: %s)",
|
|
|
|
|
|
|
|
(int)m_pbaseCheckFunction->ad_check.analysis_bind.main_channel_2s.size(),
|
|
|
|
|
|
|
|
(int)m_pbaseCheckFunction->ad_check.analysis_bind.main_channel_3s.size(),
|
|
|
|
|
|
|
|
fallback_channels.empty() ? "<empty>" : strFallbackChannels.c_str());
|
|
|
|
|
|
|
|
Analysis_AD(pALLTypeqxList, qx_idx, &fallback_channels);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Analysis_AD_Bind(pALLTypeqxList, qx_idx);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
else
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Analysis_AD(pALLTypeqxList, qx_idx);
|
|
|
|
Analysis_AD(pALLTypeqxList, qx_idx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
@ -1073,7 +1171,7 @@ int QX_Merge_Analysis::Judge_NG_Config()
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int QX_Merge_Analysis::Analysis_AD(ALL_Qx_DataList *pALLTypeqxList, int qx_idx)
|
|
|
|
int QX_Merge_Analysis::Analysis_AD(ALL_Qx_DataList *pALLTypeqxList, int qx_idx, const std::vector<std::string> *pAllowChannels)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
AD_list.clear();
|
|
|
|
AD_list.clear();
|
|
|
|
if (!m_pbaseCheckFunction)
|
|
|
|
if (!m_pbaseCheckFunction)
|
|
|
|
@ -1081,6 +1179,15 @@ int QX_Merge_Analysis::Analysis_AD(ALL_Qx_DataList *pALLTypeqxList, int qx_idx)
|
|
|
|
return 1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 回退模式(主通道未配置)且次通道也没配置:没有任何通道可参与,直接返回,
|
|
|
|
|
|
|
|
// 避免“空允许列表导致所有通道被 skip”的隐晦行为
|
|
|
|
|
|
|
|
if (pAllowChannels != nullptr && pAllowChannels->empty())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
m_pMergedetlog->AddCheckstr(PrintLevel_1, 3, "Analysis_AD",
|
|
|
|
|
|
|
|
"fallback allow list(second channels) is empty --> skip AD analysis");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Base_Function_AD_Check *pAd_checkParma = &m_pbaseCheckFunction->ad_check;
|
|
|
|
Base_Function_AD_Check *pAd_checkParma = &m_pbaseCheckFunction->ad_check;
|
|
|
|
|
|
|
|
|
|
|
|
int product_AD_num = 0; // 整个产品的 暗点数目。
|
|
|
|
int product_AD_num = 0; // 整个产品的 暗点数目。
|
|
|
|
@ -1092,6 +1199,17 @@ int QX_Merge_Analysis::Analysis_AD(ALL_Qx_DataList *pALLTypeqxList, int qx_idx)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
QX_channel_List *pQXChannelList = &pALLTypeqxList->channelqxList[i];
|
|
|
|
QX_channel_List *pQXChannelList = &pALLTypeqxList->channelqxList[i];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 回退模式:只允许次通道列表内的通道参与分析(忽略大小写)
|
|
|
|
|
|
|
|
if (pAllowChannels != nullptr && !IsChannelInList(*pAllowChannels, pQXChannelList->channel_name))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (pQXChannelList->pChannelDetlog)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
pQXChannelList->pChannelDetlog->AddCheckstr(PrintLevel_1, 3, "Analysis_AD",
|
|
|
|
|
|
|
|
"channel %s not in fallback allow list(second channels) --> skip",
|
|
|
|
|
|
|
|
pQXChannelList->channel_name.c_str());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
if (!pAd_checkParma)
|
|
|
|
if (!pAd_checkParma)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
@ -1336,6 +1454,17 @@ int QX_Merge_Analysis::Analysis_AD(ALL_Qx_DataList *pALLTypeqxList, int qx_idx)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
QX_channel_List *pQXChannelList = &pALLTypeqxList->channelqxList[i];
|
|
|
|
QX_channel_List *pQXChannelList = &pALLTypeqxList->channelqxList[i];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 回退模式:只允许次通道列表内的通道被判定NG(忽略大小写)
|
|
|
|
|
|
|
|
if (pAllowChannels != nullptr && !IsChannelInList(*pAllowChannels, pQXChannelList->channel_name))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (pQXChannelList->pChannelDetlog)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
pQXChannelList->pChannelDetlog->AddCheckstr(PrintLevel_1, 3, "Analysis_AD",
|
|
|
|
|
|
|
|
"channel %s not in fallback allow list(second channels) --> skip NG mark",
|
|
|
|
|
|
|
|
pQXChannelList->channel_name.c_str());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
if (!pAd_checkParma->bOpen)
|
|
|
|
if (!pAd_checkParma->bOpen)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
@ -1531,13 +1660,15 @@ int QX_Merge_Analysis::Analysis_AD_Bind(ALL_Qx_DataList *pALLTypeqxList, int qx_
|
|
|
|
|
|
|
|
|
|
|
|
string cur_channel_name = pQXChannelList->channel_name;
|
|
|
|
string cur_channel_name = pQXChannelList->channel_name;
|
|
|
|
|
|
|
|
|
|
|
|
if (std::find(main_channel_2s.begin(), main_channel_2s.end(), cur_channel_name) != main_channel_2s.end() ||
|
|
|
|
// 通道名忽略大小写匹配:配置由人工填写(如 "Blue" 而实际通道是 "BLUE"),
|
|
|
|
std::find(main_channel_3s.begin(), main_channel_3s.end(), cur_channel_name) != main_channel_3s.end())
|
|
|
|
// 大小写敏感匹配会让应参与的通道被静默排除
|
|
|
|
|
|
|
|
if (IsChannelInList(main_channel_2s, cur_channel_name) ||
|
|
|
|
|
|
|
|
IsChannelInList(main_channel_3s, cur_channel_name))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
main_channel_s_qxList.push_back(pALLTypeqxList->channelqxList[i]);
|
|
|
|
main_channel_s_qxList.push_back(pALLTypeqxList->channelqxList[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (std::find(second_channel_2s.begin(), second_channel_2s.end(), cur_channel_name) != second_channel_2s.end() ||
|
|
|
|
if (IsChannelInList(second_channel_2s, cur_channel_name) ||
|
|
|
|
std::find(second_channel_3s.begin(), second_channel_3s.end(), cur_channel_name) != second_channel_3s.end())
|
|
|
|
IsChannelInList(second_channel_3s, cur_channel_name))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
second_channel_s_qxList.push_back(pALLTypeqxList->channelqxList[i]);
|
|
|
|
second_channel_s_qxList.push_back(pALLTypeqxList->channelqxList[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -1640,13 +1771,13 @@ int QX_Merge_Analysis::Analysis_AD_Bind(ALL_Qx_DataList *pALLTypeqxList, int qx_
|
|
|
|
// roi_expand, fiou);
|
|
|
|
// roi_expand, fiou);
|
|
|
|
if (fiou > pAd_checkParma->analysis_iou.AD_IOU)
|
|
|
|
if (fiou > pAd_checkParma->analysis_iou.AD_IOU)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (std::find(second_channel_2s.begin(), second_channel_2s.end(), second_channel_name) != second_channel_2s.end())
|
|
|
|
if (IsChannelInList(second_channel_2s, second_channel_name))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
tmp_main_qxInfo.s_name_2.push_back(second_channel_name);
|
|
|
|
tmp_main_qxInfo.s_name_2.push_back(second_channel_name);
|
|
|
|
m_pMergedetlog->AddCheckstr(PrintLevel_3, 3, "Add 2s", "%s roi1 %s roi2 %s expand %d iou %f",
|
|
|
|
m_pMergedetlog->AddCheckstr(PrintLevel_3, 3, "Add 2s", "%s roi1 %s roi2 %s expand %d iou %f",
|
|
|
|
second_channel_name.c_str(), CheckUtil::GetRectString(roi_main).c_str(),CheckUtil::GetRectString(roi_second).c_str(),roi_expand, fiou);
|
|
|
|
second_channel_name.c_str(), CheckUtil::GetRectString(roi_main).c_str(),CheckUtil::GetRectString(roi_second).c_str(),roi_expand, fiou);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(std::find(second_channel_3s.begin(), second_channel_3s.end(), second_channel_name) != second_channel_3s.end())
|
|
|
|
if(IsChannelInList(second_channel_3s, second_channel_name))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
tmp_main_qxInfo.s_name_3.push_back(second_channel_name);
|
|
|
|
tmp_main_qxInfo.s_name_3.push_back(second_channel_name);
|
|
|
|
m_pMergedetlog->AddCheckstr(PrintLevel_3, 3, "Add 3s", "%s roi1 %s roi2 %s expand %d iou %f",
|
|
|
|
m_pMergedetlog->AddCheckstr(PrintLevel_3, 3, "Add 3s", "%s roi1 %s roi2 %s expand %d iou %f",
|
|
|
|
@ -1724,7 +1855,7 @@ int QX_Merge_Analysis::Analysis_AD_Bind(ALL_Qx_DataList *pALLTypeqxList, int qx_
|
|
|
|
{
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(std::find(merge_analysy_s_sf.begin(), merge_analysy_s_sf.end(), pQXChannelList->channel_name) != merge_analysy_s_sf.end())
|
|
|
|
if (IsChannelInList(merge_analysy_s_sf, pQXChannelList->channel_name))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
else
|
|
|
|
|