You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1293 lines
39 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "ImageResultJudge.h"
#include "ImgMmPatch.hpp"
ImageResultJudge::ImageResultJudge(/* args */)
{
m_pCommonAnalysisyConfig = NULL;
ptr_thread_Draw = NULL;
m_bExit = false;
}
ImageResultJudge::~ImageResultJudge()
{
}
int ImageResultJudge::SetAnalysisyConfig(AnalysisyConfigST *pAnalysisyConfig)
{
m_pAnalysisyConfig = pAnalysisyConfig;
m_pChannelFuntion = &m_pAnalysisyConfig->checkFunction;
m_pbaseCheckFunction = &m_pAnalysisyConfig->baseFunction;
return 0;
}
cv::Rect ImageResultJudge::GetCutRoi(cv::Rect &roi, const cv::Mat &img)
{
cv::Rect cutroi;
int pc_x = roi.x + roi.width * 0.5;
int pc_y = roi.y + roi.height * 0.5;
bool bresize = false;
if (roi.width < QX_SAMLLIMG_WIDTH && roi.height < QX_SAMLLIMG_HEIGHT)
{
cutroi.width = QX_SAMLLIMG_WIDTH;
cutroi.x = pc_x - QX_SAMLLIMG_WIDTH * 0.5;
cutroi.height = QX_SAMLLIMG_HEIGHT;
cutroi.y = pc_y - QX_SAMLLIMG_HEIGHT * 0.5;
}
else
{
// 宽 高
if (roi.width > roi.height)
{
cutroi.width = roi.width + 20;
cutroi.x = roi.x - 10;
float fsx = QX_SAMLLIMG_HEIGHT * 1.0f / QX_SAMLLIMG_WIDTH;
cutroi.height = cutroi.width * fsx;
cutroi.y = pc_y - cutroi.height * 0.5;
}
else
{
cutroi.height = roi.height + 20;
cutroi.y = roi.y - 10;
float fsy = QX_SAMLLIMG_WIDTH * 1.0f / QX_SAMLLIMG_HEIGHT;
cutroi.width = cutroi.height * fsy;
cutroi.x = pc_x - cutroi.width * 0.5;
}
bresize = true;
}
if (cutroi.x < 0)
{
cutroi.x = 0;
}
if (cutroi.y < 0)
{
cutroi.y = 0;
}
if (cutroi.x + cutroi.width >= img.cols)
{
cutroi.x = img.cols - cutroi.width;
if (cutroi.x < 0)
{
cutroi.x = 0;
if (cutroi.x + cutroi.width >= img.cols)
{
cutroi.width = img.cols;
}
}
}
if (cutroi.y + cutroi.height >= img.rows)
{
cutroi.y = img.rows - cutroi.height;
if (cutroi.y < 0)
{
cutroi.y = 0;
if (cutroi.y + cutroi.height >= img.rows)
{
cutroi.height = img.rows;
}
}
}
return cutroi;
}
int ImageResultJudge::GetAIDetImg(std::shared_ptr<ImageAllResult> pImageResult, cv::Point pcenter, cv::Mat &AI_InImg, cv::Mat &AI_OutImg)
{
// printf("%d %d \n", pcenter.x, pcenter.y);
// int AINum = pImageResult->AI_Qx_MaskList.size();
for (auto &pAIMask : pImageResult->AI_Qx_MaskList)
{
cv::Rect roi = pAIMask->roi;
if (pcenter.x >= roi.x && pcenter.x <= (roi.x + roi.width) &&
pcenter.y >= roi.y && pcenter.y <= (roi.y + roi.height))
{
// printf("%d %d %d %d \n", roi.x, roi.y, roi.width, roi.height);
// 点 (x, y) 在矩形区域内
// printf("--------------------------\n");
AI_InImg = pAIMask->AI_inImg;
AI_OutImg = pAIMask->AI_mask;
}
}
return 0;
}
QXImageResult ImageResultJudge::BuildDefectImage(std::shared_ptr<ImageAllResult> pImageResult, QX_ERROR_INFO_ *QX_info,
int qxidx, cv::Point pCenter, float fs_resize_x, float fs_resize_y)
{
cv::Rect roi = QX_info->roi; // 缺陷坐标(产品坐标系,抗倾斜)
// 检测图(detImg)坐标框,用于缺陷小图裁剪等内部用途。
// 优先用 ImgCheckAnalysisy 记录的真实 detImg 框:产品倾斜时无法再由产品坐标加回偏移还原
cv::Rect roi_det = QX_info->roiDet;
if (roi_det.empty())
{
roi_det = roi;
roi_det.x += pImageResult->ptRoiOffsetInDet.x;
roi_det.y += pImageResult->ptRoiOffsetInDet.y;
}
float JudgArea = QX_info->JudgArea;
float flen = QX_info->flen;
float fbreadth = QX_info->fbreadth;
float grayDis = QX_info->grayDis;
int energy = QX_info->energy;
int maxValue = QX_info->maxValue;
int config_qx_type = QX_info->nconfig_qx_type;
QXImageResult tem;
tem.idx = qxidx;
cv::Rect CutRoi = GetCutRoi(roi_det, pImageResult->detImg);
cv::Size sz = cv::Size(QX_SAMLLIMG_WIDTH, QX_SAMLLIMG_HEIGHT);
if (pImageResult->detImg.channels() == 1)
{
cv::cvtColor(pImageResult->detImg(CutRoi), tem.srcImg, cv::COLOR_GRAY2BGR);
}
else
{
tem.srcImg = pImageResult->detImg(CutRoi).clone();
}
cv::resize(tem.srcImg, tem.resizeImg, sz);
int nqx_type = ConfigTypeToResultType(config_qx_type);
tem.type = nqx_type;
tem.area = JudgArea;
tem.energy = energy;
tem.hj = grayDis;
tem.max_v = maxValue;
tem.strTypeName = QX_Result_Names[nqx_type];
tem.qx_Code = QX_Result_Code[nqx_type];
tem.srcImgroi = roi_det;
tem.len = flen;
tem.breadth = fbreadth;
tem.qx_type = 0;
tem.fScore = 0;
tem.density = 0;
tem.resizeImgroi.x = roi_det.x * fs_resize_x;
tem.resizeImgroi.width = roi_det.width * fs_resize_x;
tem.resizeImgroi.y = roi_det.y * fs_resize_y;
tem.resizeImgroi.height = roi_det.height * fs_resize_y;
// 缺陷中心:产品坐标系(像素/物理),相对产品左边/顶边
if (!QX_info->roiDet.empty())
{
// 抗倾斜路径:直接用点到左边/顶边线段的垂距(float 精度,不受框取整影响)
tem.x_pixel = QX_info->ptProduct.x;
tem.y_pixel = QX_info->ptProduct.y;
}
else
{
tem.x_pixel = roi.x + roi.width * 0.5;
tem.y_pixel = roi.y + roi.height * 0.5;
}
tem.x_mm = tem.x_pixel * m_fImgage_Scale_X;
// 【临时补丁】长度方向(y):产品运动速率不恒定(尾端有拉伸),按分段像素进度换算像素->mm
// 分段表见 ImgMmPatch.hpp,与产品物理高度(ImgCheckAnalysisy::CalProductSize)共用
tem.y_mm = PixelYToMm(tem.y_pixel);
tem.CutImgroi = roi_det;
tem.CutImgroi.x -= CutRoi.x;
tem.CutImgroi.y -= CutRoi.y;
#ifdef AI_Time
GetAIDetImg(pImageResult, pCenter, tem.AI_in_Img, tem.AI_out_img);
#endif
return tem;
}
int ImageResultJudge::UpdateImgageScale()
{
if (m_pBasicConfig->fImage_Scale_x > 0 && m_pBasicConfig->fImage_Scale_x < 1 &&
m_pBasicConfig->fImage_Scale_y > 0 && m_pBasicConfig->fImage_Scale_y < 1)
{
m_fImgage_Scale_X = m_pBasicConfig->fImage_Scale_x;
m_fImgage_Scale_Y = m_pBasicConfig->fImage_Scale_y;
}
return 0;
}
int ImageResultJudge::ResultJudge(std::shared_ptr<ImageAllResult> pImageResult)
{
std::shared_ptr<DetLog> pImageLog = pImageResult->detlog;
int regionNum = m_pCommonAnalysisyConfig->regionConfigArr.size();
if (regionNum <= 0)
{
return 1;
}
pImageLog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Param Judge", "img %s ====================start regon num %d", pImageResult->strChannel.c_str(), regionNum);
float fs_resize_x = pImageResult->fscale_detToresult_x;
float fs_resize_y = pImageResult->fscale_detToresult_x;
std::shared_ptr<One_Image_CheckResult_> pDetResult = pImageResult->pDetResult; // 检测结果
std::shared_ptr<CheckResult> m_CheckResult_shareP = pImageResult->result; // 返回结果
int qxNum = pDetResult->pQx_ErrorList->size();
// map<string, vector<iregionQxZoningInfo>> allQxZoning;
map<string, vector<singleQxZoningInfo>> allQxZoning;
set<string> qx_name_list;
m_zoningDrawGroups.clear();
for (int qxidx = 0; qxidx < qxNum; qxidx++)
{
QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx);
std::shared_ptr<DetLog> pQxLog = pDetResult->pQx_ErrorList->at(qxidx).detlog;
// pQxLog->bPrintStr = true;
cv::Rect roi = QX_info->roi;
float JudgArea = QX_info->JudgArea;
float JudgArea_second = QX_info->JudgArea_second;
float flen = QX_info->flen;
float fbreadth = QX_info->fbreadth;
float grayDis = QX_info->grayDis;
int energy = QX_info->energy;
float fupS = QX_info->fUpIou;
int maxValue = QX_info->maxValue;
float density = QX_info->density;
int QX_whiteBLACK = QX_info->whiteOrBlack;
int config_qx_type = QX_info->nconfig_qx_type;
std::string qx_name = CONFIG_QX_NAME_Names[config_qx_type];
std::string qx_wb = WHITE_BLCAK_Names[QX_whiteBLACK];
pQxLog->AddCheckstr(PrintLevel_1,
"", "qxidx: %d roi[%d %d %d %d] roidet[%d %d %d %d] qx %d %s %s JudgArea %f hj %f len %f breadth %f energy %d region num %ld",
qxidx, roi.x, roi.y, roi.width, roi.height,
QX_info->roiDet.x, QX_info->roiDet.y, QX_info->roiDet.width, QX_info->roiDet.height,
config_qx_type, qx_name.c_str(), qx_wb.c_str(),
JudgArea, grayDis, flen, fbreadth, energy, QX_info->detRegionidxList.size());
// 中心点用 detImg 坐标:检测区域(roiList_Src)与结果图绘制都在该坐标系下
// (产品坐标会整体平移一个常量,不影响两两距离,但绘制会偏)
cv::Point pCenter;
if (!QX_info->roiDet.empty())
{
pCenter.x = QX_info->roiDet.x + QX_info->roiDet.width * 0.5;
pCenter.y = QX_info->roiDet.y + QX_info->roiDet.height * 0.5;
}
else
{
pCenter.x = roi.x + roi.width * 0.5;
pCenter.y = roi.y + roi.height * 0.5;
}
bool bNG_Status = false;
bool bYS_Status = false;
bool Judge_Status = false;
int matched_group_id = -1;
float matched_dis = 0;
float matched_num = 0;
QX_info->result = QX_RESULT_TYPE_NoJduge;
allQxZoning[qx_name].reserve(20);
qx_name_list.insert(qx_name);
// 遍历当前区域所属的 区域进行参数判断。
for (auto iregion : QX_info->detRegionidxList)
{
pQxLog->AddCheckstr(PrintLevel_2, "QX info", ">>>>>>>> region %d ",
iregion + 1);
// 1、判断当前区域是否要检测该通道画面。
// 2、基础的参数判断
if (iregion >= regionNum)
{
pQxLog->AddCheckstr(PrintLevel_3, "QX info", "Error regionIdx %d > param size %d ",
iregion, regionNum);
addInDrawBlob(config_qx_type, qxidx, QX_info, fs_resize_x, fs_resize_y);
continue;
}
if (config_qx_type >= CONFIG_QX_NAME_count || config_qx_type < 0)
{
pQxLog->AddCheckstr(PrintLevel_3, "QX info", "Error def_type %d size %d ",
config_qx_type, CONFIG_QX_NAME_count);
addInDrawBlob(config_qx_type, qxidx, QX_info, fs_resize_x, fs_resize_y);
continue;
}
int paramIdx = m_QxInParamListIdx[config_qx_type];
if (paramIdx < 0)
{
pQxLog->AddCheckstr(PrintLevel_3, "qx error", " paramIdx < 0 ");
addInDrawBlob(config_qx_type, qxidx, QX_info, fs_resize_x, fs_resize_y);
continue;
}
// 3、 基本参数判断
int checkFlage = 0;
int nerrortype = 0;
for (int ict = 0; ict < ANALYSIS_TYPE_COUNT; ict++)
{
std::string str_checkflag = "QX-check";
checkFlage = ict;
if (ict == ANALYSIS_TYPE_YS)
{
str_checkflag = "YS-check";
}
// pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "qx judge", " %s start", str_checkflag.c_str());
CheckConfig_Regions_Param *pParam = &m_pCommonAnalysisyConfig->regionConfigArr.at(iregion).checkConfig_Regions_type[ict].checkConfig_Regions_Param.at(paramIdx);
bool bUse = false;
for (int j = 0; j < pParam->useNum; j++)
{
bool result = true;
if (!pParam->paramArr[j].bEnable)
{
// pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "error ", "param is CLosed");
continue;
}
bUse = true;
float At = pParam->paramArr[j].area;
float Et = pParam->paramArr[j].energy;
float hj = pParam->paramArr[j].hj;
float Len = pParam->paramArr[j].length;
float Breadth = pParam->paramArr[j].breadth;
float md = pParam->paramArr[j].density;
float dis = pParam->paramArr[j].dis;
float num = pParam->paramArr[j].num;
// 黑缺陷
if (QX_whiteBLACK == CONFIG_QX_WHITE)
{
// pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "param---", "qx :white");
if (hj >= 0 || Et >= 0)
{
pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "param ", "Error param idx %d / %d qx white hj %f and energ %f >0",
j + 1, pParam->useNum, hj, Et);
continue;
}
Et = std::abs(Et);
hj = std::abs(hj);
}
else
{
// pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "param---", "qx :blcak");
if (hj < 0 || Et < 0)
{
pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "param ", "Error param idx %d / %d qx blcak hj %f and energ %f < 0",
j + 1, pParam->useNum, hj, Et);
continue;
}
}
Judge_Status = true;
float detArea = JudgArea;
if (energy >= Et &&
detArea >= At &&
grayDis >= hj &&
flen >= Len &&
fbreadth >= Breadth)
{
if(dis > 0 && num > 0 && ict == ANALYSIS_TYPE_TF)
{
matched_group_id = j;
matched_dis = dis;
matched_num = num;
int if_insert = false;
singleQxInfo current_YS_info(qxidx, QX_RESULT_TYPE_YS, pCenter);
// 查找与当前缺陷参数组标识匹配的分区进行插入
for(int i = 0; i < allQxZoning[qx_name].size(); i++){
if(allQxZoning[qx_name][i].param_group_id == matched_group_id &&
allQxZoning[qx_name][i].Insert(current_YS_info)){
if_insert = true;
break;
}
}
if(!if_insert && matched_group_id >= 0){
singleQxZoningInfo newZoningInfoTemp;
newZoningInfoTemp.Init();
newZoningInfoTemp.param_group_id = matched_group_id;
newZoningInfoTemp.judge_dis = matched_dis;
newZoningInfoTemp.judge_num = matched_num;
newZoningInfoTemp.center = pCenter;
newZoningInfoTemp.scale_X = m_fImgage_Scale_X;
newZoningInfoTemp.scale_Y = m_fImgage_Scale_Y;
newZoningInfoTemp.qxList.push_back(current_YS_info);
allQxZoning[qx_name].push_back(newZoningInfoTemp); // 插入失败,添加一个新分组
}
continue;
}
nerrortype = 1;
result = false;
if (ict == ANALYSIS_TYPE_YS)
{
bYS_Status = true;
}
else
{
bNG_Status = true;
}
}
if (!result)
{
pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "result", "%s param idx %d / %d parma A %f E %f HJ %f L %f B %f",
BOOL_TO_STROK(result), j + 1, pParam->useNum, At, Et, hj, Len, Breadth);
}
else
{
pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "result", "%s param idx %d / %d", BOOL_TO_STROK(result), j + 1, pParam->useNum);
}
if (detArea < At)
{
pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "Area", "%s -> %f %s %f ",
BOOL_TO_STR(detArea >= At), detArea, BOOL_TO_ThanLess(detArea >= At), At);
}
if (energy < Et)
{
pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "Energy", "%s -> %d %s %f ",
BOOL_TO_STR(energy >= Et), energy, BOOL_TO_ThanLess(energy >= Et), Et);
}
if (grayDis < hj)
{
pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "HJ", "%s -> %f %s %f ",
BOOL_TO_STR(grayDis >= hj), grayDis, BOOL_TO_ThanLess(grayDis > hj), hj);
}
if (flen < Len)
{
pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "Len", "%s -> %f %s %f ",
BOOL_TO_STR(flen >= Len), flen, BOOL_TO_ThanLess(flen > Len), Len);
}
if (fbreadth < Breadth)
{
pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "Breadth", "%s -> %f %s %f ",
BOOL_TO_STR(fbreadth >= Breadth), fbreadth, BOOL_TO_ThanLess(fbreadth > Breadth), Breadth);
}
if (!result)
{
break;
}
}
if (!bUse)
{
pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "info", "Not Use Param Judge");
}
if (nerrortype != 0)
{
pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "info", " %s end result: erorr type %s", str_checkflag.c_str(), qx_name.c_str());
break;
}
else
{
pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "info", " %s end result: OK ", str_checkflag.c_str());
}
}
// 已经NG 就不继续判断了。
if (bNG_Status)
{
break;
}
}
std::string resultType = "OK";
if (!Judge_Status)
{
QX_info->result = QX_RESULT_TYPE_NoJduge;
}
else
{
if (bNG_Status)
{
QX_info->result = QX_RESULT_TYPE_NG;
}
else if (bYS_Status)
{
QX_info->result = QX_RESULT_TYPE_YS;
}
else
{
QX_info->result = QX_RESULT_TYPE_OK;
}
}
QX_info->result_name = QX_RESULT_TYPE_Names[QX_info->result];
resultType = QX_info->result_name;
pQxLog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "10、Param Judge", "qx %s ,result = %s", qx_name.c_str(), resultType.c_str());
// 当前是好品
if (!bNG_Status)
{
// 大缺陷判断
if (m_pbaseCheckFunction->bigNG.bOpen)
{
bool berror = false;
if (config_qx_type >= 0 || config_qx_type < CONFIG_QX_NAME_count)
{
bool qx_config_open = m_pbaseCheckFunction->bigNG.qx[config_qx_type].bOpen;
float qx_config_area = m_pbaseCheckFunction->bigNG.qx[config_qx_type].fArea;
if (qx_config_open)
{
if (JudgArea > qx_config_area)
{
berror = true;
bNG_Status = true;
}
pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "Big QX single result ", "%s ", BOOL_TO_STROK(!berror));
pQxLog->AddCheckstr(PrintLevel_4, DET_LOG_LEVEL_3, "Area", "%s -> %f %s %f ",
BOOL_TO_STR(JudgArea > qx_config_area), JudgArea, BOOL_TO_ThanLess(JudgArea > qx_config_area), qx_config_area);
}
else
{
pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, " big qx", "qx %s param close ", m_pbaseCheckFunction->bigNG.qx[config_qx_type].strname.c_str());
}
}
}
else
{
pQxLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, " big qx", " param close ");
}
if (!Judge_Status)
{
QX_info->result = QX_RESULT_TYPE_NoJduge;
}
else
{
if (bNG_Status)
{
QX_info->result = QX_RESULT_TYPE_NG;
}
else if (bYS_Status)
{
QX_info->result = QX_RESULT_TYPE_YS;
}
else
{
QX_info->result = QX_RESULT_TYPE_OK;
}
}
QX_info->result_name = QX_RESULT_TYPE_Names[QX_info->result];
resultType = QX_info->result_name;
pQxLog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "12、big qx ", "qx %s ,result = %s", qx_name.c_str(), resultType.c_str());
}
if (bNG_Status)
{
m_CheckResult_shareP->nresult = 1;
}
if (bYS_Status)
{
m_CheckResult_shareP->nYS_result = 1;
}
m_CheckResult_shareP->checkStatus = 0;
// 生成缺陷小图
if (bYS_Status || bNG_Status)
{
QXImageResult tem = BuildDefectImage(pImageResult, QX_info, qxidx, pCenter, fs_resize_x, fs_resize_y);
int nqx_type = ConfigTypeToResultType(config_qx_type);
if (bNG_Status)
{
m_CheckResult_shareP->defectResultList[nqx_type].nresult = 1;
m_CheckResult_shareP->defectResultList[nqx_type].keyName = QX_Result_Names[nqx_type];
m_CheckResult_shareP->defectResultList[nqx_type].keyCode = QX_Result_Code[nqx_type];
m_CheckResult_shareP->defectResultList[nqx_type].num++;
if (m_CheckResult_shareP->nresult <= ERROR_TYPE_OK)
{
m_CheckResult_shareP->nresult = nqx_type;
}
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);
}
else
{
if (m_CheckResult_shareP->nYS_result <= ERROR_TYPE_OK)
{
m_CheckResult_shareP->nYS_result = nqx_type;
}
m_CheckResult_shareP->YS_ImageResult.push_back(tem);
}
}
}
for (const auto& name : qx_name_list)
{
string qx_name = name;
for(int i = 0; i < allQxZoning[qx_name].size(); i++)
{
// 个数超过设定值,判NG
if(allQxZoning[qx_name][i].judgeNum())
{
pImageLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "Zoning NG", " name: %s, group_id: %d, count: %d >= %d → NG",
qx_name.c_str(), allQxZoning[qx_name][i].param_group_id,
(int)allQxZoning[qx_name][i].qxList.size(), allQxZoning[qx_name][i].judge_num);
for(int j = 0; j < allQxZoning[qx_name][i].qxList.size(); j++)
{
int qxidx = allQxZoning[qx_name][i].qxList[j].qxidx;
cv::Point pCenter = allQxZoning[qx_name][i].qxList[j].pcenter;
QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx);
QX_info->result = QX_RESULT_TYPE_NG;
QX_info->result_name = QX_RESULT_TYPE_Names[QX_info->result];
m_CheckResult_shareP->nresult = 1;
QXImageResult tem = BuildDefectImage(pImageResult, QX_info, qxidx, pCenter, fs_resize_x, fs_resize_y);
int nqx_type = ConfigTypeToResultType(QX_info->nconfig_qx_type);
m_CheckResult_shareP->defectResultList[nqx_type].nresult = 1;
m_CheckResult_shareP->defectResultList[nqx_type].keyName = QX_Result_Names[nqx_type];
m_CheckResult_shareP->defectResultList[nqx_type].keyCode = QX_Result_Code[nqx_type];
m_CheckResult_shareP->defectResultList[nqx_type].num++;
if (m_CheckResult_shareP->nresult <= ERROR_TYPE_OK)
{
m_CheckResult_shareP->nresult = nqx_type;
}
m_CheckResult_shareP->qxImageResult.push_back(tem);
}
}
// 数量未达标,判为YS
else
{
pImageLog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "Zoning YS", " name: %s, group_id: %d, count: %d < %d → YS",
qx_name.c_str(), allQxZoning[qx_name][i].param_group_id,
(int)allQxZoning[qx_name][i].qxList.size(), allQxZoning[qx_name][i].judge_num);
for(int j = 0; j < allQxZoning[qx_name][i].qxList.size(); j++)
{
int qxidx = allQxZoning[qx_name][i].qxList[j].qxidx;
cv::Point pCenter = allQxZoning[qx_name][i].qxList[j].pcenter;
QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx);
QX_info->result_name = QX_RESULT_TYPE_Names[QX_info->result];
m_CheckResult_shareP->nYS_result = 1;
QXImageResult tem = BuildDefectImage(pImageResult, QX_info, qxidx, pCenter, fs_resize_x, fs_resize_y);
int nqx_type = ConfigTypeToResultType(QX_info->nconfig_qx_type);
if (m_CheckResult_shareP->nYS_result <= ERROR_TYPE_OK)
{
m_CheckResult_shareP->nYS_result = nqx_type;
}
m_CheckResult_shareP->YS_ImageResult.push_back(tem);
}
}
// 收集本组所有缺陷中心点,用于后续连线绘制(至少2个点才有意义)
if(allQxZoning[qx_name][i].qxList.size() >= 2)
{
QxZoningDrawGroup group;
group.isNG = allQxZoning[qx_name][i].judgeNum();
for(int j = 0; j < allQxZoning[qx_name][i].qxList.size(); j++)
{
group.centers.push_back(allQxZoning[qx_name][i].qxList[j].pcenter);
}
m_zoningDrawGroups.push_back(group);
}
}
}
for (int qxidx = 0; qxidx < qxNum; qxidx++)
{
QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx);
switch (QX_info->result)
{
case QX_RESULT_TYPE_OK:
pImageResult->Ok_num++;
break;
case QX_RESULT_TYPE_NG:
pImageResult->NG_num++;
break;
case QX_RESULT_TYPE_YS:
pImageResult->YS_num++;
break;
case QX_RESULT_TYPE_NoJduge:
pImageResult->NoJudge_num++;
break;
default:
pImageResult->NoJudge_num++;
break;
}
}
pImageLog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Param Judge", "img %s ====================End ng %d ys %d ok %d nojudge %d ",
pImageResult->strChannel.c_str(), pImageResult->NG_num, pImageResult->YS_num, pImageResult->Ok_num, pImageResult->NoJudge_num);
return 0;
}
int ImageResultJudge::UpdateConfig()
{
if (m_pAnalysisyConfig->commonCheckConfig.nodeConfigArr.size() > 0)
{
m_pCommonAnalysisyConfig = &m_pAnalysisyConfig->commonCheckConfig.nodeConfigArr.at(0);
m_pRegionAnalysisyParam = &m_pCommonAnalysisyConfig->regionConfigArr.at(0);
m_pBasicConfig = &m_pAnalysisyConfig->commonCheckConfig.baseConfig;
}
else
{
m_pCommonAnalysisyConfig = NULL;
}
GetParamidx();
UpdateImgageScale();
return 0;
}
int ImageResultJudge::DrawResult(std::shared_ptr<ImageAllResult> pImageResult)
{
std::shared_ptr<txtDrawBackgroundk> txtbackgroundk = std::make_shared<txtDrawBackgroundk>();
if (!ptr_thread_Draw)
{
ptr_thread_Draw = std::make_shared<std::thread>(std::bind(&ImageResultJudge::ThreadDraw, this));
}
float fs_resize_x = pImageResult->fscale_detToresult_x;
float fs_resize_y = pImageResult->fscale_detToresult_x;
std::shared_ptr<CheckResult> m_CheckResult_shareP = pImageResult->result; // 返回结果
std::vector<cv::Rect> m_drawList;
if (m_CheckResult_shareP->resultimg.empty())
{
return 0;
}
cv::Scalar color_NG = cv::Scalar(0, 0, 255);
cv::Scalar color_Ys = cv::Scalar(0, 255, 255);
cv::Scalar color_Nojudge = cv::Scalar(0, 255, 0);
long t1 = CheckUtil::getcurTime();
for (int i = 0; i < m_CheckResult_shareP->qxImageResult.size(); i++)
{
std::shared_ptr<DrawInfo> draw_qx = std::make_shared<DrawInfo>();
QXImageResult *pqx = &m_CheckResult_shareP->qxImageResult.at(i);
cv::Rect drawroi = pqx->resizeImgroi;
cv::Point cp = cv::Point(drawroi.x + drawroi.width * .5, drawroi.y + drawroi.height * 0.5);
int r = drawroi.width;
if (drawroi.height > r)
{
r = drawroi.height;
}
r += 10;
draw_qx->dr = r;
draw_qx->cp = cp;
draw_qx->color = color_NG;
draw_qx->drawImg = m_CheckResult_shareP->resultimg;
draw_qx->type = Draw_circle;
sendTask(draw_qx);
std::shared_ptr<DrawInfo> draw_str = std::make_shared<DrawInfo>();
draw_str->drawImg = m_CheckResult_shareP->resultimg;
draw_str->type = Draw_str;
draw_str->color = color_NG;
draw_str->cp = cp;
draw_str->txtP = cv::Point(draw_qx->cp.x + r, draw_qx->cp.y - r);
draw_str->txtsize = 0.5;
draw_str->txtbackgroundk = txtbackgroundk;
cv::Rect srcroi = pqx->srcImgroi;
cv::Point srccp = cv::Point(srcroi.x + srcroi.width * .5, srcroi.y + srcroi.height * 0.5);
char buffer[128];
{
std::string text = std::to_string(pqx->idx) + ":" + pqx->strTypeName;
draw_str->strlist.push_back(text);
}
{
sprintf(buffer, " center:%d %d", srccp.x, srccp.y);
std::string text = buffer;
draw_str->strlist.push_back(text);
}
{
sprintf(buffer, " xy:%0.3f %0.3f mm", pqx->x_mm, pqx->y_mm);
std::string text = buffer;
draw_str->strlist.push_back(text);
}
{
sprintf(buffer, " len %0.2f A: %0.2f ", pqx->len, pqx->area);
std::string text = buffer;
draw_str->strlist.push_back(text);
}
{
sprintf(buffer, " breadth %0.2f A: %0.2f ", pqx->breadth, pqx->area);
std::string text = buffer;
draw_str->strlist.push_back(text);
}
{
sprintf(buffer, " E:%0.2f hj %0.2f", pqx->energy, pqx->hj);
std::string text = buffer;
draw_str->strlist.push_back(text);
}
sendTask(draw_str);
// 在小图上绘制
{
cv::Rect drawroi = pqx->CutImgroi;
cv::Point cp = cv::Point(drawroi.x + drawroi.width * .5, drawroi.y + drawroi.height * 0.5);
int r = drawroi.width;
if (drawroi.height > r)
{
r = drawroi.height;
}
r += 10;
std::shared_ptr<DrawInfo> draw_qx_small = std::make_shared<DrawInfo>();
draw_qx_small->drawImg = pqx->srcImg;
draw_qx_small->cp = cp;
draw_qx_small->dr = r;
draw_qx_small->color = color_NG;
draw_qx_small->type = Draw_circle;
sendTask(draw_qx_small);
std::shared_ptr<DrawInfo> draw_str_small = std::make_shared<DrawInfo>();
draw_str_small->drawImg = pqx->srcImg;
draw_str_small->type = Draw_str;
draw_str_small->color = color_NG;
draw_str_small->txtP = cp;
draw_str_small->cp = cp;
draw_str_small->strlist.assign(draw_str->strlist.begin(), draw_str->strlist.end());
draw_str_small->txtsize = 0.45;
sendTask(draw_str_small);
}
}
for (int i = 0; i < m_CheckResult_shareP->YS_ImageResult.size(); i++)
{
std::shared_ptr<DrawInfo> draw_qx = std::make_shared<DrawInfo>();
QXImageResult *pqx = &m_CheckResult_shareP->YS_ImageResult.at(i);
cv::Rect drawroi = pqx->resizeImgroi;
cv::Point cp = cv::Point(drawroi.x + drawroi.width * .5, drawroi.y + drawroi.height * 0.5);
int r = drawroi.width;
if (drawroi.height > r)
{
r = drawroi.height;
}
r += 10;
draw_qx->dr = r;
draw_qx->cp = cp;
draw_qx->color = color_Ys;
draw_qx->drawImg = m_CheckResult_shareP->resultimg;
draw_qx->type = Draw_circle;
sendTask(draw_qx);
std::shared_ptr<DrawInfo> draw_str = std::make_shared<DrawInfo>();
draw_str->drawImg = m_CheckResult_shareP->resultimg;
draw_str->type = Draw_str;
draw_str->color = color_Ys;
draw_str->cp = cp;
draw_str->txtP = cv::Point(draw_qx->cp.x + r, draw_qx->cp.y - r);
draw_str->txtbackgroundk = txtbackgroundk;
draw_str->txtsize = 0.5;
cv::Rect srcroi = pqx->srcImgroi;
cv::Point srccp = cv::Point(srcroi.x + srcroi.width * .5, srcroi.y + srcroi.height * 0.5);
char buffer[128];
{
std::string text = std::to_string(pqx->idx);
draw_str->strlist.push_back(text);
}
// {
// sprintf(buffer, " center:%d %d", srccp.x, srccp.y);
// std::string text = buffer;
// draw_str->strlist.push_back(text);
// }
// {
// sprintf(buffer, " len %0.2f A: %0.2f ", pqx->len, pqx->area);
// std::string text = buffer;
// draw_str->strlist.push_back(text);
// }
// {
// sprintf(buffer, " E:%0.2f hj %0.2f", pqx->energy, pqx->hj);
// std::string text = buffer;
// draw_str->strlist.push_back(text);
// }
sendTask(draw_str);
// 在小图上绘制
{
cv::Rect drawroi = pqx->CutImgroi;
cv::Point cp = cv::Point(drawroi.x + drawroi.width * .5, drawroi.y + drawroi.height * 0.5);
int r = drawroi.width;
if (drawroi.height > r)
{
r = drawroi.height;
}
r += 10;
std::shared_ptr<DrawInfo> draw_qx_small = std::make_shared<DrawInfo>();
draw_qx_small->drawImg = pqx->srcImg;
draw_qx_small->cp = cp;
draw_qx_small->dr = r;
draw_qx_small->color = color_Ys;
draw_qx_small->type = Draw_circle;
sendTask(draw_qx_small);
std::shared_ptr<DrawInfo> draw_str_small = std::make_shared<DrawInfo>();
draw_str_small->drawImg = pqx->srcImg;
draw_str_small->type = Draw_str;
draw_str_small->color = color_Ys;
draw_str_small->txtP = cp;
draw_str_small->cp = cp;
draw_str_small->strlist.assign(draw_str->strlist.begin(), draw_str->strlist.end());
draw_str_small->txtsize = 0.45;
sendTask(draw_str_small);
}
}
std::shared_ptr<One_Image_CheckResult_> pDetResult = pImageResult->pDetResult; // 检测结果
int qxNum = pDetResult->pQx_ErrorList->size();
for (int qxidx = 0; qxidx < qxNum; qxidx++)
{
QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx);
// 只绘制 未分析 或分析失败的。
if (QX_info->result != QX_RESULT_TYPE_NoJduge)
{
continue;
}
std::shared_ptr<DrawInfo> draw_qx = std::make_shared<DrawInfo>();
cv::Rect roi = QX_info->roi;
cv::Rect drawroi;
drawroi.x = roi.x * fs_resize_x;
drawroi.width = roi.width * fs_resize_x;
drawroi.y = roi.y * fs_resize_y;
drawroi.height = roi.height * fs_resize_y;
cv::Point cp = cv::Point(drawroi.x + drawroi.width * .5, drawroi.y + drawroi.height * 0.5);
int r = drawroi.width;
if (drawroi.height > r)
{
r = drawroi.height;
}
r += 10;
draw_qx->cp = cp;
draw_qx->dr = r;
draw_qx->color = color_Nojudge;
draw_qx->drawImg = m_CheckResult_shareP->resultimg;
draw_qx->type = Draw_circle;
sendTask(draw_qx);
std::shared_ptr<DrawInfo> draw_str = std::make_shared<DrawInfo>();
draw_str->drawImg = m_CheckResult_shareP->resultimg;
draw_str->type = Draw_str;
draw_str->color = color_Nojudge;
draw_str->cp = cp;
draw_str->txtP = cv::Point(draw_qx->cp.x + r, draw_qx->cp.y - r);
draw_str->txtbackgroundk = txtbackgroundk;
draw_str->txtsize = 0.5;
char buffer[128];
{
std::string text = std::to_string(QX_info->Idx);
draw_str->strlist.push_back(text);
}
sendTask(draw_str);
}
long t2 = CheckUtil::getcurTime();
// 绘制同组缺陷之间的连线(至少2个点才有连线意义)
cv::Scalar color_line_NG = cv::Scalar(0, 0, 255); // 红色,NG组连线
cv::Scalar color_line_YS = cv::Scalar(0, 200, 200); // 青黄色,YS组连线
for (const auto& group : m_zoningDrawGroups)
{
if (group.centers.size() < 2) continue;
std::shared_ptr<DrawInfo> draw_line = std::make_shared<DrawInfo>();
draw_line->drawImg = m_CheckResult_shareP->resultimg;
draw_line->type = Draw_lines;
draw_line->color = group.isNG ? color_line_NG : color_line_YS;
draw_line->dr = 1; // 线宽
// 将detection坐标系的中心点缩放到result图像坐标系
for (const auto& pt : group.centers)
{
draw_line->linePts.push_back(cv::Point(
(int)(pt.x * fs_resize_x),
(int)(pt.y * fs_resize_y)));
}
sendTask(draw_line);
}
// 等待绘制完成
WaiteDrawComplate();
long t3 = CheckUtil::getcurTime();
// printf("=====draw=all %ld send %ld wait %ld \n", t3 - t1, t2 - t1, t3 - t2);
return 0;
}
int ImageResultJudge::GetParamidx()
{
int region = 0;
if (m_pCommonAnalysisyConfig == NULL || m_pCommonAnalysisyConfig->regionConfigArr.size() <= 0)
{
return 1;
}
CheckConfig_Regions_type *p = &m_pCommonAnalysisyConfig->regionConfigArr.at(region).checkConfig_Regions_type[0];
for (int iqx = 0; iqx < CONFIG_QX_NAME_count; iqx++)
{
m_QxInParamListIdx[iqx] = -1;
std::string strqx_name = CONFIG_QX_NAME_Names[iqx];
for (int i = 0; i < p->checkConfig_Regions_Param.size(); i++)
{
std::string strconfig_name = p->checkConfig_Regions_Param[i].param_name;
// getchar();
if (strqx_name == strconfig_name)
{
printf("strqx_name %s strconfig_name %s \n", strqx_name.c_str(), strconfig_name.c_str());
m_QxInParamListIdx[iqx] = i;
break;
}
}
}
// getchar();
return 0;
}
int ImageResultJudge::addInDrawBlob(int errortype, int blobidx, QX_ERROR_INFO_ *QX_info, float fs_resize_x, float fs_resize_y)
{
return 0;
}
int ImageResultJudge::ConfigTypeToResultType(int nconfigType)
{
bool bdesc = false;
int resultError_type = ERROR_TYPE_OK;
if(nconfigType < CONFIG_QX_NAME_Names.size())
{
string cqn = CONFIG_QX_NAME_Names[nconfigType];
for(int i = 0; i < m_FlawCodeList.size(); i++)
{
for(int j = 0; j < m_FlawCodeList.at(i).config_flaw_name.size(); j++)
{
if(cqn == m_FlawCodeList.at(i).config_flaw_name[j])
{
resultError_type = i;
bdesc = true;
break;
}
}
}
}
// 如果描述没有配置,用默认值
if(!bdesc)
{
switch (nconfigType)
{
case CONFIG_QX_NAME_cell_aotudian:
resultError_type = ERROR_TYPE_aotudian;
break;
case CONFIG_QX_NAME_cell_other:
resultError_type = ERROR_TYPE_other;
break;
case CONFIG_QX_NAME_cell_line:
resultError_type = ERROR_TYPE_line;
break;
case CONFIG_QX_NAME_cell_zangwu:
resultError_type = ERROR_TYPE_zangwu;
break;
case CONFIG_QX_NAME_cell_edge:
resultError_type = ERROR_TYPE_edge;
break;
case CONFIG_QX_NAME_cell_ymhs:
resultError_type = ERROR_TYPE_ymhs;
break;
case CONFIG_QX_NAME_cell_dianzhuang:
resultError_type = ERROR_TYPE_dianzhuang;
break;
case CONFIG_QX_NAME_cell_posun:
resultError_type = ERROR_TYPE_posun;
break;
case CONFIG_QX_NAME_cell_xianwei:
resultError_type = ERROR_TYPE_xianwei;
break;
case CONFIG_QX_NAME_cell_shuizi:
resultError_type = ERROR_TYPE_shuizi;
break;
case CONFIG_QX_NAME_cell_danban:
resultError_type = ERROR_TYPE_danban;
break;
case CONFIG_QX_NAME_cell_fuchen:
resultError_type = ERROR_TYPE_fuchen;
break;
default:
break;
}
}
return resultError_type;
}
int ImageResultJudge::sendTask(std::shared_ptr<DrawInfo> task)
{
{
std::lock_guard<std::mutex> lock(m_task_mutex_);
m_DrawInfoList.push(task);
}
m_task_cv_.notify_one();
return 0;
}
std::shared_ptr<ImageResultJudge::DrawInfo> ImageResultJudge::GetTask()
{
std::shared_ptr<DrawInfo> task;
{
std::unique_lock<std::mutex> lock(m_task_mutex_);
m_task_cv_.wait(lock, [this]()
{ return !m_DrawInfoList.empty(); });
task = std::move(m_DrawInfoList.front());
m_DrawInfoList.pop();
}
return task;
}
void ImageResultJudge::ThreadDraw()
{
while (!m_bExit)
{
std::this_thread::sleep_for(std::chrono::milliseconds(0));
// 等待是否有任务
std::shared_ptr<ImageResultJudge::DrawInfo> draw = GetTask();
// 把任务发送给对应的任务处理函数进行处理
DrawResultTask(draw);
m_drawComplate_cv_.notify_all();
}
}
int ImageResultJudge::DrawResultTask(std::shared_ptr<ImageResultJudge::DrawInfo> task)
{
if (task->type == Draw_circle)
{
cv::circle(task->drawImg, task->cp, task->dr, task->color);
if (task->txtbackgroundk)
{
task->txtbackgroundk->txtDrawRoi.push_back(task->roi);
}
}
if (task->type == Draw_rect)
{
cv::rectangle(task->drawImg, task->roi, task->color);
if (task->txtbackgroundk)
{
task->txtbackgroundk->txtDrawRoi.push_back(task->roi);
}
}
if (task->type == Draw_str)
{
int fontFace = cv::FONT_HERSHEY_SIMPLEX;
double fontScale = task->txtsize;
int thickness = 0.5;
int baseline = 0;
// 行高(根据字体大小计算)
int txtH = cv::getTextSize("Test", fontFace, fontScale, thickness, &baseline).height;
int lineHeight = txtH + 5;
// 起始位置
int x = task->txtP.x;
int y = task->txtP.y;
int height = 0;
int maxw = 0;
for (const auto &txt : task->strlist)
{
// 计算文本大小
cv::Size textSize = cv::getTextSize(txt, fontFace, fontScale, thickness, &baseline);
if (textSize.width > maxw)
{
maxw = textSize.width;
}
height += lineHeight; // 下一行
}
cv::Rect rtxt = cv::Rect(x, y - txtH, maxw, height);
cv::Rect r = cv::Rect(x, y, maxw, height);
if (task->txtbackgroundk)
{
cv::Rect newr = task->txtbackgroundk->findNonOverlappingPos(rtxt);
task->txtbackgroundk->txtDrawRoi.push_back(newr);
rtxt = newr;
r = rtxt;
r.y += txtH;
}
// 左边界
if (r.x < 0)
r.x = 0;
// 上边界
if (r.y < 0)
r.y = 0;
// 右边界
if (r.x + r.width > task->drawImg.cols)
r.x = task->drawImg.cols - r.width;
// 下边界
if (r.y + r.height > task->drawImg.rows)
r.y = task->drawImg.rows - r.height;
height = 0;
for (const auto &txt : task->strlist)
{
// 画文字
cv::putText(task->drawImg, txt, cv::Point(r.x, r.y + height),
fontFace, fontScale, task->color, thickness);
height += lineHeight; // 下一行
}
// cv::rectangle(task->drawImg, rtxt, cv::Scalar(255, 0, 0));
cv::Point p(r.x, r.y);
if (task->cp.x - r.x > 30 || task->cp.y - r.y > 30)
{
cv::line(task->drawImg, p, task->cp, cv::Scalar(80, 0, 200));
}
// cv::circle(task->drawImg, task->cp, 3, task->color);
}
if (task->type == Draw_lines)
{
if (task->linePts.size() >= 2)
{
int thickness = task->dr > 0 ? task->dr : 1;
for (size_t i = 0; i < task->linePts.size() - 1; i++)
{
cv::line(task->drawImg, task->linePts[i], task->linePts[i + 1], task->color, thickness);
}
// 闭合连线:首尾相连
cv::line(task->drawImg, task->linePts.back(), task->linePts.front(), task->color, thickness);
}
}
return 0;
}
int ImageResultJudge::WaiteDrawComplate()
{
{
std::unique_lock<std::mutex> lock(m_task_mutex_);
m_drawComplate_cv_.wait(lock, [this]()
{ return m_DrawInfoList.empty(); });
}
return 0;
}