Files
better-genshin-impact/BetterGenshinImpact/GameTask/AutoFishing/AutoFishingImageRecognition.cs
FishmanTheMurloc fce70c0e96 分解5星圣遗物 (#1383)
* 分解圣遗物基础设施建设

* 分解圣遗物独立任务基本功能完成:单独的启动按钮,正则表达式逐一筛选;代码文件整理到单独的文件夹

* 自动分解5星圣遗物功能初步完成

* 修复上次修改快速分解产生的问题,主要点击分解按钮时的bug,还有与五星分解步骤衔接的问题

* 针对切换队伍时,多语言识别效果不佳的情况,将用户设定的队伍名作为正则表达式进行模糊匹配,并在LogInfo输出相关提示;传送任务对任务取消进行单独的异常处理

* 一个便于测试分解圣遗物OCR识别和正则匹配结果的弹窗
2025-04-05 19:53:52 +08:00

107 lines
4.9 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 OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace BetterGenshinImpact.GameTask.AutoFishing
{
public class AutoFishingImageRecognition
{
/// <summary>
/// 钓鱼条矩形识别
/// </summary>
/// <param name="src"></param>
/// <returns></returns>
public static List<Rect>? GetFishBarRect(Mat src)
{
try
{
// 拉条框的黄色是RGB 255, 255, 192 ~ HSV 43, 63, 255
// var testPixel = src.At<Vec3b>(105, 968); // 注意是YX
// using Mat rgbMat = src.CvtColor(ColorConversionCodes.BGR2HSV_FULL);
// var testPixelHSV = rgbMat.At<Vec3b>(105, 968); // 注意是YX
Scalar hsv = OpenCvCommonHelper.CommonHSV2OpenCVHSVFull(new Scalar(60, 0.25, 1.00));
var lowYellow = new Scalar(hsv.Val0 - 3, hsv.Val1 - 20, hsv.Val2 - 10);
var highYellow = new Scalar(hsv.Val0 + 3.5, hsv.Val1 + 40, hsv.Val2);
using Mat mask = OpenCvCommonHelper.InRangeHsvFull(src, lowYellow, highYellow);
using Mat threshold = mask.Threshold(0, 255, ThresholdTypes.Binary); //二值化
Cv2.FindContours(threshold, out var contours, out _, RetrievalModes.External,
ContourApproximationModes.ApproxSimple, null);
if (contours.Length > 0)
{
contours = contours.Where(c => Cv2.MinAreaRect(c).Angle % 45 <= 1).ToArray(); // 剔除倾斜的箭头边缘是45度角在游标靠近两侧箭头时箭头的最小外接是45度的
List<Rect> boxes = contours.Select(Cv2.BoundingRect).ToList();
Rect widest = boxes.OrderBy(b => b.Width).LastOrDefault(); // 取最宽的一根当作基准
if (widest == default)
{
return null;
}
boxes = boxes.Where(r => Math.Abs((widest.Y + widest.Height / 2) - (r.Y + r.Height / 2)) < widest.Height / 5) // 保持一条水平线
.Where(r => Math.Abs(widest.Height - r.Height) < (widest.Height / 3) && r.Width > (widest.Height / 4)).ToList(); // 剔除高度差异太大的,和宽度太小的
return boxes;
}
}
catch (Exception e)
{
Debug.WriteLine(e);
}
return null;
}
/// <summary>
/// 匹配 “鱼儿上钩拉!”文字区域
/// </summary>
/// <param name="src"></param>
/// <param name="liftingWordsAreaRect"></param>
/// <returns></returns>
public static Rect MatchFishBiteWords(Mat src, Rect liftingWordsAreaRect)
{
try
{
Cv2.CvtColor(src, src, ColorConversionCodes.BGR2RGB);
var lowPurple = new Scalar(253, 253, 253);
var highPurple = new Scalar(255, 255, 255);
Cv2.InRange(src, lowPurple, highPurple, src);
Cv2.Threshold(src, src, 0, 255, ThresholdTypes.Binary);
var kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(20, 20),
new OpenCvSharp.Point(-1, -1));
Cv2.Dilate(src, src, kernel); //膨胀
Cv2.FindContours(src, out var contours, out _, RetrievalModes.External,
ContourApproximationModes.ApproxSimple, null);
if (contours.Length > 0)
{
var boxes = contours.Select(Cv2.BoundingRect);
var rects = boxes.ToList();
if (rects.Count > 1)
{
rects.Sort((a, b) => b.Height.CompareTo(a.Height));
}
//VisionContext.Instance().DrawContent.PutRect("FishBiteTipsDebug",
// rects[0].ToWindowsRectangleOffset(liftingWordsAreaRect.X, liftingWordsAreaRect.Y)
// .ToRectDrawable());
if (rects[0].Height < src.Height
&& rects[0].Width * 1.0 / rects[0].Height >= 3 // 长宽比判断
&& liftingWordsAreaRect.Width > rects[0].Width * 3 // 文字范围3倍小于钓鱼条范围的
&& liftingWordsAreaRect.Width * 1.0 / 2 > rects[0].X // 中轴线判断左
&& liftingWordsAreaRect.Width * 1.0 / 2 < rects[0].X + rects[0].Width) // 中轴线判断右
{
return rects[0];
}
}
}
catch (Exception e)
{
Debug.WriteLine(e);
}
return default;
}
}
}