// ============================================================================ // Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved. // 文件? LineMeasurementProcessor.cs // 描述: 直线测量算子,用于测量图像中两点之间的距? // 功能: // - 用户指定两个点坐标(像素坐标? // - 计算两点之间的欧氏距离(像素单位? // - 支持像素尺寸标定,输出实际物理距? // - 在图像上绘制测量线和标注 // - 输出测量结果供后续处理使? // 算法: 欧氏距离计算 // 作? 李伟 wei.lw.li@hexagon.com // ============================================================================ using Emgu.CV; using Emgu.CV.Structure; using Serilog; using System.Drawing; using XP.ImageProcessing.Core; namespace XP.ImageProcessing.Processors; /// /// 直线测量算子 - 测量两点之间的距? /// public class LineMeasurementProcessor : ImageProcessorBase { private static readonly ILogger _logger = Log.ForContext(); public LineMeasurementProcessor() { Name = LocalizationHelper.GetString("LineMeasurementProcessor_Name"); Description = LocalizationHelper.GetString("LineMeasurementProcessor_Description"); } protected override void InitializeParameters() { Parameters.Add("X1", new ProcessorParameter( "X1", LocalizationHelper.GetString("LineMeasurementProcessor_X1"), typeof(int), 100, null, null, LocalizationHelper.GetString("LineMeasurementProcessor_X1_Desc")) { IsVisible = false }); Parameters.Add("Y1", new ProcessorParameter( "Y1", LocalizationHelper.GetString("LineMeasurementProcessor_Y1"), typeof(int), 100, null, null, LocalizationHelper.GetString("LineMeasurementProcessor_Y1_Desc")) { IsVisible = false }); Parameters.Add("X2", new ProcessorParameter( "X2", LocalizationHelper.GetString("LineMeasurementProcessor_X2"), typeof(int), 400, null, null, LocalizationHelper.GetString("LineMeasurementProcessor_X2_Desc")) { IsVisible = false }); Parameters.Add("Y2", new ProcessorParameter( "Y2", LocalizationHelper.GetString("LineMeasurementProcessor_Y2"), typeof(int), 400, null, null, LocalizationHelper.GetString("LineMeasurementProcessor_Y2_Desc")) { IsVisible = false }); Parameters.Add("PixelSize", new ProcessorParameter( "PixelSize", LocalizationHelper.GetString("LineMeasurementProcessor_PixelSize"), typeof(double), 1.0, null, null, LocalizationHelper.GetString("LineMeasurementProcessor_PixelSize_Desc"))); Parameters.Add("Unit", new ProcessorParameter( "Unit", LocalizationHelper.GetString("LineMeasurementProcessor_Unit"), typeof(string), "px", null, null, LocalizationHelper.GetString("LineMeasurementProcessor_Unit_Desc"), new string[] { "px", "mm", "μm", "cm" })); Parameters.Add("Thickness", new ProcessorParameter( "Thickness", LocalizationHelper.GetString("LineMeasurementProcessor_Thickness"), typeof(int), 2, 1, 10, LocalizationHelper.GetString("LineMeasurementProcessor_Thickness_Desc"))); Parameters.Add("ShowLabel", new ProcessorParameter( "ShowLabel", LocalizationHelper.GetString("LineMeasurementProcessor_ShowLabel"), typeof(bool), true, null, null, LocalizationHelper.GetString("LineMeasurementProcessor_ShowLabel_Desc"))); } public override Image Process(Image inputImage) { int x1 = GetParameter("X1"); int y1 = GetParameter("Y1"); int x2 = GetParameter("X2"); int y2 = GetParameter("Y2"); double pixelSize = GetParameter("PixelSize"); string unit = GetParameter("Unit"); int thickness = GetParameter("Thickness"); bool showLabel = GetParameter("ShowLabel"); _logger.Debug("LineMeasurement: ({X1},{Y1}) -> ({X2},{Y2}), PixelSize={PixelSize}, Unit={Unit}", x1, y1, x2, y2, pixelSize, unit); OutputData.Clear(); // 限制坐标在图像范围内 x1 = Math.Clamp(x1, 0, inputImage.Width - 1); y1 = Math.Clamp(y1, 0, inputImage.Height - 1); x2 = Math.Clamp(x2, 0, inputImage.Width - 1); y2 = Math.Clamp(y2, 0, inputImage.Height - 1); // 计算像素距离 double dx = x2 - x1; double dy = y2 - y1; double pixelDistance = Math.Sqrt(dx * dx + dy * dy); // 计算实际距离 double actualDistance = pixelDistance * pixelSize; // 计算角度(相对于水平方向? double angleRad = Math.Atan2(dy, dx); double angleDeg = angleRad * 180.0 / Math.PI; // 存储测量结果 OutputData["MeasurementType"] = "Line"; OutputData["Point1"] = new Point(x1, y1); OutputData["Point2"] = new Point(x2, y2); OutputData["PixelDistance"] = pixelDistance; OutputData["ActualDistance"] = actualDistance; OutputData["Unit"] = unit; OutputData["Angle"] = angleDeg; OutputData["Thickness"] = thickness; OutputData["ShowLabel"] = showLabel; // 构建测量信息文本 string distanceText = unit == "px" ? $"{pixelDistance:F2} px" : $"{actualDistance:F4} {unit} ({pixelDistance:F2} px)"; OutputData["MeasurementText"] = distanceText; _logger.Information("LineMeasurement completed: Distance={Distance}, Angle={Angle:F2}°", distanceText, angleDeg); return inputImage.Clone(); } }