From dc2ff1c8ec47dd197f535a0cd2babacdb7a1393b Mon Sep 17 00:00:00 2001 From: liusiyang Date: Fri, 4 Sep 2026 11:23:55 +0800 Subject: [PATCH] =?UTF-8?q?feat=20=E6=B7=BB=E5=8A=A0=E6=89=8B=E6=8A=8A?= =?UTF-8?q?=E7=BC=BA=E5=A4=B1=E6=A3=80=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AlgorithmModule/include/AI_Edge_Algin.h | 8 +- AlgorithmModule/src/AI_Edge_Algin.cpp | 19 +++-- AlgorithmModule/src/ALLImgCheckAnalysisy.cpp | 2 +- AlgorithmModule/src/ImgCheckAnalysisy.cpp | 90 +++++++++++++++++++- CMakeLists.txt | 2 +- ConfigModule/include/CheckConfigDefine.h | 17 +++- ConfigModule/src/JsonConfig.cpp | 28 +++++- example/deal.cpp | 6 +- 8 files changed, 151 insertions(+), 21 deletions(-) diff --git a/AlgorithmModule/include/AI_Edge_Algin.h b/AlgorithmModule/include/AI_Edge_Algin.h index f9557ae..11735ad 100644 --- a/AlgorithmModule/include/AI_Edge_Algin.h +++ b/AlgorithmModule/include/AI_Edge_Algin.h @@ -55,6 +55,9 @@ public: std::vector bigroi; // 轮廓面积从大到小排序 std::vector smallroi; // 轮廓面积从大到小排序 std::vector tagroi; // 轮廓面积从大到小排序 + cv::Mat bigmask; // 大轮廓掩码 + cv::Mat smallmask; // 小轮廓掩码 + cv::Mat tagmask; // 标记掩码 bool buseOfft; int offt_x; int offt_y; @@ -75,6 +78,9 @@ public: bigroi.clear(); smallroi.clear(); tagroi.clear(); + bigmask.release(); + smallmask.release(); + tagmask.release(); markresulList.clear(); if (!H.empty()) { @@ -154,7 +160,7 @@ public: private: int InitModel_Big(); - int Get_Edge(int AIModel_type, const cv::Mat &img, DetConfig *pDetConfig, std::string strChannel, std::vector &RoiList); + int Get_Edge(int AIModel_type, const cv::Mat &img, DetConfig *pDetConfig, std::string strChannel, std::vector &RoiList, Mat &outmask); int creatsavedir(); diff --git a/AlgorithmModule/src/AI_Edge_Algin.cpp b/AlgorithmModule/src/AI_Edge_Algin.cpp index e3285dd..173c2c3 100644 --- a/AlgorithmModule/src/AI_Edge_Algin.cpp +++ b/AlgorithmModule/src/AI_Edge_Algin.cpp @@ -237,8 +237,11 @@ int AI_Edge_Algin::Detect(const cv::Mat &img, DetConfig *pDetConfig, std::shared std::vector Big_roi; std::vector Small_roi; std::vector Tag_roi; + cv::Mat Big_outimg; + cv::Mat Small_outimg; + cv::Mat Tag_outimg; - re = Get_Edge(0, img, pDetConfig, m_pDetConfig->strChannel, Big_roi); + re = Get_Edge(0, img, pDetConfig, m_pDetConfig->strChannel, Big_roi, Big_outimg); if (re != 0) { m_pdetlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "AI_Edge_Algin ", "AICheck_Edge_Big----error %d ", re); @@ -248,7 +251,7 @@ int AI_Edge_Algin::Detect(const cv::Mat &img, DetConfig *pDetConfig, std::shared } return re; } - re = Get_Edge(1, img, pDetConfig, m_pDetConfig->strChannel, Small_roi); + re = Get_Edge(1, img, pDetConfig, m_pDetConfig->strChannel, Small_roi, Small_outimg); if (re != 0) { m_pdetlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "AI_Edge_Algin ", "AICheck_Edge_Small----error %d ", re); @@ -258,7 +261,7 @@ 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); + re = Get_Edge(2, img, pDetConfig, m_pDetConfig->strChannel, Tag_roi, Tag_outimg); if (re != 0) { m_pdetlog->AddCheckstr(PrintLevel_2, DET_LOG_LEVEL_3, "AI_Edge_Algin ", "AICheck_Tag----error %d ", re); @@ -272,9 +275,11 @@ int AI_Edge_Algin::Detect(const cv::Mat &img, DetConfig *pDetConfig, std::shared m_pCheckResult_Aling->bigroi = Big_roi; m_pCheckResult_Aling->smallroi = Small_roi; m_pCheckResult_Aling->tagroi = Tag_roi; + m_pCheckResult_Aling->bigmask = Big_outimg; + m_pCheckResult_Aling->smallmask = Small_outimg; + m_pCheckResult_Aling->tagmask = Tag_outimg; pCheckResult_Aling = m_pCheckResult_Aling; - // return 1; return 0; } @@ -343,7 +348,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, std::vector &RoiList) +int AI_Edge_Algin::Get_Edge(int AIModel_type, const cv::Mat &img, DetConfig *pDetConfig, std::string strChannel, std::vector &RoiList, Mat &outmask) { std::shared_ptr pBackPlate_Align; switch (AIModel_type) @@ -403,11 +408,13 @@ 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); } + // resize out_mask并返回 + cv::resize(mask, outmask, img.size()); // 检查模型输入尺寸 if (sz.width <= 0 || sz.height <= 0) diff --git a/AlgorithmModule/src/ALLImgCheckAnalysisy.cpp b/AlgorithmModule/src/ALLImgCheckAnalysisy.cpp index 26131a5..e8af946 100644 --- a/AlgorithmModule/src/ALLImgCheckAnalysisy.cpp +++ b/AlgorithmModule/src/ALLImgCheckAnalysisy.cpp @@ -348,7 +348,7 @@ int ALLImgCheckAnalysisy::InitTemplateMask() m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_1, "---Init Tpl---" , "start"); // 模板图路径,暂时使用固定路径 - string tplImgPath = "/home/aidlux/BOE/ZB_PLATE/Tpl/tpl.bmp"; // 模板图片路径 + string tplImgPath = "/home/aidlux/BOE/ZB_BACKPLATE/Tpl/tpl.bmp"; // 模板图片路径 Mat tplImg = imread(tplImgPath, IMREAD_UNCHANGED); if (tplImg.empty()) { diff --git a/AlgorithmModule/src/ImgCheckAnalysisy.cpp b/AlgorithmModule/src/ImgCheckAnalysisy.cpp index 86657b3..96954a4 100644 --- a/AlgorithmModule/src/ImgCheckAnalysisy.cpp +++ b/AlgorithmModule/src/ImgCheckAnalysisy.cpp @@ -11,6 +11,7 @@ #include "Define.h" #include #include "AICommonDefine.h" +#include // 用于排序轮廓的比较函数 static bool compareContourAreas(const vector &contour1, const vector &contour2) { @@ -2025,6 +2026,8 @@ int ImgCheckAnalysisy::AI_Edge(const cv::Mat &img, cv::RotatedRect &outerRoi, cv } config.strChannel = DetImgInfo_shareP->strChannel; config.pBaseCheckFunction = m_pbaseCheckFunction; + + /* 定位获取三个roi */ int re = m_pAI_Edge_Algin.Detect(img, &config, m_pEdge_Align_Result); if (re != 0) { @@ -2042,7 +2045,92 @@ int ImgCheckAnalysisy::AI_Edge(const cv::Mat &img, cv::RotatedRect &outerRoi, cv { tagroiList = m_pEdge_Align_Result->tagroi; } - // getchar(); + + /*使用m_pEdge_Align_Result->bigmask检测把手是否缺失*/ + // 截取把手大致区域 + RotatedRect tpl_handle_rroi = m_pbaseCheckFunction->supportDet.handleRect; + Rect handle_rect = Rect(tpl_handle_rroi.boundingRect().x, 0, tpl_handle_rroi.boundingRect().width, m_pEdge_Align_Result->bigmask.rows); + Mat handle_roi = m_pEdge_Align_Result->bigmask(handle_rect & Rect(0, 0, m_pEdge_Align_Result->bigmask.cols, m_pEdge_Align_Result->bigmask.rows)).clone(); + + // 对handle_roi做一下开运算 + Mat element = getStructuringElement(MORPH_RECT, Size(tpl_handle_rroi.boundingRect().width / 3, tpl_handle_rroi.boundingRect().height / 3)); + morphologyEx(handle_roi, handle_roi, MORPH_OPEN, element); + + // imwrite("handle_roi.png", handle_roi); + + // handle_roi找到最大连通域,和tpl_handle_rroi做面积形状比较,差异过大判为把手缺失,添加到缺陷并NG + { + Base_Function_Support_Det &handleDet = m_pbaseCheckFunction->supportDet; + if (handleDet.bOpen && tpl_handle_rroi.size.width > 0 && tpl_handle_rroi.size.height > 0 && !handle_roi.empty()) + { + std::vector> handle_contours; + cv::findContours(handle_roi, handle_contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); + + bool bHandleLoss = false; + if (handle_contours.empty()) + { + bHandleLoss = true; // 没有连通域,把手完全缺失 + } + else + { + // 取最大连通域 + std::sort(handle_contours.begin(), handle_contours.end(), compareContourAreas); + cv::RotatedRect cur_handle_rrect = cv::minAreaRect(handle_contours[0]); + double curArea = cv::contourArea(handle_contours[0]); + + // 面积比较 + double tplArea = tpl_handle_rroi.size.width * tpl_handle_rroi.size.height; + double areaRatio = (tplArea > 0.0) ? (curArea / tplArea) : 0.0; + + // 形状比较(长宽比) + float tplW = std::max(tpl_handle_rroi.size.width, tpl_handle_rroi.size.height); + float tplH = std::min(tpl_handle_rroi.size.width, tpl_handle_rroi.size.height); + float curW = std::max(cur_handle_rrect.size.width, cur_handle_rrect.size.height); + float curH = std::min(cur_handle_rrect.size.width, cur_handle_rrect.size.height); + float tplRatio = (tplH > 0.0f) ? (tplW / tplH) : 0.0f; + float curRatio = (curH > 0.0f) ? (curW / curH) : 0.0f; + float ratioDiff = (tplRatio > 0.0f) ? fabs(curRatio - tplRatio) / tplRatio : 0.0f; + + // 面积差异过大 或 形状差异过大 判为把手缺失 + if (areaRatio < 0.6f || ratioDiff > 0.6f) + { + bHandleLoss = true; + } + + m_pdetlog->AddCheckstr(PrintLevel_0, "把手检测", "areaRatio %f ratioDiff %f", areaRatio, ratioDiff); + } + + if (bHandleLoss) + { + QX_ERROR_INFO_ temerror; + temerror.Idx = m_pDetResult->pQx_ErrorList->size(); + + // 把手模板 roi 在原图坐标系,转换为检测图(detImg)坐标系 + cv::Rect roi = tpl_handle_rroi.boundingRect(); + roi.x -= outerRoi.boundingRect().x; + roi.y -= outerRoi.boundingRect().y; + roi &= cv::Rect(0, 0, outerRoi.boundingRect().width, outerRoi.boundingRect().height); + 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 w = tpl_handle_rroi.size.width; + float h = tpl_handle_rroi.size.height; + temerror.flen = (w > h ? w : h) * m_fImgage_Scale_X; + temerror.fbreadth = (w > h ? h : w) * m_fImgage_Scale_Y; + temerror.nconfig_qx_type = CONFIG_QX_NAME_support_loss; + temerror.qx_name = CONFIG_QX_NAME_Names[temerror.nconfig_qx_type]; + temerror.result = QX_RESULT_TYPE_NG; + temerror.result_name = QX_RESULT_TYPE_Names[QX_RESULT_TYPE_NG]; + temerror.detRegionidxList.push_back(0); + + m_pDetResult->pQx_ErrorList->push_back(temerror); + + m_pdetlog->AddCheckstr(PrintLevel_0, "把手检测", "handle loss NG roi [%d %d %d %d]", roi.x, roi.y, roi.width, roi.height); + } + } + } + return re; } diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c3c5b1..86b13af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,7 @@ message(STATUS "oPENCV Library status:") message(STATUS ">version:${OpenCV_VERSION}") message(STATUS "Include:${OpenCV_INCLUDE_DIRS}") -set(CMAKE_BUILD_TYPE "debug") +set(CMAKE_BUILD_TYPE "release") set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 要求编译器支持 C++17 set(CMAKE_CXX_EXTENSIONS OFF) # 禁用 GNU 特定的扩展 diff --git a/ConfigModule/include/CheckConfigDefine.h b/ConfigModule/include/CheckConfigDefine.h index 040289c..97f1cb3 100644 --- a/ConfigModule/include/CheckConfigDefine.h +++ b/ConfigModule/include/CheckConfigDefine.h @@ -1306,11 +1306,13 @@ struct Base_Function_Edge_Det struct Base_Function_Support_Det { bool bOpen; // 是否开启 - std::vector region; + std::vector supportRegion; cv::RotatedRect supportRect; float x_offset; float y_offset; float r_offset; + std::vector handleRegion; + cv::RotatedRect handleRect; Base_Function_Support_Det() { @@ -1320,21 +1322,24 @@ struct Base_Function_Support_Det void Init() { bOpen = false; - region.clear(); - region.erase(region.begin(), region.end()); + supportRegion.clear(); supportRect = cv::RotatedRect(); x_offset = 0; y_offset = 0; r_offset = 0; + handleRegion.clear(); + handleRect = cv::RotatedRect(); } void copy(Base_Function_Support_Det tem) { this->bOpen = tem.bOpen; - this->region.assign(tem.region.begin(), tem.region.end()); + this->supportRegion.assign(tem.supportRegion.begin(), tem.supportRegion.end()); this->supportRect = tem.supportRect; this->x_offset = tem.x_offset; this->y_offset = tem.y_offset; this->r_offset = tem.r_offset; + this->handleRegion.assign(tem.handleRegion.begin(), tem.handleRegion.end()); + this->handleRect = tem.handleRect; } void print(std::string str) { @@ -1370,6 +1375,7 @@ struct BaseCheckFunction edgeDet.Init(); saveImg.Init(); bigNG.Init(); + supportDet.Init(); } void copy(BaseCheckFunction tem) { @@ -1377,6 +1383,7 @@ struct BaseCheckFunction this->edgeDet.copy(tem.edgeDet); this->saveImg.copy(tem.saveImg); this->bigNG.copy(tem.bigNG); + this->supportDet.copy(tem.supportDet); } void print(std::string str) { @@ -1385,6 +1392,7 @@ struct BaseCheckFunction edgeDet.print("edgeDet"); saveImg.print("saveImg"); bigNG.print("bigNG"); + supportDet.print("supportDet"); } std::string GetInfo(std::string str) { @@ -1393,6 +1401,7 @@ struct BaseCheckFunction str123 += edgeDet.GetInfo("edgeDet"); str123 += saveImg.GetInfo("saveImg"); str123 += bigNG.GetInfo("bigNG"); + str123 += supportDet.GetInfo("supportDet"); // str123 += "\n"; return str123; } diff --git a/ConfigModule/src/JsonConfig.cpp b/ConfigModule/src/JsonConfig.cpp index 2b2d1a8..8450518 100644 --- a/ConfigModule/src/JsonConfig.cpp +++ b/ConfigModule/src/JsonConfig.cpp @@ -857,7 +857,7 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value) _config.supportDet.bOpen = value_f["isOpen"].asBool(); if (_config.supportDet.bOpen) { - + // 支架参数 { auto value_region = value_f["form"]["support_param"]["support_region"]; if (value_region.isArray()) @@ -868,11 +868,11 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value) p.x = value_region[idx][0].asInt(); p.y = value_region[idx][1].asInt(); - _config.supportDet.region.emplace_back(p); + _config.supportDet.supportRegion.emplace_back(p); } - if (_config.supportDet.region.size() > 0) + if (_config.supportDet.supportRegion.size() > 0) { - _config.supportDet.supportRect = minAreaRect(_config.supportDet.region); + _config.supportDet.supportRect = minAreaRect(_config.supportDet.supportRegion); } } } @@ -888,6 +888,26 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value) { _config.supportDet.r_offset = value_f["form"]["support_param"]["r_offset"].asFloat(); } + + // 把手参数 + { + auto value_region = value_f["form"]["handle_param"]["handle_region"]; + if (value_region.isArray()) + { + for (int idx = 0; idx < value_region.size(); idx++) + { + cv::Point p; + p.x = value_region[idx][0].asInt(); + p.y = value_region[idx][1].asInt(); + + _config.supportDet.handleRegion.emplace_back(p); + } + if (_config.supportDet.handleRegion.size() > 0) + { + _config.supportDet.handleRect = minAreaRect(_config.supportDet.handleRegion); + } + } + } } else { diff --git a/example/deal.cpp b/example/deal.cpp index 7b988b8..4eb0cf8 100644 --- a/example/deal.cpp +++ b/example/deal.cpp @@ -459,7 +459,7 @@ int deal::preCheck() std::shared_ptr checkResult; int re = m_pALLImgCheckAnalysisy->GetCheckReuslt(checkResult); - saveImg("/home/aidlux/BOE/ZB_PLATE/testresult/", checkResult); + saveImg("/home/aidlux/BOE/ZB_BACKPLATE/testresult/", checkResult); getresultNum++; if (getresultNum >= m_nPushImgCount) { @@ -805,14 +805,14 @@ void deal::ResultThread(int id) // 存图 // std::string savepath = "/home/aidlux/BOE/Detsave/" + runConfig.filePath + "/"; // saveImg(savepath, dealResult); - saveImg("/home/aidlux/BOE/ZB_PLATE/Detsave/", dealResult); + saveImg("/home/aidlux/BOE/ZB_BACKPLATE/Detsave/", dealResult); } { // 存 检测统计 日志 mutex_DetResult_.lock(); m_DetResult.print(false); - std::string strlog = "/home/aidlux/BOE/ZB_PLATE/ResultImg/"; + std::string strlog = "/home/aidlux/BOE/ZB_BACKPLATE/ResultImg/"; if (m_strCurDate != "") { strlog += m_strCurDate;