diff --git a/BetterGenshinImpact/GameTask/AutoDomain/Model/ResinStatus.cs b/BetterGenshinImpact/GameTask/AutoDomain/Model/ResinStatus.cs
index 54bf7bea..2f5c27da 100644
--- a/BetterGenshinImpact/GameTask/AutoDomain/Model/ResinStatus.cs
+++ b/BetterGenshinImpact/GameTask/AutoDomain/Model/ResinStatus.cs
@@ -6,6 +6,7 @@ using BetterGenshinImpact.Helpers;
using Microsoft.Extensions.Logging;
using OpenCvSharp;
using System;
+using BetterGenshinImpact.GameTask.AutoPick;
namespace BetterGenshinImpact.GameTask.AutoDomain.Model;
@@ -77,7 +78,7 @@ public class ResinStatus
if (condensedResinRes.IsExist())
{
// 找出 icon 的位置 + 25 ~ icon 的位置+45 就是浓缩树脂的数字,数字宽20
- var condensedResinCountRect = new Rect(crop2.X + condensedResinRes.Right + (int)(20 * assetScale), (int)(37 * assetScale), (int)(70 * assetScale), (int)(24 * assetScale));
+ var condensedResinCountRect = new Rect(crop2.X + condensedResinRes.Right + (int)(20 * assetScale), crop2.Y + condensedResinRes.Y, (int)(30 * assetScale), condensedResinRes.Height);
using ImageRegion countRegion = region.DeriveCrop(condensedResinCountRect);
using Mat threshold = countRegion.CacheGreyMat.Threshold(180, 255, ThresholdTypes.Binary);
using Mat bitwiseNot = new Mat();
diff --git a/BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs b/BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs
index f77cfd72..443e86f7 100644
--- a/BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs
+++ b/BetterGenshinImpact/GameTask/AutoPick/AutoPickTrigger.cs
@@ -246,7 +246,7 @@ public partial class AutoPickTrigger : ITaskTrigger
else
{
var textMat = new Mat(content.CaptureRectArea.SrcMat, textRect);
- var boundingRect = TextRectExtractor.GetTextBoundingRect(textMat, out var bin);
+ var boundingRect = TextRectExtractor.GetTextBoundingRect(textMat);
// 如果找到有效区域
if (boundingRect.X <20 && boundingRect.Width > 5 && boundingRect.Height > 5)
{
diff --git a/BetterGenshinImpact/GameTask/AutoPick/TextRectExtractor.cs b/BetterGenshinImpact/GameTask/AutoPick/TextRectExtractor.cs
index ac15db89..3b201af0 100644
--- a/BetterGenshinImpact/GameTask/AutoPick/TextRectExtractor.cs
+++ b/BetterGenshinImpact/GameTask/AutoPick/TextRectExtractor.cs
@@ -11,12 +11,17 @@ public static class TextRectExtractor
/// 从图片中提取文字范围(假定文字从最左边贴边开始,向右连续)
/// 结果矩形固定 x=0,y=0,h=原图高度,只计算连续文字宽度。
///
- public static Rect GetTextBoundingRect(Mat textMat, out Mat bin)
+ /// 文字图片
+ /// 二值化阈值
+ /// 二值化阈值
+ ///
+ public static Rect GetTextBoundingRect(Mat textMat, double min = 160, double max = 255)
{
// 转换为灰度图
- Mat gray = new Mat();
+ Mat gray;
if (textMat.Channels() == 3)
{
+ gray = new Mat();
Cv2.CvtColor(textMat, gray, ColorConversionCodes.BGR2GRAY);
}
else
@@ -25,8 +30,8 @@ public static class TextRectExtractor
}
// 使用阈值160进行二值化处理
- bin = new Mat();
- Cv2.Threshold(gray, bin, 160, 255, ThresholdTypes.Binary);
+ using var bin = new Mat();
+ Cv2.Threshold(gray, bin, min, max, ThresholdTypes.Binary);
// 形态学操作:先腐蚀后膨胀,去除噪点并保持文字完整
Mat kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3));
@@ -37,7 +42,46 @@ public static class TextRectExtractor
return ProjectionRect(textMat, bin);
}
- private static Rect ProjectionRect(Mat textMat, Mat bin)
+ public static Rect GetNumberBoundingRect(Mat textMat, double min = 180, double max = 255)
+ {
+ // 转换为灰度图
+ Mat gray;
+ if (textMat.Channels() == 3)
+ {
+ gray = new Mat();
+ Cv2.CvtColor(textMat, gray, ColorConversionCodes.BGR2GRAY);
+ }
+ else
+ {
+ gray = textMat.Clone();
+ }
+
+ // 使用阈值160进行二值化处理
+ using var bin = new Mat();
+ Cv2.Threshold(gray, bin, min, max, ThresholdTypes.Binary);
+
+ // 形态学操作:直接膨胀
+ Cv2.Dilate(bin, bin, new Mat(), iterations: 2);
+ gray.Dispose();
+ var rect = ProjectionRect(textMat, bin);
+ // 数字后面加点宽度
+ if (rect != new Rect())
+ {
+ var newWidth = rect.Width + 10;
+ rect.Width = newWidth > textMat.Width ? textMat.Width : newWidth;
+ }
+
+ return rect;
+ }
+
+ ///
+ /// 投影, 获取连续文字的边界矩形
+ ///
+ ///
+ ///
+ /// 允许的最大连续空列数
+ ///
+ public static Rect ProjectionRect(Mat textMat, Mat bin, int maxGap = 30)
{
// 投影:对行做 ReduceSum,得到 1 x width 的列和
using var projection = new Mat();
@@ -45,7 +89,6 @@ public static class TextRectExtractor
int width = projection.Cols;
projection.GetArray(out int[] colSums);
- int maxGap = 30; // 允许的最大连续空列数
int gapCount = 0;
int lastNonEmpty = -1;
@@ -66,7 +109,7 @@ public static class TextRectExtractor
}
}
}
-
+
if (lastNonEmpty == -1)
{
// 没有检测到文字
@@ -76,4 +119,4 @@ public static class TextRectExtractor
Rect boundingRect = new Rect(0, 0, lastNonEmpty, textMat.Height);
return boundingRect;
}
-}
+}
\ No newline at end of file
diff --git a/Test/BetterGenshinImpact.UnitTest/Assets b/Test/BetterGenshinImpact.UnitTest/Assets
index 3df550ad..e6446663 160000
--- a/Test/BetterGenshinImpact.UnitTest/Assets
+++ b/Test/BetterGenshinImpact.UnitTest/Assets
@@ -1 +1 @@
-Subproject commit 3df550ad83bd7c2f512d2fa8795f6284c13ddd96
+Subproject commit e644666398474a60e0d8a245dcf269c5c52d9dea
diff --git a/Test/BetterGenshinImpact.UnitTest/CoreTests/RecognitionTests/OCRTests/PaddleFixture.cs b/Test/BetterGenshinImpact.UnitTest/CoreTests/RecognitionTests/OCRTests/PaddleFixture.cs
index fd661a16..ec61fe32 100644
--- a/Test/BetterGenshinImpact.UnitTest/CoreTests/RecognitionTests/OCRTests/PaddleFixture.cs
+++ b/Test/BetterGenshinImpact.UnitTest/CoreTests/RecognitionTests/OCRTests/PaddleFixture.cs
@@ -11,19 +11,19 @@ namespace BetterGenshinImpact.UnitTest.CoreTests.RecognitionTests.OCRTests
public PaddleOcrService Get(string cultureInfoName = "zh-Hans", string version = "V5")
{
- return _paddleOcrServices.GetOrAdd(cultureInfoName, name =>
+ return _paddleOcrServices.GetOrAdd(cultureInfoName + "_" + version, _ =>
{
lock (_paddleOcrServices)
{
if (version == "V5")
{
return new PaddleOcrService(new BgiOnnxFactory(new FakeLogger()),
- PaddleOcrService.PaddleOcrModelType.FromCultureInfo(new CultureInfo(name)) ?? PaddleOcrService.PaddleOcrModelType.V5);
+ PaddleOcrService.PaddleOcrModelType.FromCultureInfo(new CultureInfo(cultureInfoName)) ?? PaddleOcrService.PaddleOcrModelType.V5);
}
else if (version == "V4")
{
return new PaddleOcrService(new BgiOnnxFactory(new FakeLogger()),
- PaddleOcrService.PaddleOcrModelType.FromCultureInfoV4(new CultureInfo(name)) ?? PaddleOcrService.PaddleOcrModelType.V4);
+ PaddleOcrService.PaddleOcrModelType.FromCultureInfoV4(new CultureInfo(cultureInfoName)) ?? PaddleOcrService.PaddleOcrModelType.V4);
}
else
{
diff --git a/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoDomainTests/ResinStatusTests.cs b/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoDomainTests/ResinStatusTests.cs
index 06d49f58..d44f7109 100644
--- a/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoDomainTests/ResinStatusTests.cs
+++ b/Test/BetterGenshinImpact.UnitTest/GameTaskTests/AutoDomainTests/ResinStatusTests.cs
@@ -21,12 +21,14 @@ namespace BetterGenshinImpact.UnitTest.GameTaskTests.AutoDomainTests
this.paddle = paddle;
}
- [Theory]
- [InlineData(@"AutoDomain\SelectRevitalization.png", 21, 0, 2, 1)]
- [InlineData(@"AutoDomain\SelectRevitalizationOcrV4.png", 11, 0, 1, 149, "V4")]
///
/// 测试识别四种树脂数量,数量应正确
///
+ [Theory]
+ [InlineData(@"AutoDomain\SelectRevitalization.png", 21, 0, 2, 1)]
+ [InlineData(@"AutoDomain\SelectRevitalizationOcrV4.png", 11, 0, 1, 149, "V4")]
+ [InlineData(@"AutoDomain\SelectRevitalizationOcrV4_NSSZ1.png", 20, 1, 1, 0, "V4")]
+ [InlineData(@"AutoDomain\SelectRevitalizationOcrV4_NSSZ1.png", 20, 1, 1, 0)]
public void RecogniseFromRegion_ResinStatusShouldBeRight(string screenshot1080p, int originalResinCount, int fragileResinCount, int condensedResinCount, int transientResinCount, string ocrVersion = "V5")
{
//