InterLineGuess.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. using o0.Geometry2D.Float;
  2. using o0.Num;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using UnityEngine;
  7. namespace o0.Project
  8. {
  9. // 猜测屏幕内部的线,用于识别屏幕的黑边
  10. // 大于阈值则猜测是Line,但是这个类不考虑梯度,外部仍需结合梯度评估
  11. public class InterLineGuess
  12. {
  13. public static float isLineThreshold = 1.0f;
  14. // 记录分段的线段数据
  15. class SubLineData
  16. {
  17. public List<float> DataList;
  18. public List<float> DiffList; // 数据与平均值的差
  19. // 幅度
  20. float diffExtent = -1;
  21. float dataExtent = -1;
  22. public SubLineData(float data, float diff)
  23. {
  24. DataList = new List<float> { data };
  25. DiffList = new List<float> { diff };
  26. }
  27. public void Add(float data, float diff)
  28. {
  29. DataList.Add(data);
  30. DiffList.Add(diff);
  31. }
  32. // 得到差异的幅度
  33. //public float GetDiffExtent()
  34. //{
  35. // if (diffExtent == -1)
  36. // {
  37. // var sum = 0.0f;
  38. // foreach (var i in DiffList)
  39. // sum += i * i;
  40. // return diffExtent = sum / DiffList.Count;
  41. // }
  42. // else
  43. // return diffExtent;
  44. //}
  45. // 得到数据的幅度(和0比)
  46. public float GetDataExtent()
  47. {
  48. if (dataExtent == -1)
  49. {
  50. var sum = 0.0f;
  51. foreach (var i in DataList)
  52. sum += i * i;
  53. return dataExtent = sum / DataList.Count;
  54. }
  55. else
  56. return dataExtent;
  57. }
  58. }
  59. public List<Matrix> ScreenLocateMatList;
  60. public float GradientLength;
  61. public float MinLineLength;
  62. public InterLineGuess(List<Matrix> screenLocateMatList, float gradientLength, float minLineLength)
  63. {
  64. ScreenLocateMatList = screenLocateMatList;
  65. GradientLength = gradientLength;
  66. MinLineLength = minLineLength;
  67. }
  68. // 猜测是直线返回true
  69. public bool GuessIsLine(LineIdentified line) => Guess(line) > isLineThreshold;
  70. // 越大越可能是直线
  71. public float Guess(LineIdentified line)
  72. {
  73. var dir = (line.Line.B - line.Line.A).Normalized;
  74. var vertical = new Vector(-dir.y, dir.x) * (GradientLength / 2);
  75. var verticalNormal = vertical.Normalized;
  76. float lineABStep = MinLineLength / 15;
  77. float lineGuessStart;
  78. float lineGuessEnd;
  79. if (line.Line.Length > 2 * MinLineLength)
  80. {
  81. lineGuessStart = 7.5f * lineABStep;
  82. lineGuessEnd = line.Line.Length - 7.5f * lineABStep; // 线的两端不计算
  83. }
  84. else
  85. {
  86. lineGuessStart = lineABStep;
  87. lineGuessEnd = line.Line.Length - lineABStep;
  88. }
  89. var gradData = new List<float>(); // 直线两侧梯度的平均值,垂直于直线变化
  90. var a0 = line.Line.A - vertical;
  91. var gradStep = 1.5f;
  92. for (float n = 0; n < GradientLength; n += gradStep)
  93. {
  94. var aN = a0 + verticalNormal * n;
  95. var gradThisLine = new List<float>();
  96. for (float i = lineGuessStart; i <= lineGuessEnd; i += lineABStep)
  97. {
  98. var point = aN + dir * i;
  99. gradThisLine.Add(ScreenLocateMatList[line.Batch][(int)point.x, (int)point.y]);
  100. }
  101. gradData.Add(gradThisLine.Mean());
  102. }
  103. //Debug.Log(line.Gradient + ", " + line.GradientDegree + ", " + gradData.ToJson());
  104. if (gradData.Count <= 3)
  105. return 400;
  106. var gradChangeData = new List<float>();
  107. for (int j = 1; j < gradData.Count; j++)
  108. gradChangeData.Add(Math.Abs(gradData[j] - gradData[j - 1]));
  109. var meanChange = gradChangeData.Mean();
  110. var diff = gradChangeData[0] - meanChange;
  111. var subList = new List<SubLineData>() { new SubLineData(gradChangeData[0], diff) };
  112. for (int i = 1; i < gradChangeData.Count; i++)
  113. {
  114. var newDiff = gradChangeData[i] - meanChange;
  115. if ((newDiff <= 0 && diff <= 0) || (newDiff > 0 && diff > 0)) // 同号,是一个分段
  116. subList.Last().Add(gradChangeData[i], newDiff);
  117. else
  118. subList.Add(new SubLineData(gradChangeData[i], newDiff));
  119. diff = newDiff;
  120. }
  121. int maxSubDataIndex = subList.MaxIndex((a, b) => a.GetDataExtent().CompareTo(b.GetDataExtent())); // 找到分段里和平均数差异最大的分段
  122. //TODO 这里要不要考虑加个阈值,过滤掉梯度太小的线条? -----------------------------------
  123. if (subList.Count < 3)
  124. maxSubDataIndex = -1; // ≥3的时候把SubDataExtent最高的这段剔除掉再计算
  125. var lineGuessExtent = 0.0f;
  126. for (int i = 0; i < subList.Count; i++)
  127. {
  128. if (i != maxSubDataIndex)
  129. lineGuessExtent += subList[i].GetDataExtent();
  130. }
  131. if (maxSubDataIndex == -1)
  132. lineGuessExtent /= subList.Count;
  133. else
  134. lineGuessExtent /= subList.Count - 1;
  135. lineGuessExtent = (float)Math.Sqrt(lineGuessExtent);
  136. var countFactor = -0.002f * Math.Abs(subList.Count - 3) + 0.015f; // 3时最大
  137. if (ScreenLocate.Main.DebugOnZIMDemo)
  138. Debug.Log("line.Index" + line.ScreenLineIndex + ", maxDiffIndex: " + maxSubDataIndex + ", sub count: " + subList.Count + ", lineGuess: " + (1 - lineGuessExtent + countFactor));
  139. return 1 - lineGuessExtent + countFactor;
  140. }
  141. }
  142. }