FindLines.cs 6.8 KB

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