|
|
|
|
@ -1,5 +1,7 @@
|
|
|
|
|
|
|
|
|
|
#include "ImageResultJudge.h"
|
|
|
|
|
#include <cmath>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
|
|
ImageResultJudge::ImageResultJudge(/* args */)
|
|
|
|
|
{
|
|
|
|
|
@ -96,6 +98,12 @@ cv::Rect ImageResultJudge::GetCutRoi(cv::Rect &roi, const cv::Mat &img)
|
|
|
|
|
|
|
|
|
|
return cutroi;
|
|
|
|
|
}
|
|
|
|
|
bool ImageResultJudge::NeedDrawAndSave()
|
|
|
|
|
{
|
|
|
|
|
// base 层“是否存图绘制”开关:绘制并保存结果图(运行时替代 SAVE_RESIMG 宏)
|
|
|
|
|
return m_pbaseCheckFunction != NULL && m_pbaseCheckFunction->bDrawAndSave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ImageResultJudge::GetAIDetImg(std::shared_ptr<ImageAllResult> pImageResult, cv::Point pcenter, cv::Mat &AI_InImg, cv::Mat &AI_OutImg)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
@ -222,6 +230,25 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
|
|
|
|
|
|
|
|
|
|
QX_info->result = QX_RESULT_TYPE_NoJduge;
|
|
|
|
|
|
|
|
|
|
// 关联通道分析:登记关联过滤源缺陷位置(类型由 analysis_bind.correlated_types 配置, 如脏污/暗点),
|
|
|
|
|
// 供 AD 分析判断关联通道是否存在重叠缺陷。
|
|
|
|
|
// 登记只依赖缺陷类型与位置,与判定结果/是否绘制无关:
|
|
|
|
|
// 被分到 NoJudge(不判定/Draw)的缺陷也要登记(如 DP 上未开启 AD 判定的暗点),否则无法过滤其它通道的重叠缺陷
|
|
|
|
|
if (m_pQX_Merge_Analysis->IsCorrelatedSourceConfigType(config_qx_type))
|
|
|
|
|
{
|
|
|
|
|
QX_Merge_Analysis::Correlated_Qx_Info_ corr_qx;
|
|
|
|
|
corr_qx.channel_name = pImageResult->strChannel;
|
|
|
|
|
corr_qx.camera_name = pImageResult->cameraBaseResult->strCameraName;
|
|
|
|
|
corr_qx.config_qx_type = config_qx_type;
|
|
|
|
|
corr_qx.result_type = ConfigTypeToResultType(config_qx_type);
|
|
|
|
|
corr_qx.product_roi = roi;
|
|
|
|
|
corr_qx.product_roi.x += fproduct_offx_piexl;
|
|
|
|
|
|
|
|
|
|
bool bAddCorr = m_pQX_Merge_Analysis->AddCorrelatedQxInfo(corr_qx, pQxLog);
|
|
|
|
|
pQxLog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, " Use Num And Dis Judge ", "qx %s ,Add Correlated %s %s",
|
|
|
|
|
qx_name.c_str(), BOOL_TO_STR_Error(bAddCorr), corr_qx.GetInfo().c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 在其他位置已经判断了 不进入分析。直接绘制。
|
|
|
|
|
if (qx_status == QX_Stauts_Draw)
|
|
|
|
|
{
|
|
|
|
|
@ -327,6 +354,7 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
|
|
|
|
|
float hj = pParam->paramArr[j].hj;
|
|
|
|
|
float Len = pParam->paramArr[j].length;
|
|
|
|
|
float md = pParam->paramArr[j].density;
|
|
|
|
|
float area_max = pParam->paramArr[j].area_max;
|
|
|
|
|
|
|
|
|
|
Judge_Status = true;
|
|
|
|
|
|
|
|
|
|
@ -385,6 +413,31 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
|
|
|
|
|
BOOL_TO_STR(flen >= Len), flen, BOOL_TO_ThanLess(flen > Len), Len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (config_qx_type == CONFIG_QX_NAME_POL_Cell && area_max > 0)
|
|
|
|
|
{
|
|
|
|
|
if (detArea > area_max)
|
|
|
|
|
{
|
|
|
|
|
nerrortype = 0;
|
|
|
|
|
result = true;
|
|
|
|
|
bNG_Status = false;
|
|
|
|
|
bYS_Status = false;
|
|
|
|
|
}
|
|
|
|
|
pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "PolCell_Area_Max", "%s -> %f %s %f ",
|
|
|
|
|
BOOL_TO_STR(detArea > area_max), detArea, BOOL_TO_ThanLess(detArea > area_max), area_max);
|
|
|
|
|
}
|
|
|
|
|
// AD根据配置检测:未配置通道的AD缺陷不判NG
|
|
|
|
|
if (config_qx_type == CONFIG_QX_NAME_AD && m_pbaseCheckFunction && ict == ANALYSIS_TYPE_TF &&
|
|
|
|
|
std::find(m_pbaseCheckFunction->ad_check.analysis_sf.region_sf.begin(),
|
|
|
|
|
m_pbaseCheckFunction->ad_check.analysis_sf.region_sf.end(),
|
|
|
|
|
strChannel) == m_pbaseCheckFunction->ad_check.analysis_sf.region_sf.end())
|
|
|
|
|
{
|
|
|
|
|
nerrortype = 0;
|
|
|
|
|
result = true;
|
|
|
|
|
bNG_Status = false;
|
|
|
|
|
bYS_Status = false;
|
|
|
|
|
pQxLog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "Param Judge", "AD channel %s not configured in region_sf", strChannel.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!result)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
@ -415,36 +468,37 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
|
|
|
|
|
Judge_Status = true;
|
|
|
|
|
checkFlage = ANALYSIS_TYPE_TF;
|
|
|
|
|
nerrortype = 1;
|
|
|
|
|
bNG_Status = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 暗点 3S 分析 对 好品 或者 是 疑是的缺陷进行3S分析。S数量分析。 3S的暗点直接NG.
|
|
|
|
|
// if ((nerrortype == 0 || checkFlage != ANALYSIS_TYPE_TF) &&
|
|
|
|
|
// config_qx_type == CONFIG_QX_NAME_AD && pFuntion &&
|
|
|
|
|
// pFuntion->function.f_AD_Check.bOpen &&
|
|
|
|
|
// pFuntion->function.f_AD_Check.analysis_s.bOpen &&
|
|
|
|
|
// pFuntion->function.f_AD_Check.analysis_s.NG_3s && bpreSucc)
|
|
|
|
|
if ((nerrortype == 0 || checkFlage != ANALYSIS_TYPE_TF) &&
|
|
|
|
|
config_qx_type == CONFIG_QX_NAME_AD && m_pbaseCheckFunction &&
|
|
|
|
|
config_qx_type == CONFIG_QX_NAME_AD && pFuntion != NULL && m_pbaseCheckFunction &&
|
|
|
|
|
m_pbaseCheckFunction->ad_check.bOpen &&
|
|
|
|
|
m_pbaseCheckFunction->ad_check.analysis_s.bOpen &&
|
|
|
|
|
m_pbaseCheckFunction->ad_check.analysis_s.NG_3s && bpreSucc)
|
|
|
|
|
{
|
|
|
|
|
bool b3sChannel = false;
|
|
|
|
|
if (std::find(m_pbaseCheckFunction->ad_check.analysis_sf.s_sf.begin(), m_pbaseCheckFunction->ad_check.analysis_sf.s_sf.end(), strChannel) != m_pbaseCheckFunction->ad_check.analysis_sf.s_sf.end())
|
|
|
|
|
{
|
|
|
|
|
b3sChannel = true;
|
|
|
|
|
}
|
|
|
|
|
Judge_Status = true;
|
|
|
|
|
int det_s_Vale = 0;
|
|
|
|
|
if (JudgArea >= pFuntion->function.f_AD_Check.S_standard_3s.area &&
|
|
|
|
|
flen >= pFuntion->function.f_AD_Check.S_standard_3s.len)
|
|
|
|
|
if (JudgArea >= m_pbaseCheckFunction->ad_check.S_standard_3s.area &&
|
|
|
|
|
flen >= m_pbaseCheckFunction->ad_check.S_standard_3s.len && b3sChannel)
|
|
|
|
|
{
|
|
|
|
|
nerrortype = 1;
|
|
|
|
|
checkFlage = ANALYSIS_TYPE_TF;
|
|
|
|
|
bNG_Status = true;
|
|
|
|
|
|
|
|
|
|
pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "info", " AD 3S result NG, det area %f len %f >=3s param area %f len %f ",
|
|
|
|
|
JudgArea, flen, pFuntion->function.f_AD_Check.S_standard_3s.area, pFuntion->function.f_AD_Check.S_standard_3s.len);
|
|
|
|
|
JudgArea, flen, m_pbaseCheckFunction->ad_check.S_standard_3s.area, m_pbaseCheckFunction->ad_check.S_standard_3s.len);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "info", " AD 3S result OK, det area %f len %f < 3s param area %f len %f ",
|
|
|
|
|
JudgArea, flen, pFuntion->function.f_AD_Check.S_standard_3s.area, pFuntion->function.f_AD_Check.S_standard_3s.len);
|
|
|
|
|
JudgArea, flen, m_pbaseCheckFunction->ad_check.S_standard_3s.area, m_pbaseCheckFunction->ad_check.S_standard_3s.len);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -479,7 +533,7 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
// 目前为止判断是好品
|
|
|
|
|
if (!bNG_Status && pFuntion->function.f_Big_QX.bOpen)
|
|
|
|
|
if (!bNG_Status && pFuntion != NULL && pFuntion->function.f_Big_QX.bOpen)
|
|
|
|
|
{
|
|
|
|
|
Judge_Status = true;
|
|
|
|
|
bool berror = false;
|
|
|
|
|
@ -503,7 +557,7 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 总面积判断
|
|
|
|
|
if (!bNG_Status && pFuntion->function.f_Big_QX.bOpen)
|
|
|
|
|
if (!bNG_Status && pFuntion != NULL && pFuntion->function.f_Big_QX.bOpen)
|
|
|
|
|
{
|
|
|
|
|
if (nSumBLobNUm <= pFuntion->function.f_Big_QX.Sum_blob_Num)
|
|
|
|
|
{
|
|
|
|
|
@ -550,6 +604,17 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
|
|
|
|
|
pQxLog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, " big qx ", "qx %s ,result = %s", qx_name.c_str(), resultType.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 对于 AD_YX 类型,面积小于设定值的 降级为NoJudge
|
|
|
|
|
if (config_qx_type == CONFIG_QX_NAME_AD_YX && bYS_Status && pFuntion != NULL &&
|
|
|
|
|
pFuntion->function.f_YXDet.bOpen && JudgArea < pFuntion->function.f_YXDet.minArea)
|
|
|
|
|
{
|
|
|
|
|
bYS_Status = false;
|
|
|
|
|
QX_info->result = QX_RESULT_TYPE_OK;
|
|
|
|
|
QX_info->result_name = QX_RESULT_TYPE_Names[QX_info->result];
|
|
|
|
|
resultType = QX_info->result_name;
|
|
|
|
|
pQxLog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "AD_YX downgrade", "area %f < %d, YS -> OK", JudgArea, pFuntion->function.f_YXDet.minArea);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bNG_Status)
|
|
|
|
|
{
|
|
|
|
|
m_CheckResult_shareP->nresult = 1;
|
|
|
|
|
@ -571,7 +636,8 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
|
|
|
|
|
// CheckUtil::printROI(CutRoi, "CutRoi");
|
|
|
|
|
cv::Size sz = cv::Size(QX_SAMLLIMG_WIDTH, QX_SAMLLIMG_HEIGHT);
|
|
|
|
|
|
|
|
|
|
#ifdef AI_Time
|
|
|
|
|
if (NeedDrawAndSave())
|
|
|
|
|
{
|
|
|
|
|
if (pImageResult->detImg.channels() == 1)
|
|
|
|
|
{
|
|
|
|
|
cv::cvtColor(pImageResult->detImg(CutRoi), tem.srcImg, cv::COLOR_GRAY2BGR);
|
|
|
|
|
@ -581,7 +647,7 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
|
|
|
|
|
tem.srcImg = pImageResult->detImg(CutRoi).clone();
|
|
|
|
|
}
|
|
|
|
|
cv::resize(tem.srcImg, tem.resizeImg, sz);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int nqx_type = ConfigTypeToResultType(config_qx_type);
|
|
|
|
|
tem.type = nqx_type;
|
|
|
|
|
@ -626,7 +692,10 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
|
|
|
|
|
m_CheckResult_shareP->nresult = nqx_type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (NeedDrawAndSave())
|
|
|
|
|
{
|
|
|
|
|
GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img);
|
|
|
|
|
}
|
|
|
|
|
m_CheckResult_shareP->qxImageResult.push_back(tem);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
@ -637,13 +706,15 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
|
|
|
|
|
m_CheckResult_shareP->nYS_result = nqx_type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (NeedDrawAndSave())
|
|
|
|
|
{
|
|
|
|
|
GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_CheckResult_shareP->YS_ImageResult.push_back(tem);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, " result ", " name %s ---code %s", tem.strTypeName.c_str(), tem.qx_Code.c_str());
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 对于大面积 的zara和 异显NG ,可以不接着分析后续的数据了。应为后续估计有很多错误类别。
|
|
|
|
|
@ -747,6 +818,573 @@ int ImageResultJudge::UpdateMergedet(std::shared_ptr<CameraResult> pCheck_Result
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief 关联过滤源过滤:撤销与关联通道过滤源缺陷重叠的暗点NG结果(含单图判定的单点NG)
|
|
|
|
|
* 被过滤的暗点不再计入NG
|
|
|
|
|
* @param pImageResult 当前检测图片结果
|
|
|
|
|
* @return int 被过滤的缺陷个数
|
|
|
|
|
*/
|
|
|
|
|
int ImageResultJudge::FilterCorrelatedDirtyNG(std::shared_ptr<ImageAllResult> pImageResult)
|
|
|
|
|
{
|
|
|
|
|
if (pImageResult == nullptr || pImageResult->cameraBaseResult == nullptr ||
|
|
|
|
|
m_pbaseCheckFunction == nullptr || m_pQX_Merge_Analysis == nullptr || m_pAnalysisyConfig == nullptr)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
// 未配置关联通道(NONE/空)时不需要判断
|
|
|
|
|
std::vector<std::string> correlated_channels = m_pbaseCheckFunction->ad_check.analysis_bind.correlated_channels;
|
|
|
|
|
if (correlated_channels.empty())
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
std::shared_ptr<One_Image_CheckResult_> pDetResult = pImageResult->pDetResult; // 检测结果
|
|
|
|
|
std::shared_ptr<CheckResult> m_CheckResult_shareP = pImageResult->result; // 返回结果
|
|
|
|
|
if (pDetResult == nullptr || pDetResult->pQx_ErrorList == nullptr || m_CheckResult_shareP == nullptr)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<DetLog> 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结果
|
|
|
|
|
UndoNGResult(pImageResult, qxidx, QX_info);
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief 判断盲失(产品坐标系ROI)在配置的过滤通道是否存在同位置缺陷(不限制缺陷类型)
|
|
|
|
|
* 同位置判断方式参考暗点联合分析:当前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)
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 过滤通道不限制缺陷类型:任意类型缺陷都参与同位置比较,与具体判定结果无关
|
|
|
|
|
for (int j = 0; j < (int)pFilterDetResult->pQx_ErrorList->size(); j++)
|
|
|
|
|
{
|
|
|
|
|
const QX_ERROR_INFO_ &filter_qx = pFilterDetResult->pQx_ErrorList->at(j);
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
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 (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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief 盲失联合判断:主通道(ms_main_channel)检出的盲失(Other)需要和过滤通道(ms_filter_channels)同位置判断,
|
|
|
|
|
* 过滤通道同位置存在缺陷(不限制缺陷类型)时不算盲失(撤销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)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
// 只处理配置的主通道
|
|
|
|
|
if (std::find(pMsParam->ms_main_channel.begin(), pMsParam->ms_main_channel.end(), pImageResult->strChannel) == pMsParam->ms_main_channel.end())
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
std::shared_ptr<One_Image_CheckResult_> pDetResult = pImageResult->pDetResult; // 检测结果
|
|
|
|
|
if (pDetResult == nullptr || pDetResult->pQx_ErrorList == nullptr || pImageResult->result == nullptr)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
std::shared_ptr<DetLog> pImageLog = pImageResult->detlog;
|
|
|
|
|
|
|
|
|
|
for (int qxidx = 0; qxidx < (int)pDetResult->pQx_ErrorList->size(); qxidx++)
|
|
|
|
|
{
|
|
|
|
|
QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx);
|
|
|
|
|
// 只处理 盲失(Other) 的 NG 结果
|
|
|
|
|
if (QX_info->nconfig_qx_type != CONFIG_QX_NAME_Other || QX_info->result != QX_RESULT_TYPE_NG)
|
|
|
|
|
{
|
|
|
|
|
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());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nFilterNum;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief 跨通道同位置判断:判断当前缺陷(产品坐标系ROI)在过滤通道是否存在同位置缺陷
|
|
|
|
|
* (match_qx_types 为空表示不限制缺陷类型)
|
|
|
|
|
* 同位置判断方式参考暗点联合分析:当前ROI与过滤通道缺陷ROI双方均按 expand 扩张后计算 IOU
|
|
|
|
|
* @param imgResults 当前相机所有通道的检测结果
|
|
|
|
|
* @param cur_channel_name 当前缺陷所属通道(主通道)
|
|
|
|
|
* @param filter_channels 需要比较的过滤通道
|
|
|
|
|
* @param match_qx_types 过滤通道中参与比较的缺陷类型(CONFIG_QX_NAME_),为空表示不限制类型
|
|
|
|
|
* @param qx_product_roi 当前缺陷的产品坐标系ROI
|
|
|
|
|
* @param roi_expand 扩张像素
|
|
|
|
|
* @param iou_threshold IOU阈值
|
|
|
|
|
* @param strTag 日志标签
|
|
|
|
|
* @param plog 日志
|
|
|
|
|
* @return bool 过滤通道同位置存在匹配缺陷返回true
|
|
|
|
|
*/
|
|
|
|
|
bool ImageResultJudge::IsOverlapQxInFilterChannels(const std::vector<std::shared_ptr<ImageAllResult>> &imgResults,
|
|
|
|
|
const std::string &cur_channel_name,
|
|
|
|
|
const std::vector<std::string> &filter_channels,
|
|
|
|
|
const std::vector<int> &match_qx_types,
|
|
|
|
|
const cv::Rect &qx_product_roi,
|
|
|
|
|
int roi_expand, float iou_threshold,
|
|
|
|
|
const std::string &strTag,
|
|
|
|
|
std::shared_ptr<DetLog> plog)
|
|
|
|
|
{
|
|
|
|
|
// 防御:ROI非法/未配置过滤通道时不判断,避免无效计算与除零
|
|
|
|
|
if (qx_product_roi.width <= 0 || qx_product_roi.height <= 0)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// match_qx_types 为空表示不限制过滤通道的缺陷类型
|
|
|
|
|
if (filter_channels.empty())
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (m_pAnalysisyConfig == nullptr)
|
|
|
|
|
{
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 只统计过滤通道内匹配类型的缺陷(未指定类型时不限制),与具体判定结果无关
|
|
|
|
|
for (int j = 0; j < (int)pFilterDetResult->pQx_ErrorList->size(); j++)
|
|
|
|
|
{
|
|
|
|
|
const QX_ERROR_INFO_ &filter_qx = pFilterDetResult->pQx_ErrorList->at(j);
|
|
|
|
|
if (!match_qx_types.empty() &&
|
|
|
|
|
std::find(match_qx_types.begin(), match_qx_types.end(), filter_qx.nconfig_qx_type) == match_qx_types.end())
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
plog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, strTag,
|
|
|
|
|
"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 (plog)
|
|
|
|
|
{
|
|
|
|
|
plog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, strTag,
|
|
|
|
|
"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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief 跨通道联合判断(通用):主通道中指定类型的NG缺陷,若在过滤通道同位置存在指定类型的缺陷,则撤销该NG
|
|
|
|
|
* 同位置判断方式参考暗点联合分析:双方按 expand 扩张后计算 IOU, 大于 iou_threshold 认为同位置
|
|
|
|
|
* @param pCheck_Result 当前相机检测结果(包含该相机所有通道的检测结果)
|
|
|
|
|
* @param main_channels 主通道
|
|
|
|
|
* @param filter_channels 过滤通道
|
|
|
|
|
* @param main_qx_types 参与判断的主通道缺陷类型(CONFIG_QX_NAME_)
|
|
|
|
|
* @param match_qx_types 过滤通道中参与比较的缺陷类型(CONFIG_QX_NAME_),为空表示不限制类型
|
|
|
|
|
* @param roi_expand 扩张像素
|
|
|
|
|
* @param iou_threshold IOU阈值
|
|
|
|
|
* @param strTag 日志标签
|
|
|
|
|
* @param strReason 过滤原因(日志)
|
|
|
|
|
* @return int 被过滤的NG个数
|
|
|
|
|
*/
|
|
|
|
|
int ImageResultJudge::FilterCrossChannelNG(std::shared_ptr<CameraResult> pCheck_Result,
|
|
|
|
|
const std::vector<std::string> &main_channels,
|
|
|
|
|
const std::vector<std::string> &filter_channels,
|
|
|
|
|
const std::vector<int> &main_qx_types,
|
|
|
|
|
const std::vector<int> &match_qx_types,
|
|
|
|
|
int roi_expand, float iou_threshold,
|
|
|
|
|
const std::string &strTag,
|
|
|
|
|
const std::string &strReason)
|
|
|
|
|
{
|
|
|
|
|
if (pCheck_Result == nullptr || m_pAnalysisyConfig == nullptr)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
// 未配置主通道/过滤通道/判断类型时不需要判断
|
|
|
|
|
if (main_channels.empty() || filter_channels.empty() || main_qx_types.empty())
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
// 只处理配置的主通道
|
|
|
|
|
if (std::find(main_channels.begin(), main_channels.end(), pImageResult->strChannel) == main_channels.end())
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
std::shared_ptr<One_Image_CheckResult_> pDetResult = pImageResult->pDetResult; // 检测结果
|
|
|
|
|
if (pDetResult == nullptr || pDetResult->pQx_ErrorList == nullptr || pImageResult->result == nullptr)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
std::shared_ptr<DetLog> pImageLog = pImageResult->detlog;
|
|
|
|
|
|
|
|
|
|
for (int qxidx = 0; qxidx < (int)pDetResult->pQx_ErrorList->size(); qxidx++)
|
|
|
|
|
{
|
|
|
|
|
QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx);
|
|
|
|
|
// 只处理指定类型的 NG 结果(YS 不降级)
|
|
|
|
|
if (QX_info->result != QX_RESULT_TYPE_NG)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (std::find(main_qx_types.begin(), main_qx_types.end(), QX_info->nconfig_qx_type) == main_qx_types.end())
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cv::Rect product_roi = QX_info->roi;
|
|
|
|
|
product_roi.x += fproduct_offx_piexl;
|
|
|
|
|
// 过滤通道同位置不存在匹配类型的缺陷时,保留该NG
|
|
|
|
|
if (!IsOverlapQxInFilterChannels(pCheck_Result->ImageALLDetResultList,
|
|
|
|
|
pImageResult->strChannel,
|
|
|
|
|
filter_channels, match_qx_types,
|
|
|
|
|
product_roi,
|
|
|
|
|
roi_expand, iou_threshold,
|
|
|
|
|
strTag, pImageLog))
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 撤销NG结果
|
|
|
|
|
UndoNGResult(pImageResult, qxidx, QX_info);
|
|
|
|
|
nFilterNum++;
|
|
|
|
|
|
|
|
|
|
if (pImageLog)
|
|
|
|
|
{
|
|
|
|
|
pImageLog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, strTag,
|
|
|
|
|
"img %s cam %s blob %d qx %s roi %s : %s",
|
|
|
|
|
pImageResult->strChannel.c_str(), pImageResult->cameraBaseResult->strCameraName.c_str(),
|
|
|
|
|
qxidx, QX_info->qx_name.c_str(), CheckUtil::GetRectString(product_roi).c_str(),
|
|
|
|
|
strReason.c_str());
|
|
|
|
|
}
|
|
|
|
|
if (m_pQX_Merge_Analysis != nullptr && m_pQX_Merge_Analysis->m_pMergedetlog)
|
|
|
|
|
{
|
|
|
|
|
m_pQX_Merge_Analysis->m_pMergedetlog->AddCheckstr(PrintLevel_1, 3, strTag,
|
|
|
|
|
"img %s cam %s blob %d qx %s roi %s : %s",
|
|
|
|
|
pImageResult->strChannel.c_str(), pImageResult->cameraBaseResult->strCameraName.c_str(),
|
|
|
|
|
qxidx, QX_info->qx_name.c_str(), CheckUtil::GetRectString(product_roi).c_str(),
|
|
|
|
|
strReason.c_str());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nFilterNum;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief cell黑白点联合判断:主通道(cellbw_main_channel)检出的cell黑白点(127画面的 Cell127 也算白点)
|
|
|
|
|
* 在过滤通道(cellbw_filter_channels)同位置存在缺陷(不限制缺陷类型)时不算cell黑白点(撤销NG)
|
|
|
|
|
* 同位置判断方式参考暗点联合分析:双方按 cellbw_expand 扩张后计算 IOU, 大于 cellbw_iou 认为同位置
|
|
|
|
|
* @param pCheck_Result 当前相机检测结果(包含该相机所有通道的检测结果)
|
|
|
|
|
* @return int 被过滤的cell黑白点NG个数
|
|
|
|
|
*/
|
|
|
|
|
int ImageResultJudge::FilterCellBwNG(std::shared_ptr<CameraResult> pCheck_Result)
|
|
|
|
|
{
|
|
|
|
|
if (m_pbaseCheckFunction == nullptr)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
Base_Function_CellBW_Check *pCellBwParam = &m_pbaseCheckFunction->cellbw_check;
|
|
|
|
|
// 未开启cell黑白点分析时不需要判断(主通道/过滤通道为空时由通用逻辑直接返回)
|
|
|
|
|
if (!pCellBwParam->bOpen)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
// 主通道只处理 cell 黑白点(白点/黑点都算,Cell127 按白点处理);过滤通道不限制缺陷类型,同位置存在任意类型缺陷即过滤
|
|
|
|
|
const std::vector<int> qxTypes = {CONFIG_QX_NAME_white_Cell, CONFIG_QX_NAME_black_Cell, CONFIG_QX_NAME_127Cell};
|
|
|
|
|
return FilterCrossChannelNG(pCheck_Result,
|
|
|
|
|
pCellBwParam->cellbw_main_channel, pCellBwParam->cellbw_filter_channels,
|
|
|
|
|
qxTypes, std::vector<int>(),
|
|
|
|
|
(int)(round)(pCellBwParam->CellBW_Expand), pCellBwParam->CellBW_IOU,
|
|
|
|
|
"CellBw", "过滤通道同位置存在缺陷, 不算cell黑白点");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ImageResultJudge::MergeResult(std::shared_ptr<ImageAllResult> pImageResult, QX_Analysis_Result_List *ptemre)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
@ -769,6 +1407,9 @@ int ImageResultJudge::MergeResult(std::shared_ptr<ImageAllResult> 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 ||
|
|
|
|
|
@ -814,7 +1455,8 @@ int ImageResultJudge::MergeResult(std::shared_ptr<ImageAllResult> pImageResult,
|
|
|
|
|
cv::Rect CutRoi = GetCutRoi(roi, pImageResult->detImg);
|
|
|
|
|
cv::Size sz = cv::Size(QX_SAMLLIMG_WIDTH, QX_SAMLLIMG_HEIGHT);
|
|
|
|
|
|
|
|
|
|
#ifdef AI_Time
|
|
|
|
|
if (NeedDrawAndSave())
|
|
|
|
|
{
|
|
|
|
|
if (pImageResult->detImg.channels() == 1)
|
|
|
|
|
{
|
|
|
|
|
cv::cvtColor(pImageResult->detImg(CutRoi), tem.srcImg, cv::COLOR_GRAY2BGR);
|
|
|
|
|
@ -824,7 +1466,7 @@ int ImageResultJudge::MergeResult(std::shared_ptr<ImageAllResult> pImageResult,
|
|
|
|
|
tem.srcImg = pImageResult->detImg(CutRoi).clone();
|
|
|
|
|
}
|
|
|
|
|
cv::resize(tem.srcImg, tem.resizeImg, sz);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int nerrortype = 1;
|
|
|
|
|
int checkFlage = ANALYSIS_TYPE_TF;
|
|
|
|
|
@ -885,7 +1527,10 @@ int ImageResultJudge::MergeResult(std::shared_ptr<ImageAllResult> pImageResult,
|
|
|
|
|
{
|
|
|
|
|
m_CheckResult_shareP->nresult = nqx_type;
|
|
|
|
|
}
|
|
|
|
|
if (NeedDrawAndSave())
|
|
|
|
|
{
|
|
|
|
|
GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img);
|
|
|
|
|
}
|
|
|
|
|
m_CheckResult_shareP->qxImageResult.push_back(tem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -1359,6 +2004,12 @@ int ImageResultJudge::ConfigTypeToResultType(int nconfigType)
|
|
|
|
|
case CONFIG_QX_NAME_LackPOL:
|
|
|
|
|
resultError_type = ERROR_TYPE_LackPol;
|
|
|
|
|
break;
|
|
|
|
|
case CONFIG_QX_NAME_RLine_X:
|
|
|
|
|
resultError_type = ERROR_TYPE_Line_X;
|
|
|
|
|
break;
|
|
|
|
|
case CONFIG_QX_NAME_RLine_Y:
|
|
|
|
|
resultError_type = ERROR_TYPE_Line_Y;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|