diff --git a/BetterGenshinImpact/BetterGenshinImpact.csproj b/BetterGenshinImpact/BetterGenshinImpact.csproj index a0a01c15..172c3c01 100644 --- a/BetterGenshinImpact/BetterGenshinImpact.csproj +++ b/BetterGenshinImpact/BetterGenshinImpact.csproj @@ -56,16 +56,16 @@ - - - + + + - - + + diff --git a/BetterGenshinImpact/Core/Recognition/OpenCv/CommonExtension.cs b/BetterGenshinImpact/Core/Recognition/OpenCv/CommonExtension.cs index 8736c805..4f25458c 100644 --- a/BetterGenshinImpact/Core/Recognition/OpenCv/CommonExtension.cs +++ b/BetterGenshinImpact/Core/Recognition/OpenCv/CommonExtension.cs @@ -61,14 +61,14 @@ public static class CommonExtension public static Point GetCenterPoint(this Rect rectangle) { - if (rectangle == Rect.Empty) throw new ArgumentException("rectangle is empty"); + if (rectangle == default) throw new ArgumentException("rectangle is empty"); return new Point(rectangle.X + rectangle.Width / 2, rectangle.Y + rectangle.Height / 2); } public static Rect Multiply(this Rect rect, double assetScale) { - if (rect == Rect.Empty) throw new ArgumentException("rect is empty"); + if (rect == default) throw new ArgumentException("rect is empty"); return new Rect((int)(rect.X * assetScale), (int)(rect.Y * assetScale), (int)(rect.Width * assetScale), (int)(rect.Height * assetScale)); } diff --git a/BetterGenshinImpact/Core/Recognition/OpenCv/FeatureMatch/FeatureMatcher.cs b/BetterGenshinImpact/Core/Recognition/OpenCv/FeatureMatch/FeatureMatcher.cs index 446ad10f..28d57ad0 100644 --- a/BetterGenshinImpact/Core/Recognition/OpenCv/FeatureMatch/FeatureMatcher.cs +++ b/BetterGenshinImpact/Core/Recognition/OpenCv/FeatureMatch/FeatureMatcher.cs @@ -334,7 +334,7 @@ public class FeatureMatcher var corners = MatchCorners(_trainKeyPoints, _trainDescriptors, queryMat, queryMatMask); if (corners.Length == 0) { - return Rect.Empty; + return default; } return Cv2.BoundingRect(corners); } @@ -483,7 +483,7 @@ public class FeatureMatcher var corners = KnnMatchCorners(_trainKeyPoints, _trainDescriptors, queryMat, queryMatMask); if (corners.Length == 0) { - return Rect.Empty; + return default; } return Cv2.BoundingRect(corners); } diff --git a/BetterGenshinImpact/Core/Recognition/OpenCv/OpenCvCommonHelper.cs b/BetterGenshinImpact/Core/Recognition/OpenCv/OpenCvCommonHelper.cs index b5d8557e..2ce6cb77 100644 --- a/BetterGenshinImpact/Core/Recognition/OpenCv/OpenCvCommonHelper.cs +++ b/BetterGenshinImpact/Core/Recognition/OpenCv/OpenCvCommonHelper.cs @@ -1,5 +1,8 @@ -using OpenCvSharp; +using System; +using System.Collections.Generic; +using OpenCvSharp; using System.Diagnostics; +using System.Linq; namespace BetterGenshinImpact.Core.Recognition.OpenCv; @@ -7,7 +10,6 @@ public class OpenCvCommonHelper { /// /// 计算灰度图中某个颜色的像素个数 - /// 快速遍历方法来自于: https://blog.csdn.net/TyroneKing/article/details/129108838 /// /// /// @@ -15,57 +17,65 @@ public class OpenCvCommonHelper public static int CountGrayMatColor(Mat mat, byte color) { Debug.Assert(mat.Depth() == MatType.CV_8U); - var channels = mat.Channels(); - var nRows = mat.Rows; - var nCols = mat.Cols * channels; - if (mat.IsContinuous()) + return SplitChannal(mat, m => CountGrayMatColorC1(m, color)).Sum(); + } + + private static IEnumerable SplitChannal(Mat mat, Func func) + { + if (mat.Empty()) return []; + if (mat.Channels() == 1) { - nCols *= nRows; - nRows = 1; + return [func.Invoke(mat)]; } - var sum = 0; - unsafe + Mat[]? channels = null; + try { - for (var i = 0; i < nRows; i++) - { - var p = mat.Ptr(i); - var b = (byte*)p.ToPointer(); - for (var j = 0; j < nCols; j++) - if (b[j] == color) - sum++; - } + channels = mat.Split(); + return channels.AsParallel().Select(func); } + finally + { + // 释放所有分离出的通道内存 + if (channels is not null) + foreach (var ch in channels) + ch.Dispose(); + } + } - return sum; + /// + /// 仅限单通道,统计等于color的颜色 + /// + /// 矩阵 + /// 值 + /// + public static int CountGrayMatColorC1(Mat mat, byte color) + { + Debug.Assert(mat.Depth() == MatType.CV_8U); + Debug.Assert(mat.Channels() == 1); + using var dst = new Mat(); + Cv2.Compare(mat, color, dst, CmpType.EQ); + return Cv2.CountNonZero(dst); + } + + /// + /// 仅限单通道,统计颜色在lowColor和highColor中范围 + /// + /// 矩阵 + /// 低 + /// 高 + /// + public static int CountGrayMatColorC1(Mat mat, byte lowColor, byte highColor) + { + using var mask = new Mat(); + // 使用InRange直接生成二值掩膜 + Cv2.InRange(mat, new Scalar(lowColor), new Scalar(highColor), mask); + return Cv2.CountNonZero(mask); } public static int CountGrayMatColor(Mat mat, byte lowColor, byte highColor) { - Debug.Assert(mat.Depth() == MatType.CV_8U); - var channels = mat.Channels(); - var nRows = mat.Rows; - var nCols = mat.Cols * channels; - if (mat.IsContinuous()) - { - nCols *= nRows; - nRows = 1; - } - - var sum = 0; - unsafe - { - for (var i = 0; i < nRows; i++) - { - var p = mat.Ptr(i); - var b = (byte*)p.ToPointer(); - for (var j = 0; j < nCols; j++) - if (b[j] >= lowColor && b[j] <= highColor) - sum++; - } - } - - return sum; + return SplitChannal(mat, m => CountGrayMatColorC1(m, lowColor, highColor)).Sum(); } public static Mat Threshold(Mat src, Scalar low, Scalar high) @@ -75,7 +85,7 @@ public class OpenCvCommonHelper Cv2.CvtColor(src, rgbMat, ColorConversionCodes.BGR2RGB); Cv2.InRange(rgbMat, low, high, mask); - Cv2.Threshold(mask, mask, 0, 255, ThresholdTypes.Binary); //二值化 + // Cv2.Threshold(mask, mask, 0, 255, ThresholdTypes.Binary); //二值化 //不需要 return mask.Clone(); } @@ -104,6 +114,6 @@ public class OpenCvCommonHelper { var mask = new Mat(); Cv2.InRange(src, s, s, mask); - return 255 - mask; + return ~ mask; } } diff --git a/BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs b/BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs index dc743a38..68bd5bb5 100644 --- a/BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs +++ b/BetterGenshinImpact/GameTask/AutoDomain/AutoDomainTask.cs @@ -662,7 +662,7 @@ public class AutoDomainTask : ISoloTask while (!_ct.IsCancellationRequested) { var treeRect = DetectTree(CaptureToRectArea()); - if (treeRect != Rect.Empty) + if (treeRect != default) { var treeMiddleX = treeRect.X + treeRect.Width / 2; if (treeRect.X + treeRect.Width < middleX && !_config.ShortMovement) @@ -828,7 +828,7 @@ public class AutoDomainTask : ISoloTask return new Rect(box.Bounds.X, box.Bounds.Y, box.Bounds.Width, box.Bounds.Height); } - return Rect.Empty; + return default; } private Task LockCameraToEastTask(CancellationTokenSource cts, Task moveAvatarTask) diff --git a/BetterGenshinImpact/GameTask/AutoFight/Model/Avatar.cs b/BetterGenshinImpact/GameTask/AutoFight/Model/Avatar.cs index 622f76b2..5fe275f9 100644 --- a/BetterGenshinImpact/GameTask/AutoFight/Model/Avatar.cs +++ b/BetterGenshinImpact/GameTask/AutoFight/Model/Avatar.cs @@ -299,7 +299,7 @@ public class Avatar /// public bool IsActive(ImageRegion region) { - if (IndexRect == Rect.Empty) + if (IndexRect == default) { throw new Exception("IndexRect为空"); } @@ -328,7 +328,7 @@ public class Avatar public bool IsActiveNoIndexRect(ImageRegion region) { // 通过寻找右侧人物编号来判断是否出战 - if (IndexRect == Rect.Empty) + if (IndexRect == default) { var assetScale = TaskContext.Instance().SystemInfo.AssetScale; // 剪裁出队伍区域 diff --git a/BetterGenshinImpact/GameTask/AutoFight/Model/CombatScenes.cs b/BetterGenshinImpact/GameTask/AutoFight/Model/CombatScenes.cs index dc7d8fbf..f8bd7121 100644 --- a/BetterGenshinImpact/GameTask/AutoFight/Model/CombatScenes.cs +++ b/BetterGenshinImpact/GameTask/AutoFight/Model/CombatScenes.cs @@ -230,7 +230,7 @@ public class CombatScenes : IDisposable var avatars = new Avatar[AvatarCount]; for (var i = 0; i < AvatarCount; i++) { - var nameRect = nameRects?[i] ?? Rect.Empty; + var nameRect = nameRects?[i] ?? default; avatars[i] = new Avatar(this, names[i], i + 1, nameRect) { IndexRect = avatarIndexRectList[i] diff --git a/BetterGenshinImpact/GameTask/AutoFishing/AutoFishingImageRecognition.cs b/BetterGenshinImpact/GameTask/AutoFishing/AutoFishingImageRecognition.cs index 64f2f17c..b9612104 100644 --- a/BetterGenshinImpact/GameTask/AutoFishing/AutoFishingImageRecognition.cs +++ b/BetterGenshinImpact/GameTask/AutoFishing/AutoFishingImageRecognition.cs @@ -99,7 +99,7 @@ namespace BetterGenshinImpact.GameTask.AutoFishing Debug.WriteLine(e); } - return Rect.Empty; + return default; } } } \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/AutoFishing/Behaviours.cs b/BetterGenshinImpact/GameTask/AutoFishing/Behaviours.cs index 42f703b2..d578e128 100644 --- a/BetterGenshinImpact/GameTask/AutoFishing/Behaviours.cs +++ b/BetterGenshinImpact/GameTask/AutoFishing/Behaviours.cs @@ -63,7 +63,7 @@ namespace BetterGenshinImpact.GameTask.AutoFishing var result = blackboard.Predictor.Detect(memoryStream); Debug.WriteLine($"YOLOv8识别: {result.Speed}"); var fishpond = new Fishpond(result, ignoreObtained: true); - if (fishpond.FishpondRect == Rect.Empty) + if (fishpond.FishpondRect == default) { return BehaviourStatus.Running; } @@ -313,7 +313,7 @@ namespace BetterGenshinImpact.GameTask.AutoFishing var fishpond = new Fishpond(result, includeTarget: timeProvider.GetLocalNow() <= ignoreObtainedEndTime); blackboard.fishpond = fishpond; Random _rd = new(); - if (fishpond.TargetRect == null || fishpond.TargetRect == Rect.Empty) + if (fishpond.TargetRect == null || fishpond.TargetRect == default) { if (!foundTarget) { @@ -713,7 +713,7 @@ namespace BetterGenshinImpact.GameTask.AutoFishing //VisionContext.Instance().DrawContent.PutRect("liftingWordsAreaRect", liftingWordsAreaRect.ToRectDrawable(new Pen(Color.Cyan, 2))); using var wordCaptureMat = new Mat(imageRegion.SrcMat, liftingWordsAreaRect); var currentBiteWordsTips = AutoFishingImageRecognition.MatchFishBiteWords(wordCaptureMat, liftingWordsAreaRect); - if (currentBiteWordsTips != Rect.Empty) + if (currentBiteWordsTips != default) { // VisionContext.Instance().DrawContent.PutRect("FishBiteTips", // currentBiteWordsTips diff --git a/BetterGenshinImpact/GameTask/AutoFishing/Blackboard.cs b/BetterGenshinImpact/GameTask/AutoFishing/Blackboard.cs index b93c9d32..40ae7960 100644 --- a/BetterGenshinImpact/GameTask/AutoFishing/Blackboard.cs +++ b/BetterGenshinImpact/GameTask/AutoFishing/Blackboard.cs @@ -52,7 +52,7 @@ namespace BetterGenshinImpact.GameTask.AutoFishing /// /// 拉条位置的识别框 /// - internal Rect fishBoxRect = Rect.Empty; + internal Rect fishBoxRect; /// /// 是否正在选鱼饵界面 @@ -106,7 +106,7 @@ namespace BetterGenshinImpact.GameTask.AutoFishing abort = false; throwRodNoTargetTimes = 0; throwRodNoBaitFishFailures = new List(); - fishBoxRect = Rect.Empty; + fishBoxRect = default; chooseBaitUIOpening = false; chooseBaitFailures = new List(); pitchReset = true; diff --git a/BetterGenshinImpact/GameTask/AutoFishing/Model/Fishpond.cs b/BetterGenshinImpact/GameTask/AutoFishing/Model/Fishpond.cs index d1fcee28..ec5e7bdd 100644 --- a/BetterGenshinImpact/GameTask/AutoFishing/Model/Fishpond.cs +++ b/BetterGenshinImpact/GameTask/AutoFishing/Model/Fishpond.cs @@ -115,7 +115,7 @@ public class Fishpond { if (Fishes.Count == 0) { - return Rect.Empty; + return default; } var left = int.MaxValue; diff --git a/BetterGenshinImpact/GameTask/AutoSkip/AutoTrackTask.cs b/BetterGenshinImpact/GameTask/AutoSkip/AutoTrackTask.cs index 3d1cc4f1..eb4533ab 100644 --- a/BetterGenshinImpact/GameTask/AutoSkip/AutoTrackTask.cs +++ b/BetterGenshinImpact/GameTask/AutoSkip/AutoTrackTask.cs @@ -36,7 +36,7 @@ public class AutoTrackTask(AutoTrackParam param) : BaseIndependentTask /// /// 任务距离 /// - private Rect _missionDistanceRect = Rect.Empty; + private Rect _missionDistanceRect = default; private CancellationToken _ct; @@ -131,7 +131,7 @@ public class AutoTrackTask(AutoTrackParam param) : BaseIndependentTask var centerX = ra.Width / 2; var centerY = ra.Height / 2; var minDistance = double.MaxValue; - var nearestRect = Rect.Empty; + Rect nearestRect = default; foreach (var tpPoint in tpPointList) { var distanceTp = Math.Sqrt(Math.Pow(Math.Abs(tpPoint.X - centerX), 2) + Math.Pow(Math.Abs(tpPoint.Y - centerY), 2)); diff --git a/BetterGenshinImpact/GameTask/AutoSkip/ExpeditionTask.cs b/BetterGenshinImpact/GameTask/AutoSkip/ExpeditionTask.cs index 4a4751ce..f279e64b 100644 --- a/BetterGenshinImpact/GameTask/AutoSkip/ExpeditionTask.cs +++ b/BetterGenshinImpact/GameTask/AutoSkip/ExpeditionTask.cs @@ -75,7 +75,7 @@ public class ExpeditionTask var result = CaptureAndOcr(content, new Rect(0, 0, captureRect.Width - (int)(480 * assetScale), captureRect.Height)); var rect = result.FindRectByText("探险完成"); // TODO i>1 的时候,可以通过关键词“探索派遣限制 4 / 5 ”判断是否已经派遣完成? - if (rect != Rect.Empty) + if (rect != default) { // 点击探险完成下方的人物头像 content.CaptureRectArea.Derive(new Rect(rect.X, rect.Y + (int)(50 * assetScale), rect.Width, (int)(80 * assetScale))).Click(); @@ -83,7 +83,7 @@ public class ExpeditionTask // 重新截图 找领取 result = CaptureAndOcr(content); rect = result.FindRectByText("领取"); - if (rect != Rect.Empty) + if (rect != default) { using var ra = content.CaptureRectArea.Derive(rect); ra.Click(); @@ -96,7 +96,7 @@ public class ExpeditionTask // 选择角色 result = CaptureAndOcr(content); rect = result.FindRectByText("选择角色"); - if (rect != Rect.Empty) + if (rect != default) { content.CaptureRectArea.Derive(rect).Click(); TaskControl.Sleep(400); // 等待动画 diff --git a/BetterGenshinImpact/GameTask/AutoSkip/Model/HangoutOption.cs b/BetterGenshinImpact/GameTask/AutoSkip/Model/HangoutOption.cs index 8cfb1a3b..b79c8acc 100644 --- a/BetterGenshinImpact/GameTask/AutoSkip/Model/HangoutOption.cs +++ b/BetterGenshinImpact/GameTask/AutoSkip/Model/HangoutOption.cs @@ -23,7 +23,7 @@ public class HangoutOption : IDisposable // 选项文字所在区域初始化 // 选项图标往上下区域扩展 2/3 - var r = Rect.Empty; + Rect r = default; var captureArea = TaskContext.Instance().SystemInfo.ScaleMax1080PCaptureRect; var assetScale = TaskContext.Instance().SystemInfo.AssetScale; if (IconRect.Left > captureArea.Width / 2) @@ -44,10 +44,10 @@ public class HangoutOption : IDisposable if (r.Width < captureArea.Width / 8) { TaskControl.Logger.LogError("自动邀约:选项文字区域过小 {Rect}", TextRect); - r = Rect.Empty; + r = default; } - if (r != Rect.Empty) + if (r != default) { if (iconRect.Prev is ImageRegion prev) { diff --git a/BetterGenshinImpact/GameTask/AutoTrackPath/TpTask.cs b/BetterGenshinImpact/GameTask/AutoTrackPath/TpTask.cs index 44572a35..3f44de8a 100644 --- a/BetterGenshinImpact/GameTask/AutoTrackPath/TpTask.cs +++ b/BetterGenshinImpact/GameTask/AutoTrackPath/TpTask.cs @@ -660,7 +660,7 @@ public class TpTask(CancellationToken ct) if (mapScaleButtonRa.IsExist()) { rect = BigMap.Instance.GetBigMapRectByFeatureMatch(ra.SrcGreyMat); - if (rect == Rect.Empty) + if (rect == default) { // 滚轮调整后再次识别 Simulation.SendInput.Mouse.VerticalScroll(2); @@ -674,7 +674,7 @@ public class TpTask(CancellationToken ct) } }, TimeSpan.FromMilliseconds(500), 5); - if (rect == Rect.Empty) + if (rect == default) { throw new InvalidOperationException("多次重试后,识别大地图位置失败"); } diff --git a/BetterGenshinImpact/GameTask/Common/Map/BigMap.cs b/BetterGenshinImpact/GameTask/Common/Map/BigMap.cs index 28c18e0e..5b0b2d1c 100644 --- a/BetterGenshinImpact/GameTask/Common/Map/BigMap.cs +++ b/BetterGenshinImpact/GameTask/Common/Map/BigMap.cs @@ -53,7 +53,7 @@ public class BigMap : Singleton catch { Debug.WriteLine("Feature Match Failed"); - return Rect.Empty; + return default; } } } diff --git a/BetterGenshinImpact/GameTask/Common/Map/Camera/CameraOrientationFromLimint.cs b/BetterGenshinImpact/GameTask/Common/Map/Camera/CameraOrientationFromLimint.cs index 19521e71..e1b03e6c 100644 --- a/BetterGenshinImpact/GameTask/Common/Map/Camera/CameraOrientationFromLimint.cs +++ b/BetterGenshinImpact/GameTask/Common/Map/Camera/CameraOrientationFromLimint.cs @@ -103,8 +103,8 @@ public class CameraOrientationFromLimint private void GeneratePoints() { - Mat r = new Mat(1, rLength, MatType.CV_32F, LinearSpaced(tplInnRad, tplOutRad, rLength)); - Mat theta = new Mat(thetaLength, 1, MatType.CV_32F, LinearSpaced(0, 360, thetaLength, false)); + Mat r = Mat.FromPixelData(1, rLength, MatType.CV_32F, LinearSpaced(tplInnRad, tplOutRad, rLength)); + Mat theta =Mat.FromPixelData(thetaLength, 1, MatType.CV_32F, LinearSpaced(0, 360, thetaLength, false)); Mat rMat = r.Repeat(thetaLength, 1); Mat thetaMat = theta.Repeat(1, rLength); rotationRemapDataX = new Mat(); @@ -117,13 +117,13 @@ public class CameraOrientationFromLimint private void CreateAlphaMask() { var values = LinearSpaced(tplInnRad, tplOutRad, rLength); - var alphaMask1Row = new Mat(1, rLength, MatType.CV_32F, values.Select(v => + var alphaMask1Row = Mat.FromPixelData(1, rLength, MatType.CV_32F, values.Select(v => { var index = Array.BinarySearch(alphaParams1, v); return (float)(229 + (index < 0 ? ~index : index)); }).ToArray()); alphaMask1 = alphaMask1Row.Repeat(thetaLength, 1); - var alphaMask2Row = new Mat(1, rLength, MatType.CV_32F, values.Select(v => (float)(111.7 + 1.836 * v)).ToArray()); + var alphaMask2Row = Mat.FromPixelData(1, rLength, MatType.CV_32F, values.Select(v => (float)(111.7 + 1.836 * v)).ToArray()); alphaMask2 = alphaMask2Row.Repeat(thetaLength, 1); } diff --git a/BetterGenshinImpact/GameTask/Common/Map/CharacterOrientation.cs b/BetterGenshinImpact/GameTask/Common/Map/CharacterOrientation.cs index 8128e760..11732b4e 100644 --- a/BetterGenshinImpact/GameTask/Common/Map/CharacterOrientation.cs +++ b/BetterGenshinImpact/GameTask/Common/Map/CharacterOrientation.cs @@ -29,7 +29,7 @@ public class CharacterOrientation if (contours.Length > 0) { - var maxRect = Rect.Empty; + Rect maxRect = default; var maxIndex = 0; for (int i = 0; i < contours.Length; i++) { diff --git a/BetterGenshinImpact/GameTask/Model/Area/ImageRegion.cs b/BetterGenshinImpact/GameTask/Model/Area/ImageRegion.cs index f32816b6..44184919 100644 --- a/BetterGenshinImpact/GameTask/Model/Area/ImageRegion.cs +++ b/BetterGenshinImpact/GameTask/Model/Area/ImageRegion.cs @@ -71,7 +71,8 @@ public class ImageRegion : Region } } - public ImageRegion(Mat mat, int x, int y, Region? owner = null, INodeConverter? converter = null, DrawContent? drawContent = null) : base(x, y, mat.Width, mat.Height, owner, converter, drawContent) + public ImageRegion(Mat mat, int x, int y, Region? owner = null, INodeConverter? converter = null, + DrawContent? drawContent = null) : base(x, y, mat.Width, mat.Height, owner, converter, drawContent) { _srcMat = mat; } @@ -160,21 +161,27 @@ public class ImageRegion : Region throw new Exception($"[TemplateMatch]识别对象{ro.Name}的模板图片不能为null"); } - if (ro.RegionOfInterest != Rect.Empty) + if (ro.RegionOfInterest != default) { // TODO roi 是可以加缓存的 - if (!(0 <= ro.RegionOfInterest.X && 0 <= ro.RegionOfInterest.Width && ro.RegionOfInterest.X + ro.RegionOfInterest.Width <= roi.Cols - && 0 <= ro.RegionOfInterest.Y && 0 <= ro.RegionOfInterest.Height && ro.RegionOfInterest.Y + ro.RegionOfInterest.Height <= roi.Rows)) + if (!(0 <= ro.RegionOfInterest.X && 0 <= ro.RegionOfInterest.Width && + ro.RegionOfInterest.X + ro.RegionOfInterest.Width <= roi.Cols + && 0 <= ro.RegionOfInterest.Y && 0 <= ro.RegionOfInterest.Height && + ro.RegionOfInterest.Y + ro.RegionOfInterest.Height <= roi.Rows)) { - TaskControl.Logger.LogError("在图像{W1}x{H1}中查找模板,名称:{Name},ROI位置{X2}x{Y2},区域{H2}x{W2},边界溢出!", roi.Width, roi.Height, ro.Name, ro.RegionOfInterest.X, ro.RegionOfInterest.Y, ro.RegionOfInterest.Width, ro.RegionOfInterest.Height); + TaskControl.Logger.LogError("在图像{W1}x{H1}中查找模板,名称:{Name},ROI位置{X2}x{Y2},区域{H2}x{W2},边界溢出!", + roi.Width, roi.Height, ro.Name, ro.RegionOfInterest.X, ro.RegionOfInterest.Y, + ro.RegionOfInterest.Width, ro.RegionOfInterest.Height); } + roi = new Mat(roi, ro.RegionOfInterest); } var p = MatchTemplateHelper.MatchTemplate(roi, template, ro.TemplateMatchMode, ro.MaskMat, ro.Threshold); if (p != new Point()) { - var newRa = Derive(p.X + ro.RegionOfInterest.X, p.Y + ro.RegionOfInterest.Y, template.Width, template.Height); + var newRa = Derive(p.X + ro.RegionOfInterest.X, p.Y + ro.RegionOfInterest.Y, template.Width, + template.Height); if (ro.DrawOnWindow && !string.IsNullOrEmpty(ro.Name)) { newRa.DrawSelf(ro.Name, ro.DrawOnWindowPen); @@ -202,7 +209,7 @@ public class ImageRegion : Region } var roi = SrcGreyMat; - if (ro.RegionOfInterest != Rect.Empty) + if (ro.RegionOfInterest != default) { roi = new Mat(SrcGreyMat, ro.RegionOfInterest); } @@ -256,7 +263,9 @@ public class ImageRegion : Region if (ro.DrawOnWindow && !string.IsNullOrEmpty(ro.Name)) { // 画出OCR识别到的区域 - var drawList = result.Regions.Select(item => this.ToRectDrawable(item.Rect.BoundingRect() + ro.RegionOfInterest.Location, ro.Name, ro.DrawOnWindowPen)).ToList(); + var drawList = result.Regions.Select(item => + this.ToRectDrawable(item.Rect.BoundingRect() + ro.RegionOfInterest.Location, ro.Name, + ro.DrawOnWindowPen)).ToList(); drawContent.PutOrRemoveRectList(ro.Name, drawList); } @@ -274,27 +283,30 @@ public class ImageRegion : Region return new Region(); } } - else if (RecognitionTypes.Ocr.Equals(ro.RecognitionType) || RecognitionTypes.ColorRangeAndOcr.Equals(ro.RecognitionType)) + else if (RecognitionTypes.Ocr.Equals(ro.RecognitionType) || + RecognitionTypes.ColorRangeAndOcr.Equals(ro.RecognitionType)) { Mat roi; if (RecognitionTypes.ColorRangeAndOcr.Equals(ro.RecognitionType)) { roi = SrcMat; - if (ro.RegionOfInterest != Rect.Empty) + if (ro.RegionOfInterest != default) { roi = new Mat(SrcMat, ro.RegionOfInterest); } + roi = roi.Clone(); if (ro.ColorConversionCode != ColorConversionCodes.BGRA2BGR) { Cv2.CvtColor(roi, roi, ro.ColorConversionCode); } + Cv2.InRange(roi, ro.LowerColor, ro.UpperColor, roi); } else { roi = SrcGreyMat; - if (ro.RegionOfInterest != Rect.Empty) + if (ro.RegionOfInterest != default) { roi = new Mat(SrcGreyMat, ro.RegionOfInterest); } @@ -308,10 +320,13 @@ public class ImageRegion : Region if (ro.DrawOnWindow && !string.IsNullOrEmpty(ro.Name)) { // 画出OCR识别到的区域 - var drawList = result.Regions.Select(item => this.ToRectDrawable(item.Rect.BoundingRect() + ro.RegionOfInterest.Location, ro.Name, ro.DrawOnWindowPen)).ToList(); + var drawList = result.Regions.Select(item => + this.ToRectDrawable(item.Rect.BoundingRect() + ro.RegionOfInterest.Location, ro.Name, + ro.DrawOnWindowPen)).ToList(); drawContent.PutOrRemoveRectList(ro.Name, drawList); } - if (ro.RegionOfInterest != Rect.Empty) + + if (ro.RegionOfInterest != default) { var newRa = Derive(ro.RegionOfInterest); newRa.Text = text; @@ -354,7 +369,8 @@ public class ImageRegion : Region /// 失败后做什么 /// 无内嵌图片的 RectArea List /// - public List FindMulti(RecognitionObject ro, Action>? successAction = null, Action? failAction = null) + public List FindMulti(RecognitionObject ro, Action>? successAction = null, + Action? failAction = null) { if (!HasImage()) { @@ -387,19 +403,21 @@ public class ImageRegion : Region throw new Exception($"[TemplateMatch]识别对象{ro.Name}的模板图片不能为null"); } - if (ro.RegionOfInterest != Rect.Empty) + if (ro.RegionOfInterest != default) { roi = new Mat(roi, ro.RegionOfInterest); } - var rectList = MatchTemplateHelper.MatchOnePicForOnePic(roi, template, ro.TemplateMatchMode, ro.MaskMat, ro.Threshold); + var rectList = + MatchTemplateHelper.MatchOnePicForOnePic(roi, template, ro.TemplateMatchMode, ro.MaskMat, ro.Threshold); if (rectList.Count > 0) { var resRaList = rectList.Select(r => this.Derive(r + ro.RegionOfInterest.Location)).ToList(); if (ro.DrawOnWindow && !string.IsNullOrEmpty(ro.Name)) { - VisionContext.Instance().DrawContent.PutOrRemoveRectList(ro.Name, resRaList.Select(ra => ra.SelfToRectDrawable(ro.Name)).ToList()); + VisionContext.Instance().DrawContent.PutOrRemoveRectList(ro.Name, + resRaList.Select(ra => ra.SelfToRectDrawable(ro.Name)).ToList()); } successAction?.Invoke(resRaList); @@ -419,7 +437,7 @@ public class ImageRegion : Region else if (RecognitionTypes.Ocr.Equals(ro.RecognitionType)) { var roi = SrcGreyMat; - if (ro.RegionOfInterest != Rect.Empty) + if (ro.RegionOfInterest != default) { roi = new Mat(SrcGreyMat, ro.RegionOfInterest); } @@ -437,7 +455,9 @@ public class ImageRegion : Region if (ro.DrawOnWindow && !string.IsNullOrEmpty(ro.Name)) { // 画出OCR识别到的区域 - var drawList = result.Regions.Select(item => this.ToRectDrawable(item.Rect.BoundingRect() + ro.RegionOfInterest.Location, ro.Name, ro.DrawOnWindowPen)).ToList(); + var drawList = result.Regions.Select(item => + this.ToRectDrawable(item.Rect.BoundingRect() + ro.RegionOfInterest.Location, ro.Name, + ro.DrawOnWindowPen)).ToList(); VisionContext.Instance().DrawContent.PutOrRemoveRectList(ro.Name, drawList); } @@ -467,4 +487,4 @@ public class ImageRegion : Region _srcMat?.Dispose(); _srcBitmap?.Dispose(); } -} +} \ No newline at end of file diff --git a/BetterGenshinImpact/GameTask/Placeholder/PlaceholderTrigger.cs b/BetterGenshinImpact/GameTask/Placeholder/PlaceholderTrigger.cs index 1d105ed0..ae4a5281 100644 --- a/BetterGenshinImpact/GameTask/Placeholder/PlaceholderTrigger.cs +++ b/BetterGenshinImpact/GameTask/Placeholder/PlaceholderTrigger.cs @@ -157,7 +157,7 @@ public class TestTrigger : ITaskTrigger if (contours.Length > 0) { - var maxRect = Rect.Empty; + Rect maxRect = default; var maxIndex = 0; for (int i = 0; i < contours.Length; i++) { diff --git a/Fischless.GameCapture/BitBlt/BitBltCapture.cs b/Fischless.GameCapture/BitBlt/BitBltCapture.cs index b06bfb50..99384c8b 100644 --- a/Fischless.GameCapture/BitBlt/BitBltCapture.cs +++ b/Fischless.GameCapture/BitBlt/BitBltCapture.cs @@ -46,13 +46,28 @@ public class BitBltCapture : IGameCapture Gdi32.SafeHBITMAP hBitmap = Gdi32.SafeHBITMAP.Null; try { - User32.GetClientRect(_hWnd, out var windowRect); - int x = 0, y = 0; + if (!User32.GetClientRect(_hWnd, out var windowRect)) + { + Debug.Fail("Failed to get client rectangle"); + return null; + } + var width = windowRect.right - windowRect.left; var height = windowRect.bottom - windowRect.top; hdcSrc = User32.GetDC(_hWnd == IntPtr.Zero ? User32.GetDesktopWindow() : _hWnd); + if (hdcSrc.IsInvalid) + { + Debug.WriteLine($"Failed to get DC for {_hWnd}"); + return null; + } + hdcDest = Gdi32.CreateCompatibleDC(hdcSrc); + if (hdcSrc.IsInvalid) + { + Debug.Fail("Failed to create CompatibleDC"); + return null; + } var bmi = new Gdi32.BITMAPINFO { @@ -68,18 +83,32 @@ public class BitBltCapture : IGameCapture } }; - nint bits = 0; - hBitmap = Gdi32.CreateDIBSection(hdcDest, bmi, Gdi32.DIBColorMode.DIB_RGB_COLORS, out bits, IntPtr.Zero, 0); + hBitmap = Gdi32.CreateDIBSection(hdcDest, bmi, Gdi32.DIBColorMode.DIB_RGB_COLORS, out var bits, + IntPtr.Zero, + 0); + if (hBitmap.IsInvalid || bits == 0) + { + Debug.WriteLine($"Failed to create dIB section for {_hWnd}"); + return null; + } + var oldBitmap = Gdi32.SelectObject(hdcDest, hBitmap); + if (oldBitmap.IsNull) + { + return null; + } - Gdi32.StretchBlt(hdcDest, 0, 0, width, height, hdcSrc, x, y, width, height, Gdi32.RasterOperationMode.SRCCOPY); + if (!Gdi32.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, Gdi32.RasterOperationMode.SRCCOPY)) + { + Debug.WriteLine($"BitBlt failed for {_hWnd}"); + return null; + } - var mat = new Mat(height, width, MatType.CV_8UC4, bits); + using var mat = Mat.FromPixelData(height, width, MatType.CV_8UC4, bits); Gdi32.SelectObject(hdcDest, oldBitmap); - if (!mat.Empty()) { - Mat bgrMat = new Mat(); + var bgrMat = new Mat(); Cv2.CvtColor(mat, bgrMat, ColorConversionCodes.BGRA2BGR); return bgrMat; } @@ -95,12 +124,12 @@ public class BitBltCapture : IGameCapture } finally { - if (hBitmap != Gdi32.SafeHBITMAP.Null) + if (!hBitmap.IsNull) { Gdi32.DeleteObject(hBitmap); } - if (hdcDest != Gdi32.SafeHDC.Null) + if (!hdcDest.IsNull) { Gdi32.DeleteDC(hdcDest); } diff --git a/Fischless.GameCapture/Fischless.GameCapture.csproj b/Fischless.GameCapture/Fischless.GameCapture.csproj index 1e832bb0..9af61e65 100644 --- a/Fischless.GameCapture/Fischless.GameCapture.csproj +++ b/Fischless.GameCapture/Fischless.GameCapture.csproj @@ -19,8 +19,8 @@ - - + + \ No newline at end of file diff --git a/Fischless.GameCapture/Graphics/GraphicsCapture.cs b/Fischless.GameCapture/Graphics/GraphicsCapture.cs index b9f13bda..f0e88ddb 100644 --- a/Fischless.GameCapture/Graphics/GraphicsCapture.cs +++ b/Fischless.GameCapture/Graphics/GraphicsCapture.cs @@ -40,7 +40,7 @@ public class GraphicsCapture : IGameCapture // 用于获取帧数据的临时纹理和暂存资源 private Texture2D? _stagingTexture; - + private long _lastFrameTime = 0; @@ -81,12 +81,14 @@ public class GraphicsCapture : IGameCapture _captureFramePool.FrameArrived += OnFrameArrived; _captureSession = _captureFramePool.CreateCaptureSession(_captureItem); - if (ApiInformation.IsPropertyPresent("Windows.Graphics.Capture.GraphicsCaptureSession", "IsCursorCaptureEnabled")) + if (ApiInformation.IsPropertyPresent("Windows.Graphics.Capture.GraphicsCaptureSession", + "IsCursorCaptureEnabled")) { _captureSession.IsCursorCaptureEnabled = false; } - if (ApiInformation.IsWriteablePropertyPresent("Windows.Graphics.Capture.GraphicsCaptureSession", "IsBorderRequired")) + if (ApiInformation.IsWriteablePropertyPresent("Windows.Graphics.Capture.GraphicsCaptureSession", + "IsBorderRequired")) { _captureSession.IsBorderRequired = false; } @@ -110,7 +112,8 @@ public class GraphicsCapture : IGameCapture ResourceRegion region = new(); - DwmApi.DwmGetWindowAttribute(hWnd, DwmApi.DWMWINDOWATTRIBUTE.DWMWA_EXTENDED_FRAME_BOUNDS, out var windowRect); + DwmApi.DwmGetWindowAttribute(hWnd, DwmApi.DWMWINDOWATTRIBUTE.DWMWA_EXTENDED_FRAME_BOUNDS, + out var windowRect); User32.GetClientRect(_hWnd, out var clientRect); //POINT point = default; // 这个点和 DwmGetWindowAttribute 结果差1 //User32.ClientToScreen(hWnd, ref point); @@ -174,13 +177,14 @@ public class GraphicsCapture : IGameCapture { return; } - + // 限制最高处理帧率为66fps var now = Kernel32.GetTickCount(); if (now - _lastFrameTime < 15) { return; } + _lastFrameTime = now; var frameSize = _captureItem.Size; @@ -227,7 +231,7 @@ public class GraphicsCapture : IGameCapture try { // 创建一个新的Mat - var newFrame = new Mat(stagingTexture.Description.Height, stagingTexture.Description.Width, + var newFrame = Mat.FromPixelData(stagingTexture.Description.Height, stagingTexture.Description.Width, _isHdrEnabled ? MatType.MakeType(7, 4) : MatType.CV_8UC4, dataBox.DataPointer); // 如果是HDR,进行HDR到SDR的转换 diff --git a/Fischless.GameCapture/Graphics/Helpers/Texture2DExtensions.cs b/Fischless.GameCapture/Graphics/Helpers/Texture2DExtensions.cs index f3f94a4e..2957a74b 100644 --- a/Fischless.GameCapture/Graphics/Helpers/Texture2DExtensions.cs +++ b/Fischless.GameCapture/Graphics/Helpers/Texture2DExtensions.cs @@ -90,7 +90,7 @@ public static class Texture2DExtensions MapMode.Read, SharpDX.Direct3D11.MapFlags.None); - var mat = new Mat(staging.Description.Height, staging.Description.Width, MatType.CV_8UC4, dataBox.DataPointer); + var mat = Mat.FromPixelData(staging.Description.Height, staging.Description.Width, MatType.CV_8UC4, dataBox.DataPointer); return mat; } catch (Exception e) diff --git a/Test/BetterGenshinImpact.Test/Dataset/AvatarClassifyGen.cs b/Test/BetterGenshinImpact.Test/Dataset/AvatarClassifyGen.cs index 31079d01..66fc31a6 100644 --- a/Test/BetterGenshinImpact.Test/Dataset/AvatarClassifyGen.cs +++ b/Test/BetterGenshinImpact.Test/Dataset/AvatarClassifyGen.cs @@ -19,12 +19,16 @@ public class AvatarClassifyGen // 读取基础图像 // List sideImageFiles = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "*.png", SearchOption.TopDirectoryOnly).ToList(); // 只用一个图像 - List sideImageFiles = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "UI_AvatarIcon_Side_Varesa.png", SearchOption.TopDirectoryOnly).ToList(); - List sideImageFiles2 = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "UI_AvatarIcon_Side_Iansan.png", SearchOption.TopDirectoryOnly).ToList(); + List sideImageFiles = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), + "UI_AvatarIcon_Side_Varesa.png", SearchOption.TopDirectoryOnly).ToList(); + List sideImageFiles2 = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), + "UI_AvatarIcon_Side_Iansan.png", SearchOption.TopDirectoryOnly).ToList(); sideImageFiles.AddRange(sideImageFiles2); - List sideImageFiles3 = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "UI_AvatarIcon_Side_AmborCostumeWic.png", SearchOption.TopDirectoryOnly).ToList(); + List sideImageFiles3 = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), + "UI_AvatarIcon_Side_AmborCostumeWic.png", SearchOption.TopDirectoryOnly).ToList(); sideImageFiles.AddRange(sideImageFiles3); - List sideImageFiles4 = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "UI_AvatarIcon_Side_Ambor.png", SearchOption.TopDirectoryOnly).ToList(); + List sideImageFiles4 = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), + "UI_AvatarIcon_Side_Ambor.png", SearchOption.TopDirectoryOnly).ToList(); sideImageFiles.AddRange(sideImageFiles4); // List sideImageFiles5 = Directory.GetFiles(Path.Combine(BaseDir, "side_src"), "UI_AvatarIcon_Side_XianglingCostumeWinter.png", SearchOption.TopDirectoryOnly).ToList(); // sideImageFiles.AddRange(sideImageFiles5); @@ -72,11 +76,14 @@ public class AvatarClassifyGen for (int i = 0; i < count; i++) { // 随机挑选一张背景图像 - string backgroundImageFile = Path.Combine(BackgroundDir, Directory.GetFiles(BackgroundDir, "*.png")[Rd.Next(Directory.GetFiles(BackgroundDir, "*.png").Length)]); + string backgroundImageFile = Path.Combine(BackgroundDir, + Directory.GetFiles(BackgroundDir, "*.png")[ + Rd.Next(Directory.GetFiles(BackgroundDir, "*.png").Length)]); // 从背景图像中随机取一块 128x128 的区域 Mat backgroundImage = Cv2.ImRead(backgroundImageFile, ImreadModes.Color); - Rect backgroundRect = new Rect(Rd.Next(backgroundImage.Width - 128), new Random().Next(backgroundImage.Height - 128), 128, 128); + Rect backgroundRect = new Rect(Rd.Next(backgroundImage.Width - 128), + new Random().Next(backgroundImage.Height - 128), 128, 128); Mat backgroundImageRegion = backgroundImage[backgroundRect]; // 随机平移、缩放保留区域 @@ -93,9 +100,11 @@ public class AvatarClassifyGen // Cv2.ImShow("resizedSideImage", resizedSideImage); var resizedMaskImage = new Mat(); // Cv2.Threshold(alphaChannel, alphaChannel, 200, 255, ThresholdTypes.Otsu); - Cv2.Resize(255 - alphaChannel, resizedMaskImage, new Size(128 * scale, 128 * scale), 0, 0, InterpolationFlags.Cubic); + Cv2.Resize(~alphaChannel, resizedMaskImage, new Size(128 * scale, 128 * scale), 0, 0, + InterpolationFlags.Cubic); var resizedAlphaChannel = new Mat(); - Cv2.Resize(alphaChannel, resizedAlphaChannel, new Size(128 * scale, 128 * scale), 0, 0, InterpolationFlags.Cubic); + Cv2.Resize(alphaChannel, resizedAlphaChannel, new Size(128 * scale, 128 * scale), 0, 0, + InterpolationFlags.Cubic); // Cv2.ImShow("resizedMaskImage", resizedMaskImage); // generatedImage[transformedRect] = resizedSideImage; @@ -112,7 +121,8 @@ public class AvatarClassifyGen int offsetY = Rd.Next(-ySpace, 0); Debug.WriteLine($"{sideImageFileName} 缩放{scale}大于1 偏移 ({offsetX},{offsetY})"); - var roi = new Rect((resizedSideImage.Width - 128) / 2 + offsetX, (resizedSideImage.Height - 128) + offsetY, 128, 128); + var roi = new Rect((resizedSideImage.Width - 128) / 2 + offsetX, + (resizedSideImage.Height - 128) + offsetY, 128, 128); // result = new Mat(); // Cv2.BitwiseAnd(backgroundImageRegionClone, backgroundImageRegionClone, result, resizedMaskImage[roi]); result = Mul(backgroundImageRegionClone, resizedAlphaChannel[roi]); @@ -126,7 +136,8 @@ public class AvatarClassifyGen int offsetY = Rd.Next(-ySpace, 0); Debug.WriteLine($"{sideImageFileName} 缩放{scale}小于等于1 偏移 ({offsetX},{offsetY})"); - var roi = new Rect((128 - resizedSideImage.Width) / 2 + offsetX, (128 - resizedSideImage.Height) + offsetY, resizedSideImage.Width, resizedSideImage.Height); + var roi = new Rect((128 - resizedSideImage.Width) / 2 + offsetX, + (128 - resizedSideImage.Height) + offsetY, resizedSideImage.Width, resizedSideImage.Height); var res = new Mat(); // Cv2.BitwiseAnd(backgroundImageRegionClone[roi], backgroundImageRegionClone[roi], res, resizedMaskImage); res = Mul(backgroundImageRegionClone[roi], resizedAlphaChannel); @@ -146,11 +157,12 @@ public class AvatarClassifyGen var channels = background.Split(); for (int i = 0; i < 3; i++) { - Cv2.Multiply(channels[i], 255 - alphaChannel, channels[i], 1 / 255.0); + Cv2.Multiply(channels[i], ~ alphaChannel, channels[i], 1 / 255.0); } + Mat result = new Mat(); Cv2.Merge(channels[..3], result); return result; } } -} +} \ No newline at end of file diff --git a/Test/BetterGenshinImpact.Test/Dataset/AvatarClassifyTransparentGen.cs b/Test/BetterGenshinImpact.Test/Dataset/AvatarClassifyTransparentGen.cs index 9ce939f6..cc6acffb 100644 --- a/Test/BetterGenshinImpact.Test/Dataset/AvatarClassifyTransparentGen.cs +++ b/Test/BetterGenshinImpact.Test/Dataset/AvatarClassifyTransparentGen.cs @@ -100,7 +100,7 @@ public class AvatarClassifyTransparentGen // Cv2.ImShow("resizedSideImage", resizedSideImage); var resizedMaskImage = new Mat(); // Cv2.Threshold(alphaChannel, alphaChannel, 200, 255, ThresholdTypes.Otsu); - Cv2.Resize(255 - alphaChannel, resizedMaskImage, new Size(128 * scale, 128 * scale), 0, 0, InterpolationFlags.Cubic); + Cv2.Resize(~ alphaChannel, resizedMaskImage, new Size(128 * scale, 128 * scale), 0, 0, InterpolationFlags.Cubic); var resizedAlphaChannel = new Mat(); Cv2.Resize(alphaChannel, resizedAlphaChannel, new Size(128 * scale, 128 * scale), 0, 0, InterpolationFlags.Cubic); @@ -153,7 +153,7 @@ public class AvatarClassifyTransparentGen var channels = background.Split(); for (int i = 0; i < 3; i++) { - Cv2.Multiply(channels[i], 255 - alphaChannel, channels[i], 1 / 255.0); + Cv2.Multiply(channels[i], ~ alphaChannel, channels[i], 1 / 255.0); } Mat result = new Mat(); Cv2.Merge(channels[..3], result); diff --git a/Test/BetterGenshinImpact.Test/Simple/AllMap/KeyPointMatchTest.cs b/Test/BetterGenshinImpact.Test/Simple/AllMap/KeyPointMatchTest.cs index 0e298f12..b5d4bbc1 100644 --- a/Test/BetterGenshinImpact.Test/Simple/AllMap/KeyPointMatchTest.cs +++ b/Test/BetterGenshinImpact.Test/Simple/AllMap/KeyPointMatchTest.cs @@ -281,10 +281,10 @@ public class KeyPointMatchTest writer.Write(image.Rows); writer.Write(image.Cols); int depth = image.Depth(); - int type = image.Type(); + MatType type = image.Type(); int channels = image.Channels(); writer.Write(depth); - writer.Write(type); + writer.Write(type.Value); writer.Write(channels); int sizeInBytes = (int)image.Step() * image.Rows; writer.Write(sizeInBytes); diff --git a/Test/BetterGenshinImpact.Test/Simple/MiniMap/CharacterOrientationTest.cs b/Test/BetterGenshinImpact.Test/Simple/MiniMap/CharacterOrientationTest.cs index 4e1f73a5..6e6a9abd 100644 --- a/Test/BetterGenshinImpact.Test/Simple/MiniMap/CharacterOrientationTest.cs +++ b/Test/BetterGenshinImpact.Test/Simple/MiniMap/CharacterOrientationTest.cs @@ -282,7 +282,7 @@ public class CharacterOrientationTest if (contours.Length > 0) { - var maxRect = Rect.Empty; + Rect maxRect = default; var maxIndex = 0; for (int i = 0; i < contours.Length; i++) { diff --git a/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoFishingTests/BehavioursTests.ChooseBait.cs b/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoFishingTests/BehavioursTests.ChooseBait.cs index be0becbe..cf70aaa8 100644 --- a/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoFishingTests/BehavioursTests.ChooseBait.cs +++ b/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoFishingTests/BehavioursTests.ChooseBait.cs @@ -31,7 +31,7 @@ namespace BetterGenshinImpact.UnitTest.GameTaskTests.AutoFishingTests FakeSystemInfo systemInfo = new FakeSystemInfo(new Vanara.PInvoke.RECT(0, 0, mat.Width, mat.Height), 1); var blackboard = new Blackboard(sleep: i => { }) { - fishpond = new Fishpond(fishNames.Select(n => new OneFish(n, OpenCvSharp.Rect.Empty, 0)).ToList()) + fishpond = new Fishpond(fishNames.Select(n => new OneFish(n, default, 0)).ToList()) }; // @@ -62,7 +62,7 @@ namespace BetterGenshinImpact.UnitTest.GameTaskTests.AutoFishingTests FakeSystemInfo systemInfo = new FakeSystemInfo(new Vanara.PInvoke.RECT(0, 0, mat.Width, mat.Height), 1); var blackboard = new Blackboard(sleep: i => { }) { - fishpond = new Fishpond(fishNames.Select(n => new OneFish(n, OpenCvSharp.Rect.Empty, 0)).ToList()) + fishpond = new Fishpond(fishNames.Select(n => new OneFish(n, default, 0)).ToList()) }; DateTimeOffset dateTime = new DateTimeOffset(2025, 2, 26, 16, 13, 54, 285, TimeSpan.FromHours(8)); @@ -116,7 +116,7 @@ namespace BetterGenshinImpact.UnitTest.GameTaskTests.AutoFishingTests FakeSystemInfo systemInfo = new FakeSystemInfo(new Vanara.PInvoke.RECT(0, 0, mat.Width, mat.Height), 1); var blackboard = new Blackboard(sleep: i => { }) { - fishpond = new Fishpond(fishNames.Select(n => new OneFish(n, OpenCvSharp.Rect.Empty, 0)).ToList()) + fishpond = new Fishpond(fishNames.Select(n => new OneFish(n, default, 0)).ToList()) }; DateTimeOffset dateTime = new DateTimeOffset(2025, 2, 26, 16, 13, 54, 285, TimeSpan.FromHours(8)); @@ -155,7 +155,7 @@ namespace BetterGenshinImpact.UnitTest.GameTaskTests.AutoFishingTests #region medaka受到遮挡,第3次失败 // fishNames = new string[] { "koi", "koi head", "sunfish" }; - blackboard.fishpond = new Fishpond(fishNames.Select(n => new OneFish(n, OpenCvSharp.Rect.Empty, 0)).ToList()); + blackboard.fishpond = new Fishpond(fishNames.Select(n => new OneFish(n, default, 0)).ToList()); sut.Reset(); fakeTimeProvider.SetUtcNow(dateTime.AddSeconds(20)); @@ -173,7 +173,7 @@ namespace BetterGenshinImpact.UnitTest.GameTaskTests.AutoFishingTests #region sunfish受到遮挡,medaka再次出现,第4次成功,并钓起medaka // fishNames = new string[] { "koi", "koi head", "medaka" }; - blackboard.fishpond = new Fishpond(fishNames.Select(n => new OneFish(n, OpenCvSharp.Rect.Empty, 0)).ToList()); + blackboard.fishpond = new Fishpond(fishNames.Select(n => new OneFish(n, default, 0)).ToList()); sut.Reset(); fakeTimeProvider.SetUtcNow(dateTime.AddSeconds(30)); @@ -191,7 +191,7 @@ namespace BetterGenshinImpact.UnitTest.GameTaskTests.AutoFishingTests #region sunfish再次出现,第5次失败 // fishNames = new string[] { "koi", "koi head", "sunfish" }; - blackboard.fishpond = new Fishpond(fishNames.Select(n => new OneFish(n, OpenCvSharp.Rect.Empty, 0)).ToList()); + blackboard.fishpond = new Fishpond(fishNames.Select(n => new OneFish(n, default, 0)).ToList()); sut.Reset(); fakeTimeProvider.SetUtcNow(dateTime.AddSeconds(40)); @@ -222,7 +222,7 @@ namespace BetterGenshinImpact.UnitTest.GameTaskTests.AutoFishingTests IEnumerable fishNames = new string[] { "koi", "koi head", "sunfish" }; var blackboard = new Blackboard(sleep: i => { }) { - fishpond = new Fishpond(fishNames.Select(n => new OneFish(n, OpenCvSharp.Rect.Empty, 0)).ToList()) + fishpond = new Fishpond(fishNames.Select(n => new OneFish(n, default, 0)).ToList()) }; DateTimeOffset dateTime = new DateTimeOffset(2025, 2, 26, 16, 13, 54, 285, TimeSpan.FromHours(8)); @@ -244,7 +244,7 @@ namespace BetterGenshinImpact.UnitTest.GameTaskTests.AutoFishingTests #region koi受到遮挡,第2次失败 // fishNames = new string[] { "sunfish" }; - blackboard.fishpond = new Fishpond(fishNames.Select(n => new OneFish(n, OpenCvSharp.Rect.Empty, 0)).ToList()); + blackboard.fishpond = new Fishpond(fishNames.Select(n => new OneFish(n, default, 0)).ToList()); sut.Reset(); fakeTimeProvider.SetUtcNow(dateTime.AddSeconds(10)); @@ -263,7 +263,7 @@ namespace BetterGenshinImpact.UnitTest.GameTaskTests.AutoFishingTests #region koi再次出现,第3次失败 // fishNames = new string[] { "koi", "koi head", "sunfish" }; - blackboard.fishpond = new Fishpond(fishNames.Select(n => new OneFish(n, OpenCvSharp.Rect.Empty, 0)).ToList()); + blackboard.fishpond = new Fishpond(fishNames.Select(n => new OneFish(n, default, 0)).ToList()); sut.Reset(); fakeTimeProvider.SetUtcNow(dateTime.AddSeconds(20)); @@ -281,7 +281,7 @@ namespace BetterGenshinImpact.UnitTest.GameTaskTests.AutoFishingTests #region 第4次失败 // fishNames = new string[] { "koi", "koi head", "sunfish" }; - blackboard.fishpond = new Fishpond(fishNames.Select(n => new OneFish(n, OpenCvSharp.Rect.Empty, 0)).ToList()); + blackboard.fishpond = new Fishpond(fishNames.Select(n => new OneFish(n, default, 0)).ToList()); sut.Reset(); fakeTimeProvider.SetUtcNow(dateTime.AddSeconds(40)); diff --git a/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoFishingTests/BehavioursTests.ThrowRod.cs b/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoFishingTests/BehavioursTests.ThrowRod.cs index b1105b81..8fc18c07 100644 --- a/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoFishingTests/BehavioursTests.ThrowRod.cs +++ b/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoFishingTests/BehavioursTests.ThrowRod.cs @@ -135,7 +135,7 @@ namespace BetterGenshinImpact.UnitTest.GameTaskTests.AutoFishingTests var actual = sut.currentFish; // - Assert.True(blackboard.fishpond.TargetRect != null && blackboard.fishpond.TargetRect.Value != OpenCvSharp.Rect.Empty); + Assert.True(blackboard.fishpond.TargetRect != null && blackboard.fishpond.TargetRect.Value != default); Assert.Equal(3, blackboard.fishpond.Fishes.Count(f => f.FishType.Name == "pufferfish")); Assert.Equal(blackboard.fishpond.Fishes.OrderBy(f => f.Rect.X).First(), actual);