Преглед на файлове

添加动态修改python resize

slambb преди 2 седмици
родител
ревизия
aef0242701

BIN
Assets/AddressableAssetsData/Windows/addressables_content_state.bin


Файловите разлики са ограничени, защото са твърде много
+ 461 - 292
Assets/LightGlue/Resources/LightGlueUI.prefab


+ 20 - 0
Assets/LightGlue/Scripts/Bridge/HardwareToPythonUdpBridge.cs

@@ -268,6 +268,13 @@ namespace LightGlue.Unity.Bridge
             {
                 LoadNetworkConfig();
             }
+
+            // 参考图 resize:与 Python --resize 一致
+            ReferenceImageResizeService.EnsureInitialized();
+            referenceCaptureWidth = ReferenceImageResizeService.Width;
+            referenceCaptureHeight = ReferenceImageResizeService.Height;
+            ReferenceImageResizeService.OnResizeChanged -= OnResizeChanged;
+            ReferenceImageResizeService.OnResizeChanged += OnResizeChanged;
             // Hardware -> Unity receiver(端口占用时捕获异常,避免崩溃)
             _receiver = new UDPJpegReceiver(hardwareBindIp, hardwarePort, hardwareTimeoutSeconds, maxQueuedFrames);
             try
@@ -358,6 +365,17 @@ namespace LightGlue.Unity.Bridge
             }
         }
 
+        private void OnDestroy()
+        {
+            ReferenceImageResizeService.OnResizeChanged -= OnResizeChanged;
+        }
+
+        private void OnResizeChanged(int w, int h)
+        {
+            referenceCaptureWidth = w;
+            referenceCaptureHeight = h;
+        }
+
         private void TryConnectStdin()
         {
             // Stdin模式:从Python进程控制器获取stdin写入流
@@ -408,6 +426,8 @@ namespace LightGlue.Unity.Bridge
             _udpSender = null;
 
             _pythonStartedByFirstFrame = false;
+
+            ReferenceImageResizeService.OnResizeChanged -= OnResizeChanged;
         }
 
         /// <summary>

+ 37 - 2
Assets/LightGlue/Scripts/Config/NetworkConfig.cs

@@ -1,5 +1,6 @@
 using System.Net;
 using System.Net.Sockets;
+using System.Text.RegularExpressions;
 using UnityEngine;
 using UnityEngine.Windows;
 
@@ -58,6 +59,13 @@ namespace LightGlue.Unity.Config
         [TextArea(3, 8)]
         public string pythonScriptArgs = "--input \"udp://0.0.0.0:{pythonPort}\" --result_ip {resultIp} --result_port {resultPort} --control_port 12349 --use_tensorrt";
 
+        [Header("参考图像尺寸(与 Python --resize 一致)")]
+        [Tooltip("参考图像宽度(像素)。用于 C# 坐标映射与 Python --resize 参数的占位符替换。")]
+        public int referenceResizeWidth = 320;
+
+        [Tooltip("参考图像高度(像素)。用于 C# 坐标映射与 Python --resize 参数的占位符替换。")]
+        public int referenceResizeHeight = 240;
+
         [Header("Python启动参数(Roma)")]
         [Tooltip("Roma 脚本启动参数(完整命令行参数,不包括脚本路径)。" +
             "可用占位符:" +
@@ -70,7 +78,7 @@ namespace LightGlue.Unity.Config
             "示例:--input udp://0.0.0.0:{pythonPort} --reference_image ... --model tiny ... --result_ip {resultIp} --result_port {resultPort} --control_port {controlPort}")]
         [TextArea(3, 8)]
         public string romaPythonScriptArgs =
-            "--input udp://0.0.0.0:{pythonPort} --reference_image assets/sacre_coeur_A.jpg --model tiny --resize 320 240 " +
+            "--input udp://0.0.0.0:{pythonPort} --reference_image assets/sacre_coeur_A.jpg --model tiny --resize {resizeW} {resizeH} " +
             "--sample_num 500 --sample_thresh 0.05 --ransac_reproj_threshold 4.0 --min_matches 120 --min_inlier_ratio 0.08 " +
             "--roma_interval 10 --smooth_alpha 0.9 --trail_len 150 --show_fps --max_fps 90 --max_display_fps 60 --idle_sleep_ms 2 --timer_print_interval 0.5 " +
             "--result_ip {resultIp} --result_port {resultPort} --control_port {controlPort} --log_send_result";
@@ -87,7 +95,7 @@ namespace LightGlue.Unity.Config
         [TextArea(3, 8)]
         public string romaWifiPythonScriptArgs =
             "--input udp://0.0.0.0:{wifiPort} " +
-            "--reference_image assets/sacre_coeur_A.jpg --model tiny --resize 320 240 " +
+            "--reference_image assets/sacre_coeur_A.jpg --model tiny --resize {resizeW} {resizeH} " +
             "--sample_num 500 --sample_thresh 0.05 --ransac_reproj_threshold 4.0 --min_matches 120 --min_inlier_ratio 0.08 " +
             "--roma_interval 10 --smooth_alpha 0.9 --trail_len 150 " +
             "--forward_ip {resultIp} --forward_port {forwardPort} --forward_fps 30 " +
@@ -245,6 +253,9 @@ namespace LightGlue.Unity.Config
             args = args.Replace("{resultIp}", pythonResultBindIp);
             args = args.Replace("{resultPort}", pythonResultPort.ToString());
             args = args.Replace("{controlPort}", romaControlPort.ToString());
+            args = args.Replace("{resizeW}", referenceResizeWidth.ToString());
+            args = args.Replace("{resizeH}", referenceResizeHeight.ToString());
+            args = InjectResizeIfHardcoded(args, referenceResizeWidth, referenceResizeHeight);
             return args;
         }
 
@@ -263,9 +274,33 @@ namespace LightGlue.Unity.Config
             args = args.Replace("{resultIp}", pythonResultBindIp);
             args = args.Replace("{resultPort}", pythonResultPort.ToString());
             args = args.Replace("{controlPort}", romaControlPort.ToString());
+            args = args.Replace("{resizeW}", referenceResizeWidth.ToString());
+            args = args.Replace("{resizeH}", referenceResizeHeight.ToString());
+            args = InjectResizeIfHardcoded(args, referenceResizeWidth, referenceResizeHeight);
             return args;
         }
 
+        private static string InjectResizeIfHardcoded(string args, int w, int h)
+        {
+            if (string.IsNullOrWhiteSpace(args)) return args;
+            if (w <= 0 || h <= 0) return args;
+
+            // 兼容历史配置:JSON 里可能还是 "--resize 640 480" 这种硬编码模板
+            // 这里统一强制注入最新值,避免 UI 下拉框改了但启动参数不变。
+            try
+            {
+                return Regex.Replace(
+                    args,
+                    @"--resize\s+\d+\s+\d+",
+                    $"--resize {w} {h}",
+                    RegexOptions.CultureInvariant);
+            }
+            catch
+            {
+                return args;
+            }
+        }
+
         /// <summary>
         /// 获取本机用于绑定的 IPv4 地址(非回环、首选网卡)。
         /// 可供外部或 UI 调用,用于填充 hardwareBindIp。

+ 110 - 0
Assets/LightGlue/Scripts/Config/ReferenceImageResizeService.cs

@@ -0,0 +1,110 @@
+using System;
+using UnityEngine;
+
+namespace LightGlue.Unity.Config
+{
+    /// <summary>
+    /// 统一管理「参考图像 resize(w,h)」的唯一来源:
+    /// - C# 映射:referenceImageWidth/referenceImageHeight
+    /// - Unity GameView 截图:referenceCaptureWidth/referenceCaptureHeight
+    /// - Python 启动参数:--resize {w} {h}(由 NetworkConfig 占位符替换)
+    /// </summary>
+    public static class ReferenceImageResizeService
+    {
+        private const int MinSize = 1;
+        private const int MaxSize = 8192;
+
+        private static bool _initialized;
+        private static int _width = 320;
+        private static int _height = 240;
+
+        public static int Width
+        {
+            get { EnsureInitialized(); return _width; }
+        }
+
+        public static int Height
+        {
+            get { EnsureInitialized(); return _height; }
+        }
+
+        public static event Action<int, int> OnResizeChanged;
+
+        /// <summary>
+        /// 确保从 NetworkConfig 初始化一次。
+        /// </summary>
+        public static void EnsureInitialized()
+        {
+            if (_initialized) return;
+            _initialized = true;
+
+            try
+            {
+                var cfg = NetworkConfigManager.GetCachedConfig();
+                if (cfg != null)
+                {
+                    int w = cfg.referenceResizeWidth;
+                    int h = cfg.referenceResizeHeight;
+                    if (IsValid(w, h))
+                    {
+                        _width = w;
+                        _height = h;
+                    }
+                }
+            }
+            catch
+            {
+                // ignore:保持默认 320x240
+            }
+        }
+
+        /// <summary>
+        /// 设置 resize;可选写入 NetworkConfig 并持久化到 JSON。
+        /// </summary>
+        public static void Set(int width, int height, bool persistToNetworkConfig = true)
+        {
+            EnsureInitialized();
+
+            width = Mathf.Clamp(width, MinSize, MaxSize);
+            height = Mathf.Clamp(height, MinSize, MaxSize);
+
+            if (_width == width && _height == height) return;
+
+            _width = width;
+            _height = height;
+
+            if (persistToNetworkConfig)
+            {
+                try
+                {
+                    var cfg = NetworkConfigManager.LoadConfig();
+                    if (cfg != null)
+                    {
+                        cfg.referenceResizeWidth = _width;
+                        cfg.referenceResizeHeight = _height;
+                        NetworkConfigManager.SaveConfig(cfg);
+                    }
+                }
+                catch (Exception ex)
+                {
+                    Debug.LogWarning($"[Resize] 保存到 NetworkConfig 失败:{ex.Message}");
+                }
+            }
+
+            try
+            {
+                OnResizeChanged?.Invoke(_width, _height);
+            }
+            catch (Exception ex)
+            {
+                Debug.LogWarning($"[Resize] OnResizeChanged 回调异常:{ex.Message}");
+            }
+        }
+
+        public static bool IsValid(int width, int height)
+        {
+            return width >= MinSize && height >= MinSize && width <= MaxSize && height <= MaxSize;
+        }
+    }
+}
+

+ 11 - 0
Assets/LightGlue/Scripts/Config/ReferenceImageResizeService.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 2dc3df6d7e5902e459d0886f414bb2b3
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 13 - 0
Assets/LightGlue/Scripts/Roma/Bridge/RomaHardwareToPythonBridge.cs

@@ -109,6 +109,11 @@ namespace LightGlue.Unity.Roma.Bridge
             Application.runInBackground = true;
             _lastReferenceRefreshTime = Time.unscaledTime;
 
+            ReferenceImageResizeService.EnsureInitialized();
+            referenceCaptureWidth = ReferenceImageResizeService.Width;
+            referenceCaptureHeight = ReferenceImageResizeService.Height;
+            ReferenceImageResizeService.OnResizeChanged += OnResizeChanged;
+
             if (autoLoadNetworkConfig)
                 LoadNetworkConfig();
 
@@ -131,6 +136,14 @@ namespace LightGlue.Unity.Roma.Bridge
             _unityRefSender = null;
             try { _esp32ControlClient?.Close(); } catch { /* ignore */ }
             _esp32ControlClient = null;
+
+            ReferenceImageResizeService.OnResizeChanged -= OnResizeChanged;
+        }
+
+        private void OnResizeChanged(int w, int h)
+        {
+            referenceCaptureWidth = w;
+            referenceCaptureHeight = h;
         }
 
         private void LoadNetworkConfig()

+ 14 - 0
Assets/LightGlue/Scripts/UI/CameraPositionCrosshair.cs

@@ -2,6 +2,7 @@ using UnityEngine;
 using UnityEngine.UI;
 using LightGlue.Unity.Game;
 using LightGlue.Unity.Networking;
+using LightGlue.Unity.Config;
 
 namespace LightGlue.Unity.UI
 {
@@ -23,6 +24,18 @@ namespace LightGlue.Unity.UI
         [Tooltip("参考图像的高度(像素),用于坐标映射")]
         public int referenceImageHeight = 480;
 
+        private void OnEnable()
+        {
+            ReferenceImageResizeService.EnsureInitialized();
+            SetReferenceImageSize(ReferenceImageResizeService.Width, ReferenceImageResizeService.Height);
+            ReferenceImageResizeService.OnResizeChanged += SetReferenceImageSize;
+        }
+
+        private void OnDisable()
+        {
+            ReferenceImageResizeService.OnResizeChanged -= SetReferenceImageSize;
+        }
+
         [Header("准心渲染方式")]
         [Tooltip("渲染模式:ScreenSpace(屏幕空间)或 Canvas(Canvas空间)")]
         public RenderMode renderMode = RenderMode.Canvas;
@@ -389,6 +402,7 @@ namespace LightGlue.Unity.UI
 
         private void OnDestroy()
         {
+            ReferenceImageResizeService.OnResizeChanged -= SetReferenceImageSize;
             if (manager != null)
             {
                 manager.OnResultUpdated -= OnResultUpdated;

+ 6 - 0
Assets/LightGlue/Scripts/UI/LightGlueCameraAimController.cs

@@ -3,6 +3,7 @@ using LightGlue.Unity.Game;
 using LightGlue.Unity.Networking;
 using LightGlue.Unity.Roma;
 using LightGlue.Unity.Runtime;
+using LightGlue.Unity.Config;
 
 namespace LightGlue.Unity.UI
 {
@@ -54,6 +55,10 @@ namespace LightGlue.Unity.UI
 
         private void OnEnable()
         {
+            ReferenceImageResizeService.EnsureInitialized();
+            SetReferenceImageSize(ReferenceImageResizeService.Width, ReferenceImageResizeService.Height);
+            ReferenceImageResizeService.OnResizeChanged += SetReferenceImageSize;
+
             if (!useOnPositionUpdate) return;
             LightGlueRuntimeFacade.Ensure();
             LightGlueRuntimeFacade.OnPositionUpdate += HandlePositionUpdate;
@@ -61,6 +66,7 @@ namespace LightGlue.Unity.UI
 
         private void OnDisable()
         {
+            ReferenceImageResizeService.OnResizeChanged -= SetReferenceImageSize;
             if (!useOnPositionUpdate) return;
             LightGlueRuntimeFacade.OnPositionUpdate -= HandlePositionUpdate;
         }

+ 142 - 0
Assets/LightGlue/Scripts/UI/LightGlueUIManager.cs

@@ -1,5 +1,7 @@
 using LightGlue.Unity.Game;
+using LightGlue.Unity.Config;
 using System.Collections.Generic;
+using TMPro;
 using UnityEngine;
 using UnityEngine.SceneManagement;
 using UnityEngine.UI;
@@ -110,6 +112,17 @@ namespace LightGlue.Unity.UI
 
         private GameObject _cursorSettingsInstance;
 
+        [Header("Reference Resize (统一与 Python --resize 一致)")]
+        [Tooltip("参考图像 resize 下拉框。若不绑定,将在运行时尝试克隆一个现有 TMP_Dropdown 作为样式,并生成到 UIRoot 下。")]
+        [SerializeField]
+        private TMP_Dropdown resizeDropdown;
+
+        [Tooltip("resize 预设列表(格式:\"320x240\")。")]
+        [SerializeField]
+        private List<string> resizePresets = new List<string> { "320x240", "640x480" };
+
+        private bool _resizeDropdownInitialized;
+
         #region 生成RomaUI管理插件部分
         public static void Create(UIType uiType = UIType.Plugin, GameObject parentObj = null)
         {
@@ -257,6 +270,135 @@ namespace LightGlue.Unity.UI
 
             ApplyUITypeVisibility();
             ApplySceneVisibilityNodes(SceneManager.GetActiveScene().name);
+
+            EnsureResizeDropdown();
+        }
+
+        private void EnsureResizeDropdown()
+        {
+            if (_resizeDropdownInitialized) return;
+            _resizeDropdownInitialized = true;
+
+            ReferenceImageResizeService.EnsureInitialized();
+
+            if (resizeDropdown == null)
+            {
+                resizeDropdown = TryCloneAnyTmpDropdown();
+            }
+
+            if (resizeDropdown == null)
+            {
+                Debug.LogWarning("[LightGlueUI] 未找到/未生成 resizeDropdown(TMP_Dropdown)。请在 LightGlueUIManager Inspector 绑定一个 TMP_Dropdown,或确保 UI 中存在可克隆的 TMP_Dropdown。");
+                return;
+            }
+
+            var options = new List<TMP_Dropdown.OptionData>();
+            for (int i = 0; i < resizePresets.Count; i++)
+            {
+                string s = resizePresets[i];
+                if (string.IsNullOrWhiteSpace(s)) continue;
+                options.Add(new TMP_Dropdown.OptionData(s.Trim()));
+            }
+            if (options.Count == 0)
+            {
+                options.Add(new TMP_Dropdown.OptionData("320x240"));
+            }
+
+            resizeDropdown.onValueChanged.RemoveListener(OnResizeDropdownChanged);
+            resizeDropdown.ClearOptions();
+            resizeDropdown.AddOptions(options);
+
+            int currentIndex = FindPresetIndex(ReferenceImageResizeService.Width, ReferenceImageResizeService.Height, resizePresets);
+            if (currentIndex < 0) currentIndex = 0;
+            resizeDropdown.SetValueWithoutNotify(currentIndex);
+            resizeDropdown.onValueChanged.AddListener(OnResizeDropdownChanged);
+        }
+
+        private TMP_Dropdown TryCloneAnyTmpDropdown()
+        {
+            if (uiRoot == null) uiRoot = gameObject;
+            Transform parent = uiRoot.transform;
+
+            TMP_Dropdown sample = null;
+            var dropdowns = uiRoot.GetComponentsInChildren<TMP_Dropdown>(true);
+            if (dropdowns != null && dropdowns.Length > 0)
+            {
+                // 优先找名字含 "resolution" 的下拉框(现有UI里通常有)
+                for (int i = 0; i < dropdowns.Length; i++)
+                {
+                    var d = dropdowns[i];
+                    if (d != null && d.name.ToLowerInvariant().Contains("resolution"))
+                    {
+                        sample = d;
+                        break;
+                    }
+                }
+                if (sample == null)
+                    sample = dropdowns[0];
+            }
+
+            if (sample == null) return null;
+
+            var inst = Instantiate(sample.gameObject, sample.transform.parent != null ? sample.transform.parent : parent);
+            inst.name = "ResizeDropdown";
+
+            // 尽量让它在 sample 旁边,避免遮挡
+            var rt = inst.GetComponent<RectTransform>();
+            var sampleRt = sample.GetComponent<RectTransform>();
+            if (rt != null && sampleRt != null)
+            {
+                rt.anchorMin = sampleRt.anchorMin;
+                rt.anchorMax = sampleRt.anchorMax;
+                rt.pivot = sampleRt.pivot;
+                rt.sizeDelta = sampleRt.sizeDelta;
+                rt.anchoredPosition = sampleRt.anchoredPosition + new Vector2(0, - (sampleRt.sizeDelta.y + 10f));
+                rt.localScale = sampleRt.localScale;
+            }
+
+            var dd = inst.GetComponent<TMP_Dropdown>();
+            if (dd == null) return null;
+
+            // 尝试改一下 label,方便辨识(不保证所有模板都有 captionText)
+            if (dd.captionText != null)
+                dd.captionText.text = "Resize";
+
+            return dd;
+        }
+
+        private static int FindPresetIndex(int w, int h, List<string> presets)
+        {
+            if (presets == null) return -1;
+            string target = $"{w}x{h}";
+            for (int i = 0; i < presets.Count; i++)
+            {
+                string s = presets[i];
+                if (string.IsNullOrWhiteSpace(s)) continue;
+                if (NormalizePreset(s) == target) return i;
+            }
+            return -1;
+        }
+
+        private static string NormalizePreset(string s)
+        {
+            s = s.Trim().ToLowerInvariant().Replace(" ", "");
+            s = s.Replace("*", "x").Replace("×", "x");
+            return s;
+        }
+
+        private void OnResizeDropdownChanged(int index)
+        {
+            if (resizePresets == null || resizePresets.Count == 0) return;
+            if (index < 0 || index >= resizePresets.Count) return;
+            string preset = resizePresets[index];
+            if (string.IsNullOrWhiteSpace(preset)) return;
+
+            preset = NormalizePreset(preset);
+            var parts = preset.Split('x');
+            if (parts.Length != 2) return;
+            if (!int.TryParse(parts[0], out int w)) return;
+            if (!int.TryParse(parts[1], out int h)) return;
+
+            ReferenceImageResizeService.Set(w, h, persistToNetworkConfig: true);
         }
 
         private void OnDestroy()

+ 14 - 0
Assets/LightGlue/Scripts/UI/SimpleCameraPositionMarker.cs

@@ -3,6 +3,7 @@ using UnityEngine.UI;
 using LightGlue.Unity.Game;
 using LightGlue.Unity.Networking;
 using LightGlue.Unity.Roma;
+using LightGlue.Unity.Config;
 
 namespace LightGlue.Unity.UI
 {
@@ -74,6 +75,19 @@ namespace LightGlue.Unity.UI
             return LightGlueCursorSettings.Instance;
         }
 
+        private void OnEnable()
+        {
+            ReferenceImageResizeService.EnsureInitialized();
+            SetReferenceImageSize(ReferenceImageResizeService.Width, ReferenceImageResizeService.Height);
+            ReferenceImageResizeService.OnResizeChanged -= SetReferenceImageSize;
+            ReferenceImageResizeService.OnResizeChanged += SetReferenceImageSize;
+        }
+
+        private void OnDisable()
+        {
+            ReferenceImageResizeService.OnResizeChanged -= SetReferenceImageSize;
+        }
+
         private void Start()
         {
             if (cursorSettings == null)

+ 5 - 2
Assets/LightGlueCustom/Resources/LightGlueGameManager.prefab

@@ -44,5 +44,8 @@ MonoBehaviour:
   m_Script: {fileID: 11500000, guid: d0e9a7d006d478e4cac003a4712acaa8, type: 3}
   m_Name: 
   m_EditorClassIdentifier: 
-  referenceImageWidth: 320
-  referenceImageHeight: 240
+  referenceImageWidth: 640
+  referenceImageHeight: 480
+  cursorSettings: {fileID: 0}
+  offsetX: 0
+  offsetY: 0

+ 19 - 0
Assets/LightGlueCustom/Scripts/LightGlueGameManager.cs

@@ -1,5 +1,6 @@
 using LightGlue.Unity.Game;
 using LightGlue.Unity.Networking;
+using LightGlue.Unity.Config;
 using LightGlue.Unity.Runtime;
 using LightGlue.Unity.UI;
 using System;
@@ -20,6 +21,24 @@ namespace LightGlue.Unity.Custom
         [Tooltip("参考图像高度(像素)")]
         public int referenceImageHeight = 240;
 
+        private void OnEnable()
+        {
+            ReferenceImageResizeService.EnsureInitialized();
+            ApplyReferenceResize(ReferenceImageResizeService.Width, ReferenceImageResizeService.Height);
+            ReferenceImageResizeService.OnResizeChanged += ApplyReferenceResize;
+        }
+
+        private void OnDisable()
+        {
+            ReferenceImageResizeService.OnResizeChanged -= ApplyReferenceResize;
+        }
+
+        private void ApplyReferenceResize(int w, int h)
+        {
+            referenceImageWidth = w;
+            referenceImageHeight = h;
+        }
+
 
         [Header("平滑参数来源(唯一来源,无本地参数)")]
         [Tooltip("留空则使用 LightGlueCursorSettings.Instance;所有平滑参数均由此引用读取,UI 修改后即时生效")]

+ 1 - 1
ProjectSettings/ProjectSettings.asset

@@ -142,7 +142,7 @@ PlayerSettings:
     16:10: 1
     16:9: 1
     Others: 1
-  bundleVersion: 2.3.7
+  bundleVersion: 2.3.8
   preloadedAssets:
   - {fileID: 11400000, guid: 8ecb9c5da30ac7d4db9243c684f470ea, type: 2}
   metroInputSource: 0

Някои файлове не бяха показани, защото твърде много файлове са промени