Просмотр исходного кода

增加屏幕坐标的映射模式,能根据分辨率转换

snowaterr 1 год назад
Родитель
Сommit
0941357bc4

+ 1 - 0
Assets/InfraredProject/InfraredCamera/Scripts/ScreenLocate.cs

@@ -4,6 +4,7 @@ using System.Collections.Generic;
 using System.Linq;
 using UnityEngine;
 using ZIM;
+using ZIM.Unity;
 
 /// <summary>
 /// JC-补充接口

+ 1 - 1
Assets/InfraredProject/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/InfraredSpot.cs

@@ -19,7 +19,7 @@ namespace ZIM
             {
                 if (ScreenLocation.HasValue)
                 {
-                    return screenMap.UVNormalize(ScreenLocation.Value);
+                    return screenMap.UVNormalized(ScreenLocation.Value);
                 }
                 else
                 {

+ 4 - 4
Assets/InfraredProject/WebCamera/Script/ZIM/InfraredLocate/ScreenIdentification.cs

@@ -74,7 +74,7 @@ namespace o0.Project
             if (ScreenLocate.Main.DebugScreenImage != null)     // 这段仅用于测试图片
             {
                 DebugImage(ScreenLocate.Main.DebugScreenImage);
-                Screen.QuadInCamera = new QuadrilateralInCamera(quadTemp[0], new Vector2(ScreenLocate.Main.DebugScreenImage.width, ScreenLocate.Main.DebugScreenImage.height));
+                Screen.QuadInCamera = new QuadrilateralInCamera(quadTemp[0], new Vector(ScreenLocate.Main.DebugScreenImage.width, ScreenLocate.Main.DebugScreenImage.height));
                 ScreenLocate.SetScreen(null);
                 ScreenLocate.Main.ShowScreen(Screen.QuadInCamera);
                 delay = 0;
@@ -257,7 +257,7 @@ namespace o0.Project
                 }
                 else if (quadTemp.Count == 1)
                 {
-                    Screen.QuadInCamera = new QuadrilateralInCamera(quadTemp[0], new Vector2(Size.x, Size.y));
+                    Screen.QuadInCamera = new QuadrilateralInCamera(quadTemp[0], new Vector(Size.x, Size.y));
                     //Debug.Log($"拟合四边形成功, quadTemp.Count: {quadTemp.Count}");
                 }
                 else
@@ -296,7 +296,7 @@ namespace o0.Project
                             predicts.Add(lr.Predict<Vector>(1));
                         }
                     }
-                    Screen.QuadInCamera = new QuadrilateralInCamera(predicts, new Vector2(Size.x, Size.y));
+                    Screen.QuadInCamera = new QuadrilateralInCamera(predicts, new Vector(Size.x, Size.y));
                     Debug.Log($"[ScreenIdentification拟合结果] RSquared: {rs}, Quad: {Screen.QuadInCamera}");
                     //if (rs < 0.8) Screen.Quad = null;
                 }
@@ -315,7 +315,7 @@ namespace o0.Project
                 if (delay == 0)
                 {
                     Size = new Geometry2D.Vector<int>(cam.width, cam.height);          // 记录当前的分辨率
-                    Debug.Log("[ScreenIdentification] 采样纹理,分辨率: [" + Size.x + ","+ Size.y+ "]");
+                    Debug.Log("[ScreenIdentification] 采样纹理,分辨率: [" + Size.x + "," + Size.y + "]");
                 }
                 return true;
             }

+ 34 - 20
Assets/InfraredProject/WebCamera/Script/ZIM/InfraredLocate/ScreenMap.cs

@@ -4,10 +4,20 @@ using UnityEngine;
 
 namespace ZIM.Unity
 {
+    // 摄像机的取景画面的纵横比设置(取景画面纵横比是否会根据分辨率变化)
+    public enum AspectRatioSetting
+    {
+        FixedAll,       // 高度和宽度都不变
+        FixedHeight,    // 高度固定
+        FixedWidth,     // 宽度固定
+    }
+
     // 记录屏幕的位置,QuadInCamera表示屏幕4个点在摄像机画面中的坐标
     // TransformToScreen可将摄像机空间的点映射到屏幕空间,反之用TransformToCamera
     public class ScreenMap
     {
+        public static AspectRatioSetting ViewAspectRatioSetting = AspectRatioSetting.FixedHeight;// 默认取景画面的高度保持不变,宽度随着分辨率变化
+
         public Rect QuadRect { get; private set; }
         public Vector2 UVSize { get; private set; }     // UV代表屏幕空间的坐标,UVSize代表屏幕坐标的取值范围
         public bool Active => quadInCamera != null;
@@ -19,39 +29,43 @@ namespace ZIM.Unity
             set
             {
                 quadInCamera = value;
-                if (value != null)
-                {
-                    var quad = value.Quad;
-                    var x = Math.Min((quad.A - quad.B).Length, (quad.C - quad.D).Length);
-                    var y = Math.Min((quad.A - quad.C).Length, (quad.B - quad.D).Length);
-                    UVSize = new Vector2(x, y);
-                    perspective = new ZIMPerspectiveTransform(quad, new OrdinalQuadrilateral(new Vector(0, 0), new Vector(x, 0), new Vector(0, y), new Vector(x, y)));
-
-                    var aabb = quad.AABBRect();
-                    QuadRect = new Rect(aabb.Item1.x, aabb.Item1.y, aabb.Item2.x - aabb.Item1.x, aabb.Item2.y - aabb.Item1.y);
-                    //Debug.Log(QuadRect);
-                }
+                InitByQuad();
+                //Debug.Log(QuadRect);
             }
         }
 
         // 刷新分辨率
         public Vector2 CurCameraSize
         {
-            get => QuadInCamera.CameraSize;
+            get => QuadInCamera.CameraSize.UnityVector();
             set
             {
-                if (QuadInCamera != null && QuadInCamera.CameraSize != value)
+                var newSize = value.o0Vector();
+                if (QuadInCamera != null && QuadInCamera.CameraSize != newSize)
                 {
                     UnityEngine.Debug.Log("[ScreenMap]根据分辨率映射: from " + QuadInCamera.CameraSize + " to " + value);
-                    var scale = new o0.Geometry2D.Float.Vector(value.x / QuadInCamera.CameraSize.x, value.y / QuadInCamera.CameraSize.y);
-                    var quad = QuadInCamera.Quad;
-                    quad.Scale(scale);
-                    QuadInCamera = new QuadrilateralInCamera(quad, value);
+                    QuadInCamera.ReSize(newSize, ViewAspectRatioSetting);
+                    InitByQuad();
                 }
             }
         }
 
-        ZIMPerspectiveTransform perspective;
+        private void InitByQuad()
+        {
+            if (quadInCamera != null)
+            {
+                var quad = QuadInCamera.Quad;
+                var x = Math.Min((quad.A - quad.B).Length, (quad.C - quad.D).Length);
+                var y = Math.Min((quad.A - quad.C).Length, (quad.B - quad.D).Length);
+                UVSize = new Vector2(x, y);
+                perspective = new ZIMPerspectiveTransform(quad, new OrdinalQuadrilateral(new Vector(0, 0), new Vector(x, 0), new Vector(0, y), new Vector(x, y)));
+
+                var aabb = quad.AABBRect();
+                QuadRect = new Rect(aabb.Item1.x, aabb.Item1.y, aabb.Item2.x - aabb.Item1.x, aabb.Item2.y - aabb.Item1.y);
+            }
+        }
+
+        private ZIMPerspectiveTransform perspective;
 
         public ScreenMap()
         {
@@ -69,7 +83,7 @@ namespace ZIM.Unity
         }
 
         // UV归一化到[0, 1]范围,仅用于输出最终结果
-        public Vector2 UVNormalize(Vector2 location)
+        public Vector2 UVNormalized(Vector2 location)
         {
             return new Vector2(location.x / UVSize.x, location.y / UVSize.y);
         }

+ 0 - 8
Assets/InfraredProject/WebCamera/Script/ZIM/Other/OrdinalQuadrilateral.cs

@@ -76,14 +76,6 @@ namespace ZIM
             return $"[{A}, {B}, {C}, {D}]";
         }
 
-        public void Scale(Vector scale)
-        {
-            A *= scale;
-            B *= scale;
-            C *= scale;
-            D *= scale;
-        }
-
         // AABB包围盒,返回矩形左下角和右上角的坐标
         public (Vector, Vector) AABBRect()
         {

+ 89 - 16
Assets/InfraredProject/WebCamera/Script/ZIM/Other/QuadrilateralInCamera.cs

@@ -4,39 +4,121 @@ using o0.Geometry2D;
 using o0.Geometry2D.Float;
 using UnityEngine;
 
-namespace ZIM
+namespace ZIM.Unity
 {
     // 屏幕识别使用,记录摄像机画面内的四边形
     public class QuadrilateralInCamera
     {
-        public Vector2 CameraSize;
+        public Vector CameraSize;
         public OrdinalQuadrilateral Quad;
 
-
+        // 固定的顶点顺序: 左下,右下,左上,右上
         public QuadrilateralInCamera(Vector2 a, Vector2 b, Vector2 c, Vector2 d, Vector2 cameraSize)
         {
-            CameraSize = cameraSize;
+            CameraSize = cameraSize.o0Vector();
             Quad = new OrdinalQuadrilateral(a.o0Vector(), b.o0Vector(), c.o0Vector(), d.o0Vector());
         }
 
+        // 固定的顶点顺序: 左下,右下,左上,右上
         public QuadrilateralInCamera(Vector a, Vector b, Vector c, Vector d, Vector cameraSize)
         {
-            CameraSize = cameraSize.UnityVector();
+            CameraSize = cameraSize;
             Quad = new OrdinalQuadrilateral(a, b, c, d);
         }
 
-        public QuadrilateralInCamera(IEnumerable<Vector> enumable, Vector2 cameraSize)
+        // 固定的顶点顺序: 左下,右下,左上,右上
+        public QuadrilateralInCamera(IEnumerable<Vector> enumable, Vector cameraSize)
         {
             CameraSize = cameraSize;
             Quad = new OrdinalQuadrilateral(enumable);
         }
 
-        public QuadrilateralInCamera(OrdinalQuadrilateral quad, Vector2 cameraSize)
+        public QuadrilateralInCamera(OrdinalQuadrilateral quad, Vector cameraSize)
         {
             CameraSize = cameraSize;
             Quad = quad;
         }
 
+        // 需要标准化的坐标(即数值范围0-1)时使用,会自动根据当前的CameraSize转换
+        private List<Vector> ScreenVertexListNormalized
+        {
+            get
+            {
+                return new List<Vector> {
+                    Quad.A / CameraSize,
+                    Quad.B / CameraSize,
+                    Quad.C / CameraSize,
+                    Quad.D / CameraSize
+                };
+            }
+            set
+            {
+                for (int i = 0; i < Quad.Count; i++)
+                    Quad[i] = value[i] * CameraSize;
+            }
+        }
+
+        // 这里是标准化坐标(即数值范围0-1)
+        public List<Vector2> GetUnityVertexList()
+        {
+            return new List<Vector2>() {
+                new Vector2(Quad.A.x / CameraSize.x, Quad.A.y / CameraSize.y),
+                new Vector2(Quad.B.x / CameraSize.x, Quad.B.y / CameraSize.y),
+                new Vector2(Quad.C.x / CameraSize.x, Quad.C.y / CameraSize.y),
+                new Vector2(Quad.D.x / CameraSize.x, Quad.D.y / CameraSize.y)
+            };
+        }
+
+        // 摄像机分辨率变化时调用
+        public void ReSize(Vector sizeNew, AspectRatioSetting viewAspectRatioSetting)
+        {
+            float ratio;
+            Func<Vector, Vector> Translate;
+            List<Vector> vertices;
+            switch (viewAspectRatioSetting)
+            {
+                case AspectRatioSetting.FixedAll:
+                    var scale = new Vector(sizeNew.x / CameraSize.x, sizeNew.y / CameraSize.y);
+                    CameraSize = sizeNew;
+                    for (int i = 0; i < Quad.Count; i++)
+                        Quad[i] *= scale;
+
+                    break;
+                case AspectRatioSetting.FixedHeight:
+                    var wOld = CameraSize.x / CameraSize.y;                // 宽度比高度
+                    var wNew = sizeNew.x / sizeNew.y;
+                    ratio = wOld / wNew;
+                    Translate = (v) =>
+                    {
+                        var x = v.x - 0.5f;
+                        return new Vector(x * ratio + 0.5f, v.y);
+                    };
+                    vertices = ScreenVertexListNormalized;
+                    for (int i = 0; i < vertices.Count; i++)
+                        vertices[i] = Translate(vertices[i]);
+                    CameraSize = sizeNew;                           // 这里要先设置Size
+                    ScreenVertexListNormalized = vertices;
+
+                    break;
+                case AspectRatioSetting.FixedWidth:
+                    var hOld = CameraSize.y / CameraSize.x;                // 高度比宽度
+                    var hNew = sizeNew.y / sizeNew.x;
+                    ratio = hOld / hNew;
+                    Translate = (v) =>
+                    {
+                        var y = v.y - 0.5f;
+                        return new Vector(v.x, y * ratio + 0.5f);
+                    };
+                    vertices = ScreenVertexListNormalized;
+                    for (int i = 0; i < vertices.Count; i++)
+                        vertices[i] = Translate(vertices[i]);
+                    CameraSize = sizeNew;
+                    ScreenVertexListNormalized = vertices;
+
+                    break;
+            }
+        }
+
         // 四边形是否完整的在屏幕内
         public bool IsQuadComplete()
         {
@@ -46,14 +128,5 @@ namespace ZIM
             return false;
         }
 
-        public List<Vector2> GetVertexList()
-        {
-            return new List<Vector2>() {
-                new Vector2(Quad[0].x / CameraSize.x, Quad[0].y / CameraSize.y),
-                new Vector2(Quad[1].x / CameraSize.x, Quad[1].y / CameraSize.y),
-                new Vector2(Quad[2].x / CameraSize.x, Quad[2].y / CameraSize.y),
-                new Vector2(Quad[3].x / CameraSize.x, Quad[3].y / CameraSize.y)
-            };
-        }
     }
 }

+ 3 - 2
Assets/InfraredProject/WebCamera/Script/ZIM/ScreenLocate.cs

@@ -9,6 +9,7 @@ using System.Linq;
 using UnityEngine;
 using UnityEngine.UI;
 using ZIM;
+using ZIM.Unity;
 using static Serenegiant.UVC.UVCManager;
 using Color = UnityEngine.Color;
 
@@ -715,14 +716,14 @@ public partial class ScreenLocate : MonoBehaviour
                 if (DebugOnEditorWin)
                 {
                     RectTransform t = ScreenQuad.GetChild(i) as RectTransform;
-                    t.anchoredPosition = screen.Quad[i].UnityVector().pixelToLocalPosition_AnchorCenter(screen.CameraSize, ScreenQuad.rect);
+                    t.anchoredPosition = screen.Quad[i].pixelToLocalPosition_AnchorCenter(screen.CameraSize, ScreenQuad.rect);
                 }
                 //mUVCCameraInfo.Size
                 //自动识别时候,记录四个点
                 //quadUnityVectorList.Add(quad[i].UnityVector());
             }
 
-            quadUnityVectorList = screen.GetVertexList();      // 记录四个点
+            quadUnityVectorList = screen.GetUnityVertexList();      // 记录四个点
 
             SaveScreenLocateVectorList();
             SyncInfraredDemo();

+ 7 - 0
Assets/InfraredProject/WebCamera/Script/ZIM/ZIMUnity/Extension.cs

@@ -83,6 +83,13 @@ namespace ZIM
             //var origin = rawImage.anchoredPosition;
             return new Vector2(dstRect.width * xp, dstRect.height * yp);
         }
+        public static Vector2 pixelToLocalPosition_AnchorCenter(this Vector pixel, Vector size, Rect dstRect)
+        {
+            var xp = pixel.x / size.x - 0.5f;
+            var yp = pixel.y / size.y - 0.5f;
+            //var origin = rawImage.anchoredPosition;
+            return new Vector2(dstRect.width * xp, dstRect.height * yp);
+        }
         // Unity局部坐标转回像素坐标
         public static Vector2 localPositionToPixel_AnchorCenter(this Vector2 localPosition, Vector2 size, Rect dstRect)
         {

+ 7 - 2
Assets/InfraredProject/WebCamera/Script/ZIM/ZIMUnity/ZIMWebCamera.cs

@@ -22,13 +22,18 @@ public class ZIMWebCamera : MonoBehaviour
 
     public Transform mParent;
 
-    IEnumerator Start()
+    private IEnumerator Start()
     {
         yield return new WaitForEndOfFrame();
         OnClick_Open();
     }
 
-    void Update()
+    private void Awake()
+    {
+
+    }
+
+    private void Update()
     {
         if (_webCamTexture)
         {