| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235 | 
							- #define ENABLE_LOG
 
- using o0.Geometry2D.Float;
 
- using o0.Num;
 
- using o0InfraredLocate;
 
- using o0InfraredLocate.ZIM;
 
- using System;
 
- using System.Collections.Generic;
 
- using System.IO;
 
- using System.Linq;
 
- using System.Threading.Tasks;
 
- using UnityEngine;
 
- using UnityEngine.UIElements;
 
- using UnityStandardAssets.Utility;
 
- using ZIM;
 
- using ZIM.Unity;
 
- namespace o0.Project
 
- {
 
-     public partial class ScreenIdentification
 
-     {
 
-         private const string TAG = "ScreenIdentification#";
 
-         // LocateAreaData表示每次屏幕的色差变化的区域,可能有多次。通过设置LocateSingleStep可调整为仅识别一次色差
 
-         static Rect[][] LocateAreaData = new Rect[][] {
 
-              new Rect[] { new Rect(0f, 0f, 0.3f, 0.3f),     new Rect(0f, 0f, 0.4f, 0.4f),     new Rect(0f, 0f, 0.5f, 0.5f)     },
 
-              new Rect[] { new Rect(0.7f, 0f, 0.3f, 0.3f),   new Rect(0.6f, 0f, 0.4f, 0.4f),   new Rect(0.5f, 0f, 0.5f, 0.5f)   },
 
-              new Rect[] { new Rect(0f, 0.7f, 0.3f, 0.3f),   new Rect(0f, 0.6f, 0.4f, 0.4f),   new Rect(0f, 0.5f, 0.5f, 0.5f)   },
 
-              new Rect[] { new Rect(0.7f, 0.7f, 0.3f, 0.3f), new Rect(0.6f, 0.6f, 0.4f, 0.4f), new Rect(0.5f, 0.5f, 0.5f, 0.5f) }
 
-         };
 
-         //static Rect[][] LocateAreaData = new Rect[][] {
 
-         //     new Rect[] { new Rect(0f, 0f, 0.3f, 0.3f),     new Rect(0f, 0f, 0.4f, 0.4f),     new Rect(0f, 0f, 0.5f, 0.5f),     new Rect(0f, 0f, 0.6f, 0.6f) },
 
-         //     new Rect[] { new Rect(0.7f, 0f, 0.3f, 0.3f),   new Rect(0.6f, 0f, 0.4f, 0.4f),   new Rect(0.5f, 0f, 0.5f, 0.5f),   new Rect(0.4f, 0f, 0.6f, 0.6f) },
 
-         //     new Rect[] { new Rect(0f, 0.7f, 0.3f, 0.3f),   new Rect(0f, 0.6f, 0.4f, 0.4f),   new Rect(0f, 0.5f, 0.5f, 0.5f),   new Rect(0f, 0.4f, 0.6f, 0.6f) },
 
-         //     new Rect[] { new Rect(0.7f, 0.7f, 0.3f, 0.3f), new Rect(0.6f, 0.6f, 0.4f, 0.4f), new Rect(0.5f, 0.5f, 0.5f, 0.5f), new Rect(0.4f, 0.4f, 0.6f, 0.6f) }
 
-         //};
 
-         //static bool LocateSingleStep = false;
 
-         static bool LocateSingleStep = true;
 
-         public Vector Size => ScreenLocate.Main.CameraSize;
 
-         public Geometry.Vector<int> o0Size => new Geometry.Vector<int>((int)Size.x, (int)Size.y);
 
-         public QuadrilateralInCamera QuadManual;
 
-         public QuadrilateralInCamera QuadAuto;      // 全自动,可以给用户选择(赋值给Screen.QuadInCamera即生效)
 
-         public QuadrilateralInCamera QuadSemiAuto;  // 半自动,可以给用户选择(赋值给Screen.QuadInCamera即生效)
 
-         public ScreenMap Screen;       // 识别到的屏幕,用于执行透视变换
 
-         int capture = 0;
 
-         int delay = 0;
 
-         int maxCapture;
 
-         int maxDelay;
 
-         Geometry.Vector<float>[] ScreenBlackTexture;
 
-         Geometry.Vector<float>[] ScreenWhiteTexture;
 
-         int locateIndex = -1;
 
-         readonly List<Rect> locateArea = new List<Rect> {
 
-             new Rect(0f, 0f, 0.5f, 0.5f), new Rect(0.5f, 0f, 0.5f, 0.5f), new Rect(0f, 0.5f, 0.5f, 0.5f), new Rect(0.5f, 0.5f, 0.5f, 0.5f)
 
-         };      // 屏幕显示白色的区域大小
 
-         float areaPercent => locateArea[locateIndex].size.x;         // 当前白色区域的占比
 
-         int areaSelected = -1;                                       // 选择哪个区域,顺序与Quadrilateral对应
 
-         readonly List<float> sumTemp = new List<float>();
 
-         readonly List<QuadrilateralInCamera> quadTemp = new List<QuadrilateralInCamera>();
 
-         //public ScreenIdentification(WebCamTexture texture)
 
-         //{
 
-         //    Size = new Geometry2D.Vector<int>(texture.width, texture.height);
 
-         //    Screen = new ScreenMap();
 
-         //}
 
-         public static UnityEngine.Color FloatValueToColor(float i)
 
-         {
 
-             return i switch
 
-             {
 
-                 1 => UnityEngine.Color.yellow,
 
-                 2 => new UnityEngine.Color(0,1,1,1),
 
-                 3 => UnityEngine.Color.green,
 
-                 4 => UnityEngine.Color.white,
 
-                 5 => UnityEngine.Color.red,
 
-                 _ => UnityEngine.Color.black,
 
-             };
 
-         }
 
-         public ScreenIdentification(o0InfraredCameraHandler cameraHandler)
 
-         {
 
-             Screen = new ScreenMap(cameraHandler);
 
-             //OnLocateScreenEnter += () => Application.targetFrameRate = 30;      // 固定识别的帧率,确保摄像机拍到正确的画面
 
-             //OnLocateScreenEnd += () => Application.targetFrameRate = 60;
 
-         }
 
-         public void SetScreenQuad(QuadrilateralInCamera quad) => Screen.QuadInCamera = quad;
 
-         // 上一次半自动识别的情况,false代表这条边识别失败,线段顺序: 下、右、上、左
 
-         public bool[] LastQuadSemiAutoState;
 
-         public event Action OnLocateScreenEnter;
 
-         public event Action OnLocateScreenEnd;
 
-         public bool bStartLocateScreen { get; set; } = false;//是否进行捕获
 
-         public bool SelectScreenAfterLocate(ScreenLocate.ScreenIdentificationTag tag)
 
-         {
 
-             QuadrilateralInCamera target = tag switch
 
-             {
 
-                 ScreenLocate.ScreenIdentificationTag.Manual => QuadManual,
 
-                 ScreenLocate.ScreenIdentificationTag.SemiAuto => QuadSemiAuto,
 
-                 ScreenLocate.ScreenIdentificationTag.Auto => QuadAuto,
 
-                 _ => null
 
-             };
 
-             if (target == null)
 
-                 return false;
 
-             Debug.Log($"<color=aqua>[ScreenIdentification] 选择已识别到的屏幕({Enum.GetName(typeof(ScreenLocate.ScreenIdentificationTag), tag)}), {target}</color>");
 
-             SetScreenQuad(target);
 
-             return true;
 
-         }
 
-         // 自动识别开始的入口
 
-         public void LocateScreen(int Capture = 30, int Delay = 30)  //数值单位是frame
 
-         {
 
-             if (ScreenLocate.Main.DebugScreenImages.Count != 0 && ScreenLocate.Main.DebugOnZIMDemo)     // 这段仅用于测试图片
 
-             {
 
-                 ScreenLocate.Main.SetCameraSize(new Vector(ScreenLocate.Main.DebugScreenImages[0].width, ScreenLocate.Main.DebugScreenImages[0].height));
 
-                 DebugImage(ScreenLocate.Main.DebugScreenImages);
 
-                 Screen.QuadInCamera = quadTemp[0];
 
-                 ScreenLocate.SetScreen(null);
 
-                 ScreenLocate.Main.ShowScreen(ScreenLocate.Main.ScreenQuad, Screen.QuadInCamera);
 
-                 delay = 0;
 
-                 capture = 0;
 
-                 ScreenWhiteTexture = null;
 
-                 ScreenBlackTexture = null;
 
-                 locateIndex = -1;
 
-                 areaSelected = -1;
 
-                 quadTemp.Clear();
 
-                 sumTemp.Clear();
 
-                 //ScreenLocate.Main.DebugScreenImages.Clear();
 
-                 return;
 
-             }
 
-             delay = Math.Max(Delay, 5);
 
-             capture = Math.Max(Capture, 5);
 
-             maxDelay = Delay;
 
-             maxCapture = Capture;
 
-             ScreenLocate.SetScreen(new Rect(0f, 0f, 1f, 1f), UnityEngine.Color.black);
 
-             //ScreenLocate.SetScreen(new Rect(0f, 0f, 0.6f, 0.6f), UnityEngine.Color.white);
 
-             //bStartLocateScreen = false;
 
-             ScreenWhiteTexture = null;
 
-             ScreenBlackTexture = null;
 
-             OnLocateScreenEnter?.Invoke();
 
-         }
 
-         /// <summary>
 
-         /// 开始进行捕获
 
-         /// 初始化了两个数据 capture 和 delay
 
-         /// </summary>
 
-         /// <returns></returns>
 
-         public bool isInitLocateScreen()
 
-         {
 
-             return capture != 0 && delay != 0;
 
-         }
 
-         void DebugImage(List<Texture2D> images)
 
-         {
 
-             QuadrilateralFit(images);
 
-             //var watch = new System.Diagnostics.Stopwatch();
 
-             //watch.Start();
 
-             //var times = new List<double>() { 0.0 };
 
- #if (!NDEBUG && DEBUG && ENABLE_LOG)
 
-             Console.WriteLine($"{TAG} quadTemp.Count:{quadTemp.Count}");
 
- #endif
 
-             if (quadTemp.Count > 0)
 
-             {
 
-                 ScreenLocate.Main.ShowScreen(ScreenLocate.Main.outputRawImages[4].transform.GetChild(0) as RectTransform, quadTemp[0]);
 
-                 // 透视变换
 
-                 //                var srcWidth = LocateLightedRedTex.width;
 
-                 //                var transformWidth = (int)((quad.B.x - quad.A.x + quad.D.x - quad.C.x) / 2);
 
-                 //                var transformHeight = (int)((quad.C.y - quad.A.y + quad.D.y - quad.B.y) / 2);
 
-                 //                var transformTex = new Texture2D(transformWidth, transformHeight);
 
-                 //                var pt = new ZIMPerspectiveTransform(new OrdinalQuadrilateral(new Vector(0, 0), new Vector(transformWidth, 0), new Vector(0, transformHeight), new Vector(transformWidth, transformHeight)), quad);
 
-                 //                var dstPixel = new UnityEngine.Color[transformWidth * transformHeight];
 
-                 //                var srcPixel = LocateLightedRedTex.GetPixels();
 
-                 //                Parallel.For(0, transformWidth, (x) =>
 
-                 //                {
 
-                 //                    for (int y = 0; y < transformHeight; y++)
 
-                 //                    {
 
-                 //                        var index = y * transformWidth + x;
 
-                 //                        var sampleCoord = pt.TransformRound(x, y);
 
-                 //                        dstPixel[index] = srcPixel[sampleCoord.y * srcWidth + sampleCoord.x];
 
-                 //                    }
 
-                 //                });
 
-                 //                transformTex.SetPixels(dstPixel);
 
-                 //                transformTex.Apply();
 
-                 //                //ScreenLocate.DebugTexture(1, transformTex);
 
-                 //#if (!NDEBUG && DEBUG && ENABLE_LOG)
 
-                 //                Console.WriteLine($"{TAG} ScreenLocate.DebugTexture 1:{transformTex.GetNativeTexturePtr()}");
 
-                 //#endif
 
-             }
 
-             //times.Add(watch.ElapsedMilliseconds);
 
-             //Debug.Log("time: " + (times[times.Count - 1] - times[times.Count - 2]));
 
-         }
 
-         public void NextScreen()
 
-         {
 
-             // 只识别一次色差变化
 
-             if (LocateSingleStep && areaSelected == -1)
 
-             {
 
-                 LocateAreaData = new Rect[][] { new Rect[] { new Rect(0, 0, 1f, 1f) } };
 
-                 locateIndex = 3;
 
-                 areaSelected = 0;
 
-                 locateArea.AddRange(LocateAreaData[0]);
 
-             }
 
-             // index从-1开始
 
-             locateIndex++;
 
-             if (locateIndex < locateArea.Count)     // 依次点亮屏幕区域
 
-             {
 
-                 ScreenLocate.SetScreen(locateArea[locateIndex], UnityEngine.Color.white);
 
-                 delay = maxDelay;
 
-                 capture = maxCapture;
 
-             }
 
-             else                // 退出屏幕黑白控制
 
-             {
 
-                 ScreenLocate.SetScreen(null);
 
-                 ScreenLocate.Main.ShowScreen(ScreenLocate.Main.ScreenQuad, Screen.QuadInCamera);
 
-                 Reset();
 
-             }
 
-         }
 
-         // 清除记录的屏幕识别数据(手动、自动等)
 
-         public void ClearQuadCache()
 
-         {
 
-             SetScreenQuad(null);
 
-             QuadManual = null;
 
-             QuadSemiAuto = null;
 
-             QuadAuto = null;
 
-         }
 
-         public void Reset()
 
-         {
 
-             // bStartLocateScreen = false;
 
-             delay = 0;
 
-             capture = 0;
 
-             ScreenWhiteTexture = null;
 
-             ScreenBlackTexture = null;
 
-             locateIndex = -1;
 
-             areaSelected = -1;
 
-             if (locateArea.Count > 4)
 
-                 locateArea.RemoveRange(4, LocateAreaData[0].Length);
 
-             quadTemp.Clear();
 
-             sumTemp.Clear();
 
-         }
 
-         public void CaptureBlack(Texture2D cam)
 
-         {
 
-             if (ScreenBlackTexture == null)
 
-                 ScreenBlackTexture = new Geometry.Vector<float>[(int)(Size.x * Size.y)];
 
-             var pixel = cam.GetPixels();
 
-             Parallel.For(0, (int)(Size.x * Size.y), i =>
 
-             {
 
-                 var ip = pixel[i];
 
-                 ScreenBlackTexture[i] += new Geometry.Vector<float>(ip.r / maxCapture, ip.g / maxCapture, ip.b / maxCapture);
 
-             });
 
-         }
 
-         public void CaptureWhite(Texture2D cam)
 
-         {
 
-             if (ScreenWhiteTexture == null)
 
-                 ScreenWhiteTexture = new Geometry.Vector<float>[(int)(Size.x * Size.y)];
 
-             var pixel = cam.GetPixels();
 
-             Parallel.For(0, (int)(Size.x * Size.y), i =>
 
-             {
 
-                 var ip = pixel[i];
 
-                 ScreenWhiteTexture[i] += new Geometry.Vector<float>(ip.r / maxCapture, ip.g / maxCapture, ip.b / maxCapture);
 
-             });
 
-         }
 
-         public void CaptureStay(Texture2D cam)
 
-         {
 
-             if (locateIndex == -1)                      // 屏幕黑色
 
-             {
 
-                 CaptureBlack(cam);
 
-             }
 
-             else                                        // 屏幕部分为白色
 
-             {
 
-                 CaptureWhite(cam);
 
-             }
 
-         }
 
-         public void CaptureEnd()
 
-         {
 
-             //Debug.Log("locateIndex: " + locateIndex + ", quad: " + quadTemp.Count);
 
-             if (locateIndex == -1)
 
-                 return;
 
-             if (locateIndex < 4)
 
-             {
 
-                 sumTemp.Add(GetBrightness());
 
-                 ScreenWhiteTexture = null;
 
-                 // 选择亮度差最大的区域
 
-                 if (locateIndex == 3)
 
-                 {
 
-                     areaSelected = sumTemp.MaxIndex();
 
-                     locateArea.AddRange(LocateAreaData[areaSelected]);
 
-                 }
 
-             }
 
-             else if (locateIndex >= 4 && locateIndex < locateArea.Count - 1)
 
-             {
 
-                 QuadrilateralFit();
 
-                 ScreenWhiteTexture = null;
 
-             }
 
-             else
 
-             {
 
-                 QuadrilateralFit();
 
-                 if (quadTemp.Count != LocateAreaData[0].Length)
 
-                 {
 
-                     Debug.Log($"<color=yellow>[ScreenIdentification] 拟合四边形失败, quadTemp.Count: {quadTemp.Count}</color>");
 
-                 }
 
-                 else if (quadTemp.Count == 1)
 
-                 {
 
-                     SetScreenQuad(quadTemp[0]);
 
-                     Debug.Log($"[ScreenIdentification] 拟合成功,识别数据: {Screen.QuadInCamera}");
 
-                 }
 
-                 else
 
-                 {
 
-                     // Debug.Log($"拟合四边形 2 , quadTemp.Count: {quadTemp.Count}");
 
-                     // 线性拟合
 
-                     var xValue = new List<float>() { 0 };
 
-                     var predicts = new List<Vector>();
 
-                     foreach (var i in LocateAreaData[0])
 
-                         xValue.Add(i.size.x);
 
-                     Vector baseVertex = Vector.Zero;            // x==0 时的点
 
-                     {
 
-                         foreach (var q in quadTemp)
 
-                         {
 
-                             baseVertex += q.Quad[areaSelected];
 
-                         }
 
-                         baseVertex /= quadTemp.Count;
 
-                     }
 
-                     double rs = 0.0;
 
-                     for (int i = 0; i < 4; i++)
 
-                     {
 
-                         if (i == areaSelected)
 
-                         {
 
-                             predicts.Add(baseVertex);
 
-                         }
 
-                         else
 
-                         {
 
-                             var yValue = new List<Vector>() { baseVertex };
 
-                             foreach (var q in quadTemp)
 
-                             {
 
-                                 yValue.Add(q.Quad[i]);
 
-                             }
 
-                             var lr = LinerRegression1D.Fit(2, xValue.ToArray(), yValue.ToArray());
 
-                             rs += lr.RSquared / 3;
 
-                             predicts.Add(lr.Predict<Vector>(1));
 
-                         }
 
-                     }
 
-                     SetScreenQuad(new QuadrilateralInCamera(predicts, new Vector(Size.x, Size.y)));
 
-                     Debug.Log($"[ScreenIdentification] 拟合成功,RSquared: {rs}, Quad: {Screen.QuadInCamera}");
 
-                     //if (rs < 0.8) Screen.Quad = null;
 
-                 }
 
-                 OnLocateScreenEnd?.Invoke();
 
-             }
 
-         }
 
-         public bool Update(Texture2D cam)
 
-         {
 
-             //if (!bStartLocateScreen) return false;
 
-             if (delay != 0)
 
-             {
 
-                 //ScreenLocate.Main.CreateUVCTexture2DFocusSizeIfNeeded(1280, 720);
 
-                 delay--;
 
-                 if (delay == 0)
 
-                 {
 
-                     ScreenLocate.Main.SetCameraSize(new Vector(cam.width, cam.height));          // 记录当前的分辨率
 
-                     Debug.Log("[ScreenIdentification] 采样纹理,记录采样分辨率: [" + Size.x + ", " + Size.y + "]");
 
-                 }
 
-                 return true;
 
-             }
 
-             if (capture != 0)
 
-             {
 
-                 //ScreenLocate.Main.CreateUVCTexture2DFocusSizeIfNeeded(1280, 720);
 
-                 CaptureStay(cam);
 
-                 capture--;
 
-                 if (capture == 0)
 
-                 {
 
-                     CaptureEnd();
 
-                     NextScreen();
 
-                 }
 
-                 return true;
 
-             }
 
-             return false;
 
-             #region Old
 
-             /*
 
-     if (delay != 0)
 
-     {
 
-         delay--;
 
-         return true;
 
-     }
 
-     if (capture != 0)
 
-     {
 
-         capture--;
 
-         if (ScreenBlackTexture == null)
 
-             ScreenBlackTexture = new Geometry.Vector<float>[Size.x * Size.y];
 
-         var pixel = cam.GetPixels();
 
-         Parallel.For(0, Size.x * Size.y, i =>
 
-         {
 
-             var ip = pixel[i];
 
-             ScreenBlackTexture[i] += new Geometry.Vector<float>(ip.r, ip.g, ip.b);
 
-         });
 
-         if (capture == 0)
 
-             ScreenLocate.SetScreen(UnityEngine.Color.black);
 
-         return true;
 
-     }
 
-     if (delay != 0)
 
-     {
 
-         delay--;
 
-         return true;
 
-     }
 
-     if (capture != 0)
 
-     {
 
-         capture--;
 
-         if (ScreenWhiteTexture == null)
 
-             ScreenWhiteTexture = new Geometry.Vector<float>[Size.x * Size.y];
 
-         var pixel = cam.GetPixels();
 
-         Parallel.For(0, Size.x * Size.y, i =>
 
-         {
 
-             var ip = pixel[i];
 
-             ScreenWhiteTexture[i] += new Geometry.Vector<float>(ip.r, ip.g, ip.b);
 
-         });
 
-         if (capture == 0)
 
-             ScreenLocate.SetScreen(UnityEngine.Color.black);
 
-         return true;
 
-     }
 
-     if (delay != 0)
 
-     {
 
-         delay--;
 
-         return true;
 
-     }
 
-     if (capture != 0)
 
-     {
 
-         capture--;
 
-         var pixel = cam.GetPixels();
 
-         Parallel.For(0, Size.x * Size.y, i =>
 
-         {
 
-             var ip = pixel[i];
 
-             ScreenWhiteTexture[i] -= new Geometry.Vector<float>(ip.r, ip.g, ip.b);
 
-         });
 
-         if (capture == 0)
 
-         {
 
-             ScreenLocate.SetScreen(null);
 
-             UnityEngine.Color[] newPixel = new UnityEngine.Color[Size.x * Size.y];
 
-             Parallel.For(0, Size.x * Size.y, i => {
 
-                 var pi = ScreenWhiteTexture[i] /= capture;
 
-                 newPixel[i] = new UnityEngine.Color(pi.x, pi.y, pi.z);
 
-             });
 
-             //读取数据
 
-             //{
 
-             //    var fileName = "3.bin";
 
-             //    ScreenLocateTexture = $"2023 04 16 厦门测试数据/{fileName}".FileReadByte<Vector<float>[]>();
 
-             //    Debug.Log($"Read {fileName}");
 
-             //    Parallel.For(0, Size.x * Size.y, i =>
 
-             //    {
 
-             //        var pi = ScreenLocateTexture[i];
 
-             //        newPixel[i] = new UnityEngine.Color(pi.x, pi.y, pi.z);
 
-             //    });
 
-             //}
 
-             var ScreenLocateTex = new Texture2D(Size.x, Size.y);
 
-             ScreenLocateTex.SetPixels(newPixel);
 
-             ScreenLocateTex.Apply();
 
-             //ScreenLocate.DebugTexture(2, ScreenLocateTex);
 
-             var ScreenLocateTexLighted = ScreenLocateTex.AutoLight(10);
 
-             //ScreenLocate.DebugTexture(2, ScreenLocateTexLighted);
 
-             //var FileSavePath = Application.persistentDataPath + "/ScreenLocateTexture.bin";
 
-             bool Save = ScreenLocate.Main.SaveToggle.isOn;
 
-             string time;
 
-             if (Save)
 
-             {
 
-                 time = DateTime.Now.ToString("yyyyMMdd_HHmmss");
 
-                 var FileSavePath = $"屏幕定位数据{time}.bin";
 
-                 FileSavePath.FileWriteByte(ScreenWhiteTexture);
 
-                 var bytes = ScreenLocateTexLighted.EncodeToPNG();
 
-                 File.WriteAllBytes($"屏幕定位数据{time}.png", bytes);
 
-                 Debug.Log("ScreenLocateTexture Saved To: " + FileSavePath);
 
-             }
 
-             var ScreenLocateTexR = ScreenLocateTexLighted.ToRGB(ColorChannel.Red);
 
-             var ScreenLocateTexG = ScreenLocateTexLighted.ToRGB(ColorChannel.Green);
 
-             var ScreenLocateTexB = ScreenLocateTexLighted.ToRGB(ColorChannel.Blue);
 
-             ScreenLocate.DebugTexture(2, ScreenLocateTexR);
 
-             //ScreenLocate.DebugTexture(4, ScreenLocateTexG);
 
-             //ScreenLocate.DebugTexture(5, ScreenLocateTexB);
 
-             var watch = new System.Diagnostics.Stopwatch();
 
-             watch.Start();
 
-             var times = new List<double>() { 0.0 };
 
-             var ScreenLocateTexLightedMat = ScreenLocateTexLighted.Too0Mat();
 
-             //var ScreenLocateTexLightedMat = texture.Too0Mat();
 
-             //var (edge, edgeDir) = ScreenLocateTexLightedMat.IdentifyEdge();
 
-             var (edge, edgeDir) = ScreenLocateTexLightedMat.zimIdentifyEdgeGradientAny(15);
 
-             //ScreenLocate.DebugTexture(4, ScreenLocateTexLighted.Too0Mat().IdentifyEdgeGradient().ToTex());
 
-             //ScreenLocate.DebugTexture(4, edge.ToTex());
 
-             var quadLines = ScreenLocateTexLightedMat.IdentifyQuadLSD(edge, edgeDir, out List<Line> lightLines, 30);
 
-             var drawLineMap = new MatrixF2D(edge..Size.x, edge.Size.y);
 
-             int lineCount = 0;
 
-             foreach (var l in quadLines)
 
-             {
 
-                 if (l != null)
 
-                 {
 
-                     o0Extension.DrawLine(drawLineMap.DrawLine(l, (x, y) => 1, new Vector(0, 10));
 
-                     lineCount++;
 
-                 }
 
-             }
 
-             if (lineCount == 4)
 
-             {
 
-                 var a = quadLines[0].Intersect(quadLines[3], false).Value;
 
-                 var b = quadLines[0].Intersect(quadLines[1], false).Value;
 
-                 var c = quadLines[2].Intersect(quadLines[3], false).Value;
 
-                 var d = quadLines[1].Intersect(quadLines[2], false).Value;
 
-                 Quad = new Quadrilateral(a, b, c, d);
 
-                 if (!Quad.IsInScreen(ScreenLocate.Main.WebCamera.Size))
 
-                     Quad = null;
 
-             }
 
-             ScreenLocate.Main.ShowScreen(Quad);
 
-             //var lines = edge.IdentifyLineLSD(edgeDir, 100);
 
-             ////var lines = ScreenLocateTexLightedMat.IdentifyLineLSD();
 
-             //var drawLineMap = new MatrixF2D(edge..Size.x, edge.Size.y);
 
-             //var returnMaxLines = lines.Sub(0, 10);
 
-             //foreach (var (line, sum, gradient) in returnMaxLines)
 
-             //    o0Extension.DrawLine(drawLineMap.DrawLine(line, (x, y) => 1, new Vector(0, 10));
 
-             ScreenLocate.DebugTexture(3, drawLineMap.ToTex());
 
-             //{
 
-             //    var bytes = drawLineMap.ToTex().EncodeToPNG();
 
-             //    File.WriteAllBytes($"屏幕定位数据DrawLineMap.png", bytes);
 
-             //}
 
-             times.Add(watch.ElapsedMilliseconds);
 
-             Debug.Log("time: " + (times[times.Count - 1] - times[times.Count - 2]));
 
-             //ScreenLocate.DebugTexture(5, edge.IdentifyLine(edgeDir).ToTex());
 
-             //ScreenLocate.DebugTexture(4, ScreenLocateTexLighted.Too0Mat().IdentifyEdgeGradientX().ToTex());
 
-             //ScreenLocate.DebugTexture(5, ScreenLocateTexLighted.Too0Mat().IdentifyEdgeGradientY().ToTex());
 
-             //var convolutionLighted2 = ScreenLocateTexLighted.Too0Mat().IdentifyEdgeVariance().ToTex();
 
-             // opecncv处理
 
-             // zim
 
-             {
 
-                 //var cvLines = edge.cvHoughLinesP();
 
-                 //ScreenLocate.DebugTexture(5, cvLines);
 
-                 //var myLines = Hough.Transform(edgeMat);
 
-                 //var cvLines = edge.cvLine(myLines);
 
-                 //ScreenLocate.DebugTexture(5, cvLines);
 
-             }
 
-             UnityEngine.Object.Destroy(ScreenLocateTex);
 
-             //ScreenLocate.DebugTexture(4, convolutionLighted2);
 
-         }
 
-         return true;
 
-     }
 
-     /*
 
-     var avg = new Geometry4D.Vector<float>();
 
-     var pixel = texture.GetPixels();
 
-     foreach(var i in pixel.Index())
 
-     {
 
-         var iP = pixel[i];
 
-         avg += new Geometry4D.Vector<float>(iP.r, iP.g, iP.b, iP.a);
 
-     }
 
-     avg /= pixel.Count();
 
-     /*
 
-     var (texLightedR, texLightedG, texLightedB) = ToRGB(newTex);
 
-     ScreenLocate.DebugTexture(3, texLightedR);
 
-     ScreenLocate.DebugTexture(4, texLightedG);
 
-     ScreenLocate.DebugTexture(5, texLightedB);
 
-     //Debug.Log(avg);
 
-     return false;
 
- /**/
 
-             #endregion
 
-         }
 
-         float GetBrightness()
 
-         {
 
-             UnityEngine.Color[] differPixel = new UnityEngine.Color[(int)(Size.x * Size.y)];
 
-             Parallel.For(0, (int)(Size.x * Size.y), i =>
 
-             {
 
-                 var pi = ScreenWhiteTexture[i] - ScreenBlackTexture[i];
 
-                 differPixel[i] = new UnityEngine.Color(pi.x, pi.y, pi.z);
 
-             });
 
-             var sum = 0f;
 
-             foreach (var i in differPixel)
 
-             {
 
-                 sum += i.Brightness();
 
-             }
 
-             sum /= differPixel.Length;
 
-             //Debug.Log(sum);
 
-             return sum;
 
-         }
 
-         // 转换成屏幕定位所需的纹理图像
 
-         Texture2D ToLocateTex(UnityEngine.Color[] pixels)
 
-         {
 
-             var ScreenLocateTex = new Texture2D(o0Size.x, o0Size.y);
 
-             ScreenLocateTex.SetPixels(pixels);
 
-             ScreenLocateTex.Apply();
 
-             //ScreenLocate.DebugTexture(2, ScreenLocateTex);
 
-             return ScreenLocateTex.AutoLight(10);
 
-             //ScreenLocate.DebugTexture(2, ScreenLocateTexLighted);
 
-             //var ScreenLocateTexR = ToLocateTex.ToRGB(ColorChannel.Red);
 
-             //var ScreenLocateTexG = ToLocateTex.ToRGB(ColorChannel.Green);
 
-             //var ScreenLocateTexB = ToLocateTex.ToRGB(ColorChannel.Blue);
 
-             //LocateLightedRedTex = ScreenLocateTexR;
 
-             //ScreenLocate.DebugTexture(2, ScreenLocateTexR);
 
-             //ScreenLocate.DebugTexture(4, ScreenLocateTexG);
 
-             //ScreenLocate.DebugTexture(5, ScreenLocateTexB);
 
-             //var ScreenLocateTexLightedMat = texture.Too0Mat();
 
-         }
 
-         /// <param name="lineWidth">识别的最小线段长度</param>
 
-         /// <param name="debugImages">这个参数如果不为null且数量大于0,则执行debug操作</param>
 
-         void QuadrilateralFit(List<Texture2D> debugImages = null)
 
-         {
 
-             // 屏幕黑白差值,存放多批次的图像用于识别, 该List数量不能等于 0 
 
-             List<UnityEngine.Color[]> PixelsMultipleBatches = new List<UnityEngine.Color[]>();
 
-             //var sw = new System.Diagnostics.Stopwatch();
 
-             //sw.Start();
 
-             //读取数据
 
-             int batchCount;
 
-             if (debugImages != null && debugImages.Count != 0)
 
-             {
 
-                 batchCount = debugImages.Count;
 
-                 var dSize = debugImages.First().Size();
 
-                 foreach (var i in debugImages)
 
-                 {
 
-                     Debug.Log($"<color=aqua>Debug {i.name}</color>");
 
-                     if (i.Size() != dSize)
 
-                         throw new InvalidOperationException("Multiple Debug textures have different sizes");
 
-                     //PixelsMultipleBatches.Add(i.GetPixels());
 
-                 }
 
-             }
 
-             else    // 获得屏幕差值
 
-             {
 
-                 var differPixel = new UnityEngine.Color[(int)(Size.x * Size.y)];
 
-                 var whitePixel = new UnityEngine.Color[(int)(Size.x * Size.y)];
 
-                 Parallel.For(0, (int)Size.x, x =>
 
-                 {
 
-                     for (int y = 0; y < (int)Size.y; y++)
 
-                     {
 
-                         var i = y * (int)Size.x + x;
 
-                         var d = ScreenWhiteTexture[i] - ScreenBlackTexture[i];
 
-                         differPixel[i] = new UnityEngine.Color(d.x, d.y, d.z);
 
-                         whitePixel[i] = new UnityEngine.Color(ScreenWhiteTexture[i].x, ScreenWhiteTexture[i].y, ScreenWhiteTexture[i].z);
 
-                     }
 
-                 });
 
-                 PixelsMultipleBatches.Add(differPixel);     // 色差图
 
-                 PixelsMultipleBatches.Add(whitePixel);      // 原图
 
-                 batchCount = PixelsMultipleBatches.Count;
 
-             }
 
-             int conSize = (int)Math.Ceiling(0.007f * Size.y) * 2 + 1;
 
-             conSize = Math.Max(conSize, 7);     // 设置最小为7
 
-             float minLength = conSize * 7.7f;
 
-             minLength = locateIndex == -1 ? minLength : minLength * areaPercent;    // minLength需要按areaPercent比例缩小
 
-             string log = $"[Log][ScreenLocate Auto] Size: ({Size.x},{Size.y}), 卷积核Size: {conSize}, 最小线段长度: {minLength}";
 
-             var allLines = new List<LineIdentified>();
 
-             List<Texture2D> LocateTexTemp = new List<Texture2D>();
 
-             List<Matrix> ScreenLocateMatList = new List<Matrix>();
 
-             for (int batch = 0; batch < batchCount; batch++)
 
-             {
 
-                 Texture2D locateTex;
 
-                 if (debugImages != null && debugImages.Count != 0)
 
-                     locateTex = debugImages[batch];
 
-                 else
 
-                     locateTex = ToLocateTex(PixelsMultipleBatches[batch]);
 
-                 LocateTexTemp.Add(locateTex);
 
-                 var ScreenLocateMat = locateTex.Too0Mat();        // 用于获取Lines的Matrix
 
-                 var lineCount = ZIMIdentifyQuadLSD(
 
-                     ref allLines,
 
-                     batch,
 
-                     ScreenLocateMat.zimIdentifyEdgeGradientAny(conSize),
 
-                     minLength,
 
-                     new Vector(minLength * 0.4f, conSize * 1.6f));
 
-                 log += $"\r\n识别图片{batch}, 识别到的线段数量为: {lineCount}";
 
-                 ScreenLocateMatList.Add(ScreenLocateMat);
 
-             }
 
-             Texture2D ScreenLocateTexture = LocateTexTemp[0];       // 色差图,for output
 
-             // LSD计算得到的矩阵尺寸较小(因为卷积),这里必须进行位移
 
-             // 新增:根据阈值筛去梯度太低的线段
 
-             float minGradient = 0.08f;
 
-             var offset = new Vector((conSize - 1) / 2, (conSize - 1) / 2);
 
-             var tempList = new List<LineIdentified>();
 
-             for (int i = 0; i < allLines.Count; i++)
 
-             {
 
-                 var l = allLines[i];
 
-                 if (l.Gradient > minGradient * l.Line.Length) 
 
-                 {
 
-                     l.Offset(offset);
 
-                     tempList.Add(l);
 
-                 }
 
-             }
 
-             allLines = tempList;
 
-             log += $"\r\n根据梯度阈值筛选,最终线段数量为: {allLines.Count}";
 
-             // 如果有手动数据,刷新一下Size
 
-             QuadManual?.ReSize(new Vector(Size.x, Size.y), ScreenMap.ViewAspectRatioSetting);
 
-             // 估算屏幕中点,如果已有手动定位数据,根据现有数据取平均即可,否则从色差计算,ScreenLocateMatList[0]默认是屏幕的黑白色差
 
-             Vector AvgPoint = QuadManual != null ? QuadManual.Quad.Centroid : GetAvgPoint(ScreenLocateMatList[0]);
 
-             // 过滤得到四边形的四条边,
 
-             var (quadLinesSemiAuto, quadLinesAuto) = FilterLines(
 
-                 ScreenLocateMatList, 
 
-                 allLines, 
 
-                 AvgPoint,
 
-                 out LineIdentified[] manualLines, 
 
-                 out List<LineIdentified> possibleLines,
 
-                 conSize, 
 
-                 minLength);
 
-             #region 全自动识别的结果
 
-             List<LineIdentified> LineIdentifiedAuto = new List<LineIdentified>();               // 线段顺序: 下、右、上、左
 
-             for (int i = 0; i < 4; i++)
 
-             {
 
-                 if (quadLinesAuto[i] != null)
 
-                     LineIdentifiedAuto.Add(quadLinesAuto[i]);
 
-             }
 
-             if (LineIdentifiedAuto.Count == 4)            // 判断识别的线段能否拼成屏幕,能拼成则记录
 
-             {
 
-                 var a = LineIdentifiedAuto[0].Line.Intersect(LineIdentifiedAuto[3].Line, false).Value;
 
-                 var b = LineIdentifiedAuto[0].Line.Intersect(LineIdentifiedAuto[1].Line, false).Value;
 
-                 var c = LineIdentifiedAuto[2].Line.Intersect(LineIdentifiedAuto[3].Line, false).Value;
 
-                 var d = LineIdentifiedAuto[1].Line.Intersect(LineIdentifiedAuto[2].Line, false).Value;
 
-                 QuadAuto = new QuadrilateralInCamera(a, b, c, d, new Vector(Size.x, Size.y));
 
-                 if (!QuadAuto.IsQuadComplete())
 
-                     QuadAuto = null;
 
-             }
 
-             #endregion
 
-             #region 半自动识别
 
-             List<LineIdentified> LineIdentifiedSemiAuto = new List<LineIdentified>();               // 线段顺序: 下、右、上、左
 
-             LastQuadSemiAutoState = new bool[4] { true, true, true, true };
 
-             for (int i = 0; i < 4; i++)
 
-             {
 
-                 if (quadLinesSemiAuto[i] != null)
 
-                     LineIdentifiedSemiAuto.Add(quadLinesSemiAuto[i]);
 
-                 else if (manualLines != null)
 
-                 {
 
-                     LineIdentifiedSemiAuto.Add(manualLines[i]);
 
-                     LastQuadSemiAutoState[i] = false;
 
-                 }
 
-             }
 
-             if (LineIdentifiedSemiAuto.Count == 4)            // 判断识别的线段能否拼成屏幕,能拼成则记录
 
-             {
 
-                 var a = LineIdentifiedSemiAuto[0].Line.Intersect(LineIdentifiedSemiAuto[3].Line, false).Value;
 
-                 var b = LineIdentifiedSemiAuto[0].Line.Intersect(LineIdentifiedSemiAuto[1].Line, false).Value;
 
-                 var c = LineIdentifiedSemiAuto[2].Line.Intersect(LineIdentifiedSemiAuto[3].Line, false).Value;
 
-                 var d = LineIdentifiedSemiAuto[1].Line.Intersect(LineIdentifiedSemiAuto[2].Line, false).Value;
 
-                 QuadSemiAuto = new QuadrilateralInCamera(a, b, c, d, new Vector(Size.x, Size.y));
 
-                 if (!QuadSemiAuto.IsQuadComplete())
 
-                     QuadSemiAuto = null;
 
-             }
 
-             #endregion
 
-             // 优先应用自动的结果(也可以在外部手动设置)
 
-             if (QuadSemiAuto == null && QuadAuto == null && Screen.QuadInCamera != null)     // 如果可能,回退到上一个screen
 
-             {
 
-                 Debug.Log($"<color=yellow>[ScreenIdentification] 本次识别失败,回退到上次的识别结果: {Screen.QuadInCamera}</color>");
 
-                 quadTemp.Add(Screen.QuadInCamera);
 
-             }
 
-             else if (QuadAuto != null)
 
-             {
 
-                 Debug.Log($"<color=aqua>[ScreenIdentification] 识别到四边形(全自动): {QuadAuto}</color>");
 
-                 quadTemp.Add(QuadAuto);
 
-             }
 
-             else if (QuadSemiAuto != null)
 
-             {
 
-                 Debug.Log($"<color=aqua>[ScreenIdentification] 识别到四边形(半自动): {QuadSemiAuto}</color>");
 
-                 quadTemp.Add(QuadSemiAuto);
 
-             }
 
-             #region 绘制 output texture
 
-             // 绘制半自动
 
-             var ScreenQuadMap = new Matrix(o0Size, Tiling: true);     // 识别的到的屏幕四边形(半自动和自动在一张图上) 
 
-             foreach (var i in LineIdentifiedSemiAuto.Index())
 
-             {
 
-                 if (LastQuadSemiAutoState[i])
 
-                     o0Extension.DrawLine(ScreenQuadMap, LineIdentifiedSemiAuto[i].DrawLine, (x, y) => 5, new Vector(0, 10));
 
-                 else
 
-                     o0Extension.DrawLine(ScreenQuadMap, LineIdentifiedSemiAuto[i].DrawLine, (x, y) => 3, new Vector(0, 6), true);
 
-             } 
 
-             // 绘制全自动
 
-             foreach (var i in LineIdentifiedAuto.Index())
 
-                 o0Extension.DrawLine(ScreenQuadMap, LineIdentifiedAuto[i].DrawLine, (x, y) => 4, new Vector(0, 4), true);
 
-             Texture2D ScreenQuad = ScreenQuadMap.ToTexRGBA(FloatValueToColor);
 
-             Texture2D ScreenQuadWithScreen = ScreenQuad.Overlay(ScreenLocateTexture);   // 叠加屏幕色差图
 
-             // 绘制allLines
 
-             var allLinesMap = new Matrix(o0Size, Tiling: true);
 
-             foreach (var l in allLines)
 
-             {
 
-                 if (l.DrawLine != null)
 
-                     o0Extension.DrawLine(allLinesMap, l.DrawLine, (x, y) => 1, new Vector(0, 2), true);
 
-             }
 
-             var allLinesTex = allLinesMap.ToTexRGBA(FloatValueToColor);
 
-             ScreenLocate.DebugTexture(1, allLinesTex);
 
-             // 还需要输出一张识别结果图,包含干扰线段
 
-             var ChoosableLineMap = new Matrix(o0Size, Tiling: true);
 
-             foreach (var l in possibleLines)
 
-             {
 
-                 if (l != null && !quadLinesSemiAuto.Contains(l) && !manualLines.Contains(l))
 
-                     o0Extension.DrawLine(ChoosableLineMap, l.DrawLine, (x, y) => 1, new Vector(0, 2), true); // 其他的备选线段
 
-             }
 
-             foreach (var l in LineIdentifiedSemiAuto)
 
-             {
 
-                 if (l != null)
 
-                     o0Extension.DrawLine(ChoosableLineMap, l.DrawLine, (x, y) => 5, new Vector(0, 5)); // 识别的结果
 
-             }
 
-             if (manualLines != null)
 
-             {
 
-                 foreach (var l in manualLines)
 
-                     o0Extension.DrawLine(ChoosableLineMap, l.DrawLine, (x, y) => 3, new Vector(0, 2), true);     // 旧的屏幕线段(例如上次手动识别的)
 
-             }
 
-             Texture2D ChoosableLineTex = ChoosableLineMap.ToTexRGBA(FloatValueToColor);
 
-             #endregion
 
-             log += $"\r\n屏幕四边形_手动识别{QuadManual != null}\r\n屏幕四边形_半自动识别{QuadSemiAuto != null}\r\n屏幕四边形_全自动识别{QuadAuto != null}";
 
-             Debug.Log(log);
 
-             // 是否将图片保存到本地
 
-             if (ScreenLocate.Main.SaveToggle?.isOn ?? false && ScreenLocate.Main.DebugOnZIMDemo)
 
-             {
 
-                 var FileDirectory = $"Debug_屏幕定位/";
 
-                 SaveImages(FileDirectory, log, ScreenLocateTexture, allLinesTex, ChoosableLineTex, ScreenQuad);
 
-             }
 
-             //times.Add(watch.ElapsedMilliseconds);
 
-             //Debug.Log("time: " + (times[times.Count - 1] - times[times.Count - 2]));
 
-             // opecncv处理, zim
 
-             {
 
-                 //var cvLines = edge.cvHoughLinesP();
 
-                 //ScreenLocate.DebugTexture(5, cvLines);
 
-                 //var myLines = Hough.Transform(edgeMat);
 
-                 //var cvLines = edge.cvLine(myLines);
 
-                 //ScreenLocate.DebugTexture(5, cvLines);
 
-             }
 
-             {
 
-                 ScreenLocate.DebugTexture(2, ScreenLocateTexture);
 
-                 ScreenLocate.DebugTexture(3, ScreenQuad);
 
-                 ScreenLocate.DebugTexture(4, ScreenQuadWithScreen);
 
-                 ScreenLocate.DebugTexture(5, ChoosableLineTex);
 
-             }
 
-             foreach (var i in LocateTexTemp)
 
-             {
 
-                 if (i != ScreenLocateTexture)       // ScreenLocateTexture 由 ScreenLocate.DebugTexture 释放
 
-                     GameObject.Destroy(i);
 
-             }
 
-         }
 
-         Vector GetAvgPoint(Matrix screenLocateMat)
 
-         {
 
-             // 加权平均
 
-             Vector[] avgPointsColumn = new Vector[screenLocateMat.Size.x];
 
-             float[] valueSumsColumn = new float[screenLocateMat.Size.x];
 
-             Parallel.For(0, screenLocateMat.Size.x, i =>
 
-             {
 
-                 for (int j = 0; j < screenLocateMat.Size.y; j++)
 
-                 {
 
-                     var value = screenLocateMat[i, j];
 
-                     valueSumsColumn[i] += value;
 
-                     avgPointsColumn[i] += new Vector(i, j) * value;
 
-                 }
 
-             });
 
-             Vector avgPoint = Vector.Zero;
 
-             var valueSum = 0f;
 
-             for (int i = 0; i < screenLocateMat.Size.x; i++)
 
-             {
 
-                 avgPoint += avgPointsColumn[i];
 
-                 valueSum += valueSumsColumn[i];
 
-             }
 
-             avgPoint /= valueSum;
 
-             return avgPoint;
 
-         }
 
-         // 返回查找到的线段数量,0是查找失败
 
-         int ZIMIdentifyQuadLSD(ref List<LineIdentified> allLines, int batch, (Matrix edgeMat, Matrix edgeDirMat) edgeGradient,
 
-             float minLength, Vector LineCaptureSize)
 
-         {
 
-             var l = edgeGradient.edgeMat.IdentifyLineLSD(edgeGradient.edgeDirMat, minLength, 25, LineCaptureSize);
 
-             if (l == null || l.Count == 0)
 
-                 return 0;
 
-             allLines.AddRange(l.Select((i) => new LineIdentified(batch, i)));
 
-             return l.Count;
 
-         }
 
-         // 返回四边形的四条边(半自动、全自动),List长度一定是4 (如果没有识别到就是null),且线段顺序是: 下、右、上、左
 
-         (List<LineIdentified>, List<LineIdentified>) FilterLines(List<Matrix> screenLocateMatList, List<LineIdentified> allLines, Vector avgPoint,
 
-             out LineIdentified[] manualLines, out List<LineIdentified> possibleLines, float gradientLength, float minLength = 100)
 
-         {
 
-             // 筛掉椭圆框外的线段(超出一半会筛掉)
 
-             var innerLines = new List<LineIdentified>();
 
-             for (int i = 0; i < allLines.Count; i++)
 
-             {
 
-                 List<Vector> InArea = new List<Vector>();
 
-                 var dir = (allLines[i].Line.B - allLines[i].Line.A) / 4;
 
-                 var points = new Vector[5] { allLines[i].Line.A, allLines[i].Line.A + dir, allLines[i].Line.A + dir * 2f, allLines[i].Line.A + dir * 3f, allLines[i].Line.B };  // A点、中间的点、B点
 
-                 for (int pI = 0; pI < points.Length; pI++)
 
-                 {
 
-                     if (ScreenLocate.Main.ScreenPixelCheaker != null && !ScreenLocate.Main.ScreenPixelCheaker.OutArea2D(points[pI], Size)) 
 
-                         InArea.Add(points[pI]);
 
-                 }
 
-                 if (InArea.Count < 2)   // 少于2个点在内部
 
-                     continue;
 
-                 else if (InArea.Count < points.Length)  // 不完全在内部
 
-                     allLines[i].DrawLine = new Line(InArea.First(), InArea.Last());        // 将部分线条设置为drawline,用于下一步的绘制
 
-                 else   // 线段全部在椭圆内
 
-                     allLines[i].DrawLine = allLines[i].Line;
 
-                 innerLines.Add(allLines[i]);
 
-             }
 
-             // 角度阈值,用来判断线段的梯度方向是否指向屏幕中心(avgPoint)
 
-             var avaAngleHalf = 75f;
 
-             // 评估屏幕内部的Line
 
-             var interLineGuess = new InterLineGuess(screenLocateMatList, gradientLength * 2, minLength);
 
-             #region 内部函数
 
-             float ScreenGrad(LineIdentified line)
 
-             {
 
-                 var dir = (line.Line.B - line.Line.A).Normalized;
 
-                 var vertical = new Vector(-dir.y, dir.x) * (gradientLength / 2);
 
-                 int step = (int)(minLength / 5);
 
-                 var ll = line.Line.Length;
 
-                 var lg = new List<float>();
 
-                 for (int i = 0; i <= ll; i += step)
 
-                 {
 
-                     var point = line.Line.A + dir * i;
 
-                     var ga = point + vertical;
 
-                     var gb = point - vertical;
 
-                     lg.Add(screenLocateMatList[line.Batch][(int)ga.x, (int)ga.y] - screenLocateMatList[line.Batch][(int)gb.x, (int)gb.y]);
 
-                 }
 
-                 return Math.Abs(lg.Mean());
 
-             }
 
-             // 沿直线计算综合梯度(梯度乘以长度系数,再乘以距离系数), distanceRatio是实际距离除以距离阈值
 
-             float estimateGradient(LineIdentified line, float distanceRatio)
 
-             {
 
-                 var gM = ScreenGrad(line);
 
-                 if (line.Batch > 0)       // 其他batch的图,梯度权重小
 
-                     gM /= 3;
 
-                 float e = (float)Math.Sqrt(Math.Ceiling(line.Line.Length / minLength));       // 长度系数,筛选时梯度更大、长度更长的线段更优
 
-                 float d = (10f - distanceRatio * distanceRatio) / 10f;             // 距离系数,距离越近,系数越大
 
-                 line.ZIMGradient = e * gM + d;      // 记录一下综合梯度,新增的识别黑边功能会二次使用
 
-                 return line.ZIMGradient;
 
-             }
 
-             // 根据线段梯度的角度,判断是不是屏幕的边,index代表是哪条边(顺序是: 下、右、上、左)
 
-             void GetScreenLineIndex(LineIdentified line)
 
-             {
 
-                 var a = (avgPoint - (line.Line.A + line.Line.B) / 2).DegreeToXAxis();
 
-                 //Debug.Log(a + ", " + gradient + ", " + sum);
 
-                 var index = -1;
 
-                 if (Math.Abs(a - line.GradientDegree) < avaAngleHalf || Math.Abs(a - 360 - line.GradientDegree) < avaAngleHalf || Math.Abs(a + 360 - line.GradientDegree) < avaAngleHalf)
 
-                 {
 
-                     if (line.GradientDegree > 45 && line.GradientDegree < 135)     // 下
 
-                         index = 0;
 
-                     else if (line.GradientDegree > 135 && line.GradientDegree < 225) // 右
 
-                         index = 1;
 
-                     else if (line.GradientDegree > 225 && line.GradientDegree < 315)  // 上
 
-                         index = 2;
 
-                     else
 
-                         index = 3;
 
-                 }
 
-                 line.ScreenLineIndex = index;
 
-             }
 
-             #endregion
 
-             // 根据梯度方向,判断是哪条边
 
-             foreach (var l in innerLines)
 
-                 GetScreenLineIndex(l);
 
-             // 下、右、上、左, 半自动和自动
 
-             var quadLinesSemiAuto = new List<(float, LineIdentified)>[4] { new List<(float, LineIdentified)>(), new List<(float, LineIdentified)>(), new List<(float, LineIdentified)>(), new List<(float, LineIdentified)>() };
 
-             var quadLinesAuto = new List<(float, LineIdentified)>[4] { new List<(float, LineIdentified)>(), new List<(float, LineIdentified)>(), new List<(float, LineIdentified)>(), new List<(float, LineIdentified)>() };
 
-             possibleLines = new List<LineIdentified>();
 
-             #region 半自动(利用手动数据)
 
-             // 如果已有手动定位数据,根据现有数据筛选线条(半自动)
 
-             manualLines = null;
 
-             if (QuadManual != null)
 
-             {
 
-                 Debug.Log($"[IdentifyLineLSD] 根据已有定位数据做筛选, QuadManual: {QuadManual}");
 
-                 manualLines = QuadManual.GetLines().Select((i) => new LineIdentified(0, i, 0, 0, true)).ToArray();
 
-                 var calibration = ScreenLocate.Main.ReDoLocateCalibrationRatio * Size.y;
 
-                 var distanceMeasure = 0.02f * Size.y;
 
-                 var avgPointCross = manualLines.Select((i) => i.Line.LineCrossWithPoint(avgPoint)).ToArray();     // 对于平均点的corss值
 
-                 var avgPointPedal = manualLines.Select((i) => o0Extension.PointPedal(i.Line, avgPoint, out _)).ToArray();     // 当前定位的垂足,下、右、上、左
 
-                 foreach (var line in innerLines)
 
-                 {
 
-                     // 筛选条件:1-梯度方向匹配,2-垂足的距离足够近, 3-线段的AB点均在旧线段外部, 4-新的线段的中点,到旧线段的垂足,要在旧线段内
 
-                     if (line.ScreenLineIndex >= 0)
 
-                     {
 
-                         var distanceToOld = (o0Extension.PointPedal(line.Line, avgPoint, out _) - avgPointPedal[line.ScreenLineIndex]).Length;
 
-                         if (distanceToOld < calibration &&
 
-                             manualLines[line.ScreenLineIndex].Line.LineCrossWithPoint(line.Line.A) * avgPointCross[line.ScreenLineIndex] <= 0 &&
 
-                             manualLines[line.ScreenLineIndex].Line.LineCrossWithPoint(line.Line.B) * avgPointCross[line.ScreenLineIndex] <= 0)
 
-                         {
 
-                             var middleToOldLine = o0Extension.PointPedal(manualLines[line.ScreenLineIndex].Line, (line.Line.A + line.Line.B) / 2, out bool inLineSegment);
 
-                             if (inLineSegment)
 
-                             {
 
-                                 quadLinesSemiAuto[line.ScreenLineIndex].Add((estimateGradient(line, (float)Math.Floor(distanceToOld / distanceMeasure)), line));
 
-                                 possibleLines.Add(line);
 
-                             }
 
-                         }
 
-                     }
 
-                 }
 
-             }
 
-             // 获得结果
 
-             var resultSemiAuto = new LineIdentified[4];
 
-             var resultSemiAutoPedal = new Vector[4];       // 用于找平行线
 
-             for (int i = 0; i < 4; i++)
 
-             {
 
-                 resultSemiAuto[i] = quadLinesSemiAuto[i].Max((a, b) => a.Item1.CompareTo(b.Item1)).Item2;
 
-                 if (resultSemiAuto[i] != null)
 
-                     resultSemiAutoPedal[i] = o0Extension.PointPedal(resultSemiAuto[i].Line, avgPoint, out _);
 
-             }
 
-             // 新增功能(解决黑边问题):根据 result 再找平行线,判断是否替换(1-在 result 内部,且离中点最近,2-接近平行)
 
-             UpdateResultlines(resultSemiAuto, FindInterLinePair(
 
-                 interLineGuess,
 
-                 GetInterSelectableLines(quadLinesSemiAuto, resultSemiAuto, resultSemiAutoPedal, avgPoint)));
 
-             #endregion
 
-             #region 全自动
 
-             // 全自动
 
-             foreach (var line in innerLines)
 
-             {
 
-                 if (line.ScreenLineIndex >= 0 && line.Batch < 1)    // 全自动只处理第一张图,默认是色差图
 
-                 {
 
-                     quadLinesAuto[line.ScreenLineIndex].Add((estimateGradient(line, 1), line));
 
-                 }
 
-             }
 
-             // 获得结果
 
-             var resultAuto = new LineIdentified[4];
 
-             var resultAutoPedal = new Vector[4];       // 用于找平行线
 
-             for (int i = 0; i < 4; i++)
 
-             {
 
-                 resultAuto[i] = quadLinesAuto[i].Max((a, b) => a.Item1.CompareTo(b.Item1)).Item2;
 
-                 if (resultAuto[i] != null)
 
-                     resultAutoPedal[i] = o0Extension.PointPedal(resultAuto[i].Line, avgPoint, out _);
 
-             }
 
-             // 新增功能(解决黑边问题):根据 resultAuto 再找平行线,判断是否替换(1-在 result 内部,且离中点最近,2-接近平行,3-LineGuess判断是直线)
 
-             UpdateResultlines(resultAuto, FindInterLinePair(
 
-                 interLineGuess,
 
-                 GetInterSelectableLines(quadLinesAuto, resultAuto, resultAutoPedal, avgPoint)));
 
-             #endregion
 
-             return (resultSemiAuto.ToList(), resultAuto.ToList());
 
-         }
 
-         List<LineIdentified> GetInterSelectableLines(List<(float, LineIdentified)>[] quadLines, LineIdentified[] resultLines, Vector[] resultPedal, Vector avgPoint)
 
-         {
 
-             var result = new List<LineIdentified>();
 
-             foreach (var ql in quadLines)
 
-             {
 
-                 foreach (var (_, line) in ql)
 
-                 {
 
-                     if (line != resultLines[line.ScreenLineIndex] && line.Batch < 1) // batch0才做黑边的内部线条检测
 
-                     {
 
-                         var pedal = o0Extension.PointPedal(line.Line, avgPoint, out _);
 
-                         var a0 = pedal - avgPoint;
 
-                         var a0L = a0.Length;
 
-                         line.DistanceToMiddle = a0L;
 
-                         var a1 = resultPedal[line.ScreenLineIndex] - avgPoint;
 
-                         var a1L = a1.Length;
 
-                         if (a0L < a1L)
 
-                         {
 
-                             var dotN = a0.Dot(a1) / a0L / a1L;
 
-                             if (Math.Abs(dotN - 1) < 0.002) // 接近平行即可
 
-                                 result.Add(line);
 
-                         }
 
-                     }
 
-                 }
 
-             }
 
-             return result;
 
-         }
 
-         void UpdateResultlines(LineIdentified[] result, (LineIdentified a, LineIdentified b) inter)
 
-         {
 
-             if (inter.a != null)   // 替换上一步筛选的结果中的部分边,得到最终的结果
 
-                 result[inter.a.ScreenLineIndex] = inter.a;
 
-             if (inter.b != null)
 
-                 result[inter.b.ScreenLineIndex] = inter.b;
 
-         }
 
-         (LineIdentified a, LineIdentified b) FindInterLinePair(InterLineGuess lineGuess, List<LineIdentified> interSelectable, int maxCountToSelect = 8)
 
-         {
 
-             Debug.Log("[ScreenIdentification] selectable inter line count: " + interSelectable.Count);
 
-             interSelectable.Sort((a, b) => b.ZIMGradient.CompareTo(a.ZIMGradient));
 
-             int count = 0;
 
-             LineIdentified[] selected = new LineIdentified[4];
 
-             foreach (var line in interSelectable)
 
-             {
 
-                 if (line.GuessIsInterLine(lineGuess))        // 评价是不是Line, 并且找到离中心点最近的
 
-                 {
 
-                     if (ScreenLocate.Main.DebugOnZIMDemo)
 
-                         Debug.Log($"[ScreenIdentification] {interSelectable.IndexOf(line)}, guess is line: (index)" + line.ScreenLineIndex);
 
-                     if (selected[line.ScreenLineIndex] == null || selected[line.ScreenLineIndex].DistanceToMiddle > line.DistanceToMiddle)
 
-                         selected[line.ScreenLineIndex] = line;
 
-                 }
 
-                 if (count++ >= maxCountToSelect)
 
-                     break;
 
-             }
 
-             var selectedList = new List<LineIdentified>();
 
-             foreach (var i in selected)
 
-             {
 
-                 if (i != null)
 
-                     selectedList.Add(i);
 
-             }
 
-             if (selectedList.Count == 4)
 
-             {
 
-                 if (selected[0].ZIMGradient + selected[2].ZIMGradient > selected[1].ZIMGradient + selected[3].ZIMGradient)
 
-                     return (selected[0], selected[2]);
 
-                 else
 
-                     return (selected[1], selected[3]);
 
-             }
 
-             else if (selected[0] != null && selected[2] != null)
 
-                 return (selected[0], selected[2]);
 
-             else if (selected[1] != null && selected[3] != null)
 
-                 return (selected[1], selected[3]);
 
-             else if (selectedList.Count == 2)
 
-                 return selectedList[0].ZIMGradient > selectedList[1].ZIMGradient ? (selectedList[0], null) : (selectedList[1], null);
 
-             else if (selectedList.Count == 1)
 
-                 return (selectedList[0], null);
 
-             else
 
-                 return (null, null);
 
-         }
 
-         void SaveImages(string FileDirectory, string log,
 
-             Texture2D ScreenLocateTex, Texture2D allLinesTex, Texture2D ChoosableLineTex, Texture2D ScreenQuadTex)
 
-         {
 
-             if (!Directory.Exists(FileDirectory))
 
-                 Directory.CreateDirectory(FileDirectory);
 
-             var time = DateTime.Now.ToString("yyyyMMdd_HHmmss");
 
-             var pngData = ScreenLocate.Main.OutputTextures[7]?.EncodeToPNG();
 
-             if (pngData != null)
 
-                 File.WriteAllBytes($"{FileDirectory}{time}A屏幕原图.png", pngData);
 
-             var pngData1 = ScreenLocateTex?.EncodeToPNG();
 
-             if (pngData1 != null)
 
-                 File.WriteAllBytes($"{FileDirectory}{time}B黑白色差.png", pngData1);
 
-             var pngData2 = allLinesTex?.EncodeToPNG();
 
-             if (pngData2 != null)
 
-                 File.WriteAllBytes($"{FileDirectory}{time}C全部识别线段_半自动.png", pngData2);
 
-             var pngData3 = ChoosableLineTex?.EncodeToPNG();
 
-             if (pngData3 != null)
 
-                 File.WriteAllBytes($"{FileDirectory}{time}D备选线段_半自动.png", pngData3);
 
-             var pngData4 = ScreenQuadTex?.EncodeToPNG();
 
-             if (pngData4 != null)
 
-                 File.WriteAllBytes($"{FileDirectory}{time}E识别结果.png", pngData4);
 
-             Debug.Log($"<color=aqua>({time}) 屏幕识别图片保存至:程序根目录/{FileDirectory}</color>");
 
-             log +=
 
-                 $"\r\n屏幕原图保存{pngData != null}, " +
 
-                 $"\r\n黑白色差保存{pngData1 != null}, " +
 
-                 $"\r\n全部识别线段(半自动)保存{pngData2 != null}, " +
 
-                 $"\r\n备选线段(半自动)保存{pngData3 != null}, " +
 
-                 $"\r\n识别结果保存{pngData4 != null}";
 
-             File.WriteAllText($"{FileDirectory}{time}屏幕自动定位_日志.log", log);
 
-         }
 
-     }
 
- }
 
 
  |