PixelSpotArea_DbScan.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. using DbscanImplementation;
  2. using o0;
  3. using o0.Num;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Threading.Tasks;
  8. using Unity.VisualScripting;
  9. using UnityEngine;
  10. using ZIM.Unity;
  11. using static ScreenLocate;
  12. using Color = UnityEngine.Color;
  13. namespace ZIM
  14. {
  15. // 亮区的点用来定位(计算center),泛光区域的点用来计算radius
  16. public class PixelSpotArea_DbScan : ISpotArea
  17. {
  18. Vector2 centroid = default; // 该项目里center不可能等于0,0
  19. public Vector2 Centroid
  20. {
  21. set { centroid = value; }
  22. // 在添加完亮区之后可以调用
  23. get
  24. {
  25. if (centroid != default)
  26. return centroid;
  27. return CalculateCentroid();
  28. }
  29. }
  30. float radius = 0;
  31. public float Radius
  32. {
  33. set { radius = value; }
  34. get
  35. {
  36. if (radius != 0)
  37. return radius;
  38. return CalculateRadius();
  39. }
  40. }
  41. public Vector2 CalculateCentroid()
  42. {
  43. centroid = Vector2.zero;
  44. foreach (var p in Pixels0)
  45. {
  46. centroid += p;
  47. }
  48. return centroid /= Pixels0.Count;
  49. }
  50. public float CalculateRadius()
  51. {
  52. //var radiusDic = new Dictionary<int, float>() { { 0, 0 }, { 45, 0 }, { 90, 0 }, { 135, 0 }, { 180, 0 }, { 225, 0 }, { 270, 0 }, { 315, 0 } };
  53. var radiusDic = new float[8];
  54. foreach (var p in Pixels0)
  55. {
  56. var dir = p - Centroid;
  57. var radius = dir.magnitude;
  58. var degreeI = radius < 0.00001f ? 0 : (int)(dir.DegreeToXAxis() / 45);
  59. if (degreeI > 7) degreeI = 0; // 防止正好360度
  60. if (radius > radiusDic[degreeI])
  61. radiusDic[degreeI] = radius;
  62. }
  63. foreach (var p in Pixels1)
  64. {
  65. var dir = p - Centroid;
  66. var radius = dir.magnitude;
  67. var degreeI = radius < 0.00001f ? 0 : (int)(dir.DegreeToXAxis() / 45);
  68. if (degreeI > 7) degreeI = 0;
  69. if (radius > radiusDic[degreeI])
  70. radiusDic[degreeI] = radius;
  71. }
  72. return radius = radiusDic.Mean();
  73. }
  74. // 中心亮点
  75. public List<Vector2> Pixels0 { get; set; }
  76. // 泛光
  77. public List<Vector2> Pixels1 { get; set; }
  78. public PixelSpotArea_DbScan(IEnumerable<Vector2> points)
  79. {
  80. Pixels0 = new List<Vector2>();
  81. Pixels1 = new List<Vector2>();
  82. Pixels0.AddRange(points);
  83. }
  84. public PixelSpotArea_DbScan(List<DbscanPoint<Vector2>> points)
  85. {
  86. Pixels0 = new List<Vector2>();
  87. Pixels1 = new List<Vector2>();
  88. Pixels0.AddRange(points.Select((i) => i.Point));
  89. }
  90. // 中心亮点
  91. public void Add0(Vector2 p)
  92. {
  93. Pixels0.Add(p);
  94. }
  95. // 泛光
  96. public void Add1(Vector2 point)
  97. {
  98. Pixels1.Add(point);
  99. }
  100. public void Clear()
  101. {
  102. Pixels0.Clear();
  103. Pixels1.Clear();
  104. }
  105. public float TotalBrightness(Color[] pixels, Func<int, int, int> Vector2ToIndex, int outer_size = 3)
  106. {
  107. (int x, int y) rectMin = ((int)(Centroid.x - Radius - outer_size), (int)(Centroid.y - Radius - outer_size));
  108. (int x, int y) rectMax = ((int)(Centroid.x + Radius + outer_size), (int)(Centroid.y + Radius + outer_size));
  109. var total = 0f;
  110. Parallel.For(rectMin.x, rectMax.x, (i) =>
  111. {
  112. var t = 0;
  113. for (int j = rectMin.y; j < rectMax.y; j++)
  114. {
  115. var index = Vector2ToIndex(i, j);
  116. var b = pixels[index].Brightness(64);
  117. t += b;
  118. }
  119. lock (InfraredLocate.locker)
  120. {
  121. total += t;
  122. }
  123. });
  124. //total /= (rectMax.y - rectMin.y) * (rectMax.x - rectMin.x);
  125. return total;
  126. }
  127. }
  128. }