Files
XplorePlane/XP.ImageProcessing.Processors/检测分析/PointToLineProcessor.cs
T
2026-04-14 17:12:31 +08:00

117 lines
4.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ============================================================================
// Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved.
// 文件名: PointToLineProcessor.cs
// 描述: 点到直线距离测量算子
// 功能:
// - 用户定义一条直线(两个端点)和一个测量点
// - 计算测量点到直线的垂直距离
// - 支持像素尺寸标定输出物理距离
// - 在图像上绘制直线、测量点、垂足和距离标注
// 算法: 点到直线距离公式
// 作者: 李伟 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;
namespace XP.ImageProcessing.Processors;
public class PointToLineProcessor : ImageProcessorBase
{
private static readonly ILogger _logger = Log.ForContext<PointToLineProcessor>();
public PointToLineProcessor()
{
Name = LocalizationHelper.GetString("PointToLineProcessor_Name");
Description = LocalizationHelper.GetString("PointToLineProcessor_Description");
}
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 });
Parameters.Add("L2Y", new ProcessorParameter("L2Y", "L2Y", typeof(int), 200, null, null, "") { IsVisible = false });
Parameters.Add("PX", new ProcessorParameter("PX", "PX", typeof(int), 250, null, null, "") { IsVisible = false });
Parameters.Add("PY", new ProcessorParameter("PY", "PY", typeof(int), 100, null, null, "") { IsVisible = false });
Parameters.Add("PixelSize", new ProcessorParameter(
"PixelSize",
LocalizationHelper.GetString("PointToLineProcessor_PixelSize"),
typeof(double), 1.0, null, null,
LocalizationHelper.GetString("PointToLineProcessor_PixelSize_Desc")));
Parameters.Add("Unit", new ProcessorParameter(
"Unit",
LocalizationHelper.GetString("PointToLineProcessor_Unit"),
typeof(string), "px", null, null,
LocalizationHelper.GetString("PointToLineProcessor_Unit_Desc"),
new string[] { "px", "mm", "μm", "cm" }));
Parameters.Add("Thickness", new ProcessorParameter(
"Thickness",
LocalizationHelper.GetString("PointToLineProcessor_Thickness"),
typeof(int), 2, 1, 10,
LocalizationHelper.GetString("PointToLineProcessor_Thickness_Desc")));
}
public override Image<Gray, byte> Process(Image<Gray, byte> inputImage)
{
int l1x = GetParameter<int>("L1X"), l1y = GetParameter<int>("L1Y");
int l2x = GetParameter<int>("L2X"), l2y = GetParameter<int>("L2Y");
int px = GetParameter<int>("PX"), py = GetParameter<int>("PY");
double pixelSize = GetParameter<double>("PixelSize");
string unit = GetParameter<string>("Unit");
int thickness = GetParameter<int>("Thickness");
OutputData.Clear();
// 点到直线距离公式: |AB × AP| / |AB|
double abx = l2x - l1x, aby = l2y - l1y;
double abLen = Math.Sqrt(abx * abx + aby * aby);
double pixelDistance = 0;
int footX = px, footY = py;
if (abLen > 0.001)
{
// 叉积求距离
double cross = Math.Abs(abx * (l1y - py) - aby * (l1x - px));
pixelDistance = cross / abLen;
// 垂足: 投影参数 t = AP·AB / |AB|²
double apx = px - l1x, apy = py - l1y;
double t = (apx * abx + apy * aby) / (abLen * abLen);
footX = (int)(l1x + t * abx);
footY = (int)(l1y + t * aby);
OutputData["ProjectionT"] = t;
}
double actualDistance = pixelDistance * pixelSize;
string distanceText = unit == "px"
? $"{pixelDistance:F2} px"
: $"{actualDistance:F4} {unit} ({pixelDistance:F2} px)";
OutputData["PointToLineResult"] = true;
OutputData["Line1"] = new Point(l1x, l1y);
OutputData["Line2"] = new Point(l2x, l2y);
OutputData["MeasurePoint"] = new Point(px, py);
OutputData["FootPoint"] = new Point(footX, footY);
OutputData["PixelDistance"] = pixelDistance;
OutputData["ActualDistance"] = actualDistance;
OutputData["Unit"] = unit;
OutputData["Thickness"] = thickness;
OutputData["DistanceText"] = distanceText;
_logger.Information("PointToLine: Distance={Dist}, Foot=({FX},{FY})", distanceText, footX, footY);
return inputImage.Clone();
}
}