work on navigation
This commit is contained in:
parent
468e0a7246
commit
802f1030d5
12 changed files with 582 additions and 64 deletions
|
|
@ -1,8 +1,4 @@
|
|||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Runtime.InteropServices;
|
||||
using OpenCvSharp;
|
||||
using OpenCvSharp.Extensions;
|
||||
using Serilog;
|
||||
using Region = Poe2Trade.Core.Region;
|
||||
using Point = OpenCvSharp.Point;
|
||||
|
|
@ -13,17 +9,45 @@ namespace Poe2Trade.Navigation;
|
|||
public class MinimapCapture : IDisposable
|
||||
{
|
||||
private readonly MinimapConfig _config;
|
||||
private readonly IScreenCapture _backend;
|
||||
private Mat? _circularMask;
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern int GetSystemMetrics(int nIndex);
|
||||
|
||||
public MinimapCapture(MinimapConfig config)
|
||||
{
|
||||
_config = config;
|
||||
_backend = CreateBackend();
|
||||
BuildCircularMask();
|
||||
}
|
||||
|
||||
private static IScreenCapture CreateBackend()
|
||||
{
|
||||
// WGC primary → DXGI fallback → GDI last resort
|
||||
try
|
||||
{
|
||||
var wgc = new WgcCapture();
|
||||
Log.Information("Screen capture: WGC (Windows Graphics Capture)");
|
||||
return wgc;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning(ex, "WGC unavailable, trying DXGI Desktop Duplication");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var dxgi = new DesktopDuplication();
|
||||
Log.Information("Screen capture: DXGI Desktop Duplication");
|
||||
return dxgi;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning(ex, "DXGI unavailable, falling back to GDI");
|
||||
}
|
||||
|
||||
Log.Information("Screen capture: GDI (CopyFromScreen)");
|
||||
return new GdiCapture();
|
||||
}
|
||||
|
||||
private void BuildCircularMask()
|
||||
{
|
||||
var size = _config.CaptureSize;
|
||||
|
|
@ -35,10 +59,9 @@ public class MinimapCapture : IDisposable
|
|||
public MinimapFrame? CaptureFrame()
|
||||
{
|
||||
var region = _config.CaptureRegion;
|
||||
using var bitmap = CaptureScreen(region);
|
||||
using var bgr = BitmapConverter.ToMat(bitmap);
|
||||
using var bgr = _backend.CaptureRegion(region);
|
||||
|
||||
if (bgr.Empty())
|
||||
if (bgr == null || bgr.Empty())
|
||||
return null;
|
||||
|
||||
// Apply circular mask to ignore area outside fog-of-war circle
|
||||
|
|
@ -64,6 +87,10 @@ public class MinimapCapture : IDisposable
|
|||
Cv2.MorphologyEx(darkMask, wallMask, MorphTypes.Close, wallKernel);
|
||||
// Only within circular mask
|
||||
Cv2.BitwiseAnd(wallMask, _circularMask!, wallMask);
|
||||
// Don't count explored pixels as wall
|
||||
using var notExplored = new Mat();
|
||||
Cv2.BitwiseNot(exploredMask, notExplored);
|
||||
Cv2.BitwiseAnd(wallMask, notExplored, wallMask);
|
||||
|
||||
// Build classified mat: Unknown=0, Explored=1, Wall=2
|
||||
var classified = new Mat(_config.CaptureSize, _config.CaptureSize, MatType.CV_8UC1, Scalar.Black);
|
||||
|
|
@ -91,6 +118,45 @@ public class MinimapCapture : IDisposable
|
|||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save debug images: raw capture, HSV mask, classified result.
|
||||
/// Call once to diagnose color ranges.
|
||||
/// </summary>
|
||||
public void SaveDebugCapture(string dir = "debug-minimap")
|
||||
{
|
||||
Directory.CreateDirectory(dir);
|
||||
var region = _config.CaptureRegion;
|
||||
using var bgr = _backend.CaptureRegion(region);
|
||||
if (bgr == null || bgr.Empty()) return;
|
||||
|
||||
using var masked = new Mat();
|
||||
Cv2.BitwiseAnd(bgr, bgr, masked, _circularMask!);
|
||||
|
||||
using var hsv = new Mat();
|
||||
Cv2.CvtColor(masked, hsv, ColorConversionCodes.BGR2HSV);
|
||||
|
||||
using var exploredMask = new Mat();
|
||||
Cv2.InRange(hsv, _config.ExploredLoHSV, _config.ExploredHiHSV, exploredMask);
|
||||
|
||||
using var playerMask = new Mat();
|
||||
Cv2.InRange(hsv, _config.PlayerLoHSV, _config.PlayerHiHSV, playerMask);
|
||||
|
||||
// Save raw, masked, explored filter, player filter
|
||||
Cv2.ImWrite(Path.Combine(dir, "1-raw.png"), bgr);
|
||||
Cv2.ImWrite(Path.Combine(dir, "2-masked.png"), masked);
|
||||
Cv2.ImWrite(Path.Combine(dir, "3-explored.png"), exploredMask);
|
||||
Cv2.ImWrite(Path.Combine(dir, "4-player.png"), playerMask);
|
||||
|
||||
// Save HSV channels separately for tuning
|
||||
var channels = Cv2.Split(hsv);
|
||||
Cv2.ImWrite(Path.Combine(dir, "5-hue.png"), channels[0]);
|
||||
Cv2.ImWrite(Path.Combine(dir, "6-sat.png"), channels[1]);
|
||||
Cv2.ImWrite(Path.Combine(dir, "7-val.png"), channels[2]);
|
||||
foreach (var c in channels) c.Dispose();
|
||||
|
||||
Log.Information("Debug minimap images saved to {Dir}", Path.GetFullPath(dir));
|
||||
}
|
||||
|
||||
private Point2d FindCentroid(Mat mask)
|
||||
{
|
||||
var moments = Cv2.Moments(mask, true);
|
||||
|
|
@ -102,18 +168,9 @@ public class MinimapCapture : IDisposable
|
|||
return new Point2d(cx, cy);
|
||||
}
|
||||
|
||||
private static Bitmap CaptureScreen(Region region)
|
||||
{
|
||||
var bitmap = new Bitmap(region.Width, region.Height, PixelFormat.Format32bppArgb);
|
||||
using var g = Graphics.FromImage(bitmap);
|
||||
g.CopyFromScreen(region.X, region.Y, 0, 0,
|
||||
new System.Drawing.Size(region.Width, region.Height),
|
||||
CopyPixelOperation.SourceCopy);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_circularMask?.Dispose();
|
||||
_backend.Dispose();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue