// ============================================================================ // 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; /// /// 将示教图上的多边形 ROI 变换到当前图(不修改图像,仅输出对齐后的 ROI 参数)。 /// public class RoiAlignmentProcessor : ImageProcessorBase { private static readonly ILogger _logger = Log.ForContext(); 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 Process(Image inputImage) { OutputData.Clear(); var reference = new Pose2D( GetParameter("RefCenterX"), GetParameter("RefCenterY"), GetParameter("RefAngle")); var measured = new Pose2D( GetParameter("MeasuredCenterX"), GetParameter("MeasuredCenterY"), GetParameter("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(); } }