using o0.Geometry2D.Float; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Unity.VisualScripting; using UnityEngine; using UnityEngine.Internal; namespace ZIM.Unity { public static partial class Extension { public static Vector2 UnityVector(this Vector v) { return new Vector2(v.x, v.y); } public static Vector o0Vector(this Vector2 v) { return new Vector(v.x, v.y); } public static UnityEngine.Color UnityColor(this o0.Color c) { return new UnityEngine.Color(c.r, c.g, c.b, c.a); } public static o0.Color o0Color(this UnityEngine.Color c) { return new o0.Color(c.r, c.g, c.b, c.a); } public static Color RGBMutiply(this UnityEngine.Color c, float multiplier) { return new Color(c.r * multiplier, c.g * multiplier, c.b * multiplier, c.a); } public static Vector2 Size(this Texture tex) => new Vector2(tex.width, tex.height); private static Dictionary colorNames = new Dictionary() { { Color.red, "Red" }, { Color.green, "Green" }, { Color.blue, "Blue" }, { Color.black, "Black" }, { Color.white, "White" }, { Color.yellow, "Yellow" }, { Color.cyan, "Cyan" }, { Color.magenta, "Magenta" }, // Add more predefined colors here }; public static string GetColorName(this UnityEngine.Color c) { if (colorNames.TryGetValue(c, out var name)) return name; return c.ToString(); } public static string GetColorName(this UnityEngine.Color? c) { if (c == null) return "null"; return c.Value.GetColorName(); } public static float Brightness(this Color c) { return 0.59f * c.r + 0.3f * c.r + 0.11f * c.r; // 红色为主 } // 转换为整数再计算 public static int Brightness(this Color c, int colorBits) { colorBits -= 1; int r = (int)(c.r * colorBits); int g = (int)(c.g * colorBits); int b = (int)(c.b * colorBits); return (int)(0.59f * r + 0.3f * g + 0.11f * b); // 红色为主 } public static Texture2D Merge(this Texture2D a, Texture2D b) { if (a.width != b.width || a.height != b.height) throw new InvalidOperationException("尺寸不同无法合并texture"); var pixel0 = a.GetPixels(); var pixel1 = b.GetPixels(); for (int i = 0; i < pixel0.Length; i++) pixel0[i] += pixel1[i]; var texAdd = new Texture2D(a.width, a.height); texAdd.SetPixels(pixel0); texAdd.Apply(); return texAdd; } // 像素坐标映射到Unity局部坐标 public static Vector2 pixelToLocalPosition_AnchorCenter(this Vector2 pixel, Vector2 size, Rect dstRect) { var xp = pixel.x / size.x - 0.5f; var yp = pixel.y / size.y - 0.5f; //var origin = rawImage.anchoredPosition; return new Vector2(dstRect.width * xp, dstRect.height * yp); } public static Vector2 pixelToLocalPosition_AnchorCenter(this Vector pixel, Vector size, Rect dstRect) { var xp = pixel.x / size.x - 0.5f; var yp = pixel.y / size.y - 0.5f; //var origin = rawImage.anchoredPosition; return new Vector2(dstRect.width * xp, dstRect.height * yp); } // Unity局部坐标转回像素坐标 public static Vector2 localPositionToPixel_AnchorCenter(this Vector2 localPosition, Vector2 size, Rect dstRect) { var xp = localPosition.x / dstRect.width + 0.5f; var yp = localPosition.y / dstRect.height + 0.5f; return new Vector2(xp * size.x, yp * size.y); } // 像素坐标映射到Unity局部坐标 public static Vector2 pixelToLocalPosition_AnchorCenter(this Vector2 pixel, o0.Geometry2D.Vector size, Rect dstRect) { var xp = pixel.x / size.x - 0.5f; var yp = pixel.y / size.y - 0.5f; //var origin = rawImage.anchoredPosition; return new Vector2(dstRect.width * xp, dstRect.height * yp); } public static Vector2 pixelToLocalPosition_AnchorLeftBottom(this Vector2 pixel, o0.Geometry2D.Vector size, Rect dstRect) { var xp = pixel.x / size.x; var yp = pixel.y / size.y; //var origin = rawImage.anchoredPosition; return new Vector2(dstRect.width * xp, dstRect.height * yp); } public static float DegreeToXAxis(this Vector2 v) { var a = v.x > 0 ? Math.Atan(v.y / v.x) * 180 / Math.PI : 180 + Math.Atan(v.y / v.x) * 180 / Math.PI; a = a < 0 ? 360 + a : a; return (float)a; } public static Texture2D zimAutoLightSimple(this WebCamTexture texture) { var pixel = texture.GetPixels(); return zimAutoLightSimple(pixel, texture.width, texture.height); } public static Texture2D zimAutoLightSimple(this Texture2D texture) { var pixel = texture.GetPixels(); return zimAutoLightSimple(pixel, texture.width, texture.height); } public static Vector2 Size(this Texture2D texture) { return new Vector2(texture.width, texture.height); } // 亮点放大到1 public static Texture2D zimAutoLightSpot(this WebCamTexture texture) { var pixel = texture.GetPixels(); float[] brightness = new float[pixel.Length]; Parallel.For(0, pixel.Length, (i) => brightness[i] = pixel[i].Brightness()); var max = Enumerable.Max(brightness); var scale = max >= 0.5f ? 1 / max : 1.3f; // 设个阈值 0.5 Parallel.For(0, pixel.Length, (i) => pixel[i] = pixel[i].RGBMutiply(scale)); var tex = new Texture2D(texture.width, texture.height); tex.SetPixels(pixel); tex.Apply(); return tex; } // 效率高,效果一般,benny写的效果更好 public static Texture2D zimAutoLightSimple(this Color[] pixel, int width, int height) { Color[] p = new Color[pixel.Length]; var brightness256 = new int[256]; for (int i = 0; i < width / 7; i++) // 间隔采样,得到256色彩下的直方图 { for (int j = 0; j < height / 7; j++) { var index = j * 7 * width + i * 7; var b = pixel[index].Brightness(256); brightness256[b]++; } } var limit = (int)(width * height / 49 * 0.001f); // 取亮度大约在前0.1%的值(不取最大的因为可能会被个别亮点影响) int select = 255; for (; select >= 0; select--) { limit -= brightness256[select]; if (limit <= 0) break; } var scale = 0.85f / (select / 256f); // 找到高亮的像素,计算放大系数 //var avgBrightness = 0f; //Parallel.For(0, pixel.Length / 256, (i) => avgBrightness += pixel[i * 256].Brightness()); //avgBrightness /= pixel.Length / 256; //var scale = 1 / avgBrightness / 2f; if (float.IsInfinity(scale)) return null; Parallel.For(0, p.Length, (i) => p[i] = pixel[i].RGBMutiply(scale)); var tex = new Texture2D(width, height); tex.SetPixels(p); tex.Apply(); return tex; } public static Texture2D zimAutoLight(this WebCamTexture texture) { var pixel = texture.GetPixels(); return zimAutoLight(pixel, texture.width, texture.height, 0); } public static Texture2D zimAutoLight(this Texture2D texture, int brightness) { var pixel = texture.GetPixels(); return zimAutoLight(pixel, texture.width, texture.height, brightness); } public static Texture2D zimAutoLight(this Color[] pixel, int width, int height, [DefaultValue("0")] int brightness) { float[] p = new float[pixel.Length]; Parallel.For(0, pixel.Length, (i) => p[i] = pixel[i].Brightness()); var scale = 1 / Enumerable.Max(p) * (2 + brightness); if (float.IsInfinity(scale)) return null; Parallel.For(0, p.Length, (i) => pixel[i] = pixel[i].RGBMutiply(scale)); // 归一化 var tex = new Texture2D(width, height); tex.SetPixels(pixel); tex.Apply(); return tex; } public static Texture2D zimAutoLevelEqualization(this WebCamTexture texture, int bit = 256) { var pixel = texture.GetPixels(); float[] p = new float[pixel.Length]; Parallel.For(0, pixel.Length, (i) => p[i] = pixel[i].r); // 红通道 bit -= 1; var scale = 1 / Enumerable.Max(p); if (float.IsInfinity(scale)) return null; 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色彩 //Debug.Log(Enumerable.Max(pint) + ", " + scale); 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()); // 取密度为颜色,并归一化 UnityEngine.Color[] pixelLighted = new UnityEngine.Color[pixel.Length]; Parallel.For(0, pixel.Length, (i) => pixelLighted[i] = new UnityEngine.Color(p[i], 0, 0)); var tex = new Texture2D(texture.width, texture.height); tex.SetPixels(pixelLighted); tex.Apply(); return tex; } public static void CopyTo(this RenderTexture src, Texture2D dst) { var pre = RenderTexture.active; RenderTexture.active = src; dst.ReadPixels(new Rect(0, 0, src.width, src.height), 0, 0); dst.Apply(); RenderTexture.active = pre; } } }