| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- using o0.Geometry;
- 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<float, float> 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);
- }
- }/**/
- /// <summary>
- /// List<(Line, float, float)>
- /// 线 线梯度和 线梯度方向0-180
- /// </summary>
- /// <returns>以梯度和最高值到最低值排列</returns>
- static public List<(Line, float, float)> IdentifyLineLSD(this Matrix mat, float minLength = 100)
- {
- var (edge, edgeDir) = mat.IdentifyEdge();
- return edge.IdentifyLineLSD(edgeDir, minLength);
- }
- /// <summary>
- /// List<(Line, float, float)>
- /// 线 线梯度和 线梯度方向0-180
- /// </summary>
- /// <param name="LineCaptureSize">获取line后,在line的位置清空多大范围的数据,以防重复获取(比如线段长10,size为5,3,则清空3像素宽,15像素长的长方形区域)</param>
- /// <returns>以梯度和最高值到最低值排列</returns>
- 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;/**/
- }
- }
- }
|