mirror of
https://github.com/babalae/better-genshin-impact
synced 2025-01-09 04:19:47 +08:00
finsh character orientation test
This commit is contained in:
parent
24fe650ac9
commit
978cd45fd8
@ -37,11 +37,18 @@ public class CharacterOrientationTest
|
||||
return Math.Sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||
}
|
||||
|
||||
static Point2f Midpoint(Point2f p1, Point2f p2)
|
||||
// static Point2f Midpoint(Point2f p1, Point2f p2)
|
||||
// {
|
||||
// var midX = (p1.X + p2.X) / 2;
|
||||
// var midY = (p1.Y + p2.Y) / 2;
|
||||
// return new Point2f(midX, midY);
|
||||
// }
|
||||
|
||||
static Point Midpoint(Point p1, Point p2)
|
||||
{
|
||||
var midX = (p1.X + p2.X) / 2;
|
||||
var midY = (p1.Y + p2.Y) / 2;
|
||||
return new Point2f(midX, midY);
|
||||
return new Point(midX, midY);
|
||||
}
|
||||
|
||||
public static void Triangle(Mat src, Mat gray)
|
||||
@ -196,7 +203,7 @@ public class CharacterOrientationTest
|
||||
}
|
||||
|
||||
|
||||
public static void Watershed()
|
||||
public static void FloodFill()
|
||||
{
|
||||
var mat = Cv2.ImRead(@"E:\HuiTask\更好的原神\自动秘境\箭头识别\s1.png", ImreadModes.Color);
|
||||
Cv2.GaussianBlur(mat, mat, new Size(3, 3), 0);
|
||||
@ -207,14 +214,159 @@ public class CharacterOrientationTest
|
||||
// Cv2.ImShow($"splitMat{i}", splitMat[i]);
|
||||
//}
|
||||
|
||||
// 红蓝通道按位与
|
||||
// 1. 红蓝通道按位与
|
||||
var red = new Mat(mat.Size(), MatType.CV_8UC1);
|
||||
Cv2.InRange(splitMat[0], new Scalar(250), new Scalar(255), red);
|
||||
//Cv2.ImShow("red", red);
|
||||
var blue = new Mat(mat.Size(), MatType.CV_8UC1);
|
||||
Cv2.InRange(splitMat[2], new Scalar(0), new Scalar(10), blue);
|
||||
//Cv2.ImShow("blue", blue);
|
||||
var andMat = red & blue;
|
||||
var andMat = new Mat(mat.Size(), MatType.CV_8UC1);
|
||||
|
||||
Cv2.BitwiseAnd(red, blue, andMat);
|
||||
Cv2.ImShow("andMat2", andMat);
|
||||
|
||||
// 寻找轮廓
|
||||
Cv2.FindContours(andMat, out var contours, out var hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple);
|
||||
Mat dst = Mat.Zeros(andMat.Size(), MatType.CV_8UC3);
|
||||
for (int i = 0; i < contours.Length; i++)
|
||||
{
|
||||
Cv2.DrawContours(dst, contours, i, Scalar.Red, 1, LineTypes.Link4, hierarchy);
|
||||
}
|
||||
|
||||
Cv2.ImShow("寻找轮廓", dst);
|
||||
|
||||
// 计算最大外接矩形
|
||||
if (contours.Length > 0)
|
||||
{
|
||||
var boxes = contours.Select(Cv2.BoundingRect).Where(w => w.Height >= 2);
|
||||
var boxArray = boxes as Rect[] ?? boxes.ToArray();
|
||||
if (boxArray.Count() != 1)
|
||||
{
|
||||
throw new Exception("找到多个外接矩形");
|
||||
}
|
||||
|
||||
var box = boxArray.First();
|
||||
|
||||
// 剪裁出准备泛洪的区域(放大4倍的区域)
|
||||
var newSrcMat = new Mat(mat, new Rect(box.X - box.Width / 2, box.Y - box.Height / 2, box.Width * 2, box.Height * 2));
|
||||
Cv2.ImShow("剪裁出准备泛洪的区域", newSrcMat);
|
||||
|
||||
// 中心点作为种子点
|
||||
var seedPoint = new Point(newSrcMat.Width / 2, newSrcMat.Height / 2);
|
||||
|
||||
// 泛洪填充
|
||||
Cv2.FloodFill(newSrcMat, seedPoint, Scalar.White, out _, new Scalar());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void Hsv()
|
||||
{
|
||||
var mat = Cv2.ImRead(@"E:\HuiTask\更好的原神\自动秘境\箭头识别\e1.png", ImreadModes.Color);
|
||||
// Cv2.GaussianBlur(mat, mat, new Size(3, 3), 0);
|
||||
var splitMat = mat.Split();
|
||||
|
||||
// 1. 红蓝通道按位与
|
||||
var red = new Mat(mat.Size(), MatType.CV_8UC1);
|
||||
Cv2.InRange(splitMat[0], new Scalar(250), new Scalar(255), red);
|
||||
var blue = new Mat(mat.Size(), MatType.CV_8UC1);
|
||||
Cv2.InRange(splitMat[2], new Scalar(0), new Scalar(10), blue);
|
||||
var andMat = new Mat(mat.Size(), MatType.CV_8UC1);
|
||||
|
||||
Cv2.BitwiseAnd(red, blue, andMat);
|
||||
Cv2.ImShow("andMat2", andMat);
|
||||
|
||||
// 寻找轮廓
|
||||
Cv2.FindContours(andMat, out var contours, out var hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple);
|
||||
Mat dst = Mat.Zeros(andMat.Size(), MatType.CV_8UC3);
|
||||
for (int i = 0; i < contours.Length; i++)
|
||||
{
|
||||
Cv2.DrawContours(dst, contours, i, Scalar.Red, 1, LineTypes.Link4, hierarchy);
|
||||
}
|
||||
|
||||
Cv2.ImShow("寻找轮廓", dst);
|
||||
|
||||
// 计算最大外接矩形
|
||||
|
||||
if (contours.Length > 0)
|
||||
{
|
||||
var maxRect = Rect.Empty;
|
||||
var maxIndex = 0;
|
||||
for (int i = 0; i < contours.Length; i++)
|
||||
{
|
||||
var box = Cv2.BoundingRect(contours[i]);
|
||||
if (box.Width * box.Height > maxRect.Width * maxRect.Height)
|
||||
{
|
||||
maxRect = box;
|
||||
maxIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
var maxContour = contours[maxIndex];
|
||||
|
||||
// 计算轮廓的周长
|
||||
var perimeter = Cv2.ArcLength(maxContour, true);
|
||||
|
||||
// 近似多边形拟合
|
||||
var approx = Cv2.ApproxPolyDP(maxContour, 0.08 * perimeter, true);
|
||||
|
||||
// 如果拟合的多边形有三个顶点,认为是三角形
|
||||
if (approx.Length == 3)
|
||||
{
|
||||
// 在图像上绘制三角形的轮廓
|
||||
Cv2.DrawContours(mat, new OpenCvSharp.Point[][] { approx }, -1, Scalar.Green, 1);
|
||||
|
||||
// 剪裁出三角形所在区域
|
||||
var newSrcMat = new Mat(mat, maxRect);
|
||||
|
||||
|
||||
// HSV 阈值取出中心飞镖
|
||||
var hsvMat = new Mat();
|
||||
Cv2.CvtColor(newSrcMat, hsvMat, ColorConversionCodes.BGR2HSV);
|
||||
// var lowScalar = new Scalar(95, 255, 255);
|
||||
// var highScalar = new Scalar(255, 255, 255);
|
||||
var lowScalar = new Scalar(93, 155, 170);
|
||||
var highScalar = new Scalar(255, 255, 255);
|
||||
var hsvThresholdMat = new Mat();
|
||||
Cv2.InRange(hsvMat, lowScalar, highScalar, hsvThresholdMat);
|
||||
Cv2.ImShow("剪裁出三角形所在区域", hsvMat);
|
||||
Cv2.ImShow("HSV 阈值取出中心飞镖", hsvThresholdMat);
|
||||
|
||||
// 循环计算三条边的中点,并计算中点到顶点的所有点中连续黑色像素的个数
|
||||
var maxBlackCount = 0;
|
||||
Point correctP1 = new(), correctP2 = new();
|
||||
var offset = new Point(maxRect.X, maxRect.Y);
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
var midPoint = Midpoint(approx[i], approx[(i + 1) % 3]);
|
||||
var targetPoint = approx[(i + 2) % 3];
|
||||
|
||||
// 中点到顶点的所有点
|
||||
var lineIterator = new LineIterator(hsvThresholdMat, midPoint - offset, targetPoint - offset, PixelConnectivity.Connectivity8);
|
||||
|
||||
// 计算连续黑色像素的个数
|
||||
var blackCount = 0;
|
||||
foreach (var item in lineIterator)
|
||||
{
|
||||
if (item.GetValue<Vec2b>().Item0 == 255)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
blackCount++;
|
||||
}
|
||||
|
||||
if (blackCount > maxBlackCount)
|
||||
{
|
||||
maxBlackCount = blackCount;
|
||||
correctP1 = midPoint;
|
||||
correctP2 = targetPoint;
|
||||
}
|
||||
}
|
||||
Cv2.Line(mat, correctP1, correctP2 + (correctP2 - correctP1) * 3, Scalar.Red, 1);
|
||||
Cv2.ImShow("最终结果", mat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
78
BetterGenshinImpact.Test/HsvTestWindow.cs
Normal file
78
BetterGenshinImpact.Test/HsvTestWindow.cs
Normal file
@ -0,0 +1,78 @@
|
||||
using OpenCvSharp;
|
||||
|
||||
namespace BetterGenshinImpact.Test;
|
||||
|
||||
internal class HsvTestWindow
|
||||
{
|
||||
private const int MaxValueH = 360 / 2;
|
||||
static readonly int MaxValue = 255;
|
||||
//private const string WindowCaptureName = "Video Capture";
|
||||
private const string _windowDetectionName = "Object Detection";
|
||||
static int _lowH = 0, _lowS = 0, _lowV = 0;
|
||||
static int _highH = MaxValueH, _highS = MaxValue, _highV = MaxValue;
|
||||
|
||||
static void on_low_H_thresh_trackbar(int pos, IntPtr userdata)
|
||||
{
|
||||
_lowH = Math.Min(_highH - 1, _lowH);
|
||||
Cv2.SetTrackbarPos("Low H", _windowDetectionName, _lowH);
|
||||
}
|
||||
static void on_high_H_thresh_trackbar(int pos, IntPtr userdata)
|
||||
{
|
||||
_highH = Math.Max(_highH, _lowH + 1);
|
||||
Cv2.SetTrackbarPos("High H", _windowDetectionName, _highH);
|
||||
}
|
||||
static void on_low_S_thresh_trackbar(int pos, IntPtr userdata)
|
||||
{
|
||||
_lowS = Math.Min(_highS - 1, _lowS);
|
||||
Cv2.SetTrackbarPos("Low S", _windowDetectionName, _lowS);
|
||||
}
|
||||
static void on_high_S_thresh_trackbar(int pos, IntPtr userdata)
|
||||
{
|
||||
_highS = Math.Max(_highS, _lowS + 1);
|
||||
Cv2.SetTrackbarPos("High S", _windowDetectionName, _highS);
|
||||
}
|
||||
static void on_low_V_thresh_trackbar(int pos, IntPtr userdata)
|
||||
{
|
||||
_lowV = Math.Min(_highV - 1, _lowV);
|
||||
Cv2.SetTrackbarPos("Low V", _windowDetectionName, _lowV);
|
||||
}
|
||||
static void on_high_V_thresh_trackbar(int pos, IntPtr userdata)
|
||||
{
|
||||
_highV = Math.Max(_highV, _lowV + 1);
|
||||
Cv2.SetTrackbarPos("High V", _windowDetectionName, _highV);
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
|
||||
//Cv2.NamedWindow(WindowCaptureName);
|
||||
Cv2.NamedWindow(_windowDetectionName);
|
||||
// Trackbars to set thresholds for HSV values
|
||||
Cv2.CreateTrackbar("Low H", _windowDetectionName, ref _lowH, MaxValueH, on_low_H_thresh_trackbar);
|
||||
Cv2.CreateTrackbar("High H", _windowDetectionName, ref _highH, MaxValueH, on_high_H_thresh_trackbar);
|
||||
Cv2.CreateTrackbar("Low S", _windowDetectionName, ref _lowS, MaxValue, on_low_S_thresh_trackbar);
|
||||
Cv2.CreateTrackbar("High S", _windowDetectionName, ref _highS, MaxValue, on_high_S_thresh_trackbar);
|
||||
Cv2.CreateTrackbar("Low V", _windowDetectionName, ref _lowV, MaxValue, on_low_V_thresh_trackbar);
|
||||
Cv2.CreateTrackbar("High V", _windowDetectionName, ref _highV, MaxValue, on_high_V_thresh_trackbar);
|
||||
var frame = Cv2.ImRead(@"E:\HuiTask\更好的原神\自动秘境\箭头识别\s1.png", ImreadModes.Color);
|
||||
Mat frameHsv = new Mat();
|
||||
// Convert from BGR to HSV colorspace
|
||||
Cv2.CvtColor(frame, frameHsv, ColorConversionCodes.BGR2HSV);
|
||||
Mat frameThreshold = new Mat();
|
||||
|
||||
while (true)
|
||||
{
|
||||
// Detect the object based on HSV Range Values
|
||||
Cv2.InRange(frameHsv, new Scalar(_lowH, _lowS, _lowV), new Scalar(_highH, _highS, _highV), frameThreshold);
|
||||
// Show the frames
|
||||
// Cv2.ImShow(WindowCaptureName, frame);
|
||||
Cv2.ImShow(_windowDetectionName, frameThreshold);
|
||||
|
||||
char key = (char)Cv2.WaitKey(30);
|
||||
if (key == 'q' || key == 27)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -19,8 +19,10 @@ namespace BetterGenshinImpact.Test
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// new HsvTestWindow().Run();
|
||||
// CharacterOrientationTest.TestArrow();
|
||||
CharacterOrientationTest.Watershed();
|
||||
CharacterOrientationTest.Hsv();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
using BetterGenshinImpact.View.Drawable;
|
||||
using OpenCvSharp;
|
||||
using SharpDX;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using Point = OpenCvSharp.Point;
|
||||
using Size = OpenCvSharp.Size;
|
||||
|
||||
@ -95,94 +97,102 @@ public class TestTrigger : ITaskTrigger
|
||||
public static void TestArrow(CaptureContent content)
|
||||
{
|
||||
var mat = new Mat(content.CaptureRectArea.SrcMat, new Rect(0,0,300,240));
|
||||
Cv2.GaussianBlur(mat, mat, new Size(3, 3), 0);
|
||||
|
||||
var splitMat = mat.Split();
|
||||
|
||||
|
||||
// 红蓝通道按位与
|
||||
// 1. 红蓝通道按位与
|
||||
var red = new Mat(mat.Size(), MatType.CV_8UC1);
|
||||
Cv2.InRange(splitMat[0], new Scalar(250), new Scalar(255), red);
|
||||
var blue = new Mat(mat.Size(), MatType.CV_8UC1);
|
||||
Cv2.InRange(splitMat[2], new Scalar(0), new Scalar(10), blue);
|
||||
var andMat = red & blue;
|
||||
var andMat = new Mat(mat.Size(), MatType.CV_8UC1);
|
||||
|
||||
Triangle(andMat);
|
||||
}
|
||||
Cv2.BitwiseAnd(red, blue, andMat);
|
||||
|
||||
public static void Rectangle(Mat andMat)
|
||||
{
|
||||
//腐蚀
|
||||
var kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3));
|
||||
var res = new Mat(andMat.Size(), MatType.CV_8UC1);
|
||||
Cv2.Erode(andMat, res, kernel);
|
||||
Cv2.ImShow("erode", res);
|
||||
// 寻找轮廓
|
||||
Cv2.FindContours(andMat, out var contours, out var hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple);
|
||||
Mat dst = Mat.Zeros(andMat.Size(), MatType.CV_8UC3);
|
||||
|
||||
Cv2.FindContours(res, out var contours, out var hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxNone);
|
||||
for (int i = 0; i < contours.Length; i++)
|
||||
// 计算最大外接矩形
|
||||
|
||||
if (contours.Length > 0)
|
||||
{
|
||||
// 最小外接矩形
|
||||
var rect = Cv2.MinAreaRect(contours[i]);
|
||||
// 矩形的四个顶点
|
||||
var points = Cv2.BoxPoints(rect);
|
||||
// 绘制矩形
|
||||
for (int j = 0; j < 4; ++j)
|
||||
var maxRect = Rect.Empty;
|
||||
var maxIndex = 0;
|
||||
for (int i = 0; i < contours.Length; i++)
|
||||
{
|
||||
//Cv2.Line(mat, (Point)points[j], (Point)points[(j + 1) % 4], Scalar.Red, 1);
|
||||
var box = Cv2.BoundingRect(contours[i]);
|
||||
if (box.Width * box.Height > maxRect.Width * maxRect.Height)
|
||||
{
|
||||
maxRect = box;
|
||||
maxIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Triangle(Mat gray)
|
||||
{
|
||||
Cv2.FindContours(gray, out var contours, out var hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxNone);
|
||||
Mat dst = Mat.Zeros(gray.Size(), MatType.CV_8UC3);
|
||||
for (int i = 0; i < contours.Length; i++)
|
||||
{
|
||||
Cv2.DrawContours(dst, contours, i, new Scalar(0, 255, 0), 1, LineTypes.Link4, hierarchy);
|
||||
}
|
||||
var maxContour = contours[maxIndex];
|
||||
|
||||
// 遍历轮廓
|
||||
for (int i = 0; i < contours.Length; i++)
|
||||
{
|
||||
// 计算轮廓的周长
|
||||
double perimeter = Cv2.ArcLength(contours[i], true);
|
||||
var perimeter = Cv2.ArcLength(maxContour, true);
|
||||
|
||||
// 近似多边形拟合
|
||||
OpenCvSharp.Point[] approx = Cv2.ApproxPolyDP(contours[i], 0.04 * perimeter, true);
|
||||
var approx = Cv2.ApproxPolyDP(maxContour, 0.08 * perimeter, true);
|
||||
|
||||
// 如果拟合的多边形有三个顶点,认为是三角形
|
||||
if (approx.Length == 3)
|
||||
{
|
||||
// 计算三条边的长度
|
||||
var sideLengths = new double[3];
|
||||
sideLengths[0] = Distance(approx[1], approx[2]);
|
||||
sideLengths[1] = Distance(approx[2], approx[0]);
|
||||
sideLengths[2] = Distance(approx[0], approx[1]);
|
||||
// 剪裁出三角形所在区域
|
||||
var newSrcMat = new Mat(mat, maxRect);
|
||||
|
||||
var result = sideLengths
|
||||
.Select((value, index) => new { Value = value, Index = index })
|
||||
.OrderBy(item => item.Value)
|
||||
.First();
|
||||
// HSV 阈值取出中心飞镖
|
||||
var hsvMat = new Mat();
|
||||
Cv2.CvtColor(newSrcMat, hsvMat, ColorConversionCodes.BGR2HSV);
|
||||
// var lowScalar = new Scalar(95, 255, 255);
|
||||
// var highScalar = new Scalar(255, 255, 255);
|
||||
var lowScalar = new Scalar(93, 155, 170);
|
||||
var highScalar = new Scalar(255, 255, 255);
|
||||
var hsvThresholdMat = new Mat();
|
||||
Cv2.InRange(hsvMat, lowScalar, highScalar, hsvThresholdMat);
|
||||
|
||||
// 计算最短线的中点
|
||||
var residue = approx.ToList();
|
||||
residue.RemoveAt(result.Index);
|
||||
var midPoint = new OpenCvSharp.Point((residue[0].X + residue[1].X) / 2, (residue[0].Y + residue[1].Y) / 2);
|
||||
// 循环计算三条边的中点,并计算中点到顶点的所有点中连续黑色像素的个数
|
||||
var maxBlackCount = 0;
|
||||
Point correctP1 = new(), correctP2 = new();
|
||||
var offset = new Point(maxRect.X, maxRect.Y);
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
var midPoint = Midpoint(approx[i], approx[(i + 1) % 3]);
|
||||
var targetPoint = approx[(i + 2) % 3];
|
||||
|
||||
// 在图像上绘制直线
|
||||
//Cv2.Line(dst2, approx[result.Index], midPoint, Scalar.Red, 1);
|
||||
// 中点到顶点的所有点
|
||||
var lineIterator = new LineIterator(hsvThresholdMat, midPoint - offset, targetPoint - offset, PixelConnectivity.Connectivity8);
|
||||
|
||||
VisionContext.Instance().DrawContent.PutLine("co", new LineDrawable(midPoint, approx[result.Index] + (approx[result.Index] - midPoint) * 3));
|
||||
// 计算连续黑色像素的个数
|
||||
var blackCount = 0;
|
||||
foreach (var item in lineIterator)
|
||||
{
|
||||
if (item.GetValue<Vec2b>().Item0 == 255)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
blackCount++;
|
||||
}
|
||||
|
||||
if (blackCount > maxBlackCount)
|
||||
{
|
||||
maxBlackCount = blackCount;
|
||||
correctP1 = midPoint;
|
||||
correctP2 = targetPoint;
|
||||
}
|
||||
}
|
||||
VisionContext.Instance().DrawContent.PutLine("co", new LineDrawable(correctP1, correctP2 + (correctP2 - correctP1) * 3));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static double Distance(OpenCvSharp.Point pt1, OpenCvSharp.Point pt2)
|
||||
static Point Midpoint(Point p1, Point p2)
|
||||
{
|
||||
int deltaX = Math.Abs(pt2.X - pt1.X);
|
||||
int deltaY = Math.Abs(pt2.Y - pt1.Y);
|
||||
|
||||
return Math.Sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||
var midX = (p1.X + p2.X) / 2;
|
||||
var midY = (p1.Y + p2.Y) / 2;
|
||||
return new Point(midX, midY);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user