FindLines.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using o0.Geometry2D;
  5. using System;
  6. using UnityEngine.UIElements;
  7. using o0.Num;
  8. using Unity.VisualScripting;
  9. using System.Threading.Tasks;
  10. using System.Linq;
  11. using o0;
  12. using o0.Project;
  13. namespace ZIM.Image
  14. {
  15. // 灰度图处理(float)
  16. public class ImgProcessGray
  17. {
  18. int width, height;
  19. float[] pixels;
  20. public float this[int index]
  21. {
  22. get
  23. {
  24. if (index >= 0 && index < pixels.Count())
  25. return pixels[index];
  26. else
  27. return 0f;
  28. }
  29. }
  30. public float this[int i, int j] => this[i + j * width];
  31. public ImgProcessGray(float[] pixels, int width, int height)
  32. {
  33. if (pixels.Length != width * height)
  34. throw new ArgumentException("Input array length must be equal to width * height");
  35. this.width = width;
  36. this.height = height;
  37. this.pixels = pixels;
  38. }
  39. public (float[] p, int w, int h) FindLines()
  40. //public List<o0.Geometry.Line<float>> FindLines()
  41. {
  42. int kernel_size = 3;
  43. int half_size = kernel_size / 2;
  44. int conv_width = width - kernel_size + 1;
  45. int conv_height = height - kernel_size + 1;
  46. var edgeArray = new ConvEdge[conv_width * conv_height];
  47. var result = new float[conv_width * conv_height];
  48. Parallel.For(0, conv_width, (i) =>
  49. //for (int i = 0; i < conv_width; i++)
  50. {
  51. for (int j = 0; j < conv_height; j++)
  52. {
  53. var e = new ConvEdge(this, (i + half_size, j + half_size), kernel_size);
  54. edgeArray[i + j * conv_width] = e;
  55. result[i + j * conv_width] = e.Variance;
  56. }
  57. });
  58. //return default;
  59. LevelEqualization(result, 10240);
  60. return (result, conv_width, conv_height);
  61. }
  62. void SigmodAdjust(float[] p)
  63. {
  64. var mean = p.Mean();
  65. Parallel.For(0, p.Length, (i) =>
  66. {
  67. p[i] = 1 / (1 + (float)Math.Exp(-p[i]/mean));
  68. });
  69. }
  70. void LevelAdjust(float[] p)
  71. {
  72. var max = p.Max();
  73. var scale = 1 / (float)Math.Sqrt(max);
  74. Parallel.For(0, p.Length, (i) =>
  75. {
  76. p[i] = (float)Math.Sqrt(p[i]) * scale;
  77. });
  78. //var scale = 1 / max;
  79. //Parallel.For(0, p.Length, (i) =>
  80. //{
  81. // p[i] = Math.Min(p[i] * scale, 1);
  82. //});
  83. }
  84. void LevelEqualization(float[] p, int bit = 256)
  85. {
  86. bit -= 1;
  87. var scale = 1 / p.Max();
  88. Parallel.For(0, p.Length, (i) => p[i] *= scale); // 归一化
  89. int[] pint = new int[p.Length];
  90. Parallel.For(0, p.Length, i => pint[i] = (int)(p[i] * bit)); // 映射到256色彩
  91. int[] H = new int[bit+1];
  92. for (int i = 0; i < p.Length; i++)
  93. H[pint[i]]++;
  94. float[] HF = new float[bit+1];
  95. for (int i = 0; i <= bit; i++)
  96. HF[i] = H[i] / (float)p.Length; // 概率
  97. float[] D = new float[bit + 1];
  98. float temp = 0;
  99. for (int i = 1; i <= bit; i++) // 不取颜色为0的概率
  100. {
  101. temp += HF[i];
  102. D[i] = temp; // 累计密度
  103. }
  104. Parallel.For(0, p.Length, i => p[i] = D[pint[i]] / D.Last()); // 去密度为颜色,并归一化
  105. }
  106. }
  107. public class ConvEdge
  108. {
  109. public Vector<float> EdgePoint;
  110. public Vector<float> EdgeDirection;
  111. public float Variance;
  112. public int noiseCount;
  113. // kernel_size应是奇数,偶数没测试
  114. public ConvEdge(ImgProcessGray imgGray, (int, int) pixel, int kernel_size, int scale = 1)
  115. {
  116. EdgePoint = new Vector<float>(pixel.Item1, pixel.Item2);
  117. noiseCount = 0;
  118. var convList = new List<(float, Vector<float>)>();
  119. var mean = 0f;
  120. for (int i = pixel.Item1 - kernel_size / 2 * scale; i <= pixel.Item1 + kernel_size / 2 * scale; i += scale)
  121. {
  122. for (int j = pixel.Item2 - kernel_size / 2 * scale; j <= pixel.Item2 + kernel_size / 2 * scale; j += scale)
  123. {
  124. var value = imgGray[i, j];
  125. convList.Add((value, new Vector<float>(i, j)));
  126. mean += value;
  127. }
  128. }
  129. mean /= convList.Count;
  130. convList.Sort((a, b) => a.Item1.CompareTo(b.Item1));
  131. var vMean0 = Vector<float>.Zero; // 暗区
  132. var vMean1 = Vector<float>.Zero; // 明区
  133. for (int k = 0; k < convList.Count / 2; k++)
  134. {
  135. Variance += (float)Math.Pow((convList[k].Item1 - mean), 2) / convList.Count;
  136. vMean0 += convList[k].Item2;
  137. if (AreaOfPoint(convList[k].Item2) == 1)
  138. noiseCount++;
  139. }
  140. vMean0 /= convList.Count / 2;
  141. for (int k = convList.Count / 2; k < convList.Count; k++)
  142. {
  143. Variance += (float)Math.Pow((convList[k].Item1 - mean), 2) / convList.Count;
  144. vMean1 += convList[k].Item2;
  145. if (AreaOfPoint(convList[k].Item2) == 0)
  146. noiseCount++;
  147. }
  148. vMean1 /= convList.Count - convList.Count / 2;
  149. GetEdgeDirection(vMean0, vMean1);
  150. }
  151. // 返回 1 在明区,返回 0 在暗区, -1 在边界上
  152. public int AreaOfPoint(Vector<float> v)
  153. {
  154. var ev = v - EdgePoint;
  155. var dot = ev.x * EdgeDirection.y - ev.y * EdgeDirection.x;
  156. if (dot == 0)
  157. return -1;
  158. return dot < 0 ? 1 : 0;
  159. }
  160. void GetEdgeDirection(Vector<float> v0, Vector<float> v1) // v0 是暗部平均点,v1 是亮部平均点
  161. {
  162. var dir = v1 - v0;
  163. EdgeDirection = new Vector<float>(dir.y, -dir.x);
  164. }
  165. //public void ConvEdge(int[] pixels, Vector2Int vec, int kernel_size, int scale)
  166. //{
  167. // var sum = 0f;
  168. // for (int i = vec.x - kernel_size / 2 * scale; i < vec.x + kernel_size / 2 * scale; i += scale)
  169. // {
  170. // for (int j = vec.y - kernel_size / 2 * scale; j < vec.y + kernel_size / 2 * scale; j += scale)
  171. // {
  172. // var index2 = webCamera.cameraInfo.Vector2ToIndex(i, j);
  173. // if (index2 > 0 && index2 < pixels.Length) // 超出边缘不计算
  174. // sum += pixels[index2];
  175. // }
  176. // }
  177. // return sum / kernel_size / kernel_size;
  178. //}
  179. }
  180. }