getting closer
This commit is contained in:
parent
40f013d07e
commit
bb8e75a2f5
2 changed files with 70 additions and 10 deletions
|
|
@ -95,11 +95,21 @@ public class MinimapConfig
|
|||
public int CanvasSize { get; set; } = 4000;
|
||||
|
||||
// Template matching: search radius around current position estimate (pixels)
|
||||
public int MatchSearchRadius { get; set; } = 50;
|
||||
public int MatchSearchRadius { get; set; } = 100;
|
||||
|
||||
// Template matching: minimum correlation confidence to accept a match
|
||||
public double MatchConfidence { get; set; } = 0.3;
|
||||
|
||||
// Wall confidence (canvas-level): per-pixel counters to filter transient noise
|
||||
public int ConfidenceInc { get; set; } = 3;
|
||||
public int ConfidenceDec { get; set; } = 1;
|
||||
public int ConfidenceThreshold { get; set; } = 8;
|
||||
public int ConfidenceMax { get; set; } = 30;
|
||||
public int WarmupFrames { get; set; } = 5;
|
||||
|
||||
// Frame dedup: min changed pixels to process a frame (skip near-identical minimap frames)
|
||||
public int FrameChangeThreshold { get; set; } = 50;
|
||||
|
||||
// Stuck detection
|
||||
public double StuckThreshold { get; set; } = 2.0;
|
||||
public int StuckFrameCount { get; set; } = 5;
|
||||
|
|
|
|||
|
|
@ -7,8 +7,10 @@ public class WorldMap : IDisposable
|
|||
{
|
||||
private readonly MinimapConfig _config;
|
||||
private readonly Mat _canvas;
|
||||
private readonly Mat _confidence; // CV_16SC1: per-pixel wall confidence counter
|
||||
private MapPosition _position;
|
||||
private int _frameCount;
|
||||
private Mat? _prevWallMask; // for frame deduplication
|
||||
|
||||
public MapPosition Position => _position;
|
||||
|
||||
|
|
@ -16,6 +18,7 @@ public class WorldMap : IDisposable
|
|||
{
|
||||
_config = config;
|
||||
_canvas = new Mat(config.CanvasSize, config.CanvasSize, MatType.CV_8UC1, Scalar.Black);
|
||||
_confidence = new Mat(config.CanvasSize, config.CanvasSize, MatType.CV_16SC1, Scalar.Black);
|
||||
_position = new MapPosition(config.CanvasSize / 2.0, config.CanvasSize / 2.0);
|
||||
}
|
||||
|
||||
|
|
@ -27,19 +30,37 @@ public class WorldMap : IDisposable
|
|||
{
|
||||
_frameCount++;
|
||||
|
||||
// First frame: just stitch at center
|
||||
if (_frameCount <= 1)
|
||||
// Frame deduplication: skip if minimap hasn't scrolled yet
|
||||
if (_prevWallMask != null && _frameCount > 1)
|
||||
{
|
||||
Stitch(classifiedMat, _position);
|
||||
using var xor = new Mat();
|
||||
Cv2.BitwiseXor(wallMask, _prevWallMask, xor);
|
||||
var changedPixels = Cv2.CountNonZero(xor);
|
||||
if (changedPixels < _config.FrameChangeThreshold)
|
||||
{
|
||||
Log.Debug("Frame dedup: {Changed} changed pixels, skipping", changedPixels);
|
||||
return _position;
|
||||
}
|
||||
}
|
||||
|
||||
// Store current wall mask for next frame's dedup check
|
||||
_prevWallMask?.Dispose();
|
||||
_prevWallMask = wallMask.Clone();
|
||||
|
||||
// Warmup: stitch at center with boosted confidence to bootstrap canvas
|
||||
if (_frameCount <= _config.WarmupFrames)
|
||||
{
|
||||
StitchWithConfidence(classifiedMat, _position, boosted: true);
|
||||
return _position;
|
||||
}
|
||||
|
||||
// Match wallMask against canvas to find best position
|
||||
var matched = MatchPosition(wallMask, _position);
|
||||
if (matched != null)
|
||||
_position = matched;
|
||||
if (matched == null)
|
||||
return _position; // skip stitching entirely on failed match
|
||||
|
||||
Stitch(classifiedMat, _position);
|
||||
_position = matched;
|
||||
StitchWithConfidence(classifiedMat, _position, boosted: false);
|
||||
return _position;
|
||||
}
|
||||
|
||||
|
|
@ -100,7 +121,7 @@ public class WorldMap : IDisposable
|
|||
return new MapPosition(matchX, matchY);
|
||||
}
|
||||
|
||||
private void Stitch(Mat classifiedMat, MapPosition position)
|
||||
private void StitchWithConfidence(Mat classifiedMat, MapPosition position, bool boosted)
|
||||
{
|
||||
var halfSize = _config.CaptureSize / 2;
|
||||
var canvasX = (int)Math.Round(position.X) - halfSize;
|
||||
|
|
@ -121,14 +142,38 @@ public class WorldMap : IDisposable
|
|||
|
||||
var srcRoi = new Mat(classifiedMat, srcRect);
|
||||
var dstRoi = new Mat(_canvas, dstRect);
|
||||
var confRoi = new Mat(_confidence, dstRect);
|
||||
|
||||
var confInc = (short)_config.ConfidenceInc;
|
||||
var confDec = (short)_config.ConfidenceDec;
|
||||
var confThreshold = (short)_config.ConfidenceThreshold;
|
||||
var confMax = (short)_config.ConfidenceMax;
|
||||
|
||||
// Paste wall pixels (walls always win)
|
||||
for (var row = 0; row < h; row++)
|
||||
for (var col = 0; col < w; col++)
|
||||
{
|
||||
var srcVal = srcRoi.At<byte>(row, col);
|
||||
var conf = confRoi.At<short>(row, col);
|
||||
|
||||
if (srcVal == (byte)MapCell.Wall)
|
||||
dstRoi.Set(row, col, srcVal);
|
||||
{
|
||||
if (boosted)
|
||||
conf = confThreshold; // warmup: immediately at threshold
|
||||
else
|
||||
conf = Math.Min((short)(conf + confInc), confMax);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pixel is in visible area but not wall — decay confidence
|
||||
conf = Math.Max((short)(conf - confDec), (short)0);
|
||||
}
|
||||
|
||||
confRoi.Set(row, col, conf);
|
||||
|
||||
if (conf >= confThreshold)
|
||||
dstRoi.Set(row, col, (byte)MapCell.Wall);
|
||||
else if (dstRoi.At<byte>(row, col) == (byte)MapCell.Wall)
|
||||
dstRoi.Set(row, col, (byte)MapCell.Explored); // lost confidence, downgrade
|
||||
}
|
||||
|
||||
// Mark explored area: circle around player, only overwrite Unknown
|
||||
|
|
@ -243,6 +288,9 @@ public class WorldMap : IDisposable
|
|||
public void Reset()
|
||||
{
|
||||
_canvas.SetTo(Scalar.Black);
|
||||
_confidence.SetTo(Scalar.Black);
|
||||
_prevWallMask?.Dispose();
|
||||
_prevWallMask = null;
|
||||
_position = new MapPosition(_config.CanvasSize / 2.0, _config.CanvasSize / 2.0);
|
||||
_frameCount = 0;
|
||||
}
|
||||
|
|
@ -250,5 +298,7 @@ public class WorldMap : IDisposable
|
|||
public void Dispose()
|
||||
{
|
||||
_canvas.Dispose();
|
||||
_confidence.Dispose();
|
||||
_prevWallMask?.Dispose();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue