using UnityEngine; namespace LightGlue.Unity.Networking { /// /// LightGlue算法结果数据类 /// 包含相机位置、匹配质量等信息 /// public struct LightGlueResult { /// /// 坐标映射目标类型: /// - GameScreen:用于 Camera.ScreenPointToRay 等“屏幕坐标”场景(左下角原点) /// - UIAnchored:用于 RectTransform.anchoredPosition 等 UI 场景(通常也是左下角原点,但可能需要 offset) /// public enum MappedCoordinateType { GameScreen = 0, UIAnchored = 1, } /// /// 结果是否有效(单应性矩阵计算成功且匹配点数量足够) /// public bool IsValid { get; } /// /// 匹配点数量(参考帧与当前帧之间的匹配关键点数量) /// public ushort NumMatches { get; } /// /// 内点比例(单应性矩阵计算中的内点比例,范围 0.0-1.0) /// public float InliersRatio { get; } /// /// 相机位置(在参考图像坐标系中的像素坐标,原点在左上角) /// public Vector2 CameraPosition { get; } /// /// 构造函数 /// public LightGlueResult(bool isValid, ushort numMatches, float inliersRatio, float cameraX, float cameraY) { IsValid = isValid; NumMatches = numMatches; InliersRatio = inliersRatio; CameraPosition = new Vector2(cameraX, cameraY); } /// /// 创建无效结果(当算法计算失败时使用) /// public static LightGlueResult CreateInvalid(ushort numMatches = 0) { return new LightGlueResult(false, numMatches, 0.0f, 0.0f, 0.0f); } /// /// 将参考图像坐标(原点左上,Y向下)映射到目标坐标(原点左下,Y向上)。 /// 用于统一 UI / Camera 的坐标转换逻辑,避免重复实现。 /// /// 参考图宽(必须与 Python --resize 一致) /// 参考图高(必须与 Python --resize 一致) /// 目标宽(Screen.width 或 Canvas 宽) /// 目标高(Screen.height 或 Canvas 高) /// 目标使用场景(UI / Camera)。当前两者映射规则一致,差别主要体现在 offset 用途。 /// 额外偏移(用于 UI anchoredPosition 的中心偏移等)。 public Vector2 GetMappedPosition( int referenceWidth, int referenceHeight, float targetWidth, float targetHeight, MappedCoordinateType type = MappedCoordinateType.GameScreen, Vector2 offset = default) { if (referenceWidth <= 0 || referenceHeight <= 0) return offset; if (targetWidth <= 0f || targetHeight <= 0f) return offset; float scaleX = targetWidth / referenceWidth; float scaleY = targetHeight / referenceHeight; float x = CameraPosition.x * scaleX; float y = targetHeight - (CameraPosition.y * scaleY); // 当前映射规则在 UI / Camera 两类场景相同;UI 额外通过 offset 适配 anchoredPosition 的坐标原点偏移 _ = type; // 保留参数,便于未来扩展不同映射策略 return new Vector2(x + offset.x, y + offset.y); } public override string ToString() { if (IsValid) { return $"LightGlueResult(Valid, Matches={NumMatches}, Inliers={InliersRatio:P1}, Pos=({CameraPosition.x:F1}, {CameraPosition.y:F1}))"; } else { return $"LightGlueResult(Invalid, Matches={NumMatches})"; } } } }