From dad094bf0adab45eabd87c8bbf0da2cfed537c78 Mon Sep 17 00:00:00 2001 From: xiewenji <527774126@qq.com> Date: Mon, 17 Aug 2026 11:41:11 +0800 Subject: [PATCH] =?UTF-8?q?feat=20=E5=88=9D=E6=AD=A5=E6=B7=BB=E5=8A=A0Pin?= =?UTF-8?q?=E8=84=9A=E6=A3=80=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AlgorithmModule/include/Edge_QX_Det.h | 252 --- AlgorithmModule/include/ImgCheckAnalysisy.hpp | 8 +- AlgorithmModule/include/Pin_QX_Det.h | 213 +++ AlgorithmModule/src/AI_Edge_Algin.cpp | 16 +- AlgorithmModule/src/Edge_QX_Det.cpp | 1671 ----------------- AlgorithmModule/src/ImgCheckAnalysisy.cpp | 26 +- AlgorithmModule/src/Pin_QX_Det.cpp | 97 + ConfigModule/src/JsonConfig.cpp | 2 +- 8 files changed, 333 insertions(+), 1952 deletions(-) delete mode 100644 AlgorithmModule/include/Edge_QX_Det.h create mode 100644 AlgorithmModule/include/Pin_QX_Det.h delete mode 100644 AlgorithmModule/src/Edge_QX_Det.cpp create mode 100644 AlgorithmModule/src/Pin_QX_Det.cpp diff --git a/AlgorithmModule/include/Edge_QX_Det.h b/AlgorithmModule/include/Edge_QX_Det.h deleted file mode 100644 index 907f04e..0000000 --- a/AlgorithmModule/include/Edge_QX_Det.h +++ /dev/null @@ -1,252 +0,0 @@ -/* - * @Author: xiewenji 527774126@qq.com - * @Date: 2025-08-04 21:26:32 - * @LastEditors: xiewenji 527774126@qq.com - * @LastEditTime: 2025-08-13 16:05:08 - * @FilePath: /BOE_CELL_AOI/AlgorithmModule/include/Edge_QX_Det.h - * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE - */ -/* - * @Author: xiewenji 527774126@qq.com - * @Date: 2025-08-04 21:26:32 - * @LastEditors: xiewenji 527774126@qq.com - * @LastEditTime: 2025-08-04 21:29:05 - * @FilePath: /BOE_CELL_AOI/AlgorithmModule/include/Edge_QX_Det.h - * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE - */ -/* -//实现对部分缺陷 需要进行 数量 和距离上分析的 - */ -#ifndef Edge_QX_Det_H_ -#define Edge_QX_Det_H_ -#include - -#include "CheckErrorCodeDefine.hpp" -#include "ImageDetConfig.h" -#include "CheckConfigDefine.h" - -using namespace std; -using namespace cv; - -// 边缘缺陷检测 -class Edge_QX_Det -{ -public: - // 搜索方向 - enum Edge_DirectSign - { - DirectSign_UP, - DirectSign_DOWN, - DirectSign_Left, - DirectSign_Right, - }; - // 搜索边缘了下,黑还是白 - enum Search_Value_Type - { - Search_Value_White, - Search_Value_Black, - }; - // 边缘搜索参数 - struct Edge_Search_Config - { - cv::Rect roi; // 边缘搜索区域 - Search_Value_Type searchValueType; // 搜索边缘了下,黑还是白 - Edge_DirectSign directSign; // 搜索方向 - int nValueThreshold; // 灰度阈值 - int nSearchCount; // 搜索点的个数 把roi 均分成多少个点。 - int nSearchrange; // 搜索范围,一般为单数,如果 1表示 搜索当前点,如果3表示 除了当前点,还有左右 点。5表示 从-2到2 - int stepCount; // 每个搜索点的步数 - int nLimit; // 连续搜索多个满足阈值的点后,停止搜索,当前搜索点 搜索成功。 - std::string strchannel; - Edge_Search_Config() - { - roi = cv::Rect(0, 0, 0, 0); - directSign = DirectSign_UP; - searchValueType = Search_Value_White; - nValueThreshold = 40; - nSearchCount = 30; - nSearchrange = 1; - stepCount = 2; - nLimit = 3; - strchannel = ""; - } - bool CheckConfigValid() - { - bool bRet = true; - if (roi.width <= 0 || roi.height <= 0) - { - printf("s1 \n"); - return false; - } - if (searchValueType < Search_Value_White || searchValueType > Search_Value_Black) - { - printf("s2 \n"); - return false; - } - if (directSign < 0 || directSign > 4) - { - printf("s3 \n"); - return false; - } - if (nValueThreshold < 0 || nValueThreshold > 255) - { - printf("s4 \n"); - return false; - } - if (nSearchCount < 0) - { - printf("s5 \n"); - return false; - } - if (stepCount < 0) - { - printf("s6 \n"); - return false; - } - if (nLimit < 0) - { - printf("s7 \n"); - return false; - } - return true; - } - }; - struct Line - { - cv::Point p1; - cv::Point p2; - Line() - { - p1 = cv::Point(0, 0); - p2 = cv::Point(0, 0); - } - }; - struct QX_Result - { - cv::Rect roi_src; - int area_pixel; - QX_Result() - { - roi_src = cv::Rect(0, 0, 0, 0); - area_pixel = 0; - } - }; - // 检测小区域的信息 - struct Det_ROI_Config - { - cv::Rect roi; - std::vector plist; - }; - struct Algin_Result - { - cv::Rect corpRoi; - int offtx; - int offty; - cv::Mat H; - Algin_Result() - { - Init(); - } - void Init() - { - corpRoi = cv::Rect(0, 0, 0, 0); - offtx = 0; - offty = 0; - if (!H.empty()) - { - H.release(); - } - - } - /* data */ - }; - - // 检测参数和结果 - struct DetConfigResult - { - - BaseCheckFunction *pBaseCheckFunction; - std::string strChannel; - std::vector qx_result; - std::vector edge_det_roi; - Algin_Result alginResult; - - std::vector Det_region; - bool bSaveResultImg; - DetConfigResult() - { - Init(); - } - void Init() - { - pBaseCheckFunction = NULL; - strChannel = ""; - qx_result.clear(); - edge_det_roi.clear(); - alginResult.Init(); - Det_region.clear(); - bSaveResultImg = false; - } - }; - - enum Det_ROI_Type - { - Det_ROI_Type_UP, - Det_ROI_Type_DOWN, - Det_ROI_Type_LEFT, - Det_ROI_Type_RIGHT, - }; - -public: - bool GetSegmentIntersection(const Line &l1, const Line &l2, cv::Point2f &intersection); - Edge_QX_Det(/* args */); - ~Edge_QX_Det(); - - int Detect(const cv::Mat &img, DetConfigResult *pDetConfig); - -private: - // 边缘点搜索函数 - int GetEdgePoint(const cv::Mat &img, Edge_Search_Config *pEdge_Search_Config, std::vector &pointList); - - int GetLine(const cv::Mat &img, std::vector &pointList, int lineNum, int xory, std::vector &lineList); - - // 检测缺陷 - int Det_qx(const cv::Mat &img, std::vector roilist, Det_ROI_Type type, DetConfigResult *pDetConfig); - - int applyMaskInROI(const cv::Mat &grayImg, const Det_ROI_Config &config, cv::Mat &result, int threshold); - - // 通过手绘的方式来检测 - int Draw_Det(const cv::Mat &img, DetConfigResult *pDetConfig); - -private: - /// @brief - /// @param img 搜到图片 单通道 - /// @param DirectSign 搜索方向 >0 正向,< 0 反向 - /// @param Gate 阈值 - /// @param BorW 搜索黑点 = 0还是白点 = 1 - /// @param roi 搜索范围 - /// @param StepCount 搜索点数 - /// @param Limit 最小满是阈值点个数算上搜索成功 - /// @return <0 搜索错误, >=0表示 搜索位置 - int UDNoiseEdgeDetect(cv::Mat img, int DirectSign, int Gate, int BorW, cv::Rect roi, int StepCount, int Limit); - /// @brief - /// @param img 搜到图片 单通道 - /// @param DirectSign 搜索方向 >0 正向,< 0 反向 - /// @param Gate 阈值 - /// @param BorW 搜索黑点 = 0还是白点 = 1 - /// @param roi 搜索范围 - /// @param StepCount 搜索点数 - /// @param Limit 最小满是阈值点个数算上搜索成功 - /// @return <0 搜索错误, >=0表示 搜索位置 - int LRNoiseEdgeDetect(cv::Mat img, int DirectSign, int Gate, int BorW, cv::Rect roi, int StepCount, int Limit); - // int LRNoiseEdgeDetect(cv::Mat img,int DirectSign, int Gate,int BorW, int StartSearchSite, int Step, int StepCount, int top, int bottom, int Limit, int Depth, int MaxLimit); - -private: - cv::Mat showimg; - bool bshowimg; - -private: - /* data */ -}; - -#endif \ No newline at end of file diff --git a/AlgorithmModule/include/ImgCheckAnalysisy.hpp b/AlgorithmModule/include/ImgCheckAnalysisy.hpp index 77d934c..8ab1107 100644 --- a/AlgorithmModule/include/ImgCheckAnalysisy.hpp +++ b/AlgorithmModule/include/ImgCheckAnalysisy.hpp @@ -31,7 +31,7 @@ #include "ImageDetConfig.h" #include "OtherDetect.h" #include "Define_Error.h" -#include "Edge_QX_Det.h" +#include "Pin_QX_Det.h" #include "AI_Edge_Algin.h" #include "AI_Factory.h" #include "ImageAllResult.h" @@ -189,7 +189,7 @@ private: int UpdateImgageScale(); // 边缘缺陷检测 - int Edge_Qx_Det(const cv::Mat &img); + int Pin_Qx_Det(const cv::Mat &img); // 把blob 汇总成 检测结果。 int BLobToDetResult(); @@ -256,8 +256,8 @@ private: // 边缘定位结果 std::shared_ptr m_pEdge_Align_Result; - Edge_QX_Det m_Edge_QX_Det; - Edge_QX_Det::DetConfigResult m_Edge_DetConfig; + Pin_QX_Det m_Pin_QX_Det; + Pin_QX_Det::DetConfigResult m_Edge_DetConfig; std::vector m_Draw_qxImageResult; // 缺陷小图结果 std::vector SmallRoiList; diff --git a/AlgorithmModule/include/Pin_QX_Det.h b/AlgorithmModule/include/Pin_QX_Det.h new file mode 100644 index 0000000..1cc7370 --- /dev/null +++ b/AlgorithmModule/include/Pin_QX_Det.h @@ -0,0 +1,213 @@ +/* + * @Author: xiewenji 527774126@qq.com + * @Date: 2025-08-04 21:26:32 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-08-13 16:05:08 + * @FilePath: /BOE_CELL_AOI/AlgorithmModule/include/Pin_QX_Det.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +/* + * @Author: xiewenji 527774126@qq.com + * @Date: 2025-08-04 21:26:32 + * @LastEditors: xiewenji 527774126@qq.com + * @LastEditTime: 2025-08-04 21:29:05 + * @FilePath: /BOE_CELL_AOI/AlgorithmModule/include/Pin_QX_Det.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +/* +//实现对部分缺陷 需要进行 数量 和距离上分析的 + */ +#ifndef Pin_QX_Det_H_ +#define Pin_QX_Det_H_ +#include + +#include +#include "CheckUtil.hpp" +#include "OtherDetBaseDefine.h" +#include "CheckErrorCodeDefine.hpp" +#include "ImageDetConfig.h" +#include "CheckConfigDefine.h" +#include "ImageStorage.h" +#include "AI_Factory.h" +#include "DetLog.h" + +using namespace std; +using namespace cv; + +// Pin脚缺陷检测 +class Pin_QX_Det +{ +public: + struct QX_Result + { + cv::Rect roi_src; + int area_pixel; + QX_Result() + { + roi_src = cv::Rect(0, 0, 0, 0); + area_pixel = 0; + } + }; + struct Det_ROI_Config + { + cv::Rect roi; + std::vector plist; + }; + // 检测参数和结果 + struct DetConfigResult + { + + BaseCheckFunction *pBaseCheckFunction; + std::string strChannel; + std::vector qx_result; + std::vector pin_det_roi; + + std::vector Det_region; + bool bSaveResultImg; + DetConfigResult() + { + Init(); + } + void Init() + { + pBaseCheckFunction = NULL; + strChannel = ""; + qx_result.clear(); + pin_det_roi.clear(); + Det_region.clear(); + bSaveResultImg = false; + } + }; + + enum Det_ROI_Type + { + Det_ROI_Type_UP, + Det_ROI_Type_DOWN, + Det_ROI_Type_LEFT, + Det_ROI_Type_RIGHT, + }; + + // 边缘搜索定位结果 + struct Pin_AI_Result + { + int nresult; + cv::RotatedRect bigroi; + cv::RotatedRect smallroi; + bool buseOfft; + int offt_x; + int offt_y; + cv::Mat H; + + Pin_AI_Result() + { + Init(); + } + void Init() + { + buseOfft = false; + nresult = 0; + offt_x = 0; + offt_y = 0; + bigroi = cv::RotatedRect(cv::Point2f(0, 0), cv::Size2f(0, 0), 0); + smallroi = cv::RotatedRect(cv::Point2f(0, 0), cv::Size2f(0, 0), 0); + if (!H.empty()) + { + H.release(); + /* code */ + } + } + }; + + enum SaveProcessType + { + Save_Close, // 不保存 + Save_Filter, // 过滤的 + Save_ALL, // 全部 + }; + struct DetConfig + { + int ncamId; // 相机ID + BaseCheckFunction *pBaseCheckFunction; + std::string strChannel; // 通道 + int nthresholdvalue; // 背景阈值 + int nAIErodesize; // 边缘腐蚀强度 + bool bSaveResultImg; // 保存结果图片 + SaveProcessType saveProcessImg; // 保存过程图片 + bool bUseDrawRoi_Check; // 是否用绘制的ROI进行校验 + cv::Rect drawRoi; // 绘制的 ROi; + cv::Mat drawMask; // 绘制的maksk + DetConfig() + { + Init(); + } + void Init() + { + pBaseCheckFunction = NULL; + ncamId = 0; + nthresholdvalue = 1; + nAIErodesize = 7; + bSaveResultImg = false; + saveProcessImg = Save_Close; + bUseDrawRoi_Check = false; + drawRoi = cv::Rect(0, 0, 0, 0); + if (!drawMask.empty()) + { + drawMask.release(); + /* code */ + } + } + void Print() + { + printf("nthresholdvalue:%d;nAIErodesize %d;bSaveResultImg %s SaveProcessImg %d\n", + nthresholdvalue, nAIErodesize, BOOL_TO_STR(bSaveResultImg), saveProcessImg); + + printf("bUseDrawRoi_Check %s roi %s \n", + BOOL_TO_STR(bUseDrawRoi_Check), CheckUtil::GetRectString(drawRoi).c_str()); + } + bool IsSaveProcessImg() + { + if (saveProcessImg != Save_Close) + { + return true; + } + + return false; + } + }; + +public: + Pin_QX_Det(std::shared_ptr& log_ref); + ~Pin_QX_Det(); + + int Detect(const cv::Mat &img, DetConfigResult *pDetConfig); + +private: + int InitModel_Pin(); + int creatsavedir(); + +private: + bool m_bInitSucc; // 是否初始化成功 + // 检测结果 + std::shared_ptr m_pCheckResult_Pin; + + std::shared_ptr& m_pdetlog; + + bool m_bInitialized; + bool m_bModelSucc; + bool m_bModel_Mark_Succ; + + bool m_bshowimg; + cv::Mat showimg; + std::string m_strRootPath_Pin; + std::string m_strSavePath_Pin; + std::string m_strLastDate; + + ImageStorage *m_pImageStorage; + + std::shared_ptr AI_Factory; + +private: + /* data */ +}; + +#endif \ No newline at end of file diff --git a/AlgorithmModule/src/AI_Edge_Algin.cpp b/AlgorithmModule/src/AI_Edge_Algin.cpp index 5023df3..f7d5732 100644 --- a/AlgorithmModule/src/AI_Edge_Algin.cpp +++ b/AlgorithmModule/src/AI_Edge_Algin.cpp @@ -332,22 +332,22 @@ int AI_Edge_Algin::InitModel_ALL() int AI_Edge_Algin::Get_Edge(int AIModel_type, const cv::Mat &img, DetConfig *pDetConfig, std::string strChannel, cv::RotatedRect &Roi) { - std::shared_ptr pCELL_Align_Outer; + std::shared_ptr pSocket_Align; switch (AIModel_type) { case 0: - pCELL_Align_Outer = AI_Factory->Align_Outer; + pSocket_Align = AI_Factory->Align_Outer; break; case 1: - pCELL_Align_Outer = AI_Factory->Align_Inner; + pSocket_Align = AI_Factory->Align_Inner; break; default: - pCELL_Align_Outer = AI_Factory->Align_Outer; + pSocket_Align = AI_Factory->Align_Outer; break; } cv::Size sz; - sz.width = pCELL_Align_Outer->input_0.width; - sz.height = pCELL_Align_Outer->input_0.height; + sz.width = pSocket_Align->input_0.width; + sz.height = pSocket_Align->input_0.height; cv::Mat detImg; cout<< pDetConfig->strChannel << ": " << "---Get_Edge-resize-" << to_string(AIModel_type) <<"-- "; cout << "imgSize: " << img.size() << ", " << "detImgSize: " << detImg.size() << ", " << "szSize: " << sz << endl; @@ -360,7 +360,7 @@ int AI_Edge_Algin::Get_Edge(int AIModel_type, const cv::Mat &img, DetConfig *pDe cv::cvtColor(detImg, detImg, cv::COLOR_RGB2GRAY); } - re = pCELL_Align_Outer->AIDet(detImg, mask); + re = pSocket_Align->AIDet(detImg, mask); if (re != 0) { m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "AI_Edge_Algin ", "AICheck_Edge_%d----error %d ", AIModel_type, re); @@ -387,7 +387,7 @@ int AI_Edge_Algin::Get_Edge(int AIModel_type, const cv::Mat &img, DetConfig *pDe } } - // if (m_pDetConfig->bSaveResultImg) + if (m_pDetConfig->bSaveResultImg) { cv::imwrite(strChannel +"_edge_"+ to_string(AIModel_type) +"_in.png", detImg); cv::imwrite(strChannel +"_edge_"+ to_string(AIModel_type) +"_out_mask.png", mask); diff --git a/AlgorithmModule/src/Edge_QX_Det.cpp b/AlgorithmModule/src/Edge_QX_Det.cpp deleted file mode 100644 index ca1f0a2..0000000 --- a/AlgorithmModule/src/Edge_QX_Det.cpp +++ /dev/null @@ -1,1671 +0,0 @@ - -#include "Edge_QX_Det.h" -#include -#include -// 计算平均值 -double computeAverage123(const std::vector &data) -{ - return std::accumulate(data.begin(), data.end(), 0.0) / data.size(); -} - -// 剔除异常数据,这里以平均值加减两倍标准差为界限 -std::vector removeOutliers123(const std::vector &data) -{ - double mean = computeAverage123(data); - double sq_sum = std::inner_product(data.begin(), data.end(), data.begin(), 0.0); - double stdev = std::sqrt(sq_sum / data.size() - mean * mean); - std::vector filteredData; - for (double value : data) - { - if (std::abs(value - mean) <= 2 * stdev) - { // 可以根据需要调整异常值判断的标准 - filteredData.push_back(value); - } - } - return filteredData; -} -// 计算点到直线距离 -float pointToLineDistance(const cv::Point &pt, const cv::Vec4f &line) -{ - float vx = line[0], vy = line[1], x0 = line[2], y0 = line[3]; - float x = pt.x, y = pt.y; - return std::abs(vy * x - vx * y + (vx * y0 - vy * x0)) / std::sqrt(vx * vx + vy * vy); -} -bool FitLineWithOutlierRemoval(const std::vector &inputPoints, cv::Vec4f &outputLine, int ransacIters = 100, float inlierThresh = 10) -{ - if (inputPoints.size() < 2) - return false; - - int bestInliers = 0; - std::vector bestInlierPoints; - - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution<> dis(0, inputPoints.size() - 1); - - for (int i = 0; i < ransacIters; ++i) - { - int idx1 = dis(gen); - int idx2 = dis(gen); - if (idx1 == idx2) - continue; - - cv::Point p1 = inputPoints[idx1]; - cv::Point p2 = inputPoints[idx2]; - if (p1 == p2) - continue; - - cv::Vec4f tempLine; - tempLine[0] = p2.x - p1.x; - tempLine[1] = p2.y - p1.y; - tempLine[2] = p1.x; - tempLine[3] = p1.y; - - std::vector inliers; - for (const auto &pt : inputPoints) - { - float dist = std::abs(tempLine[1] * pt.x - tempLine[0] * pt.y + tempLine[0] * tempLine[3] - tempLine[1] * tempLine[2]) / - std::sqrt(tempLine[0] * tempLine[0] + tempLine[1] * tempLine[1]); - if (dist < inlierThresh) - inliers.push_back(pt); - } - - if (inliers.size() > bestInliers) - { - bestInliers = inliers.size(); - bestInlierPoints = inliers; - } - } - - if (bestInlierPoints.size() < 2) - return false; - - cv::fitLine(bestInlierPoints, outputLine, cv::DIST_L2, 0, 0.01, 0.01); - return true; -} - -void drawFittedLine(cv::Mat &image, const cv::Vec4f &line, const cv::Scalar &color, int thickness = 2) -{ - double scale = std::max(image.cols, image.rows) * 2.0; - cv::Point2f pt0(line[2], line[3]); // 起点 - cv::Point2f dir(line[0], line[1]); // 方向向量 - cv::Point2f pt1 = pt0 + scale * dir; // 向正方向延伸 - cv::Point2f pt2 = pt0 - scale * dir; // 向反方向延伸 - cv::line(image, pt1, pt2, color, thickness); // 绘制直线 -} - -// 计算两条直线的交点,返回是否成功 -bool GetLineIntersection(const cv::Vec4f &line1, const cv::Vec4f &line2, cv::Point2f &intersection) -{ - float vx1 = line1[0], vy1 = line1[1], x1 = line1[2], y1 = line1[3]; - float vx2 = line2[0], vy2 = line2[1], x2 = line2[2], y2 = line2[3]; - - // 解: (x1 + t1 * vx1, y1 + t1 * vy1) == (x2 + t2 * vx2, y2 + t2 * vy2) - // 即:解 t1 和 t2 联立方程 - - float det = vx1 * vy2 - vy1 * vx2; - - if (std::abs(det) < 1e-6) - { - // 平行或重合 - return false; - } - - float dx = x2 - x1; - float dy = y2 - y1; - float t = (dx * vy2 - dy * vx2) / det; - - intersection.x = x1 + t * vx1; - intersection.y = y1 + t * vy1; - return true; -} -bool Edge_QX_Det::GetSegmentIntersection(const Line &l1, const Line &l2, cv::Point2f &intersection) -{ - cv::Point2f p = l1.p1; - cv::Point2f r = l1.p2 - l1.p1; - cv::Point2f q = l2.p1; - cv::Point2f s = l2.p2 - l2.p1; - - float rxs = r.x * s.y - r.y * s.x; - - if (std::abs(rxs) < 1e-6) - return false; // 平行或重合 - - float t = ((q - p).x * s.y - (q - p).y * s.x) / rxs; - float u = ((q - p).x * r.y - (q - p).y * r.x) / rxs; - - if (t >= 0 && t <= 1 && u >= 0 && u <= 1) - { - intersection = p + t * r; - return true; - } - - return false; -} - -Edge_QX_Det::Edge_QX_Det() -{ - bshowimg = false; -} -Edge_QX_Det::~Edge_QX_Det() -{ -} -int Edge_QX_Det::Detect(const cv::Mat &img, DetConfigResult *pDetConfig) -{ - if (!pDetConfig->pBaseCheckFunction->edgeDet.bOpen) - { - return 0; - } - if (pDetConfig->pBaseCheckFunction->edgeDet.bDrawRoi) - { - return Draw_Det(img, pDetConfig); - } - - // if (pDetConfig->strChannel == "TA") - // { - // return 0; - // } - bshowimg = false; - if (pDetConfig->bSaveResultImg) - { - bshowimg = true; - } - bool bdetSucc = false; - - if (bshowimg) - { - cv::cvtColor(img, showimg, cv::COLOR_GRAY2BGR); - } - cv::Rect roi; - // printf("Edge_QX_Det::Detect\n"); - - // getchar(); - std::vector up_edge; - std::vector Up_line; - Edge_Search_Config config; - config.nSearchCount = 300; - config.strchannel = pDetConfig->strChannel; - config.directSign = DirectSign_UP; - config.roi = cv::Rect(0, 0, img.cols, 600); - int re123 = GetEdgePoint(img, &config, up_edge); - if (re123 != 0) - { - return 1; - } - - { - re123 = GetLine(img, up_edge, 30, 0, Up_line); - if (re123 != 0) - { - return 1; - } - } - // printf("DirectSign_UP::111111111111111111 re123 %d\n", re123); - - std::vector down_edge; - std::vector down_line; - config.directSign = DirectSign_DOWN; - config.roi = cv::Rect(0, img.rows - 600, img.cols, 600); - re123 = GetEdgePoint(img, &config, down_edge); - - if (re123 != 0) - { - return 1; - } - { - re123 = GetLine(img, down_edge, 30, 0, down_line); - if (re123 != 0) - { - return 1; - } - } - // printf("DirectSign_DOWN::111111111111111111 re123 %d\n", re123); - - std::vector left_edge; - std::vector left_line; - config.directSign = DirectSign_Left; - config.roi = cv::Rect(0, 0, 600, img.rows); - re123 = GetEdgePoint(img, &config, left_edge); - - if (re123 != 0) - { - return 1; - } - { - re123 = GetLine(img, left_edge, 15, 1, left_line); - if (re123 != 0) - { - return 1; - } - } - // printf("DirectSign_Left::111111111111111111 re123 %d\n", re123); - - std::vector right_edge; - std::vector right_line; - config.directSign = DirectSign_Right; - config.roi = cv::Rect(img.cols - 600, 0, 600, img.rows); - re123 = GetEdgePoint(img, &config, right_edge); - - if (re123 != 0) - { - return 1; - } - { - re123 = GetLine(img, right_edge, 15, 1, right_line); - if (re123 != 0) - { - return 1; - } - } - // printf("DirectSign_Right::111111111111111111 re123 %d\n", re123); - - // 求交点 - std::vector cornerPoints; - cv::Point2f pt; - - // 左上角:Up_line[0] 与 Left_line[0] - if (GetSegmentIntersection(Up_line[0], left_line[0], pt)) - { - pt.x += 10; - pt.y += 10; - cornerPoints.push_back(pt); - Up_line[0].p1 = pt; - left_line[0].p1 = pt; - } - - else - return 1; - - // 右上角:Up_line.back() 与 Right_line[0] - if (GetSegmentIntersection(Up_line.back(), right_line[0], pt)) - { - pt.x -= 10; - pt.y += 10; - cornerPoints.push_back(pt); - Up_line.back().p2 = pt; - right_line[0].p1 = pt; - } - else - return 1; - - // 右下角:Down_line.back() 与 Right_line.back() - if (GetSegmentIntersection(down_line.back(), right_line.back(), pt)) - { - pt.x -= 10; - pt.y -= 10; - cornerPoints.push_back(pt); - down_line.back().p2 = pt; - right_line.back().p2 = pt; - } - else - return 1; - - // 左下角:Down_line[0] 与 Left_line.back() - if (GetSegmentIntersection(down_line[0], left_line.back(), pt)) - { - pt.x += 10; - pt.y -= 10; - cornerPoints.push_back(pt); - down_line[0].p1 = pt; - left_line.back().p2 = pt; - } - else - return 1; - - // 生成 检测的 roi。 - int roi_wh = pDetConfig->pBaseCheckFunction->edgeDet.Det_Range; - - std::vector up_det_roi; - std::vector down_det_roi; - std::vector left_det_roi; - std::vector right_det_roi; - for (const auto &line : Up_line) - { - Det_ROI_Config tem; - tem.plist.push_back(line.p1); - tem.plist.push_back(line.p2); - - tem.plist.push_back(cv::Point(line.p2.x, line.p2.y + roi_wh)); - tem.plist.push_back(cv::Point(line.p1.x, line.p1.y + roi_wh)); - tem.roi = cv::boundingRect(tem.plist); - pDetConfig->edge_det_roi.push_back(tem); - up_det_roi.push_back(tem); - } - for (const auto &line : down_line) - { - Det_ROI_Config tem; - tem.plist.push_back(line.p1); - tem.plist.push_back(line.p2); - tem.plist.push_back(cv::Point(line.p2.x, line.p2.y - roi_wh)); - tem.plist.push_back(cv::Point(line.p1.x, line.p1.y - roi_wh)); - - tem.roi = cv::boundingRect(tem.plist); - pDetConfig->edge_det_roi.push_back(tem); - down_det_roi.push_back(tem); - } - for (const auto &line : left_line) - { - Det_ROI_Config tem; - tem.plist.push_back(line.p1); - tem.plist.push_back(line.p2); - tem.plist.push_back(cv::Point(line.p2.x + roi_wh, line.p2.y)); - tem.plist.push_back(cv::Point(line.p1.x + roi_wh, line.p1.y)); - - tem.roi = cv::boundingRect(tem.plist); - pDetConfig->edge_det_roi.push_back(tem); - left_det_roi.push_back(tem); - } - for (const auto &line : right_line) - { - Det_ROI_Config tem; - tem.plist.push_back(line.p1); - tem.plist.push_back(line.p2); - tem.plist.push_back(cv::Point(line.p2.x - roi_wh, line.p2.y)); - tem.plist.push_back(cv::Point(line.p1.x - roi_wh, line.p1.y)); - - tem.roi = cv::boundingRect(tem.plist); - pDetConfig->edge_det_roi.push_back(tem); - right_det_roi.push_back(tem); - } - // 检测缺陷 - Det_qx(img, up_det_roi, Det_ROI_Type_UP, pDetConfig); - Det_qx(img, down_det_roi, Det_ROI_Type_DOWN, pDetConfig); - Det_qx(img, left_det_roi, Det_ROI_Type_LEFT, pDetConfig); - Det_qx(img, right_det_roi, Det_ROI_Type_RIGHT, pDetConfig); - - if (bshowimg) - { - for (const auto &pt : cornerPoints) - { - cv::circle(showimg, pt, 5, cv::Scalar(0, 255, 255), -1); // 黄色角点 - } - - for (const auto &line : Up_line) - { - cv::line(showimg, line.p1, line.p2, cv::Scalar(255, 0, 0)); - cv::circle(showimg, line.p1, 4, cv::Scalar(0, 255, 255)); - cv::circle(showimg, line.p2, 4, cv::Scalar(0, 255, 255)); - } - for (const auto &line : down_line) - { - cv::line(showimg, line.p1, line.p2, cv::Scalar(255, 0, 0)); - cv::circle(showimg, line.p1, 4, cv::Scalar(0, 255, 255)); - cv::circle(showimg, line.p2, 4, cv::Scalar(0, 255, 255)); - } - for (const auto &line : left_line) - { - cv::line(showimg, line.p1, line.p2, cv::Scalar(255, 0, 0)); - cv::circle(showimg, line.p1, 4, cv::Scalar(0, 255, 255)); - cv::circle(showimg, line.p2, 4, cv::Scalar(0, 255, 255)); - } - for (const auto &line : right_line) - { - cv::line(showimg, line.p1, line.p2, cv::Scalar(255, 0, 0)); - cv::circle(showimg, line.p1, 4, cv::Scalar(0, 255, 255)); - cv::circle(showimg, line.p2, 4, cv::Scalar(0, 255, 255)); - } - for (auto p : up_edge) - { - cv::circle(showimg, p, 2, cv::Scalar(0, 255, 0)); - } - for (auto p : down_edge) - { - cv::circle(showimg, p, 2, cv::Scalar(0, 255, 0)); - } - for (auto p : left_edge) - { - cv::circle(showimg, p, 2, cv::Scalar(0, 255, 0)); - } - for (auto p : right_edge) - { - cv::circle(showimg, p, 2, cv::Scalar(0, 255, 0)); - } - for (const auto &r : pDetConfig->edge_det_roi) - { - cv::rectangle(showimg, r.roi, cv::Scalar(255, 0, 255), 3); // 黄色角点 - } - for (const auto r : pDetConfig->qx_result) - { - cv::rectangle(showimg, r.roi_src, cv::Scalar(255, 22, 100), 3); // 黄色角点 - } - - cv::imwrite(pDetConfig->strChannel + "_edge_show.png", showimg); - } - // printf("=================end==================\n"); - // getchar(); - - return 0; -} - -int Edge_QX_Det::GetEdgePoint(const cv::Mat &img, Edge_Search_Config *pEdge_Search_Config, std::vector &pointList) -{ - - bool bdbuge = false; - // bdbuge = bshowimg; - if (img.empty()) - { - return -11; - } - if (img.channels() != 1) - { - printf("*****************************channels\n"); - - return -12; - } - // 检查roi; - if (!CheckUtil::RoiInImg(pEdge_Search_Config->roi, img)) - { - return -13; - } - if (!pEdge_Search_Config->CheckConfigValid()) - { - return -14; - } - - 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; - - // 对每个搜索点进行 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; - 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); - } - } - } - 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; - - // 对每个搜索点进行 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; - 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 (bdbuge) - { - cv::imwrite(pEdge_Search_Config->strchannel + "show.png", showimg); - } - - // getchar(); - - return 0; -} - -int Edge_QX_Det::GetLine(const cv::Mat &img, std::vector &pointList, int lineNum, int xory, std::vector &lineList) -{ - - lineList.clear(); - - if (pointList.size() < lineNum || lineNum <= 0) - return -1; - - const int maxDeviation = 10; // 可调阈值:最大允许偏离像素 - - std::vector avgPoints; - - size_t i = 0; - for (; i + lineNum <= pointList.size(); i += lineNum) - { - std::vector group(pointList.begin() + i, pointList.begin() + i + lineNum); - - // 第一次计算粗略均值 - int sum_y = 0, sum_x = 0; - for (const auto &pt : group) - { - sum_x += pt.x; - sum_y += pt.y; - } - float avg_y = sum_y * 1.0f / lineNum; - float avg_x = sum_x * 1.0f / lineNum; - - // 过滤异常点 - std::vector filtered; - for (const auto &pt : group) - { - 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()) - continue; // 本组全是异常点,跳过 - - // 用过滤后的点重新计算平均 - int sum_fx = 0, sum_fy = 0; - for (const auto &pt : filtered) - { - sum_fx += pt.x; - sum_fy += pt.y; - } - avgPoints.emplace_back(sum_fx / (int)filtered.size(), sum_fy / (int)filtered.size()); - } - - // 末尾不足 lineNum,用最后 lineNum 个点 - if (pointList.size() % lineNum != 0 && pointList.size() >= lineNum) - { - size_t start = pointList.size() - lineNum; - std::vector group(pointList.begin() + start, pointList.end()); - - int sum_x = 0, sum_y = 0; - for (const auto &pt : group) - { - sum_x += pt.x; - sum_y += pt.y; - } - float avg_y = sum_y * 1.0f / lineNum; - float avg_x = sum_x * 1.0f / lineNum; - - // 过滤异常点 - std::vector filtered; - for (const auto &pt : group) - { - if (xory == 0) - { - if (std::abs(pt.y - avg_y) <= maxDeviation) - filtered.push_back(pt); - } - else - { - if (std::abs(pt.x - avg_x) <= maxDeviation) - filtered.push_back(pt); - } - } - - if (!filtered.empty()) - { - int sum_fx = 0, sum_fy = 0; - for (const auto &pt : filtered) - { - sum_fx += pt.x; - sum_fy += pt.y; - } - avgPoints.emplace_back(sum_fx / (int)filtered.size(), sum_fy / (int)filtered.size()); - } - } - - if (avgPoints.empty()) - return -2; - - // 构建线段(起点终点规则) - if (xory == 0) - { - Line first; - first.p1 = cv::Point(0, avgPoints[0].y); - first.p2 = avgPoints[0]; - lineList.push_back(first); - - for (size_t k = 0; k + 1 < avgPoints.size(); ++k) - { - Line mid; - mid.p1 = avgPoints[k]; - mid.p2 = avgPoints[k + 1]; - lineList.push_back(mid); - } - - Line last; - last.p1 = avgPoints.back(); - last.p2 = cv::Point(img.cols, avgPoints.back().y); - lineList.push_back(last); - } - else - { - Line first; - first.p1 = cv::Point(avgPoints[0].x, 0); - first.p2 = avgPoints[0]; - lineList.push_back(first); - - for (size_t k = 0; k + 1 < avgPoints.size(); ++k) - { - Line mid; - mid.p1 = avgPoints[k]; - mid.p2 = avgPoints[k + 1]; - lineList.push_back(mid); - } - - Line last; - last.p1 = avgPoints.back(); - last.p2 = cv::Point(avgPoints.back().x, img.rows); - lineList.push_back(last); - } - - return 0; -} - -int Edge_QX_Det::Det_qx(const cv::Mat &img, std::vector roilist, Det_ROI_Type type, DetConfigResult *pDetConfig) -{ - if (img.empty()) - { - return -11; - } - if (img.channels() != 1) - { - printf("*****************************channels\n"); - return -12; - } - Base_Function_Edge_Det *pedgeDet = &pDetConfig->pBaseCheckFunction->edgeDet; - vector allPoints; - - for (const auto &ROI : roilist) - { - allPoints.insert(allPoints.end(), ROI.plist.begin(), ROI.plist.end()); - } - if (allPoints.size() <= 0) - { - return 1; - } - cv::Rect DetRoi = cv::boundingRect(allPoints); - cv::Mat roiMask = cv::Mat::zeros(DetRoi.height, DetRoi.width, CV_8UC1); - - for (const auto &ROI : roilist) - { - cv::Mat mask; - applyMaskInROI(img, ROI, mask, pedgeDet->Det_threshold); - cv::Rect detimg_roi; - detimg_roi.x = ROI.roi.x - DetRoi.x; - detimg_roi.y = ROI.roi.y - DetRoi.y; - detimg_roi.width = ROI.roi.width; - detimg_roi.height = ROI.roi.height; - mask.copyTo(roiMask(detimg_roi), mask); - } - int erx = pedgeDet->QX_Widht_min; - int ery = pedgeDet->QX_Height_min; - if (erx < 3) - { - erx = 3; - } - if (ery < 3) - { - ery = 3; - } - - cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(erx, ery)); - - // 进行开操作(先腐蚀后膨胀)可以去除小白点 - cv::morphologyEx(roiMask, roiMask, cv::MORPH_OPEN, kernel); - // cv::imwrite("detimg.png", img(DetRoi)); - // cv::imwrite("detimg_mask.png", roiMask); - // getchar(); - - bool jiao_f_1 = false; - bool jiao_f_2 = false; - cv::Point jiao_p_1; - cv::Point jiao_p_2; - if (type == Det_ROI_Type_UP) - { - jiao_f_1 = pDetConfig->pBaseCheckFunction->edgeDet.queJiao_LU_Open; - jiao_f_2 = pDetConfig->pBaseCheckFunction->edgeDet.queJiao_RU_Open; - jiao_p_1 = cv::Point(0, 0); - jiao_p_2 = cv::Point(roiMask.cols, 0); - } - else if (type == Det_ROI_Type_DOWN) - { - jiao_f_1 = pDetConfig->pBaseCheckFunction->edgeDet.queJiao_LD_Open; - jiao_f_2 = pDetConfig->pBaseCheckFunction->edgeDet.queJiao_RD_Open; - jiao_p_1 = cv::Point(0, roiMask.rows); - jiao_p_2 = cv::Point(roiMask.cols, roiMask.rows); - } - else if (type == Det_ROI_Type_LEFT) - { - jiao_f_1 = pDetConfig->pBaseCheckFunction->edgeDet.queJiao_LU_Open; - jiao_f_2 = pDetConfig->pBaseCheckFunction->edgeDet.queJiao_LD_Open; - - jiao_p_1 = cv::Point(0, 0); - jiao_p_2 = cv::Point(0, roiMask.rows); - } - else if (type == Det_ROI_Type_RIGHT) - { - jiao_f_1 = pDetConfig->pBaseCheckFunction->edgeDet.queJiao_RU_Open; - jiao_f_2 = pDetConfig->pBaseCheckFunction->edgeDet.queJiao_RU_Open; - jiao_p_1 = cv::Point(roiMask.cols, 0); - jiao_p_2 = cv::Point(roiMask.cols, roiMask.rows); - } - - // 寻找轮廓 - vector> contours; - cv::findContours(roiMask, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); - - // 找到最大面积的轮廓 - double maxArea = -1; - int maxAreaIdx = -1; - for (size_t i = 0; i < contours.size(); ++i) - { - cv::Rect rect = cv::boundingRect(contours[i]); - cv::Point pc(rect.x + rect.width / 2, rect.y + rect.height / 2); - if (jiao_f_1) - { - // printf("1=%d =========== %d %d\n\n", type, abs(pc.x - jiao_p_1.x), abs(pc.y - jiao_p_1.y)); - if (abs(pc.x - jiao_p_1.x) < pDetConfig->pBaseCheckFunction->edgeDet.queJiao_width && abs(pc.y - jiao_p_1.y) < pDetConfig->pBaseCheckFunction->edgeDet.queJiao_height) - { - continue; - } - } - if (jiao_f_2) - { - // printf("2=%d============ %d %d\n\n", type, abs(pc.x - jiao_p_2.x), abs(pc.y - jiao_p_2.y)); - if (abs(pc.x - jiao_p_2.x) < pDetConfig->pBaseCheckFunction->edgeDet.queJiao_width && abs(pc.y - jiao_p_2.y) < pDetConfig->pBaseCheckFunction->edgeDet.queJiao_height) - { - continue; - } - } - - if (rect.width >= pedgeDet->QX_Widht_min && rect.width <= pedgeDet->QX_Widht_max && - rect.height >= pedgeDet->QX_Height_min && rect.height <= pedgeDet->QX_Height_max) - { - double area = contourArea(contours[i]); - QX_Result tem; - tem.roi_src.x = rect.x + DetRoi.x; - tem.roi_src.y = rect.y + DetRoi.y; - tem.roi_src.width = rect.width; - tem.roi_src.height = rect.height; - tem.area_pixel = area; - pDetConfig->qx_result.push_back(tem); - } - } - - // cv::imwrite("detimg.png", img(DetRoi)); - // cv::imwrite("detimg_mask.png", roiMask); - // getchar(); - return 0; -} - -int Edge_QX_Det::applyMaskInROI(const cv::Mat &grayImg, const Det_ROI_Config &config, cv::Mat &result, int threshold) -{ - // 1. 获取 ROI 区域图像(不 clone,只引用) - cv::Mat roiGray = grayImg(config.roi); - // cv::imwrite("roiGray.png", roiGray); - // 2. 二值化(用 compare 更快) - cv::Mat binary; - cv::compare(roiGray, threshold, binary, cv::CMP_LT); // binary = roiGray > 128 ? 255 : 0 - // cv::imwrite("binary.png", binary); - // 3. 构建局部坐标的多边形(避免每次 new) - std::vector localPts; - localPts.reserve(config.plist.size()); - for (const auto &pt : config.plist) - localPts.emplace_back(pt.x - config.roi.x, pt.y - config.roi.y); - - // 4. 快速创建 mask 并填充 - cv::Mat mask = cv::Mat::zeros(roiGray.size(), CV_8UC1); - cv::fillPoly(mask, std::vector>{localPts}, 255); - // cv::imwrite("mask.png", mask); - // 5. 应用 mask - result = cv::Mat::zeros(roiGray.size(), CV_8UC1); - binary.copyTo(result, mask); - // cv::imwrite("result.png", result); - - return 0; -} - -int Edge_QX_Det::Draw_Det(const cv::Mat &img, DetConfigResult *pDetConfig) -{ - Base_Function_Edge_Det *pedgeDet = &pDetConfig->pBaseCheckFunction->edgeDet; - if (pedgeDet->region.size() <= 2) - { - return 1; - } - float resize_fx = 0.4; - float resize_fy = 0.4; - int dest_width = img.cols * resize_fx; - int dest_height = img.rows * resize_fy; - - cv::Size sz; - sz.width = dest_width; - sz.height = dest_height; - pDetConfig->Det_region.clear(); - std::vector Det_resize_region; - for (const auto p : pedgeDet->region) - { - cv::Point pc; - if (pDetConfig->alginResult.H.empty()) - { - pc.x = p.x - pDetConfig->alginResult.corpRoi.x + pDetConfig->alginResult.offtx; - pc.y = p.y - pDetConfig->alginResult.corpRoi.y + pDetConfig->alginResult.offty; - } - else - { - cv::Point pt; - pt = CheckUtil::transformPoint(p, pDetConfig->alginResult.H); - pc.x = pt.x - pDetConfig->alginResult.corpRoi.x; - pc.y = pt.y - pDetConfig->alginResult.corpRoi.y; - } - - pDetConfig->Det_region.push_back(pc); - - cv::Point pcs; - pcs.x = pc.x * resize_fx; - pcs.y = pc.y * resize_fy; - Det_resize_region.push_back(pcs); - } - - cv::Mat detimg; - cv::resize(img, detimg, sz); - if (detimg.channels() != 1) - { - cv::cvtColor(detimg, detimg, cv::COLOR_RGB2GRAY); - } - cv::Mat mask = cv::Mat::zeros(detimg.size(), CV_8UC1); - - // 把 points 转成 std::vector> 格式 - std::vector> pts; - pts.push_back(Det_resize_region); - // 填充区域为 255 - cv::fillPoly(mask, pts, cv::Scalar(255)); - - cv::Mat binary; - cv::threshold(detimg, binary, pedgeDet->Det_threshold, 255, cv::THRESH_BINARY_INV); - - cv::Mat result = cv::Mat::zeros(binary.size(), CV_8UC1); - binary.copyTo(result, mask); - - // cv::imwrite(pDetConfig->strChannel + "draw_detimg.png", detimg); - // cv::imwrite(pDetConfig->strChannel + "draw_region.png", mask); - // cv::imwrite(pDetConfig->strChannel + "draw_binary.png", binary); - // cv::imwrite(pDetConfig->strChannel + "draw_result.png", result); - // getchar(); - - // 寻找轮廓 - vector> contours; - cv::findContours(result, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); - - // 找到最大面积的轮廓 - double maxArea = -1; - int maxAreaIdx = -1; - for (size_t i = 0; i < contours.size(); ++i) - { - cv::Rect rect = cv::boundingRect(contours[i]); - rect.x /= resize_fx; - rect.y /= resize_fy; - rect.width /= resize_fx; - rect.height /= resize_fy; - // CheckUtil::printROI(rect,"dfe"); - - if (rect.width >= pedgeDet->QX_Widht_min && rect.width <= pedgeDet->QX_Widht_max && - rect.height >= pedgeDet->QX_Height_min && rect.height <= pedgeDet->QX_Height_max) - { - double area = contourArea(contours[i]); - area /= resize_fx; - area /= resize_fy; - QX_Result tem; - tem.roi_src.x = rect.x; - tem.roi_src.y = rect.y; - tem.roi_src.width = rect.width; - tem.roi_src.height = rect.height; - tem.area_pixel = area; - pDetConfig->qx_result.push_back(tem); - } - else - { - // printf("================== size \n"); - } - } - - return 0; -} - -int Edge_QX_Det::UDNoiseEdgeDetect(cv::Mat img, int DirectSign, int Gate, int BorW, cv::Rect roi, int StepCount, int Limit) -{ - if (img.empty()) - { - return -11; - } - if (img.channels() != 1) - { - printf("*****************************channels\n"); - - return -12; - } - if (StepCount < 0 || StepCount >= roi.width) - { - printf("*****************************StepCount\n"); - - return -22; - } - std::vector data; - // cv::Mat showimg; - // cv::cvtColor(img, showimg, cv::COLOR_GRAY2BGR); - uchar *pdata = (uchar *)img.data; - - int sx = roi.x; - int ex = roi.x + roi.width; - int sy = roi.y; - int ey = roi.y + roi.height; - // 表示 反向搜索 - if (DirectSign < 0) - { - sy = roi.y + roi.height; - ey = roi.y; - } - int step = roi.width / StepCount; - int offt = 0; - int sumsite = 0; - int sumcount = 0; - // 表示搜索黑点 - if (BorW == 0) - { - } - else // 表示搜索白点 - { - for (int x = roi.x; x < ex; x = x + step) - { - - int ncount = 0; - int start = 0; - - for (int y = sy;; y = y + DirectSign) - { - if (DirectSign > 0 && y > ey) - { - break; - } - if (DirectSign < 0 && y < ey) - { - break; - } - int maxv = 0; - // 1、计算当前值是否 满足基本要求 - offt = y * img.cols + x; - maxv = pdata[offt]; - - if (maxv < 40) - { - for (int ix = -4; ix < 5; ix++) - { - int newx = x + ix; - if (newx < 0) - { - newx = 0; - } - if (newx > img.cols) - { - newx = img.cols; - } - - offt = y * img.cols + newx; - - if (pdata[offt] > maxv) - { - maxv = pdata[offt]; - } - } - } - - if (maxv > 40) - { - // 2、计算区域最大值 - for (int k = -4; k < 5; k++) - { - int newy = y + k; - if (newy < 0) - { - newy = 0; - } - if (newy >= img.rows) - { - newy = img.rows - 1; - } - - for (int ix = -4; ix < 5; ix++) - { - int newx = x + ix; - if (newx < 0) - { - newx = 0; - } - if (newx > img.cols) - { - newx = img.cols; - } - - offt = newy * img.cols + newx; - - if (pdata[offt] > maxv) - { - maxv = pdata[offt]; - } - } - - /* code */ - } - if (bshowimg) - { - cv::Rect roi; - roi.x = x - 2; - roi.width = 5; - if (roi.x < 0) - { - roi.x = 0; - } - int rdp = roi.x + roi.width; - if (rdp > showimg.cols) - { - rdp = showimg.cols; - } - roi.width = rdp - roi.x; - - roi.y = y - 2; - roi.height = 5; - if (roi.y < 0) - { - roi.y = 0; - } - rdp = roi.y + roi.height; - if (rdp > showimg.rows) - { - rdp = showimg.rows; - } - roi.height = rdp - roi.y; - cv::rectangle(showimg, roi, cv::Scalar(0, 0, 255)); - /* code */ - } - } - else - { - // if (start > 0) - // { - // printf("error p %d %d %d \n", x, y, maxv); - // /* code */ - // } - } - // 3、满足要求 记录 - if (maxv >= Gate) - { - ncount += 2; - if (start == 0) - { - start = y; - } - if (ncount > Limit) - { - break; - } - } - else - { - // if (maxv < 15) - // { - // ncount = 0; - // } - ncount--; - if (ncount < 0) - { - ncount = 0; - start = 0; - } - } - } - // 4、满足退出要求,就退出 - if (ncount > Limit) - { - sumcount++; - sumsite += start; - data.push_back(start); - - if (bshowimg && !showimg.empty()) - { - cv::Point p(x, start); - cv::circle(showimg, p, 13, cv::Scalar(0, 255, 0), 5); - // cv::imwrite("showimg.png", showimg); - // printf(">>>>>>>> %d %d \n",x,start); - // getchar(); - } - } - } - } - - if (sumcount <= 0) - { - return -3; - } - else - { - // 先剔除异常数据 - std::vector filteredData = removeOutliers123(data); - - if (bshowimg && !showimg.empty()) - { - - // for (int i = 0; i < data.size(); i++) - // { - // printf("%d %f \n ", i, data.at(i)); - // } - - // for (int i = 0; i < filteredData.size(); i++) - // { - // printf("%d %f \n ", i, filteredData.at(i)); - // } - } - sumsite = 0; - sumcount = 0; - int mean = 0; - for (int i = 0; i < filteredData.size(); i++) - { - sumsite += filteredData.at(i); - sumcount++; - } - if (sumcount > 0) - { - mean = sumsite / sumcount; - } - - mean = sumsite / sumcount; - return mean; - } - - return -5; -} - -int Edge_QX_Det::LRNoiseEdgeDetect(cv::Mat img, int DirectSign, int Gate, int BorW, cv::Rect roi, int StepCount, int Limit) -{ - - if (img.empty()) - { - return -1; - } - if (img.channels() != 1) - { - printf("*****************************channels\n"); - - return -1; - } - if (StepCount < 0 || StepCount >= roi.width) - { - printf("*****************************StepCount\n"); - - return -2; - } - - std::vector data; - // cv::Mat showimg; - // cv::cvtColor(img, showimg, cv::COLOR_GRAY2BGR); - uchar *pdata = (uchar *)img.data; - - int sx = roi.x; - int ex = roi.x + roi.width; - int sy = roi.y; - int ey = roi.y + roi.height; - // 表示 反向搜索 - if (DirectSign < 0) - { - sx = roi.x + roi.width; - ex = roi.x; - } - int step = roi.height / StepCount; - int offt = 0; - int sumsite = 0; - int sumcount = 0; - // 表示搜索黑点 - if (BorW == 0) - { - } - else // 表示搜索白点 - { - // printf("---- y sy %d ey %d sx %d ex %d\n", sy, ey, sx, ex); - for (int y = sy; y < ey; y = y + step) - { - int ncount = 0; - int start = 0; - - for (int x = sx;; x = x + DirectSign) - { - if (DirectSign > 0 && x > ex) - { - break; - } - if (DirectSign < 0 && x < ex) - { - break; - } - int maxv = 0; - // 1、计算当前值是否 满足基本要求 - offt = y * img.cols + x; - maxv = pdata[offt]; - if (maxv < 40) - { - for (int k = -4; k < 5; k++) - { - int newy = y + k; - if (newy < 0) - { - newy = 0; - } - if (newy >= img.rows) - { - newy = img.rows - 1; - } - offt = newy * img.cols + x; - maxv = pdata[offt]; - if (pdata[offt] > maxv) - { - maxv = pdata[offt]; - } - } - } - - if (maxv > 40) - { - // 2、计算区域最大值 - for (int k = -4; k < 5; k++) - { - int newy = y + k; - if (newy < 0) - { - newy = 0; - } - if (newy >= img.rows) - { - newy = img.rows - 1; - } - - for (int ix = -4; ix < 5; ix++) - { - int newx = x + ix; - if (newx < 0) - { - newx = 0; - } - if (newx > img.cols) - { - newx = img.cols; - } - - offt = newy * img.cols + newx; - - if (pdata[offt] > maxv) - { - maxv = pdata[offt]; - } - } - - /* code */ - } - if (bshowimg) - { - cv::Rect roi; - roi.x = x - 2; - roi.width = 5; - if (roi.x < 0) - { - roi.x = 0; - } - int rdp = roi.x + roi.width; - if (rdp > showimg.cols) - { - rdp = showimg.cols; - } - roi.width = rdp - roi.x; - - roi.y = y - 2; - roi.height = 5; - if (roi.y < 0) - { - roi.y = 0; - } - rdp = roi.y + roi.height; - if (rdp > showimg.rows) - { - rdp = showimg.rows; - } - roi.height = rdp - roi.y; - cv::rectangle(showimg, roi, cv::Scalar(0, 0, 255)); - /* code */ - } - } - else - { - // if (start > 0) - // { - // //printf("error p %d %d %d \n", x, y, maxv); - // /* code */ - // } - } - // 3、满足要求 记录 - - if (maxv >= Gate) - { - ncount += 2; - if (start == 0) - { - start = x; - // printf("---- %d %d y %d\n", pdata[offt], start, y); - } - if (ncount > Limit) - { - break; - } - } - else - { - // if (maxv < 15) - // { - // ncount = 0; - // } - ncount--; - if (ncount < 0) - { - start = 0; - ncount = 0; - } - } - } - if (ncount > Limit) - { - sumcount++; - sumsite += start; - data.push_back(start); - if (bshowimg && !showimg.empty()) - { - cv::Point p(start, y); - cv::circle(showimg, p, 13, cv::Scalar(255, 255, 125), 5); - // cv::imwrite("showimg.png", showimg); - // printf(">>>>>>>>\n"); - // getchar(); - } - } - } - } - - // if (bshowimg && !showimg.empty()) - // { - // cv::imwrite("showimg.png", showimg); - // printf(">>>>>>123>> DirectSign %d \n",DirectSign); - // getchar(); - // } - // if (DirectSign < 0) - // { - - // cv::imwrite("showimg.png", img); - // printf(">>>>>>>>\n"); - // getchar(); - // } - if (sumcount <= 0) - { - return -3; - } - else - { - - // 先剔除异常数据 - std::vector filteredData = removeOutliers123(data); - - if (bshowimg && !showimg.empty()) - { - - // for (int i = 0; i < data.size(); i++) - // { - // printf("%d %f \n ", i, data.at(i)); - // } - - // for (int i = 0; i < filteredData.size(); i++) - // { - // printf("%d %f \n ", i, filteredData.at(i)); - // } - } - sumsite = 0; - sumcount = 0; - int mean = 0; - for (int i = 0; i < filteredData.size(); i++) - { - sumsite += filteredData.at(i); - sumcount++; - } - if (sumcount > 0) - { - mean = sumsite / sumcount; - } - - mean = sumsite / sumcount; - return mean; - } - - return -5; -} diff --git a/AlgorithmModule/src/ImgCheckAnalysisy.cpp b/AlgorithmModule/src/ImgCheckAnalysisy.cpp index 43a62d2..4ebc40d 100644 --- a/AlgorithmModule/src/ImgCheckAnalysisy.cpp +++ b/AlgorithmModule/src/ImgCheckAnalysisy.cpp @@ -20,6 +20,7 @@ static bool compareContourAreas(const vector &contour1, const vectordetImg); + int reedge1111 = Pin_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_pdetlog->AddCheckstr(PrintLevel_0, "4、detect", "-------------------------1、Pin_Qx_Det--------%ld-------\n", t42 - t41); } m_CheckResult_shareP->nresult = 0; @@ -1892,7 +1893,7 @@ int ImgCheckAnalysisy::DrawResult_Step_1() // 要绘制结果 if (m_pbaseCheckFunction && m_pbaseCheckFunction->edgeDet.bDrawResult) { - for (const auto &r : m_Edge_DetConfig.edge_det_roi) + for (const auto &r : m_Edge_DetConfig.pin_det_roi) { cv::Rect droi; droi.x = r.roi.x * fs_resize_x; @@ -2022,27 +2023,20 @@ int ImgCheckAnalysisy::UpdateImgageScale() return 0; } -int ImgCheckAnalysisy::Edge_Qx_Det(const cv::Mat &img) +int ImgCheckAnalysisy::Pin_Qx_Det(const cv::Mat &img) { m_Edge_DetConfig.Init(); m_Edge_DetConfig.strChannel = m_strCurDetChannel; m_Edge_DetConfig.pBaseCheckFunction = m_pbaseCheckFunction; - m_Edge_DetConfig.alginResult.corpRoi = m_Crop_Roi_paramImg; - - 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); + // m_pbaseCheckFunction->print("Pin_Qx_Det"); + int re = m_Pin_QX_Det.Detect(img, &m_Edge_DetConfig); if (re == 0) { for (const auto r : m_Edge_DetConfig.qx_result) @@ -2106,12 +2100,12 @@ int ImgCheckAnalysisy::Edge_Qx_Det(const cv::Mat &img) 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()); + m_pdetlog->AddCheckstr(PrintLevel_1, "Pin_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); + m_pdetlog->AddCheckstr(PrintLevel_1, "Pin_Qx_Det", " error %d", re); } return 0; diff --git a/AlgorithmModule/src/Pin_QX_Det.cpp b/AlgorithmModule/src/Pin_QX_Det.cpp new file mode 100644 index 0000000..19361c2 --- /dev/null +++ b/AlgorithmModule/src/Pin_QX_Det.cpp @@ -0,0 +1,97 @@ + +#include "Pin_QX_Det.h" +#include "CheckUtil.hpp" +#include +#include +#include "CheckErrorCodeDefine.hpp" + +int Pin_QX_Det::creatsavedir() +{ + std::string curDate = CheckUtil::getCurrentDate(); + if (curDate == m_strLastDate) + { + return 0; + } + m_strLastDate = curDate; + m_strSavePath_Pin = m_strRootPath_Pin + curDate + "/"; + + CheckUtil::CreateDir(m_strSavePath_Pin); + + return 0; + return 0; +} + +Pin_QX_Det::Pin_QX_Det(std::shared_ptr &log_ref) + : m_pdetlog(log_ref) +{ + m_bInitialized = false; + m_bModelSucc = false; + m_bModel_Mark_Succ = false; + m_bshowimg = false; + m_strRootPath_Pin = "/home/aidlux/BOE/Pin/"; + creatsavedir(); + std::string m_strSavePath; + + m_pImageStorage = ImageStorage::getInstance(); + AI_Factory = AIFactory::GetInstance(); +} +Pin_QX_Det::~Pin_QX_Det() +{ +} +int Pin_QX_Det::Detect(const cv::Mat &img, DetConfigResult *pDetConfig) +{ + // if (!pDetConfig->pBaseCheckFunction->edgeDet.bOpen) + // { + // return 0; + // } + + m_bshowimg = false; + if (pDetConfig->bSaveResultImg) + { + m_bshowimg = true; + } + + std::shared_ptr pSocket_Pin; + pSocket_Pin = AI_Factory->Pin_Loc; + cv::Size sz; + sz.width = pSocket_Pin->input_0.width; + sz.height = pSocket_Pin->input_0.height; + cv::Mat detImg; + cout<< pDetConfig->strChannel << ": " << "---Pin---"; + cout << "imgSize: " << img.size() << ", " << "detImgSize: " << detImg.size() << ", " << "szSize: " << sz << endl; + + cv::resize(img, detImg, sz); + int re = 0; + cv::Mat mask; + if (detImg.channels() != 1) + { + cv::cvtColor(detImg, detImg, cv::COLOR_RGB2GRAY); + } + + re = pSocket_Pin->AIDet(detImg, mask); + if (re != 0) + { + m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "AI_Edge_Algin ", "AICheck_Edge----error %d ", re); + int re123 = 100 + re; + return re123; + } + + if (pDetConfig->pBaseCheckFunction->saveImg.bSaveAlginImg) + { + + } + + if (pDetConfig->bSaveResultImg) + { + cv::imwrite(pDetConfig->strChannel +"_pin_" +"in.png", detImg); + cv::imwrite(pDetConfig->strChannel +"_pin_" +"out_mask.png", mask); + } + + if (m_bshowimg) + { + cv::cvtColor(img, showimg, cv::COLOR_GRAY2BGR); + } + + + return 0; +} diff --git a/ConfigModule/src/JsonConfig.cpp b/ConfigModule/src/JsonConfig.cpp index 22a865d..14baac6 100644 --- a/ConfigModule/src/JsonConfig.cpp +++ b/ConfigModule/src/JsonConfig.cpp @@ -849,7 +849,7 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value) _config.markLine.Init(); } } - if ("Edge_QX_Detect" == strCode) + if ("Pin_QX_Detect" == strCode) { auto value_f = value; // std::cout << value_f << std::endl;