work no minimap
This commit is contained in:
parent
3087f9146e
commit
7d10f1d2a9
4 changed files with 70 additions and 5 deletions
|
|
@ -205,8 +205,9 @@ public class MinimapCapture : IFrameConsumer, IDisposable
|
||||||
|
|
||||||
private Mat BuildWallMask(Mat hsv, Mat playerMask, bool sample = false)
|
private Mat BuildWallMask(Mat hsv, Mat playerMask, bool sample = false)
|
||||||
{
|
{
|
||||||
var lo = _colorTracker.AdaptedLo ?? _config.WallLoHSV;
|
var isCorner = _detectedMode == MinimapMode.Corner;
|
||||||
var hi = _colorTracker.AdaptedHi ?? _config.WallHiHSV;
|
var lo = isCorner ? _config.CornerWallLoHSV : (_colorTracker.AdaptedLo ?? _config.WallLoHSV);
|
||||||
|
var hi = isCorner ? _config.CornerWallHiHSV : (_colorTracker.AdaptedHi ?? _config.WallHiHSV);
|
||||||
|
|
||||||
var wallMask = new Mat();
|
var wallMask = new Mat();
|
||||||
Cv2.InRange(hsv, lo, hi, wallMask);
|
Cv2.InRange(hsv, lo, hi, wallMask);
|
||||||
|
|
@ -215,7 +216,7 @@ public class MinimapCapture : IFrameConsumer, IDisposable
|
||||||
Cv2.BitwiseNot(playerMask, notPlayer);
|
Cv2.BitwiseNot(playerMask, notPlayer);
|
||||||
Cv2.BitwiseAnd(wallMask, notPlayer, wallMask);
|
Cv2.BitwiseAnd(wallMask, notPlayer, wallMask);
|
||||||
|
|
||||||
if (sample)
|
if (sample && !isCorner)
|
||||||
_colorTracker.SampleFrame(hsv, wallMask);
|
_colorTracker.SampleFrame(hsv, wallMask);
|
||||||
|
|
||||||
using var kernel = Cv2.GetStructuringElement(MorphShapes.Ellipse, new Size(3, 3));
|
using var kernel = Cv2.GetStructuringElement(MorphShapes.Ellipse, new Size(3, 3));
|
||||||
|
|
|
||||||
|
|
@ -98,11 +98,15 @@ public class MinimapConfig
|
||||||
public Scalar PlayerLoHSV { get; set; } = new(5, 80, 80);
|
public Scalar PlayerLoHSV { get; set; } = new(5, 80, 80);
|
||||||
public Scalar PlayerHiHSV { get; set; } = new(25, 255, 255);
|
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
|
// HSV(115, 75, 229) — blue hue, low-medium saturation, bright
|
||||||
public Scalar WallLoHSV { get; set; } = new(110, 25, 190);
|
public Scalar WallLoHSV { get; set; } = new(110, 25, 190);
|
||||||
public Scalar WallHiHSV { get; set; } = new(136, 120, 255);
|
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)
|
// Connected components: minimum area to keep (kills speckle)
|
||||||
public int WallMinArea { get; set; } = 30;
|
public int WallMinArea { get; set; } = 30;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,24 @@ using Serilog;
|
||||||
|
|
||||||
namespace Poe2Trade.Navigation;
|
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>
|
/// <summary>
|
||||||
/// BFS pathfinding through the world map canvas. Pure function — reads canvas, never modifies it.
|
/// BFS pathfinding through the world map canvas. Pure function — reads canvas, never modifies it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class PathFinder
|
internal class PathFinder
|
||||||
{
|
{
|
||||||
|
/// <summary>Last BFS result for viewport overlay.</summary>
|
||||||
|
public BfsResult? LastResult { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// BFS through walkable (Explored) cells to find the best frontier direction.
|
/// BFS through walkable (Explored) cells to find the best frontier direction.
|
||||||
/// Instead of stopping at the nearest frontier, runs the full BFS and counts
|
/// 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> dxs = [-1, 0, 1, -1, 1, -1, 0, 1];
|
||||||
ReadOnlySpan<int> dys = [-1, -1, -1, 0, 0, 1, 1, 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 frontierCounts = new Dictionary<int, int>();
|
||||||
var firstStepCoords = new Dictionary<int, (short gx, short gy)>();
|
var firstStepCoords = new Dictionary<int, (short gx, short gy)>();
|
||||||
|
var frontierByKey = new Dictionary<int, List<Point>>();
|
||||||
|
|
||||||
while (queue.Count > 0)
|
while (queue.Count > 0)
|
||||||
{
|
{
|
||||||
|
|
@ -71,7 +85,9 @@ internal class PathFinder
|
||||||
{
|
{
|
||||||
frontierCounts[fsKey] = 1;
|
frontierCounts[fsKey] = 1;
|
||||||
firstStepCoords[fsKey] = (firstStepX[cellIdx], firstStepY[cellIdx]);
|
firstStepCoords[fsKey] = (firstStepX[cellIdx], firstStepY[cellIdx]);
|
||||||
|
frontierByKey[fsKey] = [];
|
||||||
}
|
}
|
||||||
|
frontierByKey[fsKey].Add(new Point(wx, wy));
|
||||||
break; // don't double-count this cell
|
break; // don't double-count this cell
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -114,6 +130,7 @@ internal class PathFinder
|
||||||
if (frontierCounts.Count == 0)
|
if (frontierCounts.Count == 0)
|
||||||
{
|
{
|
||||||
Log.Information("BFS: no reachable frontier within {Radius}px", searchRadius);
|
Log.Information("BFS: no reachable frontier within {Radius}px", searchRadius);
|
||||||
|
LastResult = null;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -138,6 +155,16 @@ internal class PathFinder
|
||||||
dirX /= len;
|
dirX /= len;
|
||||||
dirY /= 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})",
|
Log.Debug("BFS: {DirCount} directions, best={Best} frontier cells, dir=({Dx:F2},{Dy:F2})",
|
||||||
frontierCounts.Count, bestCount, dirX, dirY);
|
frontierCounts.Count, bestCount, dirX, dirY);
|
||||||
return (dirX, dirY);
|
return (dirX, dirY);
|
||||||
|
|
|
||||||
|
|
@ -459,6 +459,39 @@ public class WorldMap : IDisposable
|
||||||
colored.Set(r, c, new Vec3b(55, 40, 28));
|
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 px = cx - x0;
|
||||||
var py = cy - y0;
|
var py = cy - y0;
|
||||||
if (px >= 0 && px < viewSize && py >= 0 && py < viewSize)
|
if (px >= 0 && px < viewSize && py >= 0 && py < viewSize)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue