o0IdentifyLineLSD.cs 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using UnityEngine;
  7. using UnityEngine.UI;
  8. using o0.Geometry2D.Float;
  9. namespace o0.Project
  10. {
  11. public static partial class Extension
  12. {
  13. public static (Vector, float) lineSegGradient(Matrix mat, Matrix dir, float gradient, Vector start, Vector end, bool reverseXY)
  14. {
  15. int startX, endX;
  16. if (start.x < end.x)
  17. {
  18. startX = Mathf.RoundToInt(start.x) + 1;
  19. endX = Mathf.RoundToInt(end.x) + 1;
  20. }
  21. else
  22. {
  23. startX = Mathf.RoundToInt(start.x) - 1;
  24. endX = Mathf.RoundToInt(end.x) - 1;
  25. }
  26. if(startX == endX)
  27. return (new Vector(start.x, start.y), 0);
  28. var xDiff = end.x - start.x;
  29. var xToYRate = (float)(end.y - start.y) / xDiff;
  30. Func<float, float> xToYFunc = (x) => (x - start.x) * xToYRate + start.y;
  31. var B1 = Mathf.RoundToInt(start.x);
  32. var B1V = mat[B1, Mathf.RoundToInt(start.y)];
  33. var Sum1 = B1V;
  34. foreach (var x in startX.Range(endX))
  35. {
  36. var y = xToYFunc(x);
  37. var y1 = Mathf.FloorToInt(y);
  38. var y2 = Mathf.CeilToInt(y);
  39. var y0 = y1 - 1;
  40. var y3 = y2 + 1;
  41. int C0I, C3I;
  42. int C1I, C2I;
  43. if (reverseXY)
  44. {
  45. C0I = mat.Index(y0, x);
  46. C1I = mat.Index(y1, x);
  47. C2I = mat.Index(y2, x);
  48. C3I = mat.Index(y3, x);
  49. }
  50. else
  51. {
  52. C0I = mat.Index(x, y0);
  53. C1I = mat.Index(x, y1);
  54. C2I = mat.Index(x, y2);
  55. C3I = mat.Index(x, y3);
  56. }
  57. var C0A = dir.Element[C0I];
  58. var C1A = dir.Element[C1I];
  59. var C2A = dir.Element[C2I];
  60. var C3A = dir.Element[C3I];
  61. //var CV = (y2 - y) * mat.Element[C1I] + (y - y1) * mat.Element[C2I];
  62. var CV = o0.Max(mat.Element[C0I], mat.Element[C1I], mat.Element[C2I], mat.Element[C3I]);
  63. //var avaAngle2 = 22.5;
  64. var avaAngle = 90;
  65. var halfAvaAngle = avaAngle/2;
  66. //var avaAngle2 = 33.75;
  67. if (!(MathF.Abs(C0A - gradient) <= halfAvaAngle || MathF.Abs(C0A - 360 - gradient) <= halfAvaAngle || MathF.Abs(C0A + 360 - gradient) <= halfAvaAngle
  68. || MathF.Abs(C1A - gradient) <= halfAvaAngle || MathF.Abs(C1A - 360 - gradient) <= halfAvaAngle || MathF.Abs(C1A + 360 - gradient) <= halfAvaAngle
  69. || MathF.Abs(C2A - gradient) <= halfAvaAngle || MathF.Abs(C2A - 360 - gradient) <= halfAvaAngle || MathF.Abs(C2A + 360 - gradient) <= halfAvaAngle
  70. || MathF.Abs(C3A - gradient) <= halfAvaAngle || MathF.Abs(C3A - 360 - gradient) <= halfAvaAngle || MathF.Abs(C3A + 360 - gradient) <= halfAvaAngle))
  71. {
  72. break;
  73. }
  74. B1 = x;
  75. Sum1 += CV;
  76. }
  77. return (new Vector(B1, xToYFunc(B1)), Sum1);
  78. }
  79. public static (Line, float) lineSegGradient(Matrix mat, Matrix dir, float gradient, Vector start)
  80. {
  81. var lineDir = (gradient + 90) % 180;//需要检测的线的角度
  82. var line = mat.MaskLine(start, lineDir);
  83. var range = (6, 2);
  84. if (lineDir < 45 || lineDir > 135)
  85. {
  86. //var (p1, sum1) = lineSegGradient(mat, dir, gradient, start, line.A, false);
  87. //var (p2, sum2) = lineSegGradient(mat, dir, gradient, start, line.B, false);
  88. var (p1, sum1) = ZIMLineSegGradient(mat, dir, gradient, start, line.A, range, false);
  89. var (p2, sum2) = ZIMLineSegGradient(mat, dir, gradient, start, line.B, range, false);
  90. return (new Line(p1, p2), sum1 + sum2);
  91. }
  92. else
  93. {
  94. var startR = new Vector(start.y, start.x);
  95. //var (p1, sum1) = lineSegGradient(mat, dir, gradient, startR, new Vector(line.A.y, line.A.x), true);
  96. //var (p2, sum2) = lineSegGradient(mat, dir, gradient, startR, new Vector(line.B.y, line.B.x), true);
  97. var (p1, sum1) = ZIMLineSegGradient(mat, dir, gradient, startR, new Vector(line.A.y, line.A.x), range, true);
  98. var (p2, sum2) = ZIMLineSegGradient(mat, dir, gradient, startR, new Vector(line.B.y, line.B.x), range, true);
  99. return (new Line(new Vector(p1.y, p1.x), new Vector(p2.y, p2.x)), sum1 + sum2);
  100. }
  101. }/**/
  102. /// <summary>
  103. /// List<(Line, float, float)>
  104. /// 线 线梯度和 线梯度方向0-180
  105. /// </summary>
  106. /// <returns>以梯度和最高值到最低值排列</returns>
  107. static public List<(Line, float, float)> IdentifyLineLSD(this Matrix mat, float minLength = 100)
  108. {
  109. var (edge, edgeDir) = mat.IdentifyEdge();
  110. return edge.IdentifyLineLSD(edgeDir, minLength);
  111. }
  112. /// <summary>
  113. /// List<(Line, float, float)>
  114. /// 线 线梯度和 线梯度方向0-180
  115. /// </summary>
  116. /// <param name="LineCaptureSize">获取line后,在line的位置清空多大范围的数据,以防重复获取(比如线段长10,size为5,3,则清空3像素宽,15像素长的长方形区域)</param>
  117. /// <returns>以梯度和最高值到最低值排列</returns>
  118. static public List<(Line, float, float)> IdentifyLineLSD(this Matrix gradientValueMat, Matrix gradientDirMat, float minLength = 100,
  119. int maxReturnCount = int.MaxValue, Vector LineCaptureSize = default)
  120. {
  121. if (LineCaptureSize == default)
  122. LineCaptureSize = Vector.One * minLength;
  123. var matBuffer = gradientValueMat;
  124. //var (mat, gradientMat) = tex.IdentifyEdge();
  125. //var lineMinLength = 50;
  126. var avaAngle = 60;
  127. var halfAvaAngle = avaAngle / 2;
  128. var returnLines = new List<(Line, float, float)> ();
  129. // while (mat.Element[maxIndex] != default)
  130. int count = 0;
  131. /*
  132. var minIndex = matBuffer.Element.MinIndex(matBuffer.Width * matBuffer.Height / 2);
  133. foreach (var i in minIndex)
  134. matBuffer.Element[i] = 0;/**/
  135. var maxIndex = matBuffer.Element.MaxIndex();
  136. var maxPos = matBuffer.Position(maxIndex);
  137. var maxVector = new Vector(maxPos.Item1, maxPos.Item2);
  138. while (matBuffer.Element[maxIndex] != 0 && count <= maxReturnCount)
  139. {
  140. count++;
  141. var gradient = gradientDirMat.Element[maxIndex];//梯度
  142. var lines = new List<(Line, float, float, float)>(avaAngle);
  143. Parallel.For((int)Math.Floor(gradient - halfAvaAngle), (int)Math.Ceiling(gradient + halfAvaAngle) + 1, gradientI =>//需要检测的梯度
  144. {
  145. //var gradientF = (float)gradientI / scale;
  146. if (gradientI < 0)
  147. gradientI += 360;
  148. else if (gradientI > 360)
  149. gradientI -= 360;
  150. var dir = (gradientI + 90) % 180;//需要检测的线的角度
  151. //var (line, sum) = lineSegGradient(matBuffer, gradientDirMat, gradientF, maxVector);
  152. var (line, sum) = lineSegGradient(gradientValueMat, gradientDirMat, gradientI, maxVector);
  153. if (line.A != line.B)
  154. lock (matBuffer)
  155. {
  156. lines.Add((line, line.Length, sum, gradientI));
  157. //drawLineMap.DrawLine(line, sum);
  158. }
  159. });
  160. var (line , lineLength, sum, gradientI) = lines.Max((a, b) => a.Item3.CompareTo(b.Item3));
  161. if(lineLength != 0)
  162. {
  163. matBuffer.DrawLine(line, (x, y) => 0, LineCaptureSize);
  164. }
  165. if (lineLength > minLength)
  166. returnLines.Add((line, sum, gradientI));
  167. else
  168. matBuffer.Element[maxIndex] = 0;
  169. maxIndex = matBuffer.Element.MaxIndex();
  170. maxPos = matBuffer.Position(maxIndex);
  171. maxVector = new Vector(maxPos.Item1, maxPos.Item2);
  172. }/**/
  173. returnLines.Sort((a, b) => b.Item2.CompareTo(a.Item2));
  174. return returnLines;
  175. /*
  176. var drawLineMap = new MatrixF2D(matBuffer.Width, matBuffer.Height);
  177. var returnMaxLines = returnLines.Sub(0,10);
  178. foreach (var (line, sum, gradient) in returnMaxLines)
  179. {
  180. drawLineMap.DrawLine(line, (x, y) => 1, new Vector(0, 10));
  181. //drawLineMap.DrawLine(line, (x, y) => sum / line.Length, new Vector(0, 10));
  182. Debug.Log(line);
  183. }
  184. Debug.Log(returnLines.Count);
  185. return drawLineMap;/**/
  186. }
  187. }
  188. }