From c78a9418e1affbc922632aca30d50945445cd2df Mon Sep 17 00:00:00 2001 From: FishmanTheMurloc <162452111+FishmanTheMurloc@users.noreply.github.com> Date: Sun, 14 Sep 2025 20:29:52 +0800 Subject: [PATCH] =?UTF-8?q?6.0=E9=B1=BC=E5=AE=9A=E4=B9=89=E5=92=8C?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B=20(#2201)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BetterGenshinImpact.csproj | 2 +- .../GameTask/AutoFishing/Behaviours.cs | 60 +++++++++++-------- .../GameTask/AutoFishing/Model/BaitType.cs | 6 +- .../GameTask/AutoFishing/Model/BigFishType.cs | 7 +++ .../GetGridIcons/GridIconsAccuracyTestTask.cs | 23 ++++--- .../BehavioursTests.ChooseBait.cs | 30 +++++++++- .../BehavioursTests.ThrowRod.cs | 2 +- 7 files changed, 93 insertions(+), 37 deletions(-) diff --git a/BetterGenshinImpact/BetterGenshinImpact.csproj b/BetterGenshinImpact/BetterGenshinImpact.csproj index cb6b5197..8c9883e3 100644 --- a/BetterGenshinImpact/BetterGenshinImpact.csproj +++ b/BetterGenshinImpact/BetterGenshinImpact.csproj @@ -43,7 +43,7 @@ - + diff --git a/BetterGenshinImpact/GameTask/AutoFishing/Behaviours.cs b/BetterGenshinImpact/GameTask/AutoFishing/Behaviours.cs index 2aef44cc..3b4696a7 100644 --- a/BetterGenshinImpact/GameTask/AutoFishing/Behaviours.cs +++ b/BetterGenshinImpact/GameTask/AutoFishing/Behaviours.cs @@ -150,34 +150,13 @@ namespace BetterGenshinImpact.GameTask.AutoFishing logger.LogInformation("选择鱼饵 {Text}", blackboard.selectedBait.GetDescription()); // 寻找鱼饵 - using ImageRegion singleRowGrid = imageRegion.DeriveCrop(0.28 * imageRegion.Width, 0.37 * imageRegion.Height, 0.45 * imageRegion.Width, 0.22 * imageRegion.Height); - using Mat grey = singleRowGrid.SrcMat.CvtColor(ColorConversionCodes.BGR2GRAY); - using Mat canny = grey.Canny(20, 40); - - Cv2.FindContours(canny, out Point[][] contours, out _, RetrievalModes.External, ContourApproximationModes.ApproxSimple, null); - contours = contours - .Where(c => - { - Rect r = Cv2.BoundingRect(c); - if (r.Width < 0.065 * imageRegion.Width * 0.80) // 剔除太小的 - { - return false; - } - if (r.Height == 0) - { - return false; - } - return Math.Abs((float)r.Width / r.Height - 0.81) < 0.05; // 按形状筛选 - }).ToArray(); - IEnumerable boxes = contours.Select(Cv2.BoundingRect); - - foreach (Rect box in boxes) + var boxAndBaits = FindBait(imageRegion); + ; + foreach ((Rect box, string? predName) in boxAndBaits) { - using ImageRegion resRa = singleRowGrid.DeriveCrop(box); - using Mat img125 = resRa.SrcMat.GetGridIcon(); - (string predName, _) = GridIconsAccuracyTestTask.Infer(img125, this.session, this.prototypes); if (predName == blackboard.selectedBait.GetDescription()) { + using ImageRegion resRa = imageRegion.DeriveCrop(box); resRa.Click(); blackboard.Sleep(700); // 可能重复点击,所以固定界面点击下 @@ -225,6 +204,37 @@ namespace BetterGenshinImpact.GameTask.AutoFishing return BehaviourStatus.Running; } } + + public IEnumerable<(Rect, string?)> FindBait(ImageRegion imageRegion1080p) + { + using ImageRegion singleRowGrid = imageRegion1080p.DeriveCrop(0.28 * imageRegion1080p.Width, 0.37 * imageRegion1080p.Height, 0.45 * imageRegion1080p.Width, 0.22 * imageRegion1080p.Height); + using Mat grey = singleRowGrid.SrcMat.CvtColor(ColorConversionCodes.BGR2GRAY); + using Mat canny = grey.Canny(20, 40); + + Cv2.FindContours(canny, out Point[][] contours, out _, RetrievalModes.External, ContourApproximationModes.ApproxSimple, null); + contours = contours + .Where(c => + { + Rect r = Cv2.BoundingRect(c); + if (r.Width < 0.065 * imageRegion1080p.Width * 0.80) // 剔除太小的 + { + return false; + } + if (r.Height == 0) + { + return false; + } + return Math.Abs((float)r.Width / r.Height - 0.81) < 0.05; // 按形状筛选 + }).ToArray(); + IEnumerable boxes = contours.Select(Cv2.BoundingRect); + foreach (Rect box in boxes) + { + using ImageRegion resRa = singleRowGrid.DeriveCrop(box); + using Mat img125 = resRa.SrcMat.GetGridIcon(); + (string? predName, _) = GridIconsAccuracyTestTask.Infer(img125, this.session, this.prototypes); + yield return (new Rect(singleRowGrid.X + box.X, singleRowGrid.Y + box.Y, box.Width, box.Height), predName); + } + } } [Obsolete] diff --git a/BetterGenshinImpact/GameTask/AutoFishing/Model/BaitType.cs b/BetterGenshinImpact/GameTask/AutoFishing/Model/BaitType.cs index 3e269cc8..8f3049d7 100644 --- a/BetterGenshinImpact/GameTask/AutoFishing/Model/BaitType.cs +++ b/BetterGenshinImpact/GameTask/AutoFishing/Model/BaitType.cs @@ -21,5 +21,9 @@ public enum BaitType [Description("澄晶果粒饵")] SpinelgrainBait, [Description("温火饵")] - EmberglowBait + EmberglowBait, + [Description("槲梭饵")] + BerryBait, + [Description("清白饵")] + RefreshingLakkaBait } \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/AutoFishing/Model/BigFishType.cs b/BetterGenshinImpact/GameTask/AutoFishing/Model/BigFishType.cs index 6cf0f561..90162259 100644 --- a/BetterGenshinImpact/GameTask/AutoFishing/Model/BigFishType.cs +++ b/BetterGenshinImpact/GameTask/AutoFishing/Model/BigFishType.cs @@ -30,7 +30,11 @@ public class BigFishType public static readonly BigFishType Rapidfish = new("rapidfish", BaitType.SpinelgrainBait, "斗士急流鱼", 9); public static readonly BigFishType PhonyUnihornfish = new("phony unihornfish", BaitType.EmberglowBait, "燃素独角鱼", 10); public static readonly BigFishType MagmaRapidfish = new("magma rapidfish", BaitType.EmberglowBait, "炽岩斗士急流鱼", 9); + public static readonly BigFishType SecretSourceScoutSweeper = new ("secret source scout sweeper", BaitType.EmberglowBait, "秘源机关・巡戒使", 9); + public static readonly BigFishType MaulerShark = new ("mauler shark", BaitType.RefreshingLakkaBait, "凶凶鲨", 9); + public static readonly BigFishType CrystalEye = new("crystal eye", BaitType.RefreshingLakkaBait, "明眼鱼", 9); + public static readonly BigFishType AxeheadFish = new ("axehead fish", BaitType.BerryBait, "巨斧鱼", 9); public static IEnumerable Values { @@ -55,6 +59,9 @@ public class BigFishType yield return Rapidfish; yield return PhonyUnihornfish; yield return MagmaRapidfish; + yield return MaulerShark; + yield return CrystalEye; + yield return AxeheadFish; } } diff --git a/BetterGenshinImpact/GameTask/GetGridIcons/GridIconsAccuracyTestTask.cs b/BetterGenshinImpact/GameTask/GetGridIcons/GridIconsAccuracyTestTask.cs index f34900b5..4e5a9e22 100644 --- a/BetterGenshinImpact/GameTask/GetGridIcons/GridIconsAccuracyTestTask.cs +++ b/BetterGenshinImpact/GameTask/GetGridIcons/GridIconsAccuracyTestTask.cs @@ -114,15 +114,15 @@ public class GridIconsAccuracyTestTask : ISoloTask Task task1 = Delay(300, ct); // 用模型推理得到的结果 - Task<(string, int)> task2 = Task.Run(() => + Task<(string?, int)> task2 = Task.Run(() => { using Mat icon = itemRegion.SrcMat.GetGridIcon(); return Infer(icon, session, prototypes); }, ct); await Task.WhenAll(task1, task2); - (string, int) result = task2.Result; - string predName = result.Item1; + (string?, int) result = task2.Result; + string? predName = result.Item1; int predStarNum = result.Item2; // 用CV方法得到的结果 @@ -136,7 +136,11 @@ public class GridIconsAccuracyTestTask : ISoloTask // 统计结果 total_count++; - if (itemName.Contains(predName) && predStarNum == itemStarNum) + if (predName == null) + { + logger.LogInformation($"模型没有识别,应为:{itemName}|{itemStarNum}星,❌,正确率{total_acc / total_count:0.00}"); + } + else if (itemName.Contains(predName) && predStarNum == itemStarNum) { total_acc++; logger.LogInformation($"{predName}|{predStarNum}星,✔,正确率{total_acc / total_count:0.00}"); @@ -163,7 +167,7 @@ public class GridIconsAccuracyTestTask : ISoloTask /// /// (预测名称, 预测星级) /// - public static (string, int) Infer(Mat mat, InferenceSession session, Dictionary prototypes) + public static (string?, int) Infer(Mat mat, InferenceSession session, Dictionary prototypes) { if (mat.Size().Width != 125 || mat.Size().Height != 125) { @@ -194,15 +198,18 @@ public class GridIconsAccuracyTestTask : ISoloTask } if (min2 == null || distance2 < min2) { - pred_name = prototype.Key; min2 = distance2; + if (min2 < 10 * 10) // todo:负样本距离10直接读取模型 + { + pred_name = prototype.Key; + } } } - if (pred_name == null || min2 == null) + if (min2 == null) { throw new Exception("特征数据为空"); } - min2 = Math.Sqrt(min2.Value); + // min2 = Math.Sqrt(min2.Value); int pred_star = results[2].AsEnumerable().ToList().IndexOf(results[2].AsEnumerable().Max()); return (pred_name, pred_star); } diff --git a/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoFishingTests/BehavioursTests.ChooseBait.cs b/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoFishingTests/BehavioursTests.ChooseBait.cs index d5cfa27d..42c99678 100644 --- a/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoFishingTests/BehavioursTests.ChooseBait.cs +++ b/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoFishingTests/BehavioursTests.ChooseBait.cs @@ -3,6 +3,7 @@ using BetterGenshinImpact.GameTask.AutoFishing; using BetterGenshinImpact.GameTask.AutoFishing.Model; using BetterGenshinImpact.GameTask.Model.Area; using BetterGenshinImpact.GameTask.Model.Area.Converter; +using BetterGenshinImpact.Helpers.Extensions; using Microsoft.Extensions.Time.Testing; using OpenCvSharp; using System; @@ -15,10 +16,36 @@ namespace BetterGenshinImpact.UnitTest.GameTaskTests.AutoFishingTests { public partial class BehavioursTests { + [Fact] + /// + /// 测试识别数量不足的鱼饵,由于图标变灰,识别应失败 + /// + public void FindBaitTest_RecognitionShouldFail() + { + // + Mat mat = new Mat(@$"..\..\..\Assets\AutoFishing\202509141339218213_ChooseBait.png"); + var imageRegion = new ImageRegion(mat, 0, 0, new DesktopRegion(new FakeMouseSimulator()), converter: new ScaleConverter(1d)); + + FakeSystemInfo systemInfo = new FakeSystemInfo(new Vanara.PInvoke.RECT(0, 0, mat.Width, mat.Height), 1); + var blackboard = new Blackboard(); + + // + ChooseBait sut = new ChooseBait("-", blackboard, new FakeLogger(), false, systemInfo, new FakeInputSimulator(), this.session, this.prototypes); + var result = sut.FindBait(imageRegion).OrderBy(r => r.Item1.X).ToArray(); + + // + Assert.Equal(3, result.Length); + Assert.Equal(BaitType.FruitPasteBait.GetDescription(), result[0].Item2); + Assert.Equal(BaitType.BerryBait.GetDescription(), result[1].Item2); + Assert.Null(result[2].Item2); + } + [Theory] [InlineData(@"20250225101300361_ChooseBait_Succeeded.png", new string[] { "medaka", "butterflyfish", "butterflyfish", "pufferfish" })] - [InlineData(@"20250226161354285_ChooseBait_Succeeded.png", new string[] { "medaka", "medaka" })] // todo 更新用例 + [InlineData(@"20250226161354285_ChooseBait_Succeeded.png", new string[] { "medaka" })] // 不稳定的测试用例,因未学习被照亮的场景 [InlineData(@"202503160917566615@900p.png", new string[] { "pufferfish" })] + [InlineData(@"202509141339218213_ChooseBait.png", new string[] { "axehead fish" })] + [InlineData(@"202509141339218213_ChooseBait.png", new string[] { "mauler shark", "crystal eye", "medaka", "medaka", "medaka" })] /// /// 测试各种选取鱼饵,结果为成功 /// @@ -50,6 +77,7 @@ namespace BetterGenshinImpact.UnitTest.GameTaskTests.AutoFishingTests [Theory] [InlineData(@"20250226161354285_ChooseBait_Succeeded.png", new string[] { "koi" })] + [InlineData(@"202509141339218213_ChooseBait.png", new string[] { "mauler shark", "crystal eye" })] /// /// 测试各种选取鱼饵,结果为失败 /// diff --git a/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoFishingTests/BehavioursTests.ThrowRod.cs b/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoFishingTests/BehavioursTests.ThrowRod.cs index 5c0bc914..3c0dd8d8 100644 --- a/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoFishingTests/BehavioursTests.ThrowRod.cs +++ b/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoFishingTests/BehavioursTests.ThrowRod.cs @@ -14,7 +14,6 @@ namespace BetterGenshinImpact.UnitTest.GameTaskTests.AutoFishingTests { [Theory] [InlineData(@"20250225101304534_ThrowRod_Succeeded.png", BaitType.FalseWormBait)] - [InlineData(@"20250226162217468_ThrowRod_Succeeded.png", BaitType.FruitPasteBait)] /// /// 测试各种抛竿,结果为成功 /// @@ -43,6 +42,7 @@ namespace BetterGenshinImpact.UnitTest.GameTaskTests.AutoFishingTests [Theory] [InlineData(@"20250225101304534_ThrowRod_Succeeded.png", BaitType.RedrotBait)] [InlineData(@"20250225101304534_ThrowRod_Succeeded.png", BaitType.FakeFlyBait)] + [InlineData(@"20250226162217468_ThrowRod_Succeeded.png", BaitType.FruitPasteBait)] /// /// 测试各种抛竿,未满足HutaoFisher判定,结果为运行中 ///