ScreenIdentification.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749
  1. #define ENABLE_LOG
  2. using o0.Geometry2D.Float;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Threading.Tasks;
  7. using UnityEngine;
  8. using ZIM;
  9. using ZIM.Unity;
  10. namespace o0.Project
  11. {
  12. public partial class ScreenIdentification
  13. {
  14. private const string TAG = "ScreenIdentification#";
  15. //static Rect[][] LocateAreaData = new Rect[][] {
  16. // 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) },
  17. // 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) },
  18. // 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) },
  19. // 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) }
  20. //};
  21. static Rect[][] LocateAreaData = new Rect[][] {
  22. 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) },
  23. 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) },
  24. 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) },
  25. 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) }
  26. };
  27. //static bool LocateDebug = false;
  28. static bool LocateDebug = true;
  29. public Geometry2D.Vector<int> Size { get; private set; }
  30. public ScreenMap Screen; // 识别到的屏幕,用于执行透视变换
  31. int capture = 0;
  32. int delay = 0;
  33. int maxCapture;
  34. int maxDelay;
  35. Geometry.Vector<float>[] ScreenBlackTexture;
  36. Geometry.Vector<float>[] ScreenWhiteTexture;
  37. int locateIndex = -1;
  38. List<Rect> locateArea = new List<Rect> {
  39. 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)
  40. }; // 屏幕显示白色的区域大小
  41. float areaPercent => locateArea[locateIndex].size.x; // 当前白色区域的占比
  42. int areaSelected = -1; // 选择哪个区域,顺序与Quadrilateral对应
  43. List<float> sumTemp = new List<float>();
  44. List<OrdinalQuadrilateral> quadTemp = new List<OrdinalQuadrilateral>();
  45. //public ScreenIdentification(WebCamTexture texture)
  46. //{
  47. // Size = new Geometry2D.Vector<int>(texture.width, texture.height);
  48. // Screen = new ScreenMap();
  49. //}
  50. public ScreenIdentification()
  51. {
  52. Screen = new ScreenMap();
  53. //OnLocateScreenEnter += () => Debug.Log("OnLocateScreenEnter");
  54. //OnLocateScreenEnd += () => Debug.Log("OnLocateScreenEnd");
  55. }
  56. public void SetScreenQuad(QuadrilateralInCamera quad) => Screen.QuadInCamera = quad;
  57. public event Action OnLocateScreenEnter;
  58. public event Action OnLocateScreenEnd;
  59. public bool bStartLocateScreen { get; set; } = false;//是否进行捕获
  60. // 自动识别开始的入口
  61. public void LocateScreen(int Capture = 30, int Delay = 30) //数值单位是frame
  62. {
  63. if (ScreenLocate.Main.DebugScreenImage != null && ScreenLocate.Main.DebugOnEditorWin) // 这段仅用于测试图片
  64. {
  65. Size = new Geometry2D.Vector<int>(ScreenLocate.Main.DebugScreenImage.width, ScreenLocate.Main.DebugScreenImage.height);
  66. DebugImage(ScreenLocate.Main.DebugScreenImage);
  67. Screen.QuadInCamera = new QuadrilateralInCamera(quadTemp[0], new Vector(ScreenLocate.Main.DebugScreenImage.width, ScreenLocate.Main.DebugScreenImage.height));
  68. ScreenLocate.SetScreen(null);
  69. ScreenLocate.Main.ShowScreen(ScreenLocate.Main.ScreenQuad, Screen.QuadInCamera);
  70. delay = 0;
  71. capture = 0;
  72. ScreenWhiteTexture = null;
  73. ScreenBlackTexture = null;
  74. locateIndex = -1;
  75. areaSelected = -1;
  76. quadTemp.Clear();
  77. sumTemp.Clear();
  78. return;
  79. }
  80. delay = Math.Max(Delay, 5);
  81. capture = Math.Max(Capture, 5);
  82. maxDelay = Delay;
  83. maxCapture = Capture;
  84. ScreenLocate.SetScreen(new Rect(0f, 0f, 1f, 1f), UnityEngine.Color.black);
  85. //ScreenLocate.SetScreen(new Rect(0f, 0f, 0.6f, 0.6f), UnityEngine.Color.white);
  86. //bStartLocateScreen = false;
  87. OnLocateScreenEnter?.Invoke();
  88. }
  89. /// <summary>
  90. /// 开始进行捕获
  91. /// 初始化了两个数据 capture 和 delay
  92. /// </summary>
  93. /// <returns></returns>
  94. public bool isInitLocateScreen() {
  95. return capture != 0 && delay != 0;
  96. }
  97. void DebugImage(Texture2D image)
  98. {
  99. QuadrilateralFit(out Texture2D LocateTex, out Texture2D DrawLineTex, 5, image);
  100. ScreenLocate.DebugTexture(2, LocateTex);
  101. ScreenLocate.DebugTexture(3, DrawLineTex);
  102. // 融合线段和原图
  103. var pixel0 = image.GetPixels();
  104. var pixel1 = DrawLineTex.GetPixels();
  105. for (int i = 0; i < pixel0.Length; i++)
  106. pixel0[i] += pixel1[i];
  107. var texAdd = new Texture2D(image.width, image.height);
  108. texAdd.SetPixels(pixel0);
  109. texAdd.Apply();
  110. ScreenLocate.DebugTexture(4, texAdd);
  111. //var watch = new System.Diagnostics.Stopwatch();
  112. //watch.Start();
  113. //var times = new List<double>() { 0.0 };
  114. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  115. Console.WriteLine($"{TAG} quadTemp.Count:{quadTemp.Count}");
  116. #endif
  117. if (quadTemp.Count > 0)
  118. {
  119. var quad = quadTemp[0];
  120. ScreenLocate.Main.ShowScreen(ScreenLocate.Main.rawImage4.transform.GetChild(0) as RectTransform, new QuadrilateralInCamera(quad, image.Size().o0Vector()));
  121. // 透视变换
  122. var srcWidth = LocateTex.width;
  123. var transformWidth = (int)((quad.B.x - quad.A.x + quad.D.x - quad.C.x) / 2);
  124. var transformHeight = (int)((quad.C.y - quad.A.y + quad.D.y - quad.B.y) / 2);
  125. var transformTex = new Texture2D(transformWidth, transformHeight);
  126. var pt = new ZIMPerspectiveTransform(new OrdinalQuadrilateral(new Vector(0, 0), new Vector(transformWidth, 0), new Vector(0, transformHeight), new Vector(transformWidth, transformHeight)), quad);
  127. var dstPixel = new UnityEngine.Color[transformWidth * transformHeight];
  128. var srcPixel = LocateTex.GetPixels();
  129. Parallel.For(0, transformWidth, (x) =>
  130. {
  131. for (int y = 0; y < transformHeight; y++)
  132. {
  133. var index = y * transformWidth + x;
  134. var sampleCoord = pt.TransformRound(x, y);
  135. dstPixel[index] = srcPixel[sampleCoord.y * srcWidth + sampleCoord.x];
  136. }
  137. });
  138. transformTex.SetPixels(dstPixel);
  139. transformTex.Apply();
  140. //ScreenLocate.DebugTexture(1, transformTex);
  141. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  142. Console.WriteLine($"{TAG} ScreenLocate.DebugTexture 1:{transformTex.GetNativeTexturePtr()}");
  143. #endif
  144. }
  145. //times.Add(watch.ElapsedMilliseconds);
  146. //UnityEngine.Debug.Log("time: " + (times[times.Count - 1] - times[times.Count - 2]));
  147. }
  148. public void NextScreen()
  149. {
  150. // 测试用
  151. if (LocateDebug && areaSelected == -1)
  152. {
  153. LocateAreaData = new Rect[][] { new Rect[] { new Rect(0, 0, 1f, 1f) } };
  154. locateIndex = 3;
  155. areaSelected = 0;
  156. locateArea.AddRange(LocateAreaData[0]);
  157. }
  158. // index从-1开始
  159. locateIndex++;
  160. if (locateIndex < locateArea.Count) // 依次点亮屏幕区域
  161. {
  162. ScreenLocate.SetScreen(locateArea[locateIndex], UnityEngine.Color.white);
  163. delay = maxDelay;
  164. capture = maxCapture;
  165. }
  166. else // 退出屏幕黑白控制
  167. {
  168. ScreenLocate.SetScreen(null);
  169. ScreenLocate.Main.ShowScreen(ScreenLocate.Main.ScreenQuad, Screen.QuadInCamera);
  170. Reset();
  171. }
  172. }
  173. void Reset()
  174. {
  175. // bStartLocateScreen = false;
  176. delay = 0;
  177. capture = 0;
  178. ScreenWhiteTexture = null;
  179. ScreenBlackTexture = null;
  180. locateIndex = -1;
  181. areaSelected = -1;
  182. locateArea.RemoveRange(4, LocateAreaData[0].Length);
  183. quadTemp.Clear();
  184. sumTemp.Clear();
  185. }
  186. public void CaptureBlack(Texture2D cam)
  187. {
  188. if (ScreenBlackTexture == null)
  189. ScreenBlackTexture = new Geometry.Vector<float>[Size.x * Size.y];
  190. var pixel = cam.GetPixels();
  191. Parallel.For(0, Size.x * Size.y, i =>
  192. {
  193. var ip = pixel[i];
  194. ScreenBlackTexture[i] += new Geometry.Vector<float>(ip.r / maxCapture, ip.g / maxCapture, ip.b / maxCapture);
  195. });
  196. }
  197. public void CaptureWhite(Texture2D cam)
  198. {
  199. if (ScreenWhiteTexture == null)
  200. ScreenWhiteTexture = new Geometry.Vector<float>[Size.x * Size.y];
  201. var pixel = cam.GetPixels();
  202. Parallel.For(0, Size.x * Size.y, i =>
  203. {
  204. var ip = pixel[i];
  205. ScreenWhiteTexture[i] += new Geometry.Vector<float>(ip.r / maxCapture, ip.g / maxCapture, ip.b / maxCapture);
  206. });
  207. }
  208. public void CaptureStay(Texture2D cam)
  209. {
  210. if (locateIndex == -1) // 屏幕黑色
  211. {
  212. CaptureBlack(cam);
  213. }
  214. else // 屏幕部分为白色
  215. {
  216. CaptureWhite(cam);
  217. }
  218. }
  219. public void CaptureEnd()
  220. {
  221. //Debug.Log("locateIndex: " + locateIndex + ", quad: " + quadTemp.Count);
  222. if (locateIndex == -1)
  223. return;
  224. if (locateIndex < 4)
  225. {
  226. sumTemp.Add(GetBrightness());
  227. ScreenWhiteTexture = null;
  228. // 选择亮度差最大的区域
  229. if (locateIndex == 3)
  230. {
  231. areaSelected = sumTemp.MaxIndex();
  232. locateArea.AddRange(LocateAreaData[areaSelected]);
  233. }
  234. }
  235. else if (locateIndex >= 4 && locateIndex < locateArea.Count - 1)
  236. {
  237. QuadrilateralFit(out _, out _);
  238. ScreenWhiteTexture = null;
  239. }
  240. else
  241. {
  242. QuadrilateralFit(out Texture2D LocateTex, out Texture2D DrawLineTex);
  243. if (ScreenLocate.Main.DebugOnEditorWin)
  244. {
  245. ScreenLocate.DebugTexture(1, LocateTex);
  246. ScreenLocate.DebugTexture(2, DrawLineTex);
  247. }
  248. if (quadTemp.Count != LocateAreaData[0].Length)
  249. {
  250. Debug.Log($"拟合四边形失败, quadTemp.Count: {quadTemp.Count}");
  251. }
  252. else if (quadTemp.Count == 1)
  253. {
  254. Screen.QuadInCamera = new QuadrilateralInCamera(quadTemp[0], new Vector(Size.x, Size.y));
  255. //Debug.Log($"拟合四边形成功, quadTemp.Count: {quadTemp.Count}");
  256. }
  257. else
  258. {
  259. // Debug.Log($"拟合四边形 2 , quadTemp.Count: {quadTemp.Count}");
  260. // 线性拟合
  261. var xValue = new List<float>() { 0 };
  262. var predicts = new List<Vector>();
  263. foreach (var i in LocateAreaData[0])
  264. xValue.Add(i.size.x);
  265. Vector baseVertex = Vector.Zero; // x==0 时的点
  266. {
  267. foreach (var q in quadTemp)
  268. {
  269. baseVertex += q[areaSelected];
  270. }
  271. baseVertex /= quadTemp.Count;
  272. }
  273. double rs = 0.0;
  274. for (int i = 0; i < 4; i++)
  275. {
  276. if (i == areaSelected)
  277. {
  278. predicts.Add(baseVertex);
  279. }
  280. else
  281. {
  282. var yValue = new List<Vector>() { baseVertex };
  283. foreach (var q in quadTemp)
  284. {
  285. yValue.Add(q[i]);
  286. }
  287. var lr = LinerRegression1D.Fit(2, xValue.ToArray(), yValue.ToArray());
  288. rs += lr.RSquared / 3;
  289. predicts.Add(lr.Predict<Vector>(1));
  290. }
  291. }
  292. Screen.QuadInCamera = new QuadrilateralInCamera(predicts, new Vector(Size.x, Size.y));
  293. Debug.Log($"[ScreenIdentification拟合结果] RSquared: {rs}, Quad: {Screen.QuadInCamera.QuadString}");
  294. //if (rs < 0.8) Screen.Quad = null;
  295. }
  296. OnLocateScreenEnd?.Invoke();
  297. }
  298. }
  299. public bool Update(Texture2D cam)
  300. {
  301. //if (!bStartLocateScreen) return false;
  302. if (delay != 0)
  303. {
  304. //ScreenLocate.Main.CreateUVCTexture2DFocusSizeIfNeeded(1280, 720);
  305. delay--;
  306. if (delay == 0)
  307. {
  308. Size = new Geometry2D.Vector<int>(cam.width, cam.height); // 记录当前的分辨率
  309. Debug.Log("[ScreenIdentification] 采样纹理,分辨率: [" + Size.x + ", " + Size.y + "]");
  310. }
  311. return true;
  312. }
  313. if (capture != 0)
  314. {
  315. //ScreenLocate.Main.CreateUVCTexture2DFocusSizeIfNeeded(1280, 720);
  316. CaptureStay(cam);
  317. capture--;
  318. if (capture == 0)
  319. {
  320. CaptureEnd();
  321. NextScreen();
  322. }
  323. return true;
  324. }
  325. return false;
  326. #region Old
  327. /*
  328. if (delay != 0)
  329. {
  330. delay--;
  331. return true;
  332. }
  333. if (capture != 0)
  334. {
  335. capture--;
  336. if (ScreenBlackTexture == null)
  337. ScreenBlackTexture = new Geometry.Vector<float>[Size.x * Size.y];
  338. var pixel = cam.GetPixels();
  339. Parallel.For(0, Size.x * Size.y, i =>
  340. {
  341. var ip = pixel[i];
  342. ScreenBlackTexture[i] += new Geometry.Vector<float>(ip.r, ip.g, ip.b);
  343. });
  344. if (capture == 0)
  345. ScreenLocate.SetScreen(UnityEngine.Color.black);
  346. return true;
  347. }
  348. if (delay != 0)
  349. {
  350. delay--;
  351. return true;
  352. }
  353. if (capture != 0)
  354. {
  355. capture--;
  356. if (ScreenWhiteTexture == null)
  357. ScreenWhiteTexture = new Geometry.Vector<float>[Size.x * Size.y];
  358. var pixel = cam.GetPixels();
  359. Parallel.For(0, Size.x * Size.y, i =>
  360. {
  361. var ip = pixel[i];
  362. ScreenWhiteTexture[i] += new Geometry.Vector<float>(ip.r, ip.g, ip.b);
  363. });
  364. if (capture == 0)
  365. ScreenLocate.SetScreen(UnityEngine.Color.black);
  366. return true;
  367. }
  368. if (delay != 0)
  369. {
  370. delay--;
  371. return true;
  372. }
  373. if (capture != 0)
  374. {
  375. capture--;
  376. var pixel = cam.GetPixels();
  377. Parallel.For(0, Size.x * Size.y, i =>
  378. {
  379. var ip = pixel[i];
  380. ScreenWhiteTexture[i] -= new Geometry.Vector<float>(ip.r, ip.g, ip.b);
  381. });
  382. if (capture == 0)
  383. {
  384. ScreenLocate.SetScreen(null);
  385. UnityEngine.Color[] newPixel = new UnityEngine.Color[Size.x * Size.y];
  386. Parallel.For(0, Size.x * Size.y, i => {
  387. var pi = ScreenWhiteTexture[i] /= capture;
  388. newPixel[i] = new UnityEngine.Color(pi.x, pi.y, pi.z);
  389. });
  390. //读取数据
  391. //{
  392. // var fileName = "3.bin";
  393. // ScreenLocateTexture = $"2023 04 16 厦门测试数据/{fileName}".FileReadByte<Vector<float>[]>();
  394. // Debug.Log($"Read {fileName}");
  395. // Parallel.For(0, Size.x * Size.y, i =>
  396. // {
  397. // var pi = ScreenLocateTexture[i];
  398. // newPixel[i] = new UnityEngine.Color(pi.x, pi.y, pi.z);
  399. // });
  400. //}
  401. var ScreenLocateTex = new Texture2D(Size.x, Size.y);
  402. ScreenLocateTex.SetPixels(newPixel);
  403. ScreenLocateTex.Apply();
  404. //ScreenLocate.DebugTexture(2, ScreenLocateTex);
  405. var ScreenLocateTexLighted = ScreenLocateTex.AutoLight(10);
  406. //ScreenLocate.DebugTexture(2, ScreenLocateTexLighted);
  407. //var FileSavePath = Application.persistentDataPath + "/ScreenLocateTexture.bin";
  408. bool Save = ScreenLocate.Main.SaveToggle.isOn;
  409. string time;
  410. if (Save)
  411. {
  412. time = DateTime.Now.ToString("yyyyMMdd_HHmmss");
  413. var FileSavePath = $"屏幕定位数据{time}.bin";
  414. FileSavePath.FileWriteByte(ScreenWhiteTexture);
  415. var bytes = ScreenLocateTexLighted.EncodeToPNG();
  416. File.WriteAllBytes($"屏幕定位数据{time}.png", bytes);
  417. Debug.Log("ScreenLocateTexture Saved To: " + FileSavePath);
  418. }
  419. var ScreenLocateTexR = ScreenLocateTexLighted.ToRGB(ColorChannel.Red);
  420. var ScreenLocateTexG = ScreenLocateTexLighted.ToRGB(ColorChannel.Green);
  421. var ScreenLocateTexB = ScreenLocateTexLighted.ToRGB(ColorChannel.Blue);
  422. ScreenLocate.DebugTexture(2, ScreenLocateTexR);
  423. //ScreenLocate.DebugTexture(4, ScreenLocateTexG);
  424. //ScreenLocate.DebugTexture(5, ScreenLocateTexB);
  425. var watch = new System.Diagnostics.Stopwatch();
  426. watch.Start();
  427. var times = new List<double>() { 0.0 };
  428. var ScreenLocateTexLightedMat = ScreenLocateTexLighted.Too0Mat();
  429. //var ScreenLocateTexLightedMat = texture.Too0Mat();
  430. //var (edge, edgeDir) = ScreenLocateTexLightedMat.IdentifyEdge();
  431. var (edge, edgeDir) = ScreenLocateTexLightedMat.zimIdentifyEdgeGradientAny(15);
  432. //ScreenLocate.DebugTexture(4, ScreenLocateTexLighted.Too0Mat().IdentifyEdgeGradient().ToTex());
  433. //ScreenLocate.DebugTexture(4, edge.ToTex());
  434. var quadLines = ScreenLocateTexLightedMat.IdentifyQuadLSD(edge, edgeDir, out List<Line> lightLines, 30);
  435. var drawLineMap = new MatrixF2D(edge..Size.x, edge.Size.y);
  436. int lineCount = 0;
  437. foreach (var l in quadLines)
  438. {
  439. if (l != null)
  440. {
  441. drawLineMap.DrawLine(l, (x, y) => 1, new Geometry2D.Float.Vector(0, 10));
  442. lineCount++;
  443. }
  444. }
  445. if (lineCount == 4)
  446. {
  447. var a = quadLines[0].Intersect(quadLines[3], false).Value;
  448. var b = quadLines[0].Intersect(quadLines[1], false).Value;
  449. var c = quadLines[2].Intersect(quadLines[3], false).Value;
  450. var d = quadLines[1].Intersect(quadLines[2], false).Value;
  451. Quad = new Quadrilateral(a, b, c, d);
  452. if (!Quad.IsInScreen(ScreenLocate.Main.WebCamera.Size))
  453. Quad = null;
  454. }
  455. ScreenLocate.Main.ShowScreen(Quad);
  456. //var lines = edge.IdentifyLineLSD(edgeDir, 100);
  457. ////var lines = ScreenLocateTexLightedMat.IdentifyLineLSD();
  458. //var drawLineMap = new MatrixF2D(edge..Size.x, edge.Size.y);
  459. //var returnMaxLines = lines.Sub(0, 10);
  460. //foreach (var (line, sum, gradient) in returnMaxLines)
  461. // drawLineMap.DrawLine(line, (x, y) => 1, new Geometry2D.Float.Vector(0, 10));
  462. ScreenLocate.DebugTexture(3, drawLineMap.ToTex());
  463. //{
  464. // var bytes = drawLineMap.ToTex().EncodeToPNG();
  465. // File.WriteAllBytes($"屏幕定位数据DrawLineMap.png", bytes);
  466. //}
  467. times.Add(watch.ElapsedMilliseconds);
  468. UnityEngine.Debug.Log("time: " + (times[times.Count - 1] - times[times.Count - 2]));
  469. //ScreenLocate.DebugTexture(5, edge.IdentifyLine(edgeDir).ToTex());
  470. //ScreenLocate.DebugTexture(4, ScreenLocateTexLighted.Too0Mat().IdentifyEdgeGradientX().ToTex());
  471. //ScreenLocate.DebugTexture(5, ScreenLocateTexLighted.Too0Mat().IdentifyEdgeGradientY().ToTex());
  472. //var convolutionLighted2 = ScreenLocateTexLighted.Too0Mat().IdentifyEdgeVariance().ToTex();
  473. // opecncv处理
  474. // zim
  475. {
  476. //var cvLines = edge.cvHoughLinesP();
  477. //ScreenLocate.DebugTexture(5, cvLines);
  478. //var myLines = Hough.Transform(edgeMat);
  479. //var cvLines = edge.cvLine(myLines);
  480. //ScreenLocate.DebugTexture(5, cvLines);
  481. }
  482. UnityEngine.Object.Destroy(ScreenLocateTex);
  483. //ScreenLocate.DebugTexture(4, convolutionLighted2);
  484. }
  485. return true;
  486. }
  487. /*
  488. var avg = new Geometry4D.Vector<float>();
  489. var pixel = texture.GetPixels();
  490. foreach(var i in pixel.Index())
  491. {
  492. var iP = pixel[i];
  493. avg += new Geometry4D.Vector<float>(iP.r, iP.g, iP.b, iP.a);
  494. }
  495. avg /= pixel.Count();
  496. /*
  497. var (texLightedR, texLightedG, texLightedB) = ToRGB(newTex);
  498. ScreenLocate.DebugTexture(3, texLightedR);
  499. ScreenLocate.DebugTexture(4, texLightedG);
  500. ScreenLocate.DebugTexture(5, texLightedB);
  501. //Debug.Log(avg);
  502. return false;
  503. /**/
  504. #endregion
  505. }
  506. float GetBrightness()
  507. {
  508. UnityEngine.Color[] differPixel = new UnityEngine.Color[Size.x * Size.y];
  509. Parallel.For(0, Size.x * Size.y, i =>
  510. {
  511. var pi = ScreenWhiteTexture[i] - ScreenBlackTexture[i];
  512. differPixel[i] = new UnityEngine.Color(pi.x, pi.y, pi.z);
  513. });
  514. var sum = 0f;
  515. foreach (var i in differPixel)
  516. {
  517. sum += i.Brightness();
  518. }
  519. sum /= differPixel.Length;
  520. //Debug.Log(sum);
  521. return sum;
  522. }
  523. void QuadrilateralFit(out Texture2D LocateTex, out Texture2D DrawLineTex, float lineWidth = 10, Texture2D debugImage = null)
  524. {
  525. QuadrilateralInCamera screen = null;
  526. UnityEngine.Color[] differPixel = new UnityEngine.Color[Size.x * Size.y];
  527. //读取数据
  528. if (debugImage != null)
  529. {
  530. Debug.Log($"Debug {debugImage.name}");
  531. differPixel = debugImage.GetPixels();
  532. }
  533. else // 获得屏幕差值
  534. {
  535. Parallel.For(0, Size.x * Size.y, i =>
  536. {
  537. var pi = ScreenWhiteTexture[i] - ScreenBlackTexture[i];
  538. differPixel[i] = new UnityEngine.Color(pi.x, pi.y, pi.z);
  539. });
  540. }
  541. var ScreenLocateTex = new Texture2D(Size.x, Size.y);
  542. ScreenLocateTex.SetPixels(differPixel);
  543. ScreenLocateTex.Apply();
  544. //ScreenLocate.DebugTexture(2, ScreenLocateTex);
  545. var ScreenLocateTexLighted = ScreenLocateTex.AutoLight(10);
  546. //ScreenLocate.DebugTexture(2, ScreenLocateTexLighted);
  547. var ScreenLocateTexR = ScreenLocateTexLighted.ToRGB(ColorChannel.Red);
  548. var ScreenLocateTexG = ScreenLocateTexLighted.ToRGB(ColorChannel.Green);
  549. var ScreenLocateTexB = ScreenLocateTexLighted.ToRGB(ColorChannel.Blue);
  550. LocateTex = ScreenLocateTexR;
  551. //ScreenLocate.DebugTexture(2, ScreenLocateTexR);
  552. //ScreenLocate.DebugTexture(4, ScreenLocateTexG);
  553. //ScreenLocate.DebugTexture(5, ScreenLocateTexB);
  554. //var watch = new System.Diagnostics.Stopwatch();
  555. //watch.Start();
  556. //var times = new List<double>() { 0.0 };
  557. var ScreenLocateTexLightedMat = ScreenLocateTexLighted.Too0Mat();
  558. //var ScreenLocateTexLightedMat = texture.Too0Mat();
  559. //var (edge, edgeDir) = ScreenLocateTexLightedMat.IdentifyEdge();
  560. int conSize = 15;
  561. var (edge, edgeDir) = ScreenLocateTexLightedMat.zimIdentifyEdgeGradientAny(conSize);
  562. //ScreenLocate.DebugTexture(4, ScreenLocateTexLighted.Too0Mat().IdentifyEdgeGradient().ToTex());
  563. //ScreenLocate.DebugTexture(4, edge.ToTex());
  564. var drawLineMap = new Matrix(ScreenLocateTexLightedMat.Size, Tiling: true);
  565. var minLength = locateIndex == -1 ? 50 : 50 * areaPercent;
  566. var quadLines = ScreenLocateTexLightedMat.ZIMIdentifyQuadLSD(edge, edgeDir, out List<Line> lightLines, conSize, minLength);
  567. int lineCount = 0;
  568. // LSD计算得到的矩阵尺寸较小(因为卷积),这里必须进行位移
  569. var offset = new Vector((conSize - 1) / 2, (conSize - 1) / 2);
  570. for (int i = 0; i < quadLines.Count; i++)
  571. {
  572. if (quadLines[i] != null)
  573. {
  574. quadLines[i] += offset;
  575. drawLineMap.DrawLine(quadLines[i], (x, y) => 1, new Geometry2D.Float.Vector(0, lineWidth));
  576. lineCount++;
  577. }
  578. }
  579. //foreach (var l in lightLines)
  580. //{
  581. // if (l != null)
  582. // {
  583. // if (quadLines.Contains(l))
  584. // {
  585. // drawLineMap.DrawLine(l, (x, y) => 1, new Geometry2D.Float.Vector(0, 10));
  586. // lineCount++;
  587. // }
  588. // else
  589. // {
  590. // drawLineMap.DrawLine(l, (x, y) => 1, new Geometry2D.Float.Vector(0, 2));
  591. // }
  592. // }
  593. //}
  594. if (lineCount == 4)
  595. {
  596. var a = quadLines[0].Intersect(quadLines[3], false).Value;
  597. var b = quadLines[0].Intersect(quadLines[1], false).Value;
  598. var c = quadLines[2].Intersect(quadLines[3], false).Value;
  599. var d = quadLines[1].Intersect(quadLines[2], false).Value;
  600. screen = new QuadrilateralInCamera(a, b, c, d, new Vector(Size.x, Size.y));
  601. if (!screen.IsQuadComplete())
  602. screen = null;
  603. }
  604. if (screen != null)
  605. quadTemp.Add(screen.Quad);
  606. //var lines = edge.IdentifyLineLSD(edgeDir, 100);
  607. ////var lines = ScreenLocateTexLightedMat.IdentifyLineLSD();
  608. //var drawLineMap = new MatrixF2D(edge..Size.x, edge.Size.y);
  609. //var returnMaxLines = lines.Sub(0, 10);
  610. //foreach (var (line, sum, gradient) in returnMaxLines)
  611. // drawLineMap.DrawLine(line, (x, y) => 1, new Geometry2D.Float.Vector(0, 10));
  612. DrawLineTex = drawLineMap.ToTex();
  613. //ScreenLocate.DebugTexture(3, drawLineMap.ToTex());
  614. //var FileSavePath = Application.persistentDataPath + "/ScreenLocateTexture.bin";
  615. bool Save = ScreenLocate.Main.SaveToggle.isOn;
  616. string time;
  617. if (Save)
  618. {
  619. time = DateTime.Now.ToString("yyyyMMdd_HHmmss");
  620. var FileSavePath = $"{time}屏幕定位数据.bin";
  621. FileSavePath.FileWriteByte(ScreenWhiteTexture);
  622. var bytes = ScreenLocateTexLighted.EncodeToPNG();
  623. File.WriteAllBytes($"{time}屏幕.png", bytes);
  624. bytes = DrawLineTex.EncodeToPNG();
  625. File.WriteAllBytes($"{time}屏幕边框识别.png", bytes);
  626. Debug.Log("ScreenLocateTexture Saved To: " + FileSavePath);
  627. }
  628. //times.Add(watch.ElapsedMilliseconds);
  629. //UnityEngine.Debug.Log("time: " + (times[times.Count - 1] - times[times.Count - 2]));
  630. //ScreenLocate.DebugTexture(5, edge.IdentifyLine(edgeDir).ToTex());
  631. //ScreenLocate.DebugTexture(4, ScreenLocateTexLighted.Too0Mat().IdentifyEdgeGradientX().ToTex());
  632. //ScreenLocate.DebugTexture(5, ScreenLocateTexLighted.Too0Mat().IdentifyEdgeGradientY().ToTex());
  633. //var convolutionLighted2 = ScreenLocateTexLighted.Too0Mat().IdentifyEdgeVariance().ToTex();
  634. // opecncv处理
  635. // zim
  636. {
  637. //var cvLines = edge.cvHoughLinesP();
  638. //ScreenLocate.DebugTexture(5, cvLines);
  639. //var myLines = Hough.Transform(edgeMat);
  640. //var cvLines = edge.cvLine(myLines);
  641. //ScreenLocate.DebugTexture(5, cvLines);
  642. }
  643. UnityEngine.Object.Destroy(ScreenLocateTex);
  644. }
  645. }
  646. }