ScreenIdentification.cs 27 KB

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