/* * @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_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.1.0"); } 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; } 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在图像内 roi &= cv::Rect(0, 0, mask.cols, mask.rows); // 确保ROI在mask内 // 检查 mask 是否有效 if (mask.empty() || roi.width <= 0 || roi.height <= 0) { return cv::Scalar(0, 0, 0); } 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); } Point2f GetCoorPoint(Point2f point, Mat img_mat) { // 越界判定 int coor_img_rect_x = point.x-400; int coor_img_rect_y = point.y-400; int coor_img_rect_w = 800; int coor_img_rect_h = 800; if (coor_img_rect_x < 0) { coor_img_rect_x = 0; coor_img_rect_w = min(400, img_mat.cols); } if (coor_img_rect_y < 0) { coor_img_rect_y = 0; coor_img_rect_h = min(400, img_mat.rows); } if (coor_img_rect_x + coor_img_rect_w > img_mat.cols) { coor_img_rect_w = img_mat.cols - coor_img_rect_x; } if (coor_img_rect_y + coor_img_rect_h > img_mat.rows) { coor_img_rect_h = img_mat.rows - coor_img_rect_y; } if (coor_img_rect_x < 0 || coor_img_rect_y < 0 || coor_img_rect_x + coor_img_rect_w > img_mat.cols || coor_img_rect_y + coor_img_rect_h > img_mat.rows) { return point; } Mat coor_img_mat = img_mat(Rect(coor_img_rect_x, coor_img_rect_y, coor_img_rect_w, coor_img_rect_h)); Mat coor_img_bin; threshold(coor_img_mat, coor_img_bin, 50, 255, THRESH_BINARY); // 6. 查找轮廓 std::vector> contours; cv::findContours(coor_img_bin, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); if (contours.empty()) { return point; } double maxArea = 0; int maxAreaIdx = -1; for (size_t i = 0; i < contours.size(); ++i) { double area = cv::contourArea(contours[i]); if (area > maxArea) { maxArea = area; maxAreaIdx = i; } } if (maxAreaIdx < 0 || maxArea < 100) { return point; } cv::RotatedRect rect = cv::minAreaRect(contours[maxAreaIdx]); Point2f vertices[4]; rect.points(vertices); int cornerIdx = 0; float minDist = FLT_MAX; for (int i = 0; i < 4; i++) { float dist = std::pow(vertices[i].x - 400, 2) + std::pow(vertices[i].y - 400, 2); if (dist < minDist) { minDist = dist; cornerIdx = i; } } Point2f new_point; new_point.x = vertices[cornerIdx].x + coor_img_rect_x; new_point.y = vertices[cornerIdx].y + coor_img_rect_y; new_point.x = std::max(0.0f, std::min(new_point.x, static_cast(img_mat.cols - 1))); new_point.y = std::max(0.0f, std::min(new_point.y, static_cast(img_mat.rows - 1))); return new_point; } int GetEdgeRoi(Mat img, Rect &new_roi, cv::RotatedRect &rotated_roi, float scale_x, float scale_y){ if (img.empty()) { return 1; } // ============ Stage 1: 粗定位(大尺度缩小,速度快)============ Mat r_img; int resize_width = static_cast(img.cols / scale_x); int resize_height = static_cast(img.rows / scale_y); resize(img, r_img, Size(resize_width, resize_height), 0, 0, INTER_LINEAR); // 二值化找最大连通域 Mat r_img_bin; threshold(r_img, r_img_bin, 15, 255, THRESH_BINARY); std::vector> contours; cv::findContours(r_img_bin, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); if (contours.empty()) { return 2; } double maxArea = 0; int maxAreaIdx = -1; for (size_t i = 0; i < contours.size(); ++i) { double area = cv::contourArea(contours[i]); if (area > maxArea) { maxArea = area; maxAreaIdx = i; } } if (maxAreaIdx < 0) { return 3; } // 使用minAreaRect获取带旋转角度的最小外接矩形 cv::RotatedRect coarse_rotated_tmp = cv::minAreaRect(contours[maxAreaIdx]); cv::RotatedRect coarse_rotated; coarse_rotated.center.x = coarse_rotated_tmp.center.x * scale_x; coarse_rotated.center.y = coarse_rotated_tmp.center.y * scale_y; coarse_rotated.size.width = coarse_rotated_tmp.size.width * scale_x; coarse_rotated.size.height = coarse_rotated_tmp.size.height * scale_y; coarse_rotated.angle = coarse_rotated_tmp.angle; cv::Rect coarse_roi = coarse_rotated.boundingRect(); coarse_roi.x = std::max(0, coarse_roi.x); coarse_roi.y = std::max(0, coarse_roi.y); coarse_roi.width = std::min(coarse_roi.width, img.cols - coarse_roi.x); coarse_roi.height = std::min(coarse_roi.height, img.rows - coarse_roi.y); // ============ Stage 2: 精修(小尺度,只处理裁剪后的局部区域)============ // 粗定位精度损失约 scale_x/scale_y 个像素,扩展 margin 确保包含真实边界 const float fine_scale = 4.0f; // 精修阶段缩放倍率,越小越精确 int margin_x = static_cast(scale_x * 2); // 补偿粗定位误差 int margin_y = static_cast(scale_y * 2); Rect fine_roi; fine_roi.x = std::max(0, coarse_roi.x - margin_x); fine_roi.y = std::max(0, coarse_roi.y - margin_y); fine_roi.width = std::min(coarse_roi.width + 2 * margin_x, img.cols - fine_roi.x); fine_roi.height = std::min(coarse_roi.height + 2 * margin_y, img.rows - fine_roi.y); Mat fine_region = img(fine_roi); int fine_w = static_cast(fine_region.cols / fine_scale); int fine_h = static_cast(fine_region.rows / fine_scale); // 精修区域足够大时才做细化 if (fine_w > 50 && fine_h > 50) { Mat fine_resized; resize(fine_region, fine_resized, Size(fine_w, fine_h), 0, 0, INTER_LINEAR); Mat fine_bin; threshold(fine_resized, fine_bin, 15, 255, THRESH_BINARY); std::vector> fine_contours; cv::findContours(fine_bin, fine_contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); if (!fine_contours.empty()) { double fine_maxArea = 0; int fine_maxIdx = -1; for (size_t i = 0; i < fine_contours.size(); ++i) { double area = cv::contourArea(fine_contours[i]); if (area > fine_maxArea) { fine_maxArea = area; fine_maxIdx = i; } } if (fine_maxIdx >= 0) { // 使用minAreaRect获取带旋转角度的最小外接矩形(保留旋转信息) cv::RotatedRect fine_rotated = cv::minAreaRect(fine_contours[fine_maxIdx]); // 映射回原图坐标:center缩放+平移,size按比例缩放,角度不变 rotated_roi.center.x = fine_rotated.center.x * fine_scale + fine_roi.x; rotated_roi.center.y = fine_rotated.center.y * fine_scale + fine_roi.y; rotated_roi.size.width = fine_rotated.size.width * fine_scale; rotated_roi.size.height = fine_rotated.size.height * fine_scale; rotated_roi.angle = fine_rotated.angle; // 取旋转矩形的轴对齐外接框作为new_roi(用于ROI裁剪等场景) cv::Rect fine_small = rotated_roi.boundingRect(); Rect refined_roi; refined_roi.x = fine_small.x; refined_roi.y = fine_small.y; refined_roi.width = fine_small.width; refined_roi.height = fine_small.height; refined_roi.x = std::max(0, refined_roi.x); refined_roi.y = std::max(0, refined_roi.y); refined_roi.width = std::min(refined_roi.width, img.cols - refined_roi.x); refined_roi.height = std::min(refined_roi.height, img.rows - refined_roi.y); new_roi = refined_roi; return 0; } } } // 精修失败则回退到粗定位结果 new_roi = coarse_roi; rotated_roi = coarse_rotated; return 0; } std::vector sort_vertices(cv::RotatedRect rrect) { cv::Point2f pts[4]; rrect.points(pts); std::vector vertices(pts, pts + 4); // 按 y 坐标升序排序 std::sort(vertices.begin(), vertices.end(), [](const cv::Point2f& a, const cv::Point2f& b) { return a.y < b.y; }); if (vertices[0].x > vertices[1].x) std::swap(vertices[0], vertices[1]); if (vertices[2].x > vertices[3].x) std::swap(vertices[2], vertices[3]); return vertices; } int ImgCheckAnalysisy::Adapt_Config(Mat img, Rect cur_roi, bool b_update){ if (img.empty()) { std::cerr << "Error: Input image 'img' is empty!" << std::endl; return -1; } if(!b_update){ return 1; } cv::RotatedRect rot_cur_roi; int get_edge_roi = GetEdgeRoi(img, cur_roi, rot_cur_roi, 20, 20); if(get_edge_roi != 0){ return 2; } m_pdetlog->AddCheckstr(PrintLevel_0, "Adapt_Config", "-------------------start--------------"); /*计算xy偏移,缩放比例*/ // 拷贝原始数据(old_productROI 使用 markLine.region 的 minAreaRect,保留旋转角度) if(m_old_productROI.size.width == 0 || m_old_productROI.size.height == 0){ m_old_productROI = cv::minAreaRect(m_AnalysisyConfig.baseFunction.markLine.region); m_old_cur_edgeDet_region = m_AnalysisyConfig.baseFunction.edgeDet.region; m_old_cur_markLine_region = m_AnalysisyConfig.baseFunction.markLine.region; m_old_cur_markLine_mark1 = m_AnalysisyConfig.baseFunction.markLine.mark_local_1; m_old_cur_markLine_mark2 = m_AnalysisyConfig.baseFunction.markLine.mark_local_2; m_old_cur_regionConfigArr = m_AnalysisyConfig.commonCheckConfig.nodeConfigArr[0].regionConfigArr; m_old_cur_traditional_region = m_AnalysisyConfig.baseFunction.traditionDet.detArea; } /*计算old_roi到new_roi的完整仿射变换矩阵(平移+缩放+旋转)*/ // old使用 minAreaRect(region) 的顶点,new使用 GetEdgeRoi 检测到的旋转矩形顶点 vector old_vertices = sort_vertices(m_old_productROI); vector new_vertices = sort_vertices(rot_cur_roi); cv::Point2f src_pts[3] = { old_vertices[0], // 左上 old_vertices[1], // 右上 old_vertices[2] // 左下 }; cv::Point2f dst_pts[3] = { new_vertices[0], // 对应左上 new_vertices[1], // 对应右上 new_vertices[2] // 对应左下 }; cv::Mat affine_mat = cv::getAffineTransform(src_pts, dst_pts); m_pdetlog->AddCheckstr(PrintLevel_0, "Adapt_Config", "affine_mat = [%f %f %f; %f %f %f]", affine_mat.at(0,0), affine_mat.at(0,1), affine_mat.at(0,2), affine_mat.at(1,0), affine_mat.at(1,1), affine_mat.at(1,2)); // 单点仿射变换的lambda (直接使用矩阵,涵盖平移+缩放+旋转) auto affinePoint = [&](const cv::Point& p) -> cv::Point { return cv::Point( cvRound(affine_mat.at(0,0) * p.x + affine_mat.at(0,1) * p.y + affine_mat.at(0,2)), cvRound(affine_mat.at(1,0) * p.x + affine_mat.at(1,1) * p.y + affine_mat.at(1,2)) ); }; /*获取待修改的region引用*/ std::vector& cur_edgeDet_region = m_AnalysisyConfig.baseFunction.edgeDet.region; std::vector& cur_markLine_region = m_AnalysisyConfig.baseFunction.markLine.region; cv::Point& cur_markLine_mark1 = m_AnalysisyConfig.baseFunction.markLine.mark_local_1; cv::Point& cur_markLine_mark2 = m_AnalysisyConfig.baseFunction.markLine.mark_local_2; std::vector& cur_regionConfigArr = m_AnalysisyConfig.commonCheckConfig.nodeConfigArr[0].regionConfigArr; std::vector& cur_traditional_region = m_AnalysisyConfig.baseFunction.traditionDet.detArea; // if (img.empty()) // { // return 0; // } // Mat show_img = img.clone(); // cvtColor(show_img, show_img, COLOR_GRAY2BGR); // // 确保 productROI 在图像范围内 // cv::Rect safe_roi = m_AnalysisyConfig.baseFunction.markLine.productROI; // safe_roi &= cv::Rect(0, 0, show_img.cols, show_img.rows); // if (safe_roi.width > 0 && safe_roi.height > 0) // { // cv::rectangle(show_img, safe_roi, Scalar(255,255,255), 5); // } // if (cur_edgeDet_region.size() >= 2) // { // for(size_t i = 0 ; i < cur_edgeDet_region.size() - 1; i++){ // cv::line(show_img, cur_edgeDet_region[i], cur_edgeDet_region[i+1], Scalar(0,255,0), 20); // } // cv::line(show_img, cur_edgeDet_region.back(), cur_edgeDet_region.front(), Scalar(0,255,0), 20); // } // if (cur_markLine_region.size() >= 2) // { // for(size_t i = 0 ; i < cur_markLine_region.size() - 1; i++){ // cv::line(show_img, cur_markLine_region[i], cur_markLine_region[i+1], Scalar(0,0,255), 20); // } // cv::line(show_img, cur_markLine_region.back(), cur_markLine_region.front(), Scalar(0,0,255), 20); // } // for(size_t i = 0 ; i < cur_regionConfigArr.size(); i++){ // if (cur_regionConfigArr[i].basicInfo.pointArry.size() >= 2) // { // for(size_t j = 0; j < cur_regionConfigArr[i].basicInfo.pointArry.size() - 1; j++){ // cv::line(show_img, cur_regionConfigArr[i].basicInfo.pointArry[j], cur_regionConfigArr[i].basicInfo.pointArry[j+1], Scalar(255,0,0), 10); // } // cv::line(show_img, cur_regionConfigArr[i].basicInfo.pointArry.back(), cur_regionConfigArr[i].basicInfo.pointArry.front(), Scalar(255,0,0), 10); // } // } // imwrite(m_AnalysisyConfig.commonCheckConfig.baseConfig.strCamearName +"_org_img.tiff", show_img); /*使用仿射矩阵进行修改*/ // rect m_AnalysisyConfig.baseFunction.markLine.productROI = cur_roi; // point cur_markLine_mark1 = affinePoint(m_old_cur_markLine_mark1); cur_markLine_mark2 = affinePoint(m_old_cur_markLine_mark2); // region for(int i = 0; i < cur_edgeDet_region.size(); i++){ cur_edgeDet_region[i] = affinePoint(m_old_cur_edgeDet_region[i]); } for(int i = 0; i < cur_markLine_region.size(); i++){ cur_markLine_region[i] = affinePoint(m_old_cur_markLine_region[i]); } for(int i = 0 ; i < cur_regionConfigArr.size(); i++){ for(int j = 0; j < cur_regionConfigArr[i].basicInfo.pointArry.size(); j++){ cur_regionConfigArr[i].basicInfo.pointArry[j] = affinePoint(m_old_cur_regionConfigArr[i].basicInfo.pointArry[j]); } } for(int i = 0; i < cur_traditional_region.size(); i++){ cur_traditional_region[i] = affinePoint(m_old_cur_traditional_region[i]); } /*show*/ // if (img.empty()) // { // return 0; // } // show_img = img.clone(); // cvtColor(show_img, show_img, COLOR_GRAY2BGR); // // 确保 productROI 在图像范围内 // safe_roi = m_AnalysisyConfig.baseFunction.markLine.productROI; // safe_roi &= cv::Rect(0, 0, show_img.cols, show_img.rows); // if (safe_roi.width > 0 && safe_roi.height > 0) // { // cv::rectangle(show_img, safe_roi, Scalar(255,255,255), 5); // } // if (cur_edgeDet_region.size() >= 2) // { // for(size_t i = 0 ; i < cur_edgeDet_region.size() - 1; i++){ // cv::line(show_img, cur_edgeDet_region[i], cur_edgeDet_region[i+1], Scalar(0,255,0), 20); // } // cv::line(show_img, cur_edgeDet_region.back(), cur_edgeDet_region.front(), Scalar(0,255,0), 20); // } // if (cur_markLine_region.size() >= 2) // { // for(size_t i = 0 ; i < cur_markLine_region.size() - 1; i++){ // cv::line(show_img, cur_markLine_region[i], cur_markLine_region[i+1], Scalar(0,0,255), 20); // } // cv::line(show_img, cur_markLine_region.back(), cur_markLine_region.front(), Scalar(0,0,255), 20); // } // for(size_t i = 0 ; i < cur_regionConfigArr.size(); i++){ // if (cur_regionConfigArr[i].basicInfo.pointArry.size() >= 2) // { // for(size_t j = 0; j < cur_regionConfigArr[i].basicInfo.pointArry.size() - 1; j++){ // cv::line(show_img, cur_regionConfigArr[i].basicInfo.pointArry[j], cur_regionConfigArr[i].basicInfo.pointArry[j+1], Scalar(255,0,0), 10); // } // cv::line(show_img, cur_regionConfigArr[i].basicInfo.pointArry.back(), cur_regionConfigArr[i].basicInfo.pointArry.front(), Scalar(255,0,0), 10); // } // } // imwrite(m_AnalysisyConfig.commonCheckConfig.baseConfig.strCamearName +"_show_img.tiff", show_img); 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; /*自适应更新参数*/ long time_adapt_s = CheckUtil::getcurTime(); cv::RotatedRect rot_cur_roi; Adapt_Config(m_CheckResult_shareP->in_shareImage->img, m_CutRoi, m_pbaseCheckFunction->markLine.badapt_region); long time_adapt_e = CheckUtil::getcurTime(); m_pdetlog->AddCheckstr(PrintLevel_0, "Adapt_Config", "time = %ld", time_adapt_e - time_adapt_s); // 2、参数检查 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(); // 3、AI 边缘定位 if(m_CheckResult_shareP->basicResult.strChannel == "DCA" || m_CheckResult_shareP->basicResult.strChannel == "DTA") { m_pdetlog->AddCheckstr(PrintLevel_0, "Edge", "Not Use AI_Edge %s", m_CheckResult_shareP->basicResult.strChannel.c_str()); m_CutRoi = cv::Rect(rot_cur_roi.boundingRect().x - 50 , rot_cur_roi.boundingRect().y - 50, rot_cur_roi.boundingRect().width + 100, rot_cur_roi.boundingRect().height + 100) & cv::Rect(0, 0, m_CheckResult_shareP->in_shareImage->img.cols, m_CheckResult_shareP->in_shareImage->img.rows); } else { m_pdetlog->AddCheckstr(PrintLevel_0, "Edge", "Use AI_Edge %s", m_CheckResult_shareP->basicResult.strChannel.c_str()); int reedge = AI_Edge(m_CheckResult_shareP->in_shareImage->img, m_CutRoi); 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); m_Crop_Roi_paramImg = m_CutRoi; m_pImageAllResult->pDetResult->CutRoi = m_CutRoi; m_pImageAllResult->pDetResult->Param_CropRoi = m_Crop_Roi_paramImg; // 生成 检测的图片 cv::Mat image; image = m_CheckResult_shareP->in_shareImage->img; if (image.channels() == 3) { cv::cvtColor(image(m_CutRoi), m_pImageAllResult->detImg, cv::COLOR_RGB2GRAY); } else { m_pImageAllResult->detImg = image(m_CutRoi).clone(); } // bDetect为true才进行推理输出残点图,否则直接输出全黑残点图 long time_AI_s = CheckUtil::getcurTime(); if(m_pBasicConfig->bDetect) { // 多线程开启 传统/AI 推理检测 m_AItask = std::make_shared(); m_AItask->taskname = Task_AI; m_task.sendTask(m_AItask); } else { // 不推理:直接输出全黑残点图 m_pdetlog->AddCheckstr(PrintLevel_0, "2.1、pre detect", "-------------------------NO AI_Edge--------------- \n"); m_pImageAllResult->AIMaskImg = cv::Mat::zeros(m_pImageAllResult->detImg.size(), CV_8UC1); } ImgPreDet(); // 更新检测区域 Update_DetRoiList(); m_pdetlog->AddCheckstr(PrintLevel_0, "3、pre detect", "-------------------------pre Det--------------- \n"); // 实现边缘崩溃缺陷检测 { long t41 = CheckUtil::getcurTime(); int reedge1111 = Edge_Qx_Det(m_pImageAllResult->detImg); long t42 = CheckUtil::getcurTime(); m_pdetlog->AddCheckstr(PrintLevel_0, "4、detect", "-------------------------1、Edge_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::RotatedRect(); 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"); // 检查 detImg 和 AIMaskImg 是否为空 if (m_pImageAllResult->detImg.empty()) { m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "CalBlob_Other", " detImg is empty, return"); return -1; } if (m_pImageAllResult->AIMaskImg.empty()) { m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "CalBlob_Other", " AIMaskImg is empty, return"); return -1; } 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.find("CA") != std::string::npos) { 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); // bDetect为false时不进行推理,直接输出全黑残点图 if(!m_pBasicConfig->bDetect) { m_CheckResult_shareP->resultMaskImg = m_pImageAllResult->AIMaskImg; return 0; } // 传统检测路径:等待异步任务完成后,计算HFlag if(m_pbaseCheckFunction->traditionDet.bOpen) { m_AItask->waitComplate(); int rec = m_AItask->nresult; if (rec != CHECK_OK) { return rec; } if (!m_pImageAllResult->AIMaskImg.empty()) { unsigned char *pGrayErrordata = (unsigned char *)m_pImageAllResult->AIMaskImg.data; int width = m_pImageAllResult->AIMaskImg.cols; int height = m_pImageAllResult->AIMaskImg.rows; for (int y = 0; y < height; y++) { if (m_ImgBlobHFlagData[y] == 0) { unsigned char *p = pGrayErrordata + y * width; for (int x = 0; x < width; x++) { if (p[x] != 0) { m_ImgBlobHFlagData[y] = 1; break; } } } } } m_CheckResult_shareP->resultMaskImg = m_pImageAllResult->AIMaskImg; return 0; } 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) { std::shared_ptr pAIDet; // printf("=====>>>>AI_Detect_Thread m_strCurDetChannel %s \n", m_strCurDetChannel.c_str()); if (m_strCurDetChannel.find("BCA") != std::string::npos) { // printf("=====>>>>AI_Detect_Thread USE CA %s \n", m_strCurDetChannel.c_str()); pAIDet = AI_Factory->CELL_BCA_Det; } else if (m_strCurDetChannel.find("BTA") != std::string::npos) { pAIDet = AI_Factory->CELL_BTA_Det; } else if (m_strCurDetChannel.find("DCA") != std::string::npos) { pAIDet = AI_Factory->CELL_DCA_Det; } else if (m_strCurDetChannel.find("DTA") != std::string::npos) { pAIDet = AI_Factory->CELL_DTA_Det; } else { pAIDet = AI_Factory->CELL_BTA_Det; } 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 = pAIDet->input_0.width; int deal_image_height = pAIDet->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(); int submitted = 0; int completed = 0; // std::string str_Root = m_strRootPath + pDetConfig->strProductID + "_" + pDetConfig->strchannel + "_"; t2 = CheckUtil::getcurTime(); while (completed < totalTasks) { // 如果任务还没提交完,且当前处理任务数 < 2,提交新任务 if (submitted < totalTasks && runner->GetProcessingCount() < 10) { std::shared_ptr task = std::make_shared(); task->id = completed; 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()) { outimg.copyTo(ResultImg(result->roi), outimg); } { std::shared_ptr temAIresult = std::make_shared(); temAIresult->roi = result->roi; temAIresult->AI_inImg = result->input; temAIresult->AI_mask = outimg; m_pImageAllResult->AI_Qx_MaskList.push_back(temAIresult); // AI检测残点图存图 if (m_pbaseCheckFunction->saveImg.bSaveAIDetImg) { std::string roi_ext = "[" + std::to_string(result->roi.x) + "," + std::to_string(result->roi.y) + "]"; std::string strSaveDir = "/home/aidlux/BOE/FOG/AI_Detect/" + DetImgInfo_shareP->strImgProductID + "/"; CheckUtil::CreateDir(strSaveDir); std::string strSavePath_in = strSaveDir + m_strCurDetChannel +"_"+ roi_ext + "_"+ "in" + ".png"; std::string strSavePath_out = strSaveDir + m_strCurDetChannel +"_"+ roi_ext + "_"+ "out" + ".png"; cv::imwrite(strSavePath_in, result->input); cv::imwrite(strSavePath_out, outimg); } } completed++; } else { std::this_thread::sleep_for(std::chrono::milliseconds(1)); } } t3 = CheckUtil::getcurTime(); float mean_AI = (t3 - t2) / SmallRoiList.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::Traditional_Detect_Thread(const cv::Mat &img, cv::Mat &ResultImg) { std::string strBaseLog = "Traditional_Detect"; m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "Traditional_Detect Start"); // 输入校验 if (img.empty()) { m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "Traditional_Detect FAILED (empty image)"); ResultImg = cv::Mat(); return -1; } Base_Function_TraditionDet traditionParam = m_pbaseCheckFunction->traditionDet; // 首次调用时初始化传统检测参数(从 m_AnalysisyConfig 映射) { CHECK_PARAM cp; cp.nAreaLowFilter = 80; cp.nBlockSize = traditionParam.nBlockSize; cp.fZoomRatio = traditionParam.fZoomRatio; cp.nFilterLow = traditionParam.nFilterLow; cp.nFilterHigh = traditionParam.nFilterHigh; cp.nAreaFilter = traditionParam.nAreaFilter; cp.nCountFilter = traditionParam.nCountFilter; cp.productId = DetImgInfo_shareP->strImgProductID; cp.productChannel = m_strCurDetChannel; cp.bDebugsaveImg = m_pbaseCheckFunction->saveImg.bSaveAIDetImg; m_tcsCheck.SetChecConfig(&cp); } cv::Rect detroi = cv::boundingRect(traditionParam.detArea); detroi.x -= m_Crop_Roi_paramImg.x; detroi.y -= m_Crop_Roi_paramImg.y; detroi = detroi & cv::Rect(0, 0, img.cols, img.rows); if(!traditionParam.bdetArea) { detroi = cv::Rect(0, 0, img.cols, img.rows); } // 调用传统检测:输出残点二值图 int ret = m_tcsCheck.TraditionalDetect(img, detroi, ResultImg); if (ret != 0) { m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "Traditional_Detect FAILED (no product)"); return -1; } if (DetImgInfo_shareP->bsaveProcessImg) { cv::imwrite(DetImgInfo_shareP->strChannel + "_AI_mask.png", ResultImg); } m_pdetlog->AddCheckstr(PrintLevel_0, DET_LOG_LEVEL_3, strBaseLog, "Traditional_Detect End"); 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()); if (m_strCurDetChannel.find("CA") != std::string::npos) { // printf("=====>>>>AI_QX_Class_Thread USE CA %s \n", m_strCurDetChannel.c_str()); pAIDet = AI_Factory->CELL_CA_Cls; } else { pAIDet = AI_Factory->CELL_TA_Cls; } 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.find("TA") != std::string::npos) { 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::Traditional_QX_Class_Thread() { m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Traditional_Class", " Start"); // 1. 调用传统分类 if (m_pImageAllResult == nullptr || m_pImageAllResult->AIMaskImg.empty()) { m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Traditional_Class", " No mask image"); return -1; } int nDefectCount = m_tcsCheck.TraditionalClassify(m_pImageAllResult->AIMaskImg); if (nDefectCount < 0) { m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Traditional_Class", " Classify failed"); return -1; } // 2. TcsCheck 缺陷类型 → CONFIG_QX_NAME 映射表 static const int TcsDefectToConfigQX[] = { CONFIG_QX_NAME_cell_other, // DEFECT_TYPE_OK = 0 CONFIG_QX_NAME_cell_dianzhuang, // DEFECT_TYPE_POINT = 1 (硬质颗粒 → 点状) CONFIG_QX_NAME_cell_line, // DEFECT_TYPE_SCRATCH = 2 (划伤 → 线状) CONFIG_QX_NAME_cell_zangwu, // DEFECT_TYPE_DIRTY = 3 (脏污) CONFIG_QX_NAME_cell_danban, // DEFECT_TYPE_FADING_SPOTS = 4 (淡斑) }; // 3. 将分类结果匹配到 blobs.blobTab(基于位置/面积最近邻匹配) int totalTasks = blobs.blobCount; for (int i = 0; i < totalTasks; i++) { ERROR_DOTS_BLOB_DATA *pblob = &blobs.blobTab[i]; if (pblob->ErrType == ERR_TYPE_2) { pblob->AIclasstype = CONFIG_QX_NAME_cell_ymhs; continue; } // 在 TcsCheck 结果中找最佳匹配(中心距离最近) int bestIdx = -1; int bestDist2 = INT_MAX; int blobCenterX = (pblob->minx + pblob->maxx) / 2; int blobCenterY = (pblob->miny + pblob->maxy) / 2; for (int j = 0; j < nDefectCount; j++) { const DEFECT_INFO& info = m_tcsCheck.m_vecDefectInfo[j]; int defCenterX = info.nDefectX + info.nDefectWidth / 2; int defCenterY = info.nDefectY + info.nDefectHeight / 2; int dx = blobCenterX - defCenterX; int dy = blobCenterY - defCenterY; int dist2 = dx * dx + dy * dy; // 面积接近的优先(容差 50% 内) int areaDiff = std::abs(pblob->area - info.nDefectArea); if (areaDiff < info.nDefectArea / 2 && dist2 < bestDist2) { bestDist2 = dist2; bestIdx = j; } } if (bestIdx >= 0) { int defectType = m_tcsCheck.m_vecDefectInfo[bestIdx].nDefectType; pblob->AIclasstype = TcsDefectToConfigQX[defectType]; } else { pblob->AIclasstype = CONFIG_QX_NAME_cell_other; } } m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Traditional_Class", " End, classified %d/%d blobs", nDefectCount, totalTasks); 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_CutRoi.width, m_CutRoi.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; if(m_pbaseCheckFunction->traditionDet.bOpen) { rec = Traditional_Detect_Thread(m_pImageAllResult->detImg, m_pImageAllResult->AIMaskImg); } else { 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; if(m_pbaseCheckFunction->traditionDet.bOpen) { rec = Traditional_QX_Class_Thread(); } else { 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; // Adapt_Config 已通过仿射变换将配置区域适配到当前产品位置, // 此处仅做坐标映射(减去裁剪ROI偏移 + 缩放),不再叠加边缘对齐的二次偏移 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(int i = 0; i < m_DetRoiList.roiList_Show.size(); i++) { cv::polylines(m_CheckResult_shareP->resultimg, m_DetRoiList.roiList_Show[i], true, cv::Scalar(32, 128, (i*64+64)%255), 1); } // 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; // 要绘制结果 if (m_pbaseCheckFunction && m_pbaseCheckFunction->edgeDet.bDrawResult) { for (const auto &r : m_Edge_DetConfig.edge_det_roi) { cv::Point2f vertices[4]; r.rrect.points(vertices); for (int j = 0; j < 4; j++) { cv::Point p1, p2; p1.x = (int)(vertices[j].x * fs_resize_x); p1.y = (int)(vertices[j].y * fs_resize_y); p2.x = (int)(vertices[(j+1)%4].x * fs_resize_x); p2.y = (int)(vertices[(j+1)%4].y * fs_resize_y); cv::line(m_CheckResult_shareP->resultimg, p1, p2, cv::Scalar(255, 0, 255), 1); } } if (m_Edge_DetConfig.Det_region.size() > 2) { for (int i = 0; i < m_Edge_DetConfig.Det_region.size() - 1; i++) { cv::Point p1; p1.x = m_Edge_DetConfig.Det_region[i].x * fs_resize_x; p1.y = m_Edge_DetConfig.Det_region[i].y * fs_resize_y; cv::Point p2; p2.x = m_Edge_DetConfig.Det_region[i + 1].x * fs_resize_x; p2.y = m_Edge_DetConfig.Det_region[i + 1].y * fs_resize_y; cv::line(m_CheckResult_shareP->resultimg, p1, p2, cv::Scalar(0, 255, 255)); } { cv::Point p1; p1.x = m_Edge_DetConfig.Det_region[0].x * fs_resize_x; p1.y = m_Edge_DetConfig.Det_region[0].y * fs_resize_y; cv::Point p2; p2.x = m_Edge_DetConfig.Det_region[m_Edge_DetConfig.Det_region.size() - 1].x * fs_resize_x; p2.y = m_Edge_DetConfig.Det_region[m_Edge_DetConfig.Det_region.size() - 1].y * fs_resize_y; cv::line(m_CheckResult_shareP->resultimg, p1, p2, cv::Scalar(0, 255, 255)); } } } if (m_pEdge_Align_Result.get() != NULL) { if (m_pbaseCheckFunction->markLine.bDraw) { for (size_t i = 0; i < m_pEdge_Align_Result->markresulList.size(); i++) { // if (m_pEdge_Align_Result->markresulList[i].status == Mark_Result_Status_OK) { cv::Point p; p.x = m_pEdge_Align_Result->markresulList[i].det_Local_DetImg.x * fs_resize_x; p.y = m_pEdge_Align_Result->markresulList[i].det_Local_DetImg.y * fs_resize_y; cv::circle(m_CheckResult_shareP->resultimg, p, 5, cv::Scalar(0, 255, 0)); } } } } // 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::Edge_Qx_Det(const cv::Mat &img) { m_Edge_DetConfig.Init(); m_Edge_DetConfig.detlog = m_pdetlog; m_Edge_DetConfig.strChannel = m_strCurDetChannel; m_Edge_DetConfig.pBaseCheckFunction = m_pbaseCheckFunction; m_Edge_DetConfig.alginResult.corpRoi = m_Crop_Roi_paramImg; m_Edge_DetConfig.pBaseCheckFunction->edgeDet.Align_region = m_AnalysisyConfig.baseFunction.markLine.region; for(int i = 0; i < m_Edge_DetConfig.pBaseCheckFunction->edgeDet.Align_region.size(); i++) { m_Edge_DetConfig.pBaseCheckFunction->edgeDet.Align_region[i].x -= m_Crop_Roi_paramImg.x; m_Edge_DetConfig.pBaseCheckFunction->edgeDet.Align_region[i].y -= m_Crop_Roi_paramImg.y; } if (m_pEdge_Align_Result && m_pEdge_Align_Result->buseOfft) { m_Edge_DetConfig.alginResult.offtx = m_pEdge_Align_Result->offt_x; m_Edge_DetConfig.alginResult.offty = m_pEdge_Align_Result->offt_y; m_Edge_DetConfig.alginResult.H = m_pEdge_Align_Result->H.clone(); } m_Edge_DetConfig.bSaveResultImg = false; if (DetImgInfo_shareP->bsaveProcessImg) { m_Edge_DetConfig.bSaveResultImg = true; } // m_pbaseCheckFunction->print("Edge_Qx_Det"); int re = m_Edge_QX_Det.Detect(img, &m_Edge_DetConfig); if (re == 0) { for (const auto r : m_Edge_DetConfig.qx_result) { QX_ERROR_INFO_ temerror; temerror.roi = r.roi_src; temerror.Idx = m_pDetResult->pQx_ErrorList->size(); temerror.area = r.area_pixel; temerror.JudgArea = r.area_pixel * m_fImgage_Scale_X * m_fImgage_Scale_Y; temerror.JudgArea_second = temerror.JudgArea; temerror.energy = 99999999; temerror.flen = std::max(r.roi_src.width, r.roi_src.height); temerror.fbreadth = std::min(r.roi_src.width, r.roi_src.height); temerror.nconfig_qx_type = CONFIG_QX_NAME_cell_edge; temerror.qx_name = CONFIG_QX_NAME_Names[CONFIG_QX_NAME_cell_edge]; temerror.maxValue = 0; temerror.grayDis = 255; temerror.density = 0; temerror.fUpIou = 0; { cv::Point pCenter; pCenter.x = temerror.roi.x + temerror.roi.width * 0.5; pCenter.y = temerror.roi.y + temerror.roi.height * 0.5; int nmaxregionIdx = -1; 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; } if (nmaxregionIdx >= 0) { temerror.detRegionidxList.push_back(nmaxregionIdx); } } // { // cv::Point pCenter; // pCenter.x = temerror.roi.x + temerror.roi.width * 0.5; // pCenter.y = temerror.roi.y + temerror.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; // } // temerror.detRegionidxList.push_back(iregion); // } // if (temerror.detRegionidxList.size() <= 0) // { // temerror.detRegionidxList.push_back(0); // } // } m_pDetResult->pQx_ErrorList->push_back(temerror); } m_pdetlog->AddCheckstr(PrintLevel_1, "Edge_Qx_Det", " succ qx num %ld", m_Edge_DetConfig.qx_result.size()); // 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); } else { m_pdetlog->AddCheckstr(PrintLevel_1, "Edge_Qx_Det", " error %d", re); } 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 = -1; 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; } if (nmaxregionIdx >= 0) { 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::Rect &cutRoi) { 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); } cutRoi = m_pEdge_Align_Result->roi; // getchar(); return re; } int ImgCheckAnalysisy::CalProductSize() { float fw = m_CutRoi.width * m_fImgage_Scale_X; float fh = m_CutRoi.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", " [x%d, y%d, w %d,h %d] (piexl) -> [w %f h %f](mm),scale %f %f", m_CutRoi.x, m_CutRoi.y, m_CutRoi.width, m_CutRoi.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; }