Files
XplorePlane/XP.ImageProcessing.Core/Alignment/RoiAlignmentPipelineBridge.cs
T
李伟 1874c4a5bb 新增 ROI 对齐基础能力并打通到算子与 UI。
统一补齐对齐核心工具类、RoiAlignment 算子、模板匹配对齐扩展和多语言资源,便于在检测前稳定完成示教 ROI 到运行图的变换。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-01 17:04:32 +08:00

115 lines
4.2 KiB
C#

namespace XP.ImageProcessing.Core.Alignment;
/// <summary>
/// 流水线胶水入口:模板匹配 OutputData → ROI 变换 → 写入下游 VoidMeasurement 等算子参数字典。
/// 不依赖 XplorePlane;由 PipelineExecutionService 在步骤间调用。
/// </summary>
public static class RoiAlignmentPipelineBridge
{
/// <summary>
/// 将测量位姿写入 RoiAlignment 算子参数(MeasuredCenterX/Y/Angle)。
/// </summary>
public static void InjectMeasuredPose(IDictionary<string, object> roiAlignmentParameters, Pose2D measuredPose)
{
if (roiAlignmentParameters == null)
throw new ArgumentNullException(nameof(roiAlignmentParameters));
roiAlignmentParameters["MeasuredCenterX"] = measuredPose.X;
roiAlignmentParameters["MeasuredCenterY"] = measuredPose.Y;
roiAlignmentParameters["MeasuredAngle"] = measuredPose.AngleDegrees;
}
/// <summary>
/// 将示教基准位姿写入 RoiAlignment 算子参数(RefCenterX/Y/Angle)。
/// </summary>
public static void InjectReferencePose(IDictionary<string, object> roiAlignmentParameters, Pose2D referencePose)
{
if (roiAlignmentParameters == null)
throw new ArgumentNullException(nameof(roiAlignmentParameters));
roiAlignmentParameters["RefCenterX"] = referencePose.X;
roiAlignmentParameters["RefCenterY"] = referencePose.Y;
roiAlignmentParameters["RefAngle"] = referencePose.AngleDegrees;
}
/// <summary>
/// 从模板匹配一步 OutputData 读取位姿并对齐示教 ROI。
/// </summary>
public static bool TryAlignFromTemplateMatch(
AlignmentRecipe recipe,
IReadOnlyDictionary<string, object>? templateMatchOutput,
out RoiAlignmentResult result,
int matchIndex = 0)
{
result = RoiAlignmentApplier.ApplyFromTemplateMatchOutput(recipe, templateMatchOutput, matchIndex);
return result.Success;
}
/// <summary>
/// 将 RoiAlignment 算子 OutputData 中的 Poly* 拷贝到检测算子参数字典(如 VoidMeasurement)。
/// </summary>
public static bool TryCopyAlignedRoiToDetectionParameters(
IReadOnlyDictionary<string, object>? roiAlignmentOutput,
IDictionary<string, object> detectionParameters,
out string? errorMessage)
{
errorMessage = null;
if (roiAlignmentOutput == null)
{
errorMessage = "ROI alignment output is null.";
return false;
}
if (roiAlignmentOutput.TryGetValue(RoiAlignmentOutputKeys.Success, out var okObj)
&& okObj is bool ok
&& !ok)
{
if (roiAlignmentOutput.TryGetValue(RoiAlignmentOutputKeys.Message, out var msgObj)
&& msgObj is string msg
&& !string.IsNullOrWhiteSpace(msg))
errorMessage = msg;
else
errorMessage = "ROI alignment failed.";
return false;
}
if (!roiAlignmentOutput.TryGetValue(RoiPolygonParameterNames.PolyCount, out var countObj))
{
errorMessage = "ROI alignment output has no PolyCount.";
return false;
}
int count = Convert.ToInt32(countObj);
if (count < 3)
{
errorMessage = $"Invalid aligned PolyCount={count}.";
return false;
}
RoiAlignmentApplier.WriteToParameters(detectionParameters, new RoiAlignmentResult
{
Success = true,
TransformedPointsInt = ReadIntPointsFromOutput(roiAlignmentOutput, count)
});
return true;
}
private static IReadOnlyList<(int X, int Y)> ReadIntPointsFromOutput(
IReadOnlyDictionary<string, object> output,
int count)
{
var list = new List<(int X, int Y)>(count);
for (int i = 0; i < count; i++)
{
int x = output.TryGetValue(RoiPolygonParameterNames.PolyX(i), out var xo)
? Convert.ToInt32(xo) : 0;
int y = output.TryGetValue(RoiPolygonParameterNames.PolyY(i), out var yo)
? Convert.ToInt32(yo) : 0;
list.Add((x, y));
}
return list;
}
}