修复注释乱码
This commit is contained in:
@@ -1,17 +1,17 @@
|
||||
// ============================================================================
|
||||
// 文件� AngleMeasurementProcessor.cs
|
||||
// æ��è¿°: 角度测é‡�ç®—å� â€?共端点的两æ�¡ç›´çº¿å¤¹è§’
|
||||
// 文件名: AngleMeasurementProcessor.cs
|
||||
// 描述: 角度测量算子 — 共端点的两条直线夹角
|
||||
// 功能:
|
||||
// - 用户定义三个点:端点(顶点)�射�终点�射�终点
|
||||
// - 计算两�射线之间的夹角(0°~180°�
|
||||
// - 用户定义三个点:端点(顶点)、射线1终点、射线2终点
|
||||
// - 计算两条射线之间的夹角(0°~180°)
|
||||
// - 在图像上绘制两条射线、角度弧线和标注
|
||||
// ============================================================================
|
||||
|
||||
using Emgu.CV;
|
||||
using Emgu.CV.Structure;
|
||||
using XP.ImageProcessing.Core;
|
||||
using Serilog;
|
||||
using System.Drawing;
|
||||
using XP.ImageProcessing.Core;
|
||||
|
||||
namespace XP.ImageProcessing.Processors;
|
||||
|
||||
@@ -27,7 +27,7 @@ public class AngleMeasurementProcessor : ImageProcessorBase
|
||||
|
||||
protected override void InitializeParameters()
|
||||
{
|
||||
// 三个点å��æ ‡ï¼ˆç”±äº¤äº’æŽ§ä»¶æ³¨å…¥ï¼Œä½¿ç”¨ double é�¿å…�å�–整误差ï¼?
|
||||
// 三个点坐标(由交互控件注入,使用 double 避免取整误差)
|
||||
Parameters.Add("VX", new ProcessorParameter("VX", "VX", typeof(double), 250.0, null, null, "") { IsVisible = false });
|
||||
Parameters.Add("VY", new ProcessorParameter("VY", "VY", typeof(double), 250.0, null, null, "") { IsVisible = false });
|
||||
Parameters.Add("AX", new ProcessorParameter("AX", "AX", typeof(double), 100.0, null, null, "") { IsVisible = false });
|
||||
@@ -44,7 +44,7 @@ public class AngleMeasurementProcessor : ImageProcessorBase
|
||||
|
||||
OutputData.Clear();
|
||||
|
||||
// �� VA �VB
|
||||
// 向量 VA 和 VB
|
||||
double vax = ax - vx, vay = ay - vy;
|
||||
double vbx = bx - vx, vby = by - vy;
|
||||
|
||||
@@ -59,11 +59,11 @@ public class AngleMeasurementProcessor : ImageProcessorBase
|
||||
angleDeg = Math.Acos(cosAngle) * 180.0 / Math.PI;
|
||||
}
|
||||
|
||||
// 计算角度弧的起始角和扫过角(用于绘制弧线�
|
||||
// 计算角度弧的起始角和扫过角(用于绘制弧线)
|
||||
double angleA = Math.Atan2(vay, vax) * 180.0 / Math.PI;
|
||||
double angleB = Math.Atan2(vby, vbx) * 180.0 / Math.PI;
|
||||
|
||||
// 确��angleA �angleB 的扫过方�是较�的夹�
|
||||
// 确保从 angleA 到 angleB 的扫过方向是较小的夹角
|
||||
double sweep = angleB - angleA;
|
||||
if (sweep > 180) sweep -= 360;
|
||||
if (sweep < -180) sweep += 360;
|
||||
@@ -84,4 +84,4 @@ public class AngleMeasurementProcessor : ImageProcessorBase
|
||||
|
||||
return inputImage.Clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
// ============================================================================
|
||||
// Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved.
|
||||
// 文件� BgaVoidRateProcessor.cs
|
||||
// æ��è¿°: BGA 空洞率检测算å�(两æ¥è‡ªåŠ¨æ£€æµ‹æ³•ï¼?
|
||||
// 文件名: BgaVoidRateProcessor.cs
|
||||
// 描述: BGA 空洞率检测算子(两步自动检测法)
|
||||
//
|
||||
// 处理流程:
|
||||
// 第一æ?â€?焊ç�ƒå®šä½�: 高斯模糊 â†?Otsuå��å�‘二值化 â†?é—è¿�ç®?â†?轮廓检æµ?â†?圆度过滤 â†?æ¤åœ†æ‹Ÿå�ˆ
|
||||
// 第二æ?â€?气泡检æµ? 焊ç�ƒè½®å»“掩ç � â†?å�Œé˜ˆå€¼åˆ†å‰?â†?轮廓检æµ?â†?é�¢ç§¯è¿‡æ»¤ â†?气泡率计ç®?
|
||||
// 第一步 — 焊球定位: 高斯模糊 → Otsu反向二值化 → 闭运算 → 轮廓检测 → 圆度过滤 → 椭圆拟合
|
||||
// 第二步 — 气泡检测: 焊球轮廓掩码 → 双阈值分割 → 轮廓检测 → 面积过滤 → 气泡率计算
|
||||
//
|
||||
// 支持多边形ROI限定检测区域,支持IPC-7095标准PASS/FAIL判定
|
||||
// æ£ç‰‡æ¨¡å¼�:焊ç�?暗区域,气泡=亮区åŸ?
|
||||
// 正片模式:焊球=暗区域,气泡=亮区域
|
||||
//
|
||||
// 作� �伟 wei.lw.li@hexagon.com
|
||||
// 作者: 李伟 wei.lw.li@hexagon.com
|
||||
// ============================================================================
|
||||
|
||||
using Emgu.CV;
|
||||
using Emgu.CV.CvEnum;
|
||||
using Emgu.CV.Structure;
|
||||
using Emgu.CV.Util;
|
||||
using XP.ImageProcessing.Core;
|
||||
using Serilog;
|
||||
using System.Drawing;
|
||||
using XP.ImageProcessing.Core;
|
||||
|
||||
namespace XP.ImageProcessing.Processors;
|
||||
|
||||
@@ -43,7 +43,7 @@ public class BgaVoidRateProcessor : ImageProcessorBase
|
||||
LocalizationHelper.GetString("BgaVoidRateProcessor_RoiMode_Desc"),
|
||||
new string[] { "None", "Polygon" }));
|
||||
|
||||
// 多边形ROI点数和å��æ ‡ï¼ˆç”±UI注入,ä¸�å�¯è§�,最多支æŒ?2个点ï¼?
|
||||
// 多边形ROI点数和坐标(由UI注入,不可见,最多支持32个点)
|
||||
Parameters.Add("PolyCount", new ProcessorParameter("PolyCount", "PolyCount", typeof(int), 0, null, null, "") { IsVisible = false });
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
@@ -76,7 +76,7 @@ public class BgaVoidRateProcessor : ImageProcessorBase
|
||||
typeof(double), 0.5, 0.0, 1.0,
|
||||
LocalizationHelper.GetString("BgaVoidRateProcessor_BgaCircularity_Desc")));
|
||||
|
||||
// ── 第二æ¥ï¼šæ°”泡检测å�‚æ•?──
|
||||
// ── 第二步:气泡检测参数 ──
|
||||
Parameters.Add("MinThreshold", new ProcessorParameter(
|
||||
"MinThreshold",
|
||||
LocalizationHelper.GetString("BgaVoidRateProcessor_MinThreshold"),
|
||||
@@ -148,7 +148,7 @@ public class BgaVoidRateProcessor : ImageProcessorBase
|
||||
OutputData["RoiMode"] = roiMode;
|
||||
OutputData["RoiMask"] = roiMask;
|
||||
|
||||
_logger.Debug("BgaVoidRate ä¸¤æ¥æ³? BgaArea=[{Min},{Max}], Blur={Blur}, Circ={Circ}, Thresh=[{TMin},{TMax}]",
|
||||
_logger.Debug("BgaVoidRate 两步法: BgaArea=[{Min},{Max}], Blur={Blur}, Circ={Circ}, Thresh=[{TMin},{TMax}]",
|
||||
bgaMinArea, bgaMaxArea, bgaBlurSize, bgaCircularity, minThresh, maxThresh);
|
||||
|
||||
// ================================================================
|
||||
@@ -156,7 +156,7 @@ public class BgaVoidRateProcessor : ImageProcessorBase
|
||||
// ================================================================
|
||||
var bgaResults = DetectBgaBalls(inputImage, bgaBlurSize, bgaMinArea, bgaMaxArea, bgaCircularity, roiMask);
|
||||
|
||||
_logger.Information("第一æ¥å®Œæˆ? 检测到 {Count} 个BGA焊ç�ƒ", bgaResults.Count);
|
||||
_logger.Information("第一步完成: 检测到 {Count} 个BGA焊球", bgaResults.Count);
|
||||
|
||||
if (bgaResults.Count == 0)
|
||||
{
|
||||
@@ -176,7 +176,7 @@ public class BgaVoidRateProcessor : ImageProcessorBase
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// 第二æ¥ï¼šåœ¨æ¯�个焊ç�ƒåŒºåŸŸå†…检测气æ³?
|
||||
// 第二步:在每个焊球区域内检测气泡
|
||||
// ================================================================
|
||||
int totalBgaArea = 0;
|
||||
int totalVoidArea = 0;
|
||||
@@ -193,13 +193,13 @@ public class BgaVoidRateProcessor : ImageProcessorBase
|
||||
double overallVoidRate = totalBgaArea > 0 ? (double)totalVoidArea / totalBgaArea * 100.0 : 0;
|
||||
string classification = overallVoidRate <= voidLimit ? "PASS" : "FAIL";
|
||||
|
||||
// 检查æ¯�个焊ç�ƒæ˜¯å�¦å�•独超æ ?
|
||||
// 检查每个焊球是否单独超标
|
||||
foreach (var bga in bgaResults)
|
||||
{
|
||||
bga.Classification = bga.VoidRate <= voidLimit ? "PASS" : "FAIL";
|
||||
}
|
||||
|
||||
_logger.Information("第二æ¥å®Œæˆ? 总气泡率={VoidRate:F1}%, 气泡æ•?{Count}, 判定={Class}",
|
||||
_logger.Information("第二步完成: 总气泡率={VoidRate:F1}%, 气泡数={Count}, 判定={Class}",
|
||||
overallVoidRate, totalVoidCount, classification);
|
||||
|
||||
// 输出数据
|
||||
@@ -222,7 +222,7 @@ public class BgaVoidRateProcessor : ImageProcessorBase
|
||||
|
||||
/// <summary>
|
||||
/// 第一步:自动检测BGA焊球位置
|
||||
/// 使用Otsu二值化 + 轮廓检æµ?+ 圆度过滤 + æ¤åœ†æ‹Ÿå�ˆ
|
||||
/// 使用Otsu二值化 + 轮廓检测 + 圆度过滤 + 椭圆拟合
|
||||
/// </summary>
|
||||
private List<BgaBallInfo> DetectBgaBalls(Image<Gray, byte> input, int blurSize, int minArea, int maxArea, double minCircularity, Image<Gray, byte>? roiMask)
|
||||
{
|
||||
@@ -233,7 +233,7 @@ public class BgaVoidRateProcessor : ImageProcessorBase
|
||||
var blurred = new Image<Gray, byte>(w, h);
|
||||
CvInvoke.GaussianBlur(input, blurred, new Size(blurSize, blurSize), 0);
|
||||
|
||||
// Otsu自动二值化(X-Rayæ£ç‰‡ï¼šç„Šç�?暗区域)
|
||||
// Otsu自动二值化(X-Ray正片:焊球=暗区域)
|
||||
var binary = new Image<Gray, byte>(w, h);
|
||||
CvInvoke.Threshold(blurred, binary, 0, 255, ThresholdType.Otsu | ThresholdType.BinaryInv);
|
||||
|
||||
@@ -264,7 +264,7 @@ public class BgaVoidRateProcessor : ImageProcessorBase
|
||||
double circularity = 4.0 * Math.PI * area / (perimeter * perimeter);
|
||||
if (circularity < minCircularity) continue;
|
||||
|
||||
// 需è¦�至å°?个点æ‰�能拟å�ˆæ¤åœ†
|
||||
// 需要至少5个点才能拟合椭圆
|
||||
if (contours[i].Size < 5) continue;
|
||||
|
||||
var ellipse = CvInvoke.FitEllipse(contours[i]);
|
||||
@@ -284,7 +284,7 @@ public class BgaVoidRateProcessor : ImageProcessorBase
|
||||
});
|
||||
}
|
||||
|
||||
// 按�积从大到�排�
|
||||
// 按面积从大到小排序
|
||||
results.Sort((a, b) => b.BgaArea.CompareTo(a.BgaArea));
|
||||
for (int i = 0; i < results.Count; i++) results[i].Index = i + 1;
|
||||
|
||||
@@ -296,8 +296,8 @@ public class BgaVoidRateProcessor : ImageProcessorBase
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 第二æ¥ï¼šåœ¨å�•个BGA焊ç�ƒåŒºåŸŸå†…检测气æ³?
|
||||
/// 使用焊ç�ƒè½®å»“作为掩ç �,å�Œé˜ˆå€¼åˆ†å‰²æ°”泡区åŸ?
|
||||
/// 第二步:在单个BGA焊球区域内检测气泡
|
||||
/// 使用焊球轮廓作为掩码,双阈值分割气泡区域
|
||||
/// </summary>
|
||||
private void DetectVoidsInBga(Image<Gray, byte> input, BgaBallInfo bga, int minThresh, int maxThresh, int minVoidArea)
|
||||
{
|
||||
@@ -314,7 +314,7 @@ public class BgaVoidRateProcessor : ImageProcessorBase
|
||||
int bgaPixels = CvInvoke.CountNonZero(mask);
|
||||
bga.BgaArea = bgaPixels;
|
||||
|
||||
// å�Œé˜ˆå€¼åˆ†å‰²ï¼ˆæ£ç‰‡æ¨¡å¼�:气æ³?亮,ç�°åº¦åœ¨[minThresh, maxThresh]范围内判为气泡)
|
||||
// 双阈值分割(正片模式:气泡=亮,灰度在[minThresh, maxThresh]范围内判为气泡)
|
||||
var voidImg = new Image<Gray, byte>(w, h);
|
||||
byte[,,] srcData = input.Data;
|
||||
byte[,,] dstData = voidImg.Data;
|
||||
@@ -361,7 +361,7 @@ public class BgaVoidRateProcessor : ImageProcessorBase
|
||||
});
|
||||
}
|
||||
|
||||
// 按�积从大到�排�
|
||||
// 按面积从大到小排序
|
||||
bga.Voids.Sort((a, b) => b.Area.CompareTo(a.Area));
|
||||
for (int i = 0; i < bga.Voids.Count; i++) bga.Voids[i].Index = i + 1;
|
||||
|
||||
@@ -400,4 +400,4 @@ public class VoidInfo
|
||||
public double AreaPercent { get; set; }
|
||||
public Rectangle BoundingBox { get; set; }
|
||||
public Point[] ContourPoints { get; set; } = Array.Empty<Point>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
// ============================================================================
|
||||
// Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved.
|
||||
// 文件� ContourProcessor.cs
|
||||
// 文件名: ContourProcessor.cs
|
||||
// 描述: 轮廓查找算子,用于检测和分析图像中的轮廓
|
||||
// 功能:
|
||||
// - 检测图åƒ�ä¸çš„外部轮å»?
|
||||
// - 检测图像中的外部轮廓
|
||||
// - 根据面积范围过滤轮廓
|
||||
// - è®¡ç®—è½®å»“çš„å‡ ä½•ç‰¹å¾�(é�¢ç§¯ã€�周长ã€�ä¸å¿ƒã€�外接矩形ç‰ï¼?
|
||||
// - 输出轮廓信æ�¯ä¾›å�Žç»å¤„ç�†ä½¿ç”?
|
||||
// 算法: 基于OpenCV的轮廓检测算�
|
||||
// 作� �伟 wei.lw.li@hexagon.com
|
||||
// - 计算轮廓的几何特征(面积、周长、中心、外接矩形等)
|
||||
// - 输出轮廓信息供后续处理使用
|
||||
// 算法: 基于OpenCV的轮廓检测算法
|
||||
// 作者: 李伟 wei.lw.li@hexagon.com
|
||||
// ============================================================================
|
||||
|
||||
using Emgu.CV;
|
||||
using Emgu.CV.CvEnum;
|
||||
using Emgu.CV.Structure;
|
||||
using Emgu.CV.Util;
|
||||
using XP.ImageProcessing.Core;
|
||||
using Serilog;
|
||||
using System.Drawing;
|
||||
using XP.ImageProcessing.Core;
|
||||
|
||||
namespace XP.ImageProcessing.Processors;
|
||||
|
||||
@@ -117,7 +117,7 @@ public class ContourProcessor : ImageProcessorBase
|
||||
|
||||
OutputData.Clear();
|
||||
|
||||
// 创建输入图�的副本用于处�
|
||||
// 创建输入图像的副本用于处理
|
||||
Image<Gray, byte> processImage = inputImage.Clone();
|
||||
|
||||
// 步骤1:如果启用阈值分割,先进行二值化
|
||||
@@ -128,18 +128,18 @@ public class ContourProcessor : ImageProcessorBase
|
||||
|
||||
if (useOtsu)
|
||||
{
|
||||
// 使用Otsu自动阈�
|
||||
// 使用Otsu自动阈值
|
||||
CvInvoke.Threshold(processImage, thresholdImage, 0, 255, ThresholdType.Otsu);
|
||||
_logger.Debug("Applied Otsu threshold");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 使用固定阈�
|
||||
// 使用固定阈值
|
||||
CvInvoke.Threshold(processImage, thresholdImage, thresholdValue, 255, ThresholdType.Binary);
|
||||
_logger.Debug("Applied binary threshold with value {ThresholdValue}", thresholdValue);
|
||||
}
|
||||
|
||||
// ä¿�å˜é˜ˆå€¼å¤„ç�†å�Žçš„图åƒ�用于调è¯?
|
||||
// 保存阈值处理后的图像用于调试
|
||||
try
|
||||
{
|
||||
string debugPath = Path.Combine("logs", $"contour_threshold_{DateTime.Now:yyyyMMdd_HHmmss}.png");
|
||||
@@ -156,7 +156,7 @@ public class ContourProcessor : ImageProcessorBase
|
||||
processImage = thresholdImage;
|
||||
}
|
||||
|
||||
// æ¥éª¤2ï¼šå¦‚æžœç›®æ ‡æ˜¯é»‘è‰²åŒºåŸŸï¼Œéœ€è¦�å��转图åƒ?
|
||||
// 步骤2:如果目标是黑色区域,需要反转图像
|
||||
bool isBlackTarget = targetColor != null &&
|
||||
(targetColor.Equals("Black", StringComparison.OrdinalIgnoreCase) ||
|
||||
targetColor.Equals("黑色", StringComparison.OrdinalIgnoreCase));
|
||||
@@ -180,7 +180,7 @@ public class ContourProcessor : ImageProcessorBase
|
||||
}
|
||||
}
|
||||
|
||||
// æ¥éª¤3:查找轮å»?
|
||||
// 步骤3:查找轮廓
|
||||
using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
|
||||
{
|
||||
Mat hierarchy = new Mat();
|
||||
|
||||
@@ -1,64 +1,53 @@
|
||||
// ============================================================================
|
||||
// Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved.
|
||||
// 文件� EllipseDetectionProcessor.cs
|
||||
// æ��è¿°: æ¤åœ†æ£€æµ‹ç®—å�,基于轮廓分æž�å’Œæ¤åœ†æ‹Ÿå�ˆæ£€æµ‹å›¾åƒ�ä¸çš„æ¤åœ?
|
||||
// 文件名: EllipseDetectionProcessor.cs
|
||||
// 描述: 椭圆检测算子,基于轮廓分析和椭圆拟合检测图像中的椭圆
|
||||
// 功能:
|
||||
// - 阈值分�+ 轮廓��
|
||||
// - æ¤åœ†æ‹Ÿå�ˆï¼ˆFitEllipseï¼?
|
||||
// - �积/轴长/离心�拟�误差多维过滤
|
||||
// - 支��阈值分割和 Otsu 自动阈�
|
||||
// 算法: 阈值分�+ OpenCV FitEllipse
|
||||
// 作� �伟 wei.lw.li@hexagon.com
|
||||
// - 阈值分割 + 轮廓提取
|
||||
// - 椭圆拟合(FitEllipse)
|
||||
// - 面积/轴长/离心率/拟合误差多维过滤
|
||||
// - 支持双阈值分割和 Otsu 自动阈值
|
||||
// 算法: 阈值分割 + OpenCV FitEllipse
|
||||
// 作者: 李伟 wei.lw.li@hexagon.com
|
||||
// ============================================================================
|
||||
|
||||
using Emgu.CV;
|
||||
using Emgu.CV.CvEnum;
|
||||
using Emgu.CV.Structure;
|
||||
using Emgu.CV.Util;
|
||||
using XP.ImageProcessing.Core;
|
||||
using Serilog;
|
||||
using System.Drawing;
|
||||
using XP.ImageProcessing.Core;
|
||||
|
||||
namespace XP.ImageProcessing.Processors;
|
||||
|
||||
/// <summary>
|
||||
/// æ¤åœ†æ£€æµ‹ç»“æž?
|
||||
/// 椭圆检测结果
|
||||
/// </summary>
|
||||
public class EllipseInfo
|
||||
{
|
||||
/// <summary>序号</summary>
|
||||
public int Index { get; set; }
|
||||
|
||||
/// <summary>中心点X</summary>
|
||||
public float CenterX { get; set; }
|
||||
|
||||
/// <summary>中心点Y</summary>
|
||||
public float CenterY { get; set; }
|
||||
|
||||
/// <summary>长轴长度</summary>
|
||||
public float MajorAxis { get; set; }
|
||||
|
||||
/// <summary>短轴长度</summary>
|
||||
public float MinorAxis { get; set; }
|
||||
|
||||
/// <summary>旋转角度(度�/summary>
|
||||
/// <summary>旋转角度(度)</summary>
|
||||
public float Angle { get; set; }
|
||||
|
||||
/// <summary>面积</summary>
|
||||
public double Area { get; set; }
|
||||
|
||||
/// <summary>周长</summary>
|
||||
public double Perimeter { get; set; }
|
||||
|
||||
/// <summary>离心çŽ?(0=åœ? 接近1=æ‰�æ¤åœ?</summary>
|
||||
/// <summary>离心率 (0=圆, 接近1=扁椭圆)</summary>
|
||||
public double Eccentricity { get; set; }
|
||||
|
||||
/// <summary>拟合误差(像素)</summary>
|
||||
public double FitError { get; set; }
|
||||
|
||||
/// <summary>轮廓点集</summary>
|
||||
public Point[] ContourPoints { get; set; } = Array.Empty<Point>();
|
||||
|
||||
/// <summary>外接矩形</summary>
|
||||
public Rectangle BoundingBox { get; set; }
|
||||
}
|
||||
@@ -81,7 +70,7 @@ public class EllipseDetector
|
||||
public double MaxFitError { get; set; } = 5.0;
|
||||
public int Thickness { get; set; } = 2;
|
||||
|
||||
/// <summary>执行æ¤åœ†æ£€æµ?/summary>
|
||||
/// <summary>执行椭圆检测</summary>
|
||||
public List<EllipseInfo> Detect(Image<Gray, byte> inputImage, Image<Gray, byte>? roiMask = null)
|
||||
{
|
||||
_logger.Debug("Ellipse detection started: UseOtsu={UseOtsu}, MinThreshold={Min}, MaxThreshold={Max}",
|
||||
@@ -197,7 +186,7 @@ public class EllipseDetector
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// æ¤åœ†æ£€æµ‹ç®—å?
|
||||
/// 椭圆检测算子
|
||||
/// </summary>
|
||||
public class EllipseDetectionProcessor : ImageProcessorBase
|
||||
{
|
||||
@@ -211,7 +200,7 @@ public class EllipseDetectionProcessor : ImageProcessorBase
|
||||
|
||||
protected override void InitializeParameters()
|
||||
{
|
||||
// ── 多边形ROI(由UI注入,最�2个点�──
|
||||
// ── 多边形ROI(由UI注入,最多32个点) ──
|
||||
Parameters.Add("PolyCount", new ProcessorParameter("PolyCount", "PolyCount", typeof(int), 0, null, null, "") { IsVisible = false });
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
@@ -311,4 +300,4 @@ public class EllipseDetectionProcessor : ImageProcessorBase
|
||||
_logger.Information("Ellipse detection completed: detected {Count} ellipses", ellipses.Count);
|
||||
return inputImage.Clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
// ============================================================================
|
||||
// Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved.
|
||||
// 文件� FillRateProcessor.cs
|
||||
// 文件名: FillRateProcessor.cs
|
||||
// 描述: 通孔填锡率测量算子(倾斜投影几何法),基于四椭圆ROI
|
||||
// 功能:
|
||||
// - æ ·å“�倾斜çº?5°放置,利用投影ä½�移关系计算填锡率
|
||||
// - 四个æ¤åœ†å®šä¹‰ï¼?
|
||||
// - 样品倾斜约45°放置,利用投影位移关系计算填锡率
|
||||
// - 四个椭圆定义:
|
||||
// E1 = 通孔底部轮廓
|
||||
// E2 = 通孔顶部轮廓
|
||||
// E3 = 填锡起点(与E1��,代�%填锡�
|
||||
// E4 = 填锡终点(锡实际填充到的高度�
|
||||
// - 填锡çŽ?= |E4ä¸å¿ƒ - E3ä¸å¿ƒ| / |E2ä¸å¿ƒ - E1ä¸å¿ƒ| × 100%
|
||||
// - çº¯å‡ ä½•æ–¹æ³•ï¼Œä¸�ä¾�èµ–ç�°åº¦åˆ†æž?
|
||||
// - IPC-610 THT 分级判定(Class 1/2/3�
|
||||
// E3 = 填锡起点(与E1重合,代表0%填锡)
|
||||
// E4 = 填锡终点(锡实际填充到的高度)
|
||||
// - 填锡率 = |E4中心 - E3中心| / |E2中心 - E1中心| × 100%
|
||||
// - 纯几何方法,不依赖灰度分析
|
||||
// - IPC-610 THT 分级判定(Class 1/2/3)
|
||||
// 算法: 倾斜投影位移比例
|
||||
// 作� �伟 wei.lw.li@hexagon.com
|
||||
// 作者: 李伟 wei.lw.li@hexagon.com
|
||||
// ============================================================================
|
||||
|
||||
using Emgu.CV;
|
||||
using Emgu.CV.Structure;
|
||||
using XP.ImageProcessing.Core;
|
||||
using Serilog;
|
||||
using System.Drawing;
|
||||
using XP.ImageProcessing.Core;
|
||||
|
||||
namespace XP.ImageProcessing.Processors;
|
||||
|
||||
@@ -42,7 +42,7 @@ public class FillRateProcessor : ImageProcessorBase
|
||||
// 四个椭圆(由交互控件注入,UI不可见)
|
||||
AddEllipseParams("E1", 200, 250, 60, 50, 0); // 底部
|
||||
AddEllipseParams("E2", 220, 180, 60, 50, 0); // 顶部
|
||||
AddEllipseParams("E3", 200, 250, 60, 50, 0); // 填锡起点�E1�
|
||||
AddEllipseParams("E3", 200, 250, 60, 50, 0); // 填锡起点(=E1)
|
||||
AddEllipseParams("E4", 210, 220, 55, 45, 0); // 填锡终点
|
||||
|
||||
Parameters.Add("THTLimit", new ProcessorParameter(
|
||||
@@ -78,7 +78,7 @@ public class FillRateProcessor : ImageProcessorBase
|
||||
int e3cx = GetParameter<int>("E3_CX"), e3cy = GetParameter<int>("E3_CY");
|
||||
int e4cx = GetParameter<int>("E4_CX"), e4cy = GetParameter<int>("E4_CY");
|
||||
|
||||
// 获å�–æ¤åœ†è½´å�‚数(用于绘制ï¼?
|
||||
// 获取椭圆轴参数(用于绘制)
|
||||
double e1a = GetParameter<double>("E1_A"), e1b = GetParameter<double>("E1_B"), e1ang = GetParameter<double>("E1_Angle");
|
||||
double e2a = GetParameter<double>("E2_A"), e2b = GetParameter<double>("E2_B"), e2ang = GetParameter<double>("E2_Angle");
|
||||
double e3a = GetParameter<double>("E3_A"), e3b = GetParameter<double>("E3_B"), e3ang = GetParameter<double>("E3_Angle");
|
||||
@@ -89,17 +89,17 @@ public class FillRateProcessor : ImageProcessorBase
|
||||
|
||||
OutputData.Clear();
|
||||
|
||||
// 计算通å”全高度的投影ä½�移(E1底部 â†?E2顶部ï¼?
|
||||
// 计算通孔全高度的投影位移(E1底部 → E2顶部)
|
||||
double fullDx = e2cx - e1cx;
|
||||
double fullDy = e2cy - e1cy;
|
||||
double fullDistance = Math.Sqrt(fullDx * fullDx + fullDy * fullDy);
|
||||
|
||||
// 计算填锡高度的投影�移(E3起点 �E4终点�
|
||||
// 计算填锡高度的投影位移(E3起点 → E4终点)
|
||||
double fillDx = e4cx - e3cx;
|
||||
double fillDy = e4cy - e3cy;
|
||||
double fillDistance = Math.Sqrt(fillDx * fillDx + fillDy * fillDy);
|
||||
|
||||
// 填锡�= 填锡�移 / 全高度��
|
||||
// 填锡率 = 填锡位移 / 全高度位移
|
||||
double fillRate = fullDistance > 0 ? (fillDistance / fullDistance) * 100.0 : 0;
|
||||
fillRate = Math.Clamp(fillRate, 0, 100);
|
||||
|
||||
@@ -130,4 +130,4 @@ public class FillRateProcessor : ImageProcessorBase
|
||||
|
||||
return inputImage.Clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
// ============================================================================
|
||||
// Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved.
|
||||
// 文件��? LineMeasurementProcessor.cs
|
||||
// 描述: 直线测量算子,用于测量图像中两点之间的距��?
|
||||
// 文件名: LineMeasurementProcessor.cs
|
||||
// 描述: 直线测量算子,用于测量图像中两点之间的距离
|
||||
// 功能:
|
||||
// - 用户指定两个点坐标(像素坐标��?
|
||||
// - 计算两点之间的欧氏距离(像素单位��?
|
||||
// - 支持像素尺寸标定,输出实际物理距��?
|
||||
// - 用户指定两个点坐标(像素坐标)
|
||||
// - 计算两点之间的欧氏距离(像素单位)
|
||||
// - 支持像素尺寸标定,输出实际物理距离
|
||||
// - 在图像上绘制测量线和标注
|
||||
// - 输出测量结果供后续处理使��?
|
||||
// - 输出测量结果供后续处理使用
|
||||
// 算法: 欧氏距离计算
|
||||
// 作��? 李伟 wei.lw.li@hexagon.com
|
||||
// 作者: 李伟 wei.lw.li@hexagon.com
|
||||
// ============================================================================
|
||||
|
||||
using Emgu.CV;
|
||||
using Emgu.CV.CvEnum;
|
||||
using Emgu.CV.Structure;
|
||||
using XP.ImageProcessing.Core;
|
||||
using Serilog;
|
||||
using System.Drawing;
|
||||
using XP.ImageProcessing.Core;
|
||||
|
||||
namespace XP.ImageProcessing.Processors;
|
||||
|
||||
/// <summary>
|
||||
/// 直线测量算子 - 测量两点之间的距��?
|
||||
/// 直线测量算子 - 测量两点之间的距离
|
||||
/// </summary>
|
||||
public class LineMeasurementProcessor : ImageProcessorBase
|
||||
{
|
||||
@@ -40,28 +41,28 @@ public class LineMeasurementProcessor : ImageProcessorBase
|
||||
LocalizationHelper.GetString("LineMeasurementProcessor_X1"),
|
||||
typeof(int), 100, null, null,
|
||||
LocalizationHelper.GetString("LineMeasurementProcessor_X1_Desc"))
|
||||
{ IsVisible = false });
|
||||
{ IsVisible = false });
|
||||
|
||||
Parameters.Add("Y1", new ProcessorParameter(
|
||||
"Y1",
|
||||
LocalizationHelper.GetString("LineMeasurementProcessor_Y1"),
|
||||
typeof(int), 100, null, null,
|
||||
LocalizationHelper.GetString("LineMeasurementProcessor_Y1_Desc"))
|
||||
{ IsVisible = false });
|
||||
{ IsVisible = false });
|
||||
|
||||
Parameters.Add("X2", new ProcessorParameter(
|
||||
"X2",
|
||||
LocalizationHelper.GetString("LineMeasurementProcessor_X2"),
|
||||
typeof(int), 400, null, null,
|
||||
LocalizationHelper.GetString("LineMeasurementProcessor_X2_Desc"))
|
||||
{ IsVisible = false });
|
||||
{ IsVisible = false });
|
||||
|
||||
Parameters.Add("Y2", new ProcessorParameter(
|
||||
"Y2",
|
||||
LocalizationHelper.GetString("LineMeasurementProcessor_Y2"),
|
||||
typeof(int), 400, null, null,
|
||||
LocalizationHelper.GetString("LineMeasurementProcessor_Y2_Desc"))
|
||||
{ IsVisible = false });
|
||||
{ IsVisible = false });
|
||||
|
||||
Parameters.Add("PixelSize", new ProcessorParameter(
|
||||
"PixelSize",
|
||||
@@ -119,7 +120,7 @@ public class LineMeasurementProcessor : ImageProcessorBase
|
||||
// 计算实际距离
|
||||
double actualDistance = pixelDistance * pixelSize;
|
||||
|
||||
// 计算角度(相对于水平方向��?
|
||||
// 计算角度(相对于水平方向)
|
||||
double angleRad = Math.Atan2(dy, dx);
|
||||
double angleDeg = angleRad * 180.0 / Math.PI;
|
||||
|
||||
@@ -146,4 +147,4 @@ public class LineMeasurementProcessor : ImageProcessorBase
|
||||
|
||||
return inputImage.Clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
// ============================================================================
|
||||
// Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved.
|
||||
// 文件� PointToLineProcessor.cs
|
||||
// 文件名: PointToLineProcessor.cs
|
||||
// 描述: 点到直线距离测量算子
|
||||
// 功能:
|
||||
// - 用户定义一条直线(两个端点)和一个测量点
|
||||
// - 计算测�点到直线的垂直��
|
||||
// - 计算测量点到直线的垂直距离
|
||||
// - 支持像素尺寸标定输出物理距离
|
||||
// - 在图像上绘制直线、测量点、垂足和距离标注
|
||||
// 算法: 点到直线距离公式
|
||||
// 作� �伟 wei.lw.li@hexagon.com
|
||||
// 作者: 李伟 wei.lw.li@hexagon.com
|
||||
// ============================================================================
|
||||
|
||||
using Emgu.CV;
|
||||
using Emgu.CV.CvEnum;
|
||||
using Emgu.CV.Structure;
|
||||
using XP.ImageProcessing.Core;
|
||||
using Serilog;
|
||||
using System.Drawing;
|
||||
using XP.ImageProcessing.Core;
|
||||
|
||||
namespace XP.ImageProcessing.Processors;
|
||||
|
||||
@@ -31,7 +32,7 @@ public class PointToLineProcessor : ImageProcessorBase
|
||||
|
||||
protected override void InitializeParameters()
|
||||
{
|
||||
// 直线两端�+ 测�点(由交互控件注入)
|
||||
// 直线两端点 + 测量点(由交互控件注入)
|
||||
Parameters.Add("L1X", new ProcessorParameter("L1X", "L1X", typeof(int), 100, null, null, "") { IsVisible = false });
|
||||
Parameters.Add("L1Y", new ProcessorParameter("L1Y", "L1Y", typeof(int), 200, null, null, "") { IsVisible = false });
|
||||
Parameters.Add("L2X", new ProcessorParameter("L2X", "L2X", typeof(int), 400, null, null, "") { IsVisible = false });
|
||||
@@ -79,7 +80,7 @@ public class PointToLineProcessor : ImageProcessorBase
|
||||
|
||||
if (abLen > 0.001)
|
||||
{
|
||||
// �积求��
|
||||
// 叉积求距离
|
||||
double cross = Math.Abs(abx * (l1y - py) - aby * (l1x - px));
|
||||
pixelDistance = cross / abLen;
|
||||
|
||||
@@ -112,4 +113,4 @@ public class PointToLineProcessor : ImageProcessorBase
|
||||
|
||||
return inputImage.Clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
// ============================================================================
|
||||
// 文件� VoidMeasurementProcessor.cs
|
||||
// 文件名: VoidMeasurementProcessor.cs
|
||||
// 描述: 空隙测量算子
|
||||
//
|
||||
// 处理流程:
|
||||
// 1. 构建多边形ROI掩码,计算ROI面积
|
||||
// 2. 在ROI内进行�阈值分割��气泡区�
|
||||
// 2. 在ROI内进行双阈值分割提取气泡区域
|
||||
// 3. 形态学膨胀合并相邻气泡
|
||||
// 4. 轮廓检测,计算每个气泡面积
|
||||
// 5. 计算空隙�= 总气泡��/ ROI�积
|
||||
// 5. 计算空隙率 = 总气泡面积 / ROI面积
|
||||
// ============================================================================
|
||||
|
||||
using Emgu.CV;
|
||||
using Emgu.CV.CvEnum;
|
||||
using Emgu.CV.Structure;
|
||||
using Emgu.CV.Util;
|
||||
using XP.ImageProcessing.Core;
|
||||
using Serilog;
|
||||
using System.Drawing;
|
||||
using XP.ImageProcessing.Core;
|
||||
|
||||
namespace XP.ImageProcessing.Processors;
|
||||
|
||||
@@ -32,7 +32,7 @@ public class VoidMeasurementProcessor : ImageProcessorBase
|
||||
|
||||
protected override void InitializeParameters()
|
||||
{
|
||||
// ── 多边形ROI(由UI注入,最�2个点�──
|
||||
// ── 多边形ROI(由UI注入,最多32个点) ──
|
||||
Parameters.Add("PolyCount", new ProcessorParameter("PolyCount", "PolyCount", typeof(int), 0, null, null, "") { IsVisible = false });
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
@@ -40,7 +40,7 @@ public class VoidMeasurementProcessor : ImageProcessorBase
|
||||
Parameters.Add($"PolyY{i}", new ProcessorParameter($"PolyY{i}", $"PolyY{i}", typeof(int), 0, null, null, "") { IsVisible = false });
|
||||
}
|
||||
|
||||
// ── 气泡检测��──
|
||||
// ── 气泡检测参数 ──
|
||||
Parameters.Add("MinThreshold", new ProcessorParameter(
|
||||
"MinThreshold",
|
||||
LocalizationHelper.GetString("VoidMeasurementProcessor_MinThreshold"),
|
||||
@@ -109,7 +109,7 @@ public class VoidMeasurementProcessor : ImageProcessorBase
|
||||
}
|
||||
else
|
||||
{
|
||||
// æ— ROI时使用全å›?
|
||||
// 无ROI时使用全图
|
||||
roiMask = new Image<Gray, byte>(w, h);
|
||||
roiMask.SetValue(new Gray(255));
|
||||
}
|
||||
@@ -152,7 +152,7 @@ public class VoidMeasurementProcessor : ImageProcessorBase
|
||||
CvInvoke.BitwiseAnd(voidImg, roiMask, voidImg);
|
||||
}
|
||||
|
||||
// ── 轮廓检�──
|
||||
// ── 轮廓检测 ──
|
||||
using var contours = new VectorOfVectorOfPoint();
|
||||
using var hierarchy = new Mat();
|
||||
CvInvoke.FindContours(voidImg, contours, hierarchy, RetrType.External, ChainApproxMethod.ChainApproxSimple);
|
||||
@@ -183,7 +183,7 @@ public class VoidMeasurementProcessor : ImageProcessorBase
|
||||
});
|
||||
}
|
||||
|
||||
// 按�积从大到�排�
|
||||
// 按面积从大到小排序
|
||||
voids.Sort((a, b) => b.Area.CompareTo(a.Area));
|
||||
for (int i = 0; i < voids.Count; i++) voids[i].Index = i + 1;
|
||||
|
||||
@@ -227,4 +227,4 @@ public class VoidRegionInfo
|
||||
public double AreaPercent { get; set; }
|
||||
public Rectangle BoundingBox { get; set; }
|
||||
public Point[] ContourPoints { get; set; } = Array.Empty<Point>();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user