LightGlueResult.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. using UnityEngine;
  2. namespace LightGlue.Unity.Networking
  3. {
  4. /// <summary>
  5. /// LightGlue算法结果数据类
  6. /// 包含相机位置、匹配质量等信息
  7. /// </summary>
  8. public struct LightGlueResult
  9. {
  10. /// <summary>
  11. /// 坐标映射目标类型:
  12. /// - GameScreen:用于 Camera.ScreenPointToRay 等“屏幕坐标”场景(左下角原点)
  13. /// - UIAnchored:用于 RectTransform.anchoredPosition 等 UI 场景(通常也是左下角原点,但可能需要 offset)
  14. /// </summary>
  15. public enum MappedCoordinateType
  16. {
  17. GameScreen = 0,
  18. UIAnchored = 1,
  19. }
  20. /// <summary>
  21. /// 结果是否有效(单应性矩阵计算成功且匹配点数量足够)
  22. /// </summary>
  23. public bool IsValid { get; }
  24. /// <summary>
  25. /// 匹配点数量(参考帧与当前帧之间的匹配关键点数量)
  26. /// </summary>
  27. public ushort NumMatches { get; }
  28. /// <summary>
  29. /// 内点比例(单应性矩阵计算中的内点比例,范围 0.0-1.0)
  30. /// </summary>
  31. public float InliersRatio { get; }
  32. /// <summary>
  33. /// 相机位置(在参考图像坐标系中的像素坐标,原点在左上角)
  34. /// </summary>
  35. public Vector2 CameraPosition { get; }
  36. /// <summary>
  37. /// 构造函数
  38. /// </summary>
  39. public LightGlueResult(bool isValid, ushort numMatches, float inliersRatio, float cameraX, float cameraY)
  40. {
  41. IsValid = isValid;
  42. NumMatches = numMatches;
  43. InliersRatio = inliersRatio;
  44. CameraPosition = new Vector2(cameraX, cameraY);
  45. }
  46. /// <summary>
  47. /// 创建无效结果(当算法计算失败时使用)
  48. /// </summary>
  49. public static LightGlueResult CreateInvalid(ushort numMatches = 0)
  50. {
  51. return new LightGlueResult(false, numMatches, 0.0f, 0.0f, 0.0f);
  52. }
  53. /// <summary>
  54. /// 将参考图像坐标(原点左上,Y向下)映射到目标坐标(原点左下,Y向上)。
  55. /// 用于统一 UI / Camera 的坐标转换逻辑,避免重复实现。
  56. /// </summary>
  57. /// <param name="referenceWidth">参考图宽(必须与 Python --resize 一致)</param>
  58. /// <param name="referenceHeight">参考图高(必须与 Python --resize 一致)</param>
  59. /// <param name="targetWidth">目标宽(Screen.width 或 Canvas 宽)</param>
  60. /// <param name="targetHeight">目标高(Screen.height 或 Canvas 高)</param>
  61. /// <param name="type">目标使用场景(UI / Camera)。当前两者映射规则一致,差别主要体现在 offset 用途。</param>
  62. /// <param name="offset">额外偏移(用于 UI anchoredPosition 的中心偏移等)。</param>
  63. public Vector2 GetMappedPosition(
  64. int referenceWidth,
  65. int referenceHeight,
  66. float targetWidth,
  67. float targetHeight,
  68. MappedCoordinateType type = MappedCoordinateType.GameScreen,
  69. Vector2 offset = default)
  70. {
  71. if (referenceWidth <= 0 || referenceHeight <= 0) return offset;
  72. if (targetWidth <= 0f || targetHeight <= 0f) return offset;
  73. float scaleX = targetWidth / referenceWidth;
  74. float scaleY = targetHeight / referenceHeight;
  75. float x = CameraPosition.x * scaleX;
  76. float y = targetHeight - (CameraPosition.y * scaleY);
  77. // 当前映射规则在 UI / Camera 两类场景相同;UI 额外通过 offset 适配 anchoredPosition 的坐标原点偏移
  78. _ = type; // 保留参数,便于未来扩展不同映射策略
  79. return new Vector2(x + offset.x, y + offset.y);
  80. }
  81. public override string ToString()
  82. {
  83. if (IsValid)
  84. {
  85. return $"LightGlueResult(Valid, Matches={NumMatches}, Inliers={InliersRatio:P1}, Pos=({CameraPosition.x:F1}, {CameraPosition.y:F1}))";
  86. }
  87. else
  88. {
  89. return $"LightGlueResult(Invalid, Matches={NumMatches})";
  90. }
  91. }
  92. }
  93. }