mirror of
https://github.com/babalae/better-genshin-impact.git
synced 2026-05-09 00:34:14 +08:00
优化角色识别方式
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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}");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user