| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- using o0.Geometry2D.Float;
- using o0.Num;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using UnityEngine;
- namespace o0.Project
- {
- // 猜测屏幕内部的线,用于识别屏幕的黑边
- // 大于阈值则猜测是Line,但是这个类不考虑梯度,外部仍需结合梯度评估
- public class InterLineGuess
- {
- public static float isLineThreshold = 1.0f;
- // 记录分段的线段数据
- class SubLineData
- {
- public List<float> DataList;
- public List<float> DiffList; // 数据与平均值的差
- // 幅度
- float diffExtent = -1;
- float dataExtent = -1;
- public SubLineData(float data, float diff)
- {
- DataList = new List<float> { data };
- DiffList = new List<float> { diff };
- }
- public void Add(float data, float diff)
- {
- DataList.Add(data);
- DiffList.Add(diff);
- }
- // 得到差异的幅度
- //public float GetDiffExtent()
- //{
- // if (diffExtent == -1)
- // {
- // var sum = 0.0f;
- // foreach (var i in DiffList)
- // sum += i * i;
- // return diffExtent = sum / DiffList.Count;
- // }
- // else
- // return diffExtent;
- //}
- // 得到数据的幅度(和0比)
- public float GetDataExtent()
- {
- if (dataExtent == -1)
- {
- var sum = 0.0f;
- foreach (var i in DataList)
- sum += i * i;
- return dataExtent = sum / DataList.Count;
- }
- else
- return dataExtent;
- }
- }
- public List<Matrix> ScreenLocateMatList;
- public float GradientLength;
- public float MinLineLength;
- public InterLineGuess(List<Matrix> screenLocateMatList, float gradientLength, float minLineLength)
- {
- ScreenLocateMatList = screenLocateMatList;
- GradientLength = gradientLength;
- MinLineLength = minLineLength;
- }
- // 猜测是直线返回true
- public bool GuessIsLine(LineIdentified line) => Guess(line) > isLineThreshold;
- // 越大越可能是直线
- public float Guess(LineIdentified line)
- {
- var dir = (line.Line.B - line.Line.A).Normalized;
- var vertical = new Vector(-dir.y, dir.x) * (GradientLength / 2);
- var verticalNormal = vertical.Normalized;
- float lineABStep = MinLineLength / 15;
- float lineGuessStart;
- float lineGuessEnd;
- if (line.Line.Length > 2 * MinLineLength)
- {
- lineGuessStart = 7.5f * lineABStep;
- lineGuessEnd = line.Line.Length - 7.5f * lineABStep; // 线的两端不计算
- }
- else
- {
- lineGuessStart = lineABStep;
- lineGuessEnd = line.Line.Length - lineABStep;
- }
- var gradData = new List<float>(); // 直线两侧梯度的平均值,垂直于直线变化
- var a0 = line.Line.A - vertical;
- var gradStep = 1.5f;
- for (float n = 0; n < GradientLength; n += gradStep)
- {
- var aN = a0 + verticalNormal * n;
- var gradThisLine = new List<float>();
- for (float i = lineGuessStart; i <= lineGuessEnd; i += lineABStep)
- {
- var point = aN + dir * i;
- gradThisLine.Add(ScreenLocateMatList[line.Batch][(int)point.x, (int)point.y]);
- }
- gradData.Add(gradThisLine.Mean());
- }
- //Debug.Log(line.Gradient + ", " + line.GradientDegree + ", " + gradData.ToJson());
- if (gradData.Count <= 3)
- return 400;
- var gradChangeData = new List<float>();
- for (int j = 1; j < gradData.Count; j++)
- gradChangeData.Add(Math.Abs(gradData[j] - gradData[j - 1]));
- var meanChange = gradChangeData.Mean();
- var diff = gradChangeData[0] - meanChange;
- var subList = new List<SubLineData>() { new SubLineData(gradChangeData[0], diff) };
- for (int i = 1; i < gradChangeData.Count; i++)
- {
- var newDiff = gradChangeData[i] - meanChange;
- if ((newDiff <= 0 && diff <= 0) || (newDiff > 0 && diff > 0)) // 同号,是一个分段
- subList.Last().Add(gradChangeData[i], newDiff);
- else
- subList.Add(new SubLineData(gradChangeData[i], newDiff));
- diff = newDiff;
- }
- int maxSubDataIndex = subList.MaxIndex((a, b) => a.GetDataExtent().CompareTo(b.GetDataExtent())); // 找到分段里和平均数差异最大的分段
- //TODO 这里要不要考虑加个阈值,过滤掉梯度太小的线条? -----------------------------------
- if (subList.Count < 3)
- maxSubDataIndex = -1; // ≥3的时候把SubDataExtent最高的这段剔除掉再计算
- var lineGuessExtent = 0.0f;
- for (int i = 0; i < subList.Count; i++)
- {
- if (i != maxSubDataIndex)
- lineGuessExtent += subList[i].GetDataExtent();
- }
- if (maxSubDataIndex == -1)
- lineGuessExtent /= subList.Count;
- else
- lineGuessExtent /= subList.Count - 1;
- lineGuessExtent = (float)Math.Sqrt(lineGuessExtent);
- var countFactor = -0.002f * Math.Abs(subList.Count - 3) + 0.015f; // 3时最大
- if (ScreenLocate.Main.DebugOnZIMDemo)
- Debug.Log("line.Index" + line.ScreenLineIndex + ", maxDiffIndex: " + maxSubDataIndex + ", sub count: " + subList.Count + ", lineGuess: " + (1 - lineGuessExtent + countFactor));
- return 1 - lineGuessExtent + countFactor;
- }
- }
- }
|