@ -1378,38 +1378,11 @@ int ImgCheckAnalysisy::AI_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg)
long t1 , t2 , t3 ;
t1 = CheckUtil : : getcurTime ( ) ;
SmallRoiList . clear ( ) ;
SmallRoiList . erase ( SmallRoiList . begin ( ) , SmallRoiList . end ( ) ) ;
cv : : Rect cutRoi ;
cutRoi . x = 0 ;
cutRoi . y = 0 ;
cutRoi . width = img . cols - 0 ;
cutRoi . height = img . rows - 0 ;
int deal_image_width = pAIDetList [ 0 ] - > input_0 . width ;
int deal_image_height = pAIDetList [ 0 ] - > input_0 . height ;
int re = CheckUtil : : cutSmallImg ( img , SmallRoiList , cutRoi , deal_image_width , deal_image_height , 0 , 0 ) ;
m_pdetlog - > AddCheckstr ( PrintLevel_1 , DET_LOG_LEVEL_3 , strBaseLog , " cutSmallImg Num %d " , SmallRoiList . size ( ) ) ;
if ( re ! = 0 | | SmallRoiList . size ( ) < = 0 )
if ( img . empty ( ) )
{
m_pdetlog - > AddCheckstr ( PrintLevel_1 , DET_LOG_LEVEL_3 , strBaseLog , " cutSmallImg error %d" , re ) ;
m_pdetlog - > AddCheckstr ( PrintLevel_1 , DET_LOG_LEVEL_3 , strBaseLog , " input img empty error " ) ;
m_pdetlog - > AddCheckstr ( PrintLevel_0 , DET_LOG_LEVEL_3 , strBaseLog , " AI_Detect End " ) ;
return re ;
/* code */
}
// 临时存图
if ( DetImgInfo_shareP - > bsaveProcessImg )
{
cv : : Mat imshow = img . clone ( ) ; // 保持输入通道,不再灰度转假彩
for ( int i = 0 ; i < SmallRoiList . size ( ) ; i + + )
{
cv : : rectangle ( imshow , SmallRoiList . at ( i ) , CheckUtil : : GetDrawColor ( imshow , cv : : Scalar ( 0 , 0 , 255 ) ) , 3 ) ;
}
cv : : imwrite ( DetImgInfo_shareP - > strChannel + " _AI_Det_ROI.jpg " , imshow ) ;
return 1 ;
}
ResultImg = cv : : Mat : : zeros ( img . size ( ) , CV_8UC1 ) ;
@ -1422,105 +1395,108 @@ int ImgCheckAnalysisy::AI_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg)
modelMaskList [ m ] = cv : : Mat : : zeros ( img . size ( ) , CV_8UC1 ) ;
}
const int totalTasks = SmallRoiList . size ( ) ;
// 整图检测模式下,所有模型的 ROI 都是整幅检测图
const cv : : Rect fullRoi ( 0 , 0 , img . cols , img . rows ) ;
// std::string str_Root = m_strRootPath + pDetConfig->strProductID + "_" + pDetConfig->strchannel + "_";
t2 = CheckUtil : : getcurTime ( ) ;
// 依次用多个模型做检测,所有模型输出的 mask 取并集作为最终 outmask
// 模型实际输入图(整图 resize 到模型输入大小)缓存一份,供结果记录使用
cv : : Mat firstModelInput ;
// 依次用多个模型做检测:整图 resize 到模型输入大小 -> 推理 -> 输出 mask resize 回原图大小,
// 所有模型输出的 mask 取并集作为最终 outmask
for ( size_t m = 0 ; m < pAIDetList . size ( ) ; m + + )
{
std : : shared_ptr < AIModel_Base > pAIDet = pAIDetList [ m ] ;
int submitted = 0 ;
int completed = 0 ;
while ( completed < totalTasks )
std : : string strModelName = ( m < pAIDetNameList . size ( ) ) ? pAIDetNameList [ m ] : std : : string ( AI_DET_MODEL_NAME_UnKnown ) ;
int deal_image_width = pAIDet - > input_0 . width ;
int deal_image_height = pAIDet - > input_0 . height ;
if ( deal_image_width < = 0 | | deal_image_height < = 0 )
{
// 如果任务还没提交完,且当前处理任务数 < 10, 提交新任务
if ( submitted < totalTasks & & runner - > GetProcessingCount ( ) < 10 )
{
m_pdetlog - > AddCheckstr ( PrintLevel_1 , DET_LOG_LEVEL_3 , strBaseLog , " %s model input size error [%d %d] " , strModelName . c_str ( ) , deal_image_width , deal_image_height ) ;
m_pdetlog - > AddCheckstr ( PrintLevel_0 , DET_LOG_LEVEL_3 , strBaseLog , " AI_Detect End " ) ;
return 2 ;
}
std : : shared_ptr < AIMulThreadRunBase : : AITask > task = std : : make_shared < AIMulThreadRunBase : : AITask > ( ) ;
task - > id = submitted ;
task - > roi = SmallRoiList . at ( submitted ) ;
task - > input = img ( SmallRoiList . at ( submitted ) ) . clone ( ) ;
task - > output = std : : make_shared < cv : : Mat > ( ) ;
task - > engine = pAIDet ;
// 1、整图 resize 到模型输入大小
cv : : Mat detInputImg ;
cv : : resize ( img , detInputImg , cv : : Size ( deal_image_width , deal_image_height ) ) ;
// 模型输入要求单通道;原图为彩色时按 BGR 顺序转灰度(与 imread(path,0) 的亮度一致)
if ( detInputImg . channels ( ) = = 3 )
{
cv : : cvtColor ( detInputImg , detInputImg , cv : : COLOR_BGR2GRAY ) ;
}
else if ( detInputImg . channels ( ) = = 4 )
{
cv : : cvtColor ( detInputImg , detInputImg , cv : : COLOR_BGRA2GRAY ) ;
}
runner - > SubmitTask ( task ) ;
submitted + + ;
}
if ( m = = 0 )
{
firstModelInput = detInputImg ;
}
// 尝试取结果
std : : shared_ptr < AIMulThreadRunBase : : AITask > result ;
if ( runner - > PopResult ( result ) )
{
m_pdetlog - > AddCheckstr ( PrintLevel_1 , DET_LOG_LEVEL_3 , strBaseLog , " %s input img [%d*%d] -> model [%d*%d] " ,
strModelName . c_str ( ) , img . cols , img . rows , deal_image_width , deal_image_height ) ;
{
std : : lock_guard < std : : mutex > lock ( mtx_AIMaskImgBLobQueue ) ;
m_AIMaskImgBLobQueue . push ( result ) ;
}
// 临时存图:保存模型实际输入图
if ( DetImgInfo_shareP - > bsaveProcessImg )
{
cv : : imwrite ( DetImgInfo_shareP - > strChannel + " _AI_Det_ " + strModelName + " _in.jpg " , detInputImg ) ;
}
cv : : Mat & outimg = * ( result - > output ) ;
if ( ! outimg . empty ( ) )
{
// 多个模型的结果取并集
cv : : Mat roiMat = ResultImg ( result - > roi ) ;
cv : : bitwise_or ( roiMat , outimg , roiMat ) ;
// 2、整图推理
cv : : Mat modelMask ;
int re = pAIDet - > AIDet ( detInputImg , modelMask ) ;
if ( re ! = 0 )
{
m_pdetlog - > AddCheckstr ( PrintLevel_1 , DET_LOG_LEVEL_3 , strBaseLog , " %s AIDet error %d " , strModelName . c_str ( ) , re ) ;
m_pdetlog - > AddCheckstr ( PrintLevel_0 , DET_LOG_LEVEL_3 , strBaseLog , " AI_Detect End " ) ;
return re ;
}
// 当前模型自己的 mask 单独记录一份
if ( m < modelMaskList . size ( ) & & ! modelMaskList [ m ] . empty ( ) )
{
cv : : Mat modelRoiMat = modelMaskList [ m ] ( result - > roi ) ;
cv : : bitwise_or ( modelRoiMat , outimg , modelRoiMat ) ;
}
// 3、输出 mask resize 回原图大小(最近邻,保证 mask 像素值不被插值改变)
cv : : Mat modelMaskFull ;
if ( ! modelMask . empty ( ) )
{
cv : : resize ( modelMask , modelMaskFull , img . size ( ) , 0 , 0 , cv : : INTER_NEAREST ) ;
// AI 检测残点图存图:每个模型的结果都存,并增加一级 模型名称 目录,
// 用以区分该残点是由哪个模型检出的
// 目录结构:/home/aidlux/BOE/ZB_SOCKET/AI_Detect/<模型名称>/<产品ID>/
if ( m_pbaseCheckFunction - > saveImg . bSaveAIDetImg )
{
std : : string strModelName = ( m < pAIDetNameList . size ( ) ) ? pAIDetNameList [ m ] : std : : string ( AI_DET_MODEL_NAME_UnKnown ) ;
std : : string roi_ext = " [ " + std : : to_string ( result - > roi . x ) + " , " + std : : to_string ( result - > roi . y ) + " ] " ;
std : : string strSaveDir = " /home/aidlux/BOE/ZB_SOCKET/AI_Detect/ " + strModelName + " / " + DetImgInfo_shareP - > strImgProductID + " / " ;
CheckUtil : : CreateDir ( strSaveDir ) ;
std : : string strSavePath_in = strSaveDir + m_strCurDetChannel + " _ " + roi_ext + " _in.png " ;
std : : string strSavePath_out = strSaveDir + m_strCurDetChannel + " _ " + roi_ext + " _out.png " ;
cv : : imwrite ( strSavePath_in , result - > input ) ;
cv : : imwrite ( strSavePath_out , outimg ) ;
}
}
// 多个模型的 mask 取并集
cv : : bitwise_or ( ResultImg , modelMaskFull , ResultImg ) ;
// 同一 roi 的多个模型结果取并集后存入 AI_Qx_MaskList
bool bFind = false ;
for ( auto & item : m_pImageAllResult - > AI_Qx_MaskList )
{
if ( item - > roi = = result - > roi )
{
cv : : bitwise_or ( item - > AI_mask , outimg , item - > AI_mask ) ;
bFind = true ;
break ;
}
}
if ( ! bFind )
{
std : : shared_ptr < ImageAllResult : : AI_Det_MaskImg > temAIresult = std : : make_shared < ImageAllResult : : AI_Det_MaskImg > ( ) ;
temAIresult - > roi = result - > roi ;
temAIresult - > AI_inImg = result - > input ;
temAIresult - > AI_mask = outimg . clone ( ) ;
m_pImageAllResult - > AI_Qx_MaskList . push_back ( temAIresult ) ;
}
completed + + ;
}
else
{
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 1 ) ) ;
}
// 当前模型自己的 mask 单独记录一份
cv : : bitwise_or ( modelMaskList [ m ] , modelMaskFull , modelMaskList [ m ] ) ;
}
// AI 检测残点图存图:每个模型的结果都存,并增加一级 模型名称 目录,
// 用以区分该残点是由哪个模型检出的
// 目录结构:/home/aidlux/BOE/ZB_SOCKET/AI_Detect/<模型名称>/<产品ID>/
if ( m_pbaseCheckFunction - > saveImg . bSaveAIDetImg & & ! modelMaskFull . empty ( ) )
{
std : : string strSaveDir = " /home/aidlux/BOE/ZB_SOCKET/AI_Detect/ " + strModelName + " / " + DetImgInfo_shareP - > strImgProductID + " / " ;
CheckUtil : : CreateDir ( strSaveDir ) ;
std : : string strSavePath_in = strSaveDir + m_strCurDetChannel + " _in.png " ;
std : : string strSavePath_out = strSaveDir + m_strCurDetChannel + " _out.png " ;
cv : : imwrite ( strSavePath_in , detInputImg ) ;
cv : : imwrite ( strSavePath_out , modelMaskFull ) ;
}
// 4、mask 结果放入队列,用于 AIMaskDet 加速 blob 计算(整图 ROI)
if ( ! modelMaskFull . empty ( ) )
{
std : : shared_ptr < AIMulThreadRunBase : : AITask > maskTask = std : : make_shared < AIMulThreadRunBase : : AITask > ( ) ;
maskTask - > id = static_cast < int > ( m ) ;
maskTask - > roi = fullRoi ;
maskTask - > output = std : : make_shared < cv : : Mat > ( modelMaskFull ) ;
std : : lock_guard < std : : mutex > lock ( mtx_AIMaskImgBLobQueue ) ;
m_AIMaskImgBLobQueue . push ( maskTask ) ;
}
}
t3 = CheckUtil : : getcurTime ( ) ;
float mean_AI = ( t3 - t2 ) / ( SmallRoiList . size ( ) * pAIDetList . size ( ) ) ;
m_pdetlog - > AddCheckstr ( PrintLevel_1 , DET_LOG_LEVEL_3 , strBaseLog , " AI Run Time: sum %ld pre %ld Run %ld mean One Sma ll Img %f" , t3 - t1 , t2 - t1 , t3 - t2 , mean_AI ) ;
float mean_AI = ( t3 - t2 ) / ( float ) pAIDetList . size ( ) ;
m_pdetlog - > AddCheckstr ( PrintLevel_1 , DET_LOG_LEVEL_3 , strBaseLog , " AI Run Time: sum %ld pre %ld Run %ld mean One Fu ll Img %f" , t3 - t1 , t2 - t1 , t3 - t2 , mean_AI ) ;
// 保存各模型的 全图 mask, 并输出各模型检出的残点像素数量, 便于追溯
for ( size_t m = 0 ; m < modelMaskList . size ( ) ; m + + )
@ -1534,6 +1510,27 @@ int ImgCheckAnalysisy::AI_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg)
temModelMask - > strModelName . c_str ( ) , cv : : countNonZero ( temModelMask - > ModelMask ) ) ;
}
// 整图检测模式下所有模型共用同一个 ROI(整幅检测图),多个模型的 mask 已取并集,
// 按整图 ROI 记录一条 AI 检测结果,供 GetAIDetImg 按缺陷中心点取到 AI 输入图与并集 mask
bool bFind = false ;
for ( auto & item : m_pImageAllResult - > AI_Qx_MaskList )
{
if ( item - > roi = = fullRoi )
{
cv : : bitwise_or ( item - > AI_mask , ResultImg , item - > AI_mask ) ;
bFind = true ;
break ;
}
}
if ( ! bFind )
{
std : : shared_ptr < ImageAllResult : : AI_Det_MaskImg > temAIresult = std : : make_shared < ImageAllResult : : AI_Det_MaskImg > ( ) ;
temAIresult - > roi = fullRoi ;
temAIresult - > AI_inImg = firstModelInput ;
temAIresult - > AI_mask = ResultImg . clone ( ) ;
m_pImageAllResult - > AI_Qx_MaskList . push_back ( temAIresult ) ;
}
m_pdetlog - > AddCheckstr ( PrintLevel_0 , DET_LOG_LEVEL_3 , strBaseLog , " AI_Detect End " ) ;
// 临时存图