From b7da6688bafac8a7caede20ec3201dd83cec7c0d Mon Sep 17 00:00:00 2001 From: liusiyang Date: Fri, 16 Oct 2026 09:30:32 +0800 Subject: [PATCH] =?UTF-8?q?feat=20Pin=E6=B7=BB=E5=8A=A0dxdy=E6=97=A5?= =?UTF-8?q?=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AlgorithmModule/src/ImgCheckAnalysisy.cpp | 96 +++++++++++------------ 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/AlgorithmModule/src/ImgCheckAnalysisy.cpp b/AlgorithmModule/src/ImgCheckAnalysisy.cpp index 06e2221..a55dbab 100644 --- a/AlgorithmModule/src/ImgCheckAnalysisy.cpp +++ b/AlgorithmModule/src/ImgCheckAnalysisy.cpp @@ -2228,19 +2228,13 @@ int ImgCheckAnalysisy::Pin_Qx_Det(const cv::Mat &img) } std::vector curUsed(nCur, false); - // 3、偏移阈值由基础参数 pin_x_offset / pin_y_offset (mm) 换算为像素 - float offsetThX = 0.0f; - float offsetThY = 0.0f; + // 3、偏移阈值直接使用基础参数 pin_x_offset / pin_y_offset (mm),与换算为 mm 的偏移量直接比较 + float offsetThX = 0.0f; // mm + float offsetThY = 0.0f; // mm if (m_pbaseCheckFunction != NULL) { - if (m_fImgage_Scale_X > 0.0f) - { - offsetThX = m_pbaseCheckFunction->pinDet.pin_x_offset / m_fImgage_Scale_X; - } - if (m_fImgage_Scale_Y > 0.0f) - { - offsetThY = m_pbaseCheckFunction->pinDet.pin_y_offset / m_fImgage_Scale_Y; - } + offsetThX = m_pbaseCheckFunction->pinDet.pin_x_offset; + offsetThY = m_pbaseCheckFunction->pinDet.pin_y_offset; } // 上报缺失/偏移缺陷(缺陷类型可按需调整) @@ -2309,19 +2303,21 @@ int ImgCheckAnalysisy::Pin_Qx_Det(const cv::Mat &img) curUsed[bestIdx] = true; - // x 或 y 方向偏移超过配置阈值 -> 偏移 - float dx = tplCenters[i].x - curCenters[bestIdx].x; - float dy = tplCenters[i].y - curCenters[bestIdx].y; - float absDx = std::fabs(dx); - float absDy = std::fabs(dy); - if (absDx > offsetThX || absDy > offsetThY) + // x 或 y 方向偏移超过配置阈值 -> 偏移;偏移量按成像精度换算为 mm (mm = px * 成像精度) + float dx_mm = (tplCenters[i].x - curCenters[bestIdx].x) * m_fImgage_Scale_X; + float dy_mm = (tplCenters[i].y - curCenters[bestIdx].y) * m_fImgage_Scale_Y; + float absDx = std::fabs(dx_mm); + float absDy = std::fabs(dy_mm); + bool bOffset = (absDx > offsetThX || absDy > offsetThY); + if (bOffset) { nOffset++; char buf[64]; - snprintf(buf, sizeof(buf), "offset dx %.1f dy %.1f", absDx, absDy); + snprintf(buf, sizeof(buf), "offset dx %.2f dy %.2f mm", absDx, absDy); reportPinError(i, tplCenters[i], buf, CONFIG_QX_NAME_PIN_PianYi); - m_pdetlog->AddCheckstr(PrintLevel_0, "Pin Check", "pin %d OFFSET dx %.1f dy %.1f", i, absDx, absDy); } + // 每个pin脚都打印dx/dy(mm),方便调整 pin_x_offset / pin_y_offset 参数 + m_pdetlog->AddCheckstr(PrintLevel_0, "Pin Check", "pin %d %s dx %.2f dy %.2f mm", i, bOffset ? "OFFSET" : "OK", absDx, absDy); } m_pdetlog->AddCheckstr(PrintLevel_0, "Pin Check", "tpl %d cur %d miss %d offset %d", nTpl, nCur, nMiss, nOffset); @@ -2639,8 +2635,8 @@ int ImgCheckAnalysisy::Pin_Direct_Match() // 新方案(开关 PIN_USE_DIRECT_MATCH = 1): 不做模板对比, 只针对检测Pin分析 // 1) 方向扫描(0~180°, 步长1°): 取 "两排Pin沿法线投影组内方差之和" 最小的角度作为Pin排方向(对图像旋转不敏感), // 再沿该法线投影, 在最大间隙处把Pin分成两排(两排插口; Pin不足4个则按一排处理); -// 2) 每排做最小二乘直线拟合(cv::fitLine): pin中心到直线(沿法线方向)距离超过 pin_y_offset(换算像素) 判 偏移; -// 3) 每排内沿排方向排序: 相邻两pin中心连线距离超过 pin_x_offset(换算像素) 判 两pin中间缺失一个pin。 +// 2) 每排做最小二乘直线拟合(cv::fitLine): pin中心到直线(沿法线方向)距离按成像精度换算为 mm, 超过 pin_y_offset(mm) 判 偏移; +// 3) 每排内沿排方向排序: 相邻两pin中心连线距离按成像精度换算为 mm, 超过 pin_x_offset(mm) 判 两pin中间缺失一个pin。 int ImgCheckAnalysisy::Pin_Direct_Check() { // 计算轮廓中心点(外接矩形中心) @@ -2672,19 +2668,13 @@ int ImgCheckAnalysisy::Pin_Direct_Check() return 0; } - // 阈值(mm 参数换算为像素): pin_x_offset -> 相邻pin间距(缺失)阈值; pin_y_offset -> 到拟合直线距离(偏移)阈值; <=0 时不判该项 - float offsetThX = 0.0f; - float offsetThY = 0.0f; + // 阈值直接使用 mm 参数(判据按 mm 比较): pin_x_offset -> 相邻pin间距(缺失)阈值; pin_y_offset -> 到拟合直线距离(偏移)阈值; <=0 时不判该项 + float offsetThX = 0.0f; // mm + float offsetThY = 0.0f; // mm if (m_pbaseCheckFunction != NULL) { - if (m_fImgage_Scale_X > 0.0f) - { - offsetThX = m_pbaseCheckFunction->pinDet.pin_x_offset / m_fImgage_Scale_X; - } - if (m_fImgage_Scale_Y > 0.0f) - { - offsetThY = m_pbaseCheckFunction->pinDet.pin_y_offset / m_fImgage_Scale_Y; - } + offsetThX = m_pbaseCheckFunction->pinDet.pin_x_offset; + offsetThY = m_pbaseCheckFunction->pinDet.pin_y_offset; } // 沿给定方向投影排序, 在最大间隙处切分成两排(order[0..splitK] 一排, order[splitK+1..] 另一排) @@ -2801,11 +2791,11 @@ int ImgCheckAnalysisy::Pin_Direct_Check() rows.push_back(order); } m_pdetlog->AddCheckstr(PrintLevel_1, DET_LOG_LEVEL_3, "Pin Check", - "row dir %.1f deg rows %d th[gap %.1f line %.1f] px", + "row dir %.1f deg rows %d th[gap %.2f line %.2f] mm", bestTheta * 180.0f / static_cast(CV_PI), static_cast(rows.size()), offsetThX, offsetThY); - // 上报缺陷(roi/area 由调用处给出; grayDis 记录对应度量: 到直线距离 / 相邻间距, 单位像素) + // 上报缺陷(roi/area 由调用处给出; grayDis 记录对应度量: 到直线距离 / 相邻间距, 单位mm) auto reportPinError = [&](const cv::Rect &roi, int area, double grayDis, int nconfig_qx_type, const std::string &detail) { QX_ERROR_INFO_ pinErr; @@ -2870,23 +2860,28 @@ int ImgCheckAnalysisy::Pin_Direct_Check() } m_pinFitLines.push_back(std::make_pair(lineP0 + lineDir * tMin, lineP0 + lineDir * tMax)); - // 2、pin中心到直线(沿法线方向)距离超过 pin_y_offset -> 偏移 + // 2、pin中心到直线(沿法线方向)距离超过 pin_y_offset -> 偏移;距离按成像精度换算为 mm (mm = px * 成像精度) if (offsetThY > 0.0f) { for (int i = 0; i < nRow; i++) { - float absDist = std::fabs((rowPts[i] - lineP0).dot(lineNor)); - if (absDist > offsetThY) + // 垂直偏移向量(px)的分量分别换算为 mm 后求模 + float distPx = (rowPts[i] - lineP0).dot(lineNor); + float dx_mm = lineNor.x * distPx * m_fImgage_Scale_X; + float dy_mm = lineNor.y * distPx * m_fImgage_Scale_Y; + float absDist = std::sqrt(dx_mm * dx_mm + dy_mm * dy_mm); + int idx = rowIdx[i]; + bool bOffset = (absDist > offsetThY); + if (bOffset) { - int idx = rowIdx[i]; nOffset++; char buf[96]; - snprintf(buf, sizeof(buf), "pin %d offset to row line %.1f px > %.1f px", idx, absDist, offsetThY); + snprintf(buf, sizeof(buf), "pin %d offset to row line %.2f mm > %.2f mm", idx, absDist, offsetThY); reportPinError(curRects[idx], static_cast(cv::contourArea(m_curPinContours[idx])), absDist, CONFIG_QX_NAME_PIN_PianYi, buf); - m_pdetlog->AddCheckstr(PrintLevel_0, "Pin Check", "row %d pin %d OFFSET %.1f px > %.1f px", - static_cast(r), idx, absDist, offsetThY); } + // 每个pin脚都打印到拟合直线的距离(mm),方便调整 pin_y_offset 参数 + m_pdetlog->AddCheckstr(PrintLevel_0, "Pin Check", "row %d pin %d %s line %.2f mm", static_cast(r), idx, bOffset ? "OFFSET" : "OK", absDist); } } @@ -2905,11 +2900,16 @@ int ImgCheckAnalysisy::Pin_Direct_Check() { int ia = tOrder[i].second; int ib = tOrder[i + 1].second; - float gap = static_cast(cv::norm(rowPts[ib] - rowPts[ia])); - if (gap > offsetThX) + // 相邻pin中心连线距离(px)的分量分别换算为 mm 后求模 + cv::Point2f dv = rowPts[ib] - rowPts[ia]; + float dx_mm = dv.x * m_fImgage_Scale_X; + float dy_mm = dv.y * m_fImgage_Scale_Y; + float gap = std::sqrt(dx_mm * dx_mm + dy_mm * dy_mm); + int idxa = rowIdx[ia]; + int idxb = rowIdx[ib]; + bool bMiss = (gap > offsetThX); + if (bMiss) { - int idxa = rowIdx[ia]; - int idxb = rowIdx[ib]; cv::Point2f mid = (rowPts[ia] + rowPts[ib]) * 0.5f; m_pinMissMarks.push_back(mid); @@ -2923,11 +2923,11 @@ int ImgCheckAnalysisy::Pin_Direct_Check() static_cast(cv::contourArea(m_curPinContours[idxb]))) / 2; nMiss++; char buf[96]; - snprintf(buf, sizeof(buf), "miss between pin %d-%d gap %.1f px > %.1f px", idxa, idxb, gap, offsetThX); + snprintf(buf, sizeof(buf), "miss between pin %d-%d gap %.2f mm > %.2f mm", idxa, idxb, gap, offsetThX); reportPinError(roiMiss, areaAvg, gap, CONFIG_QX_NAME_PIN_QueShi, buf); - m_pdetlog->AddCheckstr(PrintLevel_0, "Pin Check", "row %d pin %d-%d MISS gap %.1f px > %.1f px", - static_cast(r), idxa, idxb, gap, offsetThX); } + // 每对相邻pin都打印间距(mm),方便调整 pin_x_offset 参数 + m_pdetlog->AddCheckstr(PrintLevel_0, "Pin Check", "row %d pin %d-%d %s gap %.2f mm", static_cast(r), idxa, idxb, bMiss ? "MISS" : "OK", gap); } } }