o0IdentifyLineLSD.cs 9.2 KB

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