/* * @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 #include "AICommonDefine.h" // 用于排序轮廓的比较函数 static bool compareContourAreas(const vector &contour1, const vector &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(); 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 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 &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 p, std::shared_ptr &pResult) { return 0; } int ImgCheckAnalysisy::ReJsonResul(std::shared_ptr p, std::shared_ptr &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> &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::bind(&ImgCheckAnalysisy::Run, this, nId)); if (!m_RunConfig.bRetest) { ptr_thread_AI = std::make_shared(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 cur_vertices = CheckUtil::sort_vertices(curOuterRect); vector 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(0); cv::Point2f pts[4]; rrect.points(pts); std::vector transformed_pts(4); for (int i = 0; i < 4; i++) { float x = static_cast(M[0] * pts[i].x + M[1] * pts[i].y + M[2]); float y = static_cast(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(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(); 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 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 &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 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 ImgCheckAnalysisy::Cal_QXLen(cv::Mat qx_maskImg, int qx_type, float fsc_x, float fsc_y) { vector resLen(3); float nlen = -1; cv::Mat detimg = qx_maskImg; resLen[0] = nlen; // 寻找轮廓 vector> 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 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> 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(); 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 AImaskResult; { std::lock_guard 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> contours; // std::vector 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>(); 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> 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 pAIDet = pAIDetList[m]; int submitted = 0; int completed = 0; while (completed < totalTasks) { // 如果任务还没提交完,且当前处理任务数 < 10,提交新任务 if (submitted < totalTasks && runner->GetProcessingCount() < 10) { std::shared_ptr task = std::make_shared(); task->id = submitted; task->roi = SmallRoiList.at(submitted); task->input = img(SmallRoiList.at(submitted)).clone(); task->output = std::make_shared(); task->engine = pAIDet; runner->SubmitTask(task); submitted++; } // 尝试取结果 std::shared_ptr result; if (runner->PopResult(result)) { { std::lock_guard 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 temAIresult = std::make_shared(); 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 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 task = std::make_shared(); 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 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 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 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 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 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 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 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> pin_contours; vector 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(img.cols) / pin_mask.cols : 0.0f; const float pin_scale_y = (pin_mask.rows > 0) ? static_cast(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 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 &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(m_tplPinContours.size()); const int nCur = static_cast(m_curPinContours.size()); if (nTpl > 0) { // 1、统计模板 pin 中心与平均最小边长,用于自适应阈值 std::vector 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(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 curCenters(nCur); for (int i = 0; i < nCur; i++) { curCenters[i] = getCenter(m_curPinContours[i]); } std::vector curUsed(nCur, false); // 上报缺失/偏移缺陷(缺陷类型可按需调整) auto reportPinError = [&](int pinIdx, const cv::Point2f &tplCenter, const std::string &reason) { QX_ERROR_INFO_ pinErr; pinErr.Idx = static_cast(m_pDetResult->pQx_ErrorList->size()); cv::Rect r = cv::boundingRect(m_tplPinContours[pinIdx]); pinErr.roi = r; pinErr.area = static_cast(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(tplCenter.x), static_cast(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(dx) * dx + static_cast(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 &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 &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; }