using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using UnityEngine; using UnityEngine.UI; using o0.Geometry2D.Float; namespace o0.Project { public static partial class Extension { public static (Vector, float) lineSegGradient(Matrix mat, Matrix dir, float gradient, Vector start, Vector end, bool reverseXY) { int startX, endX; if (start.x < end.x) { startX = Mathf.RoundToInt(start.x) + 1; endX = Mathf.RoundToInt(end.x) + 1; } else { startX = Mathf.RoundToInt(start.x) - 1; endX = Mathf.RoundToInt(end.x) - 1; } if(startX == endX) return (new Vector(start.x, start.y), 0); var xDiff = end.x - start.x; var xToYRate = (float)(end.y - start.y) / xDiff; Func xToYFunc = (x) => (x - start.x) * xToYRate + start.y; var B1 = Mathf.RoundToInt(start.x); var B1V = mat[B1, Mathf.RoundToInt(start.y)]; var Sum1 = B1V; foreach (var x in startX.Range(endX)) { var y = xToYFunc(x); var y1 = Mathf.FloorToInt(y); var y2 = Mathf.CeilToInt(y); var y0 = y1 - 1; var y3 = y2 + 1; int C0I, C3I; int C1I, C2I; if (reverseXY) { C0I = mat.Index(y0, x); C1I = mat.Index(y1, x); C2I = mat.Index(y2, x); C3I = mat.Index(y3, x); } else { C0I = mat.Index(x, y0); C1I = mat.Index(x, y1); C2I = mat.Index(x, y2); C3I = mat.Index(x, y3); } var C0A = dir.Element[C0I]; var C1A = dir.Element[C1I]; var C2A = dir.Element[C2I]; var C3A = dir.Element[C3I]; //var CV = (y2 - y) * mat.Element[C1I] + (y - y1) * mat.Element[C2I]; var CV = o0.Max(mat.Element[C0I], mat.Element[C1I], mat.Element[C2I], mat.Element[C3I]); //var avaAngle2 = 22.5; var avaAngle = 90; var halfAvaAngle = avaAngle/2; //var avaAngle2 = 33.75; if (!(MathF.Abs(C0A - gradient) <= halfAvaAngle || MathF.Abs(C0A - 360 - gradient) <= halfAvaAngle || MathF.Abs(C0A + 360 - gradient) <= halfAvaAngle || MathF.Abs(C1A - gradient) <= halfAvaAngle || MathF.Abs(C1A - 360 - gradient) <= halfAvaAngle || MathF.Abs(C1A + 360 - gradient) <= halfAvaAngle || MathF.Abs(C2A - gradient) <= halfAvaAngle || MathF.Abs(C2A - 360 - gradient) <= halfAvaAngle || MathF.Abs(C2A + 360 - gradient) <= halfAvaAngle || MathF.Abs(C3A - gradient) <= halfAvaAngle || MathF.Abs(C3A - 360 - gradient) <= halfAvaAngle || MathF.Abs(C3A + 360 - gradient) <= halfAvaAngle)) { break; } B1 = x; Sum1 += CV; } return (new Vector(B1, xToYFunc(B1)), Sum1); } public static (Line, float) lineSegGradient(Matrix mat, Matrix dir, float gradient, Vector start) { var lineDir = (gradient + 90) % 180;//需要检测的线的角度 var line = mat.MaskLine(start, lineDir); var range = (6, 2); if (lineDir < 45 || lineDir > 135) { //var (p1, sum1) = lineSegGradient(mat, dir, gradient, start, line.A, false); //var (p2, sum2) = lineSegGradient(mat, dir, gradient, start, line.B, false); var (p1, sum1) = ZIMLineSegGradient(mat, dir, gradient, start, line.A, range, false); var (p2, sum2) = ZIMLineSegGradient(mat, dir, gradient, start, line.B, range, false); return (new Line(p1, p2), sum1 + sum2); } else { var startR = new Vector(start.y, start.x); //var (p1, sum1) = lineSegGradient(mat, dir, gradient, startR, new Vector(line.A.y, line.A.x), true); //var (p2, sum2) = lineSegGradient(mat, dir, gradient, startR, new Vector(line.B.y, line.B.x), true); var (p1, sum1) = ZIMLineSegGradient(mat, dir, gradient, startR, new Vector(line.A.y, line.A.x), range, true); var (p2, sum2) = ZIMLineSegGradient(mat, dir, gradient, startR, new Vector(line.B.y, line.B.x), range, true); return (new Line(new Vector(p1.y, p1.x), new Vector(p2.y, p2.x)), sum1 + sum2); } }/**/ /// /// List<(Line, float, float)> /// 线 线梯度和 线梯度方向0-180 /// /// 以梯度和最高值到最低值排列 static public List<(Line, float, float)> IdentifyLineLSD(this Matrix mat, float minLength = 100) { var (edge, edgeDir) = mat.IdentifyEdge(); return edge.IdentifyLineLSD(edgeDir, minLength); } /// /// List<(Line, float, float)> /// 线 线梯度和 线梯度方向0-180 /// /// 获取line后,在line的位置清空多大范围的数据,以防重复获取(比如线段长10,size为5,3,则清空3像素宽,15像素长的长方形区域) /// 以梯度和最高值到最低值排列 static public List<(Line, float, float)> IdentifyLineLSD(this Matrix gradientValueMat, Matrix gradientDirMat, float minLength = 100, int maxReturnCount = int.MaxValue, Vector LineCaptureSize = default) { if (LineCaptureSize == default) LineCaptureSize = Vector.One * minLength; var matBuffer = gradientValueMat; //var (mat, gradientMat) = tex.IdentifyEdge(); //var lineMinLength = 50; var avaAngle = 60; var halfAvaAngle = avaAngle / 2; var returnLines = new List<(Line, float, float)> (); // while (mat.Element[maxIndex] != default) int count = 0; /* var minIndex = matBuffer.Element.MinIndex(matBuffer.Width * matBuffer.Height / 2); foreach (var i in minIndex) matBuffer.Element[i] = 0;/**/ var maxIndex = matBuffer.Element.MaxIndex(); var maxPos = matBuffer.Position(maxIndex); var maxVector = new Vector(maxPos.Item1, maxPos.Item2); while (matBuffer.Element[maxIndex] != 0 && count <= maxReturnCount) { count++; var gradient = gradientDirMat.Element[maxIndex];//梯度 var lines = new List<(Line, float, float, float)>(avaAngle); Parallel.For((int)Math.Floor(gradient - halfAvaAngle), (int)Math.Ceiling(gradient + halfAvaAngle) + 1, gradientI =>//需要检测的梯度 { //var gradientF = (float)gradientI / scale; if (gradientI < 0) gradientI += 360; else if (gradientI > 360) gradientI -= 360; var dir = (gradientI + 90) % 180;//需要检测的线的角度 //var (line, sum) = lineSegGradient(matBuffer, gradientDirMat, gradientF, maxVector); var (line, sum) = lineSegGradient(gradientValueMat, gradientDirMat, gradientI, maxVector); if (line.A != line.B) lock (matBuffer) { lines.Add((line, line.Length, sum, gradientI)); //drawLineMap.DrawLine(line, sum); } }); var (line , lineLength, sum, gradientI) = lines.Max((a, b) => a.Item3.CompareTo(b.Item3)); if(lineLength != 0) { matBuffer.DrawLine(line, (x, y) => 0, LineCaptureSize); } if (lineLength > minLength) returnLines.Add((line, sum, gradientI)); else matBuffer.Element[maxIndex] = 0; maxIndex = matBuffer.Element.MaxIndex(); maxPos = matBuffer.Position(maxIndex); maxVector = new Vector(maxPos.Item1, maxPos.Item2); }/**/ returnLines.Sort((a, b) => b.Item2.CompareTo(a.Item2)); return returnLines; /* var drawLineMap = new MatrixF2D(matBuffer.Width, matBuffer.Height); var returnMaxLines = returnLines.Sub(0,10); foreach (var (line, sum, gradient) in returnMaxLines) { drawLineMap.DrawLine(line, (x, y) => 1, new Vector(0, 10)); //drawLineMap.DrawLine(line, (x, y) => sum / line.Length, new Vector(0, 10)); Debug.Log(line); } Debug.Log(returnLines.Count); return drawLineMap;/**/ } } }