ScreenIdentification.cs 27 KB

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