优化角色识别方式

This commit is contained in:
辉鸭蛋
2025-11-14 03:03:10 +08:00
parent 15fcb7d36c
commit 71eb73c449
4 changed files with 129 additions and 6 deletions

View File

@@ -0,0 +1,95 @@
using System;
using System.Diagnostics;
using OpenCvSharp;
namespace BetterGenshinImpact.Core.Recognition.OpenCv;
public class ImageDifferenceDetector
{
/// <summary>
/// 找出四张灰度图中与其他三张差异最大的图片
/// 投票机制每张图片投票给与它差异最大的图片如果某张图片获得3票则返回其索引
/// </summary>
/// <param name="images">包含4张Mat对象的数组</param>
/// <returns>差异最大的图片索引0-3如果没有图片获得3票则返回-1</returns>
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;
}
/// <summary>
/// 计算差值
/// </summary>
private static double CalculateDifference(Mat img1, Mat img2)
{
using var diff = new Mat();
// 计算差值的绝对值
Cv2.Absdiff(img1, img2, diff);
// 统计非零像素点(即颜色不同的像素点)
return Cv2.CountNonZero(diff);
}
}

View File

@@ -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)

View File

@@ -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))

View File

@@ -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}");
}
}