Files
better-genshin-impact/BetterGenshinImpact/GameTask/Common/Map/EntireMap.cs
2024-08-13 23:05:53 +08:00

179 lines
6.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using BetterGenshinImpact.Core.Recognition.OpenCv;
using BetterGenshinImpact.Core.Recognition.OpenCv.FeatureMatch;
using BetterGenshinImpact.GameTask.Common.Element.Assets;
using BetterGenshinImpact.Model;
using CommunityToolkit.Mvvm.Messaging;
using CommunityToolkit.Mvvm.Messaging.Messages;
using OpenCvSharp;
using System;
using System.Diagnostics;
using BetterGenshinImpact.Helpers.Extensions;
using Point = OpenCvSharp.Point;
using Size = OpenCvSharp.Size;
namespace BetterGenshinImpact.GameTask.Common.Map;
public class EntireMap : Singleton<EntireMap>
{
// 这个模板缩放大小的计算方式 https://github.com/babalae/better-genshin-impact/issues/318
public static readonly Size TemplateSize = new(240, 135);
// 对无用部分进行裁剪左160上80下96
public static readonly Rect TemplateSizeRoi = new Rect(20, 10, TemplateSize.Width - 20, TemplateSize.Height - 22);
/// <summary>
/// 主要地图缩小1024的模板
/// </summary>
// private readonly Mat _mainMap100BlockMat;
// /// <summary>
// /// 1024区块拼接的主要地图
// /// </summary>
// private readonly Mat _mainMap1024BlockMat;
//
// /// <summary>
// /// 2048城市区块拼接的主要地图
// /// </summary>
// private readonly Mat _cityMap2048BlockMat;
private readonly FeatureMatcher _featureMatcher;
private float _prevX = -1;
private float _prevY = -1;
public EntireMap()
{
// 大地图模板匹配使用的模板
// _mainMap100BlockMat = MapAssets.Instance.MainMap100BlockMat.Value;
// _mainMap1024BlockMat = MapAssets.Instance.MainMap1024BlockMat.Value;
// _cityMap2048BlockMat = new Mat(@"E:\HuiTask\更好的原神\地图匹配\有用的素材\cityMap2048Block.png", ImreadModes.Grayscale);
// Mat grey = new();
// Cv2.CvtColor(_mainMap100BlockMat, grey, ColorConversionCodes.BGR2GRAY);
// _featureMatcher = new FeatureMatcher(MapAssets.Instance.MainMap1024BlockMat.Value, new FeatureStorage("mainMap1024Block"));
// 只从特征点加载
_featureMatcher = new FeatureMatcher(new Size(28672, 26624), new FeatureStorage("mainMap2048Block"));
}
// /// <summary>
// /// 基于模板匹配获取地图位置(100区块缩小了10.24倍)
// /// 当前只支持大地图
// /// </summary>
// /// <param name="captureMat">彩色图像</param>
// /// <returns></returns>
// public Point GetMapPositionByMatchTemplate(Mat captureMat)
// {
// Cv2.CvtColor(captureMat, captureMat, ColorConversionCodes.BGRA2BGR);
// using var tar = new Mat(captureMat.Resize(TemplateSize, 0, 0, InterpolationFlags.Cubic), TemplateSizeRoi);
// var p = MatchTemplateHelper.MatchTemplate(_mainMap100BlockMat, tar, TemplateMatchModes.CCoeffNormed, null, 0.2);
// Debug.WriteLine($"BigMap Match Template: {p}");
// return p;
// }
//
// public void GetMapPositionAndDrawByMatchTemplate(Mat captureMat)
// {
// var p = GetMapPositionByMatchTemplate(captureMat);
// WeakReferenceMessenger.Default.Send(new PropertyChangedMessage<object>(this, "UpdateBigMapRect", new object(),
// new System.Windows.Rect(p.X, p.Y, TemplateSizeRoi.Width, TemplateSizeRoi.Height)));
// }
private int _failCnt = 0;
/// <summary>
/// 基于特征匹配获取地图位置
/// 移动匹配
/// </summary>
/// <param name="greyMat">灰度图</param>
/// <param name="mask">遮罩</param>
/// <returns></returns>
public Point2f GetMiniMapPositionByFeatureMatch(Mat greyMat, Mat? mask = null)
{
try
{
Point2f p;
if (_prevX <= 0 && _prevY <= 0)
{
p = _featureMatcher.Match(greyMat, _prevX, _prevY, mask);
}
else
{
p = _featureMatcher.Match(greyMat, mask);
}
if (p.IsEmpty())
{
throw new InvalidOperationException();
}
_prevX = p.X;
_prevY = p.Y;
_failCnt = 0;
return p;
}
catch
{
Debug.WriteLine("Feature Match Failed");
_failCnt++;
if (_failCnt > 5)
{
Debug.WriteLine("Feature Match Failed Too Many Times, 重新从全地图进行特征匹配");
_failCnt = 0;
(_prevX, _prevY) = (-1, -1);
}
return new Point2f();
}
}
/// <summary>
/// 基于特征匹配获取地图位置 全部匹配
/// </summary>
/// <param name="greyMat"></param>
/// <returns></returns>
public Point2f GetBigMapPositionByFeatureMatch(Mat greyMat)
{
try
{
var p = _featureMatcher.Match(greyMat);
if (p.IsEmpty())
{
throw new InvalidOperationException();
}
return p;
}
catch
{
Debug.WriteLine("Feature Match Failed");
return new Point2f();
}
}
// public static Point GetIntersection(Point2f[] points)
// {
// double a1 = (points[0].Y - points[2].Y) / (double)(points[0].X - points[2].X);
// double b1 = points[0].Y - a1 * points[0].X;
//
// double a2 = (points[1].Y - points[3].Y) / (double)(points[1].X - points[3].X);
// double b2 = points[1].Y - a2 * points[1].X;
//
// if (Math.Abs(a1 - a2) < double.Epsilon)
// {
// // 不相交
// throw new InvalidOperationException();
// }
//
// double x = (b2 - b1) / (a1 - a2);
// double y = a1 * x + b1;
// return new Point((int)x, (int)y);
// }
// public void GetMapPositionAndDrawByFeatureMatch(Mat captureGreyMat)
// {
// var rect = GetMiniMapPositionByFeatureMatch(captureGreyMat);
// if (rect != Rect.Empty)
// {
// WeakReferenceMessenger.Default.Send(new PropertyChangedMessage<object>(this, "UpdateBigMapRect", new object(),
// new System.Windows.Rect(rect.X / 20.48, rect.Y / 20.48, rect.Width / 20.48, rect.Height / 20.48)));
// // WeakReferenceMessenger.Default.Send(new PropertyChangedMessage<object>(this, "UpdateBigMapRect", new object(),
// // new System.Windows.Rect(rect.X / 10.24, rect.Y / 10.24, rect.Width / 10.24, rect.Height / 10.24)));
// }
// }
}