1874c4a5bb
统一补齐对齐核心工具类、RoiAlignment 算子、模板匹配对齐扩展和多语言资源,便于在检测前稳定完成示教 ROI 到运行图的变换。 Co-authored-by: Cursor <cursoragent@cursor.com>
131 lines
5.7 KiB
C#
131 lines
5.7 KiB
C#
// ============================================================================
|
|
// Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved.
|
|
// 文件名: RoiAlignmentProcessor.cs
|
|
// 描述: 示教多边形 ROI 刚体对齐(平移+旋转)
|
|
//
|
|
// 流水线约定:
|
|
// 输入: 示教 Poly* + ReferencePose(Ref*) + 上一步模板匹配的 MeasuredPose(Measured*)
|
|
// 输出: OutputData 中含变换后的 PolyCount/PolyX/PolyY/RoiMode,可拷贝到 VoidMeasurement 等算子
|
|
// 或: 流水线直接调用 XP.ImageProcessing.Core.Alignment.RoiAlignmentApplier
|
|
// ============================================================================
|
|
|
|
using Emgu.CV;
|
|
using Emgu.CV.Structure;
|
|
using XP.ImageProcessing.Core;
|
|
using XP.ImageProcessing.Core.Alignment;
|
|
using Serilog;
|
|
|
|
namespace XP.ImageProcessing.Processors;
|
|
|
|
/// <summary>
|
|
/// 将示教图上的多边形 ROI 变换到当前图(不修改图像,仅输出对齐后的 ROI 参数)。
|
|
/// </summary>
|
|
public class RoiAlignmentProcessor : ImageProcessorBase
|
|
{
|
|
private static readonly ILogger _logger = Log.ForContext<RoiAlignmentProcessor>();
|
|
|
|
public RoiAlignmentProcessor()
|
|
{
|
|
Name = LocalizationHelper.GetString("RoiAlignmentProcessor_Name");
|
|
Description = LocalizationHelper.GetString("RoiAlignmentProcessor_Description");
|
|
}
|
|
|
|
protected override void InitializeParameters()
|
|
{
|
|
Parameters.Add("RefCenterX", new ProcessorParameter(
|
|
"RefCenterX",
|
|
LocalizationHelper.GetString("RoiAlignmentProcessor_RefCenterX"),
|
|
typeof(double), 0.0, null, null,
|
|
LocalizationHelper.GetString("RoiAlignmentProcessor_RefCenterX_Desc")));
|
|
|
|
Parameters.Add("RefCenterY", new ProcessorParameter(
|
|
"RefCenterY",
|
|
LocalizationHelper.GetString("RoiAlignmentProcessor_RefCenterY"),
|
|
typeof(double), 0.0, null, null,
|
|
LocalizationHelper.GetString("RoiAlignmentProcessor_RefCenterY_Desc")));
|
|
|
|
Parameters.Add("RefAngle", new ProcessorParameter(
|
|
"RefAngle",
|
|
LocalizationHelper.GetString("RoiAlignmentProcessor_RefAngle"),
|
|
typeof(double), 0.0, -180.0, 180.0,
|
|
LocalizationHelper.GetString("RoiAlignmentProcessor_RefAngle_Desc")));
|
|
|
|
Parameters.Add("MeasuredCenterX", new ProcessorParameter(
|
|
"MeasuredCenterX",
|
|
LocalizationHelper.GetString("RoiAlignmentProcessor_MeasuredCenterX"),
|
|
typeof(double), 0.0, null, null,
|
|
LocalizationHelper.GetString("RoiAlignmentProcessor_MeasuredCenterX_Desc")));
|
|
|
|
Parameters.Add("MeasuredCenterY", new ProcessorParameter(
|
|
"MeasuredCenterY",
|
|
LocalizationHelper.GetString("RoiAlignmentProcessor_MeasuredCenterY"),
|
|
typeof(double), 0.0, null, null,
|
|
LocalizationHelper.GetString("RoiAlignmentProcessor_MeasuredCenterY_Desc")));
|
|
|
|
Parameters.Add("MeasuredAngle", new ProcessorParameter(
|
|
"MeasuredAngle",
|
|
LocalizationHelper.GetString("RoiAlignmentProcessor_MeasuredAngle"),
|
|
typeof(double), 0.0, -180.0, 180.0,
|
|
LocalizationHelper.GetString("RoiAlignmentProcessor_MeasuredAngle_Desc")));
|
|
|
|
Parameters.Add(RoiPolygonParameterNames.PolyCount, new ProcessorParameter(
|
|
RoiPolygonParameterNames.PolyCount,
|
|
RoiPolygonParameterNames.PolyCount,
|
|
typeof(int), 0, null, null,
|
|
"") { IsVisible = false });
|
|
|
|
for (int i = 0; i < RoiPolygonParameterNames.MaxPoints; i++)
|
|
{
|
|
Parameters.Add(RoiPolygonParameterNames.PolyX(i), new ProcessorParameter(
|
|
RoiPolygonParameterNames.PolyX(i),
|
|
RoiPolygonParameterNames.PolyX(i),
|
|
typeof(int), 0, null, null,
|
|
"") { IsVisible = false });
|
|
|
|
Parameters.Add(RoiPolygonParameterNames.PolyY(i), new ProcessorParameter(
|
|
RoiPolygonParameterNames.PolyY(i),
|
|
RoiPolygonParameterNames.PolyY(i),
|
|
typeof(int), 0, null, null,
|
|
"") { IsVisible = false });
|
|
}
|
|
}
|
|
|
|
public override Image<Gray, byte> Process(Image<Gray, byte> inputImage)
|
|
{
|
|
OutputData.Clear();
|
|
|
|
var reference = new Pose2D(
|
|
GetParameter<double>("RefCenterX"),
|
|
GetParameter<double>("RefCenterY"),
|
|
GetParameter<double>("RefAngle"));
|
|
|
|
var measured = new Pose2D(
|
|
GetParameter<double>("MeasuredCenterX"),
|
|
GetParameter<double>("MeasuredCenterY"),
|
|
GetParameter<double>("MeasuredAngle"));
|
|
|
|
var paramDict = Parameters.ToDictionary(p => p.Key, p => p.Value.Value);
|
|
var teachPoints = RoiAlignmentApplier.ReadTeachPolygon(paramDict);
|
|
|
|
var result = RoiAlignmentApplier.Apply(reference, teachPoints, measured);
|
|
RoiAlignmentApplier.WriteToOutputData(OutputData, result);
|
|
OutputData[RoiAlignmentOutputKeys.Success] = result.Success;
|
|
if (!string.IsNullOrEmpty(result.ErrorMessage))
|
|
OutputData[RoiAlignmentOutputKeys.Message] = result.ErrorMessage!;
|
|
|
|
OutputData["ResultText"] = OutputData[RoiAlignmentOutputKeys.ResultText] = result.Success
|
|
? $"ROI aligned: {result.TransformedPointsInt.Count} pts"
|
|
: $"ROI align failed: {result.ErrorMessage}";
|
|
|
|
if (result.Success)
|
|
_logger.Debug("RoiAlignment: {Count} points, ref=({Rx:F1},{Ry:F1},{Ra:F1}) meas=({Mx:F1},{My:F1},{Ma:F1})",
|
|
result.TransformedPointsInt.Count,
|
|
reference.X, reference.Y, reference.AngleDegrees,
|
|
measured.X, measured.Y, measured.AngleDegrees);
|
|
else
|
|
_logger.Warning("RoiAlignment failed: {Msg}", result.ErrorMessage);
|
|
|
|
return inputImage.Clone();
|
|
}
|
|
}
|