|
@@ -1,13 +1,13 @@
|
|
|
#define ENABLE_LOG
|
|
#define ENABLE_LOG
|
|
|
|
|
|
|
|
using o0.Geometry2D.Float;
|
|
using o0.Geometry2D.Float;
|
|
|
|
|
+using o0.Num;
|
|
|
using System;
|
|
using System;
|
|
|
-using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
|
using System.Collections.Generic;
|
|
|
using System.IO;
|
|
using System.IO;
|
|
|
|
|
+using System.Linq;
|
|
|
using System.Threading.Tasks;
|
|
using System.Threading.Tasks;
|
|
|
using UnityEngine;
|
|
using UnityEngine;
|
|
|
-using UnityStandardAssets.ImageEffects;
|
|
|
|
|
using ZIM;
|
|
using ZIM;
|
|
|
using ZIM.Unity;
|
|
using ZIM.Unity;
|
|
|
|
|
|
|
@@ -90,11 +90,11 @@ namespace o0.Project
|
|
|
// 自动识别开始的入口
|
|
// 自动识别开始的入口
|
|
|
public void LocateScreen(int Capture = 45, int Delay = 45) //数值单位是frame
|
|
public void LocateScreen(int Capture = 45, int Delay = 45) //数值单位是frame
|
|
|
{
|
|
{
|
|
|
- if (ScreenLocate.Main.DebugScreenImage != null && ScreenLocate.Main.DebugOnZIMDemo) // 这段仅用于测试图片
|
|
|
|
|
|
|
+ if (ScreenLocate.Main.DebugScreenImages.Count != 0 && ScreenLocate.Main.DebugOnZIMDemo) // 这段仅用于测试图片
|
|
|
{
|
|
{
|
|
|
- ScreenLocate.Main.CameraSize = new Geometry2D.Vector<int>(ScreenLocate.Main.DebugScreenImage.width, ScreenLocate.Main.DebugScreenImage.height);
|
|
|
|
|
- DebugImage(ScreenLocate.Main.DebugScreenImage);
|
|
|
|
|
- Screen.QuadInCamera = new QuadrilateralInCamera(quadTemp[0], new Vector(ScreenLocate.Main.DebugScreenImage.width, ScreenLocate.Main.DebugScreenImage.height));
|
|
|
|
|
|
|
+ ScreenLocate.Main.CameraSize = new Geometry2D.Vector<int>(ScreenLocate.Main.DebugScreenImages[0].width, ScreenLocate.Main.DebugScreenImages[0].height);
|
|
|
|
|
+ DebugImage(ScreenLocate.Main.DebugScreenImages);
|
|
|
|
|
+ Screen.QuadInCamera = new QuadrilateralInCamera(quadTemp[0], new Vector(ScreenLocate.Main.DebugScreenImages[0].width, ScreenLocate.Main.DebugScreenImages[0].height));
|
|
|
ScreenLocate.SetScreen(null);
|
|
ScreenLocate.SetScreen(null);
|
|
|
ScreenLocate.Main.ShowScreen(ScreenLocate.Main.ScreenQuad, Screen.QuadInCamera);
|
|
ScreenLocate.Main.ShowScreen(ScreenLocate.Main.ScreenQuad, Screen.QuadInCamera);
|
|
|
delay = 0;
|
|
delay = 0;
|
|
@@ -105,6 +105,7 @@ namespace o0.Project
|
|
|
areaSelected = -1;
|
|
areaSelected = -1;
|
|
|
quadTemp.Clear();
|
|
quadTemp.Clear();
|
|
|
sumTemp.Clear();
|
|
sumTemp.Clear();
|
|
|
|
|
+ ScreenLocate.Main.DebugScreenImages.Clear();
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -129,14 +130,9 @@ namespace o0.Project
|
|
|
return capture != 0 && delay != 0;
|
|
return capture != 0 && delay != 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- void DebugImage(Texture2D image)
|
|
|
|
|
|
|
+ void DebugImage(List<Texture2D> images)
|
|
|
{
|
|
{
|
|
|
- QuadrilateralFit(out Texture2D LocateLightedRedTex,out Texture2D ChoosableLineTex, out Texture2D ScreenQuadTex, 5, image);
|
|
|
|
|
- ScreenLocate.DebugTexture(2, LocateLightedRedTex);
|
|
|
|
|
- ScreenLocate.DebugTexture(3, ScreenQuadTex);
|
|
|
|
|
- // 融合线段和原图
|
|
|
|
|
- ScreenLocate.DebugTexture(4, image.Merge(ScreenQuadTex));
|
|
|
|
|
- ScreenLocate.DebugTexture(5, ChoosableLineTex);
|
|
|
|
|
|
|
+ QuadrilateralFit(images, 5);
|
|
|
|
|
|
|
|
//var watch = new System.Diagnostics.Stopwatch();
|
|
//var watch = new System.Diagnostics.Stopwatch();
|
|
|
//watch.Start();
|
|
//watch.Start();
|
|
@@ -147,32 +143,32 @@ namespace o0.Project
|
|
|
if (quadTemp.Count > 0)
|
|
if (quadTemp.Count > 0)
|
|
|
{
|
|
{
|
|
|
var quad = quadTemp[0];
|
|
var quad = quadTemp[0];
|
|
|
- ScreenLocate.Main.ShowScreen(ScreenLocate.Main.outputRawImages[4].transform.GetChild(0) as RectTransform,
|
|
|
|
|
- new QuadrilateralInCamera(quad, image.Size().o0Vector()));
|
|
|
|
|
|
|
+ ScreenLocate.Main.ShowScreen(ScreenLocate.Main.outputRawImages[4].transform.GetChild(0) as RectTransform,
|
|
|
|
|
+ new QuadrilateralInCamera(quad, images[0].Size().o0Vector()));
|
|
|
|
|
|
|
|
// 透视变换
|
|
// 透视变换
|
|
|
- var srcWidth = LocateLightedRedTex.width;
|
|
|
|
|
- var transformWidth = (int)((quad.B.x - quad.A.x + quad.D.x - quad.C.x) / 2);
|
|
|
|
|
- var transformHeight = (int)((quad.C.y - quad.A.y + quad.D.y - quad.B.y) / 2);
|
|
|
|
|
- var transformTex = new Texture2D(transformWidth, transformHeight);
|
|
|
|
|
- var pt = new ZIMPerspectiveTransform(new OrdinalQuadrilateral(new Vector(0, 0), new Vector(transformWidth, 0), new Vector(0, transformHeight), new Vector(transformWidth, transformHeight)), quad);
|
|
|
|
|
- var dstPixel = new UnityEngine.Color[transformWidth * transformHeight];
|
|
|
|
|
- var srcPixel = LocateLightedRedTex.GetPixels();
|
|
|
|
|
- Parallel.For(0, transformWidth, (x) =>
|
|
|
|
|
- {
|
|
|
|
|
- for (int y = 0; y < transformHeight; y++)
|
|
|
|
|
- {
|
|
|
|
|
- var index = y * transformWidth + x;
|
|
|
|
|
- var sampleCoord = pt.TransformRound(x, y);
|
|
|
|
|
- dstPixel[index] = srcPixel[sampleCoord.y * srcWidth + sampleCoord.x];
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
- transformTex.SetPixels(dstPixel);
|
|
|
|
|
- transformTex.Apply();
|
|
|
|
|
- //ScreenLocate.DebugTexture(1, transformTex);
|
|
|
|
|
-#if (!NDEBUG && DEBUG && ENABLE_LOG)
|
|
|
|
|
- Console.WriteLine($"{TAG} ScreenLocate.DebugTexture 1:{transformTex.GetNativeTexturePtr()}");
|
|
|
|
|
-#endif
|
|
|
|
|
|
|
+// var srcWidth = LocateLightedRedTex.width;
|
|
|
|
|
+// var transformWidth = (int)((quad.B.x - quad.A.x + quad.D.x - quad.C.x) / 2);
|
|
|
|
|
+// var transformHeight = (int)((quad.C.y - quad.A.y + quad.D.y - quad.B.y) / 2);
|
|
|
|
|
+// var transformTex = new Texture2D(transformWidth, transformHeight);
|
|
|
|
|
+// var pt = new ZIMPerspectiveTransform(new OrdinalQuadrilateral(new Vector(0, 0), new Vector(transformWidth, 0), new Vector(0, transformHeight), new Vector(transformWidth, transformHeight)), quad);
|
|
|
|
|
+// var dstPixel = new UnityEngine.Color[transformWidth * transformHeight];
|
|
|
|
|
+// var srcPixel = LocateLightedRedTex.GetPixels();
|
|
|
|
|
+// Parallel.For(0, transformWidth, (x) =>
|
|
|
|
|
+// {
|
|
|
|
|
+// for (int y = 0; y < transformHeight; y++)
|
|
|
|
|
+// {
|
|
|
|
|
+// var index = y * transformWidth + x;
|
|
|
|
|
+// var sampleCoord = pt.TransformRound(x, y);
|
|
|
|
|
+// dstPixel[index] = srcPixel[sampleCoord.y * srcWidth + sampleCoord.x];
|
|
|
|
|
+// }
|
|
|
|
|
+// });
|
|
|
|
|
+// transformTex.SetPixels(dstPixel);
|
|
|
|
|
+// transformTex.Apply();
|
|
|
|
|
+// //ScreenLocate.DebugTexture(1, transformTex);
|
|
|
|
|
+//#if (!NDEBUG && DEBUG && ENABLE_LOG)
|
|
|
|
|
+// Console.WriteLine($"{TAG} ScreenLocate.DebugTexture 1:{transformTex.GetNativeTexturePtr()}");
|
|
|
|
|
+//#endif
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//times.Add(watch.ElapsedMilliseconds);
|
|
//times.Add(watch.ElapsedMilliseconds);
|
|
@@ -208,7 +204,7 @@ namespace o0.Project
|
|
|
|
|
|
|
|
void Reset()
|
|
void Reset()
|
|
|
{
|
|
{
|
|
|
- // bStartLocateScreen = false;
|
|
|
|
|
|
|
+ // bStartLocateScreen = false;
|
|
|
delay = 0;
|
|
delay = 0;
|
|
|
capture = 0;
|
|
capture = 0;
|
|
|
ScreenWhiteTexture = null;
|
|
ScreenWhiteTexture = null;
|
|
@@ -276,17 +272,12 @@ namespace o0.Project
|
|
|
}
|
|
}
|
|
|
else if (locateIndex >= 4 && locateIndex < locateArea.Count - 1)
|
|
else if (locateIndex >= 4 && locateIndex < locateArea.Count - 1)
|
|
|
{
|
|
{
|
|
|
- QuadrilateralFit(out _, out _, out _);
|
|
|
|
|
|
|
+ QuadrilateralFit();
|
|
|
ScreenWhiteTexture = null;
|
|
ScreenWhiteTexture = null;
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
- QuadrilateralFit(out Texture2D LocateLightedRedTex,out Texture2D ChoosableLineTex, out Texture2D ScreenQuadTex);
|
|
|
|
|
- ScreenLocate.DebugTexture(2, LocateLightedRedTex);
|
|
|
|
|
- ScreenLocate.DebugTexture(3, ScreenQuadTex);
|
|
|
|
|
- // 融合线段和原图
|
|
|
|
|
- ScreenLocate.DebugTexture(4, LocateLightedRedTex.Merge(ScreenQuadTex));
|
|
|
|
|
- ScreenLocate.DebugTexture(5, ChoosableLineTex);
|
|
|
|
|
|
|
+ QuadrilateralFit();
|
|
|
|
|
|
|
|
if (quadTemp.Count != LocateAreaData[0].Length)
|
|
if (quadTemp.Count != LocateAreaData[0].Length)
|
|
|
{
|
|
{
|
|
@@ -612,38 +603,22 @@ namespace o0.Project
|
|
|
return sum;
|
|
return sum;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- void QuadrilateralFit(out Texture2D LocateLightedRedTex,out Texture2D ChoosableLineTex, out Texture2D ScreenQuadTex, float lineWidth = 10, Texture2D debugImage = null)
|
|
|
|
|
|
|
+ // 转换成屏幕定位所需的纹理图像
|
|
|
|
|
+ Texture2D ToLocateTex(UnityEngine.Color[] pixels)
|
|
|
{
|
|
{
|
|
|
- UnityEngine.Color[] differPixel = new UnityEngine.Color[Size.x * Size.y];
|
|
|
|
|
-
|
|
|
|
|
- //读取数据
|
|
|
|
|
- if (debugImage != null)
|
|
|
|
|
- {
|
|
|
|
|
- Debug.Log($"<color=aqua>Debug {debugImage.name}</color>");
|
|
|
|
|
- differPixel = debugImage.GetPixels();
|
|
|
|
|
- }
|
|
|
|
|
- else // 获得屏幕差值
|
|
|
|
|
- {
|
|
|
|
|
- Parallel.For(0, Size.x * Size.y, i =>
|
|
|
|
|
- {
|
|
|
|
|
- var pi = ScreenWhiteTexture[i] - ScreenBlackTexture[i];
|
|
|
|
|
- differPixel[i] = new UnityEngine.Color(pi.x, pi.y, pi.z);
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
var ScreenLocateTex = new Texture2D(Size.x, Size.y);
|
|
var ScreenLocateTex = new Texture2D(Size.x, Size.y);
|
|
|
- ScreenLocateTex.SetPixels(differPixel);
|
|
|
|
|
|
|
+ ScreenLocateTex.SetPixels(pixels);
|
|
|
ScreenLocateTex.Apply();
|
|
ScreenLocateTex.Apply();
|
|
|
//ScreenLocate.DebugTexture(2, ScreenLocateTex);
|
|
//ScreenLocate.DebugTexture(2, ScreenLocateTex);
|
|
|
- var ScreenLocateTexLighted = ScreenLocateTex.AutoLight(10);
|
|
|
|
|
|
|
+ return ScreenLocateTex.AutoLight(10);
|
|
|
|
|
|
|
|
//ScreenLocate.DebugTexture(2, ScreenLocateTexLighted);
|
|
//ScreenLocate.DebugTexture(2, ScreenLocateTexLighted);
|
|
|
|
|
|
|
|
- var ScreenLocateTexR = ScreenLocateTexLighted.ToRGB(ColorChannel.Red);
|
|
|
|
|
- var ScreenLocateTexG = ScreenLocateTexLighted.ToRGB(ColorChannel.Green);
|
|
|
|
|
- var ScreenLocateTexB = ScreenLocateTexLighted.ToRGB(ColorChannel.Blue);
|
|
|
|
|
|
|
+ //var ScreenLocateTexR = ToLocateTex.ToRGB(ColorChannel.Red);
|
|
|
|
|
+ //var ScreenLocateTexG = ToLocateTex.ToRGB(ColorChannel.Green);
|
|
|
|
|
+ //var ScreenLocateTexB = ToLocateTex.ToRGB(ColorChannel.Blue);
|
|
|
|
|
|
|
|
- LocateLightedRedTex = ScreenLocateTexR;
|
|
|
|
|
|
|
+ //LocateLightedRedTex = ScreenLocateTexR;
|
|
|
//ScreenLocate.DebugTexture(2, ScreenLocateTexR);
|
|
//ScreenLocate.DebugTexture(2, ScreenLocateTexR);
|
|
|
//ScreenLocate.DebugTexture(4, ScreenLocateTexG);
|
|
//ScreenLocate.DebugTexture(4, ScreenLocateTexG);
|
|
|
//ScreenLocate.DebugTexture(5, ScreenLocateTexB);
|
|
//ScreenLocate.DebugTexture(5, ScreenLocateTexB);
|
|
@@ -653,33 +628,74 @@ namespace o0.Project
|
|
|
//watch.Start();
|
|
//watch.Start();
|
|
|
//var times = new List<double>() { 0.0 };
|
|
//var times = new List<double>() { 0.0 };
|
|
|
|
|
|
|
|
|
|
+ //var ScreenLocateTexLightedMat = texture.Too0Mat();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
+ /// <param name="ScreenLocateTexture">用于算法检测线段的图片</param>
|
|
|
|
|
+ /// <param name="ChoosableLineTex">输出备选线段</param>
|
|
|
|
|
+ /// <param name="ScreenQuadTex">输出最终结果</param>
|
|
|
|
|
+ /// <param name="lineWidth">识别的最小线段长度</param>
|
|
|
|
|
+ /// <param name="debugImage">这个参数如果不为null,则执行debug操作</param>
|
|
|
|
|
+ void QuadrilateralFit(List<Texture2D> debugImages = null, float lineWidth = 10)
|
|
|
|
|
+ {
|
|
|
|
|
+ // 屏幕黑白差值,存放多批次的图像用于识别, 该List数量不能等于 0
|
|
|
|
|
+ List<UnityEngine.Color[]> PixelsMultipleBatches = new List<UnityEngine.Color[]>();
|
|
|
|
|
|
|
|
- var ScreenLocateTexLightedMat = ScreenLocateTexLighted.Too0Mat();
|
|
|
|
|
- //var ScreenLocateTexLightedMat = texture.Too0Mat();
|
|
|
|
|
|
|
+ //读取数据
|
|
|
|
|
+ if (debugImages != null && debugImages.Count != 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ foreach (var i in debugImages)
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log($"<color=aqua>Debug {i.name}</color>");
|
|
|
|
|
+ PixelsMultipleBatches.Add(i.GetPixels());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ else // 获得屏幕差值
|
|
|
|
|
+ {
|
|
|
|
|
+ PixelsMultipleBatches.Add(ScreenWhiteTexture.Select((i) => new UnityEngine.Color(i.x, i.y, i.z)).ToArray());
|
|
|
|
|
+ var differPixel = new UnityEngine.Color[Size.x * Size.y];
|
|
|
|
|
+ Parallel.For(0, Size.x * Size.y, i =>
|
|
|
|
|
+ {
|
|
|
|
|
+ var pi = ScreenWhiteTexture[i] - ScreenBlackTexture[i];
|
|
|
|
|
+ differPixel[i] = new UnityEngine.Color(pi.x, pi.y, pi.z);
|
|
|
|
|
+ });
|
|
|
|
|
+ PixelsMultipleBatches.Add(differPixel);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- //var (edge, edgeDir) = ScreenLocateTexLightedMat.IdentifyEdge();
|
|
|
|
|
int conSize = (int)Math.Ceiling(0.007f * Size.y) * 2 + 1;
|
|
int conSize = (int)Math.Ceiling(0.007f * Size.y) * 2 + 1;
|
|
|
conSize = Math.Max(conSize, 7); // 设置最小为7
|
|
conSize = Math.Max(conSize, 7); // 设置最小为7
|
|
|
|
|
|
|
|
float minLength = conSize * 7.7f;
|
|
float minLength = conSize * 7.7f;
|
|
|
minLength = locateIndex == -1 ? minLength : minLength * areaPercent; // minLength需要按比例缩小
|
|
minLength = locateIndex == -1 ? minLength : minLength * areaPercent; // minLength需要按比例缩小
|
|
|
- Debug.Log($"[ScreenIdentification] Size: ({Size.x},{Size.y}), 卷积核Size: {conSize}, 最小线段长度: {minLength}");
|
|
|
|
|
- var (edge, edgeDir) = ScreenLocateTexLightedMat.zimIdentifyEdgeGradientAny(conSize);
|
|
|
|
|
|
|
+ string log = $"[ScreenLocate Auto] Size: ({Size.x},{Size.y}), 卷积核Size: {conSize}, 最小线段长度: {minLength}";
|
|
|
|
|
+
|
|
|
|
|
+ var allLines = new List<LineIdentified>();
|
|
|
|
|
+ Texture2D ScreenLocateTexture = null;
|
|
|
|
|
+ List<Matrix> ScreenLocateMatList = new List<Matrix>();
|
|
|
|
|
+ foreach (var batch in PixelsMultipleBatches.Index())
|
|
|
|
|
+ {
|
|
|
|
|
+ ScreenLocateTexture = ToLocateTex(PixelsMultipleBatches[batch]);
|
|
|
|
|
+ var ScreenLocateMat = ScreenLocateTexture.Too0Mat(); // 用于获取Lines的Matrix
|
|
|
|
|
+ var lineCount = ZIMIdentifyQuadLSD(ref allLines, batch, ScreenLocateMat.zimIdentifyEdgeGradientAny(conSize));
|
|
|
|
|
+ log += $"\r\n识别图片{batch}, 识别到的线段数量为: {lineCount}";
|
|
|
|
|
+ ScreenLocateMatList.Add(ScreenLocateMat);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
|
|
|
- var quadLines = ScreenLocateTexLightedMat.ZIMIdentifyQuadLSD(
|
|
|
|
|
- edge, edgeDir,
|
|
|
|
|
- out Line[] oldLines, out List<Line> possibleLines,out List<(Line, float, float)> allLines,
|
|
|
|
|
- Screen, conSize, conSize, minLength);
|
|
|
|
|
|
|
|
|
|
|
|
+ // 过滤得到四边形的四条边
|
|
|
|
|
+ var quadLines = FilterLines(ScreenLocateMatList, allLines, GetAvgPoint(ScreenLocateMatList[0]),
|
|
|
|
|
+ out Line[] oldLines, out List<Line> possibleLines,
|
|
|
|
|
+ Screen, conSize, conSize, minLength);
|
|
|
|
|
|
|
|
|
|
|
|
|
// 将 allLines 输出一张图片
|
|
// 将 allLines 输出一张图片
|
|
|
- var allLinesMap = new Matrix(ScreenLocateTexLightedMat.Size, Tiling: true);
|
|
|
|
|
|
|
+ var allLinesMap = new Matrix(Size, Tiling: true);
|
|
|
foreach (var l in allLines)
|
|
foreach (var l in allLines)
|
|
|
{
|
|
{
|
|
|
- if (l.Item1 != null)
|
|
|
|
|
- o0Extension.DrawLine(allLinesMap, l.Item1, (x, y) => 3, new Geometry2D.Float.Vector(0, 2), true);
|
|
|
|
|
|
|
+ if (l.Line != null)
|
|
|
|
|
+ o0Extension.DrawLine(allLinesMap, l.Line, (x, y) => 3, new Geometry2D.Float.Vector(0, 2), true);
|
|
|
}
|
|
}
|
|
|
var allLinesTex = allLinesMap.ToTexRGBA(FloatValueToColor);
|
|
var allLinesTex = allLinesMap.ToTexRGBA(FloatValueToColor);
|
|
|
ScreenLocate.DebugTexture(1, allLinesTex);
|
|
ScreenLocate.DebugTexture(1, allLinesTex);
|
|
@@ -697,10 +713,10 @@ namespace o0.Project
|
|
|
LineIdentified.Add(oldLines[i]);
|
|
LineIdentified.Add(oldLines[i]);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- var drawScreenMap = new Matrix(ScreenLocateTexLightedMat.Size, Tiling: true);
|
|
|
|
|
|
|
+ var drawScreenMap = new Matrix(Size, Tiling: true);
|
|
|
foreach (var l in LineIdentified)
|
|
foreach (var l in LineIdentified)
|
|
|
o0Extension.DrawLine(drawScreenMap, l, (x, y) => 1, new Geometry2D.Float.Vector(0, lineWidth));
|
|
o0Extension.DrawLine(drawScreenMap, l, (x, y) => 1, new Geometry2D.Float.Vector(0, lineWidth));
|
|
|
- ScreenQuadTex = drawScreenMap.ToTex(); // out ScreenQuadTex
|
|
|
|
|
|
|
+ Texture2D ScreenQuadTex = drawScreenMap.ToTex(); // out ScreenQuadTex
|
|
|
|
|
|
|
|
QuadrilateralInCamera screenQuad = null;
|
|
QuadrilateralInCamera screenQuad = null;
|
|
|
if (LineIdentified.Count == 4)
|
|
if (LineIdentified.Count == 4)
|
|
@@ -727,7 +743,7 @@ namespace o0.Project
|
|
|
|
|
|
|
|
|
|
|
|
|
// 还需要输出一张识别结果图,包含干扰线段
|
|
// 还需要输出一张识别结果图,包含干扰线段
|
|
|
- var LSDLineMap = new Matrix(ScreenLocateTexLightedMat.Size, Tiling: true);
|
|
|
|
|
|
|
+ var LSDLineMap = new Matrix(Size, Tiling: true);
|
|
|
foreach (var l in possibleLines)
|
|
foreach (var l in possibleLines)
|
|
|
{
|
|
{
|
|
|
if (l != null && !quadLines.Contains(l))
|
|
if (l != null && !quadLines.Contains(l))
|
|
@@ -743,17 +759,15 @@ namespace o0.Project
|
|
|
foreach (var l in oldLines)
|
|
foreach (var l in oldLines)
|
|
|
o0Extension.DrawLine(LSDLineMap, l, (x, y) => 1, new Geometry2D.Float.Vector(0, 2), true); // 旧的屏幕线段(例如上次手动识别的)
|
|
o0Extension.DrawLine(LSDLineMap, l, (x, y) => 1, new Geometry2D.Float.Vector(0, 2), true); // 旧的屏幕线段(例如上次手动识别的)
|
|
|
}
|
|
}
|
|
|
- ChoosableLineTex = LSDLineMap.ToTexRGBA(FloatValueToColor);
|
|
|
|
|
-
|
|
|
|
|
|
|
+ Texture2D ChoosableLineTex = LSDLineMap.ToTexRGBA(FloatValueToColor);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+ 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,
|
|
|
|
|
- $"[ScreenLocate Auto] Size: ({Size.x},{Size.y}), 卷积核Size: {conSize}, 最小线段长度: {minLength}",
|
|
|
|
|
- ScreenLocateTex, allLinesTex, ScreenQuadTex);
|
|
|
|
|
|
|
+ SaveImages(FileDirectory, log, ScreenLocateTexture, allLinesTex, ScreenQuadTex);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//times.Add(watch.ElapsedMilliseconds);
|
|
//times.Add(watch.ElapsedMilliseconds);
|
|
@@ -769,7 +783,179 @@ namespace o0.Project
|
|
|
//ScreenLocate.DebugTexture(5, cvLines);
|
|
//ScreenLocate.DebugTexture(5, cvLines);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- UnityEngine.Object.Destroy(ScreenLocateTex);
|
|
|
|
|
|
|
+ {
|
|
|
|
|
+ ScreenLocate.DebugTexture(2, ScreenLocateTexture);
|
|
|
|
|
+ ScreenLocate.DebugTexture(3, ScreenQuadTex);
|
|
|
|
|
+ // 融合线段和原图
|
|
|
|
|
+ ScreenLocate.DebugTexture(4, ScreenLocateTexture.Merge(ScreenQuadTex));
|
|
|
|
|
+ ScreenLocate.DebugTexture(5, ChoosableLineTex);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Vector GetAvgPoint(Matrix screenLocateMat)
|
|
|
|
|
+ {
|
|
|
|
|
+ // 加权平均
|
|
|
|
|
+ Vector[] avgPointsColumn = new Vector[screenLocateMat.Size.x];
|
|
|
|
|
+ float[] valueSumsColumn = new float[screenLocateMat.Size.x];
|
|
|
|
|
+ Parallel.For(0, screenLocateMat.Size.x, i =>
|
|
|
|
|
+ {
|
|
|
|
|
+ for (int j = 0; j < screenLocateMat.Size.y; j++)
|
|
|
|
|
+ {
|
|
|
|
|
+ var value = screenLocateMat[i, j];
|
|
|
|
|
+ valueSumsColumn[i] += value;
|
|
|
|
|
+ avgPointsColumn[i] += new Vector(i, j) * value;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ Vector avgPoint = Vector.Zero;
|
|
|
|
|
+ var valueSum = 0f;
|
|
|
|
|
+ for (int i = 0; i < screenLocateMat.Size.x; i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ avgPoint += avgPointsColumn[i];
|
|
|
|
|
+ valueSum += valueSumsColumn[i];
|
|
|
|
|
+ }
|
|
|
|
|
+ avgPoint /= valueSum;
|
|
|
|
|
+ return avgPoint;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 返回查找到的线段数量,0是查找失败
|
|
|
|
|
+ int ZIMIdentifyQuadLSD(ref List<LineIdentified> allLines, int batch, (Matrix edgeMat, Matrix edgeDirMat) edgeGradient,
|
|
|
|
|
+ float minLength = 100)
|
|
|
|
|
+ {
|
|
|
|
|
+ var l = edgeGradient.edgeMat.IdentifyLineLSD(edgeGradient.edgeDirMat, minLength, 20, LineCaptureSize: new Vector(0, 5));
|
|
|
|
|
+ if (l == null || l.Count == 0)
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ allLines.AddRange(l.Select((i) => new LineIdentified(batch, i)));
|
|
|
|
|
+ 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)
|
|
|
|
|
+ {
|
|
|
|
|
+ //Debug.Log("[IdentifyLineLSD] lines.Count: " + lines.Count);
|
|
|
|
|
+ // LSD计算得到的矩阵尺寸较小(因为卷积),这里必须进行位移
|
|
|
|
|
+ var offset = new Vector((conSize - 1) / 2, (conSize - 1) / 2);
|
|
|
|
|
+ for (int i = 0; i < allLines.Count; i++)
|
|
|
|
|
+ allLines[i].Offset(offset);
|
|
|
|
|
+
|
|
|
|
|
+ // 沿直线计算综合梯度(梯度乘以长度系数,再乘以距离系数), distanceRatio是实际距离除以最大距离
|
|
|
|
|
+ float estimateGradient(LineIdentified line, float distanceRatio)
|
|
|
|
|
+ {
|
|
|
|
|
+ var dir = (line.Line.B - line.Line.A).Normalized;
|
|
|
|
|
+ var vertical = new Vector(-dir.y, dir.x) * (gradientLength / 2);
|
|
|
|
|
+ var step = 2;
|
|
|
|
|
+ var ll = line.Line.Length;
|
|
|
|
|
+ var lg = new List<float>();
|
|
|
|
|
+ for (int i = 0; i <= ll; i += step)
|
|
|
|
|
+ {
|
|
|
|
|
+ var point = line.Line.A + dir * i;
|
|
|
|
|
+ var ga = point + vertical;
|
|
|
|
|
+ var gb = point - vertical;
|
|
|
|
|
+ lg.Add(screenLocateMatList[line.Batch][(int)ga.x, (int)ga.y] - screenLocateMatList[line.Batch][(int)gb.x, (int)gb.y]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ float e = (float)Math.Sqrt(Math.Max(1, line.Line.Length / minLength / 3)); // 长度系数,筛选时梯度更大、长度更长的线段更优
|
|
|
|
|
+ float d = (3 - distanceRatio) / 2; // 距离系数,距离越近,系数越大
|
|
|
|
|
+ return e * d * Math.Abs(lg.Mean());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 下、右、上、左
|
|
|
|
|
+ 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;
|
|
|
|
|
+
|
|
|
|
|
+ // 如果已有定位数据,根据现有数据筛选线条
|
|
|
|
|
+ if (screen.QuadInCamera != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ Debug.Log("[IdentifyLineLSD] 根据已有定位数据做筛选");
|
|
|
|
|
+ screen.RefreshCameraSize(new Vector2(Size.x, Size.y));
|
|
|
|
|
+
|
|
|
|
|
+ var calibration = ScreenLocate.Main.ReDoLocateCalibrationRatio * Size.y;
|
|
|
|
|
+ oldLines = screen.QuadInCamera.GetLines();
|
|
|
|
|
+
|
|
|
|
|
+ var pedals = oldLines.Select((i) => o0Extension.PointPedal(i, avgPoint)).ToArray(); // 当前定位的垂足,下、右、上、左
|
|
|
|
|
+
|
|
|
|
|
+ foreach (var i in allLines)
|
|
|
|
|
+ {
|
|
|
|
|
+ float minDistance = float.MaxValue;
|
|
|
|
|
+ int index = -1;
|
|
|
|
|
+ foreach (var j in pedals.Index())
|
|
|
|
|
+ {
|
|
|
|
|
+ var d = (o0Extension.PointPedal(i.Line, avgPoint) - pedals[j]).Length;
|
|
|
|
|
+ if (d < minDistance)
|
|
|
|
|
+ {
|
|
|
|
|
+ minDistance = d;
|
|
|
|
|
+ index = j;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ //Debug.Log(minDistance +", -----------"+ calibration);
|
|
|
|
|
+ if (minDistance < calibration) // 垂足的距离足够近
|
|
|
|
|
+ {
|
|
|
|
|
+ quadLines[index].Add((estimateGradient(i, minDistance / calibration), i.Line));
|
|
|
|
|
+ possibleLines.Add(i.Line);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ var avaAngleHalf = 75f;
|
|
|
|
|
+ foreach (var line in allLines)
|
|
|
|
|
+ {
|
|
|
|
|
+ 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.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));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var result = new Line[4];
|
|
|
|
|
+ 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;
|
|
|
|
|
+ }
|
|
|
|
|
+ return result.ToList();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void SaveImages(string FileDirectory, string log, Texture2D ScreenLocateTex, Texture2D allLinesTex, Texture2D ScreenQuadTex)
|
|
void SaveImages(string FileDirectory, string log, Texture2D ScreenLocateTex, Texture2D allLinesTex, Texture2D ScreenQuadTex)
|