map match test & add map viewer

This commit is contained in:
辉鸭蛋
2024-03-23 20:31:38 +08:00
parent a36c283784
commit f6e2694204
22 changed files with 634 additions and 118 deletions

View File

@@ -12,8 +12,10 @@ namespace BetterGenshinImpact.Test
InitializeComponent();
// new HsvTestWindow().Run();
MapPuzzle.Put();
// MapPuzzle.Put();
// OcrTest.TestYap();
// MatchTemplateTest.Test();
MatchTest.Test();
}
}
}

View File

@@ -104,7 +104,7 @@ public class MapPuzzle
int totalHeight = (lenRow + 1) * block;
// 创建空白大图
Mat largeImage = new Mat(totalHeight, totalWidth, MatType.CV_8UC3, new Scalar(255, 255, 255));
Mat largeImage = new Mat(totalHeight, totalWidth, MatType.CV_8UC3, new Scalar(0, 0, 0));
// 拼接图片
int[,] arr = new int[lenRow + 1, lenCol + 1];
@@ -145,6 +145,8 @@ public class MapPuzzle
// 保存大图
Cv2.ImWrite(@"E:\HuiTask\更好的原神\地图匹配\combined_image.png", largeImage);
Cv2.ImWrite(@"E:\HuiTask\更好的原神\地图匹配\combined_image_sd4x.png", largeImage.Resize(new Size(largeImage.Width / 4, largeImage.Height / 4), 0, 0, InterpolationFlags.Cubic));
Cv2.ImWrite(@"E:\HuiTask\更好的原神\地图匹配\combined_image_small.png", largeImage.Resize(new Size(1400, 1300), 0, 0, InterpolationFlags.Cubic));
// 释放资源
largeImage.Dispose();

View File

@@ -0,0 +1,27 @@
using BetterGenshinImpact.Core.Recognition.OpenCv;
using OpenCvSharp;
namespace BetterGenshinImpact.Test;
public class MatchTemplateTest
{
public static readonly Size TemplateSize = new(240, 135);
// 对无用部分进行裁剪左160上80下96
public static readonly Rect TemplateSizeRoi = new Rect(20, 10, TemplateSize.Width - 20, TemplateSize.Height - 22);
public static void Test()
{
var tar = new Mat(@"E:\HuiTask\更好的原神\地图匹配\比较\叠图\涂黑匹配2.png", ImreadModes.Color);
var sTar = tar.Resize(new Size(240, 135), 0, 0, InterpolationFlags.Cubic);
// sTar = new Mat(sTar, TemplateSizeRoi);
Cv2.ImShow("sTar", sTar);
var src = new Mat(@"E:\HuiTask\更好的原神\地图匹配\combined_image_small.png", ImreadModes.Color);
var src2 = src.Clone();
var p = MatchTemplateHelper.MatchTemplate(src, sTar, TemplateMatchModes.CCoeffNormed, null, 0.1);
Cv2.Rectangle(src2, new Rect(p.X, p.Y, sTar.Width, sTar.Height), new Scalar(0, 0, 255));
Cv2.ImWrite(@"E:\HuiTask\更好的原神\地图匹配\x1.png", src2);
}
}

View File

@@ -0,0 +1,343 @@
using OpenCvSharp;
using OpenCvSharp.Features2D;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Xml;
namespace BetterGenshinImpact.Test;
public class MatchTest
{
public static void Test()
{
var tar = new Mat(@"E:\HuiTask\更好的原神\地图匹配\比较\小地图\Clip_20240323_185641.png", ImreadModes.Color);
tar = tar.Resize(new Size(tar.Width * 2, tar.Height * 2), 0, 0, InterpolationFlags.Nearest);
var src = new Mat(@"E:\HuiTask\更好的原神\地图匹配\combined_image.png", ImreadModes.Color);
var res = MatchPicBySurf(src, tar);
Cv2.ImWrite(@"E:\HuiTask\更好的原神\地图匹配\s1.png", res);
}
public static Mat MatchPicBySift(Mat matSrc, Mat matTo)
{
Stopwatch sw = new Stopwatch();
sw.Start();
Mat matSrcRet = new Mat();
using Mat matToRet = new Mat();
KeyPoint[] keyPointsSrc, keyPointsTo;
using (var sift = SIFT.Create())
{
var kpPath = @"E:\HuiTask\更好的原神\地图匹配\sift.kp";
var kpMatPath = @"E:\HuiTask\更好的原神\地图匹配\sift.mat";
if (File.Exists(kpPath) && File.Exists(kpMatPath))
{
keyPointsSrc = (KeyPoint[])DeserializeObject(File.ReadAllBytes(kpPath));
GCHandle pinnedArray = GCHandle.Alloc(DeserializeObject(File.ReadAllBytes(kpMatPath)), GCHandleType.Pinned);
IntPtr pointer = pinnedArray.AddrOfPinnedObject();
matSrcRet = new Mat(166767, 128, MatType.CV_32FC1, pointer);
}
else
{
sift.DetectAndCompute(matSrc, null, out keyPointsSrc, matSrcRet);
byte[] arr = new byte[matSrcRet.Step(0) * matSrcRet.Rows]; // matSrcRet.Total() * matSrcRet.ElemSize()
Marshal.Copy(matSrcRet.Data, arr, 0, arr.Length);
File.WriteAllBytes(kpMatPath, SerializeObject(arr));
File.WriteAllBytes(kpPath, SerializeObject(keyPointsSrc));
}
sw.Stop();
Debug.WriteLine($"大地图kp耗时{sw.ElapsedMilliseconds}ms.");
sw.Restart();
sift.DetectAndCompute(matTo, null, out keyPointsTo, matToRet);
sw.Stop();
Debug.WriteLine($"模板kp耗时{sw.ElapsedMilliseconds}ms.");
sw.Restart();
}
using (var bfMatcher = new OpenCvSharp.BFMatcher())
{
var matches = bfMatcher.KnnMatch(matSrcRet, matToRet, k: 2);
var pointsSrc = new List<Point2f>();
var pointsDst = new List<Point2f>();
var goodMatches = new List<DMatch>();
foreach (DMatch[] items in matches.Where(x => x.Length > 1))
{
if (items[0].Distance < 0.5 * items[1].Distance)
{
pointsSrc.Add(keyPointsSrc[items[0].QueryIdx].Pt);
pointsDst.Add(keyPointsTo[items[0].TrainIdx].Pt);
goodMatches.Add(items[0]);
Debug.WriteLine($"{keyPointsSrc[items[0].QueryIdx].Pt.X}, {keyPointsSrc[items[0].QueryIdx].Pt.Y}");
}
}
sw.Stop();
Debug.WriteLine($"bfMatcher耗时{sw.ElapsedMilliseconds}ms.");
sw.Restart();
var outMat = new Mat();
// algorithm RANSAC Filter the matched results
var pSrc = pointsSrc.ConvertAll(Point2fToPoint2d);
var pDst = pointsDst.ConvertAll(Point2fToPoint2d);
var outMask = new Mat();
// If the original matching result is null, Skip the filtering step
if (pSrc.Count > 0 && pDst.Count > 0)
Cv2.FindHomography(pSrc, pDst, HomographyMethods.Ransac, mask: outMask);
sw.Stop();
Debug.WriteLine($"FindHomography耗时{sw.ElapsedMilliseconds}ms.");
sw.Restart();
// If passed RANSAC After processing, the matching points are more than 10.,Only filters are used. Otherwise, use the original matching point result(When the matching point is too small, it passes through RANSAC After treatment,It is possible to get the result of 0 matching points.).
if (outMask.Rows > 10)
{
byte[] maskBytes = new byte[outMask.Rows * outMask.Cols];
outMask.GetArray(out maskBytes);
Cv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, matchesMask: maskBytes, flags: DrawMatchesFlags.NotDrawSinglePoints);
}
else
Cv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, flags: DrawMatchesFlags.NotDrawSinglePoints);
sw.Stop();
Debug.WriteLine($"绘图耗时:{sw.ElapsedMilliseconds}ms.");
sw.Restart();
return outMat;
}
}
//This method may be missed, you may read a lot of blogs, but none of them wrote
private static Point2d Point2fToPoint2d(Point2f input)
{
Point2d p2 = new Point2d(input.X, input.Y);
return p2;
}
public static Mat MatchPicBySurf(Mat matSrc, Mat matTo, double threshold = 400)
{
Stopwatch sw = new Stopwatch();
sw.Start();
Mat matSrcRet = new Mat();
using Mat matToRet = new Mat();
KeyPoint[] keyPointsSrc, keyPointsTo;
using (var surf = OpenCvSharp.XFeatures2D.SURF.Create(threshold, 4, 3, true, true))
{
var kpPath = @"E:\HuiTask\更好的原神\地图匹配\surf.kp";
var kpMatPath = @"E:\HuiTask\更好的原神\地图匹配\surf.mat";
if (File.Exists(kpPath) && File.Exists(kpMatPath))
{
keyPointsSrc = (KeyPoint[])DeserializeObject(File.ReadAllBytes(kpPath));
GCHandle pinnedArray = GCHandle.Alloc(DeserializeObject(File.ReadAllBytes(kpMatPath)), GCHandleType.Pinned);
IntPtr pointer = pinnedArray.AddrOfPinnedObject();
matSrcRet = new Mat(166767, 128, MatType.CV_32FC1, pointer);
}
else
{
surf.DetectAndCompute(matSrc, null, out keyPointsSrc, matSrcRet);
byte[] arr = new byte[matSrcRet.Step(0) * matSrcRet.Rows]; // matSrcRet.Total() * matSrcRet.ElemSize()
Marshal.Copy(matSrcRet.Data, arr, 0, arr.Length);
File.WriteAllBytes(kpMatPath, SerializeObject(arr));
File.WriteAllBytes(kpPath, SerializeObject(keyPointsSrc));
}
sw.Stop();
Debug.WriteLine($"大地图kp耗时{sw.ElapsedMilliseconds}ms.");
sw.Restart();
surf.DetectAndCompute(matTo, null, out keyPointsTo, matToRet);
sw.Stop();
Debug.WriteLine($"模板kp耗时{sw.ElapsedMilliseconds}ms.");
sw.Restart();
}
using (var flnMatcher = new OpenCvSharp.FlannBasedMatcher())
{
var matches = flnMatcher.Match(matSrcRet, matToRet);
//Finding the Minimum and Maximum Distance
double minDistance = 1000; //Backward approximation
double maxDistance = 0;
for (int i = 0; i < matSrcRet.Rows; i++)
{
double distance = matches[i].Distance;
if (distance > maxDistance)
{
maxDistance = distance;
}
if (distance < minDistance)
{
minDistance = distance;
}
}
Debug.WriteLine($"max distance : {maxDistance}");
Debug.WriteLine($"min distance : {minDistance}");
var pointsSrc = new List<Point2f>();
var pointsDst = new List<Point2f>();
//Screening better matching points
var goodMatches = new List<DMatch>();
for (int i = 0; i < matSrcRet.Rows; i++)
{
double distance = matches[i].Distance;
if (distance < Math.Max(minDistance * 2, 0.02))
{
pointsSrc.Add(keyPointsSrc[matches[i].QueryIdx].Pt);
pointsDst.Add(keyPointsTo[matches[i].TrainIdx].Pt);
//Compression of new ones with distances less than ranges DMatch
goodMatches.Add(matches[i]);
}
}
sw.Stop();
Debug.WriteLine($"flnMatcher耗时{sw.ElapsedMilliseconds}ms.");
sw.Restart();
var outMat = new Mat();
// algorithm RANSAC Filter the matched results
var pSrc = pointsSrc.ConvertAll(Point2fToPoint2d);
var pDst = pointsDst.ConvertAll(Point2fToPoint2d);
var outMask = new Mat();
// If the original matching result is null, Skip the filtering step
if (pSrc.Count > 0 && pDst.Count > 0)
Cv2.FindHomography(pSrc, pDst, HomographyMethods.Ransac, mask: outMask);
sw.Stop();
Debug.WriteLine($"FindHomography耗时{sw.ElapsedMilliseconds}ms.");
sw.Restart();
// If passed RANSAC After processing, the matching points are more than 10.,Only filters are used. Otherwise, use the original matching point result(When the matching point is too small, it passes through RANSAC After treatment,It's possible to get the result of 0 matching points.).
if (outMask.Rows > 10)
{
Debug.WriteLine($"使用了Ransac的结果");
byte[] maskBytes = new byte[outMask.Rows * outMask.Cols];
outMask.GetArray(out maskBytes);
Cv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, matchesMask: maskBytes, flags: DrawMatchesFlags.NotDrawSinglePoints);
}
else
Cv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, flags: DrawMatchesFlags.NotDrawSinglePoints);
sw.Stop();
Debug.WriteLine($"绘图耗时:{sw.ElapsedMilliseconds}ms.");
return outMat;
}
}
/// <summary>
/// 序列化
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
private static byte[] Serialize(object obj)
{
using var memoryStream = new MemoryStream();
DataContractSerializer ser = new DataContractSerializer(typeof(object));
ser.WriteObject(memoryStream, obj);
var data = memoryStream.ToArray();
return data;
}
/// <summary>
/// 反序列化
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <returns></returns>
private static T Deserialize<T>(byte[] data)
{
using var memoryStream = new MemoryStream(data);
XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(memoryStream, new XmlDictionaryReaderQuotas());
DataContractSerializer ser = new DataContractSerializer(typeof(T));
var result = (T)ser.ReadObject(reader, true);
return result;
}
[Obsolete("Obsolete")]
public static byte[] SerializeObject(object obj)
{
if (obj == null)
return null;
//内存实例
MemoryStream ms = new MemoryStream();
//创建序列化的实例
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(ms, obj); //序列化对象写入ms流中
byte[] bytes = ms.GetBuffer();
return bytes;
}
[Obsolete("Obsolete")]
public static object DeserializeObject(byte[] bytes)
{
object obj = null;
if (bytes == null)
return obj;
//利用传来的byte[]创建一个内存流
MemoryStream ms = new MemoryStream(bytes);
ms.Position = 0;
BinaryFormatter formatter = new BinaryFormatter();
obj = formatter.Deserialize(ms); //把内存流反序列成对象
ms.Close();
return obj;
}
static bool WriteRawImage(Mat image, string filename)
{
using (FileStream file = new FileStream(filename, FileMode.Create))
{
if (file == null || !file.CanWrite)
return false;
BinaryWriter writer = new BinaryWriter(file);
writer.Write(image.Rows);
writer.Write(image.Cols);
int depth = image.Depth();
int type = image.Type();
int channels = image.Channels();
writer.Write(depth);
writer.Write(type);
writer.Write(channels);
int sizeInBytes = (int)image.Step() * image.Rows;
writer.Write(sizeInBytes);
byte[] arr = new byte[sizeInBytes];
Marshal.Copy(image.Data, arr, 0, arr.Length);
writer.Write(arr, 0, sizeInBytes);
}
return true;
}
static bool ReadRawImage(out Mat image, string filename)
{
int rows, cols, data, depth, type, channels;
image = null;
using (FileStream file = new FileStream(filename, FileMode.Open))
{
if (file == null || !file.CanRead)
return false;
try
{
BinaryReader reader = new BinaryReader(file);
rows = reader.ReadInt32();
cols = reader.ReadInt32();
depth = reader.ReadInt32();
type = reader.ReadInt32();
channels = reader.ReadInt32();
data = reader.ReadInt32();
image = new OpenCvSharp.Mat(rows, cols, (OpenCvSharp.MatType)type);
// reader.Read(image.Data, 0, data);
}
catch (Exception)
{
return false;
}
}
return true;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

@@ -27,6 +27,10 @@
<Resource Include="Assets\Highlighting\*.xshd" />
</ItemGroup>
<ItemGroup>
<None Remove="Assets\Map\map_sd1024.png" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AvalonEdit" Version="6.3.0.90" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
@@ -82,6 +86,9 @@
<Compile Update="View\PickerWindow.xaml.cs">
<SubType>Code</SubType>
</Compile>
<Compile Update="View\Windows\MapViewer.xaml.cs">
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
@@ -528,4 +535,8 @@
</None>
</ItemGroup>
<ItemGroup>
<Resource Include="Assets\Map\map_sd1024.png" />
</ItemGroup>
</Project>

View File

@@ -7,7 +7,6 @@ using BetterGenshinImpact.GameTask.AutoFight.Script;
using BetterGenshinImpact.GameTask.AutoGeniusInvokation.Exception;
using BetterGenshinImpact.GameTask.AutoPick.Assets;
using BetterGenshinImpact.GameTask.Common;
using BetterGenshinImpact.GameTask.Common.MiniMap;
using BetterGenshinImpact.GameTask.Model.Enum;
using BetterGenshinImpact.Helpers;
using BetterGenshinImpact.View.Drawable;
@@ -22,6 +21,7 @@ using System.Drawing.Imaging;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using BetterGenshinImpact.GameTask.Common.Map;
using static BetterGenshinImpact.GameTask.Common.TaskControl;
using static Vanara.PInvoke.User32;

View File

@@ -0,0 +1,42 @@
using System.Diagnostics;
using BetterGenshinImpact.Core.Recognition.OpenCv;
using BetterGenshinImpact.Helpers;
using CommunityToolkit.Mvvm.Messaging;
using CommunityToolkit.Mvvm.Messaging.Messages;
using OpenCvSharp;
using Point = OpenCvSharp.Point;
using Size = OpenCvSharp.Size;
namespace BetterGenshinImpact.GameTask.Common.Map;
public class BigMap
{
public static readonly Size TemplateSize = new(240, 135);
// 对无用部分进行裁剪左160上80下96
public static readonly Rect TemplateSizeRoi = new Rect(20, 10, TemplateSize.Width - 20, TemplateSize.Height - 22);
private readonly Mat _mapSrcMat;
public BigMap()
{
var stream = ResourceHelper.GetStream(@"pack://application:,,,/Assets/Map/map_sd1024.png");
_mapSrcMat = Mat.FromStream(stream, ImreadModes.Color);
}
public Point GetMapPosition(Mat captureMat)
{
Cv2.CvtColor(captureMat, captureMat, ColorConversionCodes.BGRA2BGR);
using var tar = new Mat(captureMat.Resize(TemplateSize, 0, 0, InterpolationFlags.Cubic), TemplateSizeRoi);
var p = MatchTemplateHelper.MatchTemplate(_mapSrcMat, tar, TemplateMatchModes.CCoeffNormed, null, 0.2);
Debug.WriteLine($"BigMap Match Template: {p}");
return p;
}
public void GetMapPositionAndDraw(Mat captureMat)
{
var p = GetMapPosition(captureMat);
WeakReferenceMessenger.Default.Send(new PropertyChangedMessage<object>(this, "UpdateBigMapRect", new object(),
new System.Windows.Rect(p.X, p.Y, TemplateSizeRoi.Width, TemplateSizeRoi.Height)));
}
}

View File

@@ -1,13 +1,13 @@
using BetterGenshinImpact.View.Drawable;
using OpenCvSharp;
using System;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using BetterGenshinImpact.View.Drawable;
using OpenCvSharp;
using Point = OpenCvSharp.Point;
using Size = OpenCvSharp.Size;
namespace BetterGenshinImpact.GameTask.Common.MiniMap;
namespace BetterGenshinImpact.GameTask.Common.Map;
public class CameraOrientation
{
@@ -47,7 +47,6 @@ public class CameraOrientation
var left2 = left.Zip(right, (x, y) => Math.Max(x - y, 0)).ToArray();
var right2 = right.Zip(left, (x, y) => Math.Max(x - y, 0)).ToArray();
// 左移后相乘 在附近2°内寻找最大值
var sum = new int[360];
for (var i = -2; i <= 2; i++)
@@ -132,4 +131,4 @@ public class CameraOrientation
return LeftShift(array, -k);
}
}
}
}

View File

@@ -1,12 +1,7 @@
using BetterGenshinImpact.View.Drawable;
using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BetterGenshinImpact.GameTask.Common.MiniMap;
namespace BetterGenshinImpact.GameTask.Common.Map;
public class CharacterOrientation
{
@@ -112,5 +107,4 @@ public class CharacterOrientation
var midY = (p1.Y + p2.Y) / 2;
return new Point(midX, midY);
}
}
}

View File

@@ -0,0 +1,5 @@
namespace BetterGenshinImpact.GameTask.Common.Map;
public class MiniMap
{
}

View File

@@ -1,16 +0,0 @@
using BetterGenshinImpact.View.Drawable;
using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using Point = OpenCvSharp.Point;
using Size = OpenCvSharp.Size;
namespace BetterGenshinImpact.GameTask.Common.MiniMap;
public class MiniMap
{
}

View File

@@ -1,11 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BetterGenshinImpact.GameTask.MiniMap.Model;
public class MiniMap
{
}

View File

@@ -1,18 +1,12 @@
using BetterGenshinImpact.Core.Config;
using BetterGenshinImpact.GameTask.Common.Map;
using BetterGenshinImpact.View.Drawable;
using Compunet.YoloV8;
using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using BetterGenshinImpact.GameTask.Common.MiniMap;
using Point = OpenCvSharp.Point;
using Size = OpenCvSharp.Size;
using BetterGenshinImpact.Core.Simulator;
namespace BetterGenshinImpact.GameTask.Placeholder;
@@ -31,7 +25,9 @@ public class TestTrigger : ITaskTrigger
//private readonly AutoGeniusInvokationAssets _autoGeniusInvokationAssets;
private readonly YoloV8 _predictor = new(Global.Absolute("Assets\\Model\\Domain\\bgi_tree.onnx"));
// private readonly YoloV8 _predictor = new(Global.Absolute("Assets\\Model\\Domain\\bgi_tree.onnx"));
private readonly BigMap _bigMap = new();
public TestTrigger()
{
@@ -49,24 +45,23 @@ public class TestTrigger : ITaskTrigger
{
// TestArrow(content);
// TestCamera(content);
Detect(content);
var angle = CameraOrientation.Compute(content);
Debug.WriteLine(angle);
if (angle < 180)
{
// 左移视角
Simulation.SendInputEx.Mouse.MoveMouseBy(-angle, 0);
}
else if (angle is > 180 and < 360)
{
// 右移视角
Simulation.SendInputEx.Mouse.MoveMouseBy(360 - angle, 0);
}
else
{
// 360 度 东方向视角
}
// Detect(content);
// var angle = CameraOrientation.Compute(content);
// Debug.WriteLine(angle);
// if (angle < 180)
// {
// // 左移视角
// Simulation.SendInputEx.Mouse.MoveMouseBy(-angle, 0);
// }
// else if (angle is > 180 and < 360)
// {
// // 右移视角
// Simulation.SendInputEx.Mouse.MoveMouseBy(360 - angle, 0);
// }
// else
// {
// // 360 度 东方向视角
// }
//var dictionary = GeniusInvokationControl.FindMultiPicFromOneImage2OneByOne(content.CaptureRectArea.SrcGreyMat, _autoGeniusInvokationAssets.RollPhaseDiceMats, 0.7);
//if (dictionary.Count > 0)
@@ -88,7 +83,6 @@ public class TestTrigger : ITaskTrigger
// Debug.WriteLine("找到了" + i + "个");
//}
//var foundRectArea = content.CaptureRectArea.Find(_autoGeniusInvokationAssets.ElementalTuningConfirmButtonRo);
//if (!foundRectArea.IsEmpty())
//{
@@ -98,24 +92,26 @@ public class TestTrigger : ITaskTrigger
//{
// Debug.WriteLine("没找到");
//}
_bigMap.GetMapPositionAndDraw(content.CaptureRectArea.SrcMat);
}
private void Detect(CaptureContent content)
{
using var memoryStream = new MemoryStream();
content.CaptureRectArea.SrcBitmap.Save(memoryStream, ImageFormat.Bmp);
memoryStream.Seek(0, SeekOrigin.Begin);
var result = _predictor.Detect(memoryStream);
Debug.WriteLine(result);
var list = new List<RectDrawable>();
foreach (var box in result.Boxes)
{
var rect = new System.Windows.Rect(box.Bounds.X, box.Bounds.Y, box.Bounds.Width, box.Bounds.Height);
list.Add(new RectDrawable(rect, _pen));
}
VisionContext.Instance().DrawContent.PutOrRemoveRectList("TreeBox", list);
}
// private void Detect(CaptureContent content)
// {
// using var memoryStream = new MemoryStream();
// content.CaptureRectArea.SrcBitmap.Save(memoryStream, ImageFormat.Bmp);
// memoryStream.Seek(0, SeekOrigin.Begin);
// var result = _predictor.Detect(memoryStream);
// Debug.WriteLine(result);
// var list = new List<RectDrawable>();
// foreach (var box in result.Boxes)
// {
// var rect = new System.Windows.Rect(box.Bounds.X, box.Bounds.Y, box.Bounds.Width, box.Bounds.Height);
// list.Add(new RectDrawable(rect, _pen));
// }
//
// VisionContext.Instance().DrawContent.PutOrRemoveRectList("TreeBox", list);
// }
public static void TestArrow(CaptureContent content)
{
@@ -220,7 +216,6 @@ public class TestTrigger : ITaskTrigger
return new Point(midX, midY);
}
public void TestCamera(CaptureContent content)
{
var mat = new Mat(content.CaptureRectArea.SrcGreyMat, new Rect(62, 19, 212, 212));
@@ -252,7 +247,6 @@ public class TestTrigger : ITaskTrigger
var left2 = left.Zip(right, (x, y) => Math.Max(x - y, 0)).ToArray();
var right2 = right.Zip(left, (x, y) => Math.Max(x - y, 0)).ToArray();
// 左移后相乘 在附近2°内寻找最大值
var sum = new int[360];
for (var i = -2; i <= 2; i++)
@@ -328,4 +322,4 @@ public class TestTrigger : ITaskTrigger
return LeftShift(array, -k);
}
}
}
}

View File

@@ -18,7 +18,7 @@ internal static class ResourceHelper
public static byte[] GetBytes(string uriString)
{
Uri uri = new(uriString);
StreamResourceInfo info = Application.GetResourceStream(uri);
StreamResourceInfo? info = Application.GetResourceStream(uri);
using BinaryReader stream = new(info.Stream);
return stream.ReadBytes((int)info.Stream.Length);
}
@@ -26,14 +26,18 @@ internal static class ResourceHelper
public static Stream GetStream(string uriString)
{
Uri uri = new(uriString);
StreamResourceInfo info = Application.GetResourceStream(uri);
StreamResourceInfo? info = Application.GetResourceStream(uri);
return info?.Stream!;
}
public static string GetString(string uriString, Encoding encoding = null!)
{
Uri uri = new(uriString);
StreamResourceInfo info = Application.GetResourceStream(uri);
StreamResourceInfo? info = Application.GetResourceStream(uri);
if (info == null)
{
throw new FileNotFoundException($"Resource not found: {uriString}");
}
using StreamReader stream = new(info.Stream, encoding ?? Encoding.UTF8);
return stream.ReadToEnd();
}

View File

@@ -309,6 +309,31 @@
</StackPanel>
</ui:CardExpander>
<!-- 地图 -->
<ui:CardControl Margin="0,0,0,12" Icon="{ui:SymbolIcon Cursor24}">
<ui:CardControl.Header>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ui:TextBlock Grid.Row="0"
Grid.Column="0"
FontTypography="Body"
Text="查看地图(开发者)"
TextWrapping="Wrap" />
<ui:TextBlock Grid.Row="1"
Grid.Column="0"
Foreground="{ui:ThemeResource TextFillColorTertiaryBrush}"
Text="查看当前识别到的位置"
TextWrapping="Wrap" />
</Grid>
</ui:CardControl.Header>
<ui:Button Margin="0,0,36,0"
Command="{Binding OpenMapViewerCommand}"
Content="查看地图" />
</ui:CardControl>
<!--<ui:CardControl Margin="0,0,0,12" Icon="{ui:SymbolIcon Keyboard24}">
<ui:CardControl.Header>
<Grid>

View File

@@ -0,0 +1,44 @@
<ui:FluentWindow x:Class="BetterGenshinImpact.View.Windows.MapViewer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:windows="clr-namespace:BetterGenshinImpact.ViewModel.Windows"
Title="地图"
Width="1400"
Height="1330"
MinWidth="700"
MinHeight="650"
d:DataContext="{d:DesignInstance Type=windows:MapViewerViewModel}"
ui:Design.Background="{DynamicResource ApplicationBackgroundBrush}"
ui:Design.Foreground="{DynamicResource TextFillColorPrimaryBrush}"
ExtendsContentIntoTitleBar="True"
ResizeMode="CanMinimize"
WindowStartupLocation="CenterScreen"
WindowStyle="SingleBorderWindow"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Canvas Grid.Row="1">
<ui:Image Source="pack://application:,,,/Assets/Map/map_sd1024.png" Stretch="Uniform" />
<Rectangle Canvas.Left="{Binding BigMapRect.Left}"
Canvas.Top="{Binding BigMapRect.Top}"
Width="{Binding BigMapRect.Width}"
Height="{Binding BigMapRect.Height}"
Stroke="Red" />
</Canvas>
<ui:TitleBar Title="地图" Grid.Row="0">
<ui:TitleBar.Icon>
<ui:ImageIcon Source="pack://application:,,,/Assets/Kirara.png" />
</ui:TitleBar.Icon>
</ui:TitleBar>
</Grid>
</ui:FluentWindow>

View File

@@ -0,0 +1,15 @@
using BetterGenshinImpact.ViewModel.Windows;
using System.Windows;
namespace BetterGenshinImpact.View.Windows;
public partial class MapViewer
{
public MapViewerViewModel ViewModel { get; }
public MapViewer()
{
DataContext = ViewModel = new();
InitializeComponent();
}
}

View File

@@ -4,39 +4,47 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d"
MinWidth="400"
MinHeight="200"
Title="配置"
Width="500"
Height="210"
WindowStyle="SingleBorderWindow"
ResizeMode="CanMinimize"
MinWidth="400"
MinHeight="200"
ui:Design.Background="{DynamicResource ApplicationBackgroundBrush}"
ui:Design.Foreground="{DynamicResource TextFillColorPrimaryBrush}"
ExtendsContentIntoTitleBar="True"
Title="配置"
>
ResizeMode="CanMinimize"
WindowStartupLocation="CenterScreen"
WindowStyle="SingleBorderWindow"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel
Grid.Row="1"
Margin="12">
<ui:TextBlock Name="TxtQuestion" Margin="5"/>
<ui:TextBox Name="TxtResponse" Margin="5"/>
<StackPanel Orientation="Horizontal" Margin="5" HorizontalAlignment="Right">
<ui:Button Content="确定" IsDefault="True" Margin="5" Name="BtnOk" Click="BtnOkClick" Appearance="Primary" />
<ui:Button Content="取消" IsCancel="True" Margin="5" Name="BtnCancel" Click="BtnCancelClick" />
<StackPanel Grid.Row="1" Margin="12">
<ui:TextBlock Name="TxtQuestion" Margin="5" />
<ui:TextBox Name="TxtResponse" Margin="5" />
<StackPanel Margin="5"
HorizontalAlignment="Right"
Orientation="Horizontal">
<ui:Button Name="BtnOk"
Margin="5"
Appearance="Primary"
Click="BtnOkClick"
Content="确定"
IsDefault="True" />
<ui:Button Name="BtnCancel"
Margin="5"
Click="BtnCancelClick"
Content="取消"
IsCancel="True" />
</StackPanel>
</StackPanel>
<ui:TitleBar Title="配置" Grid.Row="0">
<ui:TitleBar.Icon>
<ui:ImageIcon Source="pack://application:,,,/Assets/logo.png" />
<ui:ImageIcon Source="pack://application:,,,/Assets/Kirara.png" />
</ui:TitleBar.Icon>
</ui:TitleBar>

View File

@@ -12,6 +12,7 @@ using System;
using System.IO;
using BetterGenshinImpact.GameTask;
using BetterGenshinImpact.GameTask.Model.Enum;
using BetterGenshinImpact.View.Windows;
namespace BetterGenshinImpact.ViewModel.Pages;
@@ -70,4 +71,10 @@ public partial class CommonSettingsPageViewModel : ObservableObject, INavigation
Process.Start("explorer.exe", path);
}
}
[RelayCommand]
public void OnOpenMapViewer()
{
new MapViewer().Show();
}
}

View File

@@ -1,6 +1,5 @@
using BetterGenshinImpact.Core;
using BetterGenshinImpact.Core.Config;
using BetterGenshinImpact.Core.Recognition.OpenCv;
using BetterGenshinImpact.GameTask;
using BetterGenshinImpact.Genshin.Paths;
using BetterGenshinImpact.Helpers;
@@ -15,12 +14,9 @@ using Microsoft.Extensions.Logging;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interop;
using Windows.System;
using OpenCvSharp;
using Wpf.Ui.Controls;
using Rect = OpenCvSharp.Rect;
namespace BetterGenshinImpact.ViewModel.Pages;
@@ -32,10 +28,12 @@ public partial class HomePageViewModel : ObservableObject, INavigationAware
[ObservableProperty] private bool _taskDispatcherEnabled = false;
[ObservableProperty] [NotifyCanExecuteChangedFor(nameof(StartTriggerCommand))]
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(StartTriggerCommand))]
private bool _startButtonEnabled = true;
[ObservableProperty] [NotifyCanExecuteChangedFor(nameof(StopTriggerCommand))]
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(StopTriggerCommand))]
private bool _stopButtonEnabled = true;
public AllConfig Config { get; set; }
@@ -281,4 +279,4 @@ public partial class HomePageViewModel : ObservableObject, INavigationAware
}
}
}
}
}

View File

@@ -0,0 +1,23 @@
using System.Windows;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using CommunityToolkit.Mvvm.Messaging.Messages;
namespace BetterGenshinImpact.ViewModel.Windows;
public partial class MapViewerViewModel : ObservableObject
{
[ObservableProperty]
private Rect _bigMapRect = new(0, 0, 0, 0);
public MapViewerViewModel()
{
WeakReferenceMessenger.Default.Register<PropertyChangedMessage<object>>(this, (sender, msg) =>
{
if (msg.PropertyName == "UpdateBigMapRect")
{
BigMapRect = (Rect)msg.NewValue;
}
});
}
}