Files
XplorePlane/XP.ImageProcessing.Core/Alignment/RoiAlignment.cs
T
李伟 7447463c1a feat: ROI 对齐工具与 TM_Result 位姿扩展
- Core: Pose2D、Point2D、RoiAlignment、AlignmentRecipe(示教多边形→运行图刚体变换)

- Processors: TemplateMatchAlignmentExtensions.ToPose2D / 四角与中心一致性校验

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-15 14:31:48 +08:00

97 lines
3.6 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.
namespace XP.ImageProcessing.Core.Alignment;
/// <summary>
/// 将示教图(模板坐标系)上的 ROI 点变换到运行图坐标。
/// 旋转中心与模板匹配一致:绕 <see cref="Pose2D.X"/>/<see cref="Pose2D.Y"/>pattern 中心)。
/// </summary>
public static class RoiAlignment
{
/// <summary>
/// 刚体变换:示教图点 → 运行图点。
/// <paramref name="reference"/>:示教图上的基准位姿;
/// <paramref name="measured"/>:运行图匹配位姿。
/// </summary>
public static Point2D TransformPoint(Point2D point, Pose2D reference, Pose2D measured)
{
double dTheta = DegreesToRadians(measured.AngleDegrees - reference.AngleDegrees);
double cos = Math.Cos(dTheta);
double sin = Math.Sin(dTheta);
double dx = point.X - reference.X;
double dy = point.Y - reference.Y;
return new Point2D(
measured.X + cos * dx - sin * dy,
measured.Y + sin * dx + cos * dy);
}
public static Point2D TransformPoint(double x, double y, Pose2D reference, Pose2D measured)
=> TransformPoint(new Point2D(x, y), reference, measured);
/// <summary>变换多边形顶点(顺序不变)。</summary>
public static Point2D[] TransformPolygon(IReadOnlyList<Point2D> templatePoints, Pose2D reference, Pose2D measured)
{
if (templatePoints == null || templatePoints.Count == 0)
return Array.Empty<Point2D>();
var result = new Point2D[templatePoints.Count];
for (int i = 0; i < templatePoints.Count; i++)
result[i] = TransformPoint(templatePoints[i], reference, measured);
return result;
}
/// <summary>变换后四舍五入为整型顶点,供 BGA 等算子 PolyX/PolyY 注入。</summary>
public static (int X, int Y)[] TransformPolygonToInt(
IReadOnlyList<Point2D> templatePoints,
Pose2D reference,
Pose2D measured)
{
var transformed = TransformPolygon(templatePoints, reference, measured);
var result = new (int X, int Y)[transformed.Length];
for (int i = 0; i < transformed.Length; i++)
{
result[i] = (
(int)Math.Round(transformed[i].X, MidpointRounding.AwayFromZero),
(int)Math.Round(transformed[i].Y, MidpointRounding.AwayFromZero));
}
return result;
}
/// <summary>变换轴对齐矩形为四个顶点(左上、右上、右下、左下)。</summary>
public static Point2D[] TransformRect(double x, double y, double width, double height, Pose2D reference, Pose2D measured)
{
var corners = new[]
{
new Point2D(x, y),
new Point2D(x + width, y),
new Point2D(x + width, y + height),
new Point2D(x, y + height)
};
return TransformPolygon(corners, reference, measured);
}
/// <summary>
/// 校验匹配结果四角质心是否与 Center 一致(用于确认库的中心/角度约定)。
/// </summary>
public static bool IsMatchCenterConsistentWithCorners(
double centerX,
double centerY,
double ltX,
double ltY,
double rtX,
double rtY,
double rbX,
double rbY,
double lbX,
double lbY,
double tolerancePixels = 1.0)
{
double cx = (ltX + rtX + rbX + lbX) * 0.25;
double cy = (ltY + rtY + rbY + lbY) * 0.25;
double dx = cx - centerX;
double dy = cy - centerY;
return dx * dx + dy * dy <= tolerancePixels * tolerancePixels;
}
private static double DegreesToRadians(double degrees) => degrees * (Math.PI / 180.0);
}