using System.Collections; using System.Collections.Generic; using UnityEngine; using o0.Geometry2D; using System; using UnityEngine.UIElements; using o0.Num; using Unity.VisualScripting; using System.Threading.Tasks; using System.Linq; using o0; using o0.Project; namespace ZIM.Image { // 灰度图处理(float) public class ImgProcessGray { int width, height; float[] pixels; public float this[int index] { get { if (index >= 0 && index < pixels.Count()) return pixels[index]; else return 0f; } } public float this[int i, int j] => this[i + j * width]; public ImgProcessGray(float[] pixels, int width, int height) { if (pixels.Length != width * height) throw new ArgumentException("Input array length must be equal to width * height"); this.width = width; this.height = height; this.pixels = pixels; } public (float[] p, int w, int h) FindLines() //public List> FindLines() { int kernel_size = 3; int half_size = kernel_size / 2; int conv_width = width - kernel_size + 1; int conv_height = height - kernel_size + 1; var edgeArray = new ConvEdge[conv_width * conv_height]; var result = new float[conv_width * conv_height]; Parallel.For(0, conv_width, (i) => //for (int i = 0; i < conv_width; i++) { for (int j = 0; j < conv_height; j++) { var e = new ConvEdge(this, (i + half_size, j + half_size), kernel_size); edgeArray[i + j * conv_width] = e; result[i + j * conv_width] = e.Variance; } }); //return default; LevelEqualization(result, 10240); return (result, conv_width, conv_height); } void SigmodAdjust(float[] p) { var mean = p.Mean(); Parallel.For(0, p.Length, (i) => { p[i] = 1 / (1 + (float)Math.Exp(-p[i]/mean)); }); } void LevelAdjust(float[] p) { var max = p.Max(); var scale = 1 / (float)Math.Sqrt(max); Parallel.For(0, p.Length, (i) => { p[i] = (float)Math.Sqrt(p[i]) * scale; }); //var scale = 1 / max; //Parallel.For(0, p.Length, (i) => //{ // p[i] = Math.Min(p[i] * scale, 1); //}); } void LevelEqualization(float[] p, int bit = 256) { bit -= 1; var scale = 1 / p.Max(); Parallel.For(0, p.Length, (i) => p[i] *= scale); // 归一化 int[] pint = new int[p.Length]; Parallel.For(0, p.Length, i => pint[i] = (int)(p[i] * bit)); // 映射到256色彩 int[] H = new int[bit+1]; for (int i = 0; i < p.Length; i++) H[pint[i]]++; float[] HF = new float[bit+1]; for (int i = 0; i <= bit; i++) HF[i] = H[i] / (float)p.Length; // 概率 float[] D = new float[bit + 1]; float temp = 0; for (int i = 1; i <= bit; i++) // 不取颜色为0的概率 { temp += HF[i]; D[i] = temp; // 累计密度 } Parallel.For(0, p.Length, i => p[i] = D[pint[i]] / D.Last()); // 去密度为颜色,并归一化 } } public class ConvEdge { public Vector EdgePoint; public Vector EdgeDirection; public float Variance; public int noiseCount; // kernel_size应是奇数,偶数没测试 public ConvEdge(ImgProcessGray imgGray, (int, int) pixel, int kernel_size, int scale = 1) { EdgePoint = new Vector(pixel.Item1, pixel.Item2); noiseCount = 0; var convList = new List<(float, Vector)>(); var mean = 0f; for (int i = pixel.Item1 - kernel_size / 2 * scale; i <= pixel.Item1 + kernel_size / 2 * scale; i += scale) { for (int j = pixel.Item2 - kernel_size / 2 * scale; j <= pixel.Item2 + kernel_size / 2 * scale; j += scale) { var value = imgGray[i, j]; convList.Add((value, new Vector(i, j))); mean += value; } } mean /= convList.Count; convList.Sort((a, b) => a.Item1.CompareTo(b.Item1)); var vMean0 = Vector.Zero; // 暗区 var vMean1 = Vector.Zero; // 明区 for (int k = 0; k < convList.Count / 2; k++) { Variance += (float)Math.Pow((convList[k].Item1 - mean), 2) / convList.Count; vMean0 += convList[k].Item2; if (AreaOfPoint(convList[k].Item2) == 1) noiseCount++; } vMean0 /= convList.Count / 2; for (int k = convList.Count / 2; k < convList.Count; k++) { Variance += (float)Math.Pow((convList[k].Item1 - mean), 2) / convList.Count; vMean1 += convList[k].Item2; if (AreaOfPoint(convList[k].Item2) == 0) noiseCount++; } vMean1 /= convList.Count - convList.Count / 2; GetEdgeDirection(vMean0, vMean1); } // 返回 1 在明区,返回 0 在暗区, -1 在边界上 public int AreaOfPoint(Vector v) { var ev = v - EdgePoint; var dot = ev.x * EdgeDirection.y - ev.y * EdgeDirection.x; if (dot == 0) return -1; return dot < 0 ? 1 : 0; } void GetEdgeDirection(Vector v0, Vector v1) // v0 是暗部平均点,v1 是亮部平均点 { var dir = v1 - v0; EdgeDirection = new Vector(dir.y, -dir.x); } //public void ConvEdge(int[] pixels, Vector2Int vec, int kernel_size, int scale) //{ // var sum = 0f; // for (int i = vec.x - kernel_size / 2 * scale; i < vec.x + kernel_size / 2 * scale; i += scale) // { // for (int j = vec.y - kernel_size / 2 * scale; j < vec.y + kernel_size / 2 * scale; j += scale) // { // var index2 = webCamera.cameraInfo.Vector2ToIndex(i, j); // if (index2 > 0 && index2 < pixels.Length) // 超出边缘不计算 // sum += pixels[index2]; // } // } // return sum / kernel_size / kernel_size; //} } }