work no minimap

This commit is contained in:
Boki 2026-02-16 14:41:15 -05:00
parent 3087f9146e
commit 7d10f1d2a9
4 changed files with 70 additions and 5 deletions

View file

@ -205,8 +205,9 @@ public class MinimapCapture : IFrameConsumer, IDisposable
private Mat BuildWallMask(Mat hsv, Mat playerMask, bool sample = false)
{
var lo = _colorTracker.AdaptedLo ?? _config.WallLoHSV;
var hi = _colorTracker.AdaptedHi ?? _config.WallHiHSV;
var isCorner = _detectedMode == MinimapMode.Corner;
var lo = isCorner ? _config.CornerWallLoHSV : (_colorTracker.AdaptedLo ?? _config.WallLoHSV);
var hi = isCorner ? _config.CornerWallHiHSV : (_colorTracker.AdaptedHi ?? _config.WallHiHSV);
var wallMask = new Mat();
Cv2.InRange(hsv, lo, hi, wallMask);
@ -215,7 +216,7 @@ public class MinimapCapture : IFrameConsumer, IDisposable
Cv2.BitwiseNot(playerMask, notPlayer);
Cv2.BitwiseAnd(wallMask, notPlayer, wallMask);
if (sample)
if (sample && !isCorner)
_colorTracker.SampleFrame(hsv, wallMask);
using var kernel = Cv2.GetStructuringElement(MorphShapes.Ellipse, new Size(3, 3));

View file

@ -98,11 +98,15 @@ public class MinimapConfig
public Scalar PlayerLoHSV { get; set; } = new(5, 80, 80);
public Scalar PlayerHiHSV { get; set; } = new(25, 255, 255);
// Wall detection: target #A2AEE5 (blue-lavender structure lines)
// Wall detection (overlay): target #A2AEE5 (blue-lavender structure lines)
// HSV(115, 75, 229) — blue hue, low-medium saturation, bright
public Scalar WallLoHSV { get; set; } = new(110, 25, 190);
public Scalar WallHiHSV { get; set; } = new(136, 120, 255);
// Wall detection (corner): wider V range for faded walls
public Scalar CornerWallLoHSV { get; set; } = new(110, 25, 100);
public Scalar CornerWallHiHSV { get; set; } = new(136, 120, 255);
// Connected components: minimum area to keep (kills speckle)
public int WallMinArea { get; set; } = 30;

View file

@ -3,11 +3,24 @@ using Serilog;
namespace Poe2Trade.Navigation;
/// <summary>
/// Last BFS result for visualization.
/// </summary>
internal record BfsResult(
List<Point> BestFrontier, // frontier cells in the chosen direction (canvas coords)
List<Point> OtherFrontier, // frontier cells in other directions (canvas coords)
double DirX, double DirY, // chosen direction (unit vector)
int PlayerCx, int PlayerCy // player position on canvas
);
/// <summary>
/// BFS pathfinding through the world map canvas. Pure function — reads canvas, never modifies it.
/// </summary>
internal class PathFinder
{
/// <summary>Last BFS result for viewport overlay.</summary>
public BfsResult? LastResult { get; private set; }
/// <summary>
/// BFS through walkable (Explored) cells to find the best frontier direction.
/// Instead of stopping at the nearest frontier, runs the full BFS and counts
@ -40,9 +53,10 @@ internal class PathFinder
ReadOnlySpan<int> dxs = [-1, 0, 1, -1, 1, -1, 0, 1];
ReadOnlySpan<int> dys = [-1, -1, -1, 0, 0, 1, 1, 1];
// Count frontier cells per first-step direction
// Count frontier cells per first-step direction, and collect positions
var frontierCounts = new Dictionary<int, int>();
var firstStepCoords = new Dictionary<int, (short gx, short gy)>();
var frontierByKey = new Dictionary<int, List<Point>>();
while (queue.Count > 0)
{
@ -71,7 +85,9 @@ internal class PathFinder
{
frontierCounts[fsKey] = 1;
firstStepCoords[fsKey] = (firstStepX[cellIdx], firstStepY[cellIdx]);
frontierByKey[fsKey] = [];
}
frontierByKey[fsKey].Add(new Point(wx, wy));
break; // don't double-count this cell
}
}
@ -114,6 +130,7 @@ internal class PathFinder
if (frontierCounts.Count == 0)
{
Log.Information("BFS: no reachable frontier within {Radius}px", searchRadius);
LastResult = null;
return null;
}
@ -138,6 +155,16 @@ internal class PathFinder
dirX /= len;
dirY /= len;
// Store result for visualization
var bestFrontier = frontierByKey[bestKey];
var otherFrontier = new List<Point>();
foreach (var (key, pts) in frontierByKey)
{
if (key != bestKey)
otherFrontier.AddRange(pts);
}
LastResult = new BfsResult(bestFrontier, otherFrontier, dirX, dirY, cx, cy);
Log.Debug("BFS: {DirCount} directions, best={Best} frontier cells, dir=({Dx:F2},{Dy:F2})",
frontierCounts.Count, bestCount, dirX, dirY);
return (dirX, dirY);

View file

@ -459,6 +459,39 @@ public class WorldMap : IDisposable
colored.Set(r, c, new Vec3b(55, 40, 28));
}
// BFS overlay: frontier cells + direction line
var bfs = _pathFinder.LastResult;
if (bfs != null)
{
// Other frontier directions (dim cyan)
foreach (var pt in bfs.OtherFrontier)
{
var vx = pt.X - x0;
var vy = pt.Y - y0;
if (vx >= 0 && vx < viewSize && vy >= 0 && vy < viewSize)
colored.Set(vy, vx, new Vec3b(100, 80, 0));
}
// Best frontier direction (bright green)
foreach (var pt in bfs.BestFrontier)
{
var vx = pt.X - x0;
var vy = pt.Y - y0;
if (vx >= 0 && vx < viewSize && vy >= 0 && vy < viewSize)
colored.Set(vy, vx, new Vec3b(0, 220, 0));
}
// Direction line from player
var px2 = bfs.PlayerCx - x0;
var py2 = bfs.PlayerCy - y0;
var lineLen = 60;
var ex = (int)(px2 + bfs.DirX * lineLen);
var ey = (int)(py2 + bfs.DirY * lineLen);
Cv2.ArrowedLine(colored, new Point(px2, py2), new Point(ex, ey),
new Scalar(0, 220, 0), 2, tipLength: 0.3);
}
// Player dot (orange, on top)
var px = cx - x0;
var py = cy - y0;
if (px >= 0 && px < viewSize && py >= 0 && py < viewSize)