From db455bd0cba861180a8b9d5b836dfcc3d9387e02 Mon Sep 17 00:00:00 2001 From: liusiyang Date: Sat, 19 Sep 2026 17:06:27 +0800 Subject: [PATCH] =?UTF-8?q?feat=20=E4=B8=B4=E6=97=B6=E8=A1=A5=E4=B8=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AlgorithmModule/include/ImgMmPatch.hpp | 51 +++++++++++++++++++++++ AlgorithmModule/src/ImageResultJudge.cpp | 5 ++- AlgorithmModule/src/ImgCheckAnalysisy.cpp | 20 +++++++-- 3 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 AlgorithmModule/include/ImgMmPatch.hpp diff --git a/AlgorithmModule/include/ImgMmPatch.hpp b/AlgorithmModule/include/ImgMmPatch.hpp new file mode 100644 index 0000000..3b29cb9 --- /dev/null +++ b/AlgorithmModule/include/ImgMmPatch.hpp @@ -0,0 +1,51 @@ +#ifndef _ImgMmPatch_HPP_ +#define _ImgMmPatch_HPP_ + +// ============================================================================ +// 【临时补丁】产品长度方向(y) 像素 -> 物理毫米 的分段换算 +// +// 背景:产品沿长度方向运动/扫描时速率不恒定(尾端有拉伸),像素↔mm 不是单一 +// 比例,实测标定出 5 段,每段斜率不同。 +// +// 分段表(分段点 = 像素,**以产品顶边为 0 点**;斜率为 mm/px): +// 0 ~ 10928 0.016869 +// 10928 ~ 17002 0.016463 (6074px ↔ 100mm) +// 17002 ~ 23167 0.016220 (6165px ↔ 100mm) +// 23167 ~ 29549 0.015669 (6382px ↔ 100mm) +// >= 29549 0.014337 +// 分段点处前后两段取值相同,函数连续,不会在分段点跳变。 +// +// 共用方(必须共用同一张表,否则"产品高度"和"缺陷坐标"会各用一把尺子): +// 1) 缺陷 y 物理坐标:ImageResultJudge::BuildDefectImage() +// 2) 产品物理高度 :ImgCheckAnalysisy::CalProductSize() +// +// 注:正式方案建议把这张分段表放进配置(json),由标定数据下发;这里先硬编码。 +// ============================================================================ +inline float PixelYToMm(float fYPixel) +{ + // 各段末端的累计物理长度(mm) + const float d1 = 10928 * 0.016869; + const float d2 = 6074 * 0.016463; + const float d3 = 6165 * 0.016220; + const float d4 = 6382 * 0.015669; + + if (fYPixel < 10928.0f) + { + return fYPixel * 0.016869; + } + if (fYPixel < 17002.0f) + { + return (fYPixel - 10928.0f) * 0.016463 + d1; + } + if (fYPixel < 23167.0f) + { + return (fYPixel - 10928.0f - 6074.0f) * 0.016220 + d1 + d2; + } + if (fYPixel < 29549.0f) + { + return (fYPixel - 10928.0f - 6074.0f - 6165.0f) * 0.015669 + d1 + d2 + d3; + } + return (fYPixel - 10928.0f - 6074.0f - 6165.0f - 6382.0f) * 0.014337 + d1 + d2 + d3 + d4; +} + +#endif diff --git a/AlgorithmModule/src/ImageResultJudge.cpp b/AlgorithmModule/src/ImageResultJudge.cpp index 44441b7..fadfa1b 100644 --- a/AlgorithmModule/src/ImageResultJudge.cpp +++ b/AlgorithmModule/src/ImageResultJudge.cpp @@ -1,5 +1,6 @@ #include "ImageResultJudge.h" +#include "ImgMmPatch.hpp" ImageResultJudge::ImageResultJudge(/* args */) { @@ -186,7 +187,9 @@ QXImageResult ImageResultJudge::BuildDefectImage(std::shared_ptr } tem.x_mm = tem.x_pixel * m_fImgage_Scale_X; - tem.y_mm = tem.y_pixel * m_fImgage_Scale_Y; + // 【临时补丁】长度方向(y):产品运动速率不恒定(尾端有拉伸),按分段像素进度换算像素->mm + // 分段表见 ImgMmPatch.hpp,与产品物理高度(ImgCheckAnalysisy::CalProductSize)共用 + tem.y_mm = PixelYToMm(tem.y_pixel); tem.CutImgroi = roi_det; tem.CutImgroi.x -= CutRoi.x; diff --git a/AlgorithmModule/src/ImgCheckAnalysisy.cpp b/AlgorithmModule/src/ImgCheckAnalysisy.cpp index 7368aef..ade2795 100644 --- a/AlgorithmModule/src/ImgCheckAnalysisy.cpp +++ b/AlgorithmModule/src/ImgCheckAnalysisy.cpp @@ -8,6 +8,7 @@ */ #include "ImgCheckAnalysisy.hpp" #include "CheckUtil.hpp" +#include "ImgMmPatch.hpp" #include "Define.h" #include #include "AICommonDefine.h" @@ -2819,6 +2820,7 @@ int ImgCheckAnalysisy::AI_Edge(const cv::Mat &img, cv::Rect &cutRoi) int ImgCheckAnalysisy::CalProductSize() { float fw, fh; + float fhPixel = 0.f; // 产品沿长度方向(y)的像素高度,供长度方向分段补丁换算用 if (m_bRotCurRoiValid) { // 产品存在旋转角:用旋转矩形四个顶点的实际边长换算物理尺寸 @@ -2829,21 +2831,31 @@ int ImgCheckAnalysisy::CalProductSize() double dy = (a.y - b.y) * m_fImgage_Scale_Y; return std::sqrt(dx * dx + dy * dy); }; + // 纯像素边长(不带成像精度),供长度方向的分段补丁使用 + auto edgeLenPixel = [&](const cv::Point2f &a, const cv::Point2f &b) -> double { + double dx = a.x - b.x; + double dy = a.y - b.y; + return std::sqrt(dx * dx + dy * dy); + }; fw = (float)((edgeLenPhys(v[0], v[1]) + edgeLenPhys(v[2], v[3])) * 0.5); // 上边+下边平均 - fh = (float)((edgeLenPhys(v[0], v[2]) + edgeLenPhys(v[1], v[3])) * 0.5); // 左边+右边平均 + fhPixel = (float)((edgeLenPixel(v[0], v[2]) + edgeLenPixel(v[1], v[3])) * 0.5); // 左边+右边平均(像素) } else { fw = m_CutRoi.width * m_fImgage_Scale_X; - fh = m_CutRoi.height * m_fImgage_Scale_Y; + fhPixel = (float)m_CutRoi.height; } + // 【临时补丁】长度方向(上下边)产品运动速率不恒定,按分段像素进度换算像素->mm; + // 与缺陷 y 坐标(ImageResultJudge::BuildDefectImage)共用 ImgMmPatch.hpp 里的同一张分段表。 + // 宽度不做补丁,仍用成像精度换算。 + fh = PixelYToMm(fhPixel); fw = std::ceil(fw * 10) / 10; fh = std::ceil(fh * 10) / 10; m_CheckResult_shareP->productWidht_mm = fw; m_CheckResult_shareP->productHeight_mm = fh; - m_pdetlog->AddCheckstr(PrintLevel_1, "Det ROI", " [x%d, y%d, w %d,h %d] (piexl) -> [w %f h %f](mm),scale %f %f", - m_CutRoi.x, m_CutRoi.y, m_CutRoi.width, m_CutRoi.height, fw, fh, m_fImgage_Scale_X, m_fImgage_Scale_Y); + m_pdetlog->AddCheckstr(PrintLevel_1, "Det ROI", " [x%d, y%d, w %d,h %d] (piexl) -> [w %f h %f](mm),scale %f %f, hPixel %f", + m_CutRoi.x, m_CutRoi.y, m_CutRoi.width, m_CutRoi.height, fw, fh, m_fImgage_Scale_X, m_fImgage_Scale_Y, fhPixel); // 打印产品旋转矩形的四角坐标(原图坐标系),便于核对尺寸换算与后续坐标映射 if (m_bRotCurRoiValid)