@ -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,11 +1674,41 @@ 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 )
{
{
continue ;
}
// 关联通道存在与当前缺陷重叠的脏污缺陷时, 该缺陷不记录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 ;
pqxList - > qxList . at ( idx ) . result = 1 ;
QX_RESULT tem ;
QX_RESULT tem ;
@ -1531,7 +1726,6 @@ int QX_Merge_Analysis::Analysis_AD_Bind(ALL_Qx_DataList *pALLTypeqxList, int qx_
}
}
}
}
}
}
}
return 0 ;
return 0 ;
}
}