diff --git a/BetterGenshinImpact/Core/Recognition/OpenCv/ImageDifferenceDetector.cs b/BetterGenshinImpact/Core/Recognition/OpenCv/ImageDifferenceDetector.cs
new file mode 100644
index 00000000..e88a8a20
--- /dev/null
+++ b/BetterGenshinImpact/Core/Recognition/OpenCv/ImageDifferenceDetector.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Diagnostics;
+using OpenCvSharp;
+
+namespace BetterGenshinImpact.Core.Recognition.OpenCv;
+
+public class ImageDifferenceDetector
+{
+ ///
+ /// 找出四张灰度图中与其他三张差异最大的图片
+ /// 投票机制:每张图片投票给与它差异最大的图片,如果某张图片获得3票则返回其索引
+ ///
+ /// 包含4张Mat对象的数组
+ /// 差异最大的图片索引(0-3),如果没有图片获得3票则返回-1
+ public static int FindMostDifferentImage(Mat[] images)
+ {
+ if (images is not { Length: 4 })
+ {
+ throw new ArgumentException("必须提供4张图片");
+ }
+
+ // 验证所有图片尺寸相同
+ Size firstSize = images[0].Size();
+ for (int i = 1; i < 4; i++)
+ {
+ if (images[i].Size() != firstSize)
+ {
+ throw new ArgumentException("所有图片必须具有相同的尺寸");
+ }
+ }
+
+ // 存储每张图片获得的投票数
+ int[] votes = new int[4];
+
+ // 每张图片投票给与它差异最大的图片
+ for (int i = 0; i < 4; i++)
+ {
+ int maxDiffImageIndex = -1;
+ double maxDifference = 0;
+
+ // 找出与图片i差异最大的图片
+ for (int j = 0; j < 4; j++)
+ {
+ if (i != j)
+ {
+ double difference = CalculateDifference(images[i], images[j]);
+ Debug.WriteLine($"{i} vs {j} 差异像素数量: {difference}");
+
+ if (difference > maxDifference)
+ {
+ maxDifference = difference;
+ maxDiffImageIndex = j;
+ }
+ }
+ }
+
+ // 图片i投票给差异最大的图片
+ if (maxDiffImageIndex != -1)
+ {
+ votes[maxDiffImageIndex]++;
+ Debug.WriteLine($"图片 {i} 投票给图片 {maxDiffImageIndex} (差异值: {maxDifference:F2})");
+ }
+ }
+
+ // 输出投票结果
+ Debug.WriteLine("\n投票结果:");
+ for (int i = 0; i < 4; i++)
+ {
+ Debug.WriteLine($"图片 {i}: {votes[i]} 票");
+ }
+
+ // 检查是否有图片获得3票
+ for (int i = 0; i < 4; i++)
+ {
+ if (votes[i] >= 3)
+ {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ ///
+ /// 计算差值
+ ///
+ private static double CalculateDifference(Mat img1, Mat img2)
+ {
+ using var diff = new Mat();
+ // 计算差值的绝对值
+ Cv2.Absdiff(img1, img2, diff);
+ // 统计非零像素点(即颜色不同的像素点)
+ return Cv2.CountNonZero(diff);
+ }
+}
\ No newline at end of file
diff --git a/BetterGenshinImpact/GameTask/AutoFight/Model/CombatScenes.cs b/BetterGenshinImpact/GameTask/AutoFight/Model/CombatScenes.cs
index 7af84055..f608ec70 100644
--- a/BetterGenshinImpact/GameTask/AutoFight/Model/CombatScenes.cs
+++ b/BetterGenshinImpact/GameTask/AutoFight/Model/CombatScenes.cs
@@ -460,7 +460,7 @@ public class CombatScenes : IDisposable
{
// 多次识别失败则尝试刷新角色编号位置
// 应对草露问题
- if (context.TotalCheckFailedCount > 3)
+ if (context.TotalCheckFailedCount % 3 == 0 && context.TotalCheckFailedCount > 0 && context.TotalCheckFailedCount < 10)
{
// 失败多次,识别是否存在满足预期的编号框
if (PartyAvatarSideIndexHelper.CountIndexRect(imageRegion) == Avatars.Length)
diff --git a/BetterGenshinImpact/GameTask/AutoFight/Model/PartyAvatarSideIndexHelper.cs b/BetterGenshinImpact/GameTask/AutoFight/Model/PartyAvatarSideIndexHelper.cs
index 888b7216..411cff71 100644
--- a/BetterGenshinImpact/GameTask/AutoFight/Model/PartyAvatarSideIndexHelper.cs
+++ b/BetterGenshinImpact/GameTask/AutoFight/Model/PartyAvatarSideIndexHelper.cs
@@ -373,9 +373,12 @@ public class PartyAvatarSideIndexHelper
var whiteCount = 0;
var notWhiteRectNum = 0;
var mat = imageRegion.CacheGreyMat;
+ Mat[] mats = new Mat[rectArray.Length];
for (int i = 0; i < rectArray.Length; i++)
{
- if (IsWhiteRect(mat, rectArray[i]))
+ using var indexMat = new Mat(mat, rectArray[i]);
+ mats[i] = indexMat;
+ if (IsWhiteRect(indexMat))
{
whiteCount++;
}
@@ -391,16 +394,17 @@ public class PartyAvatarSideIndexHelper
}
else
{
- return -1;
+ // 使用更加靠谱的差值识别(-1是未识别)
+ return ImageDifferenceDetector.FindMostDifferentImage(mats);
}
}
- public static bool IsWhiteRect(Mat greyMat, Rect rect)
+ public static bool IsWhiteRect(Mat indexMat)
{
- using var indexMat = new Mat(greyMat, rect);
+
var count1 = OpenCvCommonHelper.CountGrayMatColor(indexMat, 251, 255); // 白
var count2 = OpenCvCommonHelper.CountGrayMatColor(indexMat, 50, 54); // 黑色文字
- if ((count1 + count2) * 1.0 / (indexMat.Width * indexMat.Height) > 0.5)
+ if ((count1 + count2) * 1.0 / (indexMat.Width * indexMat.Height) > 0.4)
{
// Debug.WriteLine($"白色矩形占比{(count1 + count2) * 1.0 / (indexMat.Width * indexMat.Height)}");
return true;
@@ -424,6 +428,11 @@ public class PartyAvatarSideIndexHelper
}
var curr = imageRegion.Find(ElementAssets.Instance.CurrentAvatarThreshold); // 当前出战角色标识
+ if (curr.IsEmpty())
+ {
+ return -1;
+ }
+
for (int i = 0; i < rectArray.Length; i++)
{
if (IsIntersecting(curr.Y, curr.Height, rectArray[i].Y, rectArray[i].Height))
diff --git a/Test/BetterGenshinImpact.Test/Cv/ImageDifferenceDetectorTest.cs b/Test/BetterGenshinImpact.Test/Cv/ImageDifferenceDetectorTest.cs
new file mode 100644
index 00000000..f6ffab02
--- /dev/null
+++ b/Test/BetterGenshinImpact.Test/Cv/ImageDifferenceDetectorTest.cs
@@ -0,0 +1,19 @@
+using BetterGenshinImpact.Core.Recognition.OpenCv;
+using OpenCvSharp;
+
+namespace BetterGenshinImpact.Test.Cv;
+
+public class ImageDifferenceDetectorTest
+{
+ public static void Test()
+ {
+ int i = ImageDifferenceDetector.FindMostDifferentImage([
+ Cv2.ImRead(@"E:\1.png", ImreadModes.Grayscale),
+ Cv2.ImRead(@"E:\2.png", ImreadModes.Grayscale),
+ Cv2.ImRead(@"E:\3.png", ImreadModes.Grayscale),
+ Cv2.ImRead(@"E:\4.png", ImreadModes.Grayscale)
+ ]);
+
+ Console.WriteLine($"差异最大的图片索引是: {i}");
+ }
+}
\ No newline at end of file