|
@@ -8,6 +8,7 @@ using System.IO;
|
|
|
using System.Linq;
|
|
using System.Linq;
|
|
|
using System.Threading.Tasks;
|
|
using System.Threading.Tasks;
|
|
|
using UnityEngine;
|
|
using UnityEngine;
|
|
|
|
|
+using UnityEngine.UIElements;
|
|
|
using ZIM;
|
|
using ZIM;
|
|
|
using ZIM.Unity;
|
|
using ZIM.Unity;
|
|
|
|
|
|
|
@@ -17,23 +18,29 @@ namespace o0.Project
|
|
|
{
|
|
{
|
|
|
private const string TAG = "ScreenIdentification#";
|
|
private const string TAG = "ScreenIdentification#";
|
|
|
|
|
|
|
|
- //static Rect[][] LocateAreaData = new Rect[][] {
|
|
|
|
|
- // new Rect[] { new Rect(0f, 0f, 0.3f, 0.3f), new Rect(0f, 0f, 0.4f, 0.4f), new Rect(0f, 0f, 0.5f, 0.5f), new Rect(0f, 0f, 0.6f, 0.6f) },
|
|
|
|
|
- // new Rect[] { new Rect(0.7f, 0f, 0.3f, 0.3f), new Rect(0.6f, 0f, 0.4f, 0.4f), new Rect(0.5f, 0f, 0.5f, 0.5f), new Rect(0.4f, 0f, 0.6f, 0.6f) },
|
|
|
|
|
- // new Rect[] { new Rect(0f, 0.7f, 0.3f, 0.3f), new Rect(0f, 0.6f, 0.4f, 0.4f), new Rect(0f, 0.5f, 0.5f, 0.5f), new Rect(0f, 0.4f, 0.6f, 0.6f) },
|
|
|
|
|
- // new Rect[] { new Rect(0.7f, 0.7f, 0.3f, 0.3f), new Rect(0.6f, 0.6f, 0.4f, 0.4f), new Rect(0.5f, 0.5f, 0.5f, 0.5f), new Rect(0.4f, 0.4f, 0.6f, 0.6f) }
|
|
|
|
|
- //};
|
|
|
|
|
|
|
+ // LocateAreaData表示每次屏幕的色差变化的区域,可能有多次。通过设置LocateSingleStep可调整为仅识别一次色差
|
|
|
static Rect[][] LocateAreaData = new Rect[][] {
|
|
static Rect[][] LocateAreaData = new Rect[][] {
|
|
|
new Rect[] { new Rect(0f, 0f, 0.3f, 0.3f), new Rect(0f, 0f, 0.4f, 0.4f), new Rect(0f, 0f, 0.5f, 0.5f) },
|
|
new Rect[] { new Rect(0f, 0f, 0.3f, 0.3f), new Rect(0f, 0f, 0.4f, 0.4f), new Rect(0f, 0f, 0.5f, 0.5f) },
|
|
|
new Rect[] { new Rect(0.7f, 0f, 0.3f, 0.3f), new Rect(0.6f, 0f, 0.4f, 0.4f), new Rect(0.5f, 0f, 0.5f, 0.5f) },
|
|
new Rect[] { new Rect(0.7f, 0f, 0.3f, 0.3f), new Rect(0.6f, 0f, 0.4f, 0.4f), new Rect(0.5f, 0f, 0.5f, 0.5f) },
|
|
|
new Rect[] { new Rect(0f, 0.7f, 0.3f, 0.3f), new Rect(0f, 0.6f, 0.4f, 0.4f), new Rect(0f, 0.5f, 0.5f, 0.5f) },
|
|
new Rect[] { new Rect(0f, 0.7f, 0.3f, 0.3f), new Rect(0f, 0.6f, 0.4f, 0.4f), new Rect(0f, 0.5f, 0.5f, 0.5f) },
|
|
|
new Rect[] { new Rect(0.7f, 0.7f, 0.3f, 0.3f), new Rect(0.6f, 0.6f, 0.4f, 0.4f), new Rect(0.5f, 0.5f, 0.5f, 0.5f) }
|
|
new Rect[] { new Rect(0.7f, 0.7f, 0.3f, 0.3f), new Rect(0.6f, 0.6f, 0.4f, 0.4f), new Rect(0.5f, 0.5f, 0.5f, 0.5f) }
|
|
|
};
|
|
};
|
|
|
- //static bool LocateDebug = false;
|
|
|
|
|
- static bool LocateDebug = true;
|
|
|
|
|
|
|
+ //static Rect[][] LocateAreaData = new Rect[][] {
|
|
|
|
|
+ // new Rect[] { new Rect(0f, 0f, 0.3f, 0.3f), new Rect(0f, 0f, 0.4f, 0.4f), new Rect(0f, 0f, 0.5f, 0.5f), new Rect(0f, 0f, 0.6f, 0.6f) },
|
|
|
|
|
+ // new Rect[] { new Rect(0.7f, 0f, 0.3f, 0.3f), new Rect(0.6f, 0f, 0.4f, 0.4f), new Rect(0.5f, 0f, 0.5f, 0.5f), new Rect(0.4f, 0f, 0.6f, 0.6f) },
|
|
|
|
|
+ // new Rect[] { new Rect(0f, 0.7f, 0.3f, 0.3f), new Rect(0f, 0.6f, 0.4f, 0.4f), new Rect(0f, 0.5f, 0.5f, 0.5f), new Rect(0f, 0.4f, 0.6f, 0.6f) },
|
|
|
|
|
+ // new Rect[] { new Rect(0.7f, 0.7f, 0.3f, 0.3f), new Rect(0.6f, 0.6f, 0.4f, 0.4f), new Rect(0.5f, 0.5f, 0.5f, 0.5f), new Rect(0.4f, 0.4f, 0.6f, 0.6f) }
|
|
|
|
|
+ //};
|
|
|
|
|
+
|
|
|
|
|
+ //static bool LocateSingleStep = false;
|
|
|
|
|
+ static bool LocateSingleStep = true;
|
|
|
|
|
|
|
|
public Geometry2D.Vector<int> Size => ScreenLocate.Main.CameraSize;
|
|
public Geometry2D.Vector<int> Size => ScreenLocate.Main.CameraSize;
|
|
|
|
|
|
|
|
|
|
+ public QuadrilateralInCamera QuadManual;
|
|
|
|
|
+ public QuadrilateralInCamera QuadAuto; // 全自动,可以给用户选择(赋值给Screen.QuadInCamera即生效)
|
|
|
|
|
+ public QuadrilateralInCamera QuadSemiAuto; // 半自动,可以给用户选择(赋值给Screen.QuadInCamera即生效)
|
|
|
|
|
+
|
|
|
public ScreenMap Screen; // 识别到的屏幕,用于执行透视变换
|
|
public ScreenMap Screen; // 识别到的屏幕,用于执行透视变换
|
|
|
|
|
|
|
|
int capture = 0;
|
|
int capture = 0;
|
|
@@ -45,14 +52,14 @@ namespace o0.Project
|
|
|
Geometry.Vector<float>[] ScreenBlackTexture;
|
|
Geometry.Vector<float>[] ScreenBlackTexture;
|
|
|
Geometry.Vector<float>[] ScreenWhiteTexture;
|
|
Geometry.Vector<float>[] ScreenWhiteTexture;
|
|
|
int locateIndex = -1;
|
|
int locateIndex = -1;
|
|
|
- List<Rect> locateArea = new List<Rect> {
|
|
|
|
|
|
|
+ readonly List<Rect> locateArea = new List<Rect> {
|
|
|
new Rect(0f, 0f, 0.5f, 0.5f), new Rect(0.5f, 0f, 0.5f, 0.5f), new Rect(0f, 0.5f, 0.5f, 0.5f), new Rect(0.5f, 0.5f, 0.5f, 0.5f)
|
|
new Rect(0f, 0f, 0.5f, 0.5f), new Rect(0.5f, 0f, 0.5f, 0.5f), new Rect(0f, 0.5f, 0.5f, 0.5f), new Rect(0.5f, 0.5f, 0.5f, 0.5f)
|
|
|
}; // 屏幕显示白色的区域大小
|
|
}; // 屏幕显示白色的区域大小
|
|
|
|
|
|
|
|
float areaPercent => locateArea[locateIndex].size.x; // 当前白色区域的占比
|
|
float areaPercent => locateArea[locateIndex].size.x; // 当前白色区域的占比
|
|
|
int areaSelected = -1; // 选择哪个区域,顺序与Quadrilateral对应
|
|
int areaSelected = -1; // 选择哪个区域,顺序与Quadrilateral对应
|
|
|
- List<float> sumTemp = new List<float>();
|
|
|
|
|
- List<OrdinalQuadrilateral> quadTemp = new List<OrdinalQuadrilateral>();
|
|
|
|
|
|
|
+ readonly List<float> sumTemp = new List<float>();
|
|
|
|
|
+ readonly List<OrdinalQuadrilateral> quadTemp = new List<OrdinalQuadrilateral>();
|
|
|
|
|
|
|
|
//public ScreenIdentification(WebCamTexture texture)
|
|
//public ScreenIdentification(WebCamTexture texture)
|
|
|
//{
|
|
//{
|
|
@@ -61,17 +68,14 @@ namespace o0.Project
|
|
|
//}
|
|
//}
|
|
|
public static UnityEngine.Color FloatValueToColor(float i)
|
|
public static UnityEngine.Color FloatValueToColor(float i)
|
|
|
{
|
|
{
|
|
|
- switch (i)
|
|
|
|
|
|
|
+ return i switch
|
|
|
{
|
|
{
|
|
|
- case 1:
|
|
|
|
|
- return UnityEngine.Color.green;
|
|
|
|
|
- case 2:
|
|
|
|
|
- return UnityEngine.Color.red;
|
|
|
|
|
- case 3:
|
|
|
|
|
- return UnityEngine.Color.yellow;
|
|
|
|
|
- default:
|
|
|
|
|
- return UnityEngine.Color.black;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ 1 => UnityEngine.Color.green,
|
|
|
|
|
+ 2 => UnityEngine.Color.red,
|
|
|
|
|
+ 3 => UnityEngine.Color.yellow,
|
|
|
|
|
+ 4 => UnityEngine.Color.white,
|
|
|
|
|
+ _ => UnityEngine.Color.black,
|
|
|
|
|
+ };
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public ScreenIdentification()
|
|
public ScreenIdentification()
|
|
@@ -87,6 +91,22 @@ namespace o0.Project
|
|
|
public event Action OnLocateScreenEnd;
|
|
public event Action OnLocateScreenEnd;
|
|
|
public bool bStartLocateScreen { get; set; } = false;//是否进行捕获
|
|
public bool bStartLocateScreen { get; set; } = false;//是否进行捕获
|
|
|
|
|
|
|
|
|
|
+ public bool SelectScreenAfterLocate(ScreenLocate.ScreenIdentificationTag tag)
|
|
|
|
|
+ {
|
|
|
|
|
+ QuadrilateralInCamera target = tag switch
|
|
|
|
|
+ {
|
|
|
|
|
+ ScreenLocate.ScreenIdentificationTag.Manual => QuadManual,
|
|
|
|
|
+ ScreenLocate.ScreenIdentificationTag.SemiAuto => QuadSemiAuto,
|
|
|
|
|
+ ScreenLocate.ScreenIdentificationTag.Auto => QuadAuto,
|
|
|
|
|
+ _ => null
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ if (target == null)
|
|
|
|
|
+ return false;
|
|
|
|
|
+ SetScreenQuad(target);
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// 自动识别开始的入口
|
|
// 自动识别开始的入口
|
|
|
public void LocateScreen(int Capture = 30, int Delay = 30) //数值单位是frame
|
|
public void LocateScreen(int Capture = 30, int Delay = 30) //数值单位是frame
|
|
|
{
|
|
{
|
|
@@ -132,7 +152,7 @@ namespace o0.Project
|
|
|
|
|
|
|
|
void DebugImage(List<Texture2D> images)
|
|
void DebugImage(List<Texture2D> images)
|
|
|
{
|
|
{
|
|
|
- QuadrilateralFit(images, 5);
|
|
|
|
|
|
|
+ QuadrilateralFit(images);
|
|
|
|
|
|
|
|
//var watch = new System.Diagnostics.Stopwatch();
|
|
//var watch = new System.Diagnostics.Stopwatch();
|
|
|
//watch.Start();
|
|
//watch.Start();
|
|
@@ -177,8 +197,8 @@ namespace o0.Project
|
|
|
|
|
|
|
|
public void NextScreen()
|
|
public void NextScreen()
|
|
|
{
|
|
{
|
|
|
- // 测试用
|
|
|
|
|
- if (LocateDebug && areaSelected == -1)
|
|
|
|
|
|
|
+ // 只识别一次色差变化
|
|
|
|
|
+ if (LocateSingleStep && areaSelected == -1)
|
|
|
{
|
|
{
|
|
|
LocateAreaData = new Rect[][] { new Rect[] { new Rect(0, 0, 1f, 1f) } };
|
|
LocateAreaData = new Rect[][] { new Rect[] { new Rect(0, 0, 1f, 1f) } };
|
|
|
locateIndex = 3;
|
|
locateIndex = 3;
|
|
@@ -202,7 +222,16 @@ namespace o0.Project
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- void Reset()
|
|
|
|
|
|
|
+ // 清除记录的屏幕识别数据(手动、自动等)
|
|
|
|
|
+ public void ClearQuadCache()
|
|
|
|
|
+ {
|
|
|
|
|
+ SetScreenQuad(null);
|
|
|
|
|
+ QuadManual = null;
|
|
|
|
|
+ QuadSemiAuto = null;
|
|
|
|
|
+ QuadAuto = null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void Reset()
|
|
|
{
|
|
{
|
|
|
// bStartLocateScreen = false;
|
|
// bStartLocateScreen = false;
|
|
|
delay = 0;
|
|
delay = 0;
|
|
@@ -211,7 +240,8 @@ namespace o0.Project
|
|
|
ScreenBlackTexture = null;
|
|
ScreenBlackTexture = null;
|
|
|
locateIndex = -1;
|
|
locateIndex = -1;
|
|
|
areaSelected = -1;
|
|
areaSelected = -1;
|
|
|
- locateArea.RemoveRange(4, LocateAreaData[0].Length);
|
|
|
|
|
|
|
+ if (locateArea.Count > 4)
|
|
|
|
|
+ locateArea.RemoveRange(4, LocateAreaData[0].Length);
|
|
|
quadTemp.Clear();
|
|
quadTemp.Clear();
|
|
|
sumTemp.Clear();
|
|
sumTemp.Clear();
|
|
|
}
|
|
}
|
|
@@ -623,21 +653,21 @@ namespace o0.Project
|
|
|
//ScreenLocate.DebugTexture(4, ScreenLocateTexG);
|
|
//ScreenLocate.DebugTexture(4, ScreenLocateTexG);
|
|
|
//ScreenLocate.DebugTexture(5, ScreenLocateTexB);
|
|
//ScreenLocate.DebugTexture(5, ScreenLocateTexB);
|
|
|
|
|
|
|
|
-
|
|
|
|
|
- //var watch = new System.Diagnostics.Stopwatch();
|
|
|
|
|
- //watch.Start();
|
|
|
|
|
- //var times = new List<double>() { 0.0 };
|
|
|
|
|
-
|
|
|
|
|
//var ScreenLocateTexLightedMat = texture.Too0Mat();
|
|
//var ScreenLocateTexLightedMat = texture.Too0Mat();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// <param name="lineWidth">识别的最小线段长度</param>
|
|
/// <param name="lineWidth">识别的最小线段长度</param>
|
|
|
/// <param name="debugImages">这个参数如果不为null且数量大于0,则执行debug操作</param>
|
|
/// <param name="debugImages">这个参数如果不为null且数量大于0,则执行debug操作</param>
|
|
|
- void QuadrilateralFit(List<Texture2D> debugImages = null, float lineWidth = 10)
|
|
|
|
|
|
|
+ void QuadrilateralFit(List<Texture2D> debugImages = null)
|
|
|
{
|
|
{
|
|
|
|
|
+ // 如果有旧的手动数据,刷新一下Size
|
|
|
|
|
+ QuadManual?.ReSize(new Vector(Size.x, Size.y), ScreenMap.ViewAspectRatioSetting);
|
|
|
// 屏幕黑白差值,存放多批次的图像用于识别, 该List数量不能等于 0
|
|
// 屏幕黑白差值,存放多批次的图像用于识别, 该List数量不能等于 0
|
|
|
List<UnityEngine.Color[]> PixelsMultipleBatches = new List<UnityEngine.Color[]>();
|
|
List<UnityEngine.Color[]> PixelsMultipleBatches = new List<UnityEngine.Color[]>();
|
|
|
|
|
|
|
|
|
|
+ var sw = new System.Diagnostics.Stopwatch();
|
|
|
|
|
+ sw.Start();
|
|
|
|
|
+
|
|
|
//读取数据
|
|
//读取数据
|
|
|
if (debugImages != null && debugImages.Count != 0)
|
|
if (debugImages != null && debugImages.Count != 0)
|
|
|
{
|
|
{
|
|
@@ -660,13 +690,19 @@ namespace o0.Project
|
|
|
var scale = 1.0f / maxWhite; // 放大对比度
|
|
var scale = 1.0f / maxWhite; // 放大对比度
|
|
|
|
|
|
|
|
var differPixel = new UnityEngine.Color[Size.x * Size.y];
|
|
var differPixel = new UnityEngine.Color[Size.x * Size.y];
|
|
|
- Parallel.For(0, Size.x * Size.y, i =>
|
|
|
|
|
|
|
+ var whitePixel = new UnityEngine.Color[Size.x * Size.y];
|
|
|
|
|
+ Parallel.For(0, Size.x, x =>
|
|
|
{
|
|
{
|
|
|
- var pi = ScreenWhiteTexture[i] - ScreenBlackTexture[i];
|
|
|
|
|
- differPixel[i] = new UnityEngine.Color(pi.x, pi.y, pi.z) * scale;
|
|
|
|
|
|
|
+ for (int y = 0; y < Size.y; y++)
|
|
|
|
|
+ {
|
|
|
|
|
+ var i = y * Size.x + x;
|
|
|
|
|
+ var d = ScreenWhiteTexture[i] - ScreenBlackTexture[i];
|
|
|
|
|
+ differPixel[i] = new UnityEngine.Color(d.x, d.y, d.z) * scale;
|
|
|
|
|
+ whitePixel[i] = new UnityEngine.Color(ScreenWhiteTexture[i].x, ScreenWhiteTexture[i].y, ScreenWhiteTexture[i].z) * scale;
|
|
|
|
|
+ }
|
|
|
});
|
|
});
|
|
|
PixelsMultipleBatches.Add(differPixel);
|
|
PixelsMultipleBatches.Add(differPixel);
|
|
|
- PixelsMultipleBatches.Add(ScreenWhiteTexture.Select((i) => new UnityEngine.Color(i.x, i.y, i.z) * scale).ToArray());
|
|
|
|
|
|
|
+ PixelsMultipleBatches.Add(whitePixel);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int conSize = (int)Math.Ceiling(0.007f * Size.y) * 2 + 1;
|
|
int conSize = (int)Math.Ceiling(0.007f * Size.y) * 2 + 1;
|
|
@@ -674,7 +710,7 @@ namespace o0.Project
|
|
|
|
|
|
|
|
float minLength = conSize * 7.7f;
|
|
float minLength = conSize * 7.7f;
|
|
|
minLength = locateIndex == -1 ? minLength : minLength * areaPercent; // minLength需要按比例缩小
|
|
minLength = locateIndex == -1 ? minLength : minLength * areaPercent; // minLength需要按比例缩小
|
|
|
- string log = $"[ScreenLocate Auto] Size: ({Size.x},{Size.y}), 卷积核Size: {conSize}, 最小线段长度: {minLength}";
|
|
|
|
|
|
|
+ string log = $"[Log][ScreenLocate Auto] Size: ({Size.x},{Size.y}), 卷积核Size: {conSize}, 最小线段长度: {minLength}";
|
|
|
|
|
|
|
|
var allLines = new List<LineIdentified>();
|
|
var allLines = new List<LineIdentified>();
|
|
|
List<Texture2D> LocateTexTemp = new List<Texture2D>();
|
|
List<Texture2D> LocateTexTemp = new List<Texture2D>();
|
|
@@ -690,90 +726,129 @@ namespace o0.Project
|
|
|
}
|
|
}
|
|
|
Texture2D ScreenLocateTexture = LocateTexTemp[0]; // for output
|
|
Texture2D ScreenLocateTexture = LocateTexTemp[0]; // for output
|
|
|
|
|
|
|
|
- // 过滤得到四边形的四条边, ScreenLocateMatList[0]默认是屏幕的黑白色差
|
|
|
|
|
- var quadLines = FilterLines(ScreenLocateMatList, allLines, GetAvgPoint(ScreenLocateMatList[0]),
|
|
|
|
|
- out Line[] oldLines, out List<Line> possibleLines,
|
|
|
|
|
- Screen, conSize, conSize, minLength);
|
|
|
|
|
-
|
|
|
|
|
|
|
+ // 估算屏幕中点,如果已有手动定位数据,根据现有数据取平均即可,否则从色差计算,ScreenLocateMatList[0]默认是屏幕的黑白色差
|
|
|
|
|
+ Vector AvgPoint = QuadManual != null ? QuadManual.Quad.Centroid : GetAvgPoint(ScreenLocateMatList[0]);
|
|
|
|
|
+ // 过滤得到四边形的四条边,
|
|
|
|
|
+ var (quadLinesSemiAuto, quadLinesAuto) = FilterLines(ScreenLocateMatList, allLines, AvgPoint,
|
|
|
|
|
+ out LineIdentified[] manualLines, out List<LineIdentified> possibleLines,
|
|
|
|
|
+ conSize, conSize, minLength);
|
|
|
|
|
|
|
|
- // 将 allLines 输出一张图片
|
|
|
|
|
- var allLinesMap = new Matrix(Size, Tiling: true);
|
|
|
|
|
- foreach (var l in allLines)
|
|
|
|
|
|
|
+ #region 全自动识别的结果
|
|
|
|
|
+ List<LineIdentified> LineIdentifiedAuto = new List<LineIdentified>(); // 线段顺序: 下、右、上、左
|
|
|
|
|
+ for (int i = 0; i < 4; i++)
|
|
|
{
|
|
{
|
|
|
- if (l.Line != null)
|
|
|
|
|
- o0Extension.DrawLine(allLinesMap, l.Line, (x, y) => 3, new Geometry2D.Float.Vector(0, 2), true);
|
|
|
|
|
|
|
+ if (quadLinesAuto[i] != null)
|
|
|
|
|
+ LineIdentifiedAuto.Add(quadLinesAuto[i]);
|
|
|
}
|
|
}
|
|
|
- var allLinesTex = allLinesMap.ToTexRGBA(FloatValueToColor);
|
|
|
|
|
- ScreenLocate.DebugTexture(1, allLinesTex);
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
|
|
+ if (LineIdentifiedAuto.Count == 4) // 判断识别的线段能否拼成屏幕,能拼成则记录
|
|
|
|
|
+ {
|
|
|
|
|
+ var a = LineIdentifiedAuto[0].Line.Intersect(LineIdentifiedAuto[3].Line, false).Value;
|
|
|
|
|
+ var b = LineIdentifiedAuto[0].Line.Intersect(LineIdentifiedAuto[1].Line, false).Value;
|
|
|
|
|
+ var c = LineIdentifiedAuto[2].Line.Intersect(LineIdentifiedAuto[3].Line, false).Value;
|
|
|
|
|
+ var d = LineIdentifiedAuto[1].Line.Intersect(LineIdentifiedAuto[2].Line, false).Value;
|
|
|
|
|
+ QuadAuto = new QuadrilateralInCamera(a, b, c, d, new Vector(Size.x, Size.y));
|
|
|
|
|
+ if (!QuadAuto.IsQuadComplete())
|
|
|
|
|
+ QuadAuto = null;
|
|
|
|
|
+ }
|
|
|
|
|
+ #endregion
|
|
|
|
|
|
|
|
- // 将识别到的边画出来,并判断能否拼成屏幕,能拼成则设置ScreenMap
|
|
|
|
|
- // 线段顺序: 下、右、上、左
|
|
|
|
|
- List<Line> LineIdentified = new List<Line>();
|
|
|
|
|
|
|
+ #region 半自动识别
|
|
|
|
|
+ List<LineIdentified> LineIdentifiedSemiAuto = new List<LineIdentified>(); // 线段顺序: 下、右、上、左
|
|
|
|
|
+ bool[] newLines = new bool[4] { true, true, true, true };
|
|
|
for (int i = 0; i < 4; i++)
|
|
for (int i = 0; i < 4; i++)
|
|
|
{
|
|
{
|
|
|
- if (quadLines[i] != null)
|
|
|
|
|
- LineIdentified.Add(quadLines[i]);
|
|
|
|
|
- else if (oldLines != null)
|
|
|
|
|
- LineIdentified.Add(oldLines[i]);
|
|
|
|
|
|
|
+ if (quadLinesSemiAuto[i] != null)
|
|
|
|
|
+ LineIdentifiedSemiAuto.Add(quadLinesSemiAuto[i]);
|
|
|
|
|
+ else if (manualLines != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ LineIdentifiedSemiAuto.Add(manualLines[i]);
|
|
|
|
|
+ newLines[i] = false;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- var drawScreenMap = new Matrix(Size, Tiling: true);
|
|
|
|
|
- foreach (var l in LineIdentified)
|
|
|
|
|
- o0Extension.DrawLine(drawScreenMap, l, (x, y) => 1, new Geometry2D.Float.Vector(0, lineWidth));
|
|
|
|
|
- Texture2D ScreenQuadTex = drawScreenMap.ToTex(); // out ScreenQuadTex
|
|
|
|
|
-
|
|
|
|
|
- QuadrilateralInCamera screenQuad = null;
|
|
|
|
|
- if (LineIdentified.Count == 4)
|
|
|
|
|
|
|
+ if (LineIdentifiedSemiAuto.Count == 4) // 判断识别的线段能否拼成屏幕,能拼成则记录
|
|
|
{
|
|
{
|
|
|
- var a = LineIdentified[0].Intersect(LineIdentified[3], false).Value;
|
|
|
|
|
- var b = LineIdentified[0].Intersect(LineIdentified[1], false).Value;
|
|
|
|
|
- var c = LineIdentified[2].Intersect(LineIdentified[3], false).Value;
|
|
|
|
|
- var d = LineIdentified[1].Intersect(LineIdentified[2], false).Value;
|
|
|
|
|
- screenQuad = new QuadrilateralInCamera(a, b, c, d, new Vector(Size.x, Size.y));
|
|
|
|
|
- if (!screenQuad.IsQuadComplete())
|
|
|
|
|
- screenQuad = null;
|
|
|
|
|
|
|
+ var a = LineIdentifiedSemiAuto[0].Line.Intersect(LineIdentifiedSemiAuto[3].Line, false).Value;
|
|
|
|
|
+ var b = LineIdentifiedSemiAuto[0].Line.Intersect(LineIdentifiedSemiAuto[1].Line, false).Value;
|
|
|
|
|
+ var c = LineIdentifiedSemiAuto[2].Line.Intersect(LineIdentifiedSemiAuto[3].Line, false).Value;
|
|
|
|
|
+ var d = LineIdentifiedSemiAuto[1].Line.Intersect(LineIdentifiedSemiAuto[2].Line, false).Value;
|
|
|
|
|
+ QuadSemiAuto = new QuadrilateralInCamera(a, b, c, d, new Vector(Size.x, Size.y));
|
|
|
|
|
+ if (!QuadSemiAuto.IsQuadComplete())
|
|
|
|
|
+ QuadSemiAuto = null;
|
|
|
}
|
|
}
|
|
|
- if (screenQuad == null && Screen.QuadInCamera != null) // 如果可能,回退到上一个screen
|
|
|
|
|
|
|
+ #endregion
|
|
|
|
|
+
|
|
|
|
|
+ // 优先应用半自动的结果(也可以在外部手动设置)
|
|
|
|
|
+ if (QuadSemiAuto == null && QuadAuto == null && Screen.QuadInCamera != null) // 如果可能,回退到上一个screen
|
|
|
{
|
|
{
|
|
|
Debug.Log("<color=aqua>[ScreenIdentification] 本次识别失败,回退到上次的识别结果</color>");
|
|
Debug.Log("<color=aqua>[ScreenIdentification] 本次识别失败,回退到上次的识别结果</color>");
|
|
|
quadTemp.Add(Screen.QuadInCamera.Quad);
|
|
quadTemp.Add(Screen.QuadInCamera.Quad);
|
|
|
}
|
|
}
|
|
|
- else if (screenQuad != null)
|
|
|
|
|
|
|
+ else if (QuadSemiAuto != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log("<color=aqua>[ScreenIdentification] 识别到四边形</color>");
|
|
|
|
|
+ quadTemp.Add(QuadSemiAuto.Quad);
|
|
|
|
|
+ }else if (QuadAuto != null)
|
|
|
{
|
|
{
|
|
|
Debug.Log("<color=aqua>[ScreenIdentification] 识别到四边形</color>");
|
|
Debug.Log("<color=aqua>[ScreenIdentification] 识别到四边形</color>");
|
|
|
- quadTemp.Add(screenQuad.Quad);
|
|
|
|
|
|
|
+ quadTemp.Add(QuadAuto.Quad);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ #region 绘制 output texture
|
|
|
|
|
+ // 绘制半自动
|
|
|
|
|
+ var ScreenQuadMap = new Matrix(Size, Tiling: true); // 识别的到的屏幕四边形(半自动和自动在一张图上)
|
|
|
|
|
+ foreach (var i in LineIdentifiedSemiAuto.Index())
|
|
|
|
|
+ {
|
|
|
|
|
+ if (newLines[i])
|
|
|
|
|
+ o0Extension.DrawLine(ScreenQuadMap, LineIdentifiedSemiAuto[i].DrawLine, (x, y) => 2, new Geometry2D.Float.Vector(0, 10));
|
|
|
|
|
+ else
|
|
|
|
|
+ o0Extension.DrawLine(ScreenQuadMap, LineIdentifiedSemiAuto[i].DrawLine, (x, y) => 1, new Geometry2D.Float.Vector(0, 6), true);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
+ // 绘制全自动
|
|
|
|
|
+ foreach (var i in LineIdentifiedAuto.Index())
|
|
|
|
|
+ o0Extension.DrawLine(ScreenQuadMap, LineIdentifiedAuto[i].DrawLine, (x, y) => 4, new Geometry2D.Float.Vector(0, 4), true);
|
|
|
|
|
+
|
|
|
|
|
+ Texture2D ScreenQuad = ScreenQuadMap.ToTexRGBA(FloatValueToColor);
|
|
|
|
|
+ Texture2D ScreenQuadWithScreen = ScreenQuad.Overlay(ScreenLocateTexture); // 叠加屏幕色差图
|
|
|
|
|
+
|
|
|
|
|
+ // 绘制allLines
|
|
|
|
|
+ var allLinesMap = new Matrix(Size, Tiling: true);
|
|
|
|
|
+ foreach (var l in allLines)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (l.DrawLine != null)
|
|
|
|
|
+ o0Extension.DrawLine(allLinesMap, l.DrawLine, (x, y) => 3, new Geometry2D.Float.Vector(0, 2), true);
|
|
|
|
|
+ }
|
|
|
|
|
+ var allLinesTex = allLinesMap.ToTexRGBA(FloatValueToColor);
|
|
|
|
|
+ ScreenLocate.DebugTexture(1, allLinesTex);
|
|
|
|
|
|
|
|
// 还需要输出一张识别结果图,包含干扰线段
|
|
// 还需要输出一张识别结果图,包含干扰线段
|
|
|
- var LSDLineMap = new Matrix(Size, Tiling: true);
|
|
|
|
|
|
|
+ var ChoosableLineMap = new Matrix(Size, Tiling: true);
|
|
|
foreach (var l in possibleLines)
|
|
foreach (var l in possibleLines)
|
|
|
{
|
|
{
|
|
|
- if (l != null && !quadLines.Contains(l))
|
|
|
|
|
- o0Extension.DrawLine(LSDLineMap, l, (x, y) => 3, new Geometry2D.Float.Vector(0, 2), true); // 其他的备选线段
|
|
|
|
|
|
|
+ if (l != null && !quadLinesSemiAuto.Contains(l) && !manualLines.Contains(l))
|
|
|
|
|
+ o0Extension.DrawLine(ChoosableLineMap, l.DrawLine, (x, y) => 3, new Geometry2D.Float.Vector(0, 2), true); // 其他的备选线段
|
|
|
}
|
|
}
|
|
|
- foreach (var l in quadLines)
|
|
|
|
|
|
|
+ foreach (var l in LineIdentifiedSemiAuto)
|
|
|
{
|
|
{
|
|
|
if (l != null)
|
|
if (l != null)
|
|
|
- o0Extension.DrawLine(LSDLineMap, l, (x, y) => 2, new Geometry2D.Float.Vector(0, 4)); // 这次识别到的线段
|
|
|
|
|
|
|
+ o0Extension.DrawLine(ChoosableLineMap, l.DrawLine, (x, y) => 2, new Geometry2D.Float.Vector(0, 5)); // 识别的结果
|
|
|
}
|
|
}
|
|
|
- if (oldLines != null)
|
|
|
|
|
|
|
+ if (manualLines != null)
|
|
|
{
|
|
{
|
|
|
- foreach (var l in oldLines)
|
|
|
|
|
- o0Extension.DrawLine(LSDLineMap, l, (x, y) => 1, new Geometry2D.Float.Vector(0, 2), true); // 旧的屏幕线段(例如上次手动识别的)
|
|
|
|
|
|
|
+ foreach (var l in manualLines)
|
|
|
|
|
+ o0Extension.DrawLine(ChoosableLineMap, l.DrawLine, (x, y) => 1, new Geometry2D.Float.Vector(0, 2), true); // 旧的屏幕线段(例如上次手动识别的)
|
|
|
}
|
|
}
|
|
|
- Texture2D ChoosableLineTex = LSDLineMap.ToTexRGBA(FloatValueToColor);
|
|
|
|
|
-
|
|
|
|
|
|
|
+ Texture2D ChoosableLineTex = ChoosableLineMap.ToTexRGBA(FloatValueToColor);
|
|
|
|
|
+ #endregion
|
|
|
|
|
|
|
|
|
|
+ log += $"\r\n屏幕四边形_手动识别{QuadManual != null}\r\n屏幕四边形_半自动识别{QuadSemiAuto != null}\r\n屏幕四边形_全自动识别{QuadAuto != null}";
|
|
|
Debug.Log(log);
|
|
Debug.Log(log);
|
|
|
// 是否将图片保存到本地
|
|
// 是否将图片保存到本地
|
|
|
if (ScreenLocate.Main.SaveToggle.isOn && ScreenLocate.Main.DebugOnZIMDemo)
|
|
if (ScreenLocate.Main.SaveToggle.isOn && ScreenLocate.Main.DebugOnZIMDemo)
|
|
|
{
|
|
{
|
|
|
var FileDirectory = $"Debug_屏幕定位/";
|
|
var FileDirectory = $"Debug_屏幕定位/";
|
|
|
- SaveImages(FileDirectory, log, ScreenLocateTexture, allLinesTex, ChoosableLineTex, ScreenQuadTex);
|
|
|
|
|
|
|
+ SaveImages(FileDirectory, log, ScreenLocateTexture, allLinesTex, ChoosableLineTex, ScreenQuad);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//times.Add(watch.ElapsedMilliseconds);
|
|
//times.Add(watch.ElapsedMilliseconds);
|
|
@@ -791,9 +866,8 @@ namespace o0.Project
|
|
|
|
|
|
|
|
{
|
|
{
|
|
|
ScreenLocate.DebugTexture(2, ScreenLocateTexture);
|
|
ScreenLocate.DebugTexture(2, ScreenLocateTexture);
|
|
|
- ScreenLocate.DebugTexture(3, ScreenQuadTex);
|
|
|
|
|
- // 融合线段和原图
|
|
|
|
|
- ScreenLocate.DebugTexture(4, ScreenLocateTexture.Merge(ScreenQuadTex));
|
|
|
|
|
|
|
+ ScreenLocate.DebugTexture(3, ScreenQuad);
|
|
|
|
|
+ ScreenLocate.DebugTexture(4, ScreenQuadWithScreen);
|
|
|
ScreenLocate.DebugTexture(5, ChoosableLineTex);
|
|
ScreenLocate.DebugTexture(5, ChoosableLineTex);
|
|
|
}
|
|
}
|
|
|
foreach (var i in LocateTexTemp)
|
|
foreach (var i in LocateTexTemp)
|
|
@@ -840,17 +914,42 @@ namespace o0.Project
|
|
|
return l.Count;
|
|
return l.Count;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 返回四边形的四条边,List长度一定是4 (如果没有识别到就是null),且线段顺序是: 下、右、上、左
|
|
|
|
|
- List<Line> FilterLines(List<Matrix> screenLocateMatList, List<LineIdentified> allLines, Vector avgPoint,
|
|
|
|
|
- out Line[] oldLines, out List<Line> possibleLines,
|
|
|
|
|
- ScreenMap screen, float conSize, float gradientLength, float minLength = 100)
|
|
|
|
|
|
|
+ // 返回四边形的四条边(半自动、全自动),List长度一定是4 (如果没有识别到就是null),且线段顺序是: 下、右、上、左
|
|
|
|
|
+ (List<LineIdentified>, List<LineIdentified>) FilterLines(List<Matrix> screenLocateMatList, List<LineIdentified> allLines, Vector avgPoint,
|
|
|
|
|
+ out LineIdentified[] manualLines, out List<LineIdentified> possibleLines, float conSize, float gradientLength, float minLength = 100)
|
|
|
{
|
|
{
|
|
|
//Debug.Log("[IdentifyLineLSD] lines.Count: " + lines.Count);
|
|
//Debug.Log("[IdentifyLineLSD] lines.Count: " + lines.Count);
|
|
|
- // LSD计算得到的矩阵尺寸较小(因为卷积),这里必须进行位移
|
|
|
|
|
var offset = new Vector((conSize - 1) / 2, (conSize - 1) / 2);
|
|
var offset = new Vector((conSize - 1) / 2, (conSize - 1) / 2);
|
|
|
|
|
+ // LSD计算得到的矩阵尺寸较小(因为卷积),这里必须进行位移
|
|
|
for (int i = 0; i < allLines.Count; i++)
|
|
for (int i = 0; i < allLines.Count; i++)
|
|
|
allLines[i].Offset(offset);
|
|
allLines[i].Offset(offset);
|
|
|
|
|
|
|
|
|
|
+ // 筛掉椭圆框外的线段(超出一半会筛掉)
|
|
|
|
|
+ var innerLines = new List<LineIdentified>();
|
|
|
|
|
+ for (int i = 0; i < allLines.Count; i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ List<Vector> InArea = new List<Vector>();
|
|
|
|
|
+ var dir = (allLines[i].Line.B - allLines[i].Line.A) / 4;
|
|
|
|
|
+ var points = new Vector[5] { allLines[i].Line.A, allLines[i].Line.A + dir, allLines[i].Line.A + dir * 2f, allLines[i].Line.A + dir * 3f, allLines[i].Line.B }; // A点、中间的点、B点
|
|
|
|
|
+ for (int pI = 0; pI < points.Length; pI++)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (!ScreenLocate.Main.ScreenPixelCheaker.OutArea2D(points[pI], Size))
|
|
|
|
|
+ InArea.Add(points[pI]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (InArea.Count < 2) // 少于2个点在内部
|
|
|
|
|
+ continue;
|
|
|
|
|
+ else if (InArea.Count < points.Length) // 不完全在内部
|
|
|
|
|
+ allLines[i].DrawLine = new Line(InArea.First(), InArea.Last()); // 将部分线条设置为drawline,用于下一步的绘制
|
|
|
|
|
+ else // 线段全部在椭圆内
|
|
|
|
|
+ allLines[i].DrawLine = allLines[i].Line;
|
|
|
|
|
+
|
|
|
|
|
+ innerLines.Add(allLines[i]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 角度阈值,用来判断线段的梯度方向是否指向屏幕中心(avgPoint)
|
|
|
|
|
+ var avaAngleHalf = 75f;
|
|
|
|
|
+
|
|
|
// 沿直线计算综合梯度(梯度乘以长度系数,再乘以距离系数), distanceRatio是实际距离除以最大距离
|
|
// 沿直线计算综合梯度(梯度乘以长度系数,再乘以距离系数), distanceRatio是实际距离除以最大距离
|
|
|
float estimateGradient(LineIdentified line, float distanceRatio)
|
|
float estimateGradient(LineIdentified line, float distanceRatio)
|
|
|
{
|
|
{
|
|
@@ -867,143 +966,121 @@ namespace o0.Project
|
|
|
lg.Add(screenLocateMatList[line.Batch][(int)ga.x, (int)ga.y] - screenLocateMatList[line.Batch][(int)gb.x, (int)gb.y]);
|
|
lg.Add(screenLocateMatList[line.Batch][(int)ga.x, (int)ga.y] - screenLocateMatList[line.Batch][(int)gb.x, (int)gb.y]);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- float e = (float)Math.Pow(Math.Ceiling(line.Line.Length / minLength), 0.2f); // 长度系数,筛选时梯度更大、长度更长的线段更优
|
|
|
|
|
|
|
+ float e = (float)Math.Sqrt(Math.Ceiling(line.Line.Length / minLength)); // 长度系数,筛选时梯度更大、长度更长的线段更优
|
|
|
float d = (3 - distanceRatio) / 2; // 距离系数,距离越近,系数越大
|
|
float d = (3 - distanceRatio) / 2; // 距离系数,距离越近,系数越大
|
|
|
return e * d * Math.Abs(lg.Mean());
|
|
return e * d * Math.Abs(lg.Mean());
|
|
|
}
|
|
}
|
|
|
|
|
+ // 根据线段梯度的角度,判断是不是屏幕的边,out index代表是哪条边(顺序是: 下、右、上、左)
|
|
|
|
|
+ bool isScreenLine(LineIdentified line, out int index)
|
|
|
|
|
+ {
|
|
|
|
|
+ var a = (avgPoint - (line.Line.A + line.Line.B) / 2).DegreeToXAxis();
|
|
|
|
|
+ //Debug.Log(a + ", " + gradient + ", " + sum);
|
|
|
|
|
+ index = -1;
|
|
|
|
|
+ if (Math.Abs(a - line.GradientDegree) < avaAngleHalf || Math.Abs(a - 360 - line.GradientDegree) < avaAngleHalf || Math.Abs(a + 360 - line.GradientDegree) < avaAngleHalf)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (line.GradientDegree > 45 && line.GradientDegree < 135) // 下
|
|
|
|
|
+ index = 0;
|
|
|
|
|
+ else if (line.GradientDegree > 135 && line.GradientDegree < 225) // 右
|
|
|
|
|
+ index = 1;
|
|
|
|
|
+ else if (line.GradientDegree > 225 && line.GradientDegree < 315) // 上
|
|
|
|
|
+ index = 2;
|
|
|
|
|
+ else
|
|
|
|
|
+ index = 3;
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
|
|
|
- // 下、右、上、左
|
|
|
|
|
- var quadLines = new List<(float, Line)>[4] { new List<(float, Line)>(), new List<(float, Line)>(), new List<(float, Line)>(), new List<(float, Line)>() };
|
|
|
|
|
- possibleLines = new List<Line>();
|
|
|
|
|
- oldLines = null;
|
|
|
|
|
|
|
+ // 下、右、上、左, 半自动和自动
|
|
|
|
|
+ var quadLinesSemiAuto = new List<(float, LineIdentified)>[4] { new List<(float, LineIdentified)>(), new List<(float, LineIdentified)>(), new List<(float, LineIdentified)>(), new List<(float, LineIdentified)>() };
|
|
|
|
|
+ var quadLinesAuto = new List<(float, LineIdentified)>[4] { new List<(float, LineIdentified)>(), new List<(float, LineIdentified)>(), new List<(float, LineIdentified)>(), new List<(float, LineIdentified)>() };
|
|
|
|
|
+ possibleLines = new List<LineIdentified>();
|
|
|
|
|
+ manualLines = null;
|
|
|
|
|
|
|
|
- // 如果已有定位数据,根据现有数据筛选线条
|
|
|
|
|
- if (screen.QuadInCamera != null)
|
|
|
|
|
|
|
+ // 如果已有手动定位数据,根据现有数据筛选线条(半自动)
|
|
|
|
|
+ if (QuadManual != null)
|
|
|
{
|
|
{
|
|
|
Debug.Log("[IdentifyLineLSD] 根据已有定位数据做筛选");
|
|
Debug.Log("[IdentifyLineLSD] 根据已有定位数据做筛选");
|
|
|
- screen.RefreshCameraSize(new Vector2(Size.x, Size.y));
|
|
|
|
|
-
|
|
|
|
|
var calibration = ScreenLocate.Main.ReDoLocateCalibrationRatio * Size.y;
|
|
var calibration = ScreenLocate.Main.ReDoLocateCalibrationRatio * Size.y;
|
|
|
- oldLines = screen.QuadInCamera.GetLines();
|
|
|
|
|
|
|
+ manualLines = QuadManual.GetLines().Select((i) => new LineIdentified(0, i, 0, 0, true)).ToArray();
|
|
|
|
|
|
|
|
- var pedals = oldLines.Select((i) => o0Extension.PointPedal(i, avgPoint, out _)).ToArray(); // 当前定位的垂足,下、右、上、左
|
|
|
|
|
|
|
+ var pedals = manualLines.Select((i) => o0Extension.PointPedal(i.Line, avgPoint, out _)).ToArray(); // 当前定位的垂足,下、右、上、左
|
|
|
|
|
|
|
|
- foreach (var i in allLines)
|
|
|
|
|
|
|
+ foreach (var line in innerLines)
|
|
|
{
|
|
{
|
|
|
- float minDistance = float.MaxValue;
|
|
|
|
|
- int index = -1;
|
|
|
|
|
- foreach (var j in pedals.Index())
|
|
|
|
|
- {
|
|
|
|
|
- var d = (o0Extension.PointPedal(i.Line, avgPoint, out _) - pedals[j]).Length;
|
|
|
|
|
- if (d < minDistance)
|
|
|
|
|
- {
|
|
|
|
|
- minDistance = d;
|
|
|
|
|
- index = j;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- //Debug.Log(minDistance +", -----------"+ calibration);
|
|
|
|
|
- if (minDistance < calibration) // 垂足的距离足够近
|
|
|
|
|
|
|
+ // 筛选条件:1-梯度方向匹配,2-垂足的距离足够近, 3-新的线段的中点,到旧线段的垂足,要在旧线段内
|
|
|
|
|
+ if (isScreenLine(line, out int index))
|
|
|
{
|
|
{
|
|
|
- // 另外满足,新的线段的中点,到旧线段的垂足,要在旧线段内
|
|
|
|
|
- var middleToOldLine = o0Extension.PointPedal(oldLines[index], (i.Line.A + i.Line.B) / 2, out bool inLineSegment);
|
|
|
|
|
- if (inLineSegment)
|
|
|
|
|
|
|
+ var distanceToOld = (o0Extension.PointPedal(line.Line, avgPoint, out _) - pedals[index]).Length;
|
|
|
|
|
+ if (distanceToOld < calibration)
|
|
|
{
|
|
{
|
|
|
- quadLines[index].Add((estimateGradient(i, minDistance / calibration), i.Line));
|
|
|
|
|
- possibleLines.Add(i.Line);
|
|
|
|
|
|
|
+ var middleToOldLine = o0Extension.PointPedal(manualLines[index].Line, (line.Line.A + line.Line.B) / 2, out bool inLineSegment);
|
|
|
|
|
+ if (inLineSegment)
|
|
|
|
|
+ {
|
|
|
|
|
+ quadLinesSemiAuto[index].Add((estimateGradient(line, distanceToOld / calibration), line));
|
|
|
|
|
+ possibleLines.Add(line);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- else
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 全自动
|
|
|
|
|
+ foreach (var line in allLines)
|
|
|
{
|
|
{
|
|
|
- var avaAngleHalf = 75f;
|
|
|
|
|
- foreach (var line in allLines)
|
|
|
|
|
|
|
+ if (isScreenLine(line , out int index))
|
|
|
{
|
|
{
|
|
|
- possibleLines.Add(line.Line);
|
|
|
|
|
-
|
|
|
|
|
- var a = (avgPoint - (line.Line.A + line.Line.B) / 2).DegreeToXAxis();
|
|
|
|
|
- //Debug.Log(a + ", " + gradient + ", " + sum);
|
|
|
|
|
- int index = -1;
|
|
|
|
|
- if (Math.Abs(a - line.GradientDegree) < avaAngleHalf || Math.Abs(a - 360 - line.GradientDegree) < avaAngleHalf || Math.Abs(a + 360 - line.GradientDegree) < avaAngleHalf)
|
|
|
|
|
|
|
+ if (line.Batch < 1) // 全自动只处理第一张图,默认是色差图
|
|
|
{
|
|
{
|
|
|
- if (line.GradientDegree > 45 && line.GradientDegree < 135) // 下
|
|
|
|
|
- index = 0;
|
|
|
|
|
- else if (line.GradientDegree > 135 && line.GradientDegree < 225) // 右
|
|
|
|
|
- index = 1;
|
|
|
|
|
- else if (line.GradientDegree > 225 && line.GradientDegree < 315) // 上
|
|
|
|
|
- index = 2;
|
|
|
|
|
- else
|
|
|
|
|
- index = 3;
|
|
|
|
|
-
|
|
|
|
|
- //var g = Math.Abs(lg.Mean());
|
|
|
|
|
- //Debug.Log(gradient + ", " + g);
|
|
|
|
|
-
|
|
|
|
|
- //List<float> lp1 = new List<float>(), lp2 = new List<float>(); // 线两侧的值
|
|
|
|
|
- //for (float i = 0; i <= ll; i += step)
|
|
|
|
|
- //{
|
|
|
|
|
- // var point = line.A + dir * i;
|
|
|
|
|
- // var ga = point + vertical;
|
|
|
|
|
- // var gb = point - vertical;
|
|
|
|
|
- // lp1.Add(screenLocateMat[(int)ga.x, (int)ga.y]);
|
|
|
|
|
- // lp2.Add(screenLocateMat[(int)gb.x, (int)gb.y]);
|
|
|
|
|
- //}
|
|
|
|
|
-
|
|
|
|
|
- //var avg1 = lp1.Mean();
|
|
|
|
|
- //var avg2 = lp2.Mean();
|
|
|
|
|
- //var v1 = lp1.Variance();
|
|
|
|
|
- //var v2 = lp2.Variance();
|
|
|
|
|
-
|
|
|
|
|
- //var lineGradient = Math.Abs(avg1 - avg2) / (v1 + v2 + 0.2f); // 方差越小,梯度的价值越高
|
|
|
|
|
- ////var g = Math.Abs(lg.Mean());
|
|
|
|
|
- ////Debug.Log(gradient + ", " + g);
|
|
|
|
|
- //Debug.Log(v1 + ", " + v2 + ", " + lineGradient);
|
|
|
|
|
-
|
|
|
|
|
- //quadLines[index].Add((lineGradient, line));
|
|
|
|
|
-
|
|
|
|
|
- quadLines[index].Add((estimateGradient(line, 1), line.Line));
|
|
|
|
|
|
|
+ quadLinesAuto[index].Add((estimateGradient(line, 1), line));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- var result = new Line[4];
|
|
|
|
|
|
|
+ var resultSemiAuto = new LineIdentified[4];
|
|
|
|
|
+ var resultAuto = new LineIdentified[4];
|
|
|
for (int i = 0; i < 4; i++)
|
|
for (int i = 0; i < 4; i++)
|
|
|
{
|
|
{
|
|
|
- if (quadLines[i].Count > 0)
|
|
|
|
|
- result[i] = quadLines[i].Max((a, b) => a.Item1.CompareTo(b.Item1)).Item2;
|
|
|
|
|
|
|
+ if (quadLinesSemiAuto[i].Count > 0)
|
|
|
|
|
+ resultSemiAuto[i] = quadLinesSemiAuto[i].Max((a, b) => a.Item1.CompareTo(b.Item1)).Item2;
|
|
|
|
|
+ if (quadLinesAuto[i].Count > 0)
|
|
|
|
|
+ resultAuto[i] = quadLinesAuto[i].Max((a, b) => a.Item1.CompareTo(b.Item1)).Item2;
|
|
|
}
|
|
}
|
|
|
- return result.ToList();
|
|
|
|
|
|
|
+ return (resultSemiAuto.ToList(), resultAuto.ToList());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- void SaveImages(string FileDirectory, string log, Texture2D ScreenLocateTex, Texture2D allLinesTex, Texture2D ChoosableLineTex, Texture2D ScreenQuadTex)
|
|
|
|
|
|
|
+ void SaveImages(string FileDirectory, string log,
|
|
|
|
|
+ Texture2D ScreenLocateTex, Texture2D allLinesTex, Texture2D ChoosableLineTex, Texture2D ScreenQuadTex)
|
|
|
{
|
|
{
|
|
|
if (!Directory.Exists(FileDirectory))
|
|
if (!Directory.Exists(FileDirectory))
|
|
|
Directory.CreateDirectory(FileDirectory);
|
|
Directory.CreateDirectory(FileDirectory);
|
|
|
var time = DateTime.Now.ToString("yyyyMMdd_HHmmss");
|
|
var time = DateTime.Now.ToString("yyyyMMdd_HHmmss");
|
|
|
|
|
|
|
|
- var pngData = (ScreenLocate.Main.outputTexture2D[7] as Texture2D)?.EncodeToPNG();
|
|
|
|
|
|
|
+ var pngData = ScreenLocate.Main.OutputTextures[7]?.EncodeToPNG();
|
|
|
if (pngData != null)
|
|
if (pngData != null)
|
|
|
File.WriteAllBytes($"{FileDirectory}{time}A屏幕原图.png", pngData);
|
|
File.WriteAllBytes($"{FileDirectory}{time}A屏幕原图.png", pngData);
|
|
|
- var pngData1 = ScreenLocateTex.EncodeToPNG();
|
|
|
|
|
|
|
+ var pngData1 = ScreenLocateTex?.EncodeToPNG();
|
|
|
if (pngData1 != null)
|
|
if (pngData1 != null)
|
|
|
File.WriteAllBytes($"{FileDirectory}{time}B黑白色差.png", pngData1);
|
|
File.WriteAllBytes($"{FileDirectory}{time}B黑白色差.png", pngData1);
|
|
|
- var pngData2 = allLinesTex.EncodeToPNG();
|
|
|
|
|
|
|
+ var pngData2 = allLinesTex?.EncodeToPNG();
|
|
|
if (pngData2 != null)
|
|
if (pngData2 != null)
|
|
|
- File.WriteAllBytes($"{FileDirectory}{time}C全部识别线段.png", pngData2);
|
|
|
|
|
- var pngData3 = ChoosableLineTex.EncodeToPNG();
|
|
|
|
|
|
|
+ File.WriteAllBytes($"{FileDirectory}{time}C全部识别线段_半自动.png", pngData2);
|
|
|
|
|
+ var pngData3 = ChoosableLineTex?.EncodeToPNG();
|
|
|
if (pngData3 != null)
|
|
if (pngData3 != null)
|
|
|
- File.WriteAllBytes($"{FileDirectory}{time}D备选线段.png", pngData3);
|
|
|
|
|
- var pngData4 = ScreenQuadTex.EncodeToPNG();
|
|
|
|
|
|
|
+ File.WriteAllBytes($"{FileDirectory}{time}D备选线段_半自动.png", pngData3);
|
|
|
|
|
+ var pngData4 = ScreenQuadTex?.EncodeToPNG();
|
|
|
if (pngData4 != null)
|
|
if (pngData4 != null)
|
|
|
File.WriteAllBytes($"{FileDirectory}{time}E识别结果.png", pngData4);
|
|
File.WriteAllBytes($"{FileDirectory}{time}E识别结果.png", pngData4);
|
|
|
|
|
|
|
|
|
|
|
|
|
Debug.Log($"<color=aqua>({time}) 屏幕识别图片保存至:程序根目录/{FileDirectory}</color>");
|
|
Debug.Log($"<color=aqua>({time}) 屏幕识别图片保存至:程序根目录/{FileDirectory}</color>");
|
|
|
- log +=
|
|
|
|
|
|
|
+ log +=
|
|
|
$"\r\n屏幕原图保存{pngData != null}, " +
|
|
$"\r\n屏幕原图保存{pngData != null}, " +
|
|
|
$"\r\n黑白色差保存{pngData1 != null}, " +
|
|
$"\r\n黑白色差保存{pngData1 != null}, " +
|
|
|
- $"\r\n全部识别线段保存{pngData2 != null}, " +
|
|
|
|
|
- $"\r\n备选线段保存{pngData3 != null}, " +
|
|
|
|
|
- $"\r\n识别结果保存{pngData4 != null}, ";
|
|
|
|
|
|
|
+ $"\r\n全部识别线段(半自动)保存{pngData2 != null}, " +
|
|
|
|
|
+ $"\r\n备选线段(半自动)保存{pngData3 != null}, " +
|
|
|
|
|
+ $"\r\n识别结果保存{pngData4 != null}";
|
|
|
File.WriteAllText($"{FileDirectory}{time}屏幕自动定位_日志.log", log);
|
|
File.WriteAllText($"{FileDirectory}{time}屏幕自动定位_日志.log", log);
|
|
|
}
|
|
}
|
|
|
|
|
|