From b663c7f67635de8a735877a62c6fce42f074f2b7 Mon Sep 17 00:00:00 2001 From: liusiyang Date: Wed, 12 Aug 2026 09:32:20 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E5=90=8C=E6=AD=A5=E4=BA=91=E5=B9=B3?= =?UTF-8?q?=E5=8F=B0=E8=BE=B9=E6=8D=9F=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AlgorithmModule/include/Edge_QX_Det.h | 10 +- AlgorithmModule/include/ImgCheckAnalysisy.hpp | 4 +- AlgorithmModule/src/Edge_QX_Det.cpp | 457 ++++++++++++++---- AlgorithmModule/src/ImgCheckAnalysisy.cpp | 292 ++++++++--- ConfigModule/include/CheckConfigDefine.h | 25 +- ConfigModule/src/JsonConfig.cpp | 12 +- 6 files changed, 623 insertions(+), 177 deletions(-) diff --git a/AlgorithmModule/include/Edge_QX_Det.h b/AlgorithmModule/include/Edge_QX_Det.h index 15cadcd..5da7f8f 100644 --- a/AlgorithmModule/include/Edge_QX_Det.h +++ b/AlgorithmModule/include/Edge_QX_Det.h @@ -134,8 +134,9 @@ public: // 检测小区域的信息 struct Det_ROI_Config { - cv::Rect roi; - std::vector plist; + cv::Rect roi; // 轴对齐包围盒(由 rrect.boundingRect() 计算,保持兼容) + cv::RotatedRect rrect; // 旋转矩形,贴合倾斜产品的边缘方向,避免过检 + std::vector plist; // 检测区域的多边形顶点 }; struct Algin_Result { @@ -215,10 +216,15 @@ private: // 检测缺陷 int Det_qx(const cv::Mat &img, std::vector roilist, Det_ROI_Type type, DetConfigResult *pDetConfig); + // 多边形边缘缺陷检测(无方向/角点过滤,每个ROI独立处理,避免巨型mask) + int Det_qx_polygon(const cv::Mat &img, const std::vector &roilist, 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); + // 使用定位区域巡边检测 + int Draw_Det_Align(const cv::Mat &img, DetConfigResult *pDetConfig); private: /// @brief diff --git a/AlgorithmModule/include/ImgCheckAnalysisy.hpp b/AlgorithmModule/include/ImgCheckAnalysisy.hpp index ed407d8..834b9e9 100644 --- a/AlgorithmModule/include/ImgCheckAnalysisy.hpp +++ b/AlgorithmModule/include/ImgCheckAnalysisy.hpp @@ -287,8 +287,8 @@ private: // AI mask 在这一列是否有 缺陷残点,用以 加速 blob 分析。 unsigned char *m_ImgBlobHFlagData; - // 原始区域数据 - Rect m_old_productROI = Rect(0, 0, 0, 0); + // 原始区域数据(使用 RotatedRect 以保留 region 的旋转角度信息) + cv::RotatedRect m_old_productROI; std::vector m_old_cur_edgeDet_region; std::vector m_old_cur_markLine_region; std::vector m_old_cur_traditional_region; diff --git a/AlgorithmModule/src/Edge_QX_Det.cpp b/AlgorithmModule/src/Edge_QX_Det.cpp index db31521..de06438 100644 --- a/AlgorithmModule/src/Edge_QX_Det.cpp +++ b/AlgorithmModule/src/Edge_QX_Det.cpp @@ -210,9 +210,15 @@ int Edge_QX_Det::Detect(const cv::Mat &img, DetConfigResult *pDetConfig) { return 0; } + if(pDetConfig->pBaseCheckFunction->edgeDet.bUseAlignRoi) + { + int re = Draw_Det_Align(img, pDetConfig); + return re; + } if (pDetConfig->pBaseCheckFunction->edgeDet.bDrawRoi) { - return Draw_Det(img, pDetConfig); + int re = Draw_Det(img, pDetConfig); + return re; } // if (pDetConfig->strChannel == "TA") @@ -313,59 +319,6 @@ int Edge_QX_Det::Detect(const cv::Mat &img, DetConfigResult *pDetConfig) } // 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; - // 用RANSAC剔除崩边凹陷的异常点后,拟合二次曲线使ROI贴合产品边缘的自然弧度 // 水平边缘(上下): 拟合 y = a*x² + b*x + c // 垂直边缘(左右): 拟合 x = a*y² + b*y + c @@ -487,8 +440,62 @@ int Edge_QX_Det::Detect(const cv::Mat &img, DetConfigResult *pDetConfig) } } + // 曲线拟合后重新计算角点,使角点与拟合后的线段端点对齐 + std::vector cornerPoints; + cv::Point2f pt; + cornerPoints.clear(); + // 左上角: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; + int range_offset = pDetConfig->pBaseCheckFunction->edgeDet.Det_Range_Offset; + cv::Rect imgBounds(0, 0, img.cols, img.rows); // 图像边界,用于裁剪越界 ROI std::vector up_det_roi; @@ -498,52 +505,56 @@ int Edge_QX_Det::Detect(const cv::Mat &img, DetConfigResult *pDetConfig) 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) & imgBounds; - if (tem.roi.width <= 0 || tem.roi.height <= 0) continue; + tem.plist.push_back(cv::Point(line.p1.x, line.p1.y + range_offset)); + tem.plist.push_back(cv::Point(line.p2.x, line.p2.y + range_offset)); + + tem.plist.push_back(cv::Point(line.p2.x, line.p2.y + range_offset + roi_wh)); + tem.plist.push_back(cv::Point(line.p1.x, line.p1.y + range_offset + roi_wh)); + tem.rrect = cv::minAreaRect(tem.plist); + tem.roi = tem.rrect.boundingRect() & imgBounds; + if (tem.rrect.size.width <= 0 || tem.rrect.size.height <= 0) continue; 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) & imgBounds; - if (tem.roi.width <= 0 || tem.roi.height <= 0) continue; + tem.plist.push_back(cv::Point(line.p1.x, line.p1.y - range_offset)); + tem.plist.push_back(cv::Point(line.p2.x, line.p2.y - range_offset)); + tem.plist.push_back(cv::Point(line.p2.x, line.p2.y - range_offset - roi_wh)); + tem.plist.push_back(cv::Point(line.p1.x, line.p1.y - range_offset - roi_wh)); + + tem.rrect = cv::minAreaRect(tem.plist); + tem.roi = tem.rrect.boundingRect() & imgBounds; + if (tem.rrect.size.width <= 0 || tem.rrect.size.height <= 0) continue; 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) & imgBounds; - if (tem.roi.width <= 0 || tem.roi.height <= 0) continue; + tem.plist.push_back(cv::Point(line.p1.x + range_offset, line.p1.y)); + tem.plist.push_back(cv::Point(line.p2.x + range_offset, line.p2.y)); + tem.plist.push_back(cv::Point(line.p2.x + range_offset + roi_wh, line.p2.y)); + tem.plist.push_back(cv::Point(line.p1.x + range_offset + roi_wh, line.p1.y)); + + tem.rrect = cv::minAreaRect(tem.plist); + tem.roi = tem.rrect.boundingRect() & imgBounds; + if (tem.rrect.size.width <= 0 || tem.rrect.size.height <= 0) continue; 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) & imgBounds; - if (tem.roi.width <= 0 || tem.roi.height <= 0) continue; + tem.plist.push_back(cv::Point(line.p1.x - range_offset, line.p1.y)); + tem.plist.push_back(cv::Point(line.p2.x - range_offset, line.p2.y)); + tem.plist.push_back(cv::Point(line.p2.x - range_offset - roi_wh, line.p2.y)); + tem.plist.push_back(cv::Point(line.p1.x - range_offset - roi_wh, line.p1.y)); + + tem.rrect = cv::minAreaRect(tem.plist); + tem.roi = tem.rrect.boundingRect() & imgBounds; + if (tem.rrect.size.width <= 0 || tem.rrect.size.height <= 0) continue; pDetConfig->edge_det_roi.push_back(tem); right_det_roi.push_back(tem); } @@ -602,7 +613,10 @@ int Edge_QX_Det::Detect(const cv::Mat &img, DetConfigResult *pDetConfig) } for (const auto &r : pDetConfig->edge_det_roi) { - cv::rectangle(showimg, r.roi, cv::Scalar(255, 0, 255), 3); // 黄色角点 + cv::Point2f vertices[4]; + r.rrect.points(vertices); + for (int j = 0; j < 4; j++) + cv::line(showimg, vertices[j], vertices[(j+1)%4], cv::Scalar(255, 0, 255), 3); } for (const auto r : pDetConfig->qx_result) { @@ -1072,29 +1086,38 @@ int Edge_QX_Det::Det_qx(const cv::Mat &img, std::vector roilist, return -12; } Base_Function_Edge_Det *pedgeDet = &pDetConfig->pBaseCheckFunction->edgeDet; - vector allPoints; + if (roilist.empty()) + { + return 1; + } + cv::Rect DetRoi; for (const auto &ROI : roilist) { - allPoints.insert(allPoints.end(), ROI.plist.begin(), ROI.plist.end()); + DetRoi = DetRoi | ROI.roi; } - if (allPoints.size() <= 0) + if (DetRoi.width <= 0 || DetRoi.height <= 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); + if (mask.empty()) + continue; 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); + detimg_roi.width = mask.cols; // 使用 mask 实际尺寸,而非 ROI.roi 尺寸,避免裁剪后不一致 + detimg_roi.height = mask.rows; + // 安全检查:确保 detimg_roi 在 roiMask 范围内 + cv::Rect safeDetRoi = detimg_roi & cv::Rect(0, 0, roiMask.cols, roiMask.rows); + if (safeDetRoi.width <= 0 || safeDetRoi.height <= 0) + continue; + mask.copyTo(roiMask(safeDetRoi), mask); } int erx = pedgeDet->QX_Widht_min; int ery = pedgeDet->QX_Height_min; @@ -1257,6 +1280,66 @@ int Edge_QX_Det::Det_qx(const cv::Mat &img, std::vector roilist, return 0; } +// ===== 多边形模式缺陷检测:无方向/角点过滤,逐ROI独立处理避免巨型mask ===== +int Edge_QX_Det::Det_qx_polygon(const cv::Mat &img, const std::vector &roilist, DetConfigResult *pDetConfig) +{ + if (img.empty()) return -11; + if (img.channels() != 1) return -12; + + Base_Function_Edge_Det *pedgeDet = &pDetConfig->pBaseCheckFunction->edgeDet; + if (roilist.empty()) return 1; + + int erx = std::max(pedgeDet->QX_Widht_min, 3); + int ery = std::max(pedgeDet->QX_Height_min, 3); + cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(erx, ery)); + + for (const auto &ROI : roilist) + { + cv::Rect safeRoi = ROI.roi & cv::Rect(0, 0, img.cols, img.rows); + if (safeRoi.width <= 0 || safeRoi.height <= 0) continue; + + // 二值化:暗区(产品)=255 + cv::Mat binary; + cv::compare(img(safeRoi), pedgeDet->Det_threshold, binary, cv::CMP_LT); + + // 多边形 mask(局部坐标) + std::vector localPts; + localPts.reserve(ROI.plist.size()); + for (const auto &pt : ROI.plist) + localPts.emplace_back(pt.x - safeRoi.x, pt.y - safeRoi.y); + cv::Mat polyMask = cv::Mat::zeros(safeRoi.size(), CV_8UC1); + cv::fillPoly(polyMask, std::vector>{localPts}, 255); + + // 应用 mask + cv::Mat result = cv::Mat::zeros(safeRoi.size(), CV_8UC1); + binary.copyTo(result, polyMask); + + // 形态学开操作 + cv::morphologyEx(result, result, cv::MORPH_OPEN, kernel); + + // 找轮廓 → 尺寸过滤 + std::vector> contours; + cv::findContours(result, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); + for (size_t i = 0; i < contours.size(); ++i) + { + cv::Rect rect = cv::boundingRect(contours[i]); + 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) + { + QX_Result tem; + tem.roi_src.x = rect.x + safeRoi.x; + tem.roi_src.y = rect.y + safeRoi.y; + tem.roi_src.width = rect.width; + tem.roi_src.height = rect.height; + tem.area_pixel = cv::contourArea(contours[i]); + pDetConfig->qx_result.push_back(tem); + } + } + } + + return 0; +} + int Edge_QX_Det::applyMaskInROI(const cv::Mat &grayImg, const Det_ROI_Config &config, cv::Mat &result, int threshold) { // 0. 裁剪 ROI,防止 RANSAC 投影后越界 @@ -1268,11 +1351,9 @@ int Edge_QX_Det::applyMaskInROI(const cv::Mat &grayImg, const Det_ROI_Config &co } // 1. 获取 ROI 区域图像(不 clone,只引用) cv::Mat roiGray = grayImg(safeRoi); - // 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); + cv::compare(roiGray, threshold, binary, cv::CMP_LT); // binary = gray < threshold ? 255 : 0 // 3. 构建局部坐标的多边形(相对于裁剪后的 safeRoi) std::vector localPts; localPts.reserve(config.plist.size()); @@ -1282,11 +1363,9 @@ int Edge_QX_Det::applyMaskInROI(const cv::Mat &grayImg, const Det_ROI_Config &co // 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; } @@ -1313,8 +1392,8 @@ int Edge_QX_Det::Draw_Det(const cv::Mat &img, DetConfigResult *pDetConfig) 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; + pc.x = p.x - pDetConfig->alginResult.corpRoi.x; + pc.y = p.y - pDetConfig->alginResult.corpRoi.y; } else { @@ -1397,6 +1476,190 @@ int Edge_QX_Det::Draw_Det(const cv::Mat &img, DetConfigResult *pDetConfig) return 0; } +int Edge_QX_Det::Draw_Det_Align(const cv::Mat &img, DetConfigResult *pDetConfig) +{ + Base_Function_Edge_Det *pedgeDet = &pDetConfig->pBaseCheckFunction->edgeDet; + if (pedgeDet->Align_region.size() <= 2) + { + return 1; + } + + // ===== 第1步:精细化边缘点 ===== + // 在每个Align_region点周围100x100区域内,用二值化+轮廓找最接近中心的实际边缘点 + std::vector Det_region; + for(auto p : pedgeDet->Align_region) + { + cv::Rect orig_roi(p.x - 50, p.y - 50, 100, 100); + cv::Rect c_roi_100 = orig_roi & cv::Rect(0, 0, img.cols, img.rows); + if (c_roi_100.width <= 0 || c_roi_100.height <= 0) + { + Det_region.push_back(p); + continue; + } + cv::Mat c_img = img(c_roi_100); + + // 二值化:产品区域为暗(低灰度),背景为亮(高灰度),THRESH_BINARY_INV 使暗区变白 + cv::Mat binary; + cv::threshold(c_img, binary, pedgeDet->Det_threshold, 255, cv::THRESH_BINARY_INV); + + // 找轮廓 + std::vector> contours; + cv::findContours(binary, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); + + // 找最接近中心的边缘点 + // 中心在原始100x100区域中为(50,50),裁剪后需要偏移 + cv::Point center_in_roi(50 - (orig_roi.x - c_roi_100.x), 50 - (orig_roi.y - c_roi_100.y)); + cv::Point best_pt; + double best_dist = 1e10; + bool found = false; + + for (const auto& contour : contours) + { + for (const auto& pt : contour) + { + double dist = (pt.x - center_in_roi.x) * (pt.x - center_in_roi.x) + + (pt.y - center_in_roi.y) * (pt.y - center_in_roi.y); + if (dist < best_dist) + { + best_dist = dist; + best_pt = pt; + found = true; + } + } + } + + if (found) + Det_region.push_back(cv::Point(best_pt.x + c_roi_100.x, best_pt.y + c_roi_100.y)); + else + Det_region.push_back(p); // 未找到边缘点则回退使用原始点 + } + + if (Det_region.size() <= 2) + { + return 1; + } + + // ===== 第2步:计算向内偏移的多边形 ===== + // 使用多边形有向面积判断顶点顺序,确保向内法向量方向正确 + int inward_offset = pedgeDet->Det_Range; // 使用配置的检测范围作为内缩距离 + int range_offset = pedgeDet->Det_Range_Offset; // 可选的额外偏移量 + if (inward_offset <= 0) inward_offset = 50; + + size_t n = Det_region.size(); + + // 计算有向面积判断多边形方向(CCW为正) + float signed_area = 0; + for (size_t i = 0; i < n; i++) + { + size_t j = (i + 1) % n; + signed_area += (float)Det_region[i].x * Det_region[j].y - + (float)Det_region[j].x * Det_region[i].y; + } + bool isCCW = (signed_area > 0); // 逆时针: 左法线指向内部 + + std::vector inner_pts(n); + std::vector outer_pts(n); + for (size_t i = 0; i < n; i++) + { + cv::Point2f prev = Det_region[(i + n - 1) % n]; + cv::Point2f curr = Det_region[i]; + cv::Point2f next = Det_region[(i + 1) % n]; + + // 入边方向 + cv::Point2f dir1 = curr - prev; + float len1 = cv::norm(dir1); + if (len1 > 1e-6f) dir1 = dir1 / len1; + + // 出边方向 + cv::Point2f dir2 = next - curr; + float len2 = cv::norm(dir2); + if (len2 > 1e-6f) dir2 = dir2 / len2; + + // 向内法向量 + cv::Point2f normal1, normal2; + if (isCCW) + { + normal1 = cv::Point2f(-dir1.y, dir1.x); // 左法线 = 向内(CCW) + normal2 = cv::Point2f(-dir2.y, dir2.x); + } + else + { + normal1 = cv::Point2f(dir1.y, -dir1.x); // 右法线 = 向内(CW) + normal2 = cv::Point2f(dir2.y, -dir2.x); + } + + // 角平分线方向 + cv::Point2f bisector = normal1 + normal2; + float bis_len = cv::norm(bisector); + if (bis_len < 1e-6f) + { + bisector = normal1; // 两边共线退化情况 + bis_len = cv::norm(bisector); + } + if (bis_len > 1e-6f) + bisector = bisector / bis_len; + + // 内边界 = range_offset + inward_offset(ROI高度仍为 inward_offset) + inner_pts[i] = curr + (range_offset + inward_offset) * bisector; + // 外边界 = range_offset(整个ROI向产品内部平移 range_offset) + outer_pts[i] = curr + range_offset * bisector; + } + + // ===== 第3步:生成检测ROI ===== + cv::Rect imgBounds(0, 0, img.cols, img.rows); + for (size_t i = 0; i < n; i++) + { + size_t j = (i + 1) % n; + Det_ROI_Config tem; + tem.plist.push_back(cv::Point(cvRound(outer_pts[i].x), cvRound(outer_pts[i].y))); + tem.plist.push_back(cv::Point(cvRound(outer_pts[j].x), cvRound(outer_pts[j].y))); + tem.plist.push_back(cv::Point(cvRound(inner_pts[j].x), cvRound(inner_pts[j].y))); + tem.plist.push_back(cv::Point(cvRound(inner_pts[i].x), cvRound(inner_pts[i].y))); + tem.rrect = cv::minAreaRect(tem.plist); + tem.roi = tem.rrect.boundingRect() & imgBounds; + if (tem.rrect.size.width <= 0 || tem.rrect.size.height <= 0) continue; + pDetConfig->edge_det_roi.push_back(tem); + } + // ===== 第4步:缺陷检测(多边形模式,逐ROI独立处理) ===== + Det_qx_polygon(img, pDetConfig->edge_det_roi, pDetConfig); + + if (bshowimg) + { + cv::cvtColor(img, showimg, cv::COLOR_GRAY2BGR); + // 绘制外多边形(边缘点连线) + for (size_t i = 0; i < n; i++) + { + size_t j = (i + 1) % n; + cv::line(showimg, Det_region[i], Det_region[j], cv::Scalar(0, 255, 0), 2); + cv::circle(showimg, Det_region[i], 4, cv::Scalar(0, 255, 255), -1); + } + // 绘制内缩多边形 + for (size_t i = 0; i < n; i++) + { + size_t j = (i + 1) % n; + cv::Point pi(cvRound(inner_pts[i].x), cvRound(inner_pts[i].y)); + cv::Point pj(cvRound(inner_pts[j].x), cvRound(inner_pts[j].y)); + cv::line(showimg, pi, pj, cv::Scalar(255, 0, 0), 2); + } + // 绘制检测ROI + for (const auto &r : pDetConfig->edge_det_roi) + { + cv::Point2f vertices[4]; + r.rrect.points(vertices); + for (int j = 0; j < 4; j++) + cv::line(showimg, vertices[j], vertices[(j+1)%4], cv::Scalar(255, 0, 255), 2); + } + // 绘制检测到的缺陷 + for (const auto &r : pDetConfig->qx_result) + { + cv::rectangle(showimg, r.roi_src, cv::Scalar(255, 22, 100), 3); + } + cv::imwrite(pDetConfig->strChannel + "_edge_align_show.png", showimg); + } + + 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()) diff --git a/AlgorithmModule/src/ImgCheckAnalysisy.cpp b/AlgorithmModule/src/ImgCheckAnalysisy.cpp index d8726b2..10c11dc 100644 --- a/AlgorithmModule/src/ImgCheckAnalysisy.cpp +++ b/AlgorithmModule/src/ImgCheckAnalysisy.cpp @@ -451,12 +451,12 @@ Point2f GetCoorPoint(Point2f point, Mat img_mat) return new_point; } -int GetEdgeRoi(Mat img, Rect &new_roi, float scale_x, float scale_y){ +int GetEdgeRoi(Mat img, Rect &new_roi, cv::RotatedRect &rotated_roi, float scale_x, float scale_y){ if (img.empty()) { return 1; } - // 缩小,减少耗时 + // ============ Stage 1: 粗定位(大尺度缩小,速度快)============ Mat r_img; int resize_width = static_cast(img.cols / scale_x); @@ -489,22 +489,116 @@ int GetEdgeRoi(Mat img, Rect &new_roi, float scale_x, float scale_y){ return 3; } - cv::Rect small_roi = cv::boundingRect(contours[maxAreaIdx]); - Rect roi; - roi.x = static_cast(small_roi.x * scale_x); - roi.y = static_cast(small_roi.y * scale_y); - roi.width = static_cast(small_roi.width * scale_x); - roi.height = static_cast(small_roi.height * scale_y); - roi.x = std::max(0, roi.x); - roi.y = std::max(0, roi.y); - roi.width = std::min(roi.width, img.cols - roi.x); - roi.height = std::min(roi.height, img.rows - roi.y); - - new_roi = roi; + // 使用minAreaRect获取带旋转角度的最小外接矩形 + cv::RotatedRect coarse_rotated_tmp = cv::minAreaRect(contours[maxAreaIdx]); + cv::RotatedRect coarse_rotated; + coarse_rotated.center.x = coarse_rotated_tmp.center.x * scale_x; + coarse_rotated.center.y = coarse_rotated_tmp.center.y * scale_y; + coarse_rotated.size.width = coarse_rotated_tmp.size.width * scale_x; + coarse_rotated.size.height = coarse_rotated_tmp.size.height * scale_y; + coarse_rotated.angle = coarse_rotated_tmp.angle; + cv::Rect coarse_roi = coarse_rotated.boundingRect(); + coarse_roi.x = std::max(0, coarse_roi.x); + coarse_roi.y = std::max(0, coarse_roi.y); + coarse_roi.width = std::min(coarse_roi.width, img.cols - coarse_roi.x); + coarse_roi.height = std::min(coarse_roi.height, img.rows - coarse_roi.y); + + // ============ Stage 2: 精修(小尺度,只处理裁剪后的局部区域)============ + // 粗定位精度损失约 scale_x/scale_y 个像素,扩展 margin 确保包含真实边界 + const float fine_scale = 4.0f; // 精修阶段缩放倍率,越小越精确 + int margin_x = static_cast(scale_x * 2); // 补偿粗定位误差 + int margin_y = static_cast(scale_y * 2); + + Rect fine_roi; + fine_roi.x = std::max(0, coarse_roi.x - margin_x); + fine_roi.y = std::max(0, coarse_roi.y - margin_y); + fine_roi.width = std::min(coarse_roi.width + 2 * margin_x, img.cols - fine_roi.x); + fine_roi.height = std::min(coarse_roi.height + 2 * margin_y, img.rows - fine_roi.y); + + Mat fine_region = img(fine_roi); + int fine_w = static_cast(fine_region.cols / fine_scale); + int fine_h = static_cast(fine_region.rows / fine_scale); + + // 精修区域足够大时才做细化 + if (fine_w > 50 && fine_h > 50) + { + Mat fine_resized; + resize(fine_region, fine_resized, Size(fine_w, fine_h), 0, 0, INTER_LINEAR); + + Mat fine_bin; + threshold(fine_resized, fine_bin, 15, 255, THRESH_BINARY); + + std::vector> fine_contours; + cv::findContours(fine_bin, fine_contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); + + if (!fine_contours.empty()) + { + double fine_maxArea = 0; + int fine_maxIdx = -1; + for (size_t i = 0; i < fine_contours.size(); ++i) + { + double area = cv::contourArea(fine_contours[i]); + if (area > fine_maxArea) + { + fine_maxArea = area; + fine_maxIdx = i; + } + } + + if (fine_maxIdx >= 0) + { + // 使用minAreaRect获取带旋转角度的最小外接矩形(保留旋转信息) + cv::RotatedRect fine_rotated = cv::minAreaRect(fine_contours[fine_maxIdx]); + // 映射回原图坐标:center缩放+平移,size按比例缩放,角度不变 + rotated_roi.center.x = fine_rotated.center.x * fine_scale + fine_roi.x; + rotated_roi.center.y = fine_rotated.center.y * fine_scale + fine_roi.y; + rotated_roi.size.width = fine_rotated.size.width * fine_scale; + rotated_roi.size.height = fine_rotated.size.height * fine_scale; + rotated_roi.angle = fine_rotated.angle; + // 取旋转矩形的轴对齐外接框作为new_roi(用于ROI裁剪等场景) + cv::Rect fine_small = rotated_roi.boundingRect(); + Rect refined_roi; + refined_roi.x = fine_small.x; + refined_roi.y = fine_small.y; + refined_roi.width = fine_small.width; + refined_roi.height = fine_small.height; + refined_roi.x = std::max(0, refined_roi.x); + refined_roi.y = std::max(0, refined_roi.y); + refined_roi.width = std::min(refined_roi.width, img.cols - refined_roi.x); + refined_roi.height = std::min(refined_roi.height, img.rows - refined_roi.y); + + new_roi = refined_roi; + return 0; + } + } + } + // 精修失败则回退到粗定位结果 + new_roi = coarse_roi; + rotated_roi = coarse_rotated; return 0; } +std::vector sort_vertices(cv::RotatedRect rrect) { + cv::Point2f pts[4]; + rrect.points(pts); + std::vector vertices(pts, pts + 4); + + // 按 y 坐标升序排序 + std::sort(vertices.begin(), vertices.end(), + [](const cv::Point2f& a, const cv::Point2f& b) { + return a.y < b.y; + }); + + if (vertices[0].x > vertices[1].x) + std::swap(vertices[0], vertices[1]); + + if (vertices[2].x > vertices[3].x) + std::swap(vertices[2], vertices[3]); + + return vertices; +} + int ImgCheckAnalysisy::Adapt_Config(Mat img, Rect cur_roi, bool b_update){ if (img.empty()) { std::cerr << "Error: Input image 'img' is empty!" << std::endl; @@ -513,16 +607,17 @@ int ImgCheckAnalysisy::Adapt_Config(Mat img, Rect cur_roi, bool b_update){ if(!b_update){ return 1; } - int get_edge_roi = GetEdgeRoi(img, cur_roi, 20, 20); + cv::RotatedRect rot_cur_roi; + int get_edge_roi = GetEdgeRoi(img, cur_roi, rot_cur_roi, 20, 20); if(get_edge_roi != 0){ return 2; } m_pdetlog->AddCheckstr(PrintLevel_0, "Adapt_Config", "-------------------start--------------"); /*计算xy偏移,缩放比例*/ - // 拷贝原始数据 - if(m_old_productROI.width == 0 || m_old_productROI.height == 0){ - m_old_productROI = m_AnalysisyConfig.baseFunction.markLine.productROI; + // 拷贝原始数据(old_productROI 使用 markLine.region 的 minAreaRect,保留旋转角度) + if(m_old_productROI.size.width == 0 || m_old_productROI.size.height == 0){ + m_old_productROI = cv::minAreaRect(m_AnalysisyConfig.baseFunction.markLine.region); m_old_cur_edgeDet_region = m_AnalysisyConfig.baseFunction.edgeDet.region; m_old_cur_markLine_region = m_AnalysisyConfig.baseFunction.markLine.region; m_old_cur_markLine_mark1 = m_AnalysisyConfig.baseFunction.markLine.mark_local_1; @@ -530,23 +625,35 @@ int ImgCheckAnalysisy::Adapt_Config(Mat img, Rect cur_roi, bool b_update){ m_old_cur_regionConfigArr = m_AnalysisyConfig.commonCheckConfig.nodeConfigArr[0].regionConfigArr; m_old_cur_traditional_region = m_pbaseCheckFunction->traditionDet.detArea; } - Rect old_roi = m_old_productROI; - Point old_center(old_roi.x + old_roi.width / 2, old_roi.y + old_roi.height / 2); - Point new_center(cur_roi.x + cur_roi.width / 2, cur_roi.y + cur_roi.height / 2); - int x_offset = new_center.x - old_center.x; - int y_offset = new_center.y - old_center.y; - float scale_x = (float)cur_roi.width / (float)old_roi.width; - float scale_y = (float)cur_roi.height / (float)old_roi.height; - - m_pdetlog->AddCheckstr(PrintLevel_0, "Adapt_Config", "old_roi = %d %d %d %d", old_roi.x, old_roi.y, old_roi.width, old_roi.height); - m_pdetlog->AddCheckstr(PrintLevel_0, "Adapt_Config", "cur_roi = %d %d %d %d", cur_roi.x, cur_roi.y, cur_roi.width, cur_roi.height); - m_pdetlog->AddCheckstr(PrintLevel_0, "Adapt_Config", "x_offset = %d y_offset = %d", x_offset, y_offset); - m_pdetlog->AddCheckstr(PrintLevel_0, "Adapt_Config", "scale_x = %f scale_y = %f", scale_x, scale_y); - - if(abs(x_offset) < 50 && abs(y_offset) < 50 && abs(scale_x - 1) < 0.0001 && abs(scale_y - 1) < 0.0001 ){ - return 3; - } + /*计算old_roi到new_roi的完整仿射变换矩阵(平移+缩放+旋转)*/ + // old使用 minAreaRect(region) 的顶点,new使用 GetEdgeRoi 检测到的旋转矩形顶点 + vector old_vertices = sort_vertices(m_old_productROI); + vector new_vertices = sort_vertices(rot_cur_roi); + + cv::Point2f src_pts[3] = { + old_vertices[0], // 左上 + old_vertices[1], // 右上 + old_vertices[2] // 左下 + }; + cv::Point2f dst_pts[3] = { + new_vertices[0], // 对应左上 + new_vertices[1], // 对应右上 + new_vertices[2] // 对应左下 + }; + cv::Mat affine_mat = cv::getAffineTransform(src_pts, dst_pts); + + m_pdetlog->AddCheckstr(PrintLevel_0, "Adapt_Config", "affine_mat = [%f %f %f; %f %f %f]", + affine_mat.at(0,0), affine_mat.at(0,1), affine_mat.at(0,2), + affine_mat.at(1,0), affine_mat.at(1,1), affine_mat.at(1,2)); + + // 单点仿射变换的lambda (直接使用矩阵,涵盖平移+缩放+旋转) + auto affinePoint = [&](const cv::Point& p) -> cv::Point { + return cv::Point( + cvRound(affine_mat.at(0,0) * p.x + affine_mat.at(0,1) * p.y + affine_mat.at(0,2)), + cvRound(affine_mat.at(1,0) * p.x + affine_mat.at(1,1) * p.y + affine_mat.at(1,2)) + ); + }; /*获取待修改的region引用*/ std::vector& cur_edgeDet_region = m_AnalysisyConfig.baseFunction.edgeDet.region; @@ -557,61 +664,104 @@ int ImgCheckAnalysisy::Adapt_Config(Mat img, Rect cur_roi, bool b_update){ cv::Rect& cur_traditional_rect = m_pbaseCheckFunction->traditionDet.detArea_ROI; std::vector& cur_traditional_region = m_pbaseCheckFunction->traditionDet.detArea; - /*进行修改*/ + // if (img.empty()) + // { + // return 0; + // } + // Mat show_img = img.clone(); + // cvtColor(show_img, show_img, COLOR_GRAY2BGR); + // // 确保 productROI 在图像范围内 + // cv::Rect safe_roi = m_AnalysisyConfig.baseFunction.markLine.productROI; + // safe_roi &= cv::Rect(0, 0, show_img.cols, show_img.rows); + // if (safe_roi.width > 0 && safe_roi.height > 0) + // { + // cv::rectangle(show_img, safe_roi, Scalar(255,255,255), 5); + // } + // if (cur_edgeDet_region.size() >= 2) + // { + // for(size_t i = 0 ; i < cur_edgeDet_region.size() - 1; i++){ + // cv::line(show_img, cur_edgeDet_region[i], cur_edgeDet_region[i+1], Scalar(0,255,0), 20); + // } + // cv::line(show_img, cur_edgeDet_region.back(), cur_edgeDet_region.front(), Scalar(0,255,0), 20); + // } + // if (cur_markLine_region.size() >= 2) + // { + // for(size_t i = 0 ; i < cur_markLine_region.size() - 1; i++){ + // cv::line(show_img, cur_markLine_region[i], cur_markLine_region[i+1], Scalar(0,0,255), 20); + // } + // cv::line(show_img, cur_markLine_region.back(), cur_markLine_region.front(), Scalar(0,0,255), 20); + // } + // for(size_t i = 0 ; i < cur_regionConfigArr.size(); i++){ + // if (cur_regionConfigArr[i].basicInfo.pointArry.size() >= 2) + // { + // for(size_t j = 0; j < cur_regionConfigArr[i].basicInfo.pointArry.size() - 1; j++){ + // cv::line(show_img, cur_regionConfigArr[i].basicInfo.pointArry[j], cur_regionConfigArr[i].basicInfo.pointArry[j+1], Scalar(255,0,0), 10); + // } + // cv::line(show_img, cur_regionConfigArr[i].basicInfo.pointArry.back(), cur_regionConfigArr[i].basicInfo.pointArry.front(), Scalar(255,0,0), 10); + // } + // } + // imwrite(m_AnalysisyConfig.commonCheckConfig.baseConfig.strCamearName +"_org_img.tiff", show_img); + + /*使用仿射矩阵进行修改*/ // rect m_AnalysisyConfig.baseFunction.markLine.productROI = cur_roi; // point - cur_markLine_mark1.x = m_old_cur_markLine_mark1.x + x_offset; - cur_markLine_mark1.y = m_old_cur_markLine_mark1.y + y_offset; - cur_markLine_mark1 = Point((cur_markLine_mark1.x - new_center.x) * scale_x + new_center.x, (cur_markLine_mark1.y - new_center.y) * scale_y + new_center.y); - cur_markLine_mark2.x = m_old_cur_markLine_mark2.x + x_offset; - cur_markLine_mark2.y = m_old_cur_markLine_mark2.y + y_offset; - cur_markLine_mark2 = Point((cur_markLine_mark2.x - new_center.x) * scale_x + new_center.x, (cur_markLine_mark2.y - new_center.y) * scale_y + new_center.y); + cur_markLine_mark1 = affinePoint(m_old_cur_markLine_mark1); + cur_markLine_mark2 = affinePoint(m_old_cur_markLine_mark2); // region for(int i = 0; i < cur_edgeDet_region.size(); i++){ - cur_edgeDet_region[i].x = m_old_cur_edgeDet_region[i].x + x_offset; - cur_edgeDet_region[i].y = m_old_cur_edgeDet_region[i].y + y_offset; - cur_edgeDet_region[i] = Point((cur_edgeDet_region[i].x - new_center.x) * scale_x + new_center.x, (cur_edgeDet_region[i].y - new_center.y) * scale_y + new_center.y); + cur_edgeDet_region[i] = affinePoint(m_old_cur_edgeDet_region[i]); } for(int i = 0; i < cur_markLine_region.size(); i++){ - cur_markLine_region[i].x = m_old_cur_markLine_region[i].x + x_offset; - cur_markLine_region[i].y = m_old_cur_markLine_region[i].y + y_offset; - cur_markLine_region[i] = Point((cur_markLine_region[i].x - new_center.x) * scale_x + new_center.x, (cur_markLine_region[i].y - new_center.y) * scale_y + new_center.y); + cur_markLine_region[i] = affinePoint(m_old_cur_markLine_region[i]); } for(int i = 0 ; i < cur_regionConfigArr.size(); i++){ for(int j = 0; j < cur_regionConfigArr[i].basicInfo.pointArry.size(); j++){ - cur_regionConfigArr[i].basicInfo.pointArry[j].x = m_old_cur_regionConfigArr[i].basicInfo.pointArry[j].x + x_offset; - cur_regionConfigArr[i].basicInfo.pointArry[j].y = m_old_cur_regionConfigArr[i].basicInfo.pointArry[j].y + y_offset; - cur_regionConfigArr[i].basicInfo.pointArry[j] = Point((cur_regionConfigArr[i].basicInfo.pointArry[j].x - new_center.x) * scale_x + new_center.x, (cur_regionConfigArr[i].basicInfo.pointArry[j].y - new_center.y) * scale_y + new_center.y); + cur_regionConfigArr[i].basicInfo.pointArry[j] = affinePoint(m_old_cur_regionConfigArr[i].basicInfo.pointArry[j]); } } for(int i = 0; i < cur_traditional_region.size(); i++){ - cur_traditional_region[i].x = m_old_cur_traditional_region[i].x + x_offset; - cur_traditional_region[i].y = m_old_cur_traditional_region[i].y + y_offset; - cur_traditional_region[i] = Point((cur_traditional_region[i].x - new_center.x) * scale_x + new_center.x, (cur_traditional_region[i].y - new_center.y) * scale_y + new_center.y); + cur_traditional_region[i] = affinePoint(m_old_cur_traditional_region[i]); } /*show*/ - // Mat show_img = img.clone(); - // cv::rectangle(show_img, m_AnalysisyConfig.baseFunction.markLine.productROI, Scalar(255), 5); - // if(cur_edgeDet_region.size() >=2){ - // for(int i = 0 ; i < cur_edgeDet_region.size() - 1; i++){ - // cv::line(show_img, cur_edgeDet_region[i], cur_edgeDet_region[i+1], Scalar(255), 20); + // if (img.empty()) + // { + // return 0; + // } + // show_img = img.clone(); + // cvtColor(show_img, show_img, COLOR_GRAY2BGR); + // // 确保 productROI 在图像范围内 + // safe_roi = m_AnalysisyConfig.baseFunction.markLine.productROI; + // safe_roi &= cv::Rect(0, 0, show_img.cols, show_img.rows); + // if (safe_roi.width > 0 && safe_roi.height > 0) + // { + // cv::rectangle(show_img, safe_roi, Scalar(255,255,255), 5); + // } + // if (cur_edgeDet_region.size() >= 2) + // { + // for(size_t i = 0 ; i < cur_edgeDet_region.size() - 1; i++){ + // cv::line(show_img, cur_edgeDet_region[i], cur_edgeDet_region[i+1], Scalar(0,255,0), 20); // } + // cv::line(show_img, cur_edgeDet_region.back(), cur_edgeDet_region.front(), Scalar(0,255,0), 20); // } - // if(cur_markLine_region.size() >=2){ - // for(int i = 0 ; i < cur_markLine_region.size() - 1; i++){ - // cv::line(show_img, cur_markLine_region[i], cur_markLine_region[i+1], Scalar(255), 20); + // if (cur_markLine_region.size() >= 2) + // { + // for(size_t i = 0 ; i < cur_markLine_region.size() - 1; i++){ + // cv::line(show_img, cur_markLine_region[i], cur_markLine_region[i+1], Scalar(0,0,255), 20); // } + // cv::line(show_img, cur_markLine_region.back(), cur_markLine_region.front(), Scalar(0,0,255), 20); // } - // if(cur_regionConfigArr.size() >=2){ - // for(int i = 0 ; i < cur_regionConfigArr.size(); i++){ - // for(int j = 0; j < cur_regionConfigArr[i].basicInfo.pointArry.size()-1; j++){ - // cv::line(show_img, cur_regionConfigArr[i].basicInfo.pointArry[j], cur_regionConfigArr[i].basicInfo.pointArry[j+1], Scalar(255), 20); - // } + // for(size_t i = 0 ; i < cur_regionConfigArr.size(); i++){ + // if (cur_regionConfigArr[i].basicInfo.pointArry.size() >= 2) + // { + // for(size_t j = 0; j < cur_regionConfigArr[i].basicInfo.pointArry.size() - 1; j++){ + // cv::line(show_img, cur_regionConfigArr[i].basicInfo.pointArry[j], cur_regionConfigArr[i].basicInfo.pointArry[j+1], Scalar(255,0,0), 10); + // } + // cv::line(show_img, cur_regionConfigArr[i].basicInfo.pointArry.back(), cur_regionConfigArr[i].basicInfo.pointArry.front(), Scalar(255,0,0), 10); // } // } // imwrite(m_AnalysisyConfig.commonCheckConfig.baseConfig.strCamearName +"_show_img.tiff", show_img); - + return 0; } @@ -766,7 +916,7 @@ int ImgCheckAnalysisy::SetNewConfig() { m_bupdateconfig = true; // printf("************** ImgCheckAnalysisy::SetNewConfig m_nConfigIdx %d\n", m_nConfigIdx); - m_old_productROI = cv::Rect(0, 0, 0, 0); + m_old_productROI = cv::RotatedRect(); m_pConfig->GetConfig(ConfigType_Analysisy_Common_XL, &m_AnalysisyConfig); if (m_AnalysisyConfig.commonCheckConfig.nodeConfigArr.size() > 0) { @@ -2226,7 +2376,13 @@ int ImgCheckAnalysisy::Edge_Qx_Det(const cv::Mat &img) m_Edge_DetConfig.strChannel = m_strCurDetChannel; m_Edge_DetConfig.pBaseCheckFunction = m_pbaseCheckFunction; m_Edge_DetConfig.alginResult.corpRoi = m_Crop_Roi_paramImg; + m_Edge_DetConfig.pBaseCheckFunction->edgeDet.Align_region = m_AnalysisyConfig.baseFunction.markLine.region; + for(int i = 0; i < m_Edge_DetConfig.pBaseCheckFunction->edgeDet.Align_region.size(); i++) + { + m_Edge_DetConfig.pBaseCheckFunction->edgeDet.Align_region[i].x -= m_Crop_Roi_paramImg.x; + m_Edge_DetConfig.pBaseCheckFunction->edgeDet.Align_region[i].y -= m_Crop_Roi_paramImg.y; + } if (m_pEdge_Align_Result && m_pEdge_Align_Result->buseOfft) { m_Edge_DetConfig.alginResult.offtx = m_pEdge_Align_Result->offt_x; diff --git a/ConfigModule/include/CheckConfigDefine.h b/ConfigModule/include/CheckConfigDefine.h index 051345e..ed06031 100644 --- a/ConfigModule/include/CheckConfigDefine.h +++ b/ConfigModule/include/CheckConfigDefine.h @@ -408,6 +408,7 @@ struct BasicConfig float fImage_Scale_x; // 成像精度 float fImage_Scale_y; // 成像精度 std::string strCamName; // + std::string strConfigVersion; // 配置版本 float density_R_mm; // 密度计算半径 像素 BasicConfig() @@ -429,6 +430,7 @@ struct BasicConfig fImage_Scale_y = 0.03; density_R_mm = 5; strCamName = ""; + strConfigVersion = "1.0"; strCamearName = EMPTY_CONFIG_NAME; } void copy(BasicConfig tem) @@ -452,6 +454,8 @@ struct BasicConfig this->fImage_Scale_y = tem.fImage_Scale_y; this->density_R_mm = tem.density_R_mm; this->strCamearName = tem.strCamearName; + this->strConfigVersion = tem.strConfigVersion; + } void print(std::string str = "") { @@ -955,7 +959,7 @@ struct Function_ShieldRegion { return; } - shieldMask = cv::Mat(img_H, img_W, CV_8U, cv::Scalar(0)); + shieldMask = cv::Mat::zeros(img_H, img_W, CV_8U); if (pointArry1.size() > 0) { cv::fillPoly(shieldMask, pointArry1, cv::Scalar(255)); @@ -1082,7 +1086,7 @@ struct Function_EdgeROI // { // return; // } - EdgeMask = cv::Mat(img_H, img_W, CV_8U, cv::Scalar(0)); + EdgeMask = cv::Mat::zeros(img_H, img_W, CV_8U); if (pointArry1.size() > 0) { @@ -1191,7 +1195,7 @@ struct Function_Image_Align // pointArry1[i].y -= boundingRect.y; // } - cv::Mat tem_feature_Mask = cv::Mat(img_H, img_W, CV_8U, cv::Scalar(0)); + cv::Mat tem_feature_Mask = cv::Mat::zeros(img_H, img_W, CV_8U); if (pointArry1.size() > 0) { @@ -1940,6 +1944,7 @@ struct Base_Function_Edge_Det int Search_threshold; // 搜索边缘阈值 int Det_threshold; // 缺陷检测阈值 int Det_Range; // 检测范围 + int Det_Range_Offset; // 检测范围偏移 int QX_Widht_min; // 缺陷宽度-最小 int QX_Widht_max; int QX_Height_min; @@ -1953,8 +1958,10 @@ struct Base_Function_Edge_Det int queJiao_height; bool bDrawRoi; + bool bUseAlignRoi; cv::Rect draw_ROI; std::vector region; + std::vector Align_region; bool bDrawResult; // 是否绘制结果 Base_Function_Edge_Det() @@ -1967,6 +1974,7 @@ struct Base_Function_Edge_Det Search_threshold = 30; Det_threshold = 30; Det_Range = 100; + Det_Range_Offset = 0; QX_Widht_min = 10; QX_Widht_max = 100; QX_Height_min = 10; @@ -1979,6 +1987,7 @@ struct Base_Function_Edge_Det queJiao_width = 50; queJiao_height = 50; bDrawRoi = false; + bUseAlignRoi = false; draw_ROI = cv::Rect(0, 0, 0, 0); region.clear(); region.erase(region.begin(), region.end()); @@ -1991,6 +2000,7 @@ struct Base_Function_Edge_Det this->Search_threshold = tem.Search_threshold; this->Det_threshold = tem.Det_threshold; this->Det_Range = tem.Det_Range; + this->Det_Range_Offset = tem.Det_Range_Offset; this->QX_Widht_min = tem.QX_Widht_min; this->QX_Widht_max = tem.QX_Widht_max; this->QX_Height_min = tem.QX_Height_min; @@ -2006,18 +2016,19 @@ struct Base_Function_Edge_Det this->region.assign(tem.region.begin(), tem.region.end()); this->draw_ROI = tem.draw_ROI; this->bDrawRoi = tem.bDrawRoi; + this->bUseAlignRoi = tem.bUseAlignRoi; this->bDrawResult = tem.bDrawResult; } void print(std::string str) { - printf("%s>>bOpen %d Search_threshold %d Det_threshold %d Det_Range %d QX_Widht [%d %d] QX_Height [%d %d]\n", str.c_str(), - bOpen, Search_threshold, Det_threshold, Det_Range, QX_Widht_min, QX_Widht_max, QX_Height_min, QX_Height_max); + printf("%s>>bOpen %d Search_threshold %d Det_threshold %d Det_Range %d Det_Range_Offset %d QX_Widht [%d %d] QX_Height [%d %d]\n", str.c_str(), + bOpen, Search_threshold, Det_threshold, Det_Range, Det_Range_Offset, QX_Widht_min, QX_Widht_max, QX_Height_min, QX_Height_max); } std::string GetInfo(std::string str) { char buffer[256]; - sprintf(buffer, "%s>>bOpen %d Search_threshold %d Det_threshold %d Det_Range %d QX_Widht [%d %d] QX_Height [%d %d]\n", str.c_str(), - bOpen, Search_threshold, Det_threshold, Det_Range, QX_Widht_min, QX_Widht_max, QX_Height_min, QX_Height_max); + sprintf(buffer, "%s>>bOpen %d Search_threshold %d Det_threshold %d Det_Range %d Det_Range_Offset %d QX_Widht [%d %d] QX_Height [%d %d]\n", str.c_str(), + bOpen, Search_threshold, Det_threshold, Det_Range, Det_Range_Offset, QX_Widht_min, QX_Widht_max, QX_Height_min, QX_Height_max); std::string str123 = buffer; return str123; } diff --git a/ConfigModule/src/JsonConfig.cpp b/ConfigModule/src/JsonConfig.cpp index 3937608..d406f64 100644 --- a/ConfigModule/src/JsonConfig.cpp +++ b/ConfigModule/src/JsonConfig.cpp @@ -32,7 +32,7 @@ void CommonParamToCheckConfigJson::toObjectFromValue(Json::Value root) std::unique_ptr reader(builder.newCharReader()); Json::Value rootvalue; std::string err; - // std::cout << strJson << std::endl; + std::cout << strJson << std::endl; auto nSize = strJson.size(); if (reader->parse(strJson.c_str(), strJson.c_str() + nSize, &rootvalue, &err)) { @@ -44,6 +44,11 @@ void CommonParamToCheckConfigJson::toObjectFromValue(Json::Value root) // getchar(); if (value.isObject()) { + _config.baseConfig.strConfigVersion = value["version"].asString(); + if ( _config.baseConfig.strConfigVersion == "") + { + _config.baseConfig.strConfigVersion = "NULL"; + } _config.baseConfig.image_widht = value["image_widht"].asInt(); _config.baseConfig.Image_height = value["Image_height"].asInt(); _config.baseConfig.bDrawShieldRoi = value["bDrawShieldRoi"].asBool(); @@ -1248,6 +1253,11 @@ int BaseFuntonConfigJson::GetFunction(Json::Value value) _config.edgeDet.bDrawRoi = value_f["form"]["Draw_Config"]["Open"].asBool(); } + if (value_f["form"]["Draw_Config"]["bUse_Align"]) + { + _config.edgeDet.bUseAlignRoi = value_f["form"]["Draw_Config"]["bUse_Align"].asBool(); + } + // 2、读取区域点 { auto value_region = value_f["form"]["Draw_Config"]["Edge_ROI"];