/* * @Author: your name * @Date: 2022-04-20 15:50:00 * @LastEditTime: 2025-09-23 10:29:01 * @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 "CameraCheckAnalysisy.hpp" #include "ImgCheckAnalysisy.hpp" #include "CheckUtil.hpp" #include "Define.h" #include CameraCheckAnalysisy::CameraCheckAnalysisy() { m_nErrorCode = 0; // 错误代码 m_bInitSucc = false; // 初始化状态 m_bExit = false; // 是否退出检测 m_bHaveImgeDet = false; m_strcameraName = ""; nLastCheckAnalysisyThreadIdx = 0; m_pChannelFuntion = &m_AnalysisyConfig.checkFunction; m_pbaseCheckFunction = &m_AnalysisyConfig.baseFunction; m_nConfigIdx = -1; m_pdetlog = std::make_shared(); m_pCommonAnalysisyConfig = NULL; m_imageResultJudge.SetAnalysisyConfig(&m_AnalysisyConfig); bshowimg = false; } CameraCheckAnalysisy::~CameraCheckAnalysisy() { } int CameraCheckAnalysisy::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 CameraCheckAnalysisy::WaitDetImg() { std::unique_lock lk(mtx_WaiteImg); cond_WaiteImg.wait(lk, [this]() { return m_bHaveImgeDet; }); lk.unlock(); return 0; } // 判断物料在左还是在右 string JudgeMaterialPosition(Mat img) { if (img.empty()) { cerr << "Error: Input image is empty!" << endl; return "Unknown"; } // 原图可能是彩色,内部统一转灰度计算(形参为副本,不会改动调用方图像) if (img.channels() != 1) { cv::Mat grayImg; if (img.channels() == 4) { cv::cvtColor(img, grayImg, cv::COLOR_BGRA2GRAY); } else { cv::cvtColor(img, grayImg, cv::COLOR_BGR2GRAY); } img = grayImg; } resize(img, img, Size(img.cols, img.rows * 0.001), 0, 0); int rows = img.rows; int cols = img.cols; // 统计灰度值 < bg_val 的像素数量 int left_black_count = 0; int right_black_count = 0; int bg_val = 25; for (int row = 0; row < rows; ++row) { for (int col = 0; col < 3; ++col) { if (img.at(row, col) < 25) { left_black_count++; } } for (int col = cols - 3; col < cols; ++col) { if (img.at(row, col) < 25) { right_black_count++; } } } // 判断物料位置 if (left_black_count <= right_black_count) { return "Left"; } else if (left_black_count > right_black_count) { return "Right"; } else{ return "Unknown"; } } //正常情况CA(img物料在左,img_B物料在右),TA(img物料在右,img_B物料在左) bool ifExchange(cv::Mat &img, const cv::Mat &img_B, std::string strcam ){ string img_position = JudgeMaterialPosition(img); string img_B_position = JudgeMaterialPosition(img_B); if (strcam == "TA"){ if (img_position == "Left" && img_B_position == "Right"){ return true; } else{ return false; } } else{ if (img_position == "Right" && img_B_position == "Left"){ return true; } else{ return false; } } } int CameraCheckAnalysisy::Detect_Pre() { std::string strlog; std::string strSN; std::string strBasic; strSN = m_pCheck_Result->productBaseResult->strproductName; strBasic = ">>" + strSN + " cam:" + m_strcameraName; m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s ==================start", strBasic.c_str()); std::shared_ptr pImageResult = m_pCheck_Result->GetNoDetImg(); if (!pImageResult) { return 1; } if (!pImageResult->result->in_shareImage->bCam_AB) { m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s ==================bCam_AB = false", strBasic.c_str()); return 0; } if (pImageResult->result->in_shareImage->img.empty() || pImageResult->result->in_shareImage->img_B.empty()) { m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s ==================img.empty() || img_B.empty() ", strBasic.c_str()); return 1; } //判断图片左右,0为左,1为右 bool exchange_img = ifExchange(pImageResult->result->in_shareImage->img, pImageResult->result->in_shareImage->img_B, pImageResult->result->in_shareImage->strCameraName); if(exchange_img){ std::swap(pImageResult->result->in_shareImage->img, pImageResult->result->in_shareImage->img_B); } // printf("===66666666666666666\n"); int re = Mergimg(pImageResult->result->in_shareImage->img, pImageResult->result->in_shareImage->img_B, pImageResult->result->in_shareImage->strCameraName, pImageResult->result->in_shareImage->strChannel); if (pImageResult->result->in_shareImage->Det_Mode == DET_MODE_MergeImg) { cv::imwrite(pImageResult->result->in_shareImage->strCameraName + "_MergeImg.png", pImageResult->result->in_shareImage->img); return 2; } return 0; } int CameraCheckAnalysisy::Mergimg(cv::Mat &img, const cv::Mat &img_B, std::string strcam, std::string strchannel) { // std::cout << img.size() << std::endl; // std::cout << img_B.size() << std::endl; if (img.size() != img_B.size()) { return -1; } long t1, t2; t1 = CheckUtil::getcurTime(); int re = 0; cv::Rect Left_Roi; cv::Rect Right_Roi; cv::Mat AllImg = cv::Mat::zeros(img.rows, img.cols * 2, img.type()); // cv::imwrite(strcam + strchannel + "_img.png", img); // cv::imwrite(strcam + strchannel + "img_B.png", img_B); if (strcam == "TA") { cv::Rect Left_Tem_Roi; cv::Point Left_Tem_Point_Up; cv::Point Left_Tem_Point_Donw; cv::Rect Right_Tem_Roi; cv::Point Right_Tem_Point_Up; cv::Point Right_Tem_Point_Donw; // left Img { re = GetRectAndPoint(img, Left_Tem_Roi, Left_Tem_Point_Up, Left_Tem_Point_Donw, false, strcam, strchannel); if (re != 0) { m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s Mergimg GetRectAndPoint TAA error %d", strcam.c_str(), re); return 1; } re = GetRectAndPoint(img_B, Right_Tem_Roi, Right_Tem_Point_Up, Right_Tem_Point_Donw, true, strcam, strchannel); if (re != 0) { m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s Mergimg GetRectAndPoint TAB error %d", strcam.c_str(), re); return 1; } img(Left_Tem_Roi).copyTo(AllImg(Left_Tem_Roi)); int hlen_left = Left_Tem_Point_Donw.y - Left_Tem_Point_Up.y; int hlen_right = Right_Tem_Point_Donw.y - Right_Tem_Point_Up.y; float fhscle = hlen_left * 1.0f / hlen_right; int dy = Left_Tem_Point_Up.y - Right_Tem_Point_Up.y; cv::Rect allroi = Right_Tem_Roi; allroi.height *= fhscle; allroi.x = Left_Tem_Roi.x + Left_Tem_Roi.width; allroi.y += dy; cv::Size sz; sz.width = allroi.width; sz.height = allroi.height; cv::resize(img_B(Right_Tem_Roi), AllImg(allroi), sz); } } else { cv::Rect Left_Tem_Roi; cv::Point Left_Tem_Point_Up; cv::Point Left_Tem_Point_Donw; cv::Rect Right_Tem_Roi; cv::Point Right_Tem_Point_Up; cv::Point Right_Tem_Point_Donw; // left Img { re = GetRectAndPoint(img_B, Left_Tem_Roi, Left_Tem_Point_Up, Left_Tem_Point_Donw, false, strcam, strchannel); if (re != 0) { m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s Mergimg GetRectAndPoint CAA error %d", strcam.c_str(), re); return 1; } re = GetRectAndPoint(img, Right_Tem_Roi, Right_Tem_Point_Up, Right_Tem_Point_Donw, true, strcam, strchannel); if (re != 0) { m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s Mergimg GetRectAndPoint CAB error %d", strcam.c_str(), re); return 1; } img_B(Left_Tem_Roi).copyTo(AllImg(Left_Tem_Roi)); int hlen_left = Left_Tem_Point_Donw.y - Left_Tem_Point_Up.y; int hlen_right = Right_Tem_Point_Donw.y - Right_Tem_Point_Up.y; float fhscle = hlen_left * 1.0f / hlen_right; int dy = Left_Tem_Point_Up.y - Right_Tem_Point_Up.y; cv::Rect allroi = Right_Tem_Roi; allroi.height *= fhscle; allroi.x = Left_Tem_Roi.x + Left_Tem_Roi.width; allroi.y += dy; cv::Size sz; sz.width = allroi.width; sz.height = allroi.height; cv::resize(img(Right_Tem_Roi), AllImg(allroi), sz); } } img = AllImg; t2 = CheckUtil::getcurTime(); // cv::imwrite(strcam + strchannel + "_merg.png", AllImg); m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Pre", "Cam %s Mergimg use time %ld ms", strcam.c_str(), t2 - t1); return 0; } int CameraCheckAnalysisy::GetRectAndPoint(const cv::Mat &img, cv::Rect &roi, cv::Point &merg_p_up, cv::Point &merg_p_down, bool bleft, std::string strcam, std::string strchannel) { bshowimg = false; int A_line_up = 0; int A_line_down = 0; Edge_Search_Config config; if (bshowimg) { if (img.channels() != 1) { showimg = img.clone(); } else { cv::cvtColor(img, showimg, cv::COLOR_GRAY2BGR); } } config.nSearchCount = 10; config.strchannel = strchannel; config.directSign = DirectSign_UP; if (bleft) { config.roi = cv::Rect(0, 0, 200, img.rows * 0.8); } else { config.roi = cv::Rect(img.cols - 200, 0, 200, img.rows * 0.8); } int re123 = GetEdgePoint(img, &config, A_line_up); if (re123 != 0) { printf("DirectSign_UP::111111111111GetEdgePoint111111 A_line_up %d\n", re123); return 1; } config.directSign = DirectSign_DOWN; config.strchannel = strchannel + "ccc"; config.roi = cv::Rect(0, img.rows * 0.2, 200, img.rows * 0.8 - 1); if (bleft) { config.roi = cv::Rect(0, img.rows * 0.2, 200, img.rows * 0.8 - 1); } else { config.roi = cv::Rect(img.cols - 200, img.rows * 0.2, 200, img.rows * 0.8 - 1); } re123 = GetEdgePoint(img, &config, A_line_down); if (re123 != 0) { printf("DirectSign_UP::111111111111GetEdgePoint111111 A_line_down %d\n", re123); return 1; } { if (bshowimg) { cv::line(showimg, cv::Point(0, A_line_down), cv::Point(img.cols, A_line_down), cv::Scalar(0, 255, 0), 2); cv::line(showimg, cv::Point(0, A_line_up), cv::Point(img.cols, A_line_up), cv::Scalar(0, 255, 0), 2); cv::imwrite(strcam + strchannel + "_line.png", showimg); } } // printf("DirectSign_UP::111111111111111111 re123 %d\n", re123); // getchar(); // 阈值化 + 轮廓提取只支持单通道,彩色原图内部转灰度(不改动调用方图像) cv::Mat grayImg; if (img.channels() != 1) { if (img.channels() == 4) { cv::cvtColor(img, grayImg, cv::COLOR_BGRA2GRAY); } else { cv::cvtColor(img, grayImg, cv::COLOR_BGR2GRAY); } } const cv::Mat &workImg = (img.channels() == 1) ? img : grayImg; cv::Mat small, smallbin; cv::resize(workImg, small, cv::Size(600, 1500)); cv::threshold(small, smallbin, 15, 255, cv::THRESH_BINARY); /* 3. contours */ std::vector> contours; cv::findContours(smallbin, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); if (contours.empty()) return 1; /* 4. max contour */ double maxArea = 0; int idx = -1; for (int i = 0; i < contours.size(); i++) { double area = cv::contourArea(contours[i]); if (area > maxArea) { maxArea = area; idx = i; } } if (idx < 0) return 1; cv::Rect rSmall = cv::boundingRect(contours[idx]); /* 5. map to original */ float sx = (float)workImg.cols / smallbin.cols; float sy = (float)workImg.rows / smallbin.rows; cv::Rect rectInSrc; rectInSrc.x = int(rSmall.x * sx) - 50; rectInSrc.y = int(rSmall.y * sy) - 50; rectInSrc.width = int(rSmall.width * sx) + 100; rectInSrc.height = int(rSmall.height * sy) + 100; if (rectInSrc.y >= A_line_up) { rectInSrc.y = A_line_up - 5; } if (rectInSrc.y + rectInSrc.height <= A_line_down) { rectInSrc.height = A_line_down + 5 - rectInSrc.y; } if (rectInSrc.x < 0) rectInSrc.x = 0; if (rectInSrc.y < 0) rectInSrc.y = 0; if (rectInSrc.x + rectInSrc.width > workImg.cols) rectInSrc.width = workImg.cols - rectInSrc.x; if (rectInSrc.y + rectInSrc.height > workImg.rows) { rectInSrc.height = workImg.rows - rectInSrc.y; } merg_p_up.y = A_line_up; merg_p_up.x = workImg.cols; merg_p_down.y = A_line_down; merg_p_down.x = workImg.cols; roi = rectInSrc; if (bshowimg) { cv::rectangle(showimg, rectInSrc, cv::Scalar(0, 0, 255), 2); cv::imwrite(strcam + strchannel + "_rect.png", showimg); } return 0; } // 对该相机下的每一张图片进行处理 int CameraCheckAnalysisy::Detect_Images() { std::string strlog; std::string strSN; std::string strBasic; strSN = m_pCheck_Result->productBaseResult->strproductName; strBasic = ">>" + strSN + " cam:" + m_strcameraName; m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Images", "Cam %s ==================start", strBasic.c_str()); // // 循环处理每个图片 bool bcomplete = false; long time_No_CheckAnalysisy = 30 * 1000; long ts = CheckUtil::getcurTime(); while (!bcomplete) { std::this_thread::sleep_for(std::chrono::milliseconds(20)); ImgCheckBase *pImgCheckAnalysisy = NULL; long t1 = CheckUtil::getcurTime(); // 拿到计算资源 while (true) { pImgCheckAnalysisy = GetDealResult(-1); if (pImgCheckAnalysisy != NULL) { break; } std::this_thread::sleep_for(std::chrono::milliseconds(20)); // long t2 = CheckUtil::getcurTime(); // 如果 超过秒XX都没有拿到处理资源,则直接退出 if (t2 - t1 > time_No_CheckAnalysisy) { m_pdetlog->AddCheckstr(PrintLevel_2, "Detect_Images", "Error %ld ms No pImgCheckAnalysisy", time_No_CheckAnalysisy); break; } } // 没有分析检测资源,直接退出 if (pImgCheckAnalysisy == NULL) { continue; } // 1、把每张图都进行AI 推理 获得 blob 结果 std::shared_ptr pImageResult = m_pCheck_Result->GetNoDetImg(); bool bHaveNotdetImg = false; // 没有未检测的图片了。 if (pImageResult) { m_pdetlog->AddCheckstr(PrintLevel_2, "Detect_Images", "channel %s send det ", pImageResult->strChannel.c_str()); bHaveNotdetImg = true; pImgCheckAnalysisy->SetDataRun_SharePtr(pImageResult); } else { // 图片都已经送完了。 if (m_pCheck_Result->getImgPushComplate()) { // printf("Cam Detect_Images %s ==================send end \n", strBasic.c_str()); // 没有图在进行 检测了。 bool bhavedet = false; for (int i = 0; i < IMGCHECKANALYSISY_NUM; i++) { if (CHECK_THREAD_STATUS_IDLE != m_pImgCheckAnalysisy[i]->GetStatus()) { bhavedet = true; break; } } // printf("Cam Detect_Images %s ==================bhavedet %d\n", strBasic.c_str(), bhavedet); if (!bhavedet) { bcomplete = true; } } else { // printf("Cam Detect_Images %s ==================No send end\n", strBasic.c_str() ); } } } long te = CheckUtil::getcurTime(); m_pdetlog->AddCheckstr(PrintLevel_1, "Detect_Images", "Cam %s =====ALL image det complate time %ld ms=============End", strBasic.c_str(), te - ts); return 0; } int CameraCheckAnalysisy::ResultParamJudge() { //================================================== //======= 适用于 单相机或多相机,每个相机之间的图相互没关系。 //======= //======= //======= //================================================== std::string strlog; std::string strSN; std::string strBasic; long ts = CheckUtil::getcurTime(); int ImageNum = m_pCheck_Result->ImageALLDetResultList.size(); if (ImageNum <= 0) { m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", "Error ImageNum <=0"); return 1; } // 如果 参数是空,直接返回。 if (m_pCommonAnalysisyConfig == NULL) { m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", "Error m_pCommonAnalysisyConfig == NULL"); return 1; } int regionNum = m_pCommonAnalysisyConfig->regionConfigArr.size(); if (regionNum <= 0) { m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", "Error Config region num = 0"); } m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", "==================start image Num %d region num %d", ImageNum, regionNum); // 对每个图片通道进行单独分析 for (int imgidx = 0; imgidx < ImageNum; imgidx++) { long t1 = CheckUtil::getcurTime(); int re = m_imageResultJudge.ResultJudge(m_pCheck_Result->ImageALLDetResultList.at(imgidx)); long t2 = CheckUtil::getcurTime(); m_imageResultJudge.DrawResult(m_pCheck_Result->ImageALLDetResultList.at(imgidx)); long t3 = CheckUtil::getcurTime(); m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", " det time %ld ms judge %ld draw %ld", t3 - t1, t2 - t1, t3 - t2); // 把结果转成 json 保存。 用以复测 std::shared_ptr m_CheckResult_shareP = m_pCheck_Result->ImageALLDetResultList.at(imgidx)->result; m_CheckResult_shareP->strResultJson = m_CheckResultJson.GetResultString(m_pCheck_Result->ImageALLDetResultList.at(imgidx)->pDetResult); } long te = CheckUtil::getcurTime(); m_pdetlog->AddCheckstr(PrintLevel_1, "ResultParamJudge", "==================End time %ld ms ", te - ts); // m_pdetlog->printLog(m_strcameraName); return 0; } int CameraCheckAnalysisy::Init(std::string strcameraName) { m_strcameraName = strcameraName; printf("CameraCheckAnalysisy::Init start \n"); SetNewConfig(); int re = 0; re = InitCheckAnalysisy(); if (CHECK_OK != re) { printf("InitCheckAnalysisy error\n"); return -1; } re = InitRun(); if (CHECK_OK != re) { printf("InitRun error\n"); m_nErrorCode = re; return m_nErrorCode; } printf("CameraCheckAnalysisy::Init end \n"); return 0; } void CameraCheckAnalysisy::SetTplInfo(const cv::RotatedRect &outerRect) { for (int i = 0; i < IMGCHECKANALYSISY_NUM; i++) { auto *p = static_cast(m_pImgCheckAnalysisy[i]); if (p) { p->SetTplInfo(outerRect); } } } int CameraCheckAnalysisy::StartCheck(std::shared_ptr pCamera_Check_Result) { if (m_bHaveImgeDet) { return -1; } { std::lock_guard lock(mtx_WaiteImg); m_pCheck_Result = pCamera_Check_Result; if (m_pCheck_Result->bJson) { // 如果是 复测 直接进入 参数判断阶段。 m_pCheck_Result->SetCheckStep(Check_Step_ResultParamJudg); // 进入预处理阶段 } else { m_pCheck_Result->SetCheckStep(Check_Step_PreDet); // 进入预处理阶段 } m_bHaveImgeDet = true; m_pdetlog = m_pCheck_Result->detlog; m_pdetlog->AddCheckstr(PrintLevel_0, "StartCheck", "==================start %s", m_pCheck_Result->cameraBaseResult->strCameraName.c_str()); } cond_WaiteImg.notify_all(); return 0; } int CameraCheckAnalysisy::StartThread() { m_bExit = false; // 开启检测线程 ptr_thread_Run = std::make_shared(std::bind(&CameraCheckAnalysisy::Run, this)); return 0; } int CameraCheckAnalysisy::StopThread() { m_bExit = true; if (ptr_thread_Run != nullptr) { if (ptr_thread_Run->joinable()) { ptr_thread_Run->join(); } } return 0; } int CameraCheckAnalysisy::InitRun() { int re; re = StartThread(); if (CHECK_OK != re) { return re; } m_bInitSucc = true; // 检测前更新参数 SetNewConfig(); return 0; } int CameraCheckAnalysisy::InitCheckAnalysisy() { int re = 0; // 全局递增的 CPU 核偏移: static std::atomic s_cpuOffset{0}; for (int i = 0; i < IMGCHECKANALYSISY_NUM; i++) { RunInfoST RunConfig; RunConfig.nThreadIdx = i; { // 核带下沉到库内部:不再依赖调用方传入的 nCpu_start_Idx / nCpu_num int offset = s_cpuOffset.fetch_add(1) % CHECK_CPU_BAND_NUM; RunConfig.nCpu_start_Idx = CHECK_CPU_BAND_START + offset; } RunConfig.nCpu_num = 1; m_pImgCheckAnalysisy[i] = ImgCheckBase::GetInstance(); re = m_pImgCheckAnalysisy[i]->UpdateConfig((void *)&RunConfig, CHECK_CONFIG_Run); if (re != 0) { printf("UpdateConfig %d Fail %s\n", CHECK_CONFIG_Run, m_pImgCheckAnalysisy[i]->GetErrorInfo().c_str()); return re; } re = m_pImgCheckAnalysisy[i]->UpdateConfig((void *)m_pConfig.get(), CHECK_CONFIG_Module); if (re != 0) { printf("UpdateConfig %d Fail %s\n", CHECK_CONFIG_Module, m_pImgCheckAnalysisy[i]->GetErrorInfo().c_str()); return re; } re = m_pImgCheckAnalysisy[i]->RunStart(); if (re != 0) { printf("cami %s RunStart Fail ==%d\n", m_strcameraName.c_str(), re); return re; } // printf(">>>>cami %s InitCheckAnalysisy: ImgCheckThread %d / %d Start Succ \n", m_strcameraName.c_str(), i+1, IMGCHECKANALYSISY_NUM); if (re != 0) { return re; } } return 0; } int CameraCheckAnalysisy::CheckImgRun() { int re = 0; Check_Step curcheckStep = m_pCheck_Result->GetCheckStep(); m_pdetlog->bPrintStr = false; m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "------------curcheckStep:%d ", curcheckStep); // 如果是未检测状态,则开始预处理 if (curcheckStep == Check_Step_NODet) { m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "Error curcheckStep = NODet "); return 1; } // 检测前更新参数 SetNewConfig(); // 预处理 if (curcheckStep == Check_Step_PreDet) { m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "cam %s : Check_Step_PreDet", m_pCheck_Result->cameraBaseResult->strCameraName.c_str()); re = Detect_Pre(); if (re != 0) { m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "cam %s : Check_Step_PreDet error = %d", m_pCheck_Result->cameraBaseResult->strCameraName.c_str(), re); curcheckStep = Check_Step_ImgeDet_End; // 进入到预图片检测阶段 } else { curcheckStep = Check_Step_ImgeDet; // 进入到预图片检测阶段 } m_pCheck_Result->SetCheckStep(curcheckStep); } // 检测每张图片 if (curcheckStep == Check_Step_ImgeDet) { m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "cam %s : Check_Step_ImgeDet", m_pCheck_Result->cameraBaseResult->strCameraName.c_str()); // 检测每张图片 re = Detect_Images(); curcheckStep = Check_Step_ResultParamJudg; // 进入到预图片检测阶段 m_pCheck_Result->SetCheckStep(curcheckStep); } // 对检测结果进行参数判断,判断是否NG. if (curcheckStep == Check_Step_ResultParamJudg) { m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "cam %s : Check_Step_ResultParamJudg", m_pCheck_Result->cameraBaseResult->strCameraName.c_str()); // 检测每张图片 re = ResultParamJudge(); // 如果有异常 if (re != 0) { // 图片 送图没有完成,则继续等待。 if (!m_pCheck_Result->getImgPushComplate()) { return 1; } } curcheckStep = Check_Step_ImgeDet_End; // 进入到预图片检测阶段 m_pCheck_Result->SetCheckStep(curcheckStep); } if (curcheckStep == Check_Step_ImgeDet_End) { m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "cam %s : Check_Step_ImgeDet_End", m_pCheck_Result->cameraBaseResult->strCameraName.c_str()); // 所有图片都送完了。 if (m_pCheck_Result->getImgPushComplate()) { curcheckStep = Check_Step_Complete; // 进入到预图片检测阶段 // 注意:这里先不发布 Check_Step_Complete。 // 若提前发布,ALLImgCheckAnalysisy 线程会立刻把结果塞给 deal, // 而本线程还在 InsertCameraLog() 里写 result->det_LogList,两边并发(读/写)竞争。 // 因此把 SetCheckStep(Check_Step_Complete) 挪到 InsertCameraLog() 之后。 } else { printf("========came %s wait img send end \n", m_strcameraName.c_str()); } } // 检测完成, if (curcheckStep == Check_Step_Complete) { long tend = CheckUtil::getcurTime(); m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "cam %s : Check_Step_Complete", m_pCheck_Result->cameraBaseResult->strCameraName.c_str()); std::string strTimg = CheckUtil::getCurTimeHMS(); m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "========came %s Check ALL end time %ld ms %s", m_pCheck_Result->cameraBaseResult->strCameraName.c_str(), tend - m_pCheck_Result->time_start, strTimg.c_str()); InsertCameraLog(); // 日志拼接完成后再发布“检测完成”,避免 deal 提前读到正在写入的 det_LogList m_pCheck_Result->SetCheckStep(Check_Step_Complete); std::lock_guard lock(mtx_WaiteImg); m_bHaveImgeDet = false; m_pCheck_Result.reset(); } // m_pdetlog->printLog(m_strcameraName); return 0; } int CameraCheckAnalysisy::Run() { while (!m_bExit) { std::this_thread::sleep_for(std::chrono::milliseconds(20)); WaitDetImg(); int re = CheckImgRun(); } return 0; } int CameraCheckAnalysisy::ImgEdge(cv::Mat img, cv::Mat &detMaskImg, cv::Rect &roi, int productIdx) { int re = 0; return re; } int CameraCheckAnalysisy::InsertCameraLog() { int ImageNum = m_pCheck_Result->ImageALLDetResultList.size(); for (int imgidx = 0; imgidx < ImageNum; imgidx++) { std::shared_ptr pImageResult = m_pCheck_Result->ImageALLDetResultList.at(imgidx); std::shared_ptr m_CheckResult_shareP = pImageResult->result; // 返回结果 if (!m_CheckResult_shareP || !pImageResult) { continue; } // 1、把图片的相关日志 写到 返回 日志中。 // 注意:DetLog 可能仍被实例线程写入,使用 GetLogs() 做加锁快照,避免并发遍历。 { std::vector imgLogs = pImageResult->detlog->GetLogs(); m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(), imgLogs.begin(), imgLogs.end()); } std::string str = ""; char buffer[256]; // 2、把缺陷信息 写的 返回日志中。 { std::shared_ptr pDetResult = pImageResult->pDetResult; // 检测结果 if (!pDetResult) { continue; } if (!pDetResult->pQx_ErrorList) { continue; } int qxNum = pDetResult->pQx_ErrorList->size(); // Add NG log { sprintf(buffer, " =====================NG num %d=============================", pImageResult->NG_num); str = buffer; m_CheckResult_shareP->det_LogList.push_back(str); } for (int qxidx = 0; qxidx < qxNum; qxidx++) { QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx); if (QX_info->result == QX_RESULT_TYPE_NG) { std::shared_ptr pQxLog = pDetResult->pQx_ErrorList->at(qxidx).detlog; std::vector qxLogs = pQxLog->GetLogs(); m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(), qxLogs.begin(), qxLogs.end()); } } { sprintf(buffer, " =====================YS num %d=============================", pImageResult->YS_num); str = buffer; m_CheckResult_shareP->det_LogList.push_back(str); } for (int qxidx = 0; qxidx < qxNum; qxidx++) { QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx); if (QX_info->result == QX_RESULT_TYPE_YS) { std::shared_ptr pQxLog = pDetResult->pQx_ErrorList->at(qxidx).detlog; std::vector qxLogs = pQxLog->GetLogs(); m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(), qxLogs.begin(), qxLogs.end()); } } { sprintf(buffer, " =====================OK num %d=============================", pImageResult->Ok_num); str = buffer; m_CheckResult_shareP->det_LogList.push_back(str); } for (int qxidx = 0; qxidx < qxNum; qxidx++) { QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx); if (QX_info->result == QX_RESULT_TYPE_OK) { std::shared_ptr pQxLog = pDetResult->pQx_ErrorList->at(qxidx).detlog; std::vector qxLogs = pQxLog->GetLogs(); m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(), qxLogs.begin(), qxLogs.end()); } } { sprintf(buffer, " =====================NO Judge num %d=============================", pImageResult->NoJudge_num); str = buffer; m_CheckResult_shareP->det_LogList.push_back(str); } for (int qxidx = 0; qxidx < qxNum; qxidx++) { QX_ERROR_INFO_ *QX_info = &pDetResult->pQx_ErrorList->at(qxidx); if (QX_info->result == QX_RESULT_TYPE_NoJduge) { std::shared_ptr pQxLog = pDetResult->pQx_ErrorList->at(qxidx).detlog; std::vector qxLogs = pQxLog->GetLogs(); m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(), qxLogs.begin(), qxLogs.end()); } } } { sprintf(buffer, " =====================Cam Log ============================="); str = buffer; m_CheckResult_shareP->det_LogList.push_back(str); } // 3、把相机的日志 写到 返回日志中。 { std::vector camLogs = m_pCheck_Result->detlog->GetLogs(); m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(), camLogs.begin(), camLogs.end()); } { sprintf(buffer, " =====================Product Log ============================="); str = buffer; m_CheckResult_shareP->det_LogList.push_back(str); } // 4、把产品相关日志 写到 返回日志中。 { std::vector productLogs = m_pCheck_Result->productBaseResult->detlog->GetLogs(); m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(), productLogs.begin(), productLogs.end()); } } return 0; } ChannelCheckFunction *CameraCheckAnalysisy::GetChannelFuntion(std::string strChannelName) { ChannelCheckFunction *p = NULL; // printf("m_pChannelFuntion->channelFunctionArr.size() %zu\n", m_pChannelFuntion->channelFunctionArr.size()); for (int i = 0; i < m_pChannelFuntion->channelFunctionArr.size(); i++) { if (CheckUtil::compareIgnoreCase(m_pChannelFuntion->channelFunctionArr[i].strChannelName, strChannelName)) { p = &m_pChannelFuntion->channelFunctionArr[i]; } } return p; } int CameraCheckAnalysisy::SetNewConfig() { if (m_pConfig.get() == nullptr) { return 1; } if (m_nConfigIdx < 0) { m_nConfigIdx = m_pConfig->GetConfigIdx(); m_pdetlog->AddCheckstr(PrintLevel_1, "update config", "CameraCheckAnalysisy:%s m_nConfigIdx %d", m_strcameraName.c_str(), m_nConfigIdx); } if (m_pConfig->GetConfigUpdataStatus(ConfigType_Analysisy_Common_XL, m_nConfigIdx)) { 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_imageResultJudge.UpdateConfig(); } else { m_pCommonAnalysisyConfig = NULL; printf("m_AnalysisyConfig.commonCheckConfig.nodeConfigArr == 0 \n"); } m_pdetlog->AddCheckstr(PrintLevel_1, "update config", "Get New analysisy config"); // printf("*******ALLImgCheckAnalysisy m_pConfig*********************** Update GetConfig \n"); // m_AnalysisyConfig.checkFunction.print("Update GetConfig"); } return 0; } int CameraCheckAnalysisy::preDet_ZF(std::shared_ptr p, std::shared_ptr &pResult) { ImgCheckBase *pImgCheckAnalysisy = NULL; long t1 = CheckUtil::getcurTime(); int outTime = 1000 * 5; while (true) { pImgCheckAnalysisy = GetDealResult(-1); if (pImgCheckAnalysisy != NULL) { break; } long t2 = CheckUtil::getcurTime(); // 超时 if (t2 - t1 > outTime) { return 1; } std::this_thread::sleep_for(std::chrono::milliseconds(20)); // 模拟消费过程 } p->pBaseImgCheckConfig->imgtype = 1; pImgCheckAnalysisy->CheckImg(p, pResult); p->pBaseImgCheckConfig->imgtype = 0; return 0; } ImgCheckBase *CameraCheckAnalysisy::GetDealResult(int idx) { // 特殊情况 if (idx >= 0 && idx < IMGCHECKANALYSISY_NUM) { if (CHECK_THREAD_STATUS_IDLE == m_pImgCheckAnalysisy[idx]->GetStatus()) { // printf("*-*-*-*-*-*-*-*- use m_pImgCheckAnalysisy %d \n", idx); return m_pImgCheckAnalysisy[idx]; } else { return NULL; } } int re = 0; int nidx = nLastCheckAnalysisyThreadIdx; for (int i = 0; i < IMGCHECKANALYSISY_NUM; i++) { if (nidx >= IMGCHECKANALYSISY_NUM) { nidx = 0; } if (CHECK_THREAD_STATUS_IDLE == m_pImgCheckAnalysisy[nidx]->GetStatus()) { nLastCheckAnalysisyThreadIdx = nidx + 1; // printf("*-*-*-*-*-*-*-*- use m_pImgCheckAnalysisy %d \n", nidx); return m_pImgCheckAnalysisy[nidx]; } nidx++; } return NULL; } int CameraCheckAnalysisy::GetEdgePoint(const cv::Mat &imgSrc, Edge_Search_Config *pEdge_Search_Config, int &outP) { bool bdbuge = false; bdbuge = bshowimg; if (imgSrc.empty()) { return -11; } // 边缘搜索仅支持单通道;彩色/BGRA 原图在此内部转灰度(不改动调用方图像) cv::Mat grayImg; if (imgSrc.channels() != 1) { if (imgSrc.channels() == 4) { cv::cvtColor(imgSrc, grayImg, cv::COLOR_BGRA2GRAY); } else { cv::cvtColor(imgSrc, grayImg, cv::COLOR_BGR2GRAY); } } const cv::Mat &img = (imgSrc.channels() == 1) ? imgSrc : grayImg; // 检查roi; if (!CheckUtil::RoiInImg(pEdge_Search_Config->roi, img)) { return -13; } if (!pEdge_Search_Config->CheckConfigValid()) { return -14; } std::vector pointList; bool search_UP_DOWN = false; cv::Rect roi = pEdge_Search_Config->roi; int sx = roi.x; int ex = roi.x + roi.width; int sy = roi.y; int ey = roi.y + roi.height; int nSearchLen = roi.width; // 搜索区域的长度 int nCurPoint_Step = pEdge_Search_Config->stepCount; // 当前点搜索的步长 // 搜索小范围确认 int nhalfrang = (int)pEdge_Search_Config->nSearchrange / 2; int nrange_start = 0 - nhalfrang; int nrange_end = 0 - nhalfrang; int num = 0; while (true) { num++; nrange_end++; if (num >= pEdge_Search_Config->nSearchrange) { break; } } // 判断方向 switch (pEdge_Search_Config->directSign) { case DirectSign_UP: search_UP_DOWN = true; nSearchLen = roi.width; sx = roi.x; ex = roi.x + roi.width; sy = roi.y; ey = roi.y + roi.height; nCurPoint_Step = pEdge_Search_Config->stepCount; break; case DirectSign_DOWN: search_UP_DOWN = true; nSearchLen = roi.width; nCurPoint_Step = -pEdge_Search_Config->stepCount; sx = roi.x; ex = roi.x + roi.width; sy = roi.y + roi.height - 1; ey = roi.y; break; case DirectSign_Left: nSearchLen = roi.height; search_UP_DOWN = false; nCurPoint_Step = pEdge_Search_Config->stepCount; sx = roi.x; ex = roi.x + roi.width; sy = roi.y; ey = roi.y + roi.height; break; case DirectSign_Right: nSearchLen = roi.height; search_UP_DOWN = false; nCurPoint_Step = -pEdge_Search_Config->stepCount; sx = roi.x + roi.width - 1; ex = roi.x; sy = roi.y; ey = roi.y + roi.height; break; default: break; } // 搜索 点数 int nSearchPointNum = pEdge_Search_Config->nSearchCount; // 搜素点的间隔 int nSearchPointStep = 1; if (nSearchPointNum > 1) { nSearchPointStep = int(nSearchLen * 1.0f / (nSearchPointNum - 1)); } if (bdbuge) { cv::rectangle(showimg, roi, cv::Scalar(255, 0, 0), 2); printf("nSearchPointStep %d nCurPoint_Step %d,nrange_start %d %d\n", nSearchPointStep, nCurPoint_Step, nrange_start, nrange_end); } uchar *pdata = (uchar *)img.data; int offt = 0; // 搜索 上下边 if (search_UP_DOWN) { // 每个搜索点 分布在X方向。 for (int x = sx; x < ex; x = x + nSearchPointStep) { int bOKNum = 0; int cur_x = x; int cur_y = sy; bool bSucc = false; int succ_y = 0; // 对每个搜索点进行 y方向搜索 for (int y = sy;; y = y + nCurPoint_Step) { if (y < 0 || y >= img.rows) { continue; } // if (nCurPoint_Step > 0 && y > ey) { break; } if (nCurPoint_Step < 0 && y < ey) { break; } offt = y * img.cols; int range_okNum = 0; // 对一定范围的点进行判断 for (int k = nrange_start; k < nrange_end; k++) { int rangeX = x + k; if (rangeX < 0 || rangeX >= img.cols) { continue; } offt += rangeX; if (offt < 0 || offt >= img.cols * img.rows) { printf("rangeX %d nCurPoint_Step %d off %d x %d y %d sy %d ey %d %d %d\n", rangeX, nCurPoint_Step, offt, x, y, sy, ey, img.cols, img.rows); } if (pdata[offt] >= pEdge_Search_Config->nValueThreshold) // 找到 { range_okNum++; } } if (range_okNum >= pEdge_Search_Config->nSearchrange) { if (bdbuge) { cv::circle(showimg, cv::Point(x, y), 1, cv::Scalar(0, 0, 255)); } if (bOKNum == 0) { cur_y = y; } bOKNum++; // 连续搜索到 满足要求的点。 if (bOKNum >= pEdge_Search_Config->nLimit) { bSucc = true; succ_y = y; break; } } else { // 如果有间断,需要重新计算连续情况。 bOKNum = 0; if (bdbuge) { cv::circle(showimg, cv::Point(x, y), 1, cv::Scalar(0, 255, 0)); } } } if (bSucc) { cv::Point p(cur_x, cur_y); if (bdbuge) { cv::circle(showimg, p, 3, cv::Scalar(255, 0, 0)); } pointList.push_back(p); if (pointList.size() > 5) { // printf("=============feeeee\n"); sy = succ_y - 100; ey = succ_y + 100; if (sy < 0) { sy = 0; } if (ey >= img.rows) { ey = img.rows - 1; } } } } } else // 搜索 左右边 { // 每个搜索点 分布在X方向。 for (int y = sy; y < ey; y = y + nSearchPointStep) { int bOKNum = 0; int cur_x = sx; int cur_y = y; bool bSucc = false; int succ_x = 0; // 对每个搜索点进行 y方向搜索 for (int x = sx;; x = x + nCurPoint_Step) { if (x < 0 || x >= img.cols) { continue; } // if (nCurPoint_Step > 0 && x > ex) { break; } if (nCurPoint_Step < 0 && x < ex) { break; } int range_okNum = 0; // 对一定范围的点进行判断 for (int k = nrange_start; k < nrange_end; k++) { int rangey = y + k; if (rangey < 0 || rangey >= img.rows) { continue; } offt = rangey * img.cols + x; if (offt < 0 || offt >= img.cols * img.rows) { printf("rangey %d off %d x %d y %d ey %d %d %d\n", rangey, offt, x, y, ey, img.cols, img.rows); } if (pdata[offt] >= pEdge_Search_Config->nValueThreshold) // 找到 { range_okNum++; } } if (range_okNum >= pEdge_Search_Config->nSearchrange) { if (bdbuge) { cv::circle(showimg, cv::Point(x, y), 1, cv::Scalar(0, 0, 255)); } if (bOKNum == 0) { cur_x = x; } bOKNum++; // 连续搜索到 满足要求的点。 if (bOKNum >= pEdge_Search_Config->nLimit) { bSucc = true; succ_x = x; break; } } else { // 如果有间断,需要重新计算连续情况。 bOKNum = 0; if (bdbuge) { cv::circle(showimg, cv::Point(x, y), 1, cv::Scalar(0, 255, 0)); } } } if (bSucc) { cv::Point p(cur_x, cur_y); if (bdbuge) { cv::circle(showimg, p, 3, cv::Scalar(255, 0, 0)); } pointList.push_back(p); if (pointList.size() > 5) { // printf("=============feeeee\n"); sx = succ_x - 100; ex = succ_x + 100; if (sx < 0) { sx = 0; } if (ex >= img.cols) { ex = img.cols - 1; } } } } } if (bdbuge) { cv::imwrite(pEdge_Search_Config->strchannel + "show.png", showimg); } { const int maxDeviation = 10; // 可调阈值:最大允许偏离像素 std::vector avgPoints; int PNum = pointList.size(); // 第一次计算粗略均值 int sum_y = 0, sum_x = 0; for (const auto &pt : pointList) { sum_x += pt.x; sum_y += pt.y; } float avg_y = sum_y * 1.0f / PNum; float avg_x = sum_x * 1.0f / PNum; // 过滤异常点 std::vector filtered; for (const auto &pt : pointList) { if (search_UP_DOWN) // 横向:判断 y 偏差 { if (std::abs(pt.y - avg_y) <= maxDeviation) filtered.push_back(pt); } else // 纵向:判断 x 偏差 { if (std::abs(pt.x - avg_x) <= maxDeviation) filtered.push_back(pt); } } if (filtered.empty()) return -1; int sum_fx = 0, sum_fy = 0; for (const auto &pt : filtered) { sum_fx += pt.x; sum_fy += pt.y; } if (search_UP_DOWN) // 横向:判断 y 偏差 { outP = sum_fy / (int)filtered.size(); } else // 纵向:判断 x 偏差 { outP = sum_fx / (int)filtered.size(); } } return 0; } int CameraCheckAnalysisy::GetLine(const cv::Mat &img, std::vector &pointList, int lineNum, int xory, int &outP) { if (pointList.size() < 0) return -1; const int maxDeviation = 10; // 可调阈值:最大允许偏离像素 std::vector avgPoints; int PNum = pointList.size(); // 第一次计算粗略均值 int sum_y = 0, sum_x = 0; for (const auto &pt : pointList) { sum_x += pt.x; sum_y += pt.y; } float avg_y = sum_y * 1.0f / PNum; float avg_x = sum_x * 1.0f / PNum; // 过滤异常点 std::vector filtered; for (const auto &pt : pointList) { if (xory == 0) // 横向:判断 y 偏差 { if (std::abs(pt.y - avg_y) <= maxDeviation) filtered.push_back(pt); } else // 纵向:判断 x 偏差 { if (std::abs(pt.x - avg_x) <= maxDeviation) filtered.push_back(pt); } } if (filtered.empty()) return -1; int sum_fx = 0, sum_fy = 0; for (const auto &pt : filtered) { sum_fx += pt.x; sum_fy += pt.y; } if (xory == 0) // 横向:判断 y 偏差 { outP = sum_fy / (int)filtered.size(); } else // 纵向:判断 x 偏差 { outP = sum_fx / (int)filtered.size(); } return 0; }