feat 初步添加关联通道分析

dev_lsy
liusiyang 2 months ago
parent 23a8043d32
commit ab3abb8fa8

@ -8,6 +8,8 @@
#include <mutex> #include <mutex>
#include <thread> #include <thread>
#include <condition_variable> #include <condition_variable>
#include <unordered_map>
#include <vector>
#include "CheckErrorCodeDefine.hpp" #include "CheckErrorCodeDefine.hpp"
#include "CheckConfigDefine.h" #include "CheckConfigDefine.h"
#include "QX_Analysis.h" #include "QX_Analysis.h"
@ -126,6 +128,32 @@ public:
} }
}; };
// 关联通道缺陷信息(用于判断关联通道是否存在脏污(dirty)重叠缺陷)
struct Correlated_Qx_Info_
{
std::string channel_name; // 缺陷所属通道
std::string camera_name; // 缺陷所属相机
int config_qx_type; // 缺陷配置类型 CONFIG_QX_NAME_
int result_type; // 缺陷结果类型(仅用于日志/追溯)
cv::Rect product_roi; // 产品坐标系下的缺陷ROI
Correlated_Qx_Info_()
{
channel_name = "";
camera_name = "";
config_qx_type = -1;
result_type = -1;
product_roi = cv::Rect(0, 0, 0, 0);
}
std::string GetInfo()
{
char buffer[256];
snprintf(buffer, sizeof(buffer), "cam:%s channel:%s cfgType:%d resType:%d roi:[%d,%d,%d,%d]",
camera_name.c_str(), channel_name.c_str(), config_qx_type, result_type,
product_roi.x, product_roi.y, product_roi.width, product_roi.height);
return std::string(buffer);
}
};
public: public:
QX_Merge_Analysis(); QX_Merge_Analysis();
~QX_Merge_Analysis(); ~QX_Merge_Analysis();
@ -146,6 +174,9 @@ public:
bool Idx(int qxidx); bool Idx(int qxidx);
bool AddQxInfo(int qxidx, QX_Info qxinfo, std::shared_ptr<DetLog> plog, std::shared_ptr<DetLog> pchannelLog); bool AddQxInfo(int qxidx, QX_Info qxinfo, std::shared_ptr<DetLog> plog, std::shared_ptr<DetLog> pchannelLog);
// 登记关联通道(非主/次通道)的缺陷信息,如脏污(dirty),供 AD 绑定分析判断重叠缺陷
bool AddCorrelatedQxInfo(Correlated_Qx_Info_ qxinfo, std::shared_ptr<DetLog> plog);
bool setSendStatus(std::string cameraName, RUN_STATUS_ status); bool setSendStatus(std::string cameraName, RUN_STATUS_ status);
bool waitComplete(int timeoutMs = 15000); bool waitComplete(int timeoutMs = 15000);
@ -176,6 +207,15 @@ private:
int Analysis_AD(ALL_Qx_DataList *pALLTypeqxList, int qx_idx); int Analysis_AD(ALL_Qx_DataList *pALLTypeqxList, int qx_idx);
int Analysis_AD_Bind(ALL_Qx_DataList *pALLTypeqxList, int qx_idx); int Analysis_AD_Bind(ALL_Qx_DataList *pALLTypeqxList, int qx_idx);
// 判断当前缺陷是否与关联通道(correlated_channels)中的脏污缺陷重叠
bool IsOverlapDirtyInCorrelatedChannel(const std::vector<std::string> &correlated_channels,
const std::string &cur_channel_name,
const std::string &cur_camera_name,
const cv::Rect &qx_product_roi,
int roi_expand,
float iou_threshold,
std::shared_ptr<DetLog> plog);
ChannelCheckFunction *GetChannelFuntion(std::string strChannelName); ChannelCheckFunction *GetChannelFuntion(std::string strChannelName);
double DistanceBetweenRectCenters(const cv::Rect &rect1, const cv::Rect &rect2, float fx, float fy); double DistanceBetweenRectCenters(const cv::Rect &rect1, const cv::Rect &rect2, float fx, float fy);
@ -201,6 +241,10 @@ private:
std::unordered_map<string, vector<AD_Channel_BD_Info_>> AD_list_bind; std::unordered_map<string, vector<AD_Channel_BD_Info_>> AD_list_bind;
// 关联通道缺陷缓存:channel_name -> 缺陷列表(产品坐标系)
std::unordered_map<std::string, std::vector<Correlated_Qx_Info_>> m_correlatedQxMap;
std::mutex mtx_correlatedQx;
private: private:
}; };

@ -746,6 +746,24 @@ 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());
} }
} }
// 关联通道分析:登记脏污(dirty)缺陷位置,供 AD 绑定分析判断关联通道是否存在重叠脏污缺陷
if (config_qx_type == CONFIG_QX_NAME_Dirty_L0 ||
config_qx_type == CONFIG_QX_NAME_Dirty_L1 ||
config_qx_type == CONFIG_QX_NAME_Dirty_L2)
{
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());

@ -28,6 +28,10 @@ int QX_Merge_Analysis::Clear()
{ {
m_pdetlogList.clear(); m_pdetlogList.clear();
m_statusList.clear(); m_statusList.clear();
{
std::lock_guard<std::mutex> lock(mtx_correlatedQx);
m_correlatedQxMap.clear();
}
return 0; return 0;
} }
@ -45,6 +49,10 @@ int QX_Merge_Analysis::AddCamer(std::string cameraName)
int QX_Merge_Analysis::InitData() int QX_Merge_Analysis::InitData()
{ {
m_reultList.Init(); m_reultList.Init();
{
std::lock_guard<std::mutex> lock(mtx_correlatedQx);
m_correlatedQxMap.clear();
}
m_pMergedetlog = std::make_shared<DetLog>(); m_pMergedetlog = std::make_shared<DetLog>();
m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "QX_Merge_Analysis", "InitData %s",CheckUtil::getCurTimeHMS().c_str()); m_pMergedetlog->AddCheckstr(PrintLevel_2, 3, "QX_Merge_Analysis", "InitData %s",CheckUtil::getCurTimeHMS().c_str());
@ -259,6 +267,163 @@ bool QX_Merge_Analysis::setSendStatus(std::string cameraName, RUN_STATUS_ status
return false; return false;
} }
/**
* @brief 判断缺陷配置类型是否为脏污(dirty)
* @param nconfigType 缺陷配置类型 CONFIG_QX_NAME_
* @return bool 是脏污返回true
*/
static bool IsDirtyConfigType(int nconfigType)
{
return nconfigType == CONFIG_QX_NAME_Dirty_L0 ||
nconfigType == CONFIG_QX_NAME_Dirty_L1 ||
nconfigType == CONFIG_QX_NAME_Dirty_L2;
}
/**
* @brief 判断关联通道名称是否需要参与判断(为空或NONE则不参与)
* @param strChannelName 关联通道名称
* @return bool 需要判断返回true
*/
static bool IsValidCorrelatedChannel(const std::string &strChannelName)
{
if (strChannelName == "")
{
return false;
}
if (CheckUtil::compareIgnoreCase(strChannelName, "NONE"))
{
return false;
}
return true;
}
bool QX_Merge_Analysis::AddCorrelatedQxInfo(Correlated_Qx_Info_ qxinfo, std::shared_ptr<DetLog> plog)
{
// 防御:通道为空或ROI非法时不登记,避免无效数据参与后续判断
if (qxinfo.channel_name == "" || qxinfo.product_roi.width <= 0 || qxinfo.product_roi.height <= 0)
{
return false;
}
{
std::lock_guard<std::mutex> lock(mtx_correlatedQx);
std::vector<Correlated_Qx_Info_> &qxList = m_correlatedQxMap[qxinfo.channel_name];
// 同一相机同一通道同一位置只登记一次,避免同一缺陷被重复登记
for (int i = 0; i < (int)qxList.size(); i++)
{
if (qxList.at(i).camera_name == qxinfo.camera_name &&
qxList.at(i).config_qx_type == qxinfo.config_qx_type &&
qxList.at(i).product_roi == qxinfo.product_roi)
{
return true;
}
}
qxList.push_back(qxinfo);
}
if (plog)
{
plog->AddCheckstr(PrintLevel_3, 3, "AddCorrelatedQxInfo", "add %s", qxinfo.GetInfo().c_str());
}
if (m_pMergedetlog)
{
m_pMergedetlog->AddCheckstr(PrintLevel_3, 3, "AddCorrelatedQxInfo", "add %s", qxinfo.GetInfo().c_str());
}
return true;
}
bool QX_Merge_Analysis::IsOverlapDirtyInCorrelatedChannel(const std::vector<std::string> &correlated_channels,
const std::string &cur_channel_name,
const std::string &cur_camera_name,
const cv::Rect &qx_product_roi,
int roi_expand,
float iou_threshold,
std::shared_ptr<DetLog> plog)
{
// 未配置关联通道(NONE/空)时不需要判断
if (correlated_channels.empty())
{
return false;
}
// 防御:ROI非法时不判断,避免无效计算与除零
if (qx_product_roi.width <= 0 || qx_product_roi.height <= 0)
{
return false;
}
// 拷贝出需要比较的脏污缺陷列表,避免在锁内做IoU计算
std::vector<Correlated_Qx_Info_> dirtyList;
{
std::lock_guard<std::mutex> lock(mtx_correlatedQx);
for (int i = 0; i < (int)correlated_channels.size(); i++)
{
const std::string &channel_name = correlated_channels.at(i);
if (!IsValidCorrelatedChannel(channel_name))
{
continue;
}
auto it = m_correlatedQxMap.find(channel_name);
if (it == m_correlatedQxMap.end())
{
continue;
}
for (int j = 0; j < (int)it->second.size(); j++)
{
if (IsDirtyConfigType(it->second.at(j).config_qx_type))
{
dirtyList.push_back(it->second.at(j));
}
}
}
}
if (dirtyList.empty())
{
return false;
}
// 与 Analysis_AD_Bind 中主次通道判断保持一致:双方均按 AD_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 i = 0; i < (int)dirtyList.size(); i++)
{
cv::Rect dirty_roi = dirtyList.at(i).product_roi;
cv::Rect dirty_expanded(dirty_roi.x - roi_expand, dirty_roi.y - roi_expand,
dirty_roi.width + roi_expand * 2, dirty_roi.height + roi_expand * 2);
float fiou = CheckUtil::CalIoU(roi_expanded, dirty_expanded);
if (plog)
{
plog->AddCheckstr(PrintLevel_3, 3, "CorrelatedDirty",
"cur %s cam %s roi %s <-> dirty %s roi %s expand %d iou %f",
cur_channel_name.c_str(), cur_camera_name.c_str(),
CheckUtil::GetRectString(qx_product_roi).c_str(),
dirtyList.at(i).channel_name.c_str(),
CheckUtil::GetRectString(dirty_roi).c_str(),
roi_expand, fiou);
}
// IOU 为 NaN(ROI 非法导致的除零)时比较结果为 false,不会误抑制 NG
if (fiou > iou_threshold)
{
if (plog)
{
plog->AddCheckstr(PrintLevel_1, 3, "CorrelatedDirty",
"cur %s cam %s roi %s overlap dirty %s cam %s roi %s expand %d iou %f > %f",
cur_channel_name.c_str(), cur_camera_name.c_str(),
CheckUtil::GetRectString(qx_product_roi).c_str(),
dirtyList.at(i).channel_name.c_str(), dirtyList.at(i).camera_name.c_str(),
CheckUtil::GetRectString(dirty_roi).c_str(),
roi_expand, fiou, iou_threshold);
}
return true;
}
}
return false;
}
/** /**
* @brief 等待所有任务完成 * @brief 等待所有任务完成
* @param timeoutMs 超时时间(毫秒) * @param timeoutMs 超时时间(毫秒)
@ -1509,26 +1674,55 @@ int QX_Merge_Analysis::Analysis_AD_Bind(ALL_Qx_DataList *pALLTypeqxList, int qx_
// 已经NG // 已经NG
if (bNG) if (bNG)
{ {
// 注意:按缺陷(blob)粒度逐条判断,避免把同一通道内与脏污无关的缺陷也一并放过
const int roi_expand = (int)(round)(pAd_checkParma->analysis_iou.AD_Expand);
const float iou_threshold = pAd_checkParma->analysis_iou.AD_IOU;
QX_channel_List *pqxList = pQXChannelList; QX_channel_List *pqxList = pQXChannelList;
for (int idx = 0; idx < (int)pqxList->qxList.size(); idx++) for (int idx = 0; idx < (int)pqxList->qxList.size(); idx++)
{ {
if (pqxList->qxList.at(idx).result == 0) if (pqxList->qxList.at(idx).result != 0)
{ {
pqxList->qxList.at(idx).result = 1; continue;
}
QX_RESULT tem;
tem.blobIdx = pqxList->qxList.at(idx).blobIdx;
tem.mindis = pqxList->qxList.at(idx).fmindis;
tem.flen = pqxList->qxList.at(idx).length;
tem.error_Type = pqxList->qxList.at(idx).nqx_type;
tem.camera_name = pqxList->qxList.at(idx).camera_name;
tem.channel_name = pqxList->qxList.at(idx).channel_name;
pqxList->pChannelDetlog->AddCheckstr(PrintLevel_4, 3, "result = NG", "Add New qx,Blob idx %d type %d num %d dis %f len %f ", tem.blobIdx, tem.error_Type, tem.qx_Num, tem.mindis, tem.flen);
m_pMergedetlog->AddCheckstr(PrintLevel_4, 3, "result = NG", "%s Add New qx,Blob idx %d type %d num %d dis %f len %f ",
tem.channel_name.c_str(), tem.blobIdx, tem.error_Type, tem.qx_Num, tem.mindis, tem.flen);
m_reultList.resultList.push_back(tem); // 关联通道存在与当前缺陷重叠的脏污缺陷时,该缺陷不记录NG结果
if (IsOverlapDirtyInCorrelatedChannel(correlated_channels,
pqxList->qxList.at(idx).channel_name,
pqxList->qxList.at(idx).camera_name,
pqxList->qxList.at(idx).product_roi,
roi_expand, iou_threshold,
pqxList->pChannelDetlog))
{
pqxList->pChannelDetlog->AddCheckstr(PrintLevel_1, 3, "result = NG skip",
"channel %s cam %s blob %d roi %s : 关联通道存在重叠, 不记录NG结果",
pqxList->qxList.at(idx).channel_name.c_str(),
pqxList->qxList.at(idx).camera_name.c_str(),
pqxList->qxList.at(idx).blobIdx,
CheckUtil::GetRectString(pqxList->qxList.at(idx).product_roi).c_str());
m_pMergedetlog->AddCheckstr(PrintLevel_1, 3, "result = NG skip",
"channel %s cam %s blob %d roi %s : 关联通道存在重叠, 不记录NG结果",
pqxList->qxList.at(idx).channel_name.c_str(),
pqxList->qxList.at(idx).camera_name.c_str(),
pqxList->qxList.at(idx).blobIdx,
CheckUtil::GetRectString(pqxList->qxList.at(idx).product_roi).c_str());
continue;
} }
pqxList->qxList.at(idx).result = 1;
QX_RESULT tem;
tem.blobIdx = pqxList->qxList.at(idx).blobIdx;
tem.mindis = pqxList->qxList.at(idx).fmindis;
tem.flen = pqxList->qxList.at(idx).length;
tem.error_Type = pqxList->qxList.at(idx).nqx_type;
tem.camera_name = pqxList->qxList.at(idx).camera_name;
tem.channel_name = pqxList->qxList.at(idx).channel_name;
pqxList->pChannelDetlog->AddCheckstr(PrintLevel_4, 3, "result = NG", "Add New qx,Blob idx %d type %d num %d dis %f len %f ", tem.blobIdx, tem.error_Type, tem.qx_Num, tem.mindis, tem.flen);
m_pMergedetlog->AddCheckstr(PrintLevel_4, 3, "result = NG", "%s Add New qx,Blob idx %d type %d num %d dis %f len %f ",
tem.channel_name.c_str(), tem.blobIdx, tem.error_Type, tem.qx_Num, tem.mindis, tem.flen);
m_reultList.resultList.push_back(tem);
} }
} }
} }

Loading…
Cancel
Save