PixelSpotArea.cs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. using o0;
  2. using o0.Num;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Threading.Tasks;
  7. using UnityEngine;
  8. using Color = UnityEngine.Color;
  9. namespace ZIM
  10. {
  11. public class PixelSpotArea
  12. {
  13. public static int gridLength0 = 6; // 亮区
  14. public static int gridLength1 = 20; // 边缘泛光
  15. public static (int x, int y) GetGrid0(Vector2 v)
  16. {
  17. var m = (int)(v.x / gridLength0);
  18. var n = (int)(v.y / gridLength0);
  19. return (m, n);
  20. }
  21. public static (int x, int y) GetGrid1(Vector2 v)
  22. {
  23. var m = (int)(v.x / gridLength1);
  24. var n = (int)(v.y / gridLength1);
  25. return (m, n);
  26. }
  27. // 亮点聚类到区域
  28. public static List<PixelSpotArea> Cluster(List<Vector2> spotPoint, List<Vector2> brightPoint, Func<Vector2, bool> PointFilter = null)
  29. {
  30. var spotArea = new List<PixelSpotArea>();
  31. for (int i = 0; i < spotPoint.Count; i++)
  32. {
  33. var p = spotPoint[i];
  34. if (PointFilter != null && !PointFilter(p)) // 筛选是否在屏幕内
  35. continue;
  36. var grid = PixelSpotArea.GetGrid0(p);
  37. var join = new SortedList<int, PixelSpotArea>();
  38. for (int j = 0; j < spotArea.Count; j++)
  39. {
  40. var area = spotArea[j];
  41. if (area.Include0(grid))
  42. join.Add(j, area);
  43. }
  44. if (join.Count == 0)
  45. spotArea.Add(new PixelSpotArea(p, grid, PixelSpotArea.GetGrid1(p)));
  46. else if (join.Count == 1)
  47. join.First().Value.Join(p, grid, PixelSpotArea.GetGrid1(p));
  48. else
  49. {
  50. var combine = new PixelSpotArea(join.Values);
  51. combine.Join(p, grid, PixelSpotArea.GetGrid1(p));
  52. spotArea.Add(combine);
  53. for (int j = join.Count - 1; j >= 0; j--)
  54. spotArea.RemoveAt(join.ElementAt(j).Key);
  55. }
  56. }
  57. return spotArea;
  58. }
  59. Vector2 center = default; // 该项目里center不可能等于0,0
  60. public Vector2 Center
  61. {
  62. get
  63. {
  64. if (center != default)
  65. return center;
  66. foreach (var p in Pixels0)
  67. {
  68. center += p;
  69. }
  70. return center /= Pixels0.Count;
  71. }
  72. }
  73. float radius = 0;
  74. public float Radius
  75. {
  76. set
  77. {
  78. radius = value;
  79. }
  80. get
  81. {
  82. if (radius != 0)
  83. return radius;
  84. //var radiusDic = new Dictionary<int, float>() { { 0, 0 }, { 45, 0 }, { 90, 0 }, { 135, 0 }, { 180, 0 }, { 225, 0 }, { 270, 0 }, { 315, 0 } };
  85. var radiusDic = new float[8];
  86. foreach (var p in Pixels0)
  87. {
  88. var dir = p - Center;
  89. var radius = dir.magnitude;
  90. var degreeI = radius < 0.00001f ? 0 : (int)(dir.DegreeToXAxis() / 45);
  91. if (radius > radiusDic[degreeI])
  92. radiusDic[degreeI] = radius;
  93. }
  94. foreach (var p in Pixels1)
  95. {
  96. var dir = p - Center;
  97. var radius = dir.magnitude;
  98. var degreeI = radius < 0.00001f ? 0 : (int)(dir.DegreeToXAxis() / 45);
  99. if (radius > radiusDic[degreeI])
  100. radiusDic[degreeI] = radius;
  101. }
  102. return radius = radiusDic.Mean();
  103. }
  104. }
  105. public List<Vector2> Pixels0;
  106. public List<Vector2> Pixels1;
  107. HashSet<(int, int)> grids0;
  108. HashSet<(int, int)> grids1;
  109. public PixelSpotArea(Vector2 location, (int, int) grid0, (int, int) grid1)
  110. {
  111. Pixels0 = new List<Vector2>(1000); // 预估的初始容量
  112. Pixels1 = new List<Vector2>(5000);
  113. this.grids0 = new HashSet<(int, int)>(); // hashset如果设置了太大的容量会降低效率
  114. this.grids1 = new HashSet<(int, int)>();
  115. Join(location, grid0, grid1);
  116. }
  117. public PixelSpotArea(IList<PixelSpotArea> areas)
  118. {
  119. Pixels0 = new List<Vector2>(1000);
  120. Pixels1 = new List<Vector2>(5000);
  121. grids0 = new HashSet<(int, int)>();
  122. grids1 = new HashSet<(int, int)>();
  123. foreach (var a in areas)
  124. {
  125. Pixels0.AddRange(a.Pixels0);
  126. grids0.AddRange(a.grids0);
  127. grids1.AddRange(a.grids1);
  128. //Center += a.Center * a.SpotPointCount;
  129. //SpotPointCount += a.SpotPointCount;
  130. }
  131. //Center /= SpotPointCount;
  132. }
  133. public bool Include0((int, int) grid) => grids0.Contains(grid);
  134. public bool Include1((int, int) grid) => grids1.Contains(grid);
  135. public void Join(Vector2 point) => Join(point, GetGrid0(point), GetGrid1(point));
  136. public void Join(Vector2 point, (int x, int y) grid0, (int x, int y) grid1)
  137. {
  138. Pixels0.Add(point);
  139. //SpotPointCount++;
  140. //Center += (point - Center) / SpotPointCount;
  141. grids0.AddRange(new (int, int)[]
  142. {
  143. (grid0.x + -1, grid0.y + 0) , (grid0.x + 1 , grid0.y + 0),
  144. (grid0.x + 1, grid0.y + -1) , (grid0.x + -1, grid0.y + 1),
  145. (grid0.x + 0, grid0.y + -1) , (grid0.x + 0 , grid0.y + 1),
  146. (grid0.x + -1, grid0.y + -1) , (grid0.x + 1 , grid0.y + 1),
  147. grid0
  148. });
  149. grids1.AddRange(new (int, int)[]
  150. {
  151. (grid1.x + -1, grid1.y + 0) , (grid1.x + 1 , grid1.y + 0),
  152. (grid1.x + 1, grid1.y + -1) , (grid1.x + -1, grid1.y + 1),
  153. (grid1.x + 0, grid1.y + -1) , (grid1.x + 0 , grid1.y + 1),
  154. (grid1.x + -1, grid1.y + -1) , (grid1.x + 1 , grid1.y + 1),
  155. grid1
  156. });
  157. }
  158. // 不再join之后,才可以用add添加周围泛光
  159. public void Add(Vector2 point)
  160. {
  161. //var radius = (point - Center).LengthManhattan();
  162. //if (radius > MaxRadius)
  163. // MaxRadius = radius;
  164. Pixels1.Add(point);
  165. //var radius = (point - Center).LengthManhattan();
  166. //if (radius > MaxRadius)
  167. // MaxRadius = radius;
  168. }
  169. public float TotalBrightness(Color[] pixels, Func<int, int, int> Vector2ToIndex, int outer_size = 3)
  170. {
  171. (int x, int y) rectMin = ((int)(Center.x - Radius - outer_size), (int)(Center.y - Radius - outer_size));
  172. (int x, int y) rectMax = ((int)(Center.x + Radius + outer_size), (int)(Center.y + Radius + outer_size));
  173. var total = 0f;
  174. Parallel.For(rectMin.x, rectMax.x, (i) =>
  175. {
  176. var t = 0;
  177. for (int j = rectMin.y; j < rectMax.y; j++)
  178. {
  179. var index = Vector2ToIndex(i, j);
  180. var b = pixels[index].Brightness(64);
  181. t += b;
  182. }
  183. lock (InfraredLocate.locker)
  184. {
  185. total += t;
  186. }
  187. });
  188. //total /= (rectMax.y - rectMin.y) * (rectMax.x - rectMin.x);
  189. return total;
  190. }
  191. }
  192. }