feat 区分残点来源,日志+存图

dev_lsy
liusiyang 2 months ago
parent 68f59a7a77
commit cbb7737c9a

@ -44,6 +44,13 @@ public:
cv::Mat AI_mask;
};
// 单个检测模型输出的 全图 mask,用于追溯 残点(blob) 由哪个模型检出
struct AI_Model_MaskImg
{
std::string strModelName; // 模型名称
cv::Mat ModelMask; // 该模型输出的 全图 mask
};
private:
/* data */
public:
@ -87,6 +94,8 @@ public:
std::shared_ptr<CameraBaseResult> cameraBaseResult; // 相机相关的基本结果信息
std::vector<std::shared_ptr<AI_Det_MaskImg>> AI_Qx_MaskList;
// 各检测模型独立的全图 mask 列表(与检测模型一一对应)
std::vector<std::shared_ptr<AI_Model_MaskImg>> AI_Model_MaskList;
std::mutex mtx_Det; // 互斥量
private:
PRINT_LOG_ m_PrintLog;

@ -27,6 +27,7 @@ struct QX_ERROR_INFO_
float fbreadth;
int nconfig_qx_type;
std::string qx_name;
std::string strModelName; // 检出该残点(blob)的模型名称
int maxValue;
int whiteOrBlack;
float grayDis;
@ -53,6 +54,7 @@ struct QX_ERROR_INFO_
flen = 0;
nconfig_qx_type = 0;
qx_name = "";
strModelName = "";
maxValue = 0;
grayDis = 0;
fUpIou = 0;
@ -79,6 +81,7 @@ struct QX_ERROR_INFO_
<< ", Flen: " << flen
<< ", nconfig_qx_type: " << nconfig_qx_type
<< ", QX Name: " << qx_name
<< ", Model Name: " << strModelName
<< ", Max Value: " << maxValue
<< ", Gray Dis: " << grayDis
<< ", fUpIou: " << fUpIou

@ -198,6 +198,9 @@ private:
// 把blob 汇总成 检测结果。
int BLobToDetResult();
// 获取指定 残点(blob) 是由哪个(哪些)检测模型检出的
std::string GetBlobModelName(const cv::Rect &roi);
//自适应参数区域更新
int Adapt_Config(cv::RotatedRect tplOuterRect, cv::RotatedRect curOuterRect, cv::Mat& det_img);

@ -270,6 +270,13 @@ struct DetectInfo
}
};
// 残点检测模型名称:用于区分残点由哪个模型检出(存图分文件夹 + 日志追溯)
#define AI_DET_MODEL_NAME_Defect "Defect"
#define AI_DET_MODEL_NAME_QueXi "Defect_QueXi"
#define AI_DET_MODEL_NAME_UnKnown "UnKnown"
// 多个模型都检出同一个残点时的连接符
#define AI_DET_MODEL_NAME_JOIN "+"
struct QXImageResult
{
int type; // 缺陷类型

@ -38,6 +38,7 @@ Json::Value CheckResultJson::toJsonValue()
value["flen"] = p->flen;
value["nconfig_qx_type"] = p->nconfig_qx_type;
value["qx_name"] = p->qx_name;
value["det_model_name"] = p->strModelName;
value["maxValue"] = p->maxValue;
value["grayDis"] = p->grayDis;
value["fUpIou"] = p->fUpIou;
@ -117,6 +118,11 @@ void CheckResultJson::toObjectFromValue(Json::Value root)
tem.flen = errorJson["flen"].asFloat();
tem.nconfig_qx_type = errorJson["nconfig_qx_type"].asInt();
tem.qx_name = errorJson["qx_name"].asString();
// 旧版本 json 可能没有该字段
if (errorJson.isMember("det_model_name"))
{
tem.strModelName = errorJson["det_model_name"].asString();
}
tem.maxValue = errorJson["maxValue"].asInt();
tem.grayDis = errorJson["grayDis"].asFloat();
tem.fUpIou = errorJson["fUpIou"].asFloat();

@ -173,9 +173,9 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
std::string qx_wb = WHITE_BLCAK_Names[QX_whiteBLACK];
pQxLog->AddCheckstr(PrintLevel_1,
"", "qxidx: %d roi[%d %d %d %d] qx %d %s %s JudgArea %f hj %f len %f breadth %f energy %d region num %ld",
"", "qxidx: %d roi[%d %d %d %d] qx %d %s %s JudgArea %f hj %f len %f breadth %f energy %d region num %ld detModel: %s",
qxidx, roi.x, roi.y, roi.width, roi.height, config_qx_type, qx_name.c_str(), qx_wb.c_str(),
JudgArea, grayDis, flen, fbreadth, energy, QX_info->detRegionidxList.size());
JudgArea, grayDis, flen, fbreadth, energy, QX_info->detRegionidxList.size(), QX_info->strModelName.c_str());
cv::Point pCenter;
pCenter.x = roi.x + roi.width * 0.5;
@ -559,7 +559,7 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img);
m_CheckResult_shareP->qxImageResult.push_back(tem);
pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, " result ", " ---name: %s ---code: %s ---srcImgroi.x: %d ---srcImgroi.y: %d\n", tem.strTypeName.c_str(), tem.qx_Code.c_str(), tem.srcImgroi.x, tem.srcImgroi.y);
pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, " result ", " ---name: %s ---code: %s ---detModel: %s ---srcImgroi.x: %d ---srcImgroi.y: %d\n", tem.strTypeName.c_str(), tem.qx_Code.c_str(), QX_info->strModelName.c_str(), tem.srcImgroi.x, tem.srcImgroi.y);
}
else
{
@ -572,6 +572,8 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img);
m_CheckResult_shareP->YS_ImageResult.push_back(tem);
// 疑似小图 也需要能追溯 是哪个模型检出的残点
pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, " YS result ", " ---name: %s ---code: %s ---detModel: %s ---srcImgroi.x: %d ---srcImgroi.y: %d\n", tem.strTypeName.c_str(), tem.qx_Code.c_str(), QX_info->strModelName.c_str(), tem.srcImgroi.x, tem.srcImgroi.y);
}
}
}
@ -673,6 +675,8 @@ int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img);
m_CheckResult_shareP->qxImageResult.push_back(tem);
// YS 转 NG 的残点也需要能追溯 是哪个模型检出的
pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, " YS to NG img ", " ---name: %s ---code: %s ---detModel: %s ---srcImgroi.x: %d ---srcImgroi.y: %d\n", tem.strTypeName.c_str(), tem.qx_Code.c_str(), QX_info->strModelName.c_str(), tem.srcImgroi.x, tem.srcImgroi.y);
}
}
}

@ -1346,6 +1346,11 @@ int ImgCheckAnalysisy::AI_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg)
pAIDetList.push_back(AI_Factory->Defect);
pAIDetList.push_back(AI_Factory->Defect_QueXi);
// 与 pAIDetList 一一对应的模型名称,用于区分残点由哪个模型检出
std::vector<std::string> pAIDetNameList;
pAIDetNameList.push_back(AI_DET_MODEL_NAME_Defect);
pAIDetNameList.push_back(AI_DET_MODEL_NAME_QueXi);
std::string strBaseLog = "AI_Detect";
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "AI_Detect Start");
@ -1396,6 +1401,14 @@ int ImgCheckAnalysisy::AI_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg)
ResultImg = cv::Mat::zeros(img.size(), CV_8UC1);
// 每个模型单独保存一份全图 mask,便于后续追溯残点由哪个模型检出
m_pImageAllResult->AI_Model_MaskList.clear();
std::vector<cv::Mat> modelMaskList(pAIDetList.size());
for (size_t m = 0; m < pAIDetList.size(); m++)
{
modelMaskList[m] = cv::Mat::zeros(img.size(), CV_8UC1);
}
const int totalTasks = SmallRoiList.size();
// std::string str_Root = m_strRootPath + pDetConfig->strProductID + "_" + pDetConfig->strchannel + "_";
@ -1440,6 +1453,28 @@ int ImgCheckAnalysisy::AI_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg)
// 多个模型的结果取并集
cv::Mat roiMat = ResultImg(result->roi);
cv::bitwise_or(roiMat, outimg, roiMat);
// 当前模型自己的 mask 单独记录一份
if (m < modelMaskList.size() && !modelMaskList[m].empty())
{
cv::Mat modelRoiMat = modelMaskList[m](result->roi);
cv::bitwise_or(modelRoiMat, outimg, modelRoiMat);
}
// 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);
}
}
// 同一 roi 的多个模型结果取并集后存入 AI_Qx_MaskList
@ -1474,6 +1509,18 @@ int ImgCheckAnalysisy::AI_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg)
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 Small Img %f", t3 - t1, t2 - t1, t3 - t2, mean_AI);
// 保存各模型的 全图 mask,并输出各模型检出的残点像素数量,便于追溯
for (size_t m = 0; m < modelMaskList.size(); m++)
{
std::shared_ptr<ImageAllResult::AI_Model_MaskImg> temModelMask = std::make_shared<ImageAllResult::AI_Model_MaskImg>();
temModelMask->strModelName = (m < pAIDetNameList.size()) ? pAIDetNameList[m] : std::string(AI_DET_MODEL_NAME_UnKnown);
temModelMask->ModelMask = modelMaskList[m];
m_pImageAllResult->AI_Model_MaskList.push_back(temModelMask);
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, " Det Model: %s mask pixel num %d",
temModelMask->strModelName.c_str(), cv::countNonZero(temModelMask->ModelMask));
}
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "AI_Detect End");
// 临时存图
@ -2058,6 +2105,53 @@ int ImgCheckAnalysisy::Pin_Qx_Det(const cv::Mat &img)
return 0;
}
// 获取指定 残点(blob) 是由哪个(哪些)检测模型检出的
// 做法:对各模型自己输出的全图 mask,在 blob 的 roi 内统计非零像素;
// 非零则说明该模型在该残点区域有检出。多个模型都检出时用 "+" 连接。
std::string ImgCheckAnalysisy::GetBlobModelName(const cv::Rect &roi)
{
std::string strModelName = "";
if (!m_pImageAllResult)
{
return AI_DET_MODEL_NAME_UnKnown;
}
for (auto &pModelMask : m_pImageAllResult->AI_Model_MaskList)
{
if (!pModelMask || pModelMask->ModelMask.empty())
{
continue;
}
cv::Rect imgRoi = cv::Rect(0, 0, pModelMask->ModelMask.cols, pModelMask->ModelMask.rows);
cv::Rect cutRoi = roi & imgRoi;
if (cutRoi.width <= 0 || cutRoi.height <= 0)
{
continue;
}
cv::Mat roiMask = pModelMask->ModelMask(cutRoi);
if (cv::countNonZero(roiMask) > 0)
{
if (strModelName.empty())
{
strModelName = pModelMask->strModelName;
}
else
{
strModelName += AI_DET_MODEL_NAME_JOIN + pModelMask->strModelName;
}
}
}
if (strModelName.empty())
{
strModelName = AI_DET_MODEL_NAME_UnKnown;
}
return strModelName;
}
int ImgCheckAnalysisy::BLobToDetResult()
{
long t1 = CheckUtil::getcurTime();
@ -2078,6 +2172,9 @@ int ImgCheckAnalysisy::BLobToDetResult()
float fsecondArea = JudgArea;
std::string qx_name = CONFIG_QX_NAME_Names[config_qx_type];
// 追溯该残点(blob) 是由哪个检测模型检出的
std::string strModelName = GetBlobModelName(roi);
if (true)
{
QX_ERROR_INFO_ temerror;
@ -2091,6 +2188,7 @@ int ImgCheckAnalysisy::BLobToDetResult()
temerror.fbreadth = blobs.blobTab[i].breadth;
temerror.nconfig_qx_type = config_qx_type;
temerror.qx_name = qx_name;
temerror.strModelName = strModelName;
temerror.maxValue = blobs.blobTab[i].maxValue;
temerror.grayDis = blobs.blobTab[i].grayDis;
temerror.density = blobs.blobTab[i].density;
@ -2138,6 +2236,11 @@ int ImgCheckAnalysisy::BLobToDetResult()
m_pDetResult->pQx_ErrorList->push_back(temerror);
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "BLobToDetResult",
"blob idx %d Qx Idx %d qx %d %s detModel %s roi[%d %d %d %d]",
i, temerror.Idx, config_qx_type, qx_name.c_str(), strModelName.c_str(),
roi.x, roi.y, roi.width, roi.height);
// printf("- %s idx %d a %f v %d h %f l %f\n", DetImgInfo_shareP->strChannel.c_str(), i, JudgArea, blobs.blobTab[i].maxValue, blobs.blobTab[i].grayDis, flen);
}
}

@ -1063,6 +1063,7 @@ struct Base_Function_SaveImg
bool bSaveMarkImg; // mark 存图
bool bSaveClsImg; // 分类 存图
bool bSaveAlginImg; // 分类 存图
bool bSaveAIDetImg; // AI 检测残点图 存图(每个模型单独一级目录)
Base_Function_SaveImg()
{
@ -1074,6 +1075,7 @@ struct Base_Function_SaveImg
bSaveMarkImg = false;
bSaveClsImg = false;
bSaveAlginImg = false;
bSaveAIDetImg = false;
}
void copy(Base_Function_SaveImg tem)
@ -1083,17 +1085,18 @@ struct Base_Function_SaveImg
this->bSaveMarkImg = tem.bSaveMarkImg;
this->bSaveClsImg = tem.bSaveClsImg;
this->bSaveAlginImg = tem.bSaveAlginImg;
this->bSaveAIDetImg = tem.bSaveAIDetImg;
}
void print(std::string str)
{
printf("%s>>bOpen %d bSaveMarkImg %d bSaveClsImg %d bSaveAlginImg %d \n", str.c_str(),
bOpen, bSaveMarkImg, bSaveClsImg, bSaveAlginImg);
printf("%s>>bOpen %d bSaveMarkImg %d bSaveClsImg %d bSaveAlginImg %d bSaveAIDetImg %d \n", str.c_str(),
bOpen, bSaveMarkImg, bSaveClsImg, bSaveAlginImg, bSaveAIDetImg);
}
std::string GetInfo(std::string str)
{
char buffer[256];
sprintf(buffer, "%s>>bOpen %d bSaveMarkImg %d bSaveClsImg %d bSaveAlginImg %d \n", str.c_str(),
bOpen, bSaveMarkImg, bSaveClsImg, bSaveAlginImg);
sprintf(buffer, "%s>>bOpen %d bSaveMarkImg %d bSaveClsImg %d bSaveAlginImg %d bSaveAIDetImg %d \n", str.c_str(),
bOpen, bSaveMarkImg, bSaveClsImg, bSaveAlginImg, bSaveAIDetImg);
std::string str123 = buffer;
return str123;
}

@ -846,6 +846,10 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value)
{
_config.saveImg.bSaveAlginImg = value_f["form"]["SaveImg_Config"]["Align_Big_Save"].asBool();
}
if (value_f["form"]["SaveImg_Config"]["AI_Det_Save"])
{
_config.saveImg.bSaveAIDetImg = value_f["form"]["SaveImg_Config"]["AI_Det_Save"].asBool();
}
}
else
{

Loading…
Cancel
Save