Compare commits

..

8 Commits

@ -26,7 +26,7 @@
// resize 图片的 宽度 // resize 图片的 宽度
#define RESIZE_IMAGE_WIDTH 1680 #define RESIZE_IMAGE_WIDTH 1680
// #define SAVE_RESIMG // 结果图保存/绘制开关:已由 SAVE_RESIMG 宏改为 base 层配置项“是否存图绘制”(baseCheckData 中 itemCode=bDrawAndSave 的 isOpen),运行时生效,无需再改此处宏
enum TEM_IMG_IDX_ enum TEM_IMG_IDX_
{ {

@ -107,6 +107,15 @@ 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);
// cell黑白点联合判断:主通道(cellbw_main_channel)检出的cell黑白点(Cell127 也算白点)在过滤通道
// (cellbw_filter_channels)同位置存在缺陷(不限制缺陷类型)时不算cell黑白点(撤销NG)
// 同位置判断参考暗点联合分析:双方按 cellbw_expand 扩张后计算 IOU, 大于 cellbw_iou 认为同位置
int FilterCellBwNG(std::shared_ptr<CameraResult> pCheck_Result);
private: private:
// 获取 缺陷在参数列表的位置 // 获取 缺陷在参数列表的位置
int GetParamidx(); int GetParamidx();
@ -120,6 +129,9 @@ private:
// 获取缺陷 对应的AI输入 输出图片, // 获取缺陷 对应的AI输入 输出图片,
int GetAIDetImg(std::shared_ptr<ImageAllResult> pImageResult, cv::Point pcenter, cv::Mat &AI_InImg, cv::Mat &AI_OutImg); int GetAIDetImg(std::shared_ptr<ImageAllResult> pImageResult, cv::Point pcenter, cv::Mat &AI_InImg, cv::Mat &AI_OutImg);
// 绘制并保存结果图开关(base 配置 bDrawAndSave,替代 SAVE_RESIMG 宏)
bool NeedDrawAndSave();
int sendTask(std::shared_ptr<DrawInfo> task); int sendTask(std::shared_ptr<DrawInfo> task);
std::shared_ptr<ImageResultJudge::DrawInfo> GetTask(); std::shared_ptr<ImageResultJudge::DrawInfo> GetTask();
@ -132,6 +144,36 @@ 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 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)在配置的过滤通道是否存在同位置缺陷(不限制类型,双方按 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
int 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);
// 关联过滤源过滤:撤销与关联通道过滤源缺陷重叠的暗点NG结果(含单图判定的单点NG) // 关联过滤源过滤:撤销与关联通道过滤源缺陷重叠的暗点NG结果(含单图判定的单点NG)
int FilterCorrelatedDirtyNG(std::shared_ptr<ImageAllResult> pImageResult); int FilterCorrelatedDirtyNG(std::shared_ptr<ImageAllResult> pImageResult);

@ -251,12 +251,18 @@ private:
// 临时绘制结果 // 临时绘制结果
int DrawResult_Step_1(); int DrawResult_Step_1();
// 绘制并保存结果图开关(base 配置 bDrawAndSave,替代 SAVE_RESIMG 宏)
bool NeedDrawAndSave();
// 参数缺陷类型转 结果参数类型 // 参数缺陷类型转 结果参数类型
int AIClassTypeToConfigType(int nAIQXType, cv::Rect qx_roi); int AIClassTypeToConfigType(int nAIQXType, cv::Rect qx_roi);
// 更新成像精度 // 更新成像精度
int UpdateImgageScale(); int UpdateImgageScale();
// 分类完成后按 bbox 完全相等去重(同一缺陷被多个 mask 来源各提取一次)
int DedupBlob_ByBBox();
// 把blob 汇总成 检测结果。 // 把blob 汇总成 检测结果。
int BLobToDetResult(); int BLobToDetResult();
// 二次计算缺陷面积 // 二次计算缺陷面积

@ -214,9 +214,17 @@ private:
int Judge_OK_Config(); int Judge_OK_Config();
int Judge_NG_Config(); int Judge_NG_Config();
int Analysis_AD(ALL_Qx_DataList *pALLTypeqxList, int qx_idx); // pAllowChannels 非空时仅列表内通道参与分析(主通道未配置时的回退: 仅次通道);
// nullptr=不过滤;非空但为空列表=不做任何通道分析(直接返回)
int Analysis_AD(ALL_Qx_DataList *pALLTypeqxList, int qx_idx, const std::vector<std::string> *pAllowChannels = nullptr);
int Analysis_AD_Bind(ALL_Qx_DataList *pALLTypeqxList, int qx_idx); int Analysis_AD_Bind(ALL_Qx_DataList *pALLTypeqxList, int qx_idx);
// 绑定分析的主通道是否未配置(2s 或 3s 的主通道列表为空);
// 只按配置判断,与本次产品是否检出缺陷无关(良品主通道本来就没暗点,按缺陷判断会频繁误回退)
bool IsADBindMainChannelConfigEmpty();
// 绑定分析的次通道列表(second_channel_2s + second_channel_3s, 去重并过滤空名)
std::vector<std::string> GetADBindSecondChannels();
// 关联过滤源过滤:移除与关联通道过滤源缺陷重叠的缺陷,使其不参与后续数量/距离/S分析 // 关联过滤源过滤:移除与关联通道过滤源缺陷重叠的缺陷,使其不参与后续数量/距离/S分析
int FilterCorrelatedDirtyQx(ALL_Qx_DataList *pALLTypeqxList); int FilterCorrelatedDirtyQx(ALL_Qx_DataList *pALLTypeqxList);

@ -341,6 +341,26 @@ 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);
}
}
// cell黑白点联合判断:主通道(cellbw_main_channel)检出的cell黑白点若在过滤通道(cellbw_filter_channels)同位置
// 存在缺陷(不限制类型),则不算cell黑白点(撤销NG)
{
int nCellBwFilterNum = m_imageResultJudge.FilterCellBwNG(m_pCheck_Result);
if (nCellBwFilterNum > 0)
{
m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", "cell黑白点联合判断: 过滤通道同位置存在缺陷, 过滤NG %d 个", nCellBwFilterNum);
}
}
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());
@ -361,9 +381,10 @@ int CameraCheckAnalysisy::ResultParamJudge()
long t1 = CheckUtil::getcurTime(); long t1 = CheckUtil::getcurTime();
int re = m_imageResultJudge.MergeResult(m_pCheck_Result->ImageALLDetResultList.at(imgidx), ptemre); int re = m_imageResultJudge.MergeResult(m_pCheck_Result->ImageALLDetResultList.at(imgidx), ptemre);
long t2 = CheckUtil::getcurTime(); long t2 = CheckUtil::getcurTime();
#ifdef SAVE_RESIMG if (m_pbaseCheckFunction != NULL && m_pbaseCheckFunction->bDrawAndSave)
{
m_imageResultJudge.DrawResult(m_pCheck_Result->ImageALLDetResultList.at(imgidx)); m_imageResultJudge.DrawResult(m_pCheck_Result->ImageALLDetResultList.at(imgidx));
#endif }
long t3 = CheckUtil::getcurTime(); long t3 = CheckUtil::getcurTime();
// m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", " det time %ld ms judge %ld draw %ld", t3 - t1, t2 - t1, t3 - t2); // m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", " det time %ld ms judge %ld draw %ld", t3 - t1, t2 - t1, t3 - t2);

@ -1,6 +1,7 @@
#include "ImageResultJudge.h" #include "ImageResultJudge.h"
#include <cmath> #include <cmath>
#include <algorithm>
ImageResultJudge::ImageResultJudge(/* args */) ImageResultJudge::ImageResultJudge(/* args */)
{ {
@ -97,6 +98,12 @@ cv::Rect ImageResultJudge::GetCutRoi(cv::Rect &roi, const cv::Mat &img)
return cutroi; 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) int ImageResultJudge::GetAIDetImg(std::shared_ptr<ImageAllResult> pImageResult, cv::Point pcenter, cv::Mat &AI_InImg, cv::Mat &AI_OutImg)
{ {
@ -629,7 +636,8 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
// CheckUtil::printROI(CutRoi, "CutRoi"); // CheckUtil::printROI(CutRoi, "CutRoi");
cv::Size sz = cv::Size(QX_SAMLLIMG_WIDTH, QX_SAMLLIMG_HEIGHT); cv::Size sz = cv::Size(QX_SAMLLIMG_WIDTH, QX_SAMLLIMG_HEIGHT);
#ifdef SAVE_RESIMG if (NeedDrawAndSave())
{
if (pImageResult->detImg.channels() == 1) if (pImageResult->detImg.channels() == 1)
{ {
cv::cvtColor(pImageResult->detImg(CutRoi), tem.srcImg, cv::COLOR_GRAY2BGR); cv::cvtColor(pImageResult->detImg(CutRoi), tem.srcImg, cv::COLOR_GRAY2BGR);
@ -639,7 +647,7 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
tem.srcImg = pImageResult->detImg(CutRoi).clone(); tem.srcImg = pImageResult->detImg(CutRoi).clone();
} }
cv::resize(tem.srcImg, tem.resizeImg, sz); cv::resize(tem.srcImg, tem.resizeImg, sz);
#endif }
int nqx_type = ConfigTypeToResultType(config_qx_type); int nqx_type = ConfigTypeToResultType(config_qx_type);
tem.type = nqx_type; tem.type = nqx_type;
@ -684,9 +692,10 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
m_CheckResult_shareP->nresult = nqx_type; m_CheckResult_shareP->nresult = nqx_type;
} }
#ifdef SAVE_RESIMG if (NeedDrawAndSave())
{
GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img); GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img);
#endif }
m_CheckResult_shareP->qxImageResult.push_back(tem); m_CheckResult_shareP->qxImageResult.push_back(tem);
} }
else else
@ -697,9 +706,10 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
m_CheckResult_shareP->nYS_result = nqx_type; m_CheckResult_shareP->nYS_result = nqx_type;
} }
#ifdef SAVE_RESIMG if (NeedDrawAndSave())
{
GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img); GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img);
#endif }
m_CheckResult_shareP->YS_ImageResult.push_back(tem); m_CheckResult_shareP->YS_ImageResult.push_back(tem);
} }
@ -859,6 +869,48 @@ int ImageResultJudge::FilterCorrelatedDirtyNG(std::shared_ptr<ImageAllResult> pI
continue; 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结果 // 撤销NG结果
QX_info->result = QX_RESULT_TYPE_OK; QX_info->result = QX_RESULT_TYPE_OK;
QX_info->result_name = QX_RESULT_TYPE_Names[QX_info->result]; QX_info->result_name = QX_RESULT_TYPE_Names[QX_info->result];
@ -899,26 +951,440 @@ int ImageResultJudge::FilterCorrelatedDirtyNG(std::shared_ptr<ImageAllResult> pI
m_CheckResult_shareP->nresult = ERROR_TYPE_OK; 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++; nFilterNum++;
if (pImageLog) if (pImageLog)
{ {
pImageLog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "DirtyCorrelatedFilter", pImageLog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "MsBlind",
"img %s cam %s blob %d qx %s roi %s : 关联通道存在重叠的过滤源缺陷, 过滤该暗点NG", "img %s cam %s blob %d qx %s roi %s : 过滤通道同位置存在缺陷, 不算盲失",
pImageResult->strChannel.c_str(), pImageResult->cameraBaseResult->strCameraName.c_str(), pImageResult->strChannel.c_str(), pImageResult->cameraBaseResult->strCameraName.c_str(),
qxidx, QX_info->qx_name.c_str(), CheckUtil::GetRectString(product_roi).c_str()); qxidx, QX_info->qx_name.c_str(), CheckUtil::GetRectString(product_roi).c_str());
} }
if (m_pQX_Merge_Analysis->m_pMergedetlog) if (m_pQX_Merge_Analysis != nullptr && m_pQX_Merge_Analysis->m_pMergedetlog)
{ {
m_pQX_Merge_Analysis->m_pMergedetlog->AddCheckstr(PrintLevel_1, 3, "DirtyCorrelatedFilter", m_pQX_Merge_Analysis->m_pMergedetlog->AddCheckstr(PrintLevel_1, 3, "MsBlind",
"img %s cam %s blob %d qx %s roi %s : 关联通道存在重叠的过滤源缺陷, 过滤该暗点NG", "img %s cam %s blob %d qx %s roi %s : 过滤通道同位置存在缺陷, 不算盲失",
pImageResult->strChannel.c_str(), pImageResult->cameraBaseResult->strCameraName.c_str(), pImageResult->strChannel.c_str(), pImageResult->cameraBaseResult->strCameraName.c_str(),
qxidx, QX_info->qx_name.c_str(), CheckUtil::GetRectString(product_roi).c_str()); qxidx, QX_info->qx_name.c_str(), CheckUtil::GetRectString(product_roi).c_str());
} }
} }
}
return nFilterNum; 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) int ImageResultJudge::MergeResult(std::shared_ptr<ImageAllResult> pImageResult, QX_Analysis_Result_List *ptemre)
{ {
@ -989,7 +1455,8 @@ int ImageResultJudge::MergeResult(std::shared_ptr<ImageAllResult> pImageResult,
cv::Rect CutRoi = GetCutRoi(roi, pImageResult->detImg); cv::Rect CutRoi = GetCutRoi(roi, pImageResult->detImg);
cv::Size sz = cv::Size(QX_SAMLLIMG_WIDTH, QX_SAMLLIMG_HEIGHT); cv::Size sz = cv::Size(QX_SAMLLIMG_WIDTH, QX_SAMLLIMG_HEIGHT);
#ifdef SAVE_RESIMG if (NeedDrawAndSave())
{
if (pImageResult->detImg.channels() == 1) if (pImageResult->detImg.channels() == 1)
{ {
cv::cvtColor(pImageResult->detImg(CutRoi), tem.srcImg, cv::COLOR_GRAY2BGR); cv::cvtColor(pImageResult->detImg(CutRoi), tem.srcImg, cv::COLOR_GRAY2BGR);
@ -999,7 +1466,7 @@ int ImageResultJudge::MergeResult(std::shared_ptr<ImageAllResult> pImageResult,
tem.srcImg = pImageResult->detImg(CutRoi).clone(); tem.srcImg = pImageResult->detImg(CutRoi).clone();
} }
cv::resize(tem.srcImg, tem.resizeImg, sz); cv::resize(tem.srcImg, tem.resizeImg, sz);
#endif }
int nerrortype = 1; int nerrortype = 1;
int checkFlage = ANALYSIS_TYPE_TF; int checkFlage = ANALYSIS_TYPE_TF;
@ -1060,9 +1527,10 @@ int ImageResultJudge::MergeResult(std::shared_ptr<ImageAllResult> pImageResult,
{ {
m_CheckResult_shareP->nresult = nqx_type; m_CheckResult_shareP->nresult = nqx_type;
} }
#ifdef SAVE_RESIMG if (NeedDrawAndSave())
{
GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img); GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img);
#endif }
m_CheckResult_shareP->qxImageResult.push_back(tem); m_CheckResult_shareP->qxImageResult.push_back(tem);
} }
} }

@ -8,6 +8,22 @@
// BQ blob 的分类结果会覆盖 ErrType,用该标记记录来源掩码是 BQ mask, // BQ blob 的分类结果会覆盖 ErrType,用该标记记录来源掩码是 BQ mask,
// 供 CalBlob_Other / CalBLobMean_GrayDis 在计算能量、灰度时选中正确的 mask。 // 供 CalBlob_Other / CalBLobMean_GrayDis 在计算能量、灰度时选中正确的 mask。
static const int BQ_BLOB_SOURCE_FLAG = -100; static const int BQ_BLOB_SOURCE_FLAG = -100;
// blob 来源优先级:数值越大越优先保留(BQ 专用模型 > 127/RLine 专用模型 > 主检测)
static int BlobSourcePriority(const ERROR_DOTS_BLOB_DATA &b)
{
if (b.UserErrorType == BQ_BLOB_SOURCE_FLAG)
{
return 3;
}
if (b.ErrType == CONFIG_QX_NAME_white_Cell ||
b.ErrType == CONFIG_QX_NAME_black_Cell ||
b.ErrType == CONFIG_QX_NAME_RLine_X ||
b.ErrType == CONFIG_QX_NAME_RLine_Y)
{
return 2;
}
return 1;
}
// 用于排序轮廓的比较函数 // 用于排序轮廓的比较函数
static bool compareContourAreas(const vector<Point> &contour1, const vector<Point> &contour2) static bool compareContourAreas(const vector<Point> &contour1, const vector<Point> &contour2)
{ {
@ -529,8 +545,9 @@ int ImgCheckAnalysisy::CheckRun()
m_pdetlog->AddCheckstr(PrintLevel_0, "4、BQ Detect", "-------------------------BQ AI Detect--------%ld ms-------\n", t_BQ_e - t_BQ_s); m_pdetlog->AddCheckstr(PrintLevel_0, "4、BQ Detect", "-------------------------BQ AI Detect--------%ld ms-------\n", t_BQ_e - t_BQ_s);
} }
#ifdef SAVE_RESIMG if (NeedDrawAndSave())
m_CheckResult_shareP->resultMaskImg = m_pImageAllResult->qx_DetAIResult->AI_MaskImg; {
m_CheckResult_shareP->resultMaskImg = m_pImageAllResult->qx_DetAIResult->AI_MaskImg.clone();
// 将BQ标签的AI mask合并到结果mask中 // 将BQ标签的AI mask合并到结果mask中
if (m_pImageAllResult->bq_DetAIResult && !m_pImageAllResult->bq_DetAIResult->AI_MaskImg.empty()) if (m_pImageAllResult->bq_DetAIResult && !m_pImageAllResult->bq_DetAIResult->AI_MaskImg.empty())
@ -541,7 +558,7 @@ int ImgCheckAnalysisy::CheckRun()
cv::bitwise_or(m_CheckResult_shareP->resultMaskImg, bqMask, m_CheckResult_shareP->resultMaskImg); cv::bitwise_or(m_CheckResult_shareP->resultMaskImg, bqMask, m_CheckResult_shareP->resultMaskImg);
} }
} }
#endif }
// cv::imwrite("dddddddd.png", m_pImageAllResult->qx_DetAIResult->AI_MaskImg); // cv::imwrite("dddddddd.png", m_pImageAllResult->qx_DetAIResult->AI_MaskImg);
// if (!m_pImageAllResult->qx_DetAIResult->AI_MaskImg.empty()) // if (!m_pImageAllResult->qx_DetAIResult->AI_MaskImg.empty())
@ -1492,6 +1509,10 @@ int ImgCheckAnalysisy::GetCheckResultBLob()
m_Classtask->waitComplate(); m_Classtask->waitComplate();
} }
// 分类完成后 ErrType 已是最终类型,此处按 bbox 完全相等去重,
// 避免同一缺陷被主检测与 BQ/127/RLine 多条链路各报一次。
DedupBlob_ByBBox();
// m_Classtask->waitComplate(); // m_Classtask->waitComplate();
long t13 = CheckUtil::getcurTime(); long t13 = CheckUtil::getcurTime();
@ -3185,7 +3206,8 @@ int ImgCheckAnalysisy::AI_Detect_QX()
} }
// 仅在调试模式下保存 AI_Qx_MaskList,并限制数量 // 仅在调试模式下保存 AI_Qx_MaskList,并限制数量
#ifdef SAVE_RESIMG if (NeedDrawAndSave())
{
if (DetImgInfo_shareP->bDebugsaveImg && pDetAIResult->AI_Qx_MaskList.size() < 200) if (DetImgInfo_shareP->bDebugsaveImg && pDetAIResult->AI_Qx_MaskList.size() < 200)
{ {
std::shared_ptr<ImageAllResult::AI_Det_MaskImg> temAIresult = std::make_shared<ImageAllResult::AI_Det_MaskImg>(); std::shared_ptr<ImageAllResult::AI_Det_MaskImg> temAIresult = std::make_shared<ImageAllResult::AI_Det_MaskImg>();
@ -3194,7 +3216,7 @@ int ImgCheckAnalysisy::AI_Detect_QX()
temAIresult->AI_mask = outimg; temAIresult->AI_mask = outimg;
pDetAIResult->AI_Qx_MaskList.push_back(temAIresult); pDetAIResult->AI_Qx_MaskList.push_back(temAIresult);
} }
#endif }
{ {
std::shared_ptr<ImageAllResult::AI_Det_MaskImg> temAIresult = std::make_shared<ImageAllResult::AI_Det_MaskImg>(); std::shared_ptr<ImageAllResult::AI_Det_MaskImg> temAIresult = std::make_shared<ImageAllResult::AI_Det_MaskImg>();
@ -3367,7 +3389,7 @@ int ImgCheckAnalysisy::AI_Detect_127Cell()
AIresult.copyTo(AIresultMask(result->roi), AIresult); AIresult.copyTo(AIresultMask(result->roi), AIresult);
} }
#ifdef SAVE_RESIMG if (NeedDrawAndSave())
{ {
std::shared_ptr<ImageAllResult::AI_Det_MaskImg> temAIresult = std::make_shared<ImageAllResult::AI_Det_MaskImg>(); std::shared_ptr<ImageAllResult::AI_Det_MaskImg> temAIresult = std::make_shared<ImageAllResult::AI_Det_MaskImg>();
temAIresult->roi = result->roi; temAIresult->roi = result->roi;
@ -3375,8 +3397,6 @@ int ImgCheckAnalysisy::AI_Detect_127Cell()
temAIresult->AI_mask = outimg; temAIresult->AI_mask = outimg;
pDetAIResult->AI_Qx_MaskList.push_back(temAIresult); pDetAIResult->AI_Qx_MaskList.push_back(temAIresult);
} }
#endif
{ {
std::shared_ptr<ImageAllResult::AI_Det_MaskImg> temAIresult = std::make_shared<ImageAllResult::AI_Det_MaskImg>(); std::shared_ptr<ImageAllResult::AI_Det_MaskImg> temAIresult = std::make_shared<ImageAllResult::AI_Det_MaskImg>();
temAIresult->roi = result->roi; temAIresult->roi = result->roi;
@ -3560,7 +3580,7 @@ int ImgCheckAnalysisy::AI_Detect_RLine_512()
AIresult.copyTo(AIresultMask(result->roi), AIresult); AIresult.copyTo(AIresultMask(result->roi), AIresult);
} }
#ifdef SAVE_RESIMG if (NeedDrawAndSave())
{ {
std::shared_ptr<ImageAllResult::AI_Det_MaskImg> temAIresult = std::make_shared<ImageAllResult::AI_Det_MaskImg>(); std::shared_ptr<ImageAllResult::AI_Det_MaskImg> temAIresult = std::make_shared<ImageAllResult::AI_Det_MaskImg>();
temAIresult->roi = result->roi; temAIresult->roi = result->roi;
@ -3568,8 +3588,6 @@ int ImgCheckAnalysisy::AI_Detect_RLine_512()
temAIresult->AI_mask = outimg; temAIresult->AI_mask = outimg;
pDetAIResult->AI_Qx_MaskList.push_back(temAIresult); pDetAIResult->AI_Qx_MaskList.push_back(temAIresult);
} }
#endif
{ {
std::shared_ptr<ImageAllResult::AI_Det_MaskImg> temAIresult = std::make_shared<ImageAllResult::AI_Det_MaskImg>(); std::shared_ptr<ImageAllResult::AI_Det_MaskImg> temAIresult = std::make_shared<ImageAllResult::AI_Det_MaskImg>();
temAIresult->roi = result->roi; temAIresult->roi = result->roi;
@ -3707,6 +3725,12 @@ int ImgCheckAnalysisy::ThreadTask(int nId)
return 0; return 0;
} }
bool ImgCheckAnalysisy::NeedDrawAndSave()
{
// base 层“是否存图绘制”开关:绘制并保存结果图(运行时替代 SAVE_RESIMG 宏)
return m_pbaseCheckFunction != NULL && m_pbaseCheckFunction->bDrawAndSave;
}
int ImgCheckAnalysisy::ResizeImg() int ImgCheckAnalysisy::ResizeImg()
{ {
@ -3716,7 +3740,8 @@ int ImgCheckAnalysisy::ResizeImg()
float fw = RESIZE_IMAGE_WIDTH * 1.0f / m_pImageAllResult->detImg.cols; float fw = RESIZE_IMAGE_WIDTH * 1.0f / m_pImageAllResult->detImg.cols;
sz.height = int(m_pImageAllResult->detImg.rows * fw); sz.height = int(m_pImageAllResult->detImg.rows * fw);
#ifdef SAVE_RESIMG if (NeedDrawAndSave())
{
cv::resize(m_pImageAllResult->detImg, m_pImageAllResult->resultImg, sz); cv::resize(m_pImageAllResult->detImg, m_pImageAllResult->resultImg, sz);
// 需要绘制屏蔽区 // 需要绘制屏蔽区
@ -3739,11 +3764,12 @@ int ImgCheckAnalysisy::ResizeImg()
} }
m_CheckResult_shareP->resultimg = m_pImageAllResult->resultImg; m_CheckResult_shareP->resultimg = m_pImageAllResult->resultImg;
}
#else else
{
m_pImageAllResult->fscale_detToresult_x = RESIZE_IMAGE_WIDTH * 1.0f / m_pImageAllResult->detImg.cols; m_pImageAllResult->fscale_detToresult_x = RESIZE_IMAGE_WIDTH * 1.0f / m_pImageAllResult->detImg.cols;
m_pImageAllResult->fscale_detToresult_y = sz.height * 1.0f / m_pImageAllResult->detImg.rows; m_pImageAllResult->fscale_detToresult_y = sz.height * 1.0f / m_pImageAllResult->detImg.rows;
#endif }
m_pdetlog->AddCheckstr(PrintLevel_1, "ResizeImg", "showImg size [w %d,h %d]-> show img [w %d,h %d] ", m_pdetlog->AddCheckstr(PrintLevel_1, "ResizeImg", "showImg size [w %d,h %d]-> show img [w %d,h %d] ",
m_CutRoi.width, m_CutRoi.height, sz.width, sz.height); m_CutRoi.width, m_CutRoi.height, sz.width, sz.height);
@ -3973,12 +3999,10 @@ int ImgCheckAnalysisy::UpdateBlobHFlag_RLine_512()
int ImgCheckAnalysisy::DrawResult_Step_1() int ImgCheckAnalysisy::DrawResult_Step_1()
{ {
m_pdetlog->AddCheckstr(PrintLevel_0, "DrawResult_Step_1", "=======start"); m_pdetlog->AddCheckstr(PrintLevel_0, "DrawResult_Step_1", "=======start");
#ifndef SAVE_RESIMG
if (m_CheckResult_shareP->resultimg.empty()) if (m_CheckResult_shareP->resultimg.empty())
{ {
return 0; return 0;
} }
#endif
// std::cout << m_pBasicConfig->bDrawPreRoi << std::endl; // std::cout << m_pBasicConfig->bDrawPreRoi << std::endl;
if (m_pBasicConfig->bDrawPreRoi) if (m_pBasicConfig->bDrawPreRoi)
{ {
@ -4178,6 +4202,56 @@ int ImgCheckAnalysisy::UpdateImgageScale()
return 0; return 0;
} }
// 分类完成后按 bbox 完全相等去重:同一缺陷可能被主检测与 BQ/127/RLine 各提取一次。
// 当前判据不比较 ErrType,只要求 minx/miny/maxx/maxy 完全一致;
// 重复时保留来源优先级更高的结果(BQ > 127/RLine > 主检测)。
int ImgCheckAnalysisy::DedupBlob_ByBBox()
{
int oldCount = blobs.blobCount;
if (oldCount <= 1)
{
return 0;
}
int writeIdx = 0;
int mergeNum = 0;
for (int i = 0; i < oldCount; i++)
{
bool bmerged = false;
for (int j = 0; j < writeIdx; j++)
{
if (blobs.blobTab[i].minx == blobs.blobTab[j].minx &&
blobs.blobTab[i].miny == blobs.blobTab[j].miny &&
blobs.blobTab[i].maxx == blobs.blobTab[j].maxx &&
blobs.blobTab[i].maxy == blobs.blobTab[j].maxy)
{
// bbox 完全一致:保留来源优先级更高的结果
if (BlobSourcePriority(blobs.blobTab[i]) > BlobSourcePriority(blobs.blobTab[j]))
{
blobs.blobTab[j] = blobs.blobTab[i];
}
mergeNum++;
bmerged = true;
break;
}
}
if (!bmerged)
{
if (writeIdx != i)
{
blobs.blobTab[writeIdx] = blobs.blobTab[i];
}
writeIdx++;
}
}
blobs.blobCount = writeIdx;
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "DedupBlob",
"bbox dedup: before %d after %d merged %d", oldCount, writeIdx, mergeNum);
return 0;
}
int ImgCheckAnalysisy::BLobToDetResult() int ImgCheckAnalysisy::BLobToDetResult()
{ {
long t1 = CheckUtil::getcurTime(); long t1 = CheckUtil::getcurTime();
@ -4994,14 +5068,17 @@ int ImgCheckAnalysisy::ImgPreDet()
creatsavedir(); creatsavedir();
} }
#ifdef SAVE_RESIMG if (NeedDrawAndSave())
{
m_CheckResult_shareP->cutSrcimg = m_pImageAllResult->detImg; m_CheckResult_shareP->cutSrcimg = m_pImageAllResult->detImg;
ResizeImg(); ResizeImg();
m_pImageAllResult->fscale_detToresult_x = m_pImageAllResult->resultImg.cols * 1.0f / m_pImageAllResult->detImg.cols; m_pImageAllResult->fscale_detToresult_x = m_pImageAllResult->resultImg.cols * 1.0f / m_pImageAllResult->detImg.cols;
m_pImageAllResult->fscale_detToresult_y = m_pImageAllResult->resultImg.rows * 1.0f / m_pImageAllResult->detImg.rows; m_pImageAllResult->fscale_detToresult_y = m_pImageAllResult->resultImg.rows * 1.0f / m_pImageAllResult->detImg.rows;
#else }
else
{
ResizeImg(); ResizeImg();
#endif }
return 0; return 0;
} }

@ -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)
{
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); 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

@ -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点
@ -2374,6 +2374,110 @@ struct Base_Function_AD_Check
} }
}; };
// 盲失检测功能
struct Base_Function_MS_Check
{
bool bOpen; // 是否开启
float MS_IOU; // IOU 阈值(同位置判断)
float MS_Expand; // 扩张值(像素)
std::vector<std::string> ms_main_channel; // 主通道绑定
std::vector<std::string> ms_filter_channels; // 过滤通道绑定
Base_Function_MS_Check()
{
Init();
}
void Init()
{
bOpen = false;
MS_IOU = 0.8f;
MS_Expand = 0.0f;
ms_main_channel.clear();
ms_filter_channels.clear();
}
void copy(Base_Function_MS_Check tem)
{
this->bOpen = tem.bOpen;
this->MS_IOU = tem.MS_IOU;
this->MS_Expand = tem.MS_Expand;
this->ms_main_channel = tem.ms_main_channel;
this->ms_filter_channels = tem.ms_filter_channels;
}
void print(std::string str)
{
printf("%s", GetInfo(str).c_str());
}
std::string GetInfo(std::string str)
{
char buffer[256];
sprintf(buffer, "%s>>bOpen %d MS_IOU %f MS_Expand %f ", str.c_str(), bOpen, MS_IOU, MS_Expand);
std::string str123 = buffer;
for (int i = 0; i < ms_main_channel.size(); i++)
{
str123 += str + ":ms_main_channel " + ms_main_channel.at(i) + ";";
}
for (int i = 0; i < ms_filter_channels.size(); i++)
{
str123 += str + ":ms_filter_channels " + ms_filter_channels.at(i) + ";";
}
str123 += "\n";
return str123;
}
};
// Cell黑白点检测功能
struct Base_Function_CellBW_Check
{
bool bOpen; // 是否开启
float CellBW_IOU; // IOU 阈值(同位置判断)
float CellBW_Expand; // 扩张值(像素)
std::vector<std::string> cellbw_main_channel; // 主通道绑定
std::vector<std::string> cellbw_filter_channels; // 过滤通道绑定
Base_Function_CellBW_Check()
{
Init();
}
void Init()
{
bOpen = false;
CellBW_IOU = 0.8f;
CellBW_Expand = 0.0f;
cellbw_main_channel.clear();
cellbw_filter_channels.clear();
}
void copy(Base_Function_CellBW_Check tem)
{
this->bOpen = tem.bOpen;
this->CellBW_IOU = tem.CellBW_IOU;
this->CellBW_Expand = tem.CellBW_Expand;
this->cellbw_main_channel = tem.cellbw_main_channel;
this->cellbw_filter_channels = tem.cellbw_filter_channels;
}
void print(std::string str)
{
printf("%s", GetInfo(str).c_str());
}
std::string GetInfo(std::string str)
{
char buffer[256];
sprintf(buffer, "%s>>bOpen %d CellBW_IOU %f CellBW_Expand %f ", str.c_str(), bOpen, CellBW_IOU, CellBW_Expand);
std::string str123 = buffer;
for (int i = 0; i < cellbw_main_channel.size(); i++)
{
str123 += str + ":cellbw_main_channel " + cellbw_main_channel.at(i) + ";";
}
for (int i = 0; i < cellbw_filter_channels.size(); i++)
{
str123 += str + ":cellbw_filter_channels " + cellbw_filter_channels.at(i) + ";";
}
str123 += "\n";
return str123;
}
};
// 基础检测功能 // 基础检测功能
struct BaseCheckFunction struct BaseCheckFunction
{ {
@ -2383,6 +2487,9 @@ struct BaseCheckFunction
Base_Function_BigNG bigNG; Base_Function_BigNG bigNG;
Base_Function_EdgeChannel edgeChannel; Base_Function_EdgeChannel edgeChannel;
Base_Function_AD_Check ad_check; Base_Function_AD_Check ad_check;
Base_Function_MS_Check ms_check;
Base_Function_CellBW_Check cellbw_check;
bool bDrawAndSave; // 是否存图绘制(绘制并保存结果图,运行时替代 SAVE_RESIMG 宏)
BaseCheckFunction() BaseCheckFunction()
{ {
Init(); Init();
@ -2395,6 +2502,9 @@ struct BaseCheckFunction
bigNG.Init(); bigNG.Init();
edgeChannel.Init(); edgeChannel.Init();
ad_check.Init(); ad_check.Init();
ms_check.Init();
cellbw_check.Init();
bDrawAndSave = false;
} }
void copy(BaseCheckFunction tem) void copy(BaseCheckFunction tem)
{ {
@ -2404,6 +2514,9 @@ struct BaseCheckFunction
this->bigNG.copy(tem.bigNG); this->bigNG.copy(tem.bigNG);
this->edgeChannel.copy(tem.edgeChannel); this->edgeChannel.copy(tem.edgeChannel);
this->ad_check.copy(tem.ad_check); this->ad_check.copy(tem.ad_check);
this->ms_check.copy(tem.ms_check);
this->cellbw_check.copy(tem.cellbw_check);
this->bDrawAndSave = tem.bDrawAndSave;
} }
void print(std::string str) void print(std::string str)
{ {
@ -2414,6 +2527,9 @@ struct BaseCheckFunction
bigNG.print("bigNG"); bigNG.print("bigNG");
edgeChannel.print("edgeChannel"); edgeChannel.print("edgeChannel");
ad_check.print("ad_check"); ad_check.print("ad_check");
ms_check.print("ms_check");
cellbw_check.print("cellbw_check");
printf("bDrawAndSave %d\n", bDrawAndSave);
} }
std::string GetInfo(std::string str) std::string GetInfo(std::string str)
{ {
@ -2424,6 +2540,8 @@ struct BaseCheckFunction
str123 += bigNG.GetInfo("bigNG"); str123 += bigNG.GetInfo("bigNG");
str123 += edgeChannel.GetInfo("edgeChannel"); str123 += edgeChannel.GetInfo("edgeChannel");
str123 += ad_check.GetInfo("ad_check"); str123 += ad_check.GetInfo("ad_check");
str123 += ms_check.GetInfo("ms_check");
str123 += cellbw_check.GetInfo("cellbw_check");
// str123 += "\n"; // str123 += "\n";
return str123; return str123;
} }

@ -1537,6 +1537,96 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value)
_config.ad_check.Init(); _config.ad_check.Init();
} }
} }
// 是否存图绘制开关:控制结果图绘制与保存(运行时替代 SAVE_RESIMG 宏)
if ("bDrawAndSave" == strCode)
{
_config.bDrawAndSave = value["isOpen"].asBool();
}
// 盲失分析(code绑定的qx_Other)
if ("MS_Analysis" == strCode)
{
auto value_f = value;
// std::cout << value_f << std::endl;
_config.ms_check.bOpen = value_f["isOpen"].asBool();
if (_config.ms_check.bOpen)
{
// IOU分析
if (value_f["form"]["MS_Check_Param"]["ms_iou"])
{
_config.ms_check.MS_IOU = value_f["form"]["MS_Check_Param"]["ms_iou"].asFloat();
}
if (value_f["form"]["MS_Check_Param"]["ms_expand"])
{
_config.ms_check.MS_Expand = value_f["form"]["MS_Check_Param"]["ms_expand"].asFloat();
}
// 通道绑定
auto value_qx = value_f["form"]["MS_Check_Param"]["ms_main_channels"];
if (value_qx.isArray())
{
for (int idx = 0; idx < value_qx.size(); idx++)
{
std::string channel = value_qx[idx].asString();
_config.ms_check.ms_main_channel.push_back(channel);
}
}
value_qx = value_f["form"]["MS_Check_Param"]["ms_filter_channels"];
if (value_qx.isArray())
{
for (int idx = 0; idx < value_qx.size(); idx++)
{
std::string channel = value_qx[idx].asString();
_config.ms_check.ms_filter_channels.push_back(channel);
}
}
}
else
{
_config.ms_check.Init();
}
}
// Cell黑白点分析(code绑定的qx_Other)
if ("Cellbw_Analysis" == strCode)
{
auto value_f = value;
// std::cout << value_f << std::endl;
_config.cellbw_check.bOpen = value_f["isOpen"].asBool();
if (_config.cellbw_check.bOpen)
{
// IOU分析
if (value_f["form"]["CellBW_Check_Param"]["cellbw_iou"])
{
_config.cellbw_check.CellBW_IOU = value_f["form"]["CellBW_Check_Param"]["cellbw_iou"].asFloat();
}
if (value_f["form"]["CellBW_Check_Param"]["cellbw_expand"])
{
_config.cellbw_check.CellBW_Expand = value_f["form"]["CellBW_Check_Param"]["cellbw_expand"].asFloat();
}
// 通道绑定
auto value_qx = value_f["form"]["CellBW_Check_Param"]["cellbw_main_channels"];
if (value_qx.isArray())
{
for (int idx = 0; idx < value_qx.size(); idx++)
{
std::string channel = value_qx[idx].asString();
_config.cellbw_check.cellbw_main_channel.push_back(channel);
}
}
value_qx = value_f["form"]["CellBW_Check_Param"]["cellbw_filter_channels"];
if (value_qx.isArray())
{
for (int idx = 0; idx < value_qx.size(); idx++)
{
std::string channel = value_qx[idx].asString();
_config.cellbw_check.cellbw_filter_channels.push_back(channel);
}
}
}
else
{
_config.cellbw_check.Init();
}
}
return 0; return 0;
} }

Loading…
Cancel
Save