zimIdentifyLineLSD.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. using o0.Geometry;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using UnityEngine;
  8. using UnityEngine.UI;
  9. using o0.Geometry2D.Float;
  10. using ZIM;
  11. using o0.Num;
  12. namespace o0.Project
  13. {
  14. public static partial class Extension
  15. { // (垂直方向,水平方向)
  16. public static (Vector, float) ZIMLineSegGradient(Matrix mat, Matrix dir, float gradient, Vector start, Vector end, (int, int) range, bool reverseXY)
  17. {
  18. int startX, endX;
  19. if (start.x < end.x)
  20. {
  21. startX = Mathf.RoundToInt(start.x) + 1;
  22. endX = Mathf.RoundToInt(end.x) + 1;
  23. }
  24. else
  25. {
  26. startX = Mathf.RoundToInt(start.x) - 1;
  27. endX = Mathf.RoundToInt(end.x) - 1;
  28. }
  29. if (startX == endX)
  30. return (new Vector(start.x, start.y), 0);
  31. var xDiff = end.x - start.x;
  32. var xToYRate = (float)(end.y - start.y) / xDiff;
  33. Func<float, float> xToYFunc = (x) => (x - start.x) * xToYRate + start.y;
  34. var B1 = Mathf.RoundToInt(start.x);
  35. var B1V = mat[B1, Mathf.RoundToInt(start.y)];
  36. var Sum1 = B1V;
  37. foreach (var Bx in startX.Range(endX))
  38. {
  39. int[,] CIArray = new int[range.Item1, range.Item2];
  40. float[] CAArray = new float[range.Item1 * range.Item2];
  41. float[] CMArray = new float[range.Item1 * range.Item2];
  42. for (int j = 0; j < range.Item2; j++)
  43. {
  44. var x = xDiff > 0 ? Bx + j : Bx - j;
  45. var y = xToYFunc(x);
  46. var m1 = range.Item1 / 2 - 1;
  47. var m2 = range.Item1 / 2;
  48. var y1 = Mathf.FloorToInt(y);
  49. var y2 = Mathf.CeilToInt(y);
  50. for (int i = 0; i < range.Item1 / 2; i++)
  51. {
  52. if (reverseXY)
  53. CIArray[i, j] = mat.Index(y1 + i - m1, x);
  54. else
  55. CIArray[i, j] = mat.Index(x, y1 + i - m1);
  56. CAArray[i + j * range.Item1] = dir.Element[CIArray[i, j]];
  57. CMArray[i + j * range.Item1] = mat.Element[CIArray[i, j]];
  58. }
  59. for (int i = range.Item1 / 2; i < range.Item1; i++)
  60. {
  61. if (reverseXY)
  62. CIArray[i, j] = mat.Index(y2 + i - m2, x);
  63. else
  64. CIArray[i, j] = mat.Index(x, y2 + i - m2);
  65. CAArray[i + j * range.Item1] = dir.Element[CIArray[i, j]];
  66. CMArray[i + j * range.Item1] = mat.Element[CIArray[i, j]];
  67. }
  68. }
  69. var CV = o0.Max(CMArray);
  70. var avaAngle = 60;
  71. var halfAvaAngle = avaAngle / 2;
  72. var breakFlag = true;
  73. foreach (var ca in CAArray)
  74. {
  75. if (MathF.Abs(ca - gradient) <= halfAvaAngle || MathF.Abs(ca - 360 - gradient) <= halfAvaAngle || MathF.Abs(ca + 360 - gradient) <= halfAvaAngle)
  76. {
  77. breakFlag = false;
  78. break;
  79. }
  80. }
  81. if (breakFlag)
  82. break;
  83. B1 = Bx;
  84. Sum1 += CV;
  85. }
  86. return (new Vector(B1, xToYFunc(B1)), Sum1);
  87. }
  88. // 线段顺序: 下、右、上、左
  89. public static List<Line> ZIMIdentifyQuadLSD(this Matrix screenLocateMat, Matrix edgeMat, Matrix edgeDirMat,out List<Line> lightLines,
  90. float gradientLength, float minLength = 100)
  91. {
  92. // 加权平均
  93. Vector[] avgPointsColumn = new Vector[screenLocateMat.Size.x];
  94. float[] valueSumsColumn = new float[screenLocateMat.Size.x];
  95. Parallel.For(0, screenLocateMat.Size.x, i =>
  96. {
  97. for (int j = 0; j < screenLocateMat.Size.y; j++)
  98. {
  99. var value = screenLocateMat[i, j];
  100. valueSumsColumn[i] += value;
  101. avgPointsColumn[i] += new Vector(i, j) * value;
  102. }
  103. });
  104. Vector avgPoint = Vector.Zero;
  105. var valueSum = 0f;
  106. for (int i = 0; i < screenLocateMat.Size.x; i++)
  107. {
  108. avgPoint += avgPointsColumn[i];
  109. valueSum += valueSumsColumn[i];
  110. }
  111. avgPoint /= valueSum;
  112. var lines = edgeMat.IdentifyLineLSD(edgeDirMat, minLength, 20);
  113. //Debug.Log("[IdentifyLineLSD] lines.Count: " + lines.Count);
  114. // 下、右、上、左
  115. var quadLines = new List<(float, Line)>[4] {new List<(float, Line)>(), new List<(float, Line)>(), new List<(float, Line)>(), new List<(float, Line)>() };
  116. var avaAngleHalf = 75f;
  117. lightLines = new List<Line>();
  118. foreach (var (line, sum, gradient) in lines)
  119. {
  120. lightLines.Add(line);
  121. var a = (avgPoint - (line.A + line.B) / 2).DegreeToXAxis();
  122. //Debug.Log(a + ", " + gradient + ", " + sum);
  123. int index = -1;
  124. if (Math.Abs(a - gradient) < avaAngleHalf || Math.Abs(a - 360 - gradient) < avaAngleHalf || Math.Abs(a + 360 - gradient) < avaAngleHalf)
  125. {
  126. if (gradient > 45 && gradient < 135) // 下
  127. index = 0;
  128. else if (gradient > 135 && gradient < 225) // 右
  129. index = 1;
  130. else if (gradient > 225 && gradient < 315) // 上
  131. index = 2;
  132. else
  133. index = 3;
  134. // 沿直线计算平均梯度
  135. var dir = (line.B - line.A).Normalized;
  136. var vertical = new Vector(-dir.y, dir.x) * (gradientLength / 2);
  137. var step = 2;
  138. var ll = line.Length;
  139. var lg = new List<float>();
  140. for (int i = 0; i <= ll; i += step)
  141. {
  142. var point = line.A + dir * i;
  143. var ga = point + vertical;
  144. var gb = point - vertical;
  145. lg.Add(screenLocateMat[(int)ga.x, (int)ga.y] - screenLocateMat[(int)gb.x, (int)gb.y]);
  146. //Debug.Log(lg.Last());
  147. }
  148. //var g = Math.Abs(lg.Mean());
  149. //Debug.Log(gradient + ", " + g);
  150. //List<float> lp1 = new List<float>(), lp2 = new List<float>(); // 线两侧的值
  151. //for (float i = 0; i <= ll; i += step)
  152. //{
  153. // var point = line.A + dir * i;
  154. // var ga = point + vertical;
  155. // var gb = point - vertical;
  156. // lp1.Add(screenLocateMat[(int)ga.x, (int)ga.y]);
  157. // lp2.Add(screenLocateMat[(int)gb.x, (int)gb.y]);
  158. //}
  159. //var avg1 = lp1.Mean();
  160. //var avg2 = lp2.Mean();
  161. //var v1 = lp1.Variance();
  162. //var v2 = lp2.Variance();
  163. //var lineGradient = Math.Abs(avg1 - avg2) / (v1 + v2 + 0.2f); // 方差越小,梯度的价值越高
  164. ////var g = Math.Abs(lg.Mean());
  165. ////Debug.Log(gradient + ", " + g);
  166. //Debug.Log(v1 + ", " + v2 + ", " + lineGradient);
  167. //quadLines[index].Add((lineGradient, line));
  168. quadLines[index].Add((Math.Abs(lg.Mean()), line));
  169. }
  170. }
  171. var result = new List<Line>();
  172. foreach (var list in quadLines)
  173. result.Add(list.Max((a, b) => a.Item1.CompareTo(b.Item1)).Item2);
  174. return result;
  175. }
  176. }
  177. }