fixes for noise

This commit is contained in:
Boki 2026-02-13 14:35:46 -05:00
parent d2dab86544
commit b9b9a41c3c
3 changed files with 61 additions and 71 deletions

View file

@ -53,78 +53,51 @@ public class MinimapCapture : IDisposable
if (bgr == null || bgr.Empty())
return null;
// --- 1. HSV + extract S/V channels ---
using var hsv = new Mat();
Cv2.CvtColor(bgr, hsv, ColorConversionCodes.BGR2HSV);
using var satChan = new Mat();
using var valueChan = new Mat();
Cv2.ExtractChannel(hsv, satChan, 1); // S
Cv2.ExtractChannel(hsv, valueChan, 2); // V
// --- 2. Player mask (orange marker) ---
// Player mask (orange marker)
using var playerMask = new Mat();
Cv2.InRange(hsv, _config.PlayerLoHSV, _config.PlayerHiHSV, playerMask);
var playerOffset = FindCentroid(playerMask);
// --- 3. Wall mask: bright OR saturated → structure lines ---
var wallMask = BuildWallMask(satChan, valueChan, playerMask);
// Wall mask: target #A2AEE5 blue-lavender structure lines
var wallMask = BuildWallMask(hsv, playerMask);
// --- 4. Build classified mat (walls only — for stitching) ---
// Build classified mat (walls only — for stitching)
var classified = new Mat(_config.CaptureSize, _config.CaptureSize, MatType.CV_8UC1, Scalar.Black);
classified.SetTo(new Scalar((byte)MapCell.Wall), wallMask);
// Raw walls used for everything: dedup, matching, and stitching.
// Temporal smoothing kills walls during movement (minimap scrolls between frames,
// 3/5 vote fails). The confidence system is the long-term noise filter instead.
// --- 5. Gray for optical flow tracking (player zeroed) ---
// Gray for correlation tracking (player zeroed)
var grayForCorr = new Mat();
Cv2.CvtColor(bgr, grayForCorr, ColorConversionCodes.BGR2GRAY);
grayForCorr.SetTo(Scalar.Black, playerMask);
return new MinimapFrame(
GrayMat: grayForCorr,
WallMask: wallMask, // raw — for matching + dedup
ClassifiedMat: classified, // raw — for stitching (confidence filters noise)
WallMask: wallMask,
ClassifiedMat: classified,
PlayerOffset: playerOffset,
Timestamp: DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
);
}
private Mat BuildWallMask(Mat satChan, Mat valueChan, Mat playerMask)
private Mat BuildWallMask(Mat hsv, Mat playerMask)
{
// Wall = bright OR saturated pixels (minimap structure lines, icons)
using var highV = new Mat();
Cv2.Threshold(valueChan, highV, _config.WallMinValue, 255, ThresholdTypes.Binary);
using var highS = new Mat();
Cv2.Threshold(satChan, highS, _config.WallMinSat, 255, ThresholdTypes.Binary);
// Exclude nameplate text: very bright (V > 230) AND unsaturated (S < 40)
// Nameplates are pure white text; minimap walls are colored (have saturation)
using var nameplateBright = new Mat();
Cv2.Threshold(valueChan, nameplateBright, _config.NameplateMinValue, 255, ThresholdTypes.Binary);
using var nameplateLowSat = new Mat();
Cv2.Threshold(satChan, nameplateLowSat, _config.NameplateMaxSat, 255, ThresholdTypes.BinaryInv);
using var nameplateMask = new Mat();
Cv2.BitwiseAnd(nameplateBright, nameplateLowSat, nameplateMask);
// Target wall color #A2AEE5 — HSV(115, 75, 229)
// This is map-independent: walls are always blue-lavender, fog is higher-saturation blue
var wallMask = new Mat();
Cv2.BitwiseOr(highV, highS, wallMask);
Cv2.InRange(hsv, _config.WallLoHSV, _config.WallHiHSV, wallMask);
// Subtract nameplates
using var notNameplate = new Mat();
Cv2.BitwiseNot(nameplateMask, notNameplate);
Cv2.BitwiseAnd(wallMask, notNameplate, wallMask);
// Dilate to connect wall line fragments
using var kernel = Cv2.GetStructuringElement(MorphShapes.Ellipse, new Size(3, 3));
Cv2.Dilate(wallMask, wallMask, kernel);
// Subtract player (bright/saturated marker would otherwise be classified as wall)
// Subtract player marker (orange overlaps blue range slightly on some maps)
using var notPlayer = new Mat();
Cv2.BitwiseNot(playerMask, notPlayer);
Cv2.BitwiseAnd(wallMask, notPlayer, wallMask);
// Dilate to connect thin wall line fragments
using var kernel = Cv2.GetStructuringElement(MorphShapes.Ellipse, new Size(3, 3));
Cv2.Dilate(wallMask, wallMask, kernel);
FilterSmallComponents(wallMask, _config.WallMinArea);
return wallMask;
}
@ -176,16 +149,11 @@ public class MinimapCapture : IDisposable
return result;
}
using var satChan = new Mat();
using var valueChan = new Mat();
Cv2.ExtractChannel(hsv, satChan, 1);
Cv2.ExtractChannel(hsv, valueChan, 2);
using var playerMask = new Mat();
Cv2.InRange(hsv, _config.PlayerLoHSV, _config.PlayerHiHSV, playerMask);
if (stage == MinimapDebugStage.Player) return EncodePng(playerMask);
using var wallMask = BuildWallMask(satChan, valueChan, playerMask);
using var wallMask = BuildWallMask(hsv, playerMask);
if (stage == MinimapDebugStage.Walls) return EncodePng(wallMask);
// Classified (walls + player only — explored is tracked by WorldMap)
@ -214,15 +182,10 @@ public class MinimapCapture : IDisposable
using var hsv = new Mat();
Cv2.CvtColor(bgr, hsv, ColorConversionCodes.BGR2HSV);
using var satChan = new Mat();
using var valueChan = new Mat();
Cv2.ExtractChannel(hsv, satChan, 1);
Cv2.ExtractChannel(hsv, valueChan, 2);
using var playerMask = new Mat();
Cv2.InRange(hsv, _config.PlayerLoHSV, _config.PlayerHiHSV, playerMask);
using var wallMask = BuildWallMask(satChan, valueChan, playerMask);
using var wallMask = BuildWallMask(hsv, playerMask);
// Colorized classified (walls + player)
using var classified = new Mat(_config.CaptureSize, _config.CaptureSize, MatType.CV_8UC3, Scalar.Black);