diff --git a/AlgorithmModule/include/AI_Edge_Algin.h b/AlgorithmModule/include/AI_Edge_Algin.h index ed9a144..f9557ae 100644 --- a/AlgorithmModule/include/AI_Edge_Algin.h +++ b/AlgorithmModule/include/AI_Edge_Algin.h @@ -52,8 +52,9 @@ public: struct Edge_AI_Result { int nresult; - cv::RotatedRect bigroi; - cv::RotatedRect smallroi; + std::vector bigroi; // 轮廓面积从大到小排序 + std::vector smallroi; // 轮廓面积从大到小排序 + std::vector tagroi; // 轮廓面积从大到小排序 bool buseOfft; int offt_x; int offt_y; @@ -71,8 +72,9 @@ public: 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); + bigroi.clear(); + smallroi.clear(); + tagroi.clear(); markresulList.clear(); if (!H.empty()) { @@ -152,7 +154,7 @@ public: private: int InitModel_Big(); - int Get_Edge(int AIModel_type, const cv::Mat &img, DetConfig *pDetConfig, std::string strChannel, cv::RotatedRect &Roi); + int Get_Edge(int AIModel_type, const cv::Mat &img, DetConfig *pDetConfig, std::string strChannel, std::vector &RoiList); int creatsavedir(); diff --git a/AlgorithmModule/include/ImgCheckAnalysisy.hpp b/AlgorithmModule/include/ImgCheckAnalysisy.hpp index 829f8ae..635fbc9 100644 --- a/AlgorithmModule/include/ImgCheckAnalysisy.hpp +++ b/AlgorithmModule/include/ImgCheckAnalysisy.hpp @@ -116,7 +116,7 @@ private: cv::Scalar calc_blob_info_withstats(cv::Mat &img, const cv::Mat &mask, cv::Rect &stats, cv::Size k_size = cv::Size(5, 5), int expand = 10, double threshold = 0.7); // 检测 int CheckRun(); - int AI_Edge(const cv::Mat &img, cv::RotatedRect &outerRoi, cv::RotatedRect &innerRoi); + int AI_Edge(const cv::Mat &img, cv::RotatedRect &outerRoi, cv::RotatedRect &innerRoi, std::vector &tagroiList); // 计算产品尺寸 int CalProductSize(); // 图片预处理 @@ -141,7 +141,6 @@ private: int CalBlob_Other(); // 分类 - int GetClassImg(const cv::Mat &img, cv::Mat &AIdetImg, cv::Rect qx_roi, int detwidth, int detheight); // 计算缺陷长度 @@ -287,8 +286,9 @@ private: // 模板信息 cv::RotatedRect m_tplOuterRect; // 模板外接矩形 - cv::RotatedRect m_outer_rroi; + cv::RotatedRect m_outer_rroi; cv::RotatedRect m_inner_rroi; + std::vector m_tag_roiList; }; #endif \ No newline at end of file diff --git a/AlgorithmModule/include/ImgCheckConfig.h b/AlgorithmModule/include/ImgCheckConfig.h index b55b88e..edb425f 100644 --- a/AlgorithmModule/include/ImgCheckConfig.h +++ b/AlgorithmModule/include/ImgCheckConfig.h @@ -60,6 +60,7 @@ enum ERROR_TYPE_ ERROR_TYPE_shuizi, // 11 水渍 ERROR_TYPE_danban, // 12 淡斑 ERROR_TYPE_fuchen, // 13 浮尘 + ERROR_TYPE_tag, // 14 标签 ERROR_TYPE_COUNT, }; extern std::vector QX_Result_Names; diff --git a/AlgorithmModule/src/AI_Edge_Algin.cpp b/AlgorithmModule/src/AI_Edge_Algin.cpp index 578dde2..e3285dd 100644 --- a/AlgorithmModule/src/AI_Edge_Algin.cpp +++ b/AlgorithmModule/src/AI_Edge_Algin.cpp @@ -15,6 +15,7 @@ #include // OpenCV核心功能 #include // 图像处理模块 #include // 向量容器 +#include // std::sort #include // 输入输出流 /** @@ -233,8 +234,9 @@ int AI_Edge_Algin::Detect(const cv::Mat &img, DetConfig *pDetConfig, std::shared // 1、初步定位 找到产品大致区域 int re = 0; - cv::RotatedRect Big_roi; - cv::RotatedRect Small_roi; + std::vector Big_roi; + std::vector Small_roi; + std::vector Tag_roi; re = Get_Edge(0, img, pDetConfig, m_pDetConfig->strChannel, Big_roi); if (re != 0) @@ -256,9 +258,20 @@ int AI_Edge_Algin::Detect(const cv::Mat &img, DetConfig *pDetConfig, std::shared } return re; } + re = Get_Edge(2, img, pDetConfig, m_pDetConfig->strChannel, Tag_roi); + if (re != 0) + { + m_pdetlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "AI_Edge_Algin ", "AICheck_Tag----error %d ", re); + if (m_pDetConfig->IsSaveProcessImg()) + { + cv::imwrite(str_error, img); + } + return re; + } m_pCheckResult_Aling->bigroi = Big_roi; m_pCheckResult_Aling->smallroi = Small_roi; + m_pCheckResult_Aling->tagroi = Tag_roi; pCheckResult_Aling = m_pCheckResult_Aling; // return 1; @@ -330,7 +343,7 @@ int AI_Edge_Algin::InitModel_ALL() return 0; } -int AI_Edge_Algin::Get_Edge(int AIModel_type, const cv::Mat &img, DetConfig *pDetConfig, std::string strChannel, cv::RotatedRect &Roi) +int AI_Edge_Algin::Get_Edge(int AIModel_type, const cv::Mat &img, DetConfig *pDetConfig, std::string strChannel, std::vector &RoiList) { std::shared_ptr pBackPlate_Align; switch (AIModel_type) @@ -341,6 +354,9 @@ int AI_Edge_Algin::Get_Edge(int AIModel_type, const cv::Mat &img, DetConfig *pDe case 1: pBackPlate_Align = AI_Factory->Align_Inner; break; + case 2: + pBackPlate_Align = AI_Factory->Tag_Loc; + break; default: pBackPlate_Align = AI_Factory->Align_Outer; break; @@ -393,42 +409,73 @@ int AI_Edge_Algin::Get_Edge(int AIModel_type, const cv::Mat &img, DetConfig *pDe cv::imwrite(strChannel +"_edge_"+ to_string(AIModel_type) +"_out_mask.png", mask); } - // 找到最大轮廓 - bool found; - std::vector boundingBox = CheckUtil::getLargestContourROI(mask, found); - if (!found) - { - m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "AI_Edge_Algin ", "No contours found!----error "); - return 4; - } - - // 边缘轮廓点集还原为原图坐标,并计算得到RotateROI + // 检查模型输入尺寸 if (sz.width <= 0 || sz.height <= 0) { m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "AI_Edge_Algin ", "invalid model input size!----error "); return 5; } + // 找到所有轮廓 + std::vector> contours; + std::vector hierarchy; + cv::findContours(mask.clone(), contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); + if (contours.empty()) + { + m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "AI_Edge_Algin ", "No contours found!----error "); + return 4; + } + // 检测小图 到 原图 的缩放比例 const float scale_x = static_cast(img.cols) / sz.width; const float scale_y = static_cast(img.rows) / sz.height; - // 轮廓点还原到原图坐标系 - std::vector srcContour; - srcContour.reserve(boundingBox.size()); - for (const auto &pt : boundingBox) + RoiList.clear(); + + // 按轮廓面积从大到小排序(记录面积与轮廓索引) + std::vector> areaIdx; + areaIdx.reserve(contours.size()); + for (size_t i = 0; i < contours.size(); i++) + { + double area = cv::contourArea(contours[i]); + if (area > 0) + { + areaIdx.emplace_back(area, i); + } + } + if (areaIdx.empty()) + { + m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "AI_Edge_Algin ", "No valid contours found!----error "); + return 4; + } + std::sort(areaIdx.begin(), areaIdx.end(), + [](const std::pair &a, const std::pair &b) + { return a.first > b.first; }); + + // 按面积从大到小,将每个轮廓点还原到原图坐标系并计算 RotatedRect + RoiList.reserve(areaIdx.size()); + for (const auto &ai : areaIdx) { - srcContour.emplace_back(pt.x * scale_x, pt.y * scale_y); + const std::vector &contour = contours[ai.second]; + if (contour.size() < 3) + { + continue; + } + std::vector srcContour; + srcContour.reserve(contour.size()); + for (const auto &pt : contour) + { + srcContour.emplace_back(pt.x * scale_x, pt.y * scale_y); + } + RoiList.emplace_back(cv::minAreaRect(srcContour)); } - if (srcContour.size() < 3) + if (RoiList.empty()) { m_pdetlog->AddCheckstr(PrintLevel_3, DET_LOG_LEVEL_3, "AI_Edge_Algin ", "contour points too few!----error "); return 6; } - Roi = cv::minAreaRect(srcContour); - return 0; } diff --git a/AlgorithmModule/src/ALLImgCheckAnalysisy.cpp b/AlgorithmModule/src/ALLImgCheckAnalysisy.cpp index 9d5cfdc..26131a5 100644 --- a/AlgorithmModule/src/ALLImgCheckAnalysisy.cpp +++ b/AlgorithmModule/src/ALLImgCheckAnalysisy.cpp @@ -29,6 +29,7 @@ std::vector QX_Result_Names = "shuizi", "danban", "fuchen", + "tag", }; std::vector QX_Result_Code = { @@ -45,6 +46,7 @@ std::vector QX_Result_Code = "P0002", "P0003", "P0004", + "P0005", }; int ReadFlawCodeConfig(std::string json_path) diff --git a/AlgorithmModule/src/ImageResultJudge.cpp b/AlgorithmModule/src/ImageResultJudge.cpp index 00c68f6..afd8359 100644 --- a/AlgorithmModule/src/ImageResultJudge.cpp +++ b/AlgorithmModule/src/ImageResultJudge.cpp @@ -379,6 +379,13 @@ int ImageResultJudge::ResultJudge(std::shared_ptr pImageResult) } } + // 标签缺陷:检测到标签直接判 NG + if (config_qx_type == CONFIG_QX_NAME_cell_tag) + { + bNG_Status = true; + Judge_Status = true; + } + std::string resultType = "OK"; if (!Judge_Status) @@ -1080,6 +1087,9 @@ int ImageResultJudge::ConfigTypeToResultType(int nconfigType) case CONFIG_QX_NAME_cell_fuchen: resultError_type = ERROR_TYPE_fuchen; break; + case CONFIG_QX_NAME_cell_tag: + resultError_type = ERROR_TYPE_tag; + break; default: break; diff --git a/AlgorithmModule/src/ImgCheckAnalysisy.cpp b/AlgorithmModule/src/ImgCheckAnalysisy.cpp index acaff55..601cea9 100644 --- a/AlgorithmModule/src/ImgCheckAnalysisy.cpp +++ b/AlgorithmModule/src/ImgCheckAnalysisy.cpp @@ -455,7 +455,7 @@ int ImgCheckAnalysisy::CheckRun() /*AI 边缘定位(内外边缘)*/ // 模型定位内外边缘 - int reedge = AI_Edge(m_CheckResult_shareP->in_shareImage->img, m_outer_rroi, m_inner_rroi); + int reedge = AI_Edge(m_CheckResult_shareP->in_shareImage->img, m_outer_rroi, m_inner_rroi, m_tag_roiList); if (reedge != 0) { m_pdetlog->AddCheckstr(PrintLevel_0, "Error", "AI_Edge is error type = %d", reedge); @@ -502,10 +502,57 @@ int ImgCheckAnalysisy::CheckRun() // 分析m_inner_rroi /* Tag检测 */ + { + for (const auto &tagRoi : m_tag_roiList) + { + // tag roi 在原图坐标系,转换为检测图(detImg)坐标系 + cv::Rect roi = tagRoi.boundingRect(); + roi.x -= m_outer_roi.x; + roi.y -= m_outer_roi.y; + roi &= cv::Rect(0, 0, m_pImageAllResult->detImg.cols, m_pImageAllResult->detImg.rows); + if (roi.width <= 0 || roi.height <= 0) + { + continue; + } - + QX_ERROR_INFO_ temerror; + temerror.Idx = m_pDetResult->pQx_ErrorList->size(); + temerror.roi = roi; + temerror.area = roi.width * roi.height; + temerror.JudgArea = roi.width * m_fImgage_Scale_X * roi.height * m_fImgage_Scale_Y; + temerror.JudgArea_second = temerror.JudgArea; + float tw = tagRoi.size.width; + float th = tagRoi.size.height; + temerror.flen = (tw > th ? tw : th) * m_fImgage_Scale_X; + temerror.fbreadth = (tw > th ? th : tw) * m_fImgage_Scale_Y; + temerror.nconfig_qx_type = CONFIG_QX_NAME_cell_tag; + temerror.qx_name = CONFIG_QX_NAME_Names[CONFIG_QX_NAME_cell_tag]; + temerror.result = QX_RESULT_TYPE_NG; + temerror.result_name = QX_RESULT_TYPE_Names[QX_RESULT_TYPE_NG]; + + // 计算标签中心所在的检测区域 + cv::Point pCenter; + pCenter.x = roi.x + roi.width * 0.5; + pCenter.y = roi.y + roi.height * 0.5; + int nmaxregionIdx = 0; + for (int iregion = 0; iregion < m_DetRoiList.roiList_Src.size(); iregion++) + { + const std::vector &polygon = m_DetRoiList.roiList_Src[iregion]; + double result = cv::pointPolygonTest(polygon, pCenter, false); + if (result < 0) + { + continue; + } + nmaxregionIdx = iregion; + } + temerror.detRegionidxList.push_back(nmaxregionIdx); + + m_pDetResult->pQx_ErrorList->push_back(temerror); + + m_pdetlog->AddCheckstr(PrintLevel_0, "Tag检测", "tag %d roi [%d %d %d %d] -> NG", temerror.Idx, roi.x, roi.y, roi.width, roi.height); + } + } - m_CheckResult_shareP->nresult = 0; /*把临时可以绘制的结果都绘制出来。*/ @@ -1888,7 +1935,7 @@ int ImgCheckAnalysisy::BLobToDetResult() return 0; } -int ImgCheckAnalysisy::AI_Edge(const cv::Mat &img, cv::RotatedRect &outerRoi, cv::RotatedRect &innerRoi) +int ImgCheckAnalysisy::AI_Edge(const cv::Mat &img, cv::RotatedRect &outerRoi, cv::RotatedRect &innerRoi, vector &tagroiList) { m_pdetlog->AddCheckstr(PrintLevel_0, "AI_Edge", "-------------------start--------------"); @@ -1905,8 +1952,18 @@ int ImgCheckAnalysisy::AI_Edge(const cv::Mat &img, cv::RotatedRect &outerRoi, cv { printf("AI_Edge Is Error = %d \n", re); } - outerRoi = m_pEdge_Align_Result->bigroi; - innerRoi = m_pEdge_Align_Result->smallroi; + if (!m_pEdge_Align_Result->bigroi.empty()) + { + outerRoi = m_pEdge_Align_Result->bigroi[0]; + } + if (!m_pEdge_Align_Result->smallroi.empty()) + { + innerRoi = m_pEdge_Align_Result->smallroi[0]; + } + if (!m_pEdge_Align_Result->tagroi.empty()) + { + tagroiList = m_pEdge_Align_Result->tagroi; + } // getchar(); return re; } diff --git a/ConfigModule/include/CheckConfigDefine.h b/ConfigModule/include/CheckConfigDefine.h index 1cb65ea..ab870ae 100644 --- a/ConfigModule/include/CheckConfigDefine.h +++ b/ConfigModule/include/CheckConfigDefine.h @@ -51,6 +51,7 @@ enum CONFIG_QX_NAME_ CONFIG_QX_NAME_cell_shuizi, // 分类 水渍 CONFIG_QX_NAME_cell_danban, // 分类 淡斑 CONFIG_QX_NAME_cell_fuchen, // 分类 浮尘 + CONFIG_QX_NAME_cell_tag, // 分类 标签 CONFIG_QX_NAME_count, }; // 缺陷项对应在参数中的名称 @@ -68,6 +69,7 @@ static std::vector CONFIG_QX_NAME_Names = "shuizi", "danban", "fuchen", + "tag", }; // 分析类型 diff --git a/ConfigModule/src/ConfigManager.cpp b/ConfigModule/src/ConfigManager.cpp index 4750763..60ad686 100644 --- a/ConfigModule/src/ConfigManager.cpp +++ b/ConfigModule/src/ConfigManager.cpp @@ -35,6 +35,7 @@ std::vector QX_Result_Names = "shuizi", "danban", "fuchen", + "tag", }; std::vector QX_Result_Code = { @@ -51,6 +52,7 @@ std::vector QX_Result_Code = "P0002", "P0003", "P0004", + "P0005", }; int ReadFlawCodeConfig(std::string json_path)