feat 完善盲失过滤规则

dev_lsy
liusiyang 1 week ago
parent e80cae3e60
commit 3741c2282d

@ -107,6 +107,10 @@ public:
int UpdateConfig(std::string strcameraName); int UpdateConfig(std::string strcameraName);
int DrawResult(std::shared_ptr<ImageAllResult> pImageResult); int DrawResult(std::shared_ptr<ImageAllResult> pImageResult);
// 盲失联合判断:主通道(ms_main_channel)检出的盲失(Other)若在过滤通道(ms_filter_channels)同位置存在缺陷,
// 则不算盲失(撤销NG)。同位置判断参考暗点联合分析:双方按 ms_expand 扩张后计算 IOU, 大于 ms_iou 认为同位置
int FilterMsBlindNG(std::shared_ptr<CameraResult> pCheck_Result);
private: private:
// 获取 缺陷在参数列表的位置 // 获取 缺陷在参数列表的位置
int GetParamidx(); int GetParamidx();
@ -135,6 +139,16 @@ private:
int AnalysisResult_Pre(QX_ERROR_INFO_ *QX_info); // 弱化处理 int AnalysisResult_Pre(QX_ERROR_INFO_ *QX_info); // 弱化处理
// 撤销单个缺陷的NG结果:恢复为OK,移除对应NG小图并回退计数
int UndoNGResult(std::shared_ptr<ImageAllResult> pImageResult, int qxidx, QX_ERROR_INFO_ *QX_info);
// 判断盲失(产品坐标系ROI)在配置的过滤通道是否存在同位置缺陷(双方按 expand 扩张后计算IOU)
bool IsOverlapQxInMsFilterChannel(const std::vector<std::shared_ptr<ImageAllResult>> &imgResults,
const std::string &cur_channel_name,
const cv::Rect &qx_product_roi,
int roi_expand, float iou_threshold,
std::shared_ptr<DetLog> plog);
// 关联过滤源过滤:撤销与关联通道过滤源缺陷重叠的暗点NG结果(含单图判定的单点NG) // 关联过滤源过滤:撤销与关联通道过滤源缺陷重叠的暗点NG结果(含单图判定的单点NG)
int FilterCorrelatedDirtyNG(std::shared_ptr<ImageAllResult> pImageResult); int FilterCorrelatedDirtyNG(std::shared_ptr<ImageAllResult> pImageResult);

@ -341,6 +341,16 @@ int CameraCheckAnalysisy::ResultParamJudge()
int re = m_imageResultJudge.ResultJudge(m_pCheck_Result->ImageALLDetResultList.at(imgidx)); int re = m_imageResultJudge.ResultJudge(m_pCheck_Result->ImageALLDetResultList.at(imgidx));
long t2 = CheckUtil::getcurTime(); long t2 = CheckUtil::getcurTime();
} }
// 盲失联合判断:主通道(ms_main_channel)检出的盲失若在过滤通道(ms_filter_channels)同位置存在盲失,则不算盲失(撤销NG)
{
int nMsFilterNum = m_imageResultJudge.FilterMsBlindNG(m_pCheck_Result);
if (nMsFilterNum > 0)
{
m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", "盲失联合判断: 过滤通道同位置存在盲失, 过滤盲失NG %d 个", nMsFilterNum);
}
}
m_pQX_Merge_Analysis->setSendStatus(m_strcameraName, QX_Merge_Analysis::RUN_STATUS_READY); m_pQX_Merge_Analysis->setSendStatus(m_strcameraName, QX_Merge_Analysis::RUN_STATUS_READY);
m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", "===============QX_Merge_Analysis===start %s", CheckUtil::getCurTimeHMS().c_str()); m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", "===============QX_Merge_Analysis===start %s", CheckUtil::getCurTimeHMS().c_str());

@ -1,6 +1,7 @@
#include "ImageResultJudge.h" #include "ImageResultJudge.h"
#include <cmath> #include <cmath>
#include <algorithm>
ImageResultJudge::ImageResultJudge(/* args */) ImageResultJudge::ImageResultJudge(/* args */)
{ {
@ -869,59 +870,275 @@ int ImageResultJudge::FilterCorrelatedDirtyNG(std::shared_ptr<ImageAllResult> pI
} }
// 撤销NG结果 // 撤销NG结果
QX_info->result = QX_RESULT_TYPE_OK; UndoNGResult(pImageResult, qxidx, QX_info);
QX_info->result_name = QX_RESULT_TYPE_Names[QX_info->result];
int nqx_type = ConfigTypeToResultType(QX_info->nconfig_qx_type); 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;
}
/**
* @brief 撤销单个缺陷的NG结果:恢复为OK,移除对应的NG小图并回退计数
* @param pImageResult 当前检测图片结果
* @param qxidx 缺陷在 pQx_ErrorList 中的下标
* @param QX_info 缺陷信息
* @return int 移除的NG小图个数
*/
int ImageResultJudge::UndoNGResult(std::shared_ptr<ImageAllResult> pImageResult, int qxidx, QX_ERROR_INFO_ *QX_info)
{
if (pImageResult == nullptr || QX_info == nullptr)
{
return 0;
}
std::shared_ptr<CheckResult> m_CheckResult_shareP = pImageResult->result;
if (m_CheckResult_shareP == nullptr)
{
return 0;
}
// 撤销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;
}
return nEraseNum;
}
// 移除该缺陷的NG小图 /**
int nEraseNum = 0; * @brief 判断盲失(产品坐标系ROI)在配置的过滤通道是否存在同位置且同为盲失(Other)类型的缺陷
for (auto it = m_CheckResult_shareP->qxImageResult.begin(); it != m_CheckResult_shareP->qxImageResult.end();) * 同位置判断方式参考暗点联合分析:当前ROI与过滤通道缺陷ROI双方均按 expand 扩张后计算 IOU
* @param imgResults 当前相机所有通道的检测结果
* @param cur_channel_name 盲失所属通道(主通道)
* @param qx_product_roi 盲失的产品坐标系ROI
* @param roi_expand 扩张像素(ms_expand)
* @param iou_threshold IOU阈值(ms_iou)
* @param plog 日志
* @return bool 过滤通道同位置存在盲失缺陷返回true
*/
bool ImageResultJudge::IsOverlapQxInMsFilterChannel(const std::vector<std::shared_ptr<ImageAllResult>> &imgResults,
const std::string &cur_channel_name,
const cv::Rect &qx_product_roi,
int roi_expand, float iou_threshold,
std::shared_ptr<DetLog> plog)
{
// 防御:ROI非法时不判断,避免无效计算与除零
if (qx_product_roi.width <= 0 || qx_product_roi.height <= 0)
{
return false;
}
if (m_pbaseCheckFunction == nullptr || m_pAnalysisyConfig == nullptr)
{
return false;
}
const std::vector<std::string> &filter_channels = m_pbaseCheckFunction->ms_check.ms_filter_channels;
if (filter_channels.empty())
{
return false;
}
float fproduct_offx_mm = m_pAnalysisyConfig->commonCheckConfig.baseConfig.fProduct_Off_X_mm;
int fproduct_offx_piexl = int(fproduct_offx_mm / m_fImgage_Scale_X);
// 与暗点联合分析保持一致:双方均按 expand 扩张后再计算 IOU
cv::Rect roi_expanded(qx_product_roi.x - roi_expand, qx_product_roi.y - roi_expand,
qx_product_roi.width + roi_expand * 2, qx_product_roi.height + roi_expand * 2);
for (int imgidx = 0; imgidx < (int)imgResults.size(); imgidx++)
{
std::shared_ptr<ImageAllResult> pFilterImage = imgResults.at(imgidx);
if (pFilterImage == nullptr)
{ {
if (it->idx == qxidx) continue;
}
// 只与配置的过滤通道比较;当前通道不参与,避免自身重叠导致误过滤
if (pFilterImage->strChannel == cur_channel_name)
{
continue;
}
if (std::find(filter_channels.begin(), filter_channels.end(), pFilterImage->strChannel) == filter_channels.end())
{
continue;
}
std::shared_ptr<One_Image_CheckResult_> pFilterDetResult = pFilterImage->pDetResult;
if (pFilterDetResult == nullptr || pFilterDetResult->pQx_ErrorList == nullptr)
{
continue;
}
// 只统计过滤通道内同为盲失(Other)类型的缺陷,与具体判定结果无关
for (int j = 0; j < (int)pFilterDetResult->pQx_ErrorList->size(); j++)
{
const QX_ERROR_INFO_ &filter_qx = pFilterDetResult->pQx_ErrorList->at(j);
if (filter_qx.nconfig_qx_type != CONFIG_QX_NAME_Other)
{ {
it = m_CheckResult_shareP->qxImageResult.erase(it); continue;
nEraseNum++;
} }
else cv::Rect filter_roi = filter_qx.roi;
filter_roi.x += fproduct_offx_piexl;
cv::Rect filter_expanded(filter_roi.x - roi_expand, filter_roi.y - roi_expand,
filter_roi.width + roi_expand * 2, filter_roi.height + roi_expand * 2);
float fiou = CheckUtil::CalIoU(roi_expanded, filter_expanded);
if (plog)
{ {
++it; plog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "MsBlind",
"main channel %s roi %s <-> filter channel %s qx %d roi %s expand %d iou %f",
cur_channel_name.c_str(), CheckUtil::GetRectString(qx_product_roi).c_str(),
pFilterImage->strChannel.c_str(), j,
CheckUtil::GetRectString(filter_roi).c_str(), roi_expand, fiou);
} }
} // IOU 为 NaN(ROI 非法导致的除零)时比较结果为 false,不会误过滤
if (fiou > iou_threshold)
// 计数回退
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 (plog)
{
plog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "MsBlind",
"main channel %s roi %s overlap filter channel %s qx %d roi %s expand %d iou %f > %f",
cur_channel_name.c_str(), CheckUtil::GetRectString(qx_product_roi).c_str(),
pFilterImage->strChannel.c_str(), j,
CheckUtil::GetRectString(filter_roi).c_str(), roi_expand, fiou, iou_threshold);
}
return true;
} }
} }
if (pImageResult->NG_num > 0) }
return false;
}
/**
* @brief 盲失联合判断:主通道(ms_main_channel)检出的盲失(Other)需要和过滤通道(ms_filter_channels)同位置判断,
* 过滤通道同位置存在同为盲失(Other)类型的缺陷时不算盲失(撤销NG)
* 同位置判断方式参考暗点联合分析:双方按 ms_expand 扩张后计算 IOU, 大于 ms_iou 认为同位置
* @param pCheck_Result 当前相机检测结果(包含该相机所有通道的检测结果)
* @return int 被过滤的盲失NG个数
*/
int ImageResultJudge::FilterMsBlindNG(std::shared_ptr<CameraResult> pCheck_Result)
{
if (pCheck_Result == nullptr || m_pbaseCheckFunction == nullptr || m_pAnalysisyConfig == nullptr)
{
return 0;
}
Base_Function_MS_Check *pMsParam = &m_pbaseCheckFunction->ms_check;
// 未开启盲失分析 或 未配置主通道/过滤通道 时不需要判断
if (!pMsParam->bOpen || pMsParam->ms_main_channel.empty() || pMsParam->ms_filter_channels.empty())
{
return 0;
}
const int roi_expand = (int)(round)(pMsParam->MS_Expand);
const float iou_threshold = pMsParam->MS_IOU;
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 imgidx = 0; imgidx < (int)pCheck_Result->ImageALLDetResultList.size(); imgidx++)
{
std::shared_ptr<ImageAllResult> pImageResult = pCheck_Result->ImageALLDetResultList.at(imgidx);
if (pImageResult == nullptr)
{ {
pImageResult->NG_num--; continue;
} }
pImageResult->Ok_num++; // 只处理配置的主通道
// 过滤后已无NG,则恢复图片结果 if (std::find(pMsParam->ms_main_channel.begin(), pMsParam->ms_main_channel.end(), pImageResult->strChannel) == pMsParam->ms_main_channel.end())
if (m_CheckResult_shareP->qxImageResult.empty())
{ {
m_CheckResult_shareP->nresult = ERROR_TYPE_OK; continue;
} }
std::shared_ptr<One_Image_CheckResult_> pDetResult = pImageResult->pDetResult; // 检测结果
nFilterNum++; if (pDetResult == nullptr || pDetResult->pQx_ErrorList == nullptr || pImageResult->result == nullptr)
if (pImageLog)
{ {
pImageLog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "DirtyCorrelatedFilter", continue;
"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) std::shared_ptr<DetLog> pImageLog = pImageResult->detlog;
for (int qxidx = 0; qxidx < (int)pDetResult->pQx_ErrorList->size(); qxidx++)
{ {
m_pQX_Merge_Analysis->m_pMergedetlog->AddCheckstr(PrintLevel_1, 3, "DirtyCorrelatedFilter", QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx);
"img %s cam %s blob %d qx %s roi %s : 关联通道存在重叠的过滤源缺陷, 过滤该暗点NG", // 只处理 盲失(Other) 的 NG 结果
pImageResult->strChannel.c_str(), pImageResult->cameraBaseResult->strCameraName.c_str(), if (QX_info->nconfig_qx_type != CONFIG_QX_NAME_Other || QX_info->result != QX_RESULT_TYPE_NG)
qxidx, QX_info->qx_name.c_str(), CheckUtil::GetRectString(product_roi).c_str()); {
continue;
}
cv::Rect product_roi = QX_info->roi;
product_roi.x += fproduct_offx_piexl;
// 过滤通道同位置不存在盲失时,保留盲失NG
if (!IsOverlapQxInMsFilterChannel(pCheck_Result->ImageALLDetResultList,
pImageResult->strChannel,
product_roi,
roi_expand, iou_threshold,
pImageLog))
{
continue;
}
// 撤销NG结果
UndoNGResult(pImageResult, qxidx, QX_info);
nFilterNum++;
if (pImageLog)
{
pImageLog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "MsBlind",
"img %s cam %s blob %d qx %s roi %s : 过滤通道同位置存在盲失, 不算盲失",
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 != nullptr && m_pQX_Merge_Analysis->m_pMergedetlog)
{
m_pQX_Merge_Analysis->m_pMergedetlog->AddCheckstr(PrintLevel_1, 3, "MsBlind",
"img %s cam %s blob %d qx %s roi %s : 过滤通道同位置存在盲失, 不算盲失",
pImageResult->strChannel.c_str(), pImageResult->cameraBaseResult->strCameraName.c_str(),
qxidx, QX_info->qx_name.c_str(), CheckUtil::GetRectString(product_roi).c_str());
}
} }
} }

@ -128,7 +128,7 @@ enum Function_CONFIG_QX_NAME_
Function_CONFIG_QX_NAME_PS, // ps(P0002) Function_CONFIG_QX_NAME_PS, // ps(P0002)
Function_CONFIG_QX_NAME_Weak_Bright_Mura, // 白GAP(P1654) Function_CONFIG_QX_NAME_Weak_Bright_Mura, // 白GAP(P1654)
Function_CONFIG_QX_NAME_No_Label, // 缺POL(P2833) Function_CONFIG_QX_NAME_No_Label, // 缺POL(P2833)
Function_CONFIG_QX_NAME_Other, // 缺POL(P2833) Function_CONFIG_QX_NAME_Other, // 盲失
Function_CONFIG_QX_NAME_Chess, // Chess 异常 Function_CONFIG_QX_NAME_Chess, // Chess 异常
Function_CONFIG_QX_NAME_127Cell, // 白cell Function_CONFIG_QX_NAME_127Cell, // 白cell
Function_CONFIG_QX_NAME_Cell, // 独立检测的黑白cell点 Function_CONFIG_QX_NAME_Cell, // 独立检测的黑白cell点

Loading…
Cancel
Save