Compare commits

...

4 Commits

@ -45,7 +45,13 @@ public:
AI_Edge_QX_Det(/* args */); AI_Edge_QX_Det(/* args */);
~AI_Edge_QX_Det(); ~AI_Edge_QX_Det();
int Detect(const cv::Mat &img, cv::Mat &detmask, DetConfig *pDetConfig,std::shared_ptr<DetLog> pdetlog); /// @brief 边缘缺陷检测,检测结果根据配置参数合并到 mask
/// @param img 检测原图
/// @param detmask 合并目标 mask(主检测)
/// @param pDetConfig 检测参数
/// @param pdetlog 日志
/// @param pDetmask2 可选:第二个合并目标 mask(如弱线检测mask),按与主检测相同规则合并
int Detect(const cv::Mat &img, cv::Mat &detmask, DetConfig *pDetConfig, std::shared_ptr<DetLog> pdetlog, cv::Mat *pDetmask2 = nullptr);
private: private:
int SaveProcessImg(const cv::Mat &inImg, const cv::Mat &outImg, bool isALLzeros, DetConfig *pDetConfig, int idx = 0, int nruntype = 0); int SaveProcessImg(const cv::Mat &inImg, const cv::Mat &outImg, bool isALLzeros, DetConfig *pDetConfig, int idx = 0, int nruntype = 0);

@ -195,6 +195,8 @@ private:
int GetBlob_127cell(); int GetBlob_127cell();
// 获得 RLine_512 blob // 获得 RLine_512 blob
int GetBlob_RLine_512(); int GetBlob_RLine_512();
// 更新 RLine_512 mask 的 blob 行标记(合并边缘检测结果后刷新)
int UpdateBlobHFlag_RLine_512();
// 获得 BQ标签 blob // 获得 BQ标签 blob
int GetBlob_BQ(); int GetBlob_BQ();

@ -214,8 +214,7 @@ private:
int Judge_OK_Config(); int Judge_OK_Config();
int Judge_NG_Config(); int Judge_NG_Config();
// pAllowChannels 非空时仅列表内通道参与分析(用于主通道为空回退时仅跑次通道); nullptr=不过滤 int Analysis_AD(ALL_Qx_DataList *pALLTypeqxList, int qx_idx);
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);
// 关联过滤源过滤:移除与关联通道过滤源缺陷重叠的缺陷,使其不参与后续数量/距离/S分析 // 关联过滤源过滤:移除与关联通道过滤源缺陷重叠的缺陷,使其不参与后续数量/距离/S分析

@ -122,7 +122,7 @@ std::string AI_Edge_QX_Det::GetImgSaveName(int flag)
return str_root; return str_root;
} }
int AI_Edge_QX_Det::Detect(const cv::Mat &img, cv::Mat &detmask, DetConfig *pDetConfig, std::shared_ptr<DetLog> pdetlog) int AI_Edge_QX_Det::Detect(const cv::Mat &img, cv::Mat &detmask, DetConfig *pDetConfig, std::shared_ptr<DetLog> pdetlog, cv::Mat *pDetmask2)
{ {
static int n_count = 0; static int n_count = 0;
int nRuntype = 0; // 0:检测 1:测试。。。。。 int nRuntype = 0; // 0:检测 1:测试。。。。。
@ -169,6 +169,14 @@ int AI_Edge_QX_Det::Detect(const cv::Mat &img, cv::Mat &detmask, DetConfig *pDet
m_pdetlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "AI_Edge_QX_Det ", "nruntype %d %d\n", pDetConfig->pdege_Det_config->bsave_all, pDetConfig->pdege_Det_config->bsave_qx); m_pdetlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "AI_Edge_QX_Det ", "nruntype %d %d\n", pDetConfig->pdege_Det_config->bsave_all, pDetConfig->pdege_Det_config->bsave_qx);
// 第二个合并目标(如弱线检测mask):尺寸与主检测mask一致时才参与合并
bool bMergeDetmask2 = false;
if (pDetmask2 != nullptr && !pDetmask2->empty() && pDetmask2->size() == detmask.size())
{
bMergeDetmask2 = true;
m_pdetlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "AI_Edge_QX_Det ", "extra detmask merge on %s", pDetConfig->strCamChannel.c_str());
}
if (bdege || nRuntype != 0) if (bdege || nRuntype != 0)
{ {
showImg = img.clone(); showImg = img.clone();
@ -305,14 +313,27 @@ int AI_Edge_QX_Det::Detect(const cv::Mat &img, cv::Mat &detmask, DetConfig *pDet
if (pDetConfig->pdege_Det_config->type == Function_Edge_Det::Edge_type_Add) if (pDetConfig->pdege_Det_config->type == Function_Edge_Det::Edge_type_Add)
{ {
outMask(smallImg_roi).copyTo(detmask(mask_roi), outMask(smallImg_roi)); outMask(smallImg_roi).copyTo(detmask(mask_roi), outMask(smallImg_roi));
// 第二个合并目标(如弱线检测mask):与主检测mask相同规则合并
if (bMergeDetmask2)
{
outMask(smallImg_roi).copyTo((*pDetmask2)(mask_roi), outMask(smallImg_roi));
}
} }
else if (pDetConfig->pdege_Det_config->type == Function_Edge_Det::Edge_type_And) else if (pDetConfig->pdege_Det_config->type == Function_Edge_Det::Edge_type_And)
{ {
cv::bitwise_and(detmask(mask_roi), outMask(smallImg_roi), detmask(mask_roi)); cv::bitwise_and(detmask(mask_roi), outMask(smallImg_roi), detmask(mask_roi));
if (bMergeDetmask2)
{
cv::bitwise_and((*pDetmask2)(mask_roi), outMask(smallImg_roi), (*pDetmask2)(mask_roi));
}
} }
else else
{ {
outMask(smallImg_roi).copyTo(detmask(mask_roi)); outMask(smallImg_roi).copyTo(detmask(mask_roi));
if (bMergeDetmask2)
{
outMask(smallImg_roi).copyTo((*pDetmask2)(mask_roi));
}
} }
} }
} }

@ -318,18 +318,18 @@ int ALLImgCheckAnalysisy::InitAIFactory()
GPU_Config gpu; GPU_Config gpu;
int num = 0; int num = 0;
// for (int i = 0; i < MAX_GPU_NUM; i++) for (int i = 0; i < MAX_GPU_NUM; i++)
// { {
// gpu.UseGPUList[i] = m_RunConfig.UseGPUList[i]; gpu.UseGPUList[i] = m_RunConfig.UseGPUList[i];
// if (gpu.UseGPUList[i] >= 0) if (gpu.UseGPUList[i] >= 0)
// { {
// num++; num++;
// } }
// } }
// if (num == 0) if (num == 0)
{ {
gpu.UseGPUList[0] = 1; gpu.UseGPUList[0] = 0;
gpu.UseGPUList[1] = -1; gpu.UseGPUList[1] = 1;
} }
for (int i = 0; i < MAX_GPU_NUM; i++) for (int i = 0; i < MAX_GPU_NUM; i++)
{ {

@ -223,6 +223,25 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
QX_info->result = QX_RESULT_TYPE_NoJduge; 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) if (qx_status == QX_Stauts_Draw)
{ {
@ -746,23 +765,6 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
pQxLog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, " Use Num And Dis Judge ", "qx %s ,Add %s %s", qx_name.c_str(), BOOL_TO_STR_Error(bad), CheckUtil::getCurTimeHMS().c_str()); pQxLog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, " Use Num And Dis Judge ", "qx %s ,Add %s %s", qx_name.c_str(), BOOL_TO_STR_Error(bad), CheckUtil::getCurTimeHMS().c_str());
} }
} }
// 关联通道分析:登记关联过滤源缺陷位置(类型由 analysis_bind.correlated_types 配置, 如脏污/暗点),
// 供 AD 分析判断关联通道是否存在重叠缺陷
if (m_pQX_Merge_Analysis->IsCorrelatedSourceConfigType(config_qx_type))
{
QX_Merge_Analysis::Correlated_Qx_Info_ corr_qx;
corr_qx.channel_name = pImageResult->strChannel;
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());
}
} }
pQxLog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, " Cur Result ", "qx %s ,result = %s", qx_name.c_str(), resultType.c_str()); pQxLog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, " Cur Result ", "qx %s ,result = %s", qx_name.c_str(), resultType.c_str());

@ -174,7 +174,7 @@ int ImgCheckAnalysisy::GetStatus()
std::string ImgCheckAnalysisy::GetVersion() std::string ImgCheckAnalysisy::GetVersion()
{ {
return std::string("BOE_1.3.10_" + std::string(__DATE__) + "_" + std::string(__TIME__)); return std::string("BOE_1.3.11_" + std::string(__DATE__) + "_" + std::string(__TIME__));
} }
std::string ImgCheckAnalysisy::GetErrorInfo() std::string ImgCheckAnalysisy::GetErrorInfo()
@ -3889,9 +3889,26 @@ int ImgCheckAnalysisy::Edge_Det()
// cv::Mat temMask = cv::Mat::zeros(m_TemCheck.temImgList[TEM_IMG_IDX_AImask].size(), CV_8UC1); // cv::Mat temMask = cv::Mat::zeros(m_TemCheck.temImgList[TEM_IMG_IDX_AImask].size(), CV_8UC1);
if (m_pFuntion->function.f_dege_Det.bOpen) if (m_pFuntion->function.f_dege_Det.bOpen)
{ {
// 弱线检测(512模型)的mask:与主检测mask一样,根据 f_dege_Det 参数合并边缘检测结果
cv::Mat *pRLineDetMask = nullptr;
if (m_pFuntion->function.f_RLineDet.bOpen &&
m_pFuntion->function.f_RLineDet.bOpen_512 &&
m_pImageAllResult->RLine_512_DetAIResult &&
!m_pImageAllResult->RLine_512_DetAIResult->AI_MaskImg.empty())
{
pRLineDetMask = &m_pImageAllResult->RLine_512_DetAIResult->AI_MaskImg;
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, strBaseLog, " RLine_512 mask merge enable");
}
if (m_pFuntion->function.f_dege_Det.bdetUse) if (m_pFuntion->function.f_dege_Det.bdetUse)
{ {
m_AIEdge_QX_Det.Detect(m_CheckResult_shareP->in_shareImage->img, m_pImageAllResult->qx_DetAIResult->AI_MaskImg, &detconfig, m_pdetlog); m_AIEdge_QX_Det.Detect(m_CheckResult_shareP->in_shareImage->img, m_pImageAllResult->qx_DetAIResult->AI_MaskImg, &detconfig, m_pdetlog, pRLineDetMask);
// 合并后刷新弱线mask的blob行标记,保证合并进来的像素参与blob分析
if (pRLineDetMask != nullptr)
{
UpdateBlobHFlag_RLine_512();
}
} }
else else
{ {
@ -3909,6 +3926,50 @@ int ImgCheckAnalysisy::Edge_Det()
return 0; return 0;
} }
// 弱线检测mask合并边缘检测结果后,刷新blob行标记,保证合并进来的像素参与blob分析
int ImgCheckAnalysisy::UpdateBlobHFlag_RLine_512()
{
std::shared_ptr<ImageAllResult::Image_AI_Det_Result> pDetAIResult = m_pImageAllResult->RLine_512_DetAIResult;
if (!pDetAIResult || !pDetAIResult->blobDetParam)
{
return 1;
}
unsigned char *imgBlobHFlagData = pDetAIResult->blobDetParam->imgBlobHFlagData;
cv::Mat maskimg = pDetAIResult->AI_MaskImg;
if (imgBlobHFlagData == NULL || maskimg.empty())
{
return 1;
}
int nRows = pDetAIResult->blobDetParam->ndatalen;
if (nRows > maskimg.rows)
{
nRows = maskimg.rows;
}
int width = maskimg.cols;
int nSetNum = 0;
for (int y = 0; y < nRows; y++)
{
if (imgBlobHFlagData[y] != 0)
{
continue;
}
const unsigned char *p = maskimg.ptr<unsigned char>(y);
for (int x = 0; x < width; x++)
{
if (p[x] != 0)
{
imgBlobHFlagData[y] = 1;
nSetNum++;
break;
}
}
}
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "UpdateBlobHFlag_RLine_512", " RLine_512 blob HFlag update rows %d", nSetNum);
return 0;
}
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");

@ -8,9 +8,6 @@
#include "CheckUtil.hpp" #include "CheckUtil.hpp"
#include "CheckConfigDefine.h" #include "CheckConfigDefine.h"
// Analysis_AD_Bind 返回码: 主通道为空(配置为空或本次无匹配通道), 调用方回退执行 Analysis_AD
static const int AD_BIND_RE_MAIN_EMPTY = 2;
QX_Merge_Analysis::QX_Merge_Analysis() QX_Merge_Analysis::QX_Merge_Analysis()
{ {
m_bExit = false; m_bExit = false;
@ -1028,35 +1025,7 @@ int QX_Merge_Analysis::Analysis_QXtype(ALL_Qx_DataList *pALLTypeqxList, int qx_i
{ {
if(m_pbaseCheckFunction->ad_check.analysis_bind.bUse) if(m_pbaseCheckFunction->ad_check.analysis_bind.bUse)
{ {
// 主通道为空: Analysis_AD_Bind 返回回退码, 用次通道列表里的通道走 Analysis_AD 老逻辑 Analysis_AD_Bind(pALLTypeqxList, qx_idx);
if (Analysis_AD_Bind(pALLTypeqxList, qx_idx) == AD_BIND_RE_MAIN_EMPTY)
{
// 回退过滤: 仅次通道列表(2s_second_channel + 3s_second_channel, 去重)中的通道参与
std::vector<std::string> fallback_channels;
const std::vector<std::string> &fallback_sec2 = m_pbaseCheckFunction->ad_check.analysis_bind.second_channel_2s;
const std::vector<std::string> &fallback_sec3 = m_pbaseCheckFunction->ad_check.analysis_bind.second_channel_3s;
fallback_channels.insert(fallback_channels.end(), fallback_sec2.begin(), fallback_sec2.end());
for (size_t k = 0; k < fallback_sec3.size(); k++)
{
if (std::find(fallback_channels.begin(), fallback_channels.end(), fallback_sec3[k]) == fallback_channels.end())
{
fallback_channels.push_back(fallback_sec3[k]);
}
}
std::string strFallbackChannels;
for (size_t k = 0; k < fallback_channels.size(); k++)
{
strFallbackChannels += fallback_channels[k];
if (k + 1 < fallback_channels.size())
{
strFallbackChannels += ",";
}
}
m_pMergedetlog->AddCheckstr(PrintLevel_1, 3, "Analysis_AD_Bind",
"main channel empty --> fallback Analysis_AD (only second channels: %s)",
fallback_channels.empty() ? "<empty>" : strFallbackChannels.c_str());
Analysis_AD(pALLTypeqxList, qx_idx, &fallback_channels);
}
} }
else else
{ {
@ -1104,7 +1073,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, const std::vector<std::string> *pAllowChannels) int QX_Merge_Analysis::Analysis_AD(ALL_Qx_DataList *pALLTypeqxList, int qx_idx)
{ {
AD_list.clear(); AD_list.clear();
if (!m_pbaseCheckFunction) if (!m_pbaseCheckFunction)
@ -1123,14 +1092,6 @@ 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];
// 回退过滤: pAllowChannels 非空时仅允许列表内(次通道列表)的通道参与
if (pAllowChannels &&
std::find(pAllowChannels->begin(), pAllowChannels->end(), pQXChannelList->channel_name) == pAllowChannels->end())
{
pQXChannelList->pChannelDetlog->AddCheckstr(PrintLevel_1, 3, "Analysis_AD",
"channel %s not in allow list(fallback) --> skip", pQXChannelList->channel_name.c_str());
continue;
}
if (!pAd_checkParma) if (!pAd_checkParma)
{ {
continue; continue;
@ -1375,14 +1336,6 @@ 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];
// 回退过滤: pAllowChannels 非空时仅允许列表内(次通道列表)的通道被判定NG
if (pAllowChannels &&
std::find(pAllowChannels->begin(), pAllowChannels->end(), pQXChannelList->channel_name) == pAllowChannels->end())
{
pQXChannelList->pChannelDetlog->AddCheckstr(PrintLevel_1, 3, "Analysis_AD",
"channel %s not in allow list(fallback) --> skip NG mark", pQXChannelList->channel_name.c_str());
continue;
}
if (!pAd_checkParma->bOpen) if (!pAd_checkParma->bOpen)
{ {
@ -1593,12 +1546,6 @@ int QX_Merge_Analysis::Analysis_AD_Bind(ALL_Qx_DataList *pALLTypeqxList, int qx_
m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "Analysis_AD_Bind", "main_channel %d second_channel %d", m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "Analysis_AD_Bind", "main_channel %d second_channel %d",
(int)main_channel_s_qxList.size(), (int)second_channel_s_qxList.size()); (int)main_channel_s_qxList.size(), (int)second_channel_s_qxList.size());
/* 主通道为空(配置为空或本次无匹配通道): 返回回退码, 由调用方改用 Analysis_AD 老逻辑 */
if (main_channel_s_qxList.empty())
{
return AD_BIND_RE_MAIN_EMPTY;
}
/* 画面分析 */ /* 画面分析 */
AD_list_bind.clear(); AD_list_bind.clear();
for(int i_main = 0; i_main < main_channel_s_qxList.size(); i_main++) for(int i_main = 0; i_main < main_channel_s_qxList.size(); i_main++)

Loading…
Cancel
Save