From 116a4c8790a49933b64faba36afc469c1d7a703f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=89=E9=B8=AD=E8=9B=8B?= Date: Sun, 21 Apr 2024 23:03:40 +0800 Subject: [PATCH] init way record --- .../Simple/AllMap/EntireMapTest.cs | 4 +- .../OpenCv/FeatureMatch/FeatureMatcher.cs | 5 +- .../GameTask/AutoTrackWay/Model/Way.cs | 23 +++++++ .../GameTask/AutoTrackWay/Model/WayPoint.cs | 34 +++++++++++ .../GameTask/AutoTrackWay/WayPointRecorder.cs | 53 ++++++++++++++++ .../Common/Element/Assets/MapAssets.cs | 13 ++++ .../GameTask/Common/Map/EntireMap.cs | 61 ++++++++++--------- .../GameTask/Common/Map/MapCoordinate.cs | 45 ++++++++++++++ .../Placeholder/PlaceholderTrigger.cs | 6 +- 9 files changed, 209 insertions(+), 35 deletions(-) create mode 100644 BetterGenshinImpact/GameTask/AutoTrackWay/Model/Way.cs create mode 100644 BetterGenshinImpact/GameTask/AutoTrackWay/Model/WayPoint.cs create mode 100644 BetterGenshinImpact/GameTask/AutoTrackWay/WayPointRecorder.cs create mode 100644 BetterGenshinImpact/GameTask/Common/Element/Assets/MapAssets.cs create mode 100644 BetterGenshinImpact/GameTask/Common/Map/MapCoordinate.cs diff --git a/BetterGenshinImpact.Test/Simple/AllMap/EntireMapTest.cs b/BetterGenshinImpact.Test/Simple/AllMap/EntireMapTest.cs index 0bc95c27..7055fd0b 100644 --- a/BetterGenshinImpact.Test/Simple/AllMap/EntireMapTest.cs +++ b/BetterGenshinImpact.Test/Simple/AllMap/EntireMapTest.cs @@ -1,7 +1,7 @@ -using System.Diagnostics; -using BetterGenshinImpact.Core.Recognition.OpenCv; +using BetterGenshinImpact.Core.Recognition.OpenCv.FeatureMatch; using BetterGenshinImpact.Helpers; using OpenCvSharp; +using System.Diagnostics; namespace BetterGenshinImpact.Test.Simple.AllMap; diff --git a/BetterGenshinImpact/Core/Recognition/OpenCv/FeatureMatch/FeatureMatcher.cs b/BetterGenshinImpact/Core/Recognition/OpenCv/FeatureMatch/FeatureMatcher.cs index 7c728d4b..67187b2c 100644 --- a/BetterGenshinImpact/Core/Recognition/OpenCv/FeatureMatch/FeatureMatcher.cs +++ b/BetterGenshinImpact/Core/Recognition/OpenCv/FeatureMatch/FeatureMatcher.cs @@ -5,6 +5,7 @@ using OpenCvSharp.XFeatures2D; using System; using System.Collections.Generic; using System.Diagnostics; +using BetterGenshinImpact.GameTask.Common.Map; using OpenCvSharp.Features2D; namespace BetterGenshinImpact.Core.Recognition.OpenCv.FeatureMatch; @@ -18,8 +19,8 @@ public class FeatureMatcher private readonly KeyPoint[] _trainKeyPoints; private readonly KeyPointFeatureBlock[][] _blocks; // 特征块存储 - private readonly int _splitRow = 13 * 2; // 特征点拆分行数 - private readonly int _splitCol = 14 * 2; // 特征点拆分列数 + private readonly int _splitRow = MapCoordinate.GameMapRows * 2; // 特征点拆分行数 + private readonly int _splitCol = MapCoordinate.GameMapCols * 2; // 特征点拆分列数 private KeyPointFeatureBlock? _lastMergedBlock; // 上次合并的特征块 public FeatureMatcher(Mat trainMat, Feature2DType type = Feature2DType.SIFT, double threshold = 100) diff --git a/BetterGenshinImpact/GameTask/AutoTrackWay/Model/Way.cs b/BetterGenshinImpact/GameTask/AutoTrackWay/Model/Way.cs new file mode 100644 index 00000000..196b81ea --- /dev/null +++ b/BetterGenshinImpact/GameTask/AutoTrackWay/Model/Way.cs @@ -0,0 +1,23 @@ +using OpenCvSharp; +using System.Collections.Generic; +using System.Diagnostics; + +namespace BetterGenshinImpact.GameTask.AutoTrackWay.Model; + +public class Way +{ + private List WayPointList { get; set; } = new(); + + public void AddPoint(Rect matchRect) + { + // 长宽比例大于 1.5 的矩形不加入 + var r = matchRect.Width / (double)matchRect.Height; + if (r is > 1.5 or < 0.66) + { + Debug.WriteLine($"长宽比例不符合要求: {r}"); + return; + } + + WayPointList.Add(WayPoint.BuildFrom(matchRect, WayPointList.Count)); + } +} diff --git a/BetterGenshinImpact/GameTask/AutoTrackWay/Model/WayPoint.cs b/BetterGenshinImpact/GameTask/AutoTrackWay/Model/WayPoint.cs new file mode 100644 index 00000000..7a23c774 --- /dev/null +++ b/BetterGenshinImpact/GameTask/AutoTrackWay/Model/WayPoint.cs @@ -0,0 +1,34 @@ +using OpenCvSharp; +using System; +using BetterGenshinImpact.Core.Recognition.OpenCv; +using BetterGenshinImpact.GameTask.Common.Map; + +namespace BetterGenshinImpact.GameTask.AutoTrackWay.Model; + +/// +/// 路线点 +/// 坐标必须游戏内坐标系 +/// +[Serializable] +public class WayPoint +{ + public Point Pt { get; set; } + + public Rect MatchRect { get; set; } + + public int Index { get; set; } + + public DateTime Time { get; set; } + + public static WayPoint BuildFrom(Rect matchRect, int index) + { + var pt = MapCoordinate.Main1024ToGame(matchRect.GetCenterPoint()); + return new WayPoint + { + Pt = pt, + MatchRect = new Rect(pt, matchRect.Size), + Index = index, + Time = DateTime.Now + }; + } +} diff --git a/BetterGenshinImpact/GameTask/AutoTrackWay/WayPointRecorder.cs b/BetterGenshinImpact/GameTask/AutoTrackWay/WayPointRecorder.cs new file mode 100644 index 00000000..97ae00c2 --- /dev/null +++ b/BetterGenshinImpact/GameTask/AutoTrackWay/WayPointRecorder.cs @@ -0,0 +1,53 @@ +using BetterGenshinImpact.Core.Recognition.OpenCv; +using BetterGenshinImpact.GameTask.Common.Element.Assets; +using BetterGenshinImpact.GameTask.Common.Map; +using OpenCvSharp; +using System; +using System.Threading; +using System.Threading.Tasks; +using BetterGenshinImpact.GameTask.AutoTrackWay.Model; +using static BetterGenshinImpact.GameTask.Common.TaskControl; + +namespace BetterGenshinImpact.GameTask.AutoTrackWay; + +public class WayPointRecorder +{ + private readonly Lazy _bigMap = new(); + + public void Switch() + { + } + + public Task RecordTask(CancellationTokenSource cts) + { + return new Task(() => + { + Way way = new(); + + while (!cts.Token.IsCancellationRequested) + { + Sleep(10, cts); + var ra = GetRectAreaFromDispatcher(); + + // 小地图匹配测试 + var tar = ElementAssets.Instance.PaimonMenuRo.TemplateImageGreyMat!; + var p = MatchTemplateHelper.MatchTemplate(ra.SrcGreyMat, tar, TemplateMatchModes.CCoeffNormed, null, 0.9); + if (p.X == 0 || p.Y == 0) + { + Sleep(50, cts); + continue; + } + + var rect = _bigMap.Value.GetMapPositionByFeatureMatch(new Mat(ra.SrcGreyMat, new Rect(p.X + 24, p.Y - 15, 210, 210))); + if (rect != Rect.Empty) + { + way.AddPoint(rect); + } + else + { + Sleep(50, cts); + } + } + }, cts.Token); + } +} diff --git a/BetterGenshinImpact/GameTask/Common/Element/Assets/MapAssets.cs b/BetterGenshinImpact/GameTask/Common/Element/Assets/MapAssets.cs new file mode 100644 index 00000000..9bd0fbe5 --- /dev/null +++ b/BetterGenshinImpact/GameTask/Common/Element/Assets/MapAssets.cs @@ -0,0 +1,13 @@ +using BetterGenshinImpact.Core.Config; +using BetterGenshinImpact.GameTask.Model; +using OpenCvSharp; +using System; + +namespace BetterGenshinImpact.GameTask.Common.Element.Assets; + +public class MapAssets : BaseAssets +{ + public Lazy MainMap100BlockMat { get; } = new(() => new Mat(Global.Absolute(@"Assets\Map\mainMap100Block.png"))); + + public Lazy MainMap1024BlockMat { get; } = new(() => new Mat(@"E:\HuiTask\更好的原神\地图匹配\有用的素材\mainMap1024Block.png", ImreadModes.Grayscale)); +} diff --git a/BetterGenshinImpact/GameTask/Common/Map/EntireMap.cs b/BetterGenshinImpact/GameTask/Common/Map/EntireMap.cs index 4dcbdb5d..d3fb1a7b 100644 --- a/BetterGenshinImpact/GameTask/Common/Map/EntireMap.cs +++ b/BetterGenshinImpact/GameTask/Common/Map/EntireMap.cs @@ -6,8 +6,10 @@ using CommunityToolkit.Mvvm.Messaging.Messages; using OpenCvSharp; using System; using System.Diagnostics; +using BetterGenshinImpact.Model; using Point = OpenCvSharp.Point; using Size = OpenCvSharp.Size; +using BetterGenshinImpact.GameTask.Common.Element.Assets; namespace BetterGenshinImpact.GameTask.Common.Map; @@ -34,7 +36,7 @@ public class EntireMap /// private readonly Mat _cityMap2048BlockMat; - private readonly FeatureMatcher _surfMatcher; + private readonly FeatureMatcher _featureMatcher; private int _prevX = -1; private int _prevY = -1; @@ -42,10 +44,10 @@ public class EntireMap public EntireMap() { // 大地图模板匹配使用的模板 - _mainMap100BlockMat = new Mat(Global.Absolute(@"Assets\Map\mainMap100Block.png")); - _mainMap1024BlockMat = new Mat(@"E:\HuiTask\更好的原神\地图匹配\有用的素材\mainMap1024Block.png", ImreadModes.Grayscale); + _mainMap100BlockMat = MapAssets.Instance.MainMap100BlockMat.Value; + _mainMap1024BlockMat = MapAssets.Instance.MainMap1024BlockMat.Value; // _cityMap2048BlockMat = new Mat(@"E:\HuiTask\更好的原神\地图匹配\有用的素材\cityMap2048Block.png", ImreadModes.Grayscale); - _surfMatcher = new FeatureMatcher(_mainMap1024BlockMat); + _featureMatcher = new FeatureMatcher(_mainMap1024BlockMat); } /// @@ -74,29 +76,37 @@ public class EntireMap /// 基于Surf匹配获取地图位置(1024区块) /// 支持大地图和小地图 /// - /// 灰度图 + /// 灰度图 /// - public Rect GetMapPositionBySurf(Mat captureGreyMat) + public Rect GetMapPositionByFeatureMatch(Mat greyMat) { - Point2f[]? pArray; - if (_prevX != -1 && _prevY != -1) + try { - pArray = _surfMatcher.Match(captureGreyMat, _prevX, _prevY); - } - else - { - pArray = _surfMatcher.Match(captureGreyMat); - } + Point2f[]? pArray; + if (_prevX != -1 && _prevY != -1) + { + pArray = _featureMatcher.Match(greyMat, _prevX, _prevY); + } + else + { + pArray = _featureMatcher.Match(greyMat); + } - if (pArray == null || pArray.Length < 4) + if (pArray == null || pArray.Length < 4) + { + throw new InvalidOperationException(); + } + var rect = Cv2.BoundingRect(pArray); + _prevX = rect.X + rect.Width / 2; + _prevY = rect.Y + rect.Height / 2; + return rect; + } + catch { (_prevX, _prevY) = (-1, -1); - throw new InvalidOperationException(); + Debug.WriteLine("Surf Match Failed"); + return Rect.Empty; } - var rect = Cv2.BoundingRect(pArray); - _prevX = rect.X + rect.Width / 2; - _prevY = rect.Y + rect.Height / 2; - return rect; } // public static Point GetIntersection(Point2f[] points) @@ -118,18 +128,13 @@ public class EntireMap // return new Point((int)x, (int)y); // } - public void GetMapPositionAndDrawBySurf(Mat captureGreyMat) + public void GetMapPositionAndDrawByFeatureMatch(Mat captureGreyMat) { - try + var rect = GetMapPositionByFeatureMatch(captureGreyMat); + if (rect != Rect.Empty) { - var rect = GetMapPositionBySurf(captureGreyMat); WeakReferenceMessenger.Default.Send(new PropertyChangedMessage(this, "UpdateBigMapRect", new object(), new System.Windows.Rect(rect.X / 10.24, rect.Y / 10.24, rect.Width / 10.24, rect.Height / 10.24))); } - catch (Exception) - { - (_prevX, _prevY) = (-1, -1); - Debug.WriteLine("Surf Match Failed"); - } } } diff --git a/BetterGenshinImpact/GameTask/Common/Map/MapCoordinate.cs b/BetterGenshinImpact/GameTask/Common/Map/MapCoordinate.cs new file mode 100644 index 00000000..f555672e --- /dev/null +++ b/BetterGenshinImpact/GameTask/Common/Map/MapCoordinate.cs @@ -0,0 +1,45 @@ +using System; +using OpenCvSharp; + +namespace BetterGenshinImpact.GameTask.Common.Map; + +/// +/// 地图坐标系转换 +/// 1. 原神游戏坐标系 Game +/// 2. BetterGI主地图1024区块坐标系 Main1024 +/// +public class MapCoordinate +{ + public static readonly int GameMapRows = 13; // 游戏坐标下地图块的行数 + public static readonly int GameMapCols = 14; // 游戏坐标下地图块的列数 + public static readonly int GameMapUpRows = 5; // 游戏坐标下 左上角离地图原点的行数 + public static readonly int GameMapLeftCols = 7; // 游戏坐标下 左上角离地图原点的列数 + public static readonly int GameMapBlockWidth = 1024; // 游戏地图块的长宽 + + /// + /// 原神游戏坐标系 -> 主地图1024区块坐标系 + /// + /// [a,b,c] + /// + public static Point GameToMain1024(decimal[] position) + { + // 四舍六入五取偶 + var a = (int)Math.Round(position[0]); // 上 + var c = (int)Math.Round(position[2]); // 左 + + // 转换1024区块坐标,大地图坐标系正轴是往左上方向的 + // 这里写最左上角的区块坐标(GameMapUpRows,GameMapLeftCols)/(上,左),截止4.5版本,最左上角的区块坐标是(5,7) + + return new Point((GameMapLeftCols + 1) * GameMapBlockWidth - c, (GameMapUpRows + 1) * GameMapBlockWidth - a); + } + + /// + /// 主地图1024区块坐标系 -> 原神游戏坐标系 + /// + /// + /// + public static Point Main1024ToGame(Point point) + { + return new Point((GameMapLeftCols + 1) * GameMapBlockWidth - point.X, (GameMapUpRows + 1) * GameMapBlockWidth - point.Y); + } +} diff --git a/BetterGenshinImpact/GameTask/Placeholder/PlaceholderTrigger.cs b/BetterGenshinImpact/GameTask/Placeholder/PlaceholderTrigger.cs index 6822f8d8..1131b07d 100644 --- a/BetterGenshinImpact/GameTask/Placeholder/PlaceholderTrigger.cs +++ b/BetterGenshinImpact/GameTask/Placeholder/PlaceholderTrigger.cs @@ -40,8 +40,8 @@ public class TestTrigger : ITaskTrigger public void Init() { - IsEnabled = true; - IsExclusive = true; + IsEnabled = false; + IsExclusive = false; } public void OnCapture(CaptureContent content) @@ -104,7 +104,7 @@ public class TestTrigger : ITaskTrigger return; } - _bigMap.Value.GetMapPositionAndDrawBySurf(new Mat(content.CaptureRectArea.SrcGreyMat, new Rect(p.X + 24, p.Y - 15, 210, 210))); + _bigMap.Value.GetMapPositionAndDrawByFeatureMatch(new Mat(content.CaptureRectArea.SrcGreyMat, new Rect(p.X + 24, p.Y - 15, 210, 210))); // 大地图测试 // var mat = content.CaptureRectArea.SrcGreyMat;