117 lines
4.9 KiB
C#
117 lines
4.9 KiB
C#
// ============================================================================
|
||
// 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();
|
||
}
|
||
}
|