LineGuess.cs 5.3 KB

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