|
|
/*
|
|
|
* @Author: your name
|
|
|
* @Date: 2022-04-20 15:50:00
|
|
|
* @LastEditTime: 2025-09-23 11:34:53
|
|
|
* @LastEditors: xiewenji 527774126@qq.com
|
|
|
* @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
|
|
* @FilePath: /ZCXD_MonitorPlatform/src/CoreLogicModule/src/CamDeal.cpp
|
|
|
*/
|
|
|
#include "ImgCheckAnalysisy.hpp"
|
|
|
#include "CheckUtil.hpp"
|
|
|
#include "Define.h"
|
|
|
#include <omp.h>
|
|
|
#include "AICommonDefine.h"
|
|
|
// 用于排序轮廓的比较函数
|
|
|
static bool compareContourAreas(const vector<Point> &contour1, const vector<Point> &contour2)
|
|
|
{
|
|
|
double i = contourArea(contour1);
|
|
|
double j = contourArea(contour2);
|
|
|
return (i > j);
|
|
|
}
|
|
|
ImgCheckAnalysisy::ImgCheckAnalysisy()
|
|
|
: m_pAI_Edge_Algin(m_pdetlog)
|
|
|
, m_Pin_QX_Det(m_pdetlog)
|
|
|
{
|
|
|
|
|
|
m_nErrorCode = CHECK_OK;
|
|
|
m_nThreadIdx = -1;
|
|
|
m_bInitSucc = false;
|
|
|
m_bExit = false;
|
|
|
m_nRun_Status = CHECK_THREAD_STATUS_IDLE;
|
|
|
|
|
|
m_fImgage_Scale_X = 0.03f;
|
|
|
m_fImgage_Scale_Y = 0.03f;
|
|
|
m_pBasicConfig = NULL;
|
|
|
|
|
|
m_strCurDetChannel = "";
|
|
|
m_bupdateconfig = false;
|
|
|
m_pbaseCheckFunction = &m_AnalysisyConfig.baseFunction;
|
|
|
|
|
|
m_strLastDate = "";
|
|
|
m_strRootPath_TA_cls = "/home/aidlux/BOE/Cls/TA/";
|
|
|
m_strRootPath_CA_cls = "/home/aidlux/BOE/Cls/CA/";
|
|
|
creatsavedir();
|
|
|
m_pImageStorage = ImageStorage::getInstance();
|
|
|
m_nConfigIdx = -1;
|
|
|
m_ImgBlobHFlagData = NULL;
|
|
|
}
|
|
|
|
|
|
ImgCheckAnalysisy::~ImgCheckAnalysisy()
|
|
|
{
|
|
|
ExitSystem();
|
|
|
if (m_ImgBlobHFlagData)
|
|
|
{
|
|
|
delete[] m_ImgBlobHFlagData;
|
|
|
m_ImgBlobHFlagData = NULL;
|
|
|
}
|
|
|
}
|
|
|
int ImgCheckAnalysisy::UpdateConfig(void *pconfig, int nConfigType)
|
|
|
{
|
|
|
int re = 0;
|
|
|
switch (nConfigType)
|
|
|
{
|
|
|
case CHECK_CONFIG_Run:
|
|
|
re = LoadRunConfig(pconfig);
|
|
|
if (re == 0)
|
|
|
{
|
|
|
// printf("---> LoadRunConfig Succ\n");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
printf("---> LoadRunConfig Fail\n");
|
|
|
}
|
|
|
break;
|
|
|
case CHECK_CONFIG_Module:
|
|
|
re = LoadCheckConfig(pconfig);
|
|
|
if (re == 0)
|
|
|
{
|
|
|
// printf("---> LoadAnalysisConfig Succ\n");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
printf("---> LoadAnalysisConfig Fail\n");
|
|
|
}
|
|
|
break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
return re;
|
|
|
}
|
|
|
int ImgCheckAnalysisy::RunStart(void *pconfig1)
|
|
|
{
|
|
|
|
|
|
// 1 、更新参数 并判断参数是否合法
|
|
|
int re = CHECK_OK;
|
|
|
re = SetNewConfig();
|
|
|
if (CHECK_OK != re)
|
|
|
{
|
|
|
m_nErrorCode = re;
|
|
|
return m_nErrorCode;
|
|
|
}
|
|
|
// printf("---> RunStart Start m_RunConfig.nThreadIdx %d \n", m_RunConfig.nThreadIdx);
|
|
|
|
|
|
m_nThreadIdx = m_RunConfig.nThreadIdx;
|
|
|
|
|
|
re = InitRun(m_RunConfig.nCpu_start_Idx);
|
|
|
if (CHECK_OK != re)
|
|
|
{
|
|
|
m_nErrorCode = re;
|
|
|
return m_nErrorCode;
|
|
|
}
|
|
|
runner = std::make_shared<AIMulThreadRunBase>();
|
|
|
runner->Start();
|
|
|
|
|
|
m_nErrorCode = CHECK_OK;
|
|
|
// printf("ImgCheckAnalysisy >>>> ImgCheckThread %d Start Succ \n", m_nThreadIdx);
|
|
|
return m_nErrorCode;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::SetDataRun_SharePtr(std::shared_ptr<ImageAllResult> p)
|
|
|
{
|
|
|
// 设置正在检测
|
|
|
|
|
|
m_pImageAllResult = p;
|
|
|
DetImgInfo_shareP = p->result->in_shareImage;
|
|
|
m_CheckResult_shareP = p->result;
|
|
|
m_pImageAllResult->setStep(ImageAllResult::DetStep_Deting);
|
|
|
m_pdetlog = p->detlog;
|
|
|
m_pDetResult = p->pDetResult;
|
|
|
StartCheck();
|
|
|
m_nErrorCode = CHECK_OK;
|
|
|
return m_nErrorCode;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::GetCheckReuslt(std::shared_ptr<ImageDetResult> &pResult)
|
|
|
{
|
|
|
|
|
|
m_CheckResult_shareP.reset();
|
|
|
DetImgInfo_shareP.reset();
|
|
|
SetIDLE();
|
|
|
// m_nErrorCode = CHECK_OK;
|
|
|
// printf("4 DetImgInfo_shareP count %ld m_nCheckResultErrorCode %d \n", DetImgInfo_shareP.use_count(), m_nCheckResultErrorCode);
|
|
|
return m_nCheckResultErrorCode;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::CheckImg(std::shared_ptr<ImageDetconfig> p, std::shared_ptr<ImageDetResult> &pResult)
|
|
|
{
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::ReJsonResul(std::shared_ptr<ImageDetconfig> p, std::shared_ptr<ImageDetResult> &pResult)
|
|
|
{
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::InitRun(int nId)
|
|
|
{
|
|
|
|
|
|
int re = CHECK_OK;
|
|
|
if (m_bInitSucc)
|
|
|
{
|
|
|
return CHECK_OK;
|
|
|
}
|
|
|
InitModel();
|
|
|
AI_Factory = AIFactory::GetInstance();
|
|
|
|
|
|
m_nRun_Status = CHECK_THREAD_STATUS_IDLE;
|
|
|
re = StartThread(nId);
|
|
|
if (CHECK_OK != re)
|
|
|
{
|
|
|
return re;
|
|
|
}
|
|
|
m_bInitSucc = true;
|
|
|
return re;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::GetStatus()
|
|
|
{
|
|
|
return m_nRun_Status;
|
|
|
}
|
|
|
|
|
|
std::string ImgCheckAnalysisy::GetVersion()
|
|
|
{
|
|
|
return std::string("BOE_1.7.91");
|
|
|
}
|
|
|
|
|
|
std::string ImgCheckAnalysisy::GetErrorInfo()
|
|
|
{
|
|
|
std::string str = GetErrorCodeInfo(m_nErrorCode);
|
|
|
printf("%s\n", str.c_str());
|
|
|
return str;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::creatsavedir()
|
|
|
{
|
|
|
std::string curDate = CheckUtil::getCurrentDate();
|
|
|
if (curDate == m_strLastDate)
|
|
|
{
|
|
|
return 0;
|
|
|
}
|
|
|
m_strLastDate = curDate;
|
|
|
m_strRootPath_TA_cls += m_strLastDate + "/";
|
|
|
m_strRootPath_CA_cls += m_strLastDate + "/";
|
|
|
for (int i = 0; i < AI_CLass_QX_NAME_count; i++)
|
|
|
{
|
|
|
CheckUtil::CreateDir(m_strRootPath_TA_cls + std::to_string(i) + "/");
|
|
|
CheckUtil::CreateDir(m_strRootPath_CA_cls + std::to_string(i) + "/");
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
void ImgCheckAnalysisy::SetTplInfo(const cv::RotatedRect &outerRect,
|
|
|
const std::vector<std::vector<cv::Point>> &pinContours)
|
|
|
{
|
|
|
m_tplOuterRect = outerRect;
|
|
|
m_tplPinContours = pinContours;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::LoadRunConfig(void *p)
|
|
|
{
|
|
|
if (p == NULL)
|
|
|
{
|
|
|
m_nErrorCode = CHECK_ERROR_Config_Null;
|
|
|
return m_nErrorCode;
|
|
|
}
|
|
|
RunInfoST *pconfig = (RunInfoST *)p;
|
|
|
m_RunConfig.copy(*pconfig);
|
|
|
|
|
|
return CHECK_OK;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::LoadCheckConfig(void *p)
|
|
|
{
|
|
|
if (p == NULL)
|
|
|
{
|
|
|
m_nErrorCode = CHECK_ERROR_Config_Null;
|
|
|
return m_nErrorCode;
|
|
|
}
|
|
|
m_pConfig = (ConfigBase *)p;
|
|
|
m_nConfigIdx = m_pConfig->GetConfigIdx();
|
|
|
m_nErrorCode = CHECK_OK;
|
|
|
return m_nErrorCode;
|
|
|
}
|
|
|
|
|
|
// 开启检测
|
|
|
int ImgCheckAnalysisy::StartCheck()
|
|
|
{
|
|
|
m_nRun_Status = CHECK_THREAD_STATUS_READY;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::SetIDLE()
|
|
|
{
|
|
|
// 更新参数
|
|
|
SetNewConfig();
|
|
|
m_nRun_Status = CHECK_THREAD_STATUS_IDLE;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::StartThread(int nId)
|
|
|
{
|
|
|
// 开启检测线程
|
|
|
ptr_thread_Run = std::make_shared<std::thread>(std::bind(&ImgCheckAnalysisy::Run, this, nId));
|
|
|
if (!m_RunConfig.bRetest)
|
|
|
{
|
|
|
ptr_thread_AI = std::make_shared<std::thread>(std::bind(&ImgCheckAnalysisy::ThreadTask, this, nId + 1));
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::StopThread()
|
|
|
{
|
|
|
m_bExit = true;
|
|
|
if (ptr_thread_Run != nullptr)
|
|
|
{
|
|
|
if (ptr_thread_Run->joinable())
|
|
|
{
|
|
|
ptr_thread_Run->join();
|
|
|
}
|
|
|
}
|
|
|
if (ptr_thread_AI != nullptr)
|
|
|
{
|
|
|
if (ptr_thread_AI->joinable())
|
|
|
{
|
|
|
ptr_thread_AI->join();
|
|
|
}
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::ExitSystem()
|
|
|
{
|
|
|
StopThread();
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::InitModel()
|
|
|
{
|
|
|
|
|
|
// 获取当前gpu号确定的 AI处理线程
|
|
|
|
|
|
m_OtherDet_Config.nDeviceId = m_RunConfig.nDeviceId;
|
|
|
|
|
|
m_pAI_Edge_Algin.Init(&m_OtherDet_Config);
|
|
|
m_pAI_Edge_Algin.InitModel_ALL();
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
cv::Scalar ImgCheckAnalysisy::calc_blob_info_withstats(cv::Mat &img, const cv::Mat &mask, cv::Rect &stats, cv::Size k_size, int expand, double threshold)
|
|
|
{
|
|
|
|
|
|
// 解包 stats(x, y, w, h, area)
|
|
|
int x = stats.x, y = stats.y, w = stats.width, h = stats.height;
|
|
|
|
|
|
// 将图像转换为灰度图像
|
|
|
|
|
|
// 计算感兴趣区域 (ROI)
|
|
|
cv::Rect roi(x - expand, y - expand, w + 2 * expand, h + 2 * expand);
|
|
|
roi &= cv::Rect(0, 0, img.cols, img.rows); // 确保ROI在图像内
|
|
|
|
|
|
cv::Mat cimg = img(roi);
|
|
|
|
|
|
// cv::cvtColor(cimg, cimg, cv::COLOR_BGR2GRAY);
|
|
|
// return cv::Scalar(0, 0, 0);
|
|
|
|
|
|
cv::Mat cmask = mask(roi);
|
|
|
// getchar();
|
|
|
// 扩张掩膜
|
|
|
|
|
|
cv::Scalar mean_bk = cv::mean(cimg, ~cmask);
|
|
|
double fbk = mean_bk[0];
|
|
|
|
|
|
cv::Scalar mean_det = cv::mean(cimg, cmask);
|
|
|
double fdet = mean_det[0];
|
|
|
|
|
|
// 计算差异图像
|
|
|
cv::Mat diff = cv::abs(cimg - fbk);
|
|
|
|
|
|
// cv::imwrite("cimg.png",cimg);
|
|
|
// cv::imwrite("cmask.png",cmask);
|
|
|
// printf("%f %f - %f \n",fbk,fdet,fbk-fdet);
|
|
|
// getchar();
|
|
|
|
|
|
// diff = diff.mul(cmask > 0);
|
|
|
cv::Mat masked_image;
|
|
|
diff.copyTo(masked_image, cmask);
|
|
|
// 计算能量
|
|
|
double energy = cv::sum(masked_image)[0];
|
|
|
|
|
|
// 计算 hj(差异图像大于0的像素均值)
|
|
|
// double hj = std::abs(fbk - fdet);
|
|
|
// double hj = CheckUtil::CalHj(cimg, cmask, mean_bk.val[0]);
|
|
|
double hj = CheckUtil::CalHjWeighted(cimg, cmask, mean_bk.val[0], 2.0f);
|
|
|
|
|
|
int worb = 0;
|
|
|
if (fdet >= fbk)
|
|
|
{
|
|
|
worb = 1;
|
|
|
}
|
|
|
// cv::imwrite("cimg.png", cimg);
|
|
|
// cv::imwrite("cmask.png", cmask);
|
|
|
// cv::imwrite("diff.png", diff);
|
|
|
// cv::imwrite("masked_image.png", masked_image);
|
|
|
// printf("fbk %f fdet %f energy %f\n", fbk, fdet, energy);
|
|
|
// getchar();
|
|
|
|
|
|
return cv::Scalar(worb, energy, hj);
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::Adapt_Config(RotatedRect tplOuterRect, RotatedRect curOuterRect, Mat& det_img){
|
|
|
vector<cv::Point2f> cur_vertices = CheckUtil::sort_vertices(curOuterRect);
|
|
|
vector<cv::Point2f> tpl_vertices = CheckUtil::sort_vertices(tplOuterRect);
|
|
|
|
|
|
cv::Point2f src_pts[3] = {
|
|
|
cur_vertices[0], // 对应左上
|
|
|
cur_vertices[1], // 对应右上
|
|
|
cur_vertices[2] // 对应左下
|
|
|
};
|
|
|
cv::Point2f dst_pts[3] = {
|
|
|
tpl_vertices[0], // 左上
|
|
|
tpl_vertices[1], // 右上
|
|
|
tpl_vertices[2] // 左下
|
|
|
};
|
|
|
cv::Mat affine_mat = cv::getAffineTransform(src_pts, dst_pts);
|
|
|
|
|
|
// 仿射变换
|
|
|
cv::warpAffine(det_img, det_img, affine_mat, det_img.size());
|
|
|
|
|
|
// 将m_outer_rroi和m_inner_rroi变换到模板图像坐标系下
|
|
|
auto transformRotatedRect = [&affine_mat](cv::RotatedRect &rrect)
|
|
|
{
|
|
|
const double *M = affine_mat.ptr<double>(0);
|
|
|
|
|
|
cv::Point2f pts[4];
|
|
|
rrect.points(pts);
|
|
|
|
|
|
std::vector<cv::Point2f> transformed_pts(4);
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
{
|
|
|
float x = static_cast<float>(M[0] * pts[i].x + M[1] * pts[i].y + M[2]);
|
|
|
float y = static_cast<float>(M[3] * pts[i].x + M[4] * pts[i].y + M[5]);
|
|
|
transformed_pts[i] = cv::Point2f(x, y);
|
|
|
}
|
|
|
rrect = cv::minAreaRect(transformed_pts);
|
|
|
};
|
|
|
|
|
|
transformRotatedRect(m_outer_rroi);
|
|
|
transformRotatedRect(m_inner_rroi);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::CheckRun()
|
|
|
{
|
|
|
|
|
|
// printf(">>>%s ================start \n", m_pImageAllResult->strBaseInfo.c_str());
|
|
|
|
|
|
long t1, t2, t3, t4, t5, t6, t7;
|
|
|
SetNewConfig();
|
|
|
t1 = CheckUtil::getcurTime();
|
|
|
|
|
|
CheckImgInit();
|
|
|
if (DetImgInfo_shareP->bsaveProcessImg)
|
|
|
{
|
|
|
m_pdetlog->bPrintStr = true;
|
|
|
}
|
|
|
m_pdetlog->bPrintStr = true;
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "1、basic Info", "---------------------------1、basic Info---------------------------------");
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Version", "%s", GetVersion().c_str());
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Updateconfig", "%d", m_bupdateconfig);
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Start", "%s", m_pImageAllResult->strBaseInfo.c_str());
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "ImgageScale", "Scale_X = %f Scale_Y = %f", m_fImgage_Scale_X, m_fImgage_Scale_Y);
|
|
|
m_bupdateconfig = false;
|
|
|
// 返回结果状态初始化
|
|
|
m_CheckResult_shareP->checkStatus = 1;
|
|
|
m_CheckResult_shareP->nresult = -1;
|
|
|
|
|
|
m_CheckResult_shareP->basicResult.img_id = m_CheckResult_shareP->in_shareImage->img_id;
|
|
|
m_CheckResult_shareP->basicResult.imgtype = m_CheckResult_shareP->in_shareImage->imgtype;
|
|
|
m_CheckResult_shareP->basicResult.imgstr = m_CheckResult_shareP->in_shareImage->imgstr;
|
|
|
m_CheckResult_shareP->basicResult.strChannel = m_CheckResult_shareP->in_shareImage->strChannel;
|
|
|
m_strCurDetChannel = m_CheckResult_shareP->basicResult.strChannel;
|
|
|
|
|
|
/*参数检查*/
|
|
|
int rec = ConfigCheck(DetImgInfo_shareP->img);
|
|
|
if (rec != CHECK_OK)
|
|
|
{
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Error", "ConfigCheck is error type = %d", rec);
|
|
|
m_nErrorCode = rec;
|
|
|
m_nCheckResultErrorCode = m_nErrorCode;
|
|
|
return m_nErrorCode;
|
|
|
}
|
|
|
long time_edge_s = CheckUtil::getcurTime();
|
|
|
|
|
|
/*AI 边缘定位(内外边缘)*/
|
|
|
// 模型定位内外边缘
|
|
|
int reedge = AI_Edge(m_CheckResult_shareP->in_shareImage->img, m_outer_rroi, m_inner_rroi);
|
|
|
if (reedge != 0)
|
|
|
{
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Error", "AI_Edge is error type = %d", reedge);
|
|
|
m_nErrorCode = reedge;
|
|
|
m_nCheckResultErrorCode = m_nErrorCode;
|
|
|
return m_nErrorCode;
|
|
|
}
|
|
|
long time_edge_e = CheckUtil::getcurTime();
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "2、pre detect", "-------------------------AI_Edge------------succ---time %ld----\n", time_edge_e - time_edge_s);
|
|
|
|
|
|
// 计算内外边缘夹角
|
|
|
float aouter = CheckUtil::getLongAxisAngle(m_outer_rroi);
|
|
|
float ainner = CheckUtil::getLongAxisAngle(m_inner_rroi);
|
|
|
|
|
|
float diff_align = std::fabs(aouter - ainner);
|
|
|
diff_align = std::fmod(diff_align, 180.0f); // 模 180 度
|
|
|
|
|
|
// 两条直线的夹角取锐角:min(diff, 180 - diff)
|
|
|
if (diff_align > 90.0f)
|
|
|
{
|
|
|
diff_align = 180.0f - diff_align;
|
|
|
}
|
|
|
|
|
|
// 如果diff_align大于10,则添加到缺陷列表
|
|
|
if (diff_align > 10.0f)
|
|
|
{
|
|
|
QX_ERROR_INFO_ alignErr;
|
|
|
alignErr.Idx = static_cast<int>(m_pDetResult->pQx_ErrorList->size());
|
|
|
|
|
|
// roi 用整张检测图区域(detImg 坐标系)
|
|
|
cv::Rect tplRect = m_tplOuterRect.boundingRect();
|
|
|
alignErr.roi = cv::Rect(0, 0, tplRect.width, tplRect.height);
|
|
|
alignErr.area = alignErr.roi.width * alignErr.roi.height;
|
|
|
alignErr.JudgArea = alignErr.area * m_fImgage_Scale_X * m_fImgage_Scale_Y;
|
|
|
alignErr.flen = tplRect.width * m_fImgage_Scale_X;
|
|
|
alignErr.fbreadth = tplRect.height * m_fImgage_Scale_Y;
|
|
|
|
|
|
alignErr.nconfig_qx_type = CONFIG_QX_NAME_cell_zangwu;
|
|
|
alignErr.qx_name = CONFIG_QX_NAME_Names[CONFIG_QX_NAME_cell_zangwu];
|
|
|
alignErr.grayDis = diff_align; // 记录内外边缘夹角(度)
|
|
|
alignErr.detRegionidxList.push_back(0);
|
|
|
|
|
|
alignErr.detlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Align Check",
|
|
|
"outer-inner angle diff %.2f deg", diff_align);
|
|
|
m_pDetResult->pQx_ErrorList->push_back(alignErr);
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Align Check", "angle diff %.2f deg > 10", diff_align);
|
|
|
}
|
|
|
|
|
|
/*投影对齐模板*/
|
|
|
Adapt_Config(m_tplOuterRect, m_outer_rroi, m_CheckResult_shareP->in_shareImage->img);
|
|
|
m_outer_roi = m_tplOuterRect.boundingRect();
|
|
|
m_Crop_Roi_paramImg = m_outer_roi;
|
|
|
m_pImageAllResult->pDetResult->CutRoi = m_outer_roi;
|
|
|
m_pImageAllResult->pDetResult->Param_CropRoi = m_Crop_Roi_paramImg;
|
|
|
long time_calan_e = CheckUtil::getcurTime();
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "2.1、pre detect", "-------------------------CalAndAffine------------succ---time %ld----\n", time_calan_e - time_edge_s);
|
|
|
|
|
|
/*生成 检测的图片*/
|
|
|
cv::Mat image;
|
|
|
image = m_CheckResult_shareP->in_shareImage->img;
|
|
|
if (image.channels() == 3)
|
|
|
{
|
|
|
cv::cvtColor(image(m_outer_roi), m_pImageAllResult->detImg, cv::COLOR_RGB2GRAY);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
m_pImageAllResult->detImg = image(m_outer_roi).clone();
|
|
|
}
|
|
|
/*多线程开启 AI 推理检测*/
|
|
|
long time_AI_s = CheckUtil::getcurTime();
|
|
|
m_AItask = std::make_shared<TaskInfo>();
|
|
|
m_AItask->taskname = Task_AI;
|
|
|
m_task.sendTask(m_AItask);
|
|
|
|
|
|
ImgPreDet();
|
|
|
/*更新检测区域*/
|
|
|
// Update_DetRoiList();
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "3、pre detect", "-------------------------pre Det--------------- \n");
|
|
|
|
|
|
/*实现PIN脚检测*/
|
|
|
{
|
|
|
long t41 = CheckUtil::getcurTime();
|
|
|
int reedge1111 = Pin_Qx_Det(m_pImageAllResult->detImg);
|
|
|
long t42 = CheckUtil::getcurTime();
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "4、detect", "-------------------------1、Pin_Qx_Det--------%ld-------\n", t42 - t41);
|
|
|
}
|
|
|
|
|
|
m_CheckResult_shareP->nresult = 0;
|
|
|
|
|
|
/*把临时可以绘制的结果都绘制出来。*/
|
|
|
DrawResult_Step_1();
|
|
|
long time_AI_e;
|
|
|
/*AI 推理生成*/
|
|
|
{
|
|
|
long t211 = CheckUtil::getcurTime();
|
|
|
// 对AI的结果进行 处理,等待 AI 推理全部完成。
|
|
|
rec = AIMaskDet();
|
|
|
if (rec != CHECK_OK)
|
|
|
{
|
|
|
m_nErrorCode = rec;
|
|
|
m_nCheckResultErrorCode = m_nErrorCode;
|
|
|
return m_nErrorCode;
|
|
|
}
|
|
|
time_AI_e = CheckUtil::getcurTime();
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "4、detect", "-------------------------2、AI Detect--------%ld wait AI complate %ld-------\n", time_AI_e - time_AI_s, time_AI_e - t211);
|
|
|
|
|
|
m_CheckResult_shareP->resultMaskImg = m_pImageAllResult->AIMaskImg;
|
|
|
}
|
|
|
|
|
|
{
|
|
|
|
|
|
t4 = CheckUtil::getcurTime();
|
|
|
rec = GetCheckResultBLob();
|
|
|
if (rec != CHECK_OK)
|
|
|
{
|
|
|
m_nErrorCode = rec;
|
|
|
m_nCheckResultErrorCode = m_nErrorCode;
|
|
|
return m_nErrorCode;
|
|
|
}
|
|
|
t5 = CheckUtil::getcurTime();
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "5、BLob ", "------------------------ --------%ld -------\n", t5 - t4);
|
|
|
}
|
|
|
// m_pdetlog->printLog(m_strCurDetChannel);
|
|
|
|
|
|
long te = CheckUtil::getcurTime();
|
|
|
m_pdetlog->bPrintStr = true;
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, "result", " ALL use Time %ld edge %ld AI %ld blob %ld",
|
|
|
te - t1, time_edge_e - time_edge_s, time_AI_e - time_AI_s, t5 - t4);
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, "End", " Check Run");
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::SetNewConfig()
|
|
|
{
|
|
|
if (m_nConfigIdx < 0)
|
|
|
{
|
|
|
return 1;
|
|
|
/* code */
|
|
|
}
|
|
|
|
|
|
if (m_pConfig->GetConfigUpdataStatus(ConfigType_Analysisy_Common_XL, m_nConfigIdx))
|
|
|
{
|
|
|
m_bupdateconfig = true;
|
|
|
// printf("************** ImgCheckAnalysisy::SetNewConfig m_nConfigIdx %d\n", m_nConfigIdx);
|
|
|
m_old_productROI = cv::Rect(0, 0, 0, 0);
|
|
|
m_pConfig->GetConfig(ConfigType_Analysisy_Common_XL, &m_AnalysisyConfig);
|
|
|
if (m_AnalysisyConfig.commonCheckConfig.nodeConfigArr.size() > 0)
|
|
|
{
|
|
|
m_pCommonAnalysisyConfig = &m_AnalysisyConfig.commonCheckConfig.nodeConfigArr.at(0);
|
|
|
m_pBasicConfig = &m_AnalysisyConfig.commonCheckConfig.baseConfig;
|
|
|
m_pRegionAnalysisyParam = &m_pCommonAnalysisyConfig->regionConfigArr.at(0);
|
|
|
|
|
|
UpdateImgageScale();
|
|
|
if (false)
|
|
|
{
|
|
|
printf("SetNewConfig m_nConfigIdx %d m_CheckConfig.strSkuName %s \n", m_nConfigIdx, m_AnalysisyConfig.strSkuName.c_str());
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
printf("m_AnalysisyConfig.commonCheckConfig.nodeConfigArr == 0 \n");
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
// printf("ConfigType_Analysisy_Common_XL no Update \n");
|
|
|
}
|
|
|
m_nErrorCode = CHECK_OK;
|
|
|
return CHECK_OK;
|
|
|
}
|
|
|
|
|
|
ChannelCheckFunction *ImgCheckAnalysisy::GetChannelFuntion(std::string strChannelName)
|
|
|
{
|
|
|
ChannelCheckFunction *p = NULL;
|
|
|
for (int i = 0; i < m_AnalysisyConfig.checkFunction.channelFunctionArr.size(); i++)
|
|
|
{
|
|
|
if (CheckUtil::compareIgnoreCase(m_AnalysisyConfig.checkFunction.channelFunctionArr[i].strChannelName, strChannelName))
|
|
|
{
|
|
|
p = &m_AnalysisyConfig.checkFunction.channelFunctionArr[i];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return p;
|
|
|
}
|
|
|
int ImgCheckAnalysisy::Run(int nId)
|
|
|
{
|
|
|
std::vector<int> vi;
|
|
|
vi.push_back(nId);
|
|
|
auto nRet = set_cpu_id(vi);
|
|
|
// printf("Check So %d bind cpu ret %d, %d\n", m_nThreadIdx, nRet, nId);
|
|
|
while (!m_bExit)
|
|
|
{
|
|
|
// 数据准备完成,开启检测
|
|
|
if (m_nRun_Status == CHECK_THREAD_STATUS_READY)
|
|
|
{
|
|
|
m_nRun_Status = CHECK_THREAD_STATUS_BUSY;
|
|
|
/* 检测 */
|
|
|
CheckRun();
|
|
|
m_nRun_Status = CHECK_THREAD_STATUS_COMPLETE;
|
|
|
m_pImageAllResult->setStep(ImageAllResult::DetStep_Complet);
|
|
|
m_nRun_Status = CHECK_THREAD_STATUS_IDLE;
|
|
|
// printf("*--------%d\n", m_nRun_Status);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
|
|
|
usleep(1000);
|
|
|
}
|
|
|
// printf("*-");
|
|
|
usleep(1000);
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
int ImgCheckAnalysisy::set_cpu_id(const std::vector<int> &cpu_set_vec)
|
|
|
{
|
|
|
// for cpu affinity
|
|
|
int nRet = 0;
|
|
|
#ifdef __linux
|
|
|
cpu_set_t _cur_cpu_set;
|
|
|
CPU_ZERO(&_cur_cpu_set);
|
|
|
for (auto _id : cpu_set_vec)
|
|
|
{
|
|
|
CPU_SET(_id, &_cur_cpu_set);
|
|
|
}
|
|
|
if (0 > pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &_cur_cpu_set))
|
|
|
{
|
|
|
perror("set cpu affinity failed: ");
|
|
|
printf("Warning: set cpu affinity failed ... ...\n");
|
|
|
nRet = -1;
|
|
|
}
|
|
|
#endif //__linux
|
|
|
return nRet;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::CalBlob_Other()
|
|
|
{
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "CalBlob_Other", " Start");
|
|
|
|
|
|
float fs_x = m_fImgage_Scale_X;
|
|
|
float fs_y = m_fImgage_Scale_Y;
|
|
|
|
|
|
float fs_resize_x = m_pImageAllResult->fscale_detToresult_x;
|
|
|
float fs_resize_y = m_pImageAllResult->fscale_detToresult_y;
|
|
|
// 遍历每个检测blob
|
|
|
for (int i = 0; i < blobs.blobCount; i++)
|
|
|
{
|
|
|
|
|
|
// m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Blob", "%d/%d start", i, blobs.blobCount);
|
|
|
|
|
|
cv::Rect roi;
|
|
|
roi.x = blobs.blobTab[i].minx;
|
|
|
roi.y = blobs.blobTab[i].miny;
|
|
|
roi.width = blobs.blobTab[i].maxx - blobs.blobTab[i].minx + 1;
|
|
|
roi.height = blobs.blobTab[i].maxy - blobs.blobTab[i].miny + 1;
|
|
|
|
|
|
cv::Scalar result = calc_blob_info_withstats(m_pImageAllResult->detImg, m_pImageAllResult->AIMaskImg, roi);
|
|
|
|
|
|
int QX_whiteBLACK = CONFIG_QX_BLACK;
|
|
|
if (result[0] > 0)
|
|
|
{
|
|
|
QX_whiteBLACK = CONFIG_QX_WHITE;
|
|
|
}
|
|
|
|
|
|
double hj = result[2];
|
|
|
double energe = result[1];
|
|
|
blobs.blobTab[i].energy = energe;
|
|
|
blobs.blobTab[i].grayDis = hj;
|
|
|
|
|
|
float JudgArea = blobs.blobTab[i].area * fs_x * fs_y;
|
|
|
blobs.blobTab[i].JudgArea = JudgArea;
|
|
|
float flen = roi.width * fs_x;
|
|
|
float fwid = roi.height * fs_x;
|
|
|
if (roi.height * fs_y > flen)
|
|
|
{
|
|
|
flen = roi.height * fs_y;
|
|
|
fwid = roi.width * fs_y;
|
|
|
}
|
|
|
blobs.blobTab[i].len = flen;
|
|
|
blobs.blobTab[i].breadth = fwid;
|
|
|
|
|
|
int nerrortype = 0;
|
|
|
int checkFlage = 0;
|
|
|
|
|
|
float fmaxScore = 0;
|
|
|
int config_qx_type = 0;
|
|
|
|
|
|
if (blobs.blobTab[i].ErrType == ERR_TYPE_2)
|
|
|
{
|
|
|
QX_whiteBLACK = CONFIG_QX_BLACK; // 强制为 黑色
|
|
|
}
|
|
|
blobs.blobTab[i].whiteOrblack = QX_whiteBLACK;
|
|
|
|
|
|
// 精确计算长度
|
|
|
vector<float> re_len = Cal_QXLen(m_pImageAllResult->detImg(roi), config_qx_type, fs_x, fs_y);
|
|
|
|
|
|
if (re_len.size() > 2)
|
|
|
{
|
|
|
if(re_len[0] >= 0){
|
|
|
flen = re_len[0];
|
|
|
blobs.blobTab[i].len = flen;
|
|
|
}
|
|
|
if(re_len[1] >= 0){
|
|
|
fwid = re_len[1];
|
|
|
blobs.blobTab[i].breadth = fwid;
|
|
|
}
|
|
|
|
|
|
}
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::GetClassImg(const cv::Mat &img, cv::Mat &AIdetImg, cv::Rect qx_roi, int detwidth, int detheight)
|
|
|
{
|
|
|
|
|
|
cv::Rect cutroi;
|
|
|
cv::Rect roi = qx_roi;
|
|
|
bool bresize = false;
|
|
|
{
|
|
|
|
|
|
int pc_x = roi.x + roi.width * 0.5;
|
|
|
int pc_y = roi.y + roi.height * 0.5;
|
|
|
|
|
|
if (roi.width < detwidth && roi.height < detheight)
|
|
|
{
|
|
|
cutroi.width = detwidth;
|
|
|
cutroi.x = pc_x - detwidth * 0.5;
|
|
|
cutroi.height = detheight;
|
|
|
cutroi.y = pc_y - detheight * 0.5;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
// 宽 高
|
|
|
if (roi.width > roi.height)
|
|
|
{
|
|
|
cutroi.width = roi.width + 20;
|
|
|
cutroi.x = roi.x - 10;
|
|
|
|
|
|
float fsx = detheight * 1.0f / detwidth;
|
|
|
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 = detwidth * 1.0f / detheight;
|
|
|
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;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
if (!CheckUtil::RoiInImg(cutroi, img))
|
|
|
{
|
|
|
return 1;
|
|
|
}
|
|
|
cv::Size sz;
|
|
|
sz.width = detwidth;
|
|
|
sz.height = detheight;
|
|
|
if (cutroi.width != sz.width || cutroi.height != sz.height)
|
|
|
{
|
|
|
cv::resize(img(cutroi), AIdetImg, sz);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
AIdetImg = img(cutroi).clone();
|
|
|
}
|
|
|
|
|
|
if (1 != AIdetImg.channels())
|
|
|
{
|
|
|
cv::cvtColor(AIdetImg, AIdetImg, cv::COLOR_BGR2GRAY);
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
vector<float> ImgCheckAnalysisy::Cal_QXLen(cv::Mat qx_maskImg, int qx_type, float fsc_x, float fsc_y)
|
|
|
{
|
|
|
vector<float> resLen(3);
|
|
|
|
|
|
float nlen = -1;
|
|
|
cv::Mat detimg = qx_maskImg;
|
|
|
|
|
|
resLen[0] = nlen;
|
|
|
// 寻找轮廓
|
|
|
vector<vector<Point>> contours;
|
|
|
cv::findContours(detimg, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
|
|
|
|
|
|
// 找到最大面积的轮廓
|
|
|
double maxArea = -1;
|
|
|
int maxAreaIdx = -1;
|
|
|
for (size_t i = 0; i < contours.size(); ++i)
|
|
|
{
|
|
|
double area = contourArea(contours[i]);
|
|
|
if (area > maxArea)
|
|
|
{
|
|
|
maxArea = area;
|
|
|
maxAreaIdx = i;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 如果找到了最大面积的轮廓
|
|
|
if (maxAreaIdx >= 0)
|
|
|
{
|
|
|
|
|
|
// 使用minAreaRect找到最小外接矩形
|
|
|
cv::RotatedRect rect = cv::minAreaRect(contours[maxAreaIdx]);
|
|
|
|
|
|
// // 绘制最小外接矩形
|
|
|
// Point2f vertices[4];
|
|
|
// rect.points(vertices);
|
|
|
// for (int i = 0; i < 4; ++i)
|
|
|
// {
|
|
|
// line(detimg, vertices[i], vertices[(i + 1) % 4], Scalar(128, 255, 0), 2); // 绿色线
|
|
|
// }
|
|
|
// 输出结果
|
|
|
|
|
|
// 获取最小外接矩形的尺寸
|
|
|
float width = rect.size.width;
|
|
|
float height = rect.size.height;
|
|
|
|
|
|
// std::cout << "1 Width: " << width << ", Height: " << height << std::endl;
|
|
|
Point2f vertices[4];
|
|
|
rect.points(vertices);
|
|
|
|
|
|
vector<Point2f> newcont;
|
|
|
for (int i = 0; i < 4; ++i)
|
|
|
{
|
|
|
Point2f p;
|
|
|
p.x = vertices[i].x * fsc_x;
|
|
|
p.y = vertices[i].y * fsc_y;
|
|
|
newcont.push_back(p);
|
|
|
}
|
|
|
vector<vector<Point2f>> contours_New;
|
|
|
contours_New.push_back(newcont);
|
|
|
// Recreate the rotated rectangle with scaled vertices
|
|
|
RotatedRect scaledRect = minAreaRect(contours_New[0]);
|
|
|
|
|
|
// Calculate scaled width and height
|
|
|
width = scaledRect.size.width;
|
|
|
height = scaledRect.size.height;
|
|
|
// std::cout << "2 width: " << width << ", height: " << height << std::endl;
|
|
|
// float scale = 0.5; // 缩放比例
|
|
|
// rect.size.width *= fsc_x;
|
|
|
// rect.size.height *= fsc_y;
|
|
|
// std::cout << "fsc_x: " << fsc_x << ", fsc_y: " << fsc_y << std::endl;
|
|
|
// std::cout << "Width: " << width << ", Height: " << height << std::endl;
|
|
|
// 获取最小外接矩形的尺寸
|
|
|
// width = rect.size.width;
|
|
|
// height = rect.size.height;
|
|
|
if (width > height)
|
|
|
{
|
|
|
nlen = width;
|
|
|
resLen[0] = width;
|
|
|
resLen[1] = height;
|
|
|
/* code */
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
nlen = height;
|
|
|
resLen[0] = height;
|
|
|
resLen[1] = width;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// getchar();
|
|
|
return resLen;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::GetCheckResultBLob()
|
|
|
{
|
|
|
long t1, t2, t3, t4, t5, t6, t7;
|
|
|
t1 = CheckUtil::getcurTime();
|
|
|
int re = GetALLBlob();
|
|
|
if (re != 0)
|
|
|
{
|
|
|
return re;
|
|
|
}
|
|
|
|
|
|
// 缺陷分类 多线程 实现。
|
|
|
long t11 = CheckUtil::getcurTime();
|
|
|
m_Classtask = std::make_shared<TaskInfo>();
|
|
|
m_Classtask->taskname = Task_Class;
|
|
|
m_task.sendTask(m_Classtask);
|
|
|
|
|
|
re = CalBlob_Other();
|
|
|
if (re != 0)
|
|
|
{
|
|
|
return re;
|
|
|
}
|
|
|
long t12 = CheckUtil::getcurTime();
|
|
|
// 等待分类 完成。
|
|
|
m_Classtask->waitComplate();
|
|
|
long t13 = CheckUtil::getcurTime();
|
|
|
// printf("=========== cls time %ld waite time %ld\n", t13 - t11, t13 - t12);
|
|
|
|
|
|
BLobToDetResult();
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
void worker(const unsigned char *img, int w, int startRow, int endRow, unsigned char *rowFlags)
|
|
|
{
|
|
|
for (int y = startRow; y < endRow; y++)
|
|
|
{
|
|
|
const unsigned char *p = img + (size_t)y * w;
|
|
|
rowFlags[y] = 0;
|
|
|
for (int x = 0; x < w; x++)
|
|
|
{
|
|
|
if (p[x] != 0)
|
|
|
{
|
|
|
rowFlags[y] = 1;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
int ImgCheckAnalysisy::GetALLBlob()
|
|
|
{
|
|
|
|
|
|
std::string strBaseLog = "Blob";
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "image Blob Analysis Start");
|
|
|
if (m_pImageAllResult->AIMaskImg.empty())
|
|
|
{
|
|
|
return 1;
|
|
|
}
|
|
|
unsigned char *pGrayErrordata = (unsigned char *)m_pImageAllResult->AIMaskImg.data;
|
|
|
int width = m_pImageAllResult->AIMaskImg.cols;
|
|
|
int height = m_pImageAllResult->AIMaskImg.rows;
|
|
|
|
|
|
long t1 = CheckUtil::getcurTime();
|
|
|
|
|
|
memset(&blobs, 0x00, sizeof(ERROR_DOTS_BLOBS));
|
|
|
|
|
|
ERROR_DOTS_BLOBS blobs_v1;
|
|
|
memset(&blobs_v1, 0x00, sizeof(ERROR_DOTS_BLOBS));
|
|
|
ERROR_DOTS_BLOBS blobs_big;
|
|
|
memset(&blobs_big, 0x00, sizeof(ERROR_DOTS_BLOBS));
|
|
|
ERROR_DOTS_BLOBS blobs_big_2;
|
|
|
memset(&blobs_big_2, 0x00, sizeof(ERROR_DOTS_BLOBS));
|
|
|
printf("=====>>>> GetALLBlob m_strCurDetChannel %s \n", m_strCurDetChannel.c_str());
|
|
|
if (m_strCurDetChannel == "CA")
|
|
|
{
|
|
|
printf("=====>>>>GetALLBlob USE CA %s \n", m_strCurDetChannel.c_str());
|
|
|
GetBlobs_ALL_New(&blobs_v1, pGrayErrordata, m_ImgBlobHFlagData, width, height, 15);
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "blob 1 num %d", blobs_v1.blobCount);
|
|
|
|
|
|
if (blobs_v1.srcBlobCount >= _MAX_ERROR_DOT_BLOB)
|
|
|
{
|
|
|
|
|
|
GetBlobs_ALL_New(&blobs_big, pGrayErrordata, m_ImgBlobHFlagData, width, height, 200);
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "blob 2 num %d", blobs_big.blobCount);
|
|
|
|
|
|
if (blobs_big.srcBlobCount >= _MAX_ERROR_DOT_BLOB)
|
|
|
{
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "blob 3 num %d", blobs_big_2.blobCount);
|
|
|
GetBlobs_ALL_New(&blobs_big_2, pGrayErrordata, m_ImgBlobHFlagData, width, height, 500);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
GetBlobs_oneLabe(&blobs_v1, pGrayErrordata, m_ImgBlobHFlagData, width, height, 15);
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "blob 1 num %d", blobs_v1.blobCount);
|
|
|
|
|
|
if (blobs_v1.srcBlobCount >= _MAX_ERROR_DOT_BLOB)
|
|
|
{
|
|
|
|
|
|
GetBlobs_oneLabe(&blobs_big, pGrayErrordata, m_ImgBlobHFlagData, width, height, 200);
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "blob 2 num %d", blobs_big.blobCount);
|
|
|
|
|
|
if (blobs_big.srcBlobCount >= _MAX_ERROR_DOT_BLOB)
|
|
|
{
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "blob 3 num %d", blobs_big_2.blobCount);
|
|
|
GetBlobs_oneLabe(&blobs_big_2, pGrayErrordata, m_ImgBlobHFlagData, width, height, 500);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
long t2 = CheckUtil::getcurTime();
|
|
|
PushBlob(&blobs, &blobs_big_2);
|
|
|
PushBlob(&blobs, &blobs_big);
|
|
|
PushBlob(&blobs, &blobs_v1);
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "blob ALL num %d", blobs.blobCount);
|
|
|
// long t2 = CheckUtil::getcurTime();
|
|
|
// printf(" BLob time %ld \n", t2 - t1);
|
|
|
|
|
|
if (false || DetImgInfo_shareP->bsaveProcessImg)
|
|
|
{
|
|
|
int font_face = cv::FONT_HERSHEY_SIMPLEX;
|
|
|
double font_scale = 0.5;
|
|
|
int thickness = 1;
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, strBaseLog, "Save Tem Img");
|
|
|
cv::Mat tm;
|
|
|
cv::cvtColor(m_pImageAllResult->AIMaskImg, tm, cv::COLOR_GRAY2RGB); // 彩色 可选项
|
|
|
for (int i = 0; i < blobs.blobCount; i++)
|
|
|
{
|
|
|
cv::Rect roi;
|
|
|
roi.x = blobs.blobTab[i].minx;
|
|
|
roi.y = blobs.blobTab[i].miny;
|
|
|
roi.width = blobs.blobTab[i].maxx - blobs.blobTab[i].minx + 1;
|
|
|
roi.height = blobs.blobTab[i].maxy - blobs.blobTab[i].miny + 1;
|
|
|
|
|
|
if (blobs.blobTab[i].ErrType == 0)
|
|
|
{
|
|
|
cv::rectangle(tm, roi, cv::Scalar(0, 0, 255));
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
cv::rectangle(tm, roi, cv::Scalar(0, 255, 255));
|
|
|
}
|
|
|
|
|
|
char buffer[128];
|
|
|
sprintf(buffer, "id:%d type:%d m %0.1f", i,blobs.blobTab[i].ErrType, blobs.blobTab[i].density);
|
|
|
std::string text = buffer;
|
|
|
cv::Point origin = cv::Point(roi.x, roi.y);
|
|
|
cv::putText(tm, text, origin, font_face, font_scale, cv::Scalar(0, 255, 0), thickness, 1, 0);
|
|
|
|
|
|
// printf("type: %d %d %d %d %d %d %d\n", blobs.blobTab[i].ErrType, blobs.blobTab[i].area, blobs.blobTab[i].energy, roi.x, roi.y, roi.width, roi.height);
|
|
|
}
|
|
|
cv::imwrite(m_CheckResult_shareP->in_shareImage->strChannel + "_image_resize_blob.png", tm);
|
|
|
}
|
|
|
|
|
|
long te = CheckUtil::getcurTime();
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "image Blob Analysis End use time %ld blob %ld ms", te - t1, t2 - t1);
|
|
|
|
|
|
// getchar();
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::AIMaskDet()
|
|
|
{
|
|
|
|
|
|
// 计算 mask 图片的一行 是否有 残点,用以加速 Blob的计算。
|
|
|
if (m_ImgBlobHFlagData)
|
|
|
{
|
|
|
delete[] m_ImgBlobHFlagData;
|
|
|
m_ImgBlobHFlagData = NULL;
|
|
|
}
|
|
|
m_ImgBlobHFlagData = new unsigned char[m_pImageAllResult->detImg.rows];
|
|
|
memset(m_ImgBlobHFlagData, 0, sizeof(unsigned char) * m_pImageAllResult->detImg.rows);
|
|
|
|
|
|
while (true)
|
|
|
{
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
|
std::shared_ptr<AIMulThreadRunBase::AITask> AImaskResult;
|
|
|
{
|
|
|
std::lock_guard<std::mutex> lock(mtx_AIMaskImgBLobQueue);
|
|
|
if (m_AIMaskImgBLobQueue.size() > 0)
|
|
|
{
|
|
|
AImaskResult = std::move(m_AIMaskImgBLobQueue.front());
|
|
|
m_AIMaskImgBLobQueue.pop();
|
|
|
// printf("size ============== %ld\n", m_AIMaskImgBLobQueue.size());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 有AI mask 的结果
|
|
|
if (AImaskResult)
|
|
|
{
|
|
|
// static int ss = 0;
|
|
|
cv::Mat &outimg = *(AImaskResult->output);
|
|
|
// cv::imwrite(std::to_string(ss++) + ".png", outimg);
|
|
|
|
|
|
unsigned char *pGrayErrordata = (unsigned char *)outimg.data;
|
|
|
int width = outimg.cols;
|
|
|
int height = outimg.rows;
|
|
|
int start_Y = AImaskResult->roi.y;
|
|
|
if (cv::countNonZero(outimg != 0) != 0)
|
|
|
{
|
|
|
// #pragma omp parallel for
|
|
|
for (int y = 0; y < height; y++)
|
|
|
{
|
|
|
if (m_ImgBlobHFlagData[y + start_Y] == 0)
|
|
|
{
|
|
|
unsigned char *p = pGrayErrordata + y * width;
|
|
|
for (int x = 0; x < width; x++)
|
|
|
{
|
|
|
if (p[x] != 0)
|
|
|
{
|
|
|
m_ImgBlobHFlagData[y + start_Y] = 1;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
/* code */
|
|
|
|
|
|
if (m_AItask->isComplate())
|
|
|
{
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
// printf("===========================================1 \n");
|
|
|
m_AItask->waitComplate();
|
|
|
int rec = m_AItask->nresult;
|
|
|
if (rec != CHECK_OK)
|
|
|
{
|
|
|
return rec;
|
|
|
}
|
|
|
// printf("===========================================2 \n");
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::Contours()
|
|
|
{
|
|
|
// std::string strBaseLog = "Contours";
|
|
|
// // m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "Contours Start");
|
|
|
// cv::Mat detimg;
|
|
|
// {
|
|
|
// // 膨胀
|
|
|
// cv::Mat se = getStructuringElement(0, Size(5, 5)); // 构造矩形结构元素
|
|
|
// cv::dilate(m_pdetlog->temImgList[TEM_IMG_IDX_AImask], detimg, se);
|
|
|
// }
|
|
|
|
|
|
// std::vector<std::vector<cv::Point>> contours;
|
|
|
// std::vector<cv::Vec4i> hierarchy;
|
|
|
// cv::findContours(detimg, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE); // 只找最外层轮廓
|
|
|
|
|
|
// // cv::cvtColor(m_pdetlog->temImgList[TEM_IMG_IDX_SrcCrop], m_pdetlog->temImgList[TEM_IMG_IDX_DrawSrc], cv::COLOR_GRAY2BGR);
|
|
|
|
|
|
// for (int i = 0; i < contours.size(); ++i)
|
|
|
// { // 绘制所有轮廓
|
|
|
// cv::drawContours(m_pdetlog->temImgList[TEM_IMG_IDX_DrawSrc], contours, i, cv::Scalar(255, 0, 255)); // thickness为-1时为填充整个轮廓
|
|
|
// }
|
|
|
|
|
|
// float fx = m_pdetlog->temImgList[TEM_IMG_IDX_Result].cols * 1.0f / m_pdetlog->temImgList[TEM_IMG_IDX_SrcCrop].cols;
|
|
|
// float fy = m_pdetlog->temImgList[TEM_IMG_IDX_Result].rows * 1.0f / m_pdetlog->temImgList[TEM_IMG_IDX_SrcCrop].rows;
|
|
|
// for (int i = 0; i < contours.size(); ++i)
|
|
|
// {
|
|
|
// for (int j = 0; j < contours.at(i).size(); ++j)
|
|
|
// {
|
|
|
// contours.at(i).at(j).x *= fx;
|
|
|
// contours.at(i).at(j).y *= fy;
|
|
|
// }
|
|
|
// }
|
|
|
// // cv::cvtColor(m_pdetlog->temImgList[TEM_IMG_IDX_Result], m_pdetlog->temImgList[TEM_IMG_IDX_Result], cv::COLOR_GRAY2BGR);
|
|
|
|
|
|
// for (int i = 0; i < contours.size(); ++i)
|
|
|
// { // 绘制所有轮廓
|
|
|
// cv::drawContours(m_pdetlog->temImgList[TEM_IMG_IDX_Result], contours, i, cv::Scalar(255, 0, 255)); // thickness为-1时为填充整个轮廓
|
|
|
// }
|
|
|
// cv::imwrite("TEM_IMG_IDX_Result.png", m_pdetlog->temImgList[TEM_IMG_IDX_Result]);
|
|
|
// cv::imwrite("deeeee.png", m_pdetlog->temImgList[TEM_IMG_IDX_Drawmask]);
|
|
|
// getchar();
|
|
|
// m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "Contours End");
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::CheckImgInit()
|
|
|
{
|
|
|
// 1、初始化
|
|
|
|
|
|
m_pDetResult->pQx_ErrorList = std::make_shared<std::vector<QX_ERROR_INFO_>>();
|
|
|
m_pdetlog->Init();
|
|
|
m_pdetlog->addLogLevel = DET_LOG_LEVEL_3;
|
|
|
memset(&blobs, 0, sizeof(ERROR_DOTS_BLOBS));
|
|
|
m_nCheckResultErrorCode = 0;
|
|
|
|
|
|
m_Draw_qxImageResult.erase(m_Draw_qxImageResult.begin(), m_Draw_qxImageResult.end());
|
|
|
|
|
|
m_DetRoiList.Init();
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::ConfigCheck(cv::Mat img)
|
|
|
{
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "start", "Config Check");
|
|
|
int re = CHECK_OK;
|
|
|
if (img.empty())
|
|
|
{
|
|
|
m_nErrorCode = CHECK_ERROR_CheckImg_Empty;
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, "Error", "check Img empty");
|
|
|
return m_nErrorCode;
|
|
|
}
|
|
|
|
|
|
// if (m_pCommonAnalysisyConfig->regionConfigArr.size() <= 0)
|
|
|
// {
|
|
|
// m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Error", "regionConfig Num = 0");
|
|
|
// m_nErrorCode = CHECK_ERROR_Config_Value;
|
|
|
// return m_nErrorCode;
|
|
|
// }
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Succ", "Config Check Succ");
|
|
|
return re;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::AI_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg)
|
|
|
{
|
|
|
// 依次使用多个检测模型,各模型输出 mask 取并集作为最终 outmask
|
|
|
std::vector<std::shared_ptr<AIModel_Base>> pAIDetList;
|
|
|
pAIDetList.push_back(AI_Factory->Defect);
|
|
|
pAIDetList.push_back(AI_Factory->Defect_QueXi);
|
|
|
|
|
|
|
|
|
std::string strBaseLog = "AI_Detect";
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "AI_Detect Start");
|
|
|
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)
|
|
|
{
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, strBaseLog, " cutSmallImg error %d", re);
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "AI_Detect End");
|
|
|
return re;
|
|
|
/* code */
|
|
|
}
|
|
|
|
|
|
// 临时存图
|
|
|
if (DetImgInfo_shareP->bsaveProcessImg)
|
|
|
{
|
|
|
|
|
|
cv::Mat imshow;
|
|
|
if (img.channels() == 1)
|
|
|
{
|
|
|
cv::cvtColor(img, imshow, cv::COLOR_GRAY2RGB); // 彩色 可选项
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
imshow = img.clone();
|
|
|
}
|
|
|
for (int i = 0; i < SmallRoiList.size(); i++)
|
|
|
{
|
|
|
cv::rectangle(imshow, SmallRoiList.at(i), cv::Scalar(0, 0, 255), 3);
|
|
|
}
|
|
|
cv::imwrite(DetImgInfo_shareP->strChannel + "_AI_Det_ROI.jpg", imshow);
|
|
|
}
|
|
|
|
|
|
ResultImg = cv::Mat::zeros(img.size(), CV_8UC1);
|
|
|
|
|
|
const int totalTasks = SmallRoiList.size();
|
|
|
|
|
|
// std::string str_Root = m_strRootPath + pDetConfig->strProductID + "_" + pDetConfig->strchannel + "_";
|
|
|
t2 = CheckUtil::getcurTime();
|
|
|
|
|
|
// 依次用多个模型做检测,所有模型输出的 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)
|
|
|
{
|
|
|
// 如果任务还没提交完,且当前处理任务数 < 10,提交新任务
|
|
|
if (submitted < totalTasks && runner->GetProcessingCount() < 10)
|
|
|
{
|
|
|
|
|
|
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;
|
|
|
|
|
|
runner->SubmitTask(task);
|
|
|
submitted++;
|
|
|
}
|
|
|
|
|
|
// 尝试取结果
|
|
|
std::shared_ptr<AIMulThreadRunBase::AITask> result;
|
|
|
if (runner->PopResult(result))
|
|
|
{
|
|
|
|
|
|
{
|
|
|
std::lock_guard<std::mutex> lock(mtx_AIMaskImgBLobQueue);
|
|
|
m_AIMaskImgBLobQueue.push(result);
|
|
|
}
|
|
|
|
|
|
cv::Mat &outimg = *(result->output);
|
|
|
if (!outimg.empty())
|
|
|
{
|
|
|
// 多个模型的结果取并集
|
|
|
cv::Mat roiMat = ResultImg(result->roi);
|
|
|
cv::bitwise_or(roiMat, outimg, roiMat);
|
|
|
}
|
|
|
|
|
|
// 同一 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));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
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 Small Img %f", t3 - t1, t2 - t1, t3 - t2, mean_AI);
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "AI_Detect End");
|
|
|
|
|
|
// 临时存图
|
|
|
if (DetImgInfo_shareP->bsaveProcessImg)
|
|
|
{
|
|
|
cv::imwrite(DetImgInfo_shareP->strChannel + "_AI_mask.png", ResultImg);
|
|
|
}
|
|
|
|
|
|
// getchar();
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::AI_QX_Class_Thread()
|
|
|
{
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "QX_Class", " Start");
|
|
|
|
|
|
std::shared_ptr<AIModel_Base> pAIDet;
|
|
|
// printf("=====>>>>AI_QX_Class_Thread m_strCurDetChannel %s \n", m_strCurDetChannel.c_str());
|
|
|
{
|
|
|
// printf("=====>>>>AI_QX_Class_Thread USE CA %s \n", m_strCurDetChannel.c_str());
|
|
|
pAIDet = AI_Factory->Class;
|
|
|
}
|
|
|
|
|
|
int deal_image_width = pAIDet->input_0.width;
|
|
|
int deal_image_height = pAIDet->input_0.height;
|
|
|
|
|
|
const int totalTasks = blobs.blobCount;
|
|
|
int submitted = 0;
|
|
|
int completed = 0;
|
|
|
int detblobIdx = 0;
|
|
|
int clsnum = 0;
|
|
|
// std::string str_Root = m_strRootPath + pDetConfig->strProductID + "_" + pDetConfig->strchannel + "_";
|
|
|
long t2 = CheckUtil::getcurTime();
|
|
|
while (completed < totalTasks)
|
|
|
{
|
|
|
// std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
|
if (submitted < totalTasks)
|
|
|
{
|
|
|
ERROR_DOTS_BLOB_DATA *pblob = &blobs.blobTab[submitted];
|
|
|
if (pblob->ErrType == ERR_TYPE_2)
|
|
|
{
|
|
|
pblob->AIclasstype = CONFIG_QX_NAME_cell_ymhs;
|
|
|
submitted++;
|
|
|
completed++;
|
|
|
continue;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
// 如果任务还没提交完,且当前处理任务数 < 2,提交新任务
|
|
|
if (runner->GetProcessingCount() < 10)
|
|
|
{
|
|
|
clsnum++;
|
|
|
cv::Rect roi;
|
|
|
roi.x = pblob->minx;
|
|
|
roi.y = pblob->miny;
|
|
|
roi.width = pblob->maxx - pblob->minx + 1;
|
|
|
roi.height = pblob->maxy - pblob->miny + 1;
|
|
|
|
|
|
std::shared_ptr<AIMulThreadRunBase::AITask> task = std::make_shared<AIMulThreadRunBase::AITask>();
|
|
|
task->id = submitted;
|
|
|
int re = GetClassImg(m_pImageAllResult->detImg, task->input, roi, deal_image_width, deal_image_height);
|
|
|
if (re == 0)
|
|
|
{
|
|
|
task->bclass = true;
|
|
|
task->engine = pAIDet;
|
|
|
runner->SubmitTask(task);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
completed++;
|
|
|
}
|
|
|
|
|
|
submitted++;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 尝试取结果
|
|
|
std::shared_ptr<AIMulThreadRunBase::AITask> result;
|
|
|
if (runner->PopResult(result))
|
|
|
{
|
|
|
|
|
|
int temClass = result->cls_label;
|
|
|
int cls_num = 0;
|
|
|
|
|
|
switch (temClass)
|
|
|
{
|
|
|
case 0:
|
|
|
cls_num = AI_CLass_QX_NAME_aotudian;
|
|
|
break;
|
|
|
|
|
|
case 1:
|
|
|
cls_num = AI_CLass_QX_NAME_other;
|
|
|
break;
|
|
|
|
|
|
case 2:
|
|
|
cls_num = AI_CLass_QX_NAME_line;
|
|
|
break;
|
|
|
|
|
|
case 3:
|
|
|
cls_num = AI_CLass_QX_NAME_zangwu;
|
|
|
break;
|
|
|
|
|
|
case 4:
|
|
|
cls_num = AI_CLass_QX_NAME_dianzhuang;
|
|
|
break;
|
|
|
|
|
|
case 5:
|
|
|
cls_num = AI_CLass_QX_NAME_posun;
|
|
|
break;
|
|
|
|
|
|
case 6:
|
|
|
cls_num = AI_CLass_QX_NAME_xianwei;
|
|
|
break;
|
|
|
|
|
|
case 7:
|
|
|
cls_num = AI_CLass_QX_NAME_shuizi;
|
|
|
break;
|
|
|
|
|
|
case 8:
|
|
|
cls_num = AI_CLass_QX_NAME_danban;
|
|
|
break;
|
|
|
|
|
|
case 9:
|
|
|
cls_num = AI_CLass_QX_NAME_fuchen;
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
cls_num = AI_CLass_QX_NAME_zangwu;
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
// std::string strclassName = AI_CLass_QX_NAME_Names[cls_num];
|
|
|
// printf("AI Class num %d = %s %f\n", cls_num, strclassName.c_str(), result->cls_score);
|
|
|
|
|
|
// 分类存图 开启。
|
|
|
if (m_pbaseCheckFunction->saveImg.bSaveAlginImg)
|
|
|
{
|
|
|
|
|
|
std::string saveimgpaht = "";
|
|
|
|
|
|
if (m_strCurDetChannel == "TA")
|
|
|
{
|
|
|
saveimgpaht = m_strRootPath_TA_cls + std::to_string(cls_num) + "/" + std::to_string(CheckUtil::getcurTime()) + "_" + std::to_string(result->cls_score) + ".png";
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
saveimgpaht = m_strRootPath_CA_cls + std::to_string(cls_num) + "/" + std::to_string(CheckUtil::getcurTime()) + "_" + std::to_string(result->cls_score) + ".png";
|
|
|
}
|
|
|
|
|
|
{
|
|
|
m_pImageStorage->addImage(saveimgpaht, result->input);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
int configqx = AIClassTypeToConfigType(cls_num);
|
|
|
|
|
|
ERROR_DOTS_BLOB_DATA *pblob = &blobs.blobTab[result->id];
|
|
|
pblob->AIclasstype = configqx;
|
|
|
|
|
|
completed++;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
|
}
|
|
|
}
|
|
|
// printf("=====>>>>AI_QX_Class_Thread clsnum %d \n", clsnum);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::ThreadTask(int nId)
|
|
|
{
|
|
|
|
|
|
while (!m_bExit)
|
|
|
{
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
|
|
// 等待是否有任务
|
|
|
std::shared_ptr<TaskInfo> task = m_task.GetTask();
|
|
|
|
|
|
// 把任务发送给对应的任务处理函数进行处理
|
|
|
switch (task->taskname)
|
|
|
{
|
|
|
case Task_AI:
|
|
|
TaskFun_AIDet(task);
|
|
|
break;
|
|
|
case Task_Class:
|
|
|
TaskFun_QxClass(task);
|
|
|
break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::ResizeImg()
|
|
|
{
|
|
|
|
|
|
cv::Size sz;
|
|
|
sz.width = RESIZE_IMAGE_WIDTH;
|
|
|
|
|
|
float fw = RESIZE_IMAGE_WIDTH * 1.0f / m_pImageAllResult->detImg.cols;
|
|
|
sz.height = int(m_pImageAllResult->detImg.rows * fw);
|
|
|
|
|
|
cv::resize(m_pImageAllResult->detImg, m_pImageAllResult->resultImg, sz);
|
|
|
if (m_pImageAllResult->resultImg.channels() == 1)
|
|
|
{
|
|
|
cv::cvtColor(m_pImageAllResult->resultImg, m_pImageAllResult->resultImg, cv::COLOR_GRAY2BGR);
|
|
|
}
|
|
|
m_CheckResult_shareP->resultimg = m_pImageAllResult->resultImg;
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, "showImg size", " [w %d,h %d]-> show img [w %d,h %d] ",
|
|
|
m_outer_roi.width, m_outer_roi.height, sz.width, sz.height);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
void ImgCheckAnalysisy::TaskFun_AIDet(std::shared_ptr<TaskInfo> task)
|
|
|
{
|
|
|
task->SetStatus(TaskStep_run);
|
|
|
long t1, t2;
|
|
|
// AI 推理生成
|
|
|
{
|
|
|
t1 = CheckUtil::getcurTime();
|
|
|
|
|
|
int rec = AI_Detect_Thread(m_pImageAllResult->detImg, m_pImageAllResult->AIMaskImg);
|
|
|
|
|
|
t2 = CheckUtil::getcurTime();
|
|
|
task->nresult = rec;
|
|
|
}
|
|
|
task->SetStatus(TaskStep_compate);
|
|
|
}
|
|
|
|
|
|
void ImgCheckAnalysisy::TaskFun_QxClass(std::shared_ptr<TaskInfo> task)
|
|
|
{
|
|
|
task->SetStatus(TaskStep_run);
|
|
|
long t1, t2;
|
|
|
// AI 推理生成
|
|
|
{
|
|
|
t1 = CheckUtil::getcurTime();
|
|
|
|
|
|
int rec = AI_QX_Class_Thread();
|
|
|
|
|
|
t2 = CheckUtil::getcurTime();
|
|
|
task->nresult = rec;
|
|
|
}
|
|
|
task->SetStatus(TaskStep_compate);
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::Update_DetRoiList()
|
|
|
{
|
|
|
float fx = m_pImageAllResult->fscale_detToresult_x;
|
|
|
float fy = m_pImageAllResult->fscale_detToresult_y;
|
|
|
|
|
|
int num = 0;
|
|
|
cv::Rect offsetroi = m_Crop_Roi_paramImg;
|
|
|
|
|
|
if (m_pEdge_Align_Result && m_pEdge_Align_Result->buseOfft)
|
|
|
{
|
|
|
for (const auto ®ion : m_pCommonAnalysisyConfig->regionConfigArr)
|
|
|
{
|
|
|
|
|
|
if (m_pEdge_Align_Result->H.empty())
|
|
|
{
|
|
|
|
|
|
m_DetRoiList.Update_1(region.basicInfo.pointArry, offsetroi, m_pEdge_Align_Result->offt_x, m_pEdge_Align_Result->offt_y, fx, fy);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
|
|
|
m_DetRoiList.Update_Marit(region.basicInfo.pointArry, offsetroi, m_pEdge_Align_Result->H, fx, fy);
|
|
|
}
|
|
|
|
|
|
// m_DetRoiList.Update_1(region.basicInfo.pointArry, offsetroi, m_pEdge_Align_Result->offt_x, m_pEdge_Align_Result->offt_y, fx, fy);
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
for (const auto ®ion : m_pCommonAnalysisyConfig->regionConfigArr)
|
|
|
{
|
|
|
m_DetRoiList.Update(region.basicInfo.pointArry, m_Crop_Roi_paramImg, fx, fy);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "info", "roiList_Src roi num %ld", m_DetRoiList.roiList_Src.size());
|
|
|
// m_DetRoiList.print("m_DetRoiList");
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::DrawResult_Step_1()
|
|
|
{
|
|
|
|
|
|
// std::cout << m_pBasicConfig->bDrawPreRoi << std::endl;
|
|
|
if (m_pBasicConfig->bDrawPreRoi)
|
|
|
{
|
|
|
int n = 0;
|
|
|
// std::cout << m_DetRoiList.roiList_Show.size() << std::endl;
|
|
|
for (const auto &polygon : m_DetRoiList.roiList_Show)
|
|
|
{
|
|
|
// n++;
|
|
|
// if (n == 1)
|
|
|
// {
|
|
|
// continue;
|
|
|
// }
|
|
|
|
|
|
// std::cout << polygon << std::endl;
|
|
|
|
|
|
// 绘制多边形的边界(不填充),使用绿色线条,线宽为2
|
|
|
cv::polylines(m_CheckResult_shareP->resultimg, polygon, true, cv::Scalar(128, 128, 255), 1); // true表示闭合多边形
|
|
|
}
|
|
|
// cv::imwrite(DetImgInfo_shareP->strChannel + "roi_src.png", m_pdetlog->temImgList[TEM_IMG_IDX_DrawSrc]);
|
|
|
// cv::imwrite(DetImgInfo_shareP->strChannel + "roi_ss.png", m_pdetlog->temImgList[TEM_IMG_IDX_Result]);
|
|
|
|
|
|
// getchar();
|
|
|
}
|
|
|
|
|
|
float fs_resize_x = m_pImageAllResult->resultImg.cols * 1.0f / m_pImageAllResult->detImg.cols;
|
|
|
float fs_resize_y = m_pImageAllResult->resultImg.rows * 1.0f / m_pImageAllResult->detImg.rows;
|
|
|
|
|
|
// 绘制模板 pin 轮廓(绿色)与当前 pin 轮廓(红色)
|
|
|
for (const auto &contour : m_tplPinContours)
|
|
|
{
|
|
|
std::vector<cv::Point> draw_pts;
|
|
|
draw_pts.reserve(contour.size());
|
|
|
for (const auto &pt : contour)
|
|
|
{
|
|
|
draw_pts.emplace_back(cvRound(pt.x * fs_resize_x), cvRound(pt.y * fs_resize_y));
|
|
|
}
|
|
|
cv::polylines(m_CheckResult_shareP->resultimg, draw_pts, true, cv::Scalar(255, 255, 0), 1);
|
|
|
}
|
|
|
for (const auto &contour : m_curPinContours)
|
|
|
{
|
|
|
std::vector<cv::Point> draw_pts;
|
|
|
draw_pts.reserve(contour.size());
|
|
|
for (const auto &pt : contour)
|
|
|
{
|
|
|
draw_pts.emplace_back(cvRound(pt.x * fs_resize_x), cvRound(pt.y * fs_resize_y));
|
|
|
}
|
|
|
cv::polylines(m_CheckResult_shareP->resultimg, draw_pts, true, cv::Scalar(255, 0, 255), 1);
|
|
|
}
|
|
|
|
|
|
// 绘制m_inner_rroi(蓝色)
|
|
|
{
|
|
|
cv::Point2f vertices[4];
|
|
|
m_inner_rroi.points(vertices);
|
|
|
std::vector<cv::Point> draw_pts;
|
|
|
draw_pts.reserve(4);
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
{
|
|
|
draw_pts.emplace_back(cvRound((vertices[i].x - m_Crop_Roi_paramImg.x) * fs_resize_x),
|
|
|
cvRound((vertices[i].y - m_Crop_Roi_paramImg.y) * fs_resize_y));
|
|
|
}
|
|
|
cv::polylines(m_CheckResult_shareP->resultimg, draw_pts, true, cv::Scalar(255, 0, 0), 1);
|
|
|
}
|
|
|
|
|
|
// cv::imwrite("sss.png", m_CheckResult_shareP->resultimg);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::AIClassTypeToConfigType(int nAIQXType)
|
|
|
{
|
|
|
|
|
|
int resultError_type = CONFIG_QX_NAME_cell_aotudian;
|
|
|
switch (nAIQXType)
|
|
|
{
|
|
|
case AI_CLass_QX_NAME_aotudian:
|
|
|
resultError_type = CONFIG_QX_NAME_cell_aotudian;
|
|
|
break;
|
|
|
case AI_CLass_QX_NAME_other:
|
|
|
resultError_type = CONFIG_QX_NAME_cell_other;
|
|
|
break;
|
|
|
case AI_CLass_QX_NAME_line:
|
|
|
resultError_type = CONFIG_QX_NAME_cell_line;
|
|
|
break;
|
|
|
case AI_CLass_QX_NAME_zangwu:
|
|
|
resultError_type = CONFIG_QX_NAME_cell_zangwu;
|
|
|
break;
|
|
|
case AI_CLass_QX_NAME_dianzhuang:
|
|
|
resultError_type = CONFIG_QX_NAME_cell_dianzhuang;
|
|
|
break;
|
|
|
case AI_CLass_QX_NAME_posun:
|
|
|
resultError_type = CONFIG_QX_NAME_cell_posun;
|
|
|
break;
|
|
|
case AI_CLass_QX_NAME_xianwei:
|
|
|
resultError_type = CONFIG_QX_NAME_cell_xianwei;
|
|
|
break;
|
|
|
case AI_CLass_QX_NAME_shuizi:
|
|
|
resultError_type = CONFIG_QX_NAME_cell_shuizi;
|
|
|
break;
|
|
|
case AI_CLass_QX_NAME_danban:
|
|
|
resultError_type = CONFIG_QX_NAME_cell_danban;
|
|
|
break;
|
|
|
case AI_CLass_QX_NAME_fuchen:
|
|
|
resultError_type = CONFIG_QX_NAME_cell_fuchen;
|
|
|
break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
return resultError_type;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::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 ImgCheckAnalysisy::Pin_Qx_Det(const cv::Mat &img)
|
|
|
{
|
|
|
|
|
|
m_Edge_DetConfig.Init();
|
|
|
m_Edge_DetConfig.strChannel = m_strCurDetChannel;
|
|
|
m_Edge_DetConfig.pBaseCheckFunction = m_pbaseCheckFunction;
|
|
|
|
|
|
m_Edge_DetConfig.bSaveResultImg = false;
|
|
|
if (DetImgInfo_shareP->bsaveProcessImg)
|
|
|
{
|
|
|
m_Edge_DetConfig.bSaveResultImg = true;
|
|
|
}
|
|
|
// m_pbaseCheckFunction->print("Pin_Qx_Det");
|
|
|
Mat pin_mask;
|
|
|
int re = m_Pin_QX_Det.GetPinMask(img, &m_Edge_DetConfig, pin_mask);
|
|
|
|
|
|
// 统计tplPinMask的blob边缘点,并绘制到tplImg上
|
|
|
vector<vector<Point>> pin_contours;
|
|
|
vector<Vec4i> hierarchy;
|
|
|
cv::findContours(pin_mask, pin_contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
|
|
|
//缩放比例
|
|
|
const float pin_scale_x = (pin_mask.cols > 0) ? static_cast<float>(img.cols) / pin_mask.cols : 0.0f;
|
|
|
const float pin_scale_y = (pin_mask.rows > 0) ? static_cast<float>(img.rows) / pin_mask.rows : 0.0f;
|
|
|
// 将轮廓点从 mask 坐标系 映射回 tplImg 坐标系
|
|
|
m_curPinContours.clear();
|
|
|
m_curPinContours.reserve(pin_contours.size());
|
|
|
for (size_t i = 0; i < pin_contours.size(); i++)
|
|
|
{
|
|
|
std::vector<cv::Point> mapped;
|
|
|
mapped.reserve(pin_contours[i].size());
|
|
|
for (const auto &pt : pin_contours[i])
|
|
|
{
|
|
|
mapped.emplace_back(cvRound(pt.x * pin_scale_x),
|
|
|
cvRound(pt.y * pin_scale_y));
|
|
|
}
|
|
|
m_curPinContours.push_back(mapped);
|
|
|
}
|
|
|
|
|
|
// 根据模板Pin和当前Pin轮廓进行对比,判断当前有无缺失和偏移
|
|
|
{
|
|
|
// 计算轮廓中心点(外接矩形中心)
|
|
|
auto getCenter = [](const std::vector<cv::Point> &contour) -> cv::Point2f
|
|
|
{
|
|
|
cv::Rect r = cv::boundingRect(contour);
|
|
|
return cv::Point2f(r.x + r.width * 0.5f, r.y + r.height * 0.5f);
|
|
|
};
|
|
|
|
|
|
const int nTpl = static_cast<int>(m_tplPinContours.size());
|
|
|
const int nCur = static_cast<int>(m_curPinContours.size());
|
|
|
|
|
|
if (nTpl > 0)
|
|
|
{
|
|
|
// 1、统计模板 pin 中心与平均最小边长,用于自适应阈值
|
|
|
std::vector<cv::Point2f> tplCenters(nTpl);
|
|
|
double sumMinDim = 0.0;
|
|
|
for (int i = 0; i < nTpl; i++)
|
|
|
{
|
|
|
tplCenters[i] = getCenter(m_tplPinContours[i]);
|
|
|
cv::Rect r = cv::boundingRect(m_tplPinContours[i]);
|
|
|
sumMinDim += (r.width < r.height) ? r.width : r.height;
|
|
|
}
|
|
|
const float avgMinDim = static_cast<float>(sumMinDim / nTpl);
|
|
|
|
|
|
// 偏移阈值约 1/4 个 pin 尺寸,缺失阈值约 3/4 个 pin 尺寸
|
|
|
float offsetTh = avgMinDim * 0.5f;
|
|
|
if (offsetTh < 3.0f)
|
|
|
{
|
|
|
offsetTh = 3.0f;
|
|
|
}
|
|
|
float missTh = avgMinDim * 0.75f;
|
|
|
if (missTh < offsetTh + 1.0f)
|
|
|
{
|
|
|
missTh = offsetTh + 1.0f;
|
|
|
}
|
|
|
|
|
|
// 2、当前 pin 中心
|
|
|
std::vector<cv::Point2f> curCenters(nCur);
|
|
|
for (int i = 0; i < nCur; i++)
|
|
|
{
|
|
|
curCenters[i] = getCenter(m_curPinContours[i]);
|
|
|
}
|
|
|
std::vector<bool> curUsed(nCur, false);
|
|
|
|
|
|
// 上报缺失/偏移缺陷(缺陷类型可按需调整)
|
|
|
auto reportPinError = [&](int pinIdx, const cv::Point2f &tplCenter, const std::string &reason)
|
|
|
{
|
|
|
QX_ERROR_INFO_ pinErr;
|
|
|
pinErr.Idx = static_cast<int>(m_pDetResult->pQx_ErrorList->size());
|
|
|
cv::Rect r = cv::boundingRect(m_tplPinContours[pinIdx]);
|
|
|
pinErr.roi = r;
|
|
|
pinErr.area = static_cast<int>(cv::contourArea(m_tplPinContours[pinIdx]));
|
|
|
pinErr.JudgArea = pinErr.area * m_fImgage_Scale_X * m_fImgage_Scale_Y;
|
|
|
int longSide = (r.width > r.height) ? r.width : r.height;
|
|
|
int shortSide = (r.width < r.height) ? r.width : r.height;
|
|
|
pinErr.flen = longSide * m_fImgage_Scale_X;
|
|
|
pinErr.fbreadth = shortSide * m_fImgage_Scale_Y;
|
|
|
pinErr.nconfig_qx_type = CONFIG_QX_NAME_cell_ymhs;
|
|
|
pinErr.qx_name = CONFIG_QX_NAME_Names[CONFIG_QX_NAME_cell_ymhs];
|
|
|
pinErr.detRegionidxList.push_back(0);
|
|
|
pinErr.detlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Pin Check",
|
|
|
"pin %d center(%d,%d) %s",
|
|
|
pinIdx, static_cast<int>(tplCenter.x), static_cast<int>(tplCenter.y),
|
|
|
reason.c_str());
|
|
|
m_pDetResult->pQx_ErrorList->push_back(pinErr);
|
|
|
};
|
|
|
|
|
|
int nMiss = 0;
|
|
|
int nOffset = 0;
|
|
|
|
|
|
// 3、逐个模板 pin 找最近且未被占用的当前 pin
|
|
|
for (int i = 0; i < nTpl; i++)
|
|
|
{
|
|
|
int bestIdx = -1;
|
|
|
double bestDist = 1e12;
|
|
|
for (int j = 0; j < nCur; j++)
|
|
|
{
|
|
|
if (curUsed[j])
|
|
|
{
|
|
|
continue;
|
|
|
}
|
|
|
float dx = tplCenters[i].x - curCenters[j].x;
|
|
|
float dy = tplCenters[i].y - curCenters[j].y;
|
|
|
double d = std::sqrt(static_cast<double>(dx) * dx + static_cast<double>(dy) * dy);
|
|
|
if (d < bestDist)
|
|
|
{
|
|
|
bestDist = d;
|
|
|
bestIdx = j;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 无候选或距离过远 -> 缺失
|
|
|
if (bestIdx < 0 || bestDist > missTh)
|
|
|
{
|
|
|
nMiss++;
|
|
|
reportPinError(i, tplCenters[i], "miss");
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Pin Check", "pin %d MISS", i);
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
curUsed[bestIdx] = true;
|
|
|
|
|
|
// 距离超出偏移阈值 -> 偏移
|
|
|
if (bestDist > offsetTh)
|
|
|
{
|
|
|
nOffset++;
|
|
|
char buf[64];
|
|
|
snprintf(buf, sizeof(buf), "offset %.1fpx", bestDist);
|
|
|
reportPinError(i, tplCenters[i], buf);
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Pin Check", "pin %d OFFSET %.1fpx", i, bestDist);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "Pin Check", "tpl %d cur %d miss %d offset %d", nTpl, nCur, nMiss, nOffset);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (m_Edge_DetConfig.bSaveResultImg)
|
|
|
{
|
|
|
Mat showimg;
|
|
|
cv::cvtColor(img, showimg, cv::COLOR_GRAY2BGR);
|
|
|
cv::drawContours(showimg, m_curPinContours, -1, cv::Scalar(0, 0, 255), 1);
|
|
|
cv::drawContours(showimg, m_tplPinContours, -1, cv::Scalar(0, 255, 0), 1);
|
|
|
imwrite("pin_contours.png", showimg);
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::BLobToDetResult()
|
|
|
{
|
|
|
long t1 = CheckUtil::getcurTime();
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "BLobToDetResult", " Start old qx num %ld", m_pDetResult->pQx_ErrorList->size());
|
|
|
|
|
|
// 遍历每个检测blob
|
|
|
for (int i = 0; i < blobs.blobCount; i++)
|
|
|
{
|
|
|
cv::Rect roi;
|
|
|
roi.x = blobs.blobTab[i].minx;
|
|
|
roi.y = blobs.blobTab[i].miny;
|
|
|
roi.width = blobs.blobTab[i].maxx - blobs.blobTab[i].minx + 1;
|
|
|
roi.height = blobs.blobTab[i].maxy - blobs.blobTab[i].miny + 1;
|
|
|
|
|
|
int config_qx_type = blobs.blobTab[i].AIclasstype;
|
|
|
|
|
|
float JudgArea = blobs.blobTab[i].JudgArea;
|
|
|
float fsecondArea = JudgArea;
|
|
|
std::string qx_name = CONFIG_QX_NAME_Names[config_qx_type];
|
|
|
|
|
|
if (true)
|
|
|
{
|
|
|
QX_ERROR_INFO_ temerror;
|
|
|
temerror.roi = roi;
|
|
|
temerror.Idx = m_pDetResult->pQx_ErrorList->size();
|
|
|
temerror.area = blobs.blobTab[i].area;
|
|
|
temerror.JudgArea = JudgArea;
|
|
|
temerror.JudgArea_second = fsecondArea;
|
|
|
temerror.energy = blobs.blobTab[i].energy;
|
|
|
temerror.flen = blobs.blobTab[i].len;
|
|
|
temerror.fbreadth = blobs.blobTab[i].breadth;
|
|
|
temerror.nconfig_qx_type = config_qx_type;
|
|
|
temerror.qx_name = qx_name;
|
|
|
temerror.maxValue = blobs.blobTab[i].maxValue;
|
|
|
temerror.grayDis = blobs.blobTab[i].grayDis;
|
|
|
temerror.density = blobs.blobTab[i].density;
|
|
|
temerror.fUpIou = 0;
|
|
|
temerror.whiteOrBlack = blobs.blobTab[i].whiteOrblack;
|
|
|
|
|
|
{
|
|
|
cv::Point pCenter;
|
|
|
pCenter.x = roi.x + roi.width * 0.5;
|
|
|
pCenter.y = roi.y + roi.height * 0.5;
|
|
|
int nmaxregionIdx = 0;
|
|
|
for (int iregion = 0; iregion < m_DetRoiList.roiList_Src.size(); iregion++)
|
|
|
{
|
|
|
const std::vector<cv::Point> &polygon = m_DetRoiList.roiList_Src[iregion];
|
|
|
double result = cv::pointPolygonTest(polygon, pCenter, false);
|
|
|
if (result < 0)
|
|
|
{
|
|
|
continue;
|
|
|
}
|
|
|
nmaxregionIdx = iregion;
|
|
|
}
|
|
|
|
|
|
temerror.detRegionidxList.push_back(nmaxregionIdx);
|
|
|
}
|
|
|
|
|
|
// {
|
|
|
// cv::Point pCenter;
|
|
|
// pCenter.x = roi.x + roi.width * 0.5;
|
|
|
// pCenter.y = roi.y + roi.height * 0.5;
|
|
|
// for (int iregion = 0; iregion < m_DetRoiList.roiList_Src.size(); iregion++)
|
|
|
// {
|
|
|
// const std::vector<cv::Point> &polygon = m_DetRoiList.roiList_Src[iregion];
|
|
|
// double result = cv::pointPolygonTest(polygon, pCenter, false);
|
|
|
// if (result < 0)
|
|
|
// {
|
|
|
// continue;
|
|
|
// }
|
|
|
// temerror.detRegionidxList.push_back(iregion);
|
|
|
// }
|
|
|
// if (temerror.detRegionidxList.size() <= 0)
|
|
|
// {
|
|
|
// temerror.detRegionidxList.push_back(0);
|
|
|
// }
|
|
|
// }
|
|
|
|
|
|
m_pDetResult->pQx_ErrorList->push_back(temerror);
|
|
|
|
|
|
// 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);
|
|
|
}
|
|
|
}
|
|
|
long t2 = CheckUtil::getcurTime();
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "BLobToDetResult", " end qx num %ld use time %ld", m_pDetResult->pQx_ErrorList->size(), t2 - t1);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::AI_Edge(const cv::Mat &img, cv::RotatedRect &outerRoi, cv::RotatedRect &innerRoi)
|
|
|
{
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_0, "AI_Edge", "-------------------start--------------");
|
|
|
|
|
|
AI_Edge_Algin::DetConfig config;
|
|
|
|
|
|
if (DetImgInfo_shareP->bsaveProcessImg)
|
|
|
{
|
|
|
config.bSaveResultImg = true;
|
|
|
}
|
|
|
config.strChannel = DetImgInfo_shareP->strChannel;
|
|
|
config.pBaseCheckFunction = m_pbaseCheckFunction;
|
|
|
int re = m_pAI_Edge_Algin.Detect(img, &config, m_pEdge_Align_Result);
|
|
|
if (re != 0)
|
|
|
{
|
|
|
printf("AI_Edge Is Error = %d \n", re);
|
|
|
}
|
|
|
outerRoi = m_pEdge_Align_Result->bigroi;
|
|
|
innerRoi = m_pEdge_Align_Result->smallroi;
|
|
|
// getchar();
|
|
|
return re;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::CalProductSize()
|
|
|
{
|
|
|
float fw = m_outer_roi.width * m_fImgage_Scale_X;
|
|
|
float fh = m_outer_roi.height * m_fImgage_Scale_Y;
|
|
|
fw = std::ceil(fw * 10) / 10;
|
|
|
fh = std::ceil(fh * 10) / 10;
|
|
|
m_CheckResult_shareP->productWidht_mm = fw;
|
|
|
m_CheckResult_shareP->productHeight_mm = fh;
|
|
|
|
|
|
m_pdetlog->AddCheckstr(PrintLevel_1, "Det ROI", " [w %d,h %d] (piexl) -> [w %f h %f](mm),scale %f %f",
|
|
|
m_outer_roi.width, m_outer_roi.height, fw, fh, m_fImgage_Scale_X, m_fImgage_Scale_Y);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int ImgCheckAnalysisy::ImgPreDet()
|
|
|
{
|
|
|
|
|
|
// 计算产品尺寸
|
|
|
CalProductSize();
|
|
|
|
|
|
if (m_pbaseCheckFunction->saveImg.bSaveClsImg)
|
|
|
{
|
|
|
creatsavedir();
|
|
|
}
|
|
|
|
|
|
m_CheckResult_shareP->cutSrcimg = m_pImageAllResult->detImg;
|
|
|
ResizeImg();
|
|
|
|
|
|
m_pImageAllResult->fscale_detToresult_x = m_pImageAllResult->resultImg.cols * 1.0f / m_pImageAllResult->detImg.cols;
|
|
|
m_pImageAllResult->fscale_detToresult_y = m_pImageAllResult->resultImg.rows * 1.0f / m_pImageAllResult->detImg.rows;
|
|
|
return 0;
|
|
|
}
|